Moved documentation site to its own directory and included kernel driver. (#2)

* Moved documentation site to its own directory

* Initial commit of kernel driver code from Rekall.
This commit is contained in:
Mike Cohen
2020-09-28 22:05:50 +10:00
committed by GitHub
parent 6efea939ef
commit f4a21345db
72 changed files with 3988 additions and 206 deletions
+3 -3
View File
@@ -1,3 +1,3 @@
[submodule "themes/hugo-whisper-theme"]
path = themes/hugo-whisper-theme
url = https://github.com/JugglerX/hugo-whisper-theme.git
[submodule "site/themes/hugo-whisper-theme"]
path = site/themes/hugo-whisper-theme
url = https://github.com/JugglerX/hugo-whisper-theme.git
+202
View File
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2012 Michael Cohen <scudette@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+10 -3
View File
@@ -1,4 +1,11 @@
The Pmem Memory acquisition tools.
==================================
# The Winpmem memory acquisition driver and userspace.
This is the documentation site for WinPmem
Winpmem has been the default open source memory acquisition driver for
windows for a long time. It used to live in the Rekall project, but
has recently been separated into its own repository.
## Copyright
This code was originally developed within Google but was released
under the Apache License.
+1 -1
View File
@@ -124,7 +124,7 @@
<script type="text/javascript" src="/js/scripts.min.bf1e1f7ae8e03db5f012356e825843facdff51c0a559cb0d27fe2bbe1db405c2.js"></script>
<script type="text/javascript" src="/js/scripts.min.1237ff71925bb8625c97a9af8db4c54525258bedfd7c47493daaff723bea755e.js"></script>
+1 -1
View File
@@ -1 +1 @@
winpmem.velocidex.com
winpmem.velocidex.com
+1 -1
View File
@@ -126,7 +126,7 @@
<script type="text/javascript" src="/js/scripts.min.bf1e1f7ae8e03db5f012356e825843facdff51c0a559cb0d27fe2bbe1db405c2.js"></script>
<script type="text/javascript" src="/js/scripts.min.1237ff71925bb8625c97a9af8db4c54525258bedfd7c47493daaff723bea755e.js"></script>
+3 -7
View File
@@ -1,14 +1,10 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Categories on WinPmem memory imager</title>
<link>https://winpmem.velocidex.com/categories/</link>
<description>Recent content in Categories on WinPmem memory imager</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<atom:link href="https://winpmem.velocidex.com/categories/index.xml" rel="self" type="application/rss+xml" />
<language>en-us</language><atom:link href="https://winpmem.velocidex.com/categories/index.xml" rel="self" type="application/rss+xml" />
</channel>
</rss>
</rss>
+12 -17
View File
@@ -130,28 +130,23 @@
<div class="col-12 col-md-9">
<h1 class="title">Extracting streams from AFF4 volumes</h1>
<div class="content">
<p>Analysis tools which already support AFF4 will be able to use the AFF4
<div class="content ">
<p>Analysis tools which already support AFF4 will be able to use the AFF4
image directly, but sometimes you may come across a tool which does
not. In this case you will want to extract the RAW streams out of the
AFF4 volume.</p>
<p>To extract streams from an AFF4 volume we use the <em>-e</em> flag.</p>
<h2 id="extract-streams-by-using-wild-cards">Extract streams by using wild cards</h2>
<div class="highlight"><pre class="chroma"> WinPmem.exe -e &#39;*/kallsyms&#39; --export_dir /tmp/export/ /tmp/test.aff4</pre></div>
<p>By default export directory is the current directory. The imager
will create a directory structure under the export directory which
contains all the matched files.</p>
<div class="highlight"><pre class="chroma"><code class="language-fallback" data-lang="fallback"> WinPmem.exe -e &#39;*/kallsyms&#39; --export_dir /tmp/export/ /tmp/test.aff4
</code></pre></div><p>By default export directory is the current directory. The imager
will create a directory structure under the export directory which
contains all the matched files.</p>
<h2 id="extract-streams-from-stdin">Extract streams from stdin</h2>
<div class="highlight"><pre class="chroma"> WinPmem.exe -l test.aff4 | grep exe | \
WinPmem.exe -e @ --export_dir export/ test.aff4</pre></div>
<p>In the above example, we list the streams in the volume, then grep
only the executable files, and extract them into the export
directory.</p>
<div class="highlight"><pre class="chroma"><code class="language-fallback" data-lang="fallback"> WinPmem.exe -l test.aff4 | grep exe | \
WinPmem.exe -e @ --export_dir export/ test.aff4
</code></pre></div><p>In the above example, we list the streams in the volume, then grep
only the executable files, and extract them into the export
directory.</p>
</div>
</div>
@@ -183,7 +178,7 @@ AFF4 volume.</p>
<script type="text/javascript" src="/js/scripts.min.bf1e1f7ae8e03db5f012356e825843facdff51c0a559cb0d27fe2bbe1db405c2.js"></script>
<script type="text/javascript" src="/js/scripts.min.1237ff71925bb8625c97a9af8db4c54525258bedfd7c47493daaff723bea755e.js"></script>
+50 -60
View File
@@ -130,75 +130,65 @@
<div class="col-12 col-md-9">
<h1 class="title">Acquiring Files</h1>
<div class="content">
<p>The WinPmem imager can also acquire multiple files into the AFF4
<div class="content ">
<p>The WinPmem imager can also acquire multiple files into the AFF4
volume. These can be devices (such as disks using /dev/sda) or logical
files.</p>
<h2 id="acquiring-a-disk-image">Acquiring a disk image</h2>
<div class="highlight"><pre class="chroma"> WinPmem.exe -i \\.\c: -o output.aff4 -dd</pre></div>
<p>Note that by default the aff4 imager will append new streams to the
output volume if it already exists. This is useful for appending
more relevant evidence after the initial acquisition is
completed. If you dont want this behaviour you can specify the -t
(&ndash;truncate) flag to truncate the output volume before adding the
new stream.</p>
<div class="highlight"><pre class="chroma"><code class="language-fallback" data-lang="fallback"> WinPmem.exe -i \\.\c: -o output.aff4 -dd
</code></pre></div><p>Note that by default the aff4 imager will append new streams to the
output volume if it already exists. This is useful for appending
more relevant evidence after the initial acquisition is
completed. If you dont want this behaviour you can specify the -t
(&ndash;truncate) flag to truncate the output volume before adding the
new stream.</p>
<h2 id="acquiring-multiple-logical-files">Acquiring multiple logical files</h2>
<div class="highlight"><pre class="chroma"> WinPmem -i C:/Windows/*.exe -o output.aff4</pre></div>
<p>Using glob expressions as input files will be expanded as required
to include all filenames matching the globs. This works also on
Windows which does not expand globs on the shell.</p>
<div class="highlight"><pre class="chroma"><code class="language-fallback" data-lang="fallback"> WinPmem -i C:/Windows/*.exe -o output.aff4
</code></pre></div><p>Using glob expressions as input files will be expanded as required
to include all filenames matching the globs. This works also on
Windows which does not expand globs on the shell.</p>
<h2 id="acquiring-files-newer-than-30-days-can-be-done-by-using-the-find">Acquiring files newer than 30 days can be done by using the find</h2>
<p>command on Linux or Powershell script on Windows.</p>
<div class="highlight"><pre class="chroma"> find /usr/bin/ -ctime -30 | WinPmem -i @ -o /tmp/output.aff4</pre></div>
<p>Or on Windows:</p>
<div class="highlight"><pre class="chroma"> powershell -Command &#34;Get-ChildItem f:\ | Where{$_.LastWriteTime -gt
(Get-Date).AddDays(-7)} | SELECT Name | ft -hidetableheaders&#34; |
WinPmem -i @ -o /tmp/output.aff4</pre></div>
<p>Using a single @ as the input filename, makes the aff4 imager read
the list of files to acqiure from stdin. This allows for more
sophisticated pre-processing and makes it easier to acquire files
with spaces or special characters in their names (without having to
worry about shell escapes). In the above example we use the find
unix command to identify files newer than 30 days and also add them
to the image.</p>
<div class="highlight"><pre class="chroma"><code class="language-fallback" data-lang="fallback"> find /usr/bin/ -ctime -30 | WinPmem -i @ -o /tmp/output.aff4
</code></pre></div><p>Or on Windows:</p>
<div class="highlight"><pre class="chroma"><code class="language-fallback" data-lang="fallback"> powershell -Command &#34;Get-ChildItem f:\ | Where{$_.LastWriteTime -gt
(Get-Date).AddDays(-7)} | SELECT Name | ft -hidetableheaders&#34; |
WinPmem -i @ -o /tmp/output.aff4
</code></pre></div><p>Using a single @ as the input filename, makes the aff4 imager read
the list of files to acqiure from stdin. This allows for more
sophisticated pre-processing and makes it easier to acquire files
with spaces or special characters in their names (without having to
worry about shell escapes). In the above example we use the find
unix command to identify files newer than 30 days and also add them
to the image.</p>
<h2 id="enabling-multiple-threads">Enabling multiple threads</h2>
<div class="highlight"><pre class="chroma"> WinPmem.exe -o /tmp/output.aff4 --threads 6</pre></div>
<p>The aff4 imager uses a single thread by default, but if your
machine has more cores, then you will see vastly better performance
by allowing more threads to run. This is particularly important
when using the default compression of the zlib compressor which
needs more CPU resources.</p>
<div class="highlight"><pre class="chroma"><code class="language-fallback" data-lang="fallback"> WinPmem.exe -o /tmp/output.aff4 --threads 6
</code></pre></div><p>The aff4 imager uses a single thread by default, but if your
machine has more cores, then you will see vastly better performance
by allowing more threads to run. This is particularly important
when using the default compression of the zlib compressor which
needs more CPU resources.</p>
<h2 id="enabling-snappy-compression">Enabling snappy compression</h2>
<div class="highlight"><pre class="chroma"> WinPmem.exe -o output.aff4 --compression snappy</pre></div>
<p>The Snappy compression engine is much faster than the default zlib
but trades off compression size. Enabling snappy compression will
result in slightly larger images but should complete faster.</p>
<div class="highlight"><pre class="chroma"><code class="language-fallback" data-lang="fallback"> WinPmem.exe -o output.aff4 --compression snappy
</code></pre></div><p>The Snappy compression engine is much faster than the default zlib
but trades off compression size. Enabling snappy compression will
result in slightly larger images but should complete faster.</p>
<h2 id="splitting-an-image-into-multiple-volumes">Splitting an image into multiple volumes</h2>
<div class="highlight"><pre class="chroma"> WinPmem.exe -o output.aff4 --split 650m</pre></div>
<p>Some images are very large. By enabling splitting images it is
possible to restrict the maximum size of each volume. The imager
will close off each volume as it is done with it, and so you can
start uploading, archiving each volume as soon as it is
finished. Note that the same stream may be split across one or more
volumes so you will need all volumes to properly extract the
stream.</p>
<div class="highlight"><pre class="chroma"><code class="language-fallback" data-lang="fallback"> WinPmem.exe -o output.aff4 --split 650m
</code></pre></div><p>Some images are very large. By enabling splitting images it is
possible to restrict the maximum size of each volume. The imager
will close off each volume as it is done with it, and so you can
start uploading, archiving each volume as soon as it is
finished. Note that the same stream may be split across one or more
volumes so you will need all volumes to properly extract the
stream.</p>
<h2 id="acquiring-into-standard-output">Acquiring into standard output</h2>
<div class="highlight"><pre class="chroma"> WinPmem.exe -o - | gsutil cp - gs://rekall-test/test.aff4</pre></div>
<p>If the output filename is specifies as a single dash (&ldquo;-&rdquo;), the
imager writes the AFF4 volume to stdout. This allows the image to
be piped to a different tool. The example above streams the image
directly to a cloud storage bucket without needing to write a
temporary local copy.</p>
<div class="highlight"><pre class="chroma"><code class="language-fallback" data-lang="fallback"> WinPmem.exe -o - | gsutil cp - gs://rekall-test/test.aff4
</code></pre></div><p>If the output filename is specifies as a single dash (&quot;-&quot;), the
imager writes the AFF4 volume to stdout. This allows the image to
be piped to a different tool. The example above streams the image
directly to a cloud storage bucket without needing to write a
temporary local copy.</p>
</div>
</div>
@@ -230,7 +220,7 @@ files.</p>
<script type="text/javascript" src="/js/scripts.min.bf1e1f7ae8e03db5f012356e825843facdff51c0a559cb0d27fe2bbe1db405c2.js"></script>
<script type="text/javascript" src="/js/scripts.min.1237ff71925bb8625c97a9af8db4c54525258bedfd7c47493daaff723bea755e.js"></script>
+17 -10
View File
@@ -133,10 +133,7 @@
<span class="overview">Overview</span>
<h1 class="title">Winpmem Documentation</h1>
<div class="content">
<h2 id="documentation">Documentation</h2>
<h2 id="documentation">Documentation</h2>
<p>This is the winpmem documentation.</p>
</div>
@@ -145,36 +142,46 @@
<div class="summary mb-2">
<h2 class="title-summary"><a href="https://winpmem.velocidex.com/docs/usage/">Overview</a></h2>
<p> WinPmem is developed as part of the AFF4 imager project. AFF4 is an advanced, open forensic imaging format. The format has been </p>
<p>WinPmem is developed as part of the AFF4 imager project. AFF4 is an advanced, open forensic imaging format. The format has been standardized in the AFF4 Standard Specification, and it is increasing more supported by other tools.
WinPmem by default will use AFF4 to store the memory image, but it is also possible to write the image in RAW format or ELF format. You might want to do this if you are going to use the image with tools that can not read AFF4 natively.</p>
</div>
<div class="summary mb-2">
<h2 class="title-summary"><a href="https://winpmem.velocidex.com/docs/memory/">Acquiring Memory</a></h2>
<p>Acquiring memory using WinPmem is a very simple process:
F:\&amp;gt;winpmem.exe -o test.aff4 -dd 2019-05-17 02:26:22 I This is The WinPmem </p>
F:\&gt;winpmem.exe -o test.aff4 -dd 2019-05-17 02:26:22 I This is The WinPmem memory imager. version 3.3rc1 2019-05-17 02:26:22 I Extracted 45368 bytes into C:\Users\test\AppData\Local\Temp\pmeB5CC.tmp 2019-05-17 02:26:22 I Driver Unloaded. 2019-05-17 02:26:22 I Loaded Driver C:\Users\test\AppData\Local\Temp\pmeB5CC.tmp 2019-05-17 02:26:22 I Setting acquisition mode 2 2019-05-17 02:26:22 I CR3: 0x00001AA000 5 memory ranges: Start 0x00001000 - Length 0x0009E000 Start 0x00100000 - Length 0x00002000 Start 0x00103000 - Length 0xBFDDD000 Start 0xBFF00000 - Length 0x00100000 Start 0x100000000 - Length 0x52400000 2019-05-17 02:26:22 W Output file test.</p>
</div>
<div class="summary mb-2">
<h2 class="title-summary"><a href="https://winpmem.velocidex.com/docs/files/">Acquiring Files</a></h2>
<p> The WinPmem imager can also acquire multiple files into the AFF4 volume. These can be devices (such as disks using /dev/sda) or logical </p>
<p>The WinPmem imager can also acquire multiple files into the AFF4 volume. These can be devices (such as disks using /dev/sda) or logical files.
Acquiring a disk image WinPmem.exe -i \\.\c: -o output.aff4 -dd Note that by default the aff4 imager will append new streams to the output volume if it already exists. This is useful for appending more relevant evidence after the initial acquisition is completed. If you dont want this behaviour you can specify the -t (&ndash;truncate) flag to truncate the output volume before adding the new stream.</p>
</div>
<div class="summary mb-2">
<h2 class="title-summary"><a href="https://winpmem.velocidex.com/docs/inspecting/">Inspecting AFF4 volumes</a></h2>
<p>AFF4 volumes are based around the common Zip compression standard (for large volumes we use Zip64 extensions). Therefore it is possible to </p>
<p>AFF4 volumes are based around the common Zip compression standard (for large volumes we use Zip64 extensions). Therefore it is possible to examine AFF4 volumes using common zip utilities.
⟫ unzip -l /tmp/test.aff4 Archive: /tmp/test.aff4 aff4://c7c60030-cc3e-43a6-b5d1-1551b29c9918 Length Date Time Name --------- ---------- ----- ---- 189432 2018-01-15 12:50 usr/bin/mksquashfs 951952 2018-01-15 12:50 usr/bin/x86_64-w64-mingw32-cpp ... 50929 2018-01-15 12:50 information.turtle ... --------- ------- 315748394 327 files We can see that each volume has a unique URN, and it contains a file called &ldquo;information.</p>
</div>
<div class="summary mb-2">
<h2 class="title-summary"><a href="https://winpmem.velocidex.com/docs/extracting/">Extracting streams from AFF4 volumes</a></h2>
<p> Analysis tools which already support AFF4 will be able to use the AFF4 image directly, but sometimes you may come across a tool which does </p>
<p>Analysis tools which already support AFF4 will be able to use the AFF4 image directly, but sometimes you may come across a tool which does not. In this case you will want to extract the RAW streams out of the AFF4 volume.
To extract streams from an AFF4 volume we use the -e flag.
Extract streams by using wild cards WinPmem.exe -e &#39;*/kallsyms&#39; --export_dir /tmp/export/ /tmp/test.aff4 By default export directory is the current directory.</p>
</div>
</div>
</div>
</div>
@@ -202,7 +209,7 @@ F:\&amp;gt;winpmem.exe -o test.aff4 -dd 2019-05-17 02:26:22 I This is The WinPme
<script type="text/javascript" src="/js/scripts.min.bf1e1f7ae8e03db5f012356e825843facdff51c0a559cb0d27fe2bbe1db405c2.js"></script>
<script type="text/javascript" src="/js/scripts.min.1237ff71925bb8625c97a9af8db4c54525258bedfd7c47493daaff723bea755e.js"></script>
+3 -7
View File
@@ -1,15 +1,11 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Winpmem Documentation on WinPmem memory imager</title>
<link>https://winpmem.velocidex.com/docs/</link>
<description>Recent content in Winpmem Documentation on WinPmem memory imager</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<atom:link href="https://winpmem.velocidex.com/docs/index.xml" rel="self" type="application/rss+xml" />
<language>en-us</language><atom:link href="https://winpmem.velocidex.com/docs/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Overview</title>
<link>https://winpmem.velocidex.com/docs/usage/</link>
@@ -62,4 +58,4 @@ Extract streams by using wild cards WinPmem.exe -e &amp;#39;*/kallsyms&amp;#39;
</item>
</channel>
</rss>
</rss>
+24 -23
View File
@@ -130,11 +130,11 @@
<div class="col-12 col-md-9">
<h1 class="title">Inspecting AFF4 volumes</h1>
<div class="content">
<div class="content ">
<p>AFF4 volumes are based around the common Zip compression standard (for
large volumes we use Zip64 extensions). Therefore it is possible to
examine AFF4 volumes using common zip utilities.</p>
<div class="highlight"><pre class="chroma"> ⟫ unzip -l /tmp/test.aff4
<div class="highlight"><pre class="chroma"><code class="language-fallback" data-lang="fallback"> ⟫ unzip -l /tmp/test.aff4
Archive: /tmp/test.aff4
aff4://c7c60030-cc3e-43a6-b5d1-1551b29c9918
Length Date Time Name
@@ -145,14 +145,13 @@ examine AFF4 volumes using common zip utilities.</p>
50929 2018-01-15 12:50 information.turtle
...
--------- -------
315748394 327 files</pre></div>
<p>We can see that each volume has a unique URN, and it contains a file
315748394 327 files
</code></pre></div><p>We can see that each volume has a unique URN, and it contains a file
called &ldquo;information.turtle&rdquo;. This file contains the AFF4 metadata for
the volume as an RDF turtle file.</p>
<p>We can get the aff4 imager to display the metadata in the volume using
the -V flag::</p>
<div class="highlight"><pre class="chroma"> ⟫ aff4imager -V /tmp/test.aff4
<div class="highlight"><pre class="chroma"><code class="language-fallback" data-lang="fallback"> ⟫ aff4imager -V /tmp/test.aff4
@prefix rdf: &lt;http://www.w3.org/1999/02/22-rdf-syntax-ns#&gt; .
@prefix aff4: &lt;http://aff4.org/Schema#&gt; .
@prefix xsd: &lt;http://www.w3.org/2001/XMLSchema#&gt; .
@@ -171,32 +170,34 @@ the -V flag::</p>
aff4:compressionMethod &lt;https://www.ietf.org/rfc/rfc1950.txt&gt; ;
aff4:size 8531652608 ;
aff4:stored &lt;aff4://2d874721-267b-40fb-ac20-7bc22a8af883&gt; ;
a aff4:ImageStream .</pre></div>
<p>Note that if we have multiple volumes (as in a split volume set) we
a aff4:ImageStream .
</code></pre></div><p>Note that if we have multiple volumes (as in a split volume set) we
should list all volumes as parameters to -V.</p>
<p>In the above output we see some interesting artifacts of the AFF4 format:</p>
<ol>
<li><p>All streams within the AFF4 volume have a unique URN. The imager
<li>
<p>All streams within the AFF4 volume have a unique URN. The imager
creates the URNs based on their original filename, but this is just
a convenience. The imager also stores the original filename (which
might contain backslashes on windows).</p></li>
<li><p>Smaller files (e.g. <em>/proc/kallsyms</em>) are stored as AFF4 Segments
might contain backslashes on windows).</p>
</li>
<li>
<p>Smaller files (e.g. <em>/proc/kallsyms</em>) are stored as AFF4 Segments
which are just regular zip archive members. This means you can
extract Smaller files using normal zip tools.</p></li>
<li><p>Larger files are stored as AFF4 ImageStream. This type of storage
extract Smaller files using normal zip tools.</p>
</li>
<li>
<p>Larger files are stored as AFF4 ImageStream. This type of storage
chunks the file data into 32kb chunks, and stores groups of chunks
in their own zip segment.</p></li>
<li><p>Finally sparse images (such as memory images) are stores as an AFF4
in their own zip segment.</p>
</li>
<li>
<p>Finally sparse images (such as memory images) are stores as an AFF4
Map. The map does not actually store any data itself (the data is
stored by the stream <em>/proc/kcore/data</em>) but it specifies a
transformation of its underlying stream.</p></li>
transformation of its underlying stream.</p>
</li>
</ol>
<p>Finally using the -l flag enables a listing of all Image streams from the volume.</p>
</div>
@@ -229,7 +230,7 @@ transformation of its underlying stream.</p></li>
<script type="text/javascript" src="/js/scripts.min.bf1e1f7ae8e03db5f012356e825843facdff51c0a559cb0d27fe2bbe1db405c2.js"></script>
<script type="text/javascript" src="/js/scripts.min.1237ff71925bb8625c97a9af8db4c54525258bedfd7c47493daaff723bea755e.js"></script>
+29 -22
View File
@@ -130,9 +130,9 @@
<div class="col-12 col-md-9">
<h1 class="title">Acquiring Memory</h1>
<div class="content">
<div class="content ">
<p>Acquiring memory using WinPmem is a very simple process:</p>
<div class="highlight"><pre class="chroma">F:\&gt;winpmem.exe -o test.aff4 -dd
<div class="highlight"><pre class="chroma"><code class="language-fallback" data-lang="fallback">F:\&gt;winpmem.exe -o test.aff4 -dd
2019-05-17 02:26:22 I This is The WinPmem memory imager. version 3.3rc1
2019-05-17 02:26:22 I Extracted 45368 bytes into C:\Users\test\AppData\Local\Temp\pmeB5CC.tmp
2019-05-17 02:26:22 I Driver Unloaded.
@@ -154,35 +154,42 @@
2019-05-17 02:26:22 I Dumping Range 2 (Starts at 0x103000, length 0xbfddd000
2019-05-17 02:26:23 I Reading 2103000 32 MiB / 4387 (25 MiB/s)
2019-05-17 02:26:24 I Reading 4103000 64 MiB / 4387 (26 MiB/s)
2019-05-17 02:26:25 I Reading 6103000 96 MiB / 4387 (28 MiB/s)</pre></div>
<ul>
<li><p>The <code>-o</code> flag instructs WinPmem to create a new AFF4 volume with the
name <code>test.aff4</code>.</p></li>
<li><p>The -d flag instructs WinPmem to produce more vebose output (twice
for progress reporting).</p></li>
<li><p>We see that WinPmem extracts the kernel driver into the temporary
2019-05-17 02:26:25 I Reading 6103000 96 MiB / 4387 (28 MiB/s)
</code></pre></div><ul>
<li>
<p>The <code>-o</code> flag instructs WinPmem to create a new AFF4 volume with the
name <code>test.aff4</code>.</p>
</li>
<li>
<p>The -d flag instructs WinPmem to produce more vebose output (twice
for progress reporting).</p>
</li>
<li>
<p>We see that WinPmem extracts the kernel driver into the temporary
directory and loads it into the kernel. The driver provides access
to raw memory via a number of acquisition methods but the default is
usually the best.</p></li>
<li><p>WinPmem then displays the detected physical memory ranges and
continues to dump each range.</p></li>
<li><p>By default WinPmem uses 2 threads to compress the image, however
usually the best.</p>
</li>
<li>
<p>WinPmem then displays the detected physical memory ranges and
continues to dump each range.</p>
</li>
<li>
<p>By default WinPmem uses 2 threads to compress the image, however
most machines can use multiple cores. Using the <code>--thread</code> flag you
may increase this number. Using more threads will result in quicker
compression, and therefore quicker imaging.</p></li>
<li><p>By default WinPmem will use an AFF4 image and will store the memory
compression, and therefore quicker imaging.</p>
</li>
<li>
<p>By default WinPmem will use an AFF4 image and will store the memory
image using an AFF4 Map object with a compressed backing stream. If
you want to produce a raw file format or an elf file, you may
specify the <code>--format elf</code> or <code>--format raw</code> to produce these image
formats. Note that due to limitations in these image formats it is
not possible to include additional streams. Neither of these formats
support compression either (but ELF format supports sparse data
runs).</p></li>
runs).</p>
</li>
</ul>
</div>
@@ -215,7 +222,7 @@ runs).</p></li>
<script type="text/javascript" src="/js/scripts.min.bf1e1f7ae8e03db5f012356e825843facdff51c0a559cb0d27fe2bbe1db405c2.js"></script>
<script type="text/javascript" src="/js/scripts.min.1237ff71925bb8625c97a9af8db4c54525258bedfd7c47493daaff723bea755e.js"></script>
+22 -25
View File
@@ -130,64 +130,61 @@
<div class="col-12 col-md-9">
<h1 class="title">Overview</h1>
<div class="content">
<p>WinPmem is developed as part of the AFF4 imager project. AFF4 is an
<div class="content ">
<p>WinPmem is developed as part of the AFF4 imager project. AFF4 is an
advanced, open forensic imaging format. The format has been
standardized in the <a href="https://github.com/aff4/Standard">AFF4 Standard Specification</a>, and it is increasing more supported by other tools.</p>
<p>WinPmem by default will use AFF4 to store the memory image, but it is
also possible to write the image in RAW format or ELF format. You
might want to do this if you are going to use the image with tools
that can not read AFF4 natively. However, note that using these
imaging format will cause WinPmem to skip acquisition of multiple
files and metadata making the image harder to use.</p>
<h2 id="why-use-aff4">Why use AFF4?</h2>
<p>The AFF4 format is specifically designed to support a wide range of
use cases in forensic evidence capture and preservation. Some of the
benefits of using AFF4 over another proprietary format are</p>
<ul>
<li><p>The AFF4 format is an opened standard with many open source
<li>
<p>The AFF4 format is an opened standard with many open source
implementations in a variery of languages. The format itself is very
simple and so it will always be possible to extract data even
without an proper implementation.</p></li>
<li><p>AFF4 storage is designed around the widely used Zip file
without an proper implementation.</p>
</li>
<li>
<p>AFF4 storage is designed around the widely used Zip file
format. This means that you can use typical Zip recovery utilities
to repair corrupted images, inspect the content of images etc.</p></li>
<li><p>AFF4 supports multiple streams within the same volume. This allows
to repair corrupted images, inspect the content of images etc.</p>
</li>
<li>
<p>AFF4 supports multiple streams within the same volume. This allows
multiple sources of evidence to be captured into the same case
file. For example, related memory, disk and logical file streams can
be handled simultaneously. WinPmem uses this property to store
memory images in the same volume as important files like drivers and
kernel image, thus assisting the analysis phase.</p></li>
<li><p>AFF4 supports sparse streams (using the Map stream type). This is
kernel image, thus assisting the analysis phase.</p>
</li>
<li>
<p>AFF4 supports sparse streams (using the Map stream type). This is
useful for representing memory images (which might have gaps in
them) as well as simply representing read errors (rather than simply
zero padding them).</p></li>
<li><p>AFF4 supports arbitrary metadata as RDF statements.</p></li>
zero padding them).</p>
</li>
<li>
<p>AFF4 supports arbitrary metadata as RDF statements.</p>
</li>
</ul>
<p>The Pmem memory acquisition suite includes the <em>WinPmem</em>, <em>OSXPmem</em>
and <em>LinPmem</em> tool. Each tool implements memory acquisition for its
respective OS but all use largely the same options. All the below
commands should also work on any tools in the pmem suite. For
simplicity we demonstrate with WinPmem.</p>
<p>You can download_ the latest release of the aff4 imager through the
<a href="https://github.com/Velocidex/c-aff4/releases">project&rsquo;s release page</a>. Releases are
statically built for their respective platforms in order to ensure
that they can be easily deployed with minimal system requirements -
even on very old systems. You do not need to include any runtime
dependencies (like Visual C runtimes).</p>
<p>The following section describes how to use the imager effectively. You
can get some helpful messages from the imager itself when run with the
<em>&ndash;help</em> flag.</p>
@@ -222,7 +219,7 @@ can get some helpful messages from the imager itself when run with the
<script type="text/javascript" src="/js/scripts.min.bf1e1f7ae8e03db5f012356e825843facdff51c0a559cb0d27fe2bbe1db405c2.js"></script>
<script type="text/javascript" src="/js/scripts.min.1237ff71925bb8625c97a9af8db4c54525258bedfd7c47493daaff723bea755e.js"></script>
+2 -2
View File
@@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta name="generator" content="Hugo 0.56.0-DEV" />
<meta name="generator" content="Hugo 0.75.1" />
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>WinPmem memory imager</title>
@@ -154,7 +154,7 @@ include WinPmem, OSXPmem and LinPmem.</p>
<script type="text/javascript" src="/js/scripts.min.bf1e1f7ae8e03db5f012356e825843facdff51c0a559cb0d27fe2bbe1db405c2.js"></script>
<script type="text/javascript" src="/js/scripts.min.1237ff71925bb8625c97a9af8db4c54525258bedfd7c47493daaff723bea755e.js"></script>
+3 -7
View File
@@ -1,15 +1,11 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>The Pmem Suite on WinPmem memory imager</title>
<link>https://winpmem.velocidex.com/</link>
<description>Recent content in The Pmem Suite on WinPmem memory imager</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<atom:link href="https://winpmem.velocidex.com/index.xml" rel="self" type="application/rss+xml" />
<language>en-us</language><atom:link href="https://winpmem.velocidex.com/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Overview</title>
<link>https://winpmem.velocidex.com/docs/usage/</link>
@@ -62,4 +58,4 @@ Extract streams by using wild cards WinPmem.exe -e &amp;#39;*/kallsyms&amp;#39;
</item>
</channel>
</rss>
</rss>
@@ -0,0 +1,6 @@
var body=document.querySelector('body')
var menuTrigger=document.querySelector('#toggle-main-menu-mobile');var menuContainer=document.querySelector('#main-menu-mobile');menuTrigger.onclick=function(){menuContainer.classList.toggle('open');menuTrigger.classList.toggle('is-active')
body.classList.toggle('lock-scroll')}
var content=document.querySelector('.content.anchor-link-enabled')
if(content){addHeaderAnchors(content);}
function addHeaderAnchors(content){var headers=content.querySelectorAll('h1, h2, h3, h4');var linkSvg=' <svg xmlns="http://www.w3.org/2000/svg" width="16px" height="16px" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"></path><path d="M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z"/></svg>';var anchorForId=function(id){var anchor=document.createElement('a');anchor.classList.add('header-anchor');anchor.href="#"+id;anchor.innerHTML=linkSvg;return anchor;};for(var h=0;h<headers.length;h++){var header=headers[h];if(typeof header.id!=="undefined"&&header.id!==""){header.appendChild(anchorForId(header.id));}}}
@@ -1,3 +0,0 @@
var body=document.querySelector('body')
var menuTrigger=document.querySelector('#toggle-main-menu-mobile');var menuContainer=document.querySelector('#main-menu-mobile');menuTrigger.onclick=function(){menuContainer.classList.toggle('open');menuTrigger.classList.toggle('is-active')
body.classList.toggle('lock-scroll')}
+2 -4
View File
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xhtml="http://www.w3.org/1999/xhtml">
@@ -28,16 +28,14 @@
<url>
<loc>https://winpmem.velocidex.com/categories/</loc>
<priority>0</priority>
</url>
<url>
<loc>https://winpmem.velocidex.com/tags/</loc>
<priority>0</priority>
</url>
<url>
<loc>https://winpmem.velocidex.com/</loc>
</url>
</urlset>
</urlset>
+1 -1
View File
@@ -126,7 +126,7 @@
<script type="text/javascript" src="/js/scripts.min.bf1e1f7ae8e03db5f012356e825843facdff51c0a559cb0d27fe2bbe1db405c2.js"></script>
<script type="text/javascript" src="/js/scripts.min.1237ff71925bb8625c97a9af8db4c54525258bedfd7c47493daaff723bea755e.js"></script>
+3 -7
View File
@@ -1,14 +1,10 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Tags on WinPmem memory imager</title>
<link>https://winpmem.velocidex.com/tags/</link>
<description>Recent content in Tags on WinPmem memory imager</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<atom:link href="https://winpmem.velocidex.com/tags/index.xml" rel="self" type="application/rss+xml" />
<language>en-us</language><atom:link href="https://winpmem.velocidex.com/tags/index.xml" rel="self" type="application/rss+xml" />
</channel>
</rss>
</rss>
+207
View File
@@ -0,0 +1,207 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2012 Michael Cohen <scudette@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Please note: The Winpmem project is release under the Apache license. This means
that all files under the path tools/windows/winpmem/ are released under the
Apache license, despite residing in the Rekall code repository (Which is GPL).
+210
View File
@@ -0,0 +1,210 @@
WinPMEM - a kernel mode driver for gaining access to physical memory.
Version 1.3
Copyright 2012 Michael Cohen <scudette@gmail.com>
This is a physical memory imager which implements the following features:
- This code builds on 64 bit windows as well as 32 bit windows.
- A read device interface is used instead of writing the image from the kernel
like some other imagers. This allows us to have complex userspace imager
(e.g. copy across network, hash etc), as well as run analysis on the live
system (e.g. rekall can be run directly on the device).
- The userspace component can write crash dumps of 32 and 64 bit systems.
- The image can be written to stdout (using an output filename of "-"). This can
then be piped using the usual ways (netcat, ssh etc).
The files in this directory (Including the winpmem sources and signed binaries),
are available under the following license: Apache License, Version 2.0
How to use these drivers.
=========================
There are two user space programs that can be used to acquire memory images. The
python acquitision program demonstrates how to use the driver from python and
can be easily extended to handle the image in another way (e.g. compress, hash,
send across the network etc).
The winpmem_1.3.exe program is a self contained binary with both 32 and 64 bit
drivers embedded. It is the easiest and most recommended to use for incident
response since it requires no external dependencies, and automatically installs
the correct driver.
The Python acquitision tool winpmem.py
--------------------------------------
This release comes with signed binary drivers and a python program which uses
this driver to create raw images. (Note that in order to load the driver on 64
bit windows the driver _must_ be signed). Below we assume we are running on a 64
bit system. The driver for 32 bit systems can be found in
binaries\i386\winpmem_32.sys.
To get help about the acquisition tool:
c:\..> winpmem.py -h
Usage: winpmem.py [options]
Options:
-h, --help show this help message and exit
-d FILE, --driver=FILE
The driver location (winpmem.sys)
-f FILE, --filename=FILE
write image to FILE
-n NAME, --name=NAME The name of the device.
-m MODE, --mode=MODE The acquisition mode. Can be (physical or iospace)
-l, --load Only load the driver and immediately quit. (Useful
just before attaching with rekall)
-u, --unload Unload the driver and immediately quit.
To acquire memory into the file foobar.raw:
c:\..> winpmem.py -d binaries\amd64\winpmem_64.sys -f foobar.raw
CR3 = 0x187000
Memory ranges:
Start Length
0x1000 0x9E000
0x100000 0x6F6FB000
Imaging to foo.raw
Padding from 0x0 to 0x1000
0000MB .
Padding from 0x9F000 to 0x100000
................................................
0050MB ..................................................
0100MB ..................................................
0150MB ..................................................
0200MB ..................................................
0250MB ..................................................
Note that CR3 and the valid physical memory ranges are reported.
Normally when acquiring memory we load the driver, acquire the memory, then
unload the driver. To use rekall on the raw memory we need to leave the
driver loaded:
c:\..> winpmem.py -d binaries\amd64\winpmem.sys -l
Loaded the winpmem driver. You can now attach rekall to \\.\pmem
and once we finished with it we can unload it (Make sure to exit rekall
before unloading the driver):
c:\..> winpmem.py -d binaries\amd64\winpmem.sys -u
(1073, 'CreateService', 'The specified service already exists.')
unloaded winpmem driver.
The self contained binary winpmem.exe
-------------------------------------
This program is easiest to use for incident response since it requires no other
dependencies than the executable itself. The program will load the correct
driver (32 bit or 64 bit) automatically.
c:\..> winpmem_1.3.exe -h
Winpmem - A memory imager for windows.
Copyright Michael Cohen (scudette@gmail.com) 2012.
Version 1.3. Built Nov 12 2012
Usage:
winpmem_1.3.exe [option] [output path]
Option:
-l Load the driver and exit.
-u Unload the driver and exit.
-h Display this help.
-w Turn on/off write mode.
-1 Use MmMapIoSpace method.
-2 Use \\Device\PhysicalMemory method (Default).
-d Produce a crashdump file.
NOTE: an output filename of - will write the image to STDOUT.
Examples:
winpmem_1.3.exe physmem.raw
Writes a raw image to physmem.raw
winpmem_1.3.exe -d - | nc 192.168.1.1 80
Writes a crashdump file to netcat for network transport. Output is supressed
here because STDOUT is redirected.
To load the driver and exit:
c:\..> winpmem.exe -l
Loaded Driver.
To unload the driver and exit:
c:\..> winpmem.exe -u
Driver Unloaded.
To acquire a raw image using the MmMapIoSpace method:
c:\..> winpmem_1.3.exe -1 myimage.raw
The driver will be automatically unloaded after the image is acquired.
To acquire an image in crashdump format:
c:\..>winpmem_1.3.exe -d c:\temp\test.dmp
Driver Unloaded.
Loaded Driver C:\Users\mic\AppData\Local\Temp\win6C6.tmp.
Will write a crash dump file
CR3: 0x0000187000
2 memory ranges:
Start 0x00001000 - Length 0x0009E000
Start 0x00100000 - Length 0x6F6FB000
00% 0x00001000 .
00% 0x00100000 ..................................................
02% 0x03300000 ..................................................
05% 0x06500000 ..................................................
...
92% 0x67300000 ..................................................
95% 0x6A500000 ..................................................
98% 0x6D700000 .................................
Driver Unloaded.
Experimental write support
--------------------------
As from Version 1.1, the winpmem drivers support writing to memory as well as
reading. This capability is a great learning tool since many rootkit hiding
techniques can be emulated by writing to memory directly. For example the
following Rekall session illustrates changing the name of the binary:
WinXPSP2x86:pmem 03:10:40> task = session.profile._EPROCESS(0x82079c18)
WinXPSP2x86:pmem 03:10:57> task.ImageFileName
Out<3> [String:ImageFileName]: 'cmd.exe\x00'
WinXPSP2x86:pmem 03:11:15> task.ImageFileName = "foo.exe\x00"
WinXPSP2x86:pmem 03:11:21> task.ImageFileName
Out<6> [String:ImageFileName]: 'foo.exe\x00'
NOTE: Since this is a rather dangerous capability, the signed binary drivers
have write support disabled. The unsigned binaries (really self signed with a
test certificate) can not load on a regular system due to them being test self
signed. You can allow the unsigned drivers to be loaded on a test system by
issuing (see
http://msdn.microsoft.com/en-us/library/windows/hardware/ff553484(v=vs.85).aspx):
Bcdedit.exe -set TESTSIGNING ON
and reboot. You will see a small "Test Mode" text on the desktop to remind you
that this machine is configured for test signed drivers.
Alternatively you can test this on XP or Vista32 which have no driver signing
restrictions.
Additionally, Write support must also be enabled at load time:
winpmem_1.3-write.exe -w -l
This will load the drivers and turn on write support. Then we can run rekall
interactively, as usual on the raw device:
vol.exe --profile Win7SP1x64 --file \\.\pmem
+16
View File
@@ -0,0 +1,16 @@
TARGETNAME=winpmem
TARGETTYPE=DRIVER
TARGETPATH=release
TARGETLIBS=$(DDK_LIB_PATH)\wdmsec.lib
DDKROOT=$(BASEDIR)
LINKER_FLAGS=$(LINKER_FLAGS) /PDBALTPATH:x.pdb
INCLUDES=$(DDK_INC_PATH);
SOURCES= winpmem.c \
read.c \
api.c \
kd.c \
pte_mmap.c \
pte_mmap_windows.c \
pci.c
+1
View File
@@ -0,0 +1 @@
This directory contains the MSVC 14 project files for building the driver.
+87
View File
@@ -0,0 +1,87 @@
;
; winpmem.inf
;
[Version]
Signature="$WINDOWS NT$"
Class=USBDevice
ClassGuid={88BAE032-5A81-49f0-BC3D-A4FF138216D6}
Provider=%ManufacturerName%
CatalogFile=winpmem.cat
DriverVer=
[DestinationDirs]
DefaultDestDir = 12
winpmem_Device_CoInstaller_CopyFiles = 11
[SourceDisksNames]
1 = %DiskName%,,,""
[SourceDisksFiles]
winpmem.sys = 1,,
WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll=1 ; make sure the number matches with SourceDisksNames
;*****************************************
; Install Section
;*****************************************
[Manufacturer]
%ManufacturerName%=Standard,NT$ARCH$
[Standard.NT$ARCH$]
%winpmem.DeviceDesc%=winpmem_Device, USB\VID_vvvv&PID_pppp
[winpmem_Device.NT]
CopyFiles=Drivers_Dir
[Drivers_Dir]
winpmem.sys
[winpmem_Device.NT.HW]
AddReg=winpmem_AddReg
[winpmem_AddReg]
; By default, USBDevice class uses iProduct descriptor to name the device in
; Device Manager on Windows 8 and higher.
; Uncomment for this device to use %DeviceName% on Windows 8 and higher:
;HKR,,FriendlyName,,%winpmem.DeviceDesc%
;-------------- Service installation
[winpmem_Device.NT.Services]
AddService = winpmem,%SPSVCINST_ASSOCSERVICE%, winpmem_Service_Inst
; -------------- winpmem driver install sections
[winpmem_Service_Inst]
DisplayName = %winpmem.SVCDESC%
ServiceType = 1 ; SERVICE_KERNEL_DRIVER
StartType = 3 ; SERVICE_DEMAND_START
ErrorControl = 1 ; SERVICE_ERROR_NORMAL
ServiceBinary = %12%\winpmem.sys
;
;--- winpmem_Device Coinstaller installation ------
;
[winpmem_Device.NT.CoInstallers]
AddReg=winpmem_Device_CoInstaller_AddReg
CopyFiles=winpmem_Device_CoInstaller_CopyFiles
[winpmem_Device_CoInstaller_AddReg]
HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller"
[winpmem_Device_CoInstaller_CopyFiles]
WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll
[winpmem_Device.NT.Wdf]
KmdfService = winpmem, winpmem_wdfsect
[winpmem_wdfsect]
KmdfLibraryVersion = $KMDFVERSION$
[Strings]
SPSVCINST_ASSOCSERVICE= 0x00000002
ManufacturerName="<Your manufacturer name>" ;TODO: Replace with your manufacturer name
ClassName="Universal Serial Bus devices"
DiskName = "winpmem Installation Disk"
winpmem.DeviceDesc = "winpmem Device"
winpmem.SVCDESC = "winpmem Service"
REG_MULTI_SZ = 0x00010000
+158
View File
@@ -0,0 +1,158 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<None Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\api.c" />
<ClCompile Include="..\kd.c" />
<ClCompile Include="..\pci.c" />
<ClCompile Include="..\pte_mmap.c" />
<ClCompile Include="..\pte_mmap_windows.c" />
<ClCompile Include="..\read.c" />
<ClCompile Include="..\winpmem.c" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{8BAC86C0-A3EA-4652-92BF-C51C0DF5D86C}</ProjectGuid>
<TemplateGuid>{8c0e3d8b-df43-455b-815a-4a0e72973bc6}</TemplateGuid>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<MinimumVisualStudioVersion>12.0</MinimumVisualStudioVersion>
<Configuration>Debug</Configuration>
<Platform Condition="'$(Platform)' == ''">Win32</Platform>
<RootNamespace>winpmem</RootNamespace>
</PropertyGroup>
<PropertyGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
<ConfigurationType>Driver</ConfigurationType>
<DriverType>KMDF</DriverType>
<DriverTargetPlatform>Universal</DriverTargetPlatform>
</PropertyGroup>
<PropertyGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
<ConfigurationType>Driver</ConfigurationType>
<DriverType>KMDF</DriverType>
<DriverTargetPlatform>Universal</DriverTargetPlatform>
</PropertyGroup>
<PropertyGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
<ConfigurationType>Driver</ConfigurationType>
<DriverType>KMDF</DriverType>
<DriverTargetPlatform>Universal</DriverTargetPlatform>
</PropertyGroup>
<PropertyGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
<ConfigurationType>Driver</ConfigurationType>
<DriverType>KMDF</DriverType>
<DriverTargetPlatform>Universal</DriverTargetPlatform>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<TargetVersion>Windows10</TargetVersion>
<UseDebugLibraries>true</UseDebugLibraries>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<TargetVersion>Windows10</TargetVersion>
<UseDebugLibraries>false</UseDebugLibraries>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<TargetVersion>Windows10</TargetVersion>
<UseDebugLibraries>true</UseDebugLibraries>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<TargetVersion>Windows10</TargetVersion>
<UseDebugLibraries>false</UseDebugLibraries>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WppEnabled>true</WppEnabled>
<WppRecorderEnabled>true</WppRecorderEnabled>
<WppKernelMode>true</WppKernelMode>
<TreatWarningAsError>false</TreatWarningAsError>
<SupportJustMyCode>false</SupportJustMyCode>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies);usbdex.lib;ntstrsafe.lib;wdmsec.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WppEnabled>true</WppEnabled>
<WppRecorderEnabled>true</WppRecorderEnabled>
<WppKernelMode>true</WppKernelMode>
<TreatWarningAsError>false</TreatWarningAsError>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies);usbdex.lib;ntstrsafe.lib;wdmsec.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WppEnabled>true</WppEnabled>
<WppRecorderEnabled>true</WppRecorderEnabled>
<WppKernelMode>true</WppKernelMode>
<TreatWarningAsError>false</TreatWarningAsError>
<SupportJustMyCode>false</SupportJustMyCode>
<LanguageStandard>stdcpp14</LanguageStandard>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies);usbdex.lib;ntstrsafe.lib;wdmsec.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WppEnabled>true</WppEnabled>
<WppRecorderEnabled>true</WppRecorderEnabled>
<WppKernelMode>true</WppKernelMode>
<TreatWarningAsError>false</TreatWarningAsError>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<LanguageStandard>stdcpp14</LanguageStandard>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies);usbdex.lib;ntstrsafe.lib;wdmsec.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<FilesToPackage Include="$(TargetPath)" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
+47
View File
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Driver Files">
<UniqueIdentifier>{8E41214B-6785-4CFE-B992-037D68949A14}</UniqueIdentifier>
<Extensions>inf;inv;inx;mof;mc;</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\api.c">
<Filter>Driver Files</Filter>
</ClCompile>
<ClCompile Include="..\kd.c">
<Filter>Driver Files</Filter>
</ClCompile>
<ClCompile Include="..\pci.c">
<Filter>Driver Files</Filter>
</ClCompile>
<ClCompile Include="..\pte_mmap.c">
<Filter>Driver Files</Filter>
</ClCompile>
<ClCompile Include="..\pte_mmap_windows.c">
<Filter>Driver Files</Filter>
</ClCompile>
<ClCompile Include="..\read.c">
<Filter>Driver Files</Filter>
</ClCompile>
<ClCompile Include="..\winpmem.c">
<Filter>Driver Files</Filter>
</ClCompile>
</ItemGroup>
</Project>
+14
View File
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<EnableVerifier>False</EnableVerifier>
<AllDrivers>False</AllDrivers>
<VerifyProjectOutput>True</VerifyProjectOutput>
<VerifyDrivers />
<VerifyFlags>133563</VerifyFlags>
<TestCertificate>CN="WDKTestCert mic,131384300355942867" | 7EA426631F0B9F382BA48901017D8EF0D2B1AD4F</TestCertificate>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>
+81
View File
@@ -0,0 +1,81 @@
#include "winpmem.h"
#include "api.h"
#include "kd.h"
struct Pmem_KernelExports_t Pmem_KernelExports;
NTSTATUS PmemGetProcAddresses() {
void *image_base = KernelGetModuleBaseByPtr(NtBuildNumber);
char key[sizeof(OBFUSCATION_KEY)] = OBFUSCATION_KEY;
void *api = NULL;
RtlZeroMemory(&Pmem_KernelExports, sizeof(Pmem_KernelExports));
if (!image_base) {
goto error;
};
// If any of the below APIs fail, they will have a NULL pointer in the export
// table - this will cause that acquisition method to be rejected.
if (image_base) {
{
int i;
char parameter[sizeof(X_MmGetPhysicalMemoryRanges)] =
X_MmGetPhysicalMemoryRanges;
for(i=0; i<min(sizeof(parameter), sizeof(key)); i++) {
parameter[i] ^= key[i];
};
WinDbgPrint("Fetching API %s\n", parameter);
api = KernelGetProcAddress(image_base, parameter);
Pmem_KernelExports.MmGetPhysicalMemoryRanges = api;
};
{
int i;
char parameter[sizeof(X_MmGetVirtualForPhysical)] =
X_MmGetVirtualForPhysical;
for(i=0; i<min(sizeof(parameter), sizeof(key)); i++) {
parameter[i] ^= key[i];
};
WinDbgPrint("Fetching API %s\n", parameter);
api = KernelGetProcAddress(image_base, parameter);
Pmem_KernelExports.MmGetVirtualForPhysical = api;
};
{
int i;
char parameter[sizeof(X_MmMapIoSpace)] = X_MmMapIoSpace;
for(i=0; i<min(sizeof(parameter), sizeof(key)); i++) {
parameter[i] ^= key[i];
};
WinDbgPrint("Fetching API %s\n", parameter);
api = KernelGetProcAddress(image_base, parameter);
Pmem_KernelExports.MmMapIoSpace = api;
};
{
int i;
char parameter[sizeof(X_MmUnmapIoSpace)] = X_MmUnmapIoSpace;
for(i=0; i<min(sizeof(parameter), sizeof(key)); i++) {
parameter[i] ^= key[i];
};
WinDbgPrint("Fetching API %s\n", parameter);
api = KernelGetProcAddress(image_base, parameter);
Pmem_KernelExports.MmUnmapIoSpace = api;
};
};
return STATUS_SUCCESS;
error:
return STATUS_INVALID_PARAMETER;
};
+32
View File
@@ -0,0 +1,32 @@
// This module uses obfuscated GetProcAddress calls to load certain functions
// which are usually only used by memory acquisition tools. This makes it a
// little bit harder to recognize us as an acquisition tool.
#ifndef _API_H_
#define _API_H_
#include <ntifs.h>
#include <wdmsec.h>
#include <initguid.h>
#include <stdarg.h>
#include <stdio.h>
// Select a better/different key or obfuscation scheme here.
#define OBFUSCATION_KEY "\x43\x73\x17\x54\x19\x3C\x42\xE5\xA2\x6B\x7C\x8A\x1C\x2E\x5C\x2C\x95\xCD\xC8\x3A\x68\x54\xEE\xC9\x36\x55\xCB\xE9\x4D\x98\x05\x04\x20\x5E\x77\x0F\xCD\x09\x35\xAF\x4C\xF8\x45\x22\x12\x30\x8F\xCB\x55\xC4"
#define X_MmGetPhysicalMemoryRanges "\x0E\x1E\x50\x31\x6D\x6C\x2A\x9C\xD1\x02\x1F\xEB\x70\x63\x39\x41\xFA\xBF\xB1\x68\x09\x3A\x89\xAC\x45\x55"
#define X_MmGetVirtualForPhysical "\x0E\x1E\x50\x31\x6D\x6A\x2B\x97\xD6\x1E\x1D\xE6\x5A\x41\x2E\x7C\xFD\xB4\xBB\x53\x0B\x35\x82\xC9"
#define X_MmMapIoSpace "\x0E\x1E\x5A\x35\x69\x75\x2D\xB6\xD2\x0A\x1F\xEF\x1C"
#define X_MmUnmapIoSpace "\x0E\x1E\x42\x3A\x74\x5D\x32\xAC\xCD\x38\x0C\xEB\x7F\x4B\x5C"
struct Pmem_KernelExports_t {
PHYSICAL_MEMORY_RANGE *(*MmGetPhysicalMemoryRanges)();
void *(*MmGetVirtualForPhysical)(PHYSICAL_ADDRESS);
unsigned char *(*MmMapIoSpace)(LARGE_INTEGER, int, int);
void (*MmUnmapIoSpace)(unsigned char *, int);
};
extern struct Pmem_KernelExports_t Pmem_KernelExports;
NTSTATUS PmemGetProcAddresses();
#endif _API_H_
+32
View File
@@ -0,0 +1,32 @@
// This module uses obfuscated GetProcAddress calls to load certain functions
// which are usually only used by memory acquisition tools. This makes it a
// little bit harder to recognize us as an acquisition tool.
#ifndef _API_H_
#define _API_H_
#include <ntifs.h>
#include <wdmsec.h>
#include <initguid.h>
#include <stdarg.h>
#include <stdio.h>
// Select a better/different key or obfuscation scheme here.
#define OBFUSCATION_KEY "%(key)s"
#define X_MmGetPhysicalMemoryRanges "%(MmGetPhysicalMemoryRanges)s"
#define X_MmGetVirtualForPhysical "%(MmGetVirtualForPhysical)s"
#define X_MmMapIoSpace "%(MmMapIoSpace)s"
#define X_MmUnmapIoSpace "%(MmUnmapIoSpace)s"
struct Pmem_KernelExports_t {
PHYSICAL_MEMORY_RANGE *(*MmGetPhysicalMemoryRanges)();
void *(*MmGetVirtualForPhysical)(PHYSICAL_ADDRESS);
unsigned char *(*MmMapIoSpace)(LARGE_INTEGER, int, int);
void (*MmUnmapIoSpace)(unsigned char *, int);
};
extern struct Pmem_KernelExports_t Pmem_KernelExports;
NTSTATUS PmemGetProcAddresses();
#endif _API_H_
+185
View File
@@ -0,0 +1,185 @@
/*
Copyright 2012 Michael Cohen <scudette@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "kd.h"
/*
This code inspired and updated from
http://alter.org.ua/docs/nt_kernel/procaddr/#KernelGetModuleBaseByPtr
We try to locate the kernel's base address. We do this by looking for an MZ
header a short space before the location of a known exported symbol.
Unfortunately we might hit unmapped kernel memory which will blue screen so we
need to check if the kernel address is at all valid.
*/
IMAGE_DOS_HEADER *KernelGetModuleBaseByPtr(IN void *in_section) {
unsigned char *p;
IMAGE_DOS_HEADER *dos = NULL;
IMAGE_NT_HEADERS *nt;
int count = 0;
p = (unsigned char *)((uintptr_t)in_section & ~(PAGE_SIZE-1));
for(;p;p -= PAGE_SIZE) {
count ++;
// Dont go back too far.
if (count > 0x800) {
return NULL;
};
__try {
dos = (IMAGE_DOS_HEADER *)p;
// If this address is not mapped in, there will be a BSOD
// PAGE_FAULT_IN_NONPAGED_AREA so we check first.
if(!MmIsAddressValid(dos)) {
continue;
}
if(dos->e_magic != 0x5a4d) // MZ
continue;
nt = (IMAGE_NT_HEADERS *)((uintptr_t)dos + dos->e_lfanew);
if((uintptr_t)nt >= (uintptr_t)in_section)
continue;
if((uintptr_t)nt <= (uintptr_t)dos)
continue;
if(!MmIsAddressValid(nt)) {
continue;
}
if(nt->Signature != 0x00004550) // PE
continue;
break;
// Ignore potential errors.
} __except(EXCEPTION_CONTINUE_EXECUTION) {}
}
return dos;
}
/* Resolve a kernel function by name.
*/
void *KernelGetProcAddress(void *image_base, char *func_name) {
void *func_address = NULL;
__try {
int size = 0;
IMAGE_DOS_HEADER *dos =(IMAGE_DOS_HEADER *)image_base;
IMAGE_NT_HEADERS *nt =(IMAGE_NT_HEADERS *)((uintptr_t)image_base + dos->e_lfanew);
IMAGE_DATA_DIRECTORY *expdir = (IMAGE_DATA_DIRECTORY *)
(nt->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_EXPORT);
IMAGE_EXPORT_DIRECTORY *exports =(PIMAGE_EXPORT_DIRECTORY)
((uintptr_t)image_base + expdir->VirtualAddress);
uintptr_t addr = (uintptr_t)exports-(uintptr_t)image_base;
// These are arrays of RVA addresses.
unsigned int *functions = (unsigned int *)((uintptr_t)image_base +
exports->AddressOfFunctions);
unsigned int *names = (unsigned int *)((uintptr_t)image_base +
exports->AddressOfNames);
short *ordinals = (short *)((uintptr_t)image_base +
exports->AddressOfNameOrdinals);
unsigned int max_name = exports->NumberOfNames;
unsigned int max_func = exports->NumberOfFunctions;
unsigned int i;
for (i = 0; i < max_name; i++) {
unsigned int ord = ordinals[i];
if(i >= max_name || ord >= max_func) {
return NULL;
}
if (functions[ord] < addr || functions[ord] >= addr + size) {
if (strcmp((char *)image_base + names[i], func_name) == 0) {
func_address = (char *)image_base + functions[ord];
break;
}
}
}
}
__except(EXCEPTION_EXECUTE_HANDLER) {
func_address = NULL;
}
return func_address;
} // end KernelGetProcAddress()
/* Search for a section by name.
Returns the mapped virtual memory section or NULL if not found.
*/
IMAGE_SECTION_HEADER *GetSection(IMAGE_DOS_HEADER *image_base, char *name) {
IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *)
((uintptr_t)image_base + image_base->e_lfanew);
int i;
int number_of_sections = nt->FileHeader.NumberOfSections;
IMAGE_SECTION_HEADER *sections = (IMAGE_SECTION_HEADER *)
((uintptr_t)&nt->OptionalHeader + nt->FileHeader.SizeOfOptionalHeader);
for (i=0; i<number_of_sections; i++) {
if(!strcmp((char *)sections[i].Name, name))
return &sections[i];
};
return NULL;
};
/*
Enumerate the KPCR blocks from all CPUs.
*/
int GetKPCR(struct PmemMemoryInfo *info) {
__int64 active_processors = KeQueryActiveProcessors();
int i;
for (i=0; i < 32; i++) {
info->KPCR[i].QuadPart = 0;
};
for (i=0; i < 32; i++) {
if (active_processors & ((__int64)1 << i)) {
KeSetSystemAffinityThread((__int64)1 << i);
#if _WIN64 || __amd64__
//64 bit uses gs and _KPCR.Self is at 0x18:
info->KPCR[i].QuadPart = (uintptr_t)__readgsqword(0x18);
#else
//32 bit uses fs and _KPCR.SelfPcr is at 0x1c:
info->KPCR[i].QuadPart = (uintptr_t)__readfsword(0x1c);
#endif
};
};
KeRevertToUserAffinityThread();
return 1;
};
+29
View File
@@ -0,0 +1,29 @@
/*
Copyright 2012 Michael Cohen <scudette@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef _WINPMEM_KD_H
#define _WINPMEM_KD_H
#include "winpmem.h"
#include "ntimage.h"
IMAGE_DOS_HEADER *KernelGetModuleBaseByPtr(IN void *in_section);
void *KernelGetProcAddress(void *image_base, char *func_name);
int GetKPCR(struct PmemMemoryInfo *info);
#endif // _WINPMEM_KD_H
+26
View File
@@ -0,0 +1,26 @@
import random
class Interpolator(object):
def __init__(self):
self.key = [random.randint(1, 255) for _ in range(50)]
def __getitem__(self, item):
if item == "key":
return "".join(["\\x%02X" % x for x in self.key])
# Add a NULL terminator
item += "\x00"
# Xor with the key.
return "".join(["\\x%02X" % (ord(y) ^ x)
for x, y in zip(self.key, item)])
def interpolate_file(filename):
data = open(filename + ".in", "rb").read()
with open(filename, "wb") as fd:
fd.write(data % Interpolator())
interpolate_file("api.h")
Executable
+399
View File
@@ -0,0 +1,399 @@
#include "pci.h"
u32 read_pci_config(u8 bus, u8 slot, u8 func, u8 offset) {
u32 v;
__outdword(PCI_CONFIG_ADDRESS,
0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset);
v = __indword(PCI_CONFIG_DATA);
return v;
}
void write_pci_config(u8 bus, u8 slot, u8 func, u8 offset, u32 value) {
__outdword(PCI_CONFIG_ADDRESS,
0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset);
__outdword(PCI_CONFIG_DATA, value);
}
void write_pci_config_16(u8 bus, u8 slot, u8 func, u8 offset, u16 value) {
__outdword(PCI_CONFIG_ADDRESS,
0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset);
__outword(PCI_CONFIG_DATA, value);
}
u8 read_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset) {
u8 v;
__outdword(PCI_CONFIG_ADDRESS,
0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset);
v = __inbyte(PCI_CONFIG_DATA + (offset&3));
return v;
}
u16 read_pci_config_16(u8 bus, u8 slot, u8 func, u8 offset) {
u16 v;
__outdword(PCI_CONFIG_ADDRESS,
0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset);
v = __inword(PCI_CONFIG_DATA + (offset&2));
return v;
}
u32 get_base_register_size(u8 bus, u8 slot, u8 func, u8 offset) {
__int32 base = read_pci_config(bus, slot, func, offset);
u32 mask = 0;
u16 command =0;
if (base == 0) return 0;
command = read_pci_config_16(bus, slot, func, PCI_COMMAND);
// Disable IO and memory bus access.
write_pci_config_16(bus, slot, func, PCI_COMMAND, 0);
// Write to config space all 0xFFFFFFFF
write_pci_config(bus, slot, func, offset, 0xFFFFFFFF);
mask = read_pci_config(bus, slot, func, offset) & 0xFFFFFFF0;
write_pci_config(bus, slot, func, offset, base);
// Reenable bus access.
write_pci_config_16(bus, slot, func, PCI_COMMAND, command);
return ~mask + base;
};
#if WINPMEM_PCI_DEBUG
// Debugging functions for dumping out PCI configuration data.
void dump_interesting_fields(u8 bus, u8 slot, u8 func) {
u16 vendor_id = read_pci_config_16(bus, slot, func, PCI_VENDOR_ID);
u16 device_id = read_pci_config_16(bus, slot, func, PCI_DEVICE_ID);
WinDbgPrint("pci 0000:%02x:%02x.%d ", bus, slot, func);
WinDbgPrint("Id %04x:%04x config space:\n", vendor_id, device_id);
};
void dump_bar(u8 bus, u8 slot, u8 func) {
u16 vendor_id = read_pci_config_16(bus, slot, func, PCI_VENDOR_ID);
u16 device_id = read_pci_config_16(bus, slot, func, PCI_DEVICE_ID);
u32 base0 = read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_0);
u32 base1 = read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_1);
u32 base2 = read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_2);
u32 base3 = read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_3);
u32 base4 = read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_4);
u32 base5 = read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_5);
WinDbgPrint("Base Addresses: %08X %08X %08X %08X %08X %08X\n",
base0, base1, base2, base3, base4, base5);
WinDbgPrint("Masks: %08X %08X %08X %08X %08X %08X\n",
get_base_register_size(bus, slot, func, PCI_BASE_ADDRESS_0),
get_base_register_size(bus, slot, func, PCI_BASE_ADDRESS_1),
get_base_register_size(bus, slot, func, PCI_BASE_ADDRESS_2),
get_base_register_size(bus, slot, func, PCI_BASE_ADDRESS_3),
get_base_register_size(bus, slot, func, PCI_BASE_ADDRESS_4),
get_base_register_size(bus, slot, func, PCI_BASE_ADDRESS_5));
}
void DumpConfigSpace(u8 bus, u8 slot, u8 func) {
u8 i, j;
for(i=0; i<0x80; i+=0x10) {
WinDbgPrint("0x%02X ", i);
for(j=i; j<i+0x10; j++) {
u8 b = read_pci_config_byte(bus, slot, func, j);
WinDbgPrint("%02X ", b);
};
WinDbgPrint("\n");
}
};
void DumpRuns(struct PmemMemoryInfo *info) {
int i;
for(i=0; i<info->NumberOfRuns.QuadPart; i++) {
WinDbgPrint("0x%llx 0x%llx 0x%llx\n", info->Run[i].BaseAddress.QuadPart,
info->Run[i].BaseAddress.QuadPart + info->Run[i].NumberOfBytes.QuadPart,
info->Run[i].NumberOfBytes.QuadPart);
};
};
#endif
static NTSTATUS InsertMemoryHole(struct PmemMemoryInfo *info, int len,
u64 start, u64 end) {
int i;
#if WINPMEM_PCI_DEBUG
WinDbgPrint("Inserting memory hole at Start %llX end %llx\n", start, end);
#endif
// Round start and end to page boundaries.
start = start & 0xFFFFFFFFFFFFF000;
end = end | 0xFFF;
if (start == end){
goto exit;
};
for (i=0; i<info->NumberOfRuns.QuadPart; i++) {
PHYSICAL_MEMORY_RANGE Run = info->Run[i];
u64 run_start = Run.BaseAddress.QuadPart;
u64 run_end = Run.BaseAddress.QuadPart + Run.NumberOfBytes.QuadPart;
if (run_start < start && start < run_end) {
// Make some room for a new entry.
RtlMoveMemory(&info->Run[i+1], &info->Run[i],
sizeof(Run) * (info->NumberOfRuns.LowPart - i));
info->NumberOfRuns.QuadPart++;
info->Run[i].NumberOfBytes.QuadPart = start - run_start - 1;
info->Run[i+1].BaseAddress.QuadPart = start;
info->Run[i+1].NumberOfBytes.QuadPart = run_end - start - 1;
continue;
};
if (run_start < end && end < run_end) {
info->Run[i].BaseAddress.QuadPart = end + 1;
info->Run[i].NumberOfBytes.QuadPart = run_end - end - 1;
goto exit;
};
};
exit:
#if WINPMEM_PCI_DEBUG
DumpRuns(info);
#endif
return STATUS_SUCCESS;
};
static NTSTATUS DumpBaseAddressRegister32(u8 bus, u8 slot, u8 func, u8 offset,
struct PmemMemoryInfo *info, int len) {
u32 mask = 0;
u32 base = read_pci_config(bus, slot, func, offset);
u16 command = read_pci_config_16(bus, slot, func, PCI_COMMAND);
// Disable IO and memory bus access.
write_pci_config_16(bus, slot, func, PCI_COMMAND, 0);
write_pci_config(bus, slot, func, offset, 0xFFFFFFFF);
mask = read_pci_config(bus, slot, func, offset) & 0xFFFFFFF0;
write_pci_config(bus, slot, func, offset, base);
// Reenable bus access.
write_pci_config_16(bus, slot, func, PCI_COMMAND, command);
base = base & 0xFFFFFFF0;
return InsertMemoryHole(info, len, base, ~mask + base);
};
static NTSTATUS DumpBaseAddressRegister64(u8 bus, u8 slot, u8 func, u8 offset,
struct PmemMemoryInfo *info, int len) {
u64 base = read_pci_config(bus, slot, func, offset);
u32 base_high = read_pci_config(bus, slot, func, offset + sizeof(u32));
u32 mask = 0;
u32 mask_high = 0;
u64 end = 0;
u16 command = read_pci_config_16(bus, slot, func, PCI_COMMAND);
// Disable IO and memory bus access.
write_pci_config_16(bus, slot, func, PCI_COMMAND, 0);
// Check the lower word first.
write_pci_config(bus, slot, func, offset, 0xFFFFFFFF);
mask = read_pci_config(bus, slot, func, offset) & 0xFFFFFFF0;
write_pci_config(bus, slot, func, offset, (u32)base);
// Check the upper 32 bit word.
write_pci_config(bus, slot, func, offset + sizeof(u32), 0xFFFFFFFF);
mask_high = read_pci_config(bus, slot, func, offset + sizeof(u32));
write_pci_config(bus, slot, func, offset + sizeof(u32), (u32)base_high);
// Reenable bus access.
write_pci_config_16(bus, slot, func, PCI_COMMAND, command);
base = ((base & 0xFFFFFFF0) | ((u64)base_high) << 32);
end = ~(mask | ((u64)mask_high) << 32) + base;
return InsertMemoryHole(info, len, base, end);
};
// Advances the offset depending on the size of the base address register.
static NTSTATUS DumpBaseAddressRegister(u8 bus, u8 slot, u8 func, u8 *offset,
struct PmemMemoryInfo *info, int len) {
u64 base = read_pci_config(bus, slot, func, *offset) & 0xFFFFFFFF;
if (base == 0) {
*offset += sizeof(u32);
return STATUS_SUCCESS;
};
// We skip IO space registers since they are not interesting for memory
// acquisition.
if ((base & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
*offset += sizeof(u32);
// 64 bit base address register.
} else if ((base & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
PCI_BASE_ADDRESS_MEM_TYPE_64) {
DumpBaseAddressRegister64(bus, slot, func, *offset, info, len);
*offset += sizeof(u64);
// 32 bit memspace or io space base address register.
} else if ((base & PCI_BASE_ADDRESS_SPACE) ==
PCI_BASE_ADDRESS_SPACE_MEMORY) {
DumpBaseAddressRegister32(bus, slot, func, *offset, info, len);
*offset += sizeof(u32);
} else {
// Something else - Just advance the offset one word forward.
*offset += sizeof(u32);
};
return STATUS_SUCCESS;
};
static NTSTATUS DumpStandardHeader(u8 bus, u8 slot, u8 func,
struct PmemMemoryInfo *info, int len) {
u8 offset;
// For standard devices we just go over all their base address registers.
for(offset = PCI_BASE_ADDRESS_0; offset <= PCI_BASE_ADDRESS_5;) {
DumpBaseAddressRegister(bus, slot, func, &offset, info, len);
};
return STATUS_SUCCESS;
};
static NTSTATUS DumpPCIBridge(u8 bus, u8 slot, u8 func,
struct PmemMemoryInfo *info, int len) {
u8 offset;
u64 base;
u64 limit;
// Support direct Bridge BARs.
for(offset = PCI_BASE_ADDRESS_0; offset <= PCI_BASE_ADDRESS_1;) {
DumpBaseAddressRegister(bus, slot, func, &offset, info, len);
};
// I/O base and limit registers are not interesting for memory acquisition.
// Memory base and limit registers.
base = read_pci_config_16(bus, slot, func, PCI_MEMORY_BASE);
if (base != 0) {
base = (base & 0xFFF0) << 20;
limit = read_pci_config_16(bus, slot, func, PCI_MEMORY_LIMIT);
limit = (limit & 0xFFF0) << 20 | 0xFFFFFF;
if (limit > base) {
InsertMemoryHole(info, len, base, limit);
};
};
// Prefetcheable Memory base and limit registers.
base = read_pci_config_16(bus, slot, func, PCI_PREF_MEMORY_BASE);
if (base != 0) {
// Determine if the base register is 32 or 64 bit.
if ((base & 0xF) == 0) {
base = (base & 0xFFF0) << 20;
} else {
base = ((base & 0xFFF0) << 20) |
((u64)read_pci_config(bus, slot, func, PCI_PREF_BASE_UPPER32) << 32);
};
limit = read_pci_config_16(bus, slot, func, PCI_PREF_MEMORY_LIMIT);
// Determine if the limit register is 32 or 64 bit.
if ((limit & 0xF) == 0) {
limit = (limit & 0xFFF0) << 20 | 0xFFFFFF;
} else {
limit = ((limit & 0xFFF0) << 20) | 0xFFFFFF |
((u64)read_pci_config(bus, slot, func, PCI_PREF_LIMIT_UPPER32) << 32);
};
if (limit > base) {
InsertMemoryHole(info, len, base, limit);
};
};
return STATUS_SUCCESS;
};
/*
Uses direct PCI probing to add accessible physical memory ranges.
*/
NTSTATUS PCI_AddMemoryRanges(struct PmemMemoryInfo *info, int len) {
int required_length = (sizeof(struct PmemMemoryInfo) +
sizeof(PHYSICAL_MEMORY_RANGE));
unsigned int bus, slot, func;
if (len < required_length) {
return STATUS_INFO_LENGTH_MISMATCH;
};
// Initialize the physical memory range.
info->NumberOfRuns.QuadPart = 1;
info->Run[0].BaseAddress.QuadPart = 0;
info->Run[0].NumberOfBytes.QuadPart = -1;
for (bus = 0; bus < 256; bus++) {
for (slot = 0; slot < 32; slot++) {
for (func = 0; func < 8; func++) {
u8 type;
u16 vendor_id = read_pci_config_16((u8)bus, (u8)slot, (u8)func,
PCI_VENDOR_ID);
// Device not present.
if (vendor_id == 0xffff)
continue;
type = read_pci_config_byte((u8)bus, (u8)slot, (u8)func,
PCI_HEADER_TYPE);
// Standard header.
if ((type & 0x1f) == 0) {
#if WINPMEM_PCI_DEBUG
WinDbgPrint("PCI Type %X\n", type);
dump_interesting_fields((u8)bus, (u8)slot, (u8)func);
dump_bar((u8)bus, (u8)slot, (u8)func);
DumpConfigSpace((u8)bus, (u8)slot, (u8)func);
#endif
DumpStandardHeader((u8)bus, (u8)slot, (u8)func, info, len);
// PCI-PCI bridge.
} else if ((type & 0x1f) == 1) {
#if WINPMEM_PCI_DEBUG
WinDbgPrint("PCI Type %X\n", type);
dump_interesting_fields((u8)bus, (u8)slot, (u8)func);
DumpConfigSpace((u8)bus, (u8)slot, (u8)func);
#endif
DumpPCIBridge((u8)bus, (u8)slot, (u8)func, info, len);
} else {
WinDbgPrint("Unknown header PCI at 0000:%02x:%02x.%d type %d\n",
bus, slot, func, type);
};
// This is not a multi function device.
if (func == 0 && (type & 0x80) == 0) {
break;
};
}
}
}
return STATUS_SUCCESS;
};
Executable
+48
View File
@@ -0,0 +1,48 @@
// Implements a raw pci access method for communicating with the pci
// controller directly.
#include "winpmem.h"
#define PCI_VENDOR_ID 0x00 /* 16 bits */
#define PCI_DEVICE_ID 0x02 /* 16 bits */
#define PCI_COMMAND 0x04 /* 16 bits */
#define PCI_COMMAND_IO 0x01
#define PCI_COMMAND_MEMORY 0x02
#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */
#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits [htype 0,1 only] */
#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits [htype 0 only] */
#define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */
#define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */
#define PCI_BASE_ADDRESS_5 0x24 /* 32 bits */
#define PCI_BASE_ADDRESS_SPACE 0x01 /* 0 = memory, 1 = I/O */
#define PCI_BASE_ADDRESS_SPACE_IO 0x01
#define PCI_BASE_ADDRESS_SPACE_MEMORY 0x00
#define PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06
#define PCI_BASE_ADDRESS_MEM_TYPE_32 0x00 /* 32 bit address */
#define PCI_BASE_ADDRESS_MEM_TYPE_1M 0x02 /* Below 1M [obsolete] */
#define PCI_BASE_ADDRESS_MEM_TYPE_64 0x04 /* 64 bit address */
#define PCI_BASE_ADDRESS_MEM_PREFETCH 0x08 /* prefetchable? */
#define PCI_BASE_ADDRESS_MEM_MASK (~(pciaddr_t)0x0f)
#define PCI_BASE_ADDRESS_IO_MASK (~(pciaddr_t)0x03)
/* bit 1 is reserved if address_space = 1 */
#define PCI_IO_BASE 0x1c /* I/O range behind the bridge */
#define PCI_IO_LIMIT 0x1d
#define PCI_MEMORY_BASE 0x20 /* Memory range behind */
#define PCI_MEMORY_LIMIT 0x22
#define PCI_PREF_MEMORY_BASE 0x24 /* Prefetchable memory range behind */
#define PCI_PREF_MEMORY_LIMIT 0x26
#define PCI_PREF_BASE_UPPER32 0x28 /* Upper half of prefetchable memory range */
#define PCI_PREF_LIMIT_UPPER32 0x2c
#define PCI_IO_BASE_UPPER16 0x30 /* Upper half of I/O addresses */
#define PCI_IO_LIMIT_UPPER16 0x32
#define PCI_CONFIG_DATA 0xCFC
#define PCI_CONFIG_ADDRESS 0xCF8
#define PCI_CLASS_REVISION 0x08 /* High 24 bits are class, low 8 revision */
#define PCI_HEADER_TYPE 0x0e /* 8 bits */
NTSTATUS PCI_AddMemoryRanges(struct PmemMemoryInfo *info, int len);
+231
View File
@@ -0,0 +1,231 @@
// This module contains helper functions to directly edit the page tables of a
// process, enabling it to map physical memory independent of the operating
// system.
//
// Warning: This code directly writes to the kernel page tables and executes
// priviledged instructions as invlpg. It will only run in ring 0.
//
//
// Copyright 2018 Velocidex Innovations <mike@velocidex.com>
// Copyright 2014 - 2017 Google Inc.
// Copyright 2012 Google Inc. All Rights Reserved.
// Authors: Johannes Stüttgen (johannes.stuettgen@gmail.com)
// Michael Cohen <mike@velocidex.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "pte_mmap.h"
#include "winpmem.h"
// Edit the page tables to point a virtual address to a specific physical page.
//
// Args:
// self: The this pointer to the object using this function.
// target: The physical address to map to.
//
// Returns:
// PTE_SUCCESS or PTE_ERROR
//
static PTE_STATUS pte_remap_rogue_page(PTE_MMAP_OBJ *self, PHYS_ADDR target) {
if (self->rogue_page.pointer == NULL) {
// We do not have a rogue page to remap at all.
return PTE_ERROR;
}
// Can only remap pages, addresses must be page aligned.
if (((!target) & PAGE_MASK) || self->rogue_page.offset) {
WinDbgPrint("Failed to map %#016llx, "
"only page aligned remapping is supported!",
target);
return PTE_ERROR;
}
WinDbgPrintDebug("Remapping pte at %p to %#016llx",
self->rogue_pte,
target);
// Change the pte to point to the new offset.
self->rogue_pte->page_frame = PAGE_TO_PFN(target);
// Flush the old pte from the tlbs in the system.
self->flush_tlbs_page_(self->rogue_page.pointer);
return PTE_SUCCESS;
}
// Parse a 64 bit page table entry and print it.
static void print_pte_contents(PTE_MMAP_OBJ *self, PTE_LOGLEVEL loglevel,
PTE *pte) {
WinDbgPrint("Virtual Address:%#016llx\n"
"\tpresent: %lld\n"
"\trw: %lld\n"
"\tuser: %lld\n"
"\twrite_through:%lld\n"
"\tcache_disable:%lld\n"
"\taccessed: %lld\n"
"\tdirty: %lld\n"
"\tpat: %lld\n"
"\tglobal: %lld\n"
"\txd: %lld\n"
"\tpfn: %010llx",
(pte_uint64)pte,
(pte_uint64)pte->present,
(pte_uint64)pte->rw,
(pte_uint64)pte->user,
(pte_uint64)pte->write_through,
(pte_uint64)pte->cache_disable,
(pte_uint64)pte->accessed,
(pte_uint64)pte->dirty,
(pte_uint64)pte->pat,
(pte_uint64)pte->global,
(pte_uint64)pte->xd,
(pte_uint64)pte->page_frame);
}
// Traverses the page tables to find the pte for a given virtual address.
//
// Args:
// self: The this pointer for the object calling this function.
// vaddr: The virtual address to resolve the pte for
// pte: A pointer to a pointer which will be set with the address of the pte,
// if found.
//
// Returns:
// PTE_SUCCESS or PTE_ERROR
//
static PTE_STATUS virt_find_pte(PTE_MMAP_OBJ *self, void *addr,
PTE **pte) {
PTE_CR3 cr3;
PML4E *pml4;
PML4E *pml4e;
PDPTE *pdpt;
PDPTE *pdpte;
PDE *pd;
PDE *pde;
PTE *pt;
VIRT_ADDR vaddr;
PTE_STATUS status = PTE_ERROR;
vaddr.pointer = addr;
WinDbgPrint("Resolving PTE for Address:%#016llx", vaddr);
// Get contents of cr3 register to get to the PML4
cr3 = self->get_cr3_();
WinDbgPrint("Kernel CR3 is %p", cr3);
WinDbgPrint("Kernel PML4 is at %p physical",
PFN_TO_PAGE(cr3.pml4_p));
// Resolve the PML4
pml4 = (PML4E *)self->phys_to_virt_(PFN_TO_PAGE(cr3.pml4_p));
WinDbgPrint("kernel PML4 is at %p virtual", pml4);
// Resolve the PDPT
pml4e = (pml4 + vaddr.pml4_index);
WinDbgPrint("PML4 entry %d is at %p", vaddr.pml4_index,
pml4e);
if (!pml4e->present) {
WinDbgPrint("Error, address %#016llx has no valid mapping in PML4:",
vaddr.value);
self->print_pte_(self, PTE_ERR, (PTE *)pml4e);
goto error;
}
WinDbgPrint("PML4[%#010x]: %p)", vaddr.pml4_index, pml4e);
pdpt = (PDPTE *)self->phys_to_virt_(PFN_TO_PAGE(pml4e->pdpt_p));
WinDbgPrintDebug("Points to PDPT: %p)", pdpt);
// Resolve the PDT
pdpte = (pdpt + vaddr.pdpt_index);
if (!pdpte->present) {
WinDbgPrint("Error, address %#016llx has no valid mapping in PDPT:",
vaddr.value);
self->print_pte_(self, PTE_ERR, (PTE *)pdpte);
goto error;
}
if (pdpte->page_size) {
WinDbgPrint("Error, address %#016llx belongs to a 1GB page:",
vaddr.value);
self->print_pte_(self, PTE_ERR, (PTE *)pdpte);
goto error;
}
WinDbgPrint("PDPT[%#010x]: %p)", vaddr.pdpt_index, pdpte);
pd = (PDE *)self->phys_to_virt_(PFN_TO_PAGE(pdpte->pd_p));
WinDbgPrint("Points to PD: %p)", pd);
// Resolve the PT
pde = (pd + vaddr.pd_index);
if (!pde->present) {
WinDbgPrint("Error, address %#016llx has no valid mapping in PD:",
vaddr.value);
self->print_pte_(self, PTE_ERR, (PTE *)pde);
goto error;
}
if (pde->page_size) {
WinDbgPrint("Error, address %#016llx belongs to a 2MB page:",
vaddr.value);
self->print_pte_(self, PTE_ERR, (PTE *)pde);
goto error;
}
WinDbgPrint("PD [%#010x]: %p)", vaddr.pd_index, pde);
pt = (PTE *)self->phys_to_virt_(PFN_TO_PAGE(pde->pt_p));
WinDbgPrint("Points to PT: %p)", pt);
// Get the PTE and Page Frame
*pte = (pt + vaddr.pt_index);
if (! (*pte)->present) {
WinDbgPrint("Error, address %#016llx has no valid mapping in PT:",
vaddr.value);
self->print_pte_(self, PTE_ERR, (*pte));
goto error;
}
WinDbgPrint("PT [%#010x]: %p)", vaddr.pt_index, *pte);
status = PTE_SUCCESS;
error:
return status;
}
// Initializer for objects of this class. Takes care of the non-abstract parts
// of the object.
//
// Args:
// self: Pointer to the allocated memory for this object.
//
void pte_mmap_init(PTE_MMAP_OBJ *self) {
// store this pointer
self->self = self;
// store non-abstract functions in vtable
self->remap_page = pte_remap_rogue_page;
self->find_pte_ = virt_find_pte;
self->print_pte_ = print_pte_contents;
// Initialize attributes
self->loglevel = PTE_BUILD_LOGLEVEL;
}
// Call this before freeing the object or the rogue_page.
// Will reset the page table entry for the rogue page.
//
// Args:
// self: Pointer to the allocated memory for this object.
//
void pte_mmap_cleanup(PTE_MMAP_OBJ *self) {
WinDbgPrintDebug("Restoring pte to original mapping (%#016llx)",
self->original_addr);
self->remap_page(self, self->original_addr);
self->free_rogue_page_(self->rogue_page.pointer);
}
+186
View File
@@ -0,0 +1,186 @@
// Directly manipulates the page tables to map physical memory into the kernel.
// Notice: This is only an abstract base class and cannot be used standalone.
// Use the actual implementation for your operating system (eg. pte_mmap_linux).
//
// Copyright 2018 Velocidex Innovations <mike@velocidex.com>
// Copyright 2014 - 2017 Google Inc.
// Copyright 2012 Google Inc. All Rights Reserved.
// Author: Johannes Stüttgen (johannes.stuettgen@gmail.com)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _REKALL_DRIVER_PTE_MMAP_H_
#define _REKALL_DRIVER_PTE_MMAP_H_
#define PAGE_MASK (~(PAGE_SIZE-1))
#define PFN_TO_PAGE(pfn) (pfn << PAGE_SHIFT)
#define PAGE_TO_PFN(pfn) (pfn >> PAGE_SHIFT)
typedef unsigned __int64 pte_uint64;
#pragma warning(disable:4214)
#pragma warning(disable:4201) /*nonstandard extension used: nameless struct/union */
#pragma pack(push, 1)
typedef union CR3_ {
pte_uint64 value;
struct {
pte_uint64 ignored_1 : 3;
pte_uint64 write_through : 1;
pte_uint64 cache_disable : 1;
pte_uint64 ignored_2 : 7;
pte_uint64 pml4_p :40;
pte_uint64 reserved :12;
};
} PTE_CR3;
typedef union VIRT_ADDR_ {
pte_uint64 value;
void *pointer;
struct {
pte_uint64 offset : 12;
pte_uint64 pt_index : 9;
pte_uint64 pd_index : 9;
pte_uint64 pdpt_index : 9;
pte_uint64 pml4_index : 9;
pte_uint64 reserved : 16;
};
} VIRT_ADDR;
typedef pte_uint64 PHYS_ADDR;
typedef union PML4E_ {
pte_uint64 value;
struct {
pte_uint64 present : 1;
pte_uint64 rw : 1;
pte_uint64 user : 1;
pte_uint64 write_through : 1;
pte_uint64 cache_disable : 1;
pte_uint64 accessed : 1;
pte_uint64 ignored_1 : 1;
pte_uint64 reserved_1 : 1;
pte_uint64 ignored_2 : 4;
pte_uint64 pdpt_p :40;
pte_uint64 ignored_3 :11;
pte_uint64 xd : 1;
};
} PML4E;
typedef union PDPTE_ {
pte_uint64 value;
struct {
pte_uint64 present : 1;
pte_uint64 rw : 1;
pte_uint64 user : 1;
pte_uint64 write_through : 1;
pte_uint64 cache_disable : 1;
pte_uint64 accessed : 1;
pte_uint64 dirty : 1;
pte_uint64 page_size : 1;
pte_uint64 ignored_2 : 4;
pte_uint64 pd_p :40;
pte_uint64 ignored_3 :11;
pte_uint64 xd : 1;
};
} PDPTE;
typedef union PDE_ {
pte_uint64 value;
struct {
pte_uint64 present : 1;
pte_uint64 rw : 1;
pte_uint64 user : 1;
pte_uint64 write_through : 1;
pte_uint64 cache_disable : 1;
pte_uint64 accessed : 1;
pte_uint64 dirty : 1;
pte_uint64 page_size : 1;
pte_uint64 ignored_2 : 4;
pte_uint64 pt_p :40;
pte_uint64 ignored_3 :11;
pte_uint64 xd : 1;
};
} PDE;
typedef union PTE_ {
pte_uint64 value;
VIRT_ADDR vaddr;
struct {
pte_uint64 present : 1;
pte_uint64 rw : 1;
pte_uint64 user : 1;
pte_uint64 write_through : 1;
pte_uint64 cache_disable : 1;
pte_uint64 accessed : 1;
pte_uint64 dirty : 1;
pte_uint64 pat : 1;
pte_uint64 global : 1;
pte_uint64 ignored_1 : 3;
pte_uint64 page_frame :40;
pte_uint64 ignored_3 :11;
pte_uint64 xd : 1;
};
} PTE;
#pragma pack(pop)
// Loglevels to exclude debug messages from production builds.
typedef enum PTE_LOGLEVEL_ {
PTE_ERR = 0,
PTE_LOG,
PTE_DEBUG
} PTE_LOGLEVEL;
// The default loglevel for this build
#define PTE_BUILD_LOGLEVEL PTE_LOG
// Operating system independent error checking.
typedef enum PTE_STATUS_ {
PTE_SUCCESS = 0,
PTE_ERROR,
PTE_ERROR_HUGE_PAGE,
PTE_ERROR_RO_PTE
} PTE_STATUS;
// Functions and data for directly manipulating the page tables.
// Create an object of this type by mallocing some memory and then calling
// pte_mmap_init() on it.
typedef struct PTE_MMAP_OBJ_ {
// this pointer.
struct PTE_MMAP_OBJ_ *self;
// Public
PTE_STATUS (*remap_page)(struct PTE_MMAP_OBJ_ *self, PHYS_ADDR target);
// Private
void *(*get_rogue_page_)(void);
void (*free_rogue_page_)(void *page);
void *(*phys_to_virt_)(PHYS_ADDR addr);
PTE_STATUS (*find_pte_)(struct PTE_MMAP_OBJ_ *self, void *vaddr, PTE **pte);
void (*flush_tlbs_page_)(void *page);
PTE_CR3 (*get_cr3_)(void);
void (*print_pte_)(struct PTE_MMAP_OBJ_ *self, PTE_LOGLEVEL loglevel,
PTE *pte);
// Internal Attributes
VIRT_ADDR rogue_page;
PTE *rogue_pte;
PHYS_ADDR original_addr;
PTE_LOGLEVEL loglevel;
} PTE_MMAP_OBJ;
// Initializer for newly created objects.
void pte_mmap_init(PTE_MMAP_OBJ *self);
// Call this before freeing obj or the rogue_page.
// Will reset the page table entry for the rogue page.
void pte_mmap_cleanup(PTE_MMAP_OBJ *self);
#endif // _REKALL_DRIVER_PTE_MMAP_H_
+122
View File
@@ -0,0 +1,122 @@
// Subclass of the pte_mmap module. Contains implementations for the Linux
// specific part of the module.
//
// Copyright 2012 Google Inc. All Rights Reserved.
// Author: Johannes Stüttgen (johannes.stuettgen@gmail.com)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "pte_mmap_linux.h"
#include <asm/io.h>
#include <linux/smp.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
// Get a free, non-paged page of memory.
static void *pte_get_rogue_page(void) {
return vmalloc(PAGE_SIZE);
}
// Frees a single page allocated with vmalloc().
static void pte_free_rogue_page(void *page) {
vfree(page);
return;
}
// Makes use of the fact that the page tables are always mapped in the direct
// Kernel memory map.
static void *pte_phys_to_virt(PHYS_ADDR address) {
return phys_to_virt(address);
}
// Flushes the tlb entry for a specific page.
static void pte_flush_tlb_page(void *addr) {
__asm__ __volatile__("invlpg %0;"
:
:"m"(addr)
: "memory");
}
// Flush a specific page from all cpus by sending an ipi.
static void pte_flush_all_tlbs_page(void *page) {
on_each_cpu(pte_flush_tlb_page, page, 1);
}
/* Get the contents of the CR3 register. */
static CR3 pte_get_cr3(void) {
CR3 cr3;
__asm__ __volatile__("mov %%cr3, %0;": "=r"(cr3.value));
return cr3;
}
// Print messages to the kernel msg ring buffer.
static void pte_log_print(PTE_MMAP_OBJ *self, PTE_LOGLEVEL loglevel,
const char *fmt, ...) {
va_list argptr;
if (self->loglevel < loglevel) {
return;
}
if (loglevel == PTE_ERR) {
printk("PTE MMAP Error: ");
}
va_start(argptr, fmt);
vprintk(fmt, argptr);
va_end(argptr);
printk("\n");
}
// Initializer that fills an operating system specific vtable,
// allocates memory, etc.
PTE_MMAP_OBJ *pte_mmap_linux_new(void) {
PTE_MMAP_OBJ *self = NULL;
// Allocate the object
self = kmalloc(GFP_KERNEL, sizeof(PTE_MMAP_OBJ));
// Let the superconstructor set up the internal stuff
pte_mmap_init(self);
// Fill the virtual function into the vtable
self->get_rogue_page_ = pte_get_rogue_page;
self->free_rogue_page_ = pte_free_rogue_page;
self->phys_to_virt_ = pte_phys_to_virt;
self->flush_tlbs_page_ = pte_flush_all_tlbs_page;
self->get_cr3_ = pte_get_cr3;
self->log_print_ = pte_log_print;
// Initialize attributes that rely on memory allocation
self->rogue_page.pointer = self->get_rogue_page_();
self->log_print_(self, PTE_DEBUG, "Looking up PTE for rogue page: %p",
self->rogue_page);
if (self->find_pte_(self, self->rogue_page.pointer, &self->rogue_pte)) {
self->log_print_(self, PTE_ERR,
"Failed to find the PTE for the rogue page, "
"might be inside huge page, aborting...");
goto error;
}
self->log_print_(self, PTE_DEBUG, "Found rogue pte at %p", self->rogue_pte);
// Back up the address this pte points to for cleaning up later.
self->original_addr = PFN_TO_PAGE(self->rogue_pte->page_frame);
return self;
error:
pte_mmap_linux_delete(self);
return NULL;
}
// Will reset the page table entry for the rogue page and free the object.
void pte_mmap_linux_delete(PTE_MMAP_OBJ *self) {
pte_mmap_cleanup(self);
kfree(self);
}
+41
View File
@@ -0,0 +1,41 @@
// Linux specific implementation of the pte_mmap module.
//
// Copyright 2012 Google Inc. All Rights Reserved.
// Author: Johannes Stüttgen (johannes.stuettgen@gmail.com)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef _VOLATILITY_DRIVER_PTE_MMAP_LINUX_H_
#define _VOLATILITY_DRIVER_PTE_MMAP_LINUX_H_
#ifndef __linux
#error "This module is linux specific. Use the pte_mmap subclass for your OS"
#endif
#ifndef __LP64__
#error "This module contains x86-64 code and cannot run on your machine"
#endif
#include "pte_mmap.h"
#include <linux/module.h>
// Initializer that fills an operating system specific vtable,
// allocates memory, etc.
PTE_MMAP_OBJ *pte_mmap_linux_new(void);
// Call this before freeing obj or the rogue_page.
// Will reset the page table entry for the rogue page.
void pte_mmap_linux_delete(PTE_MMAP_OBJ *self);
#endif // _VOLATILITY_DRIVER_PTE_MMAP_LINUX_H_
+165
View File
@@ -0,0 +1,165 @@
// Subclass of the pte_mmap module. Contains implementations for the Windows
// specific part of the module.
//
// Copyright 2018 Velocidex Innovations <mike@velocidex.com>
// Copyright 2014 - 2017 Google Inc.
// Copyright 2012 Google Inc. All Rights Reserved.
//
// Author: Johannes Stüttgen (johannes.stuettgen@gmail.com)
// Author: Michael Cohen (scudette@gmail.com)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "pte_mmap_windows.h"
static char rogue_page[PAGE_SIZE * 3] = "";
static char *page_aligned_space = NULL;
static MDL *rogue_mdl = NULL;
// Get a free, non-paged page of memory. On windows we can not
// allocate from pool because pool storage is controlled by large page
// PTEs. So we just use a static page in the driver executable.
static void *pte_get_rogue_page(void) {
if (page_aligned_space == NULL) {
// We would ideally like to just allocate memory from non paged
// pool but on Windows 7, non paged pool is allocated from large
// pages and we wont be able to use the page in PTE remapping. So
// this code creates an MDL from a static buffer within the
// driver's data section. We must ensure that this buffer is not
// paged out though so we must call MmGetSystemAddressForMdlSafe
// to ensure the MDL is locked into memory.
// page_aligned_space is the first page aligned offset within the
// buffer.
page_aligned_space = &rogue_page[0];
page_aligned_space += PAGE_SIZE - ((__int64)&rogue_page[0]) % PAGE_SIZE;
// MDL is for a single page.
rogue_mdl = IoAllocateMdl(page_aligned_space, PAGE_SIZE,
FALSE, FALSE, NULL);
if (!rogue_mdl) {
return NULL;
}
try {
// This locks the physical page into memory.
MmProbeAndLockPages(rogue_mdl, KernelMode, IoReadAccess);
page_aligned_space = MmMapLockedPagesSpecifyCache(
rogue_mdl, KernelMode, MmCached, NULL, 0, NormalPagePriority);
return page_aligned_space;
} except(EXCEPTION_EXECUTE_HANDLER) {
NTSTATUS ntStatus = GetExceptionCode();
WinDbgPrint("Exception while locking rogue_mdl %#08X\n", ntStatus);
IoFreeMdl(rogue_mdl);
rogue_mdl = NULL;
return NULL;
}
}
return page_aligned_space;
}
// Frees a single page allocated with vmalloc(). Rogue page is static
// we do not free it.
static void pte_free_rogue_page(void *page) {
if (rogue_mdl) {
MmUnlockPages(rogue_mdl);
IoFreeMdl(rogue_mdl);
rogue_mdl = NULL;
};
return;
}
// Makes use of the fact that the page tables are always mapped in the direct
// Kernel memory map.
static void *pte_phys_to_virt(PHYS_ADDR address) {
PHYSICAL_ADDRESS phys_address;
phys_address.QuadPart = address;
//return phys_to_virt(address);
// TODO(scudette): Use PFNDB here.
return Pmem_KernelExports.MmGetVirtualForPhysical(phys_address);
}
// Flushes the tlb entry for a specific page.
static void pte_flush_tlb_page(void *addr) {
// Use compiler instrinsic.
__invlpg(addr);
}
// Flush a specific page from all cpus by sending an ipi.
static void pte_flush_all_tlbs_page(void *page) {
// TODO: Make this work.
pte_flush_tlb_page(page);
}
/* Get the contents of the CR3 register. */
static PTE_CR3 pte_get_cr3(void) {
PTE_CR3 result;
result.value = __readcr3();
return result;
}
// Will reset the page table entry for the rogue page and free the object.
void pte_mmap_windows_delete(PTE_MMAP_OBJ *self) {
pte_mmap_cleanup(self);
ExFreePool(self);
}
// Initializer that fills an operating system specific vtable,
// allocates memory, etc.
PTE_MMAP_OBJ *pte_mmap_windows_new(void) {
PTE_MMAP_OBJ *self = NULL;
// Allocate the object
self = ExAllocatePoolWithTag(NonPagedPoolNx, sizeof(PTE_MMAP_OBJ),
PMEM_POOL_TAG);
if (!self) return NULL;
// Let the superconstructor set up the internal stuff
pte_mmap_init(self);
// Fill the virtual function into the vtable
self->get_rogue_page_ = pte_get_rogue_page;
self->free_rogue_page_ = pte_free_rogue_page;
self->phys_to_virt_ = pte_phys_to_virt;
self->flush_tlbs_page_ = pte_flush_all_tlbs_page;
self->get_cr3_ = pte_get_cr3;
// Initialize attributes that rely on memory allocation
self->rogue_page.pointer = self->get_rogue_page_();
if (self->rogue_page.pointer == NULL) {
goto error;
}
WinDbgPrintDebug("Looking up PTE for rogue page: %p",
self->rogue_page);
if (self->find_pte_(self, self->rogue_page.pointer, &self->rogue_pte)) {
WinDbgPrint("Failed to find the PTE for the rogue page, "
"might be inside huge page, aborting...");
goto error;
}
WinDbgPrintDebug("Found rogue pte at %p", self->rogue_pte);
// Back up the address this pte points to for cleaning up later.
self->original_addr = PFN_TO_PAGE(self->rogue_pte->page_frame);
return self;
error:
pte_mmap_windows_delete(self);
return NULL;
}
+5
View File
@@ -0,0 +1,5 @@
#include "winpmem.h"
#include "pte_mmap.h"
void pte_mmap_windows_delete(PTE_MMAP_OBJ *self);
PTE_MMAP_OBJ *pte_mmap_windows_new(void);
+311
View File
@@ -0,0 +1,311 @@
/*
Copyright 2018 Velocidex Innovations <mike@velocidex.com>
Copyright 2014-2017 Google Inc.
Copyright 2012 Michael Cohen <scudette@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "read.h"
static int EnsureExtensionHandle(PDEVICE_EXTENSION extension) {
NTSTATUS NtStatus;
UNICODE_STRING PhysicalMemoryPath;
OBJECT_ATTRIBUTES MemoryAttributes;
/* Make sure we have a valid handle now. */
if(!extension->MemoryHandle) {
RtlInitUnicodeString(&PhysicalMemoryPath, L"\\Device\\PhysicalMemory");
InitializeObjectAttributes(&MemoryAttributes,
&PhysicalMemoryPath,
OBJ_KERNEL_HANDLE,
(HANDLE) NULL,
(PSECURITY_DESCRIPTOR) NULL);
NtStatus = ZwOpenSection(&extension->MemoryHandle,
SECTION_MAP_READ, &MemoryAttributes);
if (!NT_SUCCESS(NtStatus)) {
WinDbgPrint("Failed ZwOpenSection(MemoryHandle) => %08X\n", NtStatus);
return 0;
}
};
return 1;
}
static LONG PhysicalMemoryPartialRead(IN PDEVICE_EXTENSION extension,
LARGE_INTEGER offset, PCHAR buf,
ULONG count) {
ULONG page_offset = offset.QuadPart % PAGE_SIZE;
ULONG to_read = min(PAGE_SIZE - page_offset, count);
PUCHAR mapped_buffer = NULL;
SIZE_T ViewSize = PAGE_SIZE;
NTSTATUS NtStatus;
if (EnsureExtensionHandle(extension)) {
/* Map page into the Kernel AS */
NtStatus = ZwMapViewOfSection(extension->MemoryHandle, (HANDLE) -1,
&mapped_buffer, 0L, PAGE_SIZE, &offset,
&ViewSize, ViewUnmap, 0, PAGE_READONLY);
if (NT_SUCCESS(NtStatus)) {
RtlCopyMemory(buf, mapped_buffer + page_offset, to_read);
ZwUnmapViewOfSection((HANDLE)-1, mapped_buffer);
} else {
WinDbgPrint("Failed to Map page at 0x%llX\n", offset.QuadPart);
RtlZeroMemory(buf, to_read);
};
};
return to_read;
};
// Read a single page using MmMapIoSpace.
static LONG MapIOPagePartialRead(IN PDEVICE_EXTENSION extension,
LARGE_INTEGER offset, PCHAR buf,
ULONG count) {
extension;
ULONG page_offset = offset.QuadPart % PAGE_SIZE;
ULONG to_read = min(PAGE_SIZE - page_offset, count);
PUCHAR mapped_buffer = NULL;
LARGE_INTEGER ViewBase;
// Round to page size
ViewBase.QuadPart = offset.QuadPart - page_offset;
// Map exactly one page.
mapped_buffer = Pmem_KernelExports.MmMapIoSpace(
ViewBase, PAGE_SIZE, MmNonCached);
if (mapped_buffer) {
try {
// Be extra careful here to not produce a BSOD.
RtlCopyMemory(buf, mapped_buffer+page_offset, to_read);
} except(EXCEPTION_EXECUTE_HANDLER) {
WinDbgPrintDebug("Unable to read %d bytes from %p for %p\n", to_read, source, offset.QuadPart - page_offset);
Pmem_KernelExports.MmUnmapIoSpace(mapped_buffer, PAGE_SIZE);
return -1;
}
Pmem_KernelExports.MmUnmapIoSpace(mapped_buffer, PAGE_SIZE);
return to_read;
} else {
// Failed to map page, return an error.
return -1;
};
};
// Read a single page using direct PTE mapping.
static LONG PTEMmapPartialRead(IN PDEVICE_EXTENSION extension,
LARGE_INTEGER offset, PCHAR buf,
ULONG count) {
ULONG page_offset = offset.QuadPart % PAGE_SIZE;
ULONG to_read = min(PAGE_SIZE - page_offset, count);
LARGE_INTEGER ViewBase;
LONG result = -1;
// Round to page size
ViewBase.QuadPart = offset.QuadPart - page_offset;
// Map exactly one page.
if(extension->pte_mmapper &&
extension->pte_mmapper->remap_page(extension->pte_mmapper,
offset.QuadPart - page_offset) ==
PTE_SUCCESS) {
char *source = (char *)(extension->pte_mmapper->rogue_page.value + page_offset);
try {
// Be extra careful here to not produce a BSOD. We would rather
// return an error than a BSOD.
RtlCopyMemory(buf, source, to_read);
result = to_read;
} except(EXCEPTION_EXECUTE_HANDLER) {
WinDbgPrintDebug("Unable to read %d bytes from %p for %p\n", to_read, source, offset.QuadPart - page_offset);
}
}
// Failed to map page, or an exception occurred - error out.
return result;
};
static NTSTATUS DeviceRead(IN PDEVICE_EXTENSION extension, LARGE_INTEGER offset,
PCHAR buf, ULONG count, OUT ULONG *total_read,
LONG (*handler)(IN PDEVICE_EXTENSION, LARGE_INTEGER,
PCHAR, ULONG)) {
int result = 0;
*total_read = 0;
ExAcquireFastMutex(&extension->mu);
while(*total_read < count) {
result = handler(extension, offset, buf, count - *total_read);
/* Error Occured. */
if(result < 0)
goto error;
/* No data available. */
if(result==0) {
break;
};
offset.QuadPart += result;
buf += result;
*total_read += result;
};
ExReleaseFastMutex(&extension->mu);
return STATUS_SUCCESS;
error:
ExReleaseFastMutex(&extension->mu);
return STATUS_IO_DEVICE_ERROR;
};
NTSTATUS PmemRead(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
PVOID Buf; //Buffer provided by user space.
ULONG BufLen; //Buffer length for user provided buffer.
LARGE_INTEGER BufOffset; // The file offset requested from userspace.
PIO_STACK_LOCATION pIoStackIrp;
PDEVICE_EXTENSION extension;
NTSTATUS status = STATUS_SUCCESS;
ULONG total_read = 0;
// We must be running in PASSIVE_LEVEL or we bluescreen here. We
// theoretically should always be running at PASSIVE_LEVEL here, but
// in case we ended up here at the wrong IRQL its better to bail
// than to bluescreen.
if(KeGetCurrentIrql() != PASSIVE_LEVEL) {
status = STATUS_ABANDONED;
goto exit;
};
extension = DeviceObject->DeviceExtension;
pIoStackIrp = IoGetCurrentIrpStackLocation(Irp);
BufLen = pIoStackIrp->Parameters.Read.Length;
BufOffset = pIoStackIrp->Parameters.Read.ByteOffset;
Buf = (PCHAR)(Irp->AssociatedIrp.SystemBuffer);
switch(extension->mode) {
// Read using the physical memory handle.
case ACQUISITION_MODE_PHYSICAL_MEMORY:
status = DeviceRead(extension, BufOffset, Buf, BufLen, &total_read,
PhysicalMemoryPartialRead);
break;
case ACQUISITION_MODE_MAP_IO_SPACE:
status = DeviceRead(extension, BufOffset, Buf, BufLen, &total_read,
MapIOPagePartialRead);
break;
case ACQUISITION_MODE_PTE_MMAP_WITH_PCI_PROBE:
case ACQUISITION_MODE_PTE_MMAP:
if (extension->pte_mmapper == NULL) {
status = STATUS_NOT_IMPLEMENTED;
goto exit;
};
status = DeviceRead(extension, BufOffset, Buf, BufLen, &total_read,
PTEMmapPartialRead);
break;
default:
WinDbgPrint("Acquisition mode %u not supported.\n", extension->mode);
status = STATUS_NOT_IMPLEMENTED;
BufLen = 0;
}
exit:
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = total_read;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
#if PMEM_WRITE_ENABLED == 1
NTSTATUS PmemWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
PVOID Buf; //Buffer provided by user space.
ULONG BufLen; //Buffer length for user provided buffer.
LARGE_INTEGER BufOffset; // The file offset requested from userspace.
PIO_STACK_LOCATION pIoStackIrp;
PDEVICE_EXTENSION extension;
NTSTATUS status = STATUS_SUCCESS;
SIZE_T ViewSize = PAGE_SIZE;
PUCHAR mapped_buffer = NULL;
ULONG page_offset = 0;
LARGE_INTEGER offset;
// We must be running in PASSIVE_LEVEL or we bluescreen here. We
// theoretically should always be running at PASSIVE_LEVEL here, but
// in case we ended up here at the wrong IRQL its better to bail
// than to bluescreen.
if(KeGetCurrentIrql() != PASSIVE_LEVEL) {
status = STATUS_ABANDONED;
goto exit;
};
extension = DeviceObject->DeviceExtension;
if (!extension->WriteEnabled) {
status = STATUS_ACCESS_DENIED;
WinDbgPrint("Write mode not enabled.\n");
goto exit;
};
pIoStackIrp = IoGetCurrentIrpStackLocation(Irp);
BufLen = pIoStackIrp->Parameters.Write.Length;
// Where to write exactly.
BufOffset = pIoStackIrp->Parameters.Write.ByteOffset;
Buf = (PCHAR)(Irp->AssociatedIrp.SystemBuffer);
page_offset = BufOffset.QuadPart % PAGE_SIZE;
offset.QuadPart = BufOffset.QuadPart - page_offset; // Page aligned.
// How much we need to write rounded up to the next page.
ViewSize = BufLen + page_offset;
ViewSize += PAGE_SIZE - (ViewSize % PAGE_SIZE);
/* Map memory into the Kernel AS */
if (EnsureExtensionHandle(extension)) {
status = ZwMapViewOfSection(extension->MemoryHandle, (HANDLE) -1,
&mapped_buffer, 0L, PAGE_SIZE, &offset,
&ViewSize, ViewUnmap, 0, PAGE_READWRITE);
if (NT_SUCCESS(status)) {
RtlCopyMemory(mapped_buffer + page_offset, Buf, BufLen);
ZwUnmapViewOfSection((HANDLE)-1, mapped_buffer);
} else {
WinDbgPrint("Failed to map view %lld %ld (%ld).\n", offset, ViewSize,
status);
}
}
exit:
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
#endif
+45
View File
@@ -0,0 +1,45 @@
/**
This file implement methods for reading through the pmem device.
Copyright 2012 Michael Cohen <scudette@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef __READ_H
#define __READ_H
#include "winpmem.h"
/* Read a page through the PhysicalMemory device. */
LONG PhysicalMemoryPartialRead(IN PDEVICE_EXTENSION extension,
LARGE_INTEGER offset, PCHAR buf, ULONG count);
/* Read a large buffer by concatenating lots of small reads. */
NTSTATUS DeviceRead(IN PDEVICE_EXTENSION extension, LARGE_INTEGER offset,
PCHAR buf, ULONG count, OUT ULONG *total_read,
LONG (*handler)(IN PDEVICE_EXTENSION,
LARGE_INTEGER, PCHAR, ULONG)
);
/* Actual read handler. */
__drv_dispatchType(IRP_MJ_READ)
DRIVER_DISPATCH PmemRead;
NTSTATUS PmemRead(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
__drv_dispatchType(IRP_MJ_WRITE)
DRIVER_DISPATCH PmemWrite;
NTSTATUS PmemWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
#endif
+460
View File
@@ -0,0 +1,460 @@
/*
Copyright 2018 Velocidex Innovations <mike@velocidex.com>
Copyright 2014-2017 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "winpmem.h"
#include "pte_mmap_windows.h"
#include "api.h"
#include "read.h"
#include "kd.h"
//#include "pci.h"
// The following globals are populated in the kernel context from DriverEntry
// and reported to the user context.
// The kernel CR3
LARGE_INTEGER CR3;
DRIVER_UNLOAD IoUnload;
VOID IoUnload(IN PDRIVER_OBJECT DriverObject) {
UNICODE_STRING DeviceLinkUnicodeString;
PDEVICE_OBJECT pDeviceObject = NULL;
PDEVICE_EXTENSION ext = NULL;
if (DriverObject == NULL)
return;
pDeviceObject = DriverObject->DeviceObject;
ext=(PDEVICE_EXTENSION)pDeviceObject->DeviceExtension;
RtlInitUnicodeString (&DeviceLinkUnicodeString, L"\\??\\" PMEM_DEVICE_NAME);
IoDeleteSymbolicLink (&DeviceLinkUnicodeString);
if(ext->pte_mmapper)
pte_mmap_windows_delete(ext->pte_mmapper);
IoDeleteDevice(pDeviceObject);
}
/*
Gets information about the memory layout.
- The Physical memory address ranges.
*/
NTSTATUS AddMemoryRanges(struct PmemMemoryInfo *info, int len) {
PPHYSICAL_MEMORY_RANGE MmPhysicalMemoryRange;
int number_of_runs = 0;
int required_length;
// Enumerate address ranges.
MmPhysicalMemoryRange = Pmem_KernelExports.MmGetPhysicalMemoryRanges();
if (MmPhysicalMemoryRange == NULL) {
return STATUS_ACCESS_DENIED;
};
/** Find out how many ranges there are. */
for(number_of_runs=0;
(MmPhysicalMemoryRange[number_of_runs].BaseAddress.QuadPart) ||
(MmPhysicalMemoryRange[number_of_runs].NumberOfBytes.QuadPart);
number_of_runs++);
required_length = (sizeof(struct PmemMemoryInfo) +
number_of_runs * sizeof(PHYSICAL_MEMORY_RANGE));
/* Do we have enough space? */
if(len < required_length) {
return STATUS_INFO_LENGTH_MISMATCH;
};
RtlZeroMemory(info, required_length);
info->NumberOfRuns.QuadPart = number_of_runs;
RtlCopyMemory(&info->Run[0], MmPhysicalMemoryRange,
number_of_runs * sizeof(PHYSICAL_MEMORY_RANGE));
ExFreePool(MmPhysicalMemoryRange);
return STATUS_SUCCESS;
};
__drv_dispatchType(IRP_MJ_CREATE)
DRIVER_DISPATCH wddCreate;
static NTSTATUS wddCreate(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
// PDEVICE_EXTENSION ext=(PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
//PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
if (!DeviceObject || !Irp) {
return STATUS_INVALID_PARAMETER;
}
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
return STATUS_SUCCESS;
};
__drv_dispatchType(IRP_MJ_CLOSE)
DRIVER_DISPATCH wddClose;
static NTSTATUS wddClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
PDEVICE_EXTENSION ext=(PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
// PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
if (!DeviceObject || !Irp) {
return STATUS_INVALID_PARAMETER;
}
if(ext->MemoryHandle != 0) {
ZwClose(ext->MemoryHandle);
ext->MemoryHandle = 0;
};
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
__drv_dispatchType(IRP_MJ_DEVICE_CONTROL)
DRIVER_DISPATCH wddDispatchDeviceControl;
NTSTATUS wddDispatchDeviceControl(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PIO_STACK_LOCATION IrpStack;
NTSTATUS status = STATUS_INVALID_PARAMETER;
ULONG IoControlCode;
PVOID IoBuffer;
PDEVICE_EXTENSION ext;
ULONG InputLen, OutputLen;
// We must be running in PASSIVE_LEVEL or we bluescreen here. We
// theoretically should always be running at PASSIVE_LEVEL here, but
// in case we ended up here at the wrong IRQL its better to bail
// than to bluescreen.
if(KeGetCurrentIrql() != PASSIVE_LEVEL) {
status = STATUS_ABANDONED;
goto exit;
};
ext = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
Irp->IoStatus.Information = 0;
IrpStack = IoGetCurrentIrpStackLocation(Irp);
IoBuffer = Irp->AssociatedIrp.SystemBuffer;
OutputLen = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
InputLen = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
IoControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
switch ((IoControlCode & 0xFFFFFF0F)) {
// The old deprecated ioctrl interface for backwards
// compatibility. Do not use for new code.
case IOCTL_GET_INFO_DEPRECATED: {
char *buffer = ExAllocatePoolWithTag(NonPagedPoolNx, 0x1000, PMEM_POOL_TAG);
if (buffer) {
struct DeprecatedPmemMemoryInfo *info = (void *)IoBuffer;
struct PmemMemoryInfo *memory_info = (void *)buffer;
status = AddMemoryRanges(memory_info, 0x1000);
if (status != STATUS_SUCCESS) {
ExFreePoolWithTag(buffer, PMEM_POOL_TAG);
goto exit;
};
info->CR3.QuadPart = CR3.QuadPart;
info->NumberOfRuns = (unsigned long)memory_info->NumberOfRuns.QuadPart;
// Is there enough space in the user supplied buffer?
if (OutputLen < (info->NumberOfRuns * sizeof(PHYSICAL_MEMORY_RANGE) +
sizeof(struct DeprecatedPmemMemoryInfo))) {
status = STATUS_INFO_LENGTH_MISMATCH;
ExFreePoolWithTag(buffer, PMEM_POOL_TAG);
goto exit;
};
// Copy the runs over.
RtlCopyMemory(&info->Run[0], &memory_info->Run[0],
info->NumberOfRuns * sizeof(PHYSICAL_MEMORY_RANGE));
// This is the total length of the response.
Irp->IoStatus.Information =
sizeof(struct DeprecatedPmemMemoryInfo) +
info->NumberOfRuns * sizeof(PHYSICAL_MEMORY_RANGE);
WinDbgPrint("Returning info on the system memory using deprecated "
"interface!\n");
ExFreePoolWithTag(buffer, PMEM_POOL_TAG);
status = STATUS_SUCCESS;
};
}; break;
// Return information about memory layout etc through this ioctrl.
case IOCTL_GET_INFO: {
struct PmemMemoryInfo *info = (void *)IoBuffer;
if (OutputLen < sizeof(struct PmemMemoryInfo)) {
status = STATUS_INFO_LENGTH_MISMATCH;
goto exit;
};
// Ensure we clear the buffer first.
RtlZeroMemory(IoBuffer, sizeof(struct PmemMemoryInfo));
#if 0
// Get the memory ranges according to the mode.
if (ext->mode == ACQUISITION_MODE_PTE_MMAP_WITH_PCI_PROBE) {
status = PCI_AddMemoryRanges(info, OutputLen);
} else {
status = AddMemoryRanges(info, OutputLen);
}
#else
status = AddMemoryRanges(info, OutputLen);
#endif
if (status != STATUS_SUCCESS) {
goto exit;
};
WinDbgPrint("Returning info on the system memory.\n");
// We are currently running in user context which means __readcr3() will
// return the process CR3. So we return the kernel CR3 we found
// when loading.
info->CR3.QuadPart = CR3.QuadPart;
info->NtBuildNumber.QuadPart = *NtBuildNumber;
info->NtBuildNumberAddr.QuadPart = (uintptr_t)NtBuildNumber;
info->KernBase.QuadPart = (uintptr_t)KernelGetModuleBaseByPtr(NtBuildNumber);
// Fill in KPCR.
GetKPCR(info);
// This is the length of the response.
Irp->IoStatus.Information =
sizeof(struct PmemMemoryInfo) +
info->NumberOfRuns.LowPart * sizeof(PHYSICAL_MEMORY_RANGE);
status = STATUS_SUCCESS;
}; break;
case IOCTL_SET_MODE: {
WinDbgPrint("Setting Acquisition mode.\n");
/* First u32 is the acquisition mode. */
if (InputLen >= sizeof(u32)) {
enum PMEM_ACQUISITION_MODE mode = *(u32 *)IoBuffer;
switch(mode) {
case ACQUISITION_MODE_PHYSICAL_MEMORY:
// These are all the requirements for this method.
if (!Pmem_KernelExports.MmGetPhysicalMemoryRanges) {
WinDbgPrint("Kernel APIs required for this method are not "
"available.");
status = STATUS_UNSUCCESSFUL;
} else {
WinDbgPrint("Using physical memory device for acquisition.\n");
status = STATUS_SUCCESS;
ext->mode = mode;
};
break;
case ACQUISITION_MODE_MAP_IO_SPACE:
if (!Pmem_KernelExports.MmGetPhysicalMemoryRanges ||
!Pmem_KernelExports.MmMapIoSpace ||
!Pmem_KernelExports.MmUnmapIoSpace) {
WinDbgPrint("Kernel APIs required for this method are not "
"available.");
status = STATUS_UNSUCCESSFUL;
} else {
WinDbgPrint("Using MmMapIoSpace for acquisition.\n");
status = STATUS_SUCCESS;
ext->mode = mode;
};
break;
case ACQUISITION_MODE_PTE_MMAP:
if (!Pmem_KernelExports.MmGetVirtualForPhysical ||
!Pmem_KernelExports.MmGetPhysicalMemoryRanges ||
!ext->pte_mmapper) {
WinDbgPrint("Kernel APIs required for this method are not "
"available.");
status = STATUS_UNSUCCESSFUL;
} else {
WinDbgPrint("Using PTE Remapping for acquisition.\n");
status = STATUS_SUCCESS;
ext->mode = mode;
};
break;
#if 0
case ACQUISITION_MODE_PTE_MMAP_WITH_PCI_PROBE:
if (!Pmem_KernelExports.MmGetVirtualForPhysical ||
!ext->pte_mmapper) {
WinDbgPrint("Kernel APIs required for this method are not "
"available.");
status = STATUS_UNSUCCESSFUL;
} else {
WinDbgPrint("Using PTE Remapping with PCI probe for acquisition.\n");
status = STATUS_SUCCESS;
ext->mode = mode;
};
break;
#endif
default:
WinDbgPrint("Invalid acquisition mode %d.\n", mode);
status = STATUS_INVALID_PARAMETER;
};
} else {
status = STATUS_INFO_LENGTH_MISMATCH;
};
}; break;
#if PMEM_WRITE_ENABLED == 1
case IOCTL_WRITE_ENABLE: {
ext->WriteEnabled = !ext->WriteEnabled;
WinDbgPrint("Write mode is %d. Do you know what you are doing?\n",
ext->WriteEnabled);
status = STATUS_SUCCESS;
}; break;
#endif
default: {
WinDbgPrint("Invalid IOCTRL %d\n", IoControlCode);
status = STATUS_INVALID_PARAMETER;
};
}
exit:
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
return status;
}
DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry (IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
UNICODE_STRING DeviceName, DeviceLink;
NTSTATUS NtStatus;
PDEVICE_OBJECT DeviceObject = NULL;
PDEVICE_EXTENSION extension;
RegistryPath; // Unused
WinDbgPrint("WinPMEM - " PMEM_VERSION " - Physical memory acquisition\n");
#if PMEM_WRITE_ENABLED == 1
WinDbgPrint("WinPMEM write support available!");
#endif
WinDbgPrint("Copyright (c) 2018, Velocidex Innovations <mike@velocidex.com>\n");
WinDbgPrint("Copyright (c) 2017, Google Inc.\n");
// Initialize import tables:
if(PmemGetProcAddresses() != STATUS_SUCCESS) {
WinDbgPrint("Failed to initialize import table. Aborting.\n");
goto error;
};
RtlInitUnicodeString (&DeviceName, L"\\Device\\" PMEM_DEVICE_NAME);
// We create our secure device.
// http://msdn.microsoft.com/en-us/library/aa490540.aspx
NtStatus = IoCreateDeviceSecure(DriverObject,
sizeof(DEVICE_EXTENSION),
&DeviceName,
FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&SDDL_DEVOBJ_SYS_ALL_ADM_ALL,
&GUID_DEVCLASS_PMEM_DUMPER,
&DeviceObject);
if (!NT_SUCCESS(NtStatus)) {
WinDbgPrint ("IoCreateDevice failed. => %08X\n", NtStatus);
return NtStatus;
}
DriverObject->MajorFunction[IRP_MJ_CREATE] = wddCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = wddClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = wddDispatchDeviceControl;
DriverObject->MajorFunction[IRP_MJ_READ] = PmemRead;
#if PMEM_WRITE_ENABLED == 1
{
// Make sure that the drivers with write support are clearly marked as such.
static char TAG[] = "Write Supported";
}
// Support writing.
DriverObject->MajorFunction[IRP_MJ_WRITE] = PmemWrite;
#endif
DriverObject->DriverUnload = IoUnload;
// Use buffered IO - a bit slower but simpler to implement, and more
// efficient for small reads.
SetFlag(DeviceObject->Flags, DO_BUFFERED_IO );
ClearFlag(DeviceObject->Flags, DO_DIRECT_IO );
ClearFlag(DeviceObject->Flags, DO_DEVICE_INITIALIZING);
RtlInitUnicodeString (&DeviceLink, L"\\??\\" PMEM_DEVICE_NAME);
NtStatus = IoCreateSymbolicLink (&DeviceLink, &DeviceName);
if (!NT_SUCCESS(NtStatus)) {
IoDeleteSymbolicLink(&DeviceLink);
NtStatus = IoCreateSymbolicLink(&DeviceLink, &DeviceName);
if (!NT_SUCCESS(NtStatus)) {
WinDbgPrint("IoCreateSymbolicLink failed. => %08X\n", NtStatus);
IoDeleteDevice(DeviceObject);
goto error;
}
}
// Populate globals in kernel context.
CR3.QuadPart = __readcr3();
// Initialize the device extension with safe defaults.
extension = DeviceObject->DeviceExtension;
extension->mode = ACQUISITION_MODE_PHYSICAL_MEMORY;
extension->MemoryHandle = 0;
#if _WIN64
// Disable pte mapping for 32 bit systems.
extension->pte_mmapper = pte_mmap_windows_new();
if (extension->pte_mmapper == NULL) {
IoDeleteDevice(DeviceObject);
goto error;
}
extension->pte_mmapper->loglevel = PTE_ERR;
extension->mode = ACQUISITION_MODE_PTE_MMAP;
#else
extension->pte_mmapper = NULL;
#endif
ExInitializeFastMutex(&extension->mu);
WinDbgPrint("Driver intialization completed.");
return NtStatus;
error:
return STATUS_UNSUCCESSFUL;
}
+187
View File
@@ -0,0 +1,187 @@
/*
Copyright 2018 Velocidex Innovations <mike@velocidex.com>
Copyright 2014-2017 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef _WINPMEM_H_
#define _WINPMEM_H_
/* These should be changed for incident response purposes to prevent trivial
* rootkit subversion.
*/
#define SILENT_OPERATION 0
// Really verbose debugging.
#define VERBOSE_DEBUG 0
#define PMEM_DEVICE_NAME L"pmem"
#define PMEM_VERSION "v1.6.3"
#define PMEM_POOL_TAG 0x4d454d50
// In order to enable writing this must be set to 1 and the
// appropriate IOCTL must be sent to switch the driver to write mode.
#define PMEM_WRITE_ENABLED 0
#include <ntifs.h>
#include <wdmsec.h>
#include <initguid.h>
#include <stdarg.h>
#include <stdio.h>
#include "pte_mmap.h"
#include "api.h"
// Some standard integer sizes.
typedef unsigned __int64 u64;
typedef unsigned __int32 u32;
typedef unsigned __int16 u16;
typedef unsigned __int8 u8;
#define MI_CONVERT_PHYSICAL_TO_PFN(Pa) (Pa >> 12)
//
// IOCTL
//
// This is used to query the driver about memory stats.
#define IOCTL_GET_INFO CTL_CODE(FILE_DEVICE_UNKNOWN, 0x103, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
#define IOCTL_SET_MODE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x101, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
#define IOCTL_WRITE_ENABLE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x102, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// This is the old deprecated interface. Use IOCTL_GET_INFO instead.
#define IOCTL_GET_INFO_DEPRECATED CTL_CODE(FILE_DEVICE_UNKNOWN, 0x100, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// This is the structure which is returned.
#pragma pack(push, 2)
extern PUSHORT NtBuildNumber;
/* This is the format of the deprecated IOCTL_GET_INFO_DEPRECATED
call.
*/
struct DeprecatedPmemMemoryInfo {
LARGE_INTEGER CR3;
LARGE_INTEGER KPCR;
ULONG NumberOfRuns;
// A Null terminated array of ranges.
PHYSICAL_MEMORY_RANGE Run[1];
};
struct PmemMemoryInfo {
LARGE_INTEGER CR3;
LARGE_INTEGER NtBuildNumber; // Version of this kernel.
LARGE_INTEGER KernBase; // The base of the kernel image.
// The following are deprecated and will not be set by the driver. It is safer
// to get these during analysis from NtBuildNumberAddr below.
LARGE_INTEGER KDBG; // The address of KDBG
// Support up to 32 processors for KPCR.
LARGE_INTEGER KPCR[32];
LARGE_INTEGER PfnDataBase;
LARGE_INTEGER PsLoadedModuleList;
LARGE_INTEGER PsActiveProcessHead;
// END DEPRECATED.
// The address of the NtBuildNumber integer - this is used to find the kernel
// base quickly.
LARGE_INTEGER NtBuildNumberAddr;
// As the driver is extended we can add fields here maintaining
// driver alignment..
LARGE_INTEGER Padding[0xfe];
LARGE_INTEGER NumberOfRuns;
// A Null terminated array of ranges.
PHYSICAL_MEMORY_RANGE Run[1];
};
enum PMEM_ACQUISITION_MODE {
// Use the MmMapIoSpace API.
ACQUISITION_MODE_MAP_IO_SPACE = 0,
// Map the \\.\PhysicalMemory device.
ACQUISITION_MODE_PHYSICAL_MEMORY = 1,
// Use direct page table manipulation.
ACQUISITION_MODE_PTE_MMAP = 2,
// Use direct page table manipulation with PCI memory map probing
ACQUISITION_MODE_PTE_MMAP_WITH_PCI_PROBE = 3
};
struct PmemMemoryControl {
u32 mode; //really: enum PMEM_ACQUISITION_MODE mode but we want to enforce
//standard struct sizes.;
};
/* When we are silent we do not emit any debug messages. */
#if SILENT_OPERATION == 1
#define WinDbgPrint(fmt, ...)
#define vWinDbgPrintEx(x, ...)
#else
#define WinDbgPrint DbgPrint
#define vWinDbgPrintEx vDbgPrintEx
#endif
# if VERBOSE_DEBUG == 1
#define WinDbgPrintDebug DbgPrint
# else
#define WinDbgPrintDebug(fmt, ...)
#endif
// Add verbose debugging to PCI code.
#define WINPMEM_PCI_DEBUG 0
/*
Our Device Extension Structure.
*/
typedef struct _DEVICE_EXTENSION {
/* If we read from \\Device\\PhysicalMemory, this is the handle to that. */
HANDLE MemoryHandle;
/* How we should acquire memory. */
enum WDD_ACQUISITION_MODE mode;
int WriteEnabled;
/* Hold a handle to the pte_mmap object. */
PTE_MMAP_OBJ *pte_mmapper;
FAST_MUTEX mu;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
// 5e1ce668-47cb-410e-a664-5c705ae4d71b
DEFINE_GUID(GUID_DEVCLASS_PMEM_DUMPER,
0x5e1ce668L,
0x47cb,
0x410e,
0xa6, 0x64, 0x5c, 0x70, 0x5a, 0xe4, 0xd7, 0x1b);
#pragma pack(pop)
#endif
+258
View File
@@ -0,0 +1,258 @@
#!python
"""This is the user space program which is required for dumping images using the
winpmem driver.
Copyright 2012 Michael Cohen <scudette@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
from __future__ import print_function
__author__ = "Michael Cohen <scudette@gmail.com>"
import win32service
import win32file
import struct
import sys
import os
import time
import optparse
parser = optparse.OptionParser()
parser.add_option("-d", "--driver",
help="The driver location (winpmem.sys)", metavar="FILE")
parser.add_option("-f", "--filename", dest="filename", default="pmemdump.raw",
help="write image to FILE", metavar="FILE")
parser.add_option("-n", "--name", default="pmem",
help="The name of the device.")
parser.add_option("-m", "--mode", default="physical",
help="The acquisition mode. Can be (physical or iospace)")
parser.add_option("-l", "--load", default=False, action="store_true",
help="Only load the driver and immediately quit. "
"(Useful just before attaching with volatility)")
parser.add_option("-u", "--unload", default=False, action="store_true",
help="Unload the driver and immediately quit. ")
def CTL_CODE(DeviceType, Function, Method, Access):
return (DeviceType<<16) | (Access << 14) | (Function << 2) | Method
# IOCTLS for interacting with the driver.
CTRL_IOCTRL = CTL_CODE(0x22, 0x101, 0, 3)
INFO_IOCTRL = CTL_CODE(0x22, 0x103, 0, 3)
INFO_IOCTRL_DEPRECATED = CTL_CODE(0x22, 0x100, 0, 3)
class Image(object):
"""This class abstracts the image."""
buffer_size = 1024 * 1024
def __init__(self, fd):
self.fd = fd
self.SetMode()
self.ParseMemoryRuns()
# Tell the driver what acquisition mode we want.
self.GetInfo()
#self.GetInfoDeprecated()
def GetInfoDeprecated(self):
result = win32file.DeviceIoControl(self.fd, INFO_IOCTRL_DEPRECATED, "",
1024, None)
fmt_string = "QQl"
offset = struct.calcsize(fmt_string)
cr3, kpcr, number_of_runs = struct.unpack_from(fmt_string, result)
for x in range(number_of_runs):
start, length = struct.unpack_from("QQ", result, x * 16 + offset)
print("0x%X\t\t0x%X" % (start, length))
FIELDS = (["CR3", "NtBuildNumber", "KernBase", "KDBG"] +
["KPCR%02d" % i for i in range(32)] +
["PfnDataBase", "PsLoadedModuleList", "PsActiveProcessHead"] +
["Padding%s" % i for i in range(0xff)] +
["NumberOfRuns"])
def ParseMemoryRuns(self):
self.runs = []
result = win32file.DeviceIoControl(
self.fd, INFO_IOCTRL, "", 102400, None)
fmt_string = "Q" * len(self.FIELDS)
self.memory_parameters = dict(zip(self.FIELDS, struct.unpack_from(
fmt_string, result)))
self.dtb = self.memory_parameters["CR3"]
self.kdbg = self.memory_parameters["KDBG"]
offset = struct.calcsize(fmt_string)
for x in range(self.memory_parameters["NumberOfRuns"]):
start, length = struct.unpack_from("QQ", result, x * 16 + offset)
self.runs.append((start, length))
def GetInfo(self):
for k, v in sorted(self.memory_parameters.items()):
if k.startswith("Pad"):
continue
if not v: continue
print("%s: \t%#08x (%s)" % (k, v, v))
print("Memory ranges:")
print("Start\t\tEnd\t\tLength")
for start, length in self.runs:
print("0x%X\t\t0x%X\t\t0x%X" % (start, start+length, length))
def SetMode(self):
if FLAGS.mode == "iospace":
mode = 0
elif FLAGS.mode == "physical":
mode = 1
elif FLAGS.mode == "pte":
mode = 2
elif FLAGS.mode == "pte_pci":
mode = 3
else:
raise RuntimeError("Mode %s not supported" % FLAGS.mode)
win32file.DeviceIoControl(
self.fd, CTRL_IOCTRL, struct.pack("I", mode), 0, None)
def PadWithNulls(self, outfd, length):
while length > 0:
to_write = min(length, self.buffer_size)
outfd.write("\x00" * to_write)
length -= to_write
def DumpWithRead(self, output_filename):
"""Read the image and write all the data to a raw file."""
with open(output_filename, "wb") as outfd:
offset = 0
for start, length in self.runs:
if start > offset:
print("\nPadding from 0x%X to 0x%X\n" % (offset, start))
self.PadWithNulls(outfd, start - offset)
offset = start
end = start + length
while offset < end:
to_read = min(self.buffer_size, end - offset)
win32file.SetFilePointer(self.fd, offset, 0)
_, data = win32file.ReadFile(self.fd, to_read)
outfd.write(data)
offset += to_read
offset_in_mb = offset/1024/1024
if not offset_in_mb % 50:
sys.stdout.write("\n%04dMB\t" % offset_in_mb)
sys.stdout.write(".")
sys.stdout.flush()
def main():
"""Load the driver and image the memory."""
# Check the driver is somewhere
if not FLAGS.driver or not os.access(FLAGS.driver, os.R_OK):
print("You must specify a valid driver file.")
sys.exit(-1)
# Must have absolute path here.
driver = os.path.join(os.getcwd(), FLAGS.driver)
hScm = win32service.OpenSCManager(
None, None, win32service.SC_MANAGER_CREATE_SERVICE)
try:
hSvc = win32service.CreateService(
hScm, FLAGS.name, FLAGS.name,
win32service.SERVICE_ALL_ACCESS,
win32service.SERVICE_KERNEL_DRIVER,
win32service.SERVICE_DEMAND_START,
win32service.SERVICE_ERROR_IGNORE,
driver,
None, 0, None, None, None)
except win32service.error as e:
print(e)
hSvc = win32service.OpenService(hScm, FLAGS.name,
win32service.SERVICE_ALL_ACCESS)
# Make sure the service is stopped.
try:
win32service.ControlService(hSvc, win32service.SERVICE_CONTROL_STOP)
except win32service.error:
pass
if FLAGS.unload:
print("unloaded winpmem driver.")
return
try:
win32service.StartService(hSvc, [])
except win32service.error as e:
print("%s: will try to continue" % e)
if FLAGS.load:
fd = win32file.CreateFile(
"\\\\.\\" + FLAGS.name,
win32file.GENERIC_READ | win32file.GENERIC_WRITE,
win32file.FILE_SHARE_READ | win32file.FILE_SHARE_WRITE,
None,
win32file.OPEN_EXISTING,
win32file.FILE_ATTRIBUTE_NORMAL,
None)
print(r"Loaded the winpmem driver. You can now attach "
r"volatility to \\.\pmem")
image = Image(fd)
return
try:
fd = win32file.CreateFile(
"\\\\.\\" + FLAGS.name,
win32file.GENERIC_READ | win32file.GENERIC_WRITE,
win32file.FILE_SHARE_READ | win32file.FILE_SHARE_WRITE,
None,
win32file.OPEN_EXISTING,
win32file.FILE_ATTRIBUTE_NORMAL,
None)
try:
t = time.time()
image = Image(fd)
print("Imaging to %s" % FLAGS.filename)
image.DumpWithRead(FLAGS.filename)
print("\nCompleted in %s seconds" % (time.time() - t))
finally:
win32file.CloseHandle(fd)
finally:
try:
win32service.ControlService(hSvc, win32service.SERVICE_CONTROL_STOP)
except win32service.error:
pass
win32service.DeleteService(hSvc)
win32service.CloseServiceHandle(hSvc)
if __name__ == "__main__":
(FLAGS, args) = parser.parse_args()
main()
View File
View File
+4
View File
@@ -0,0 +1,4 @@
all:
rm -rf ../docs/
hugo
echo winpmem.velocidex.com > ../docs/CNAME
+4
View File
@@ -0,0 +1,4 @@
The Pmem Memory acquisition tools.
==================================
This is the documentation site for WinPmem
+1 -1
View File
@@ -2,7 +2,7 @@ baseURL = "https://winpmem.velocidex.com/"
languageCode = "en-us"
title = "WinPmem memory imager"
theme = "hugo-whisper-theme"
publishDir = "docs"
publishDir = "../docs"
pygmentsCodeFences = true
pygmentsCodefencesGuessSyntax = true
pygmentsUseClasses = true