Version 2.0

This commit is contained in:
Ulf Frisk
2019-02-06 14:14:31 +01:00
parent b89bee2c38
commit a1b02c970c
105 changed files with 7894 additions and 4194 deletions
+1
View File
@@ -1,4 +1,5 @@
/.vs
*.ilk
*pycache*
/files/vmm_example.exe
/files/lib
+67 -65
View File
@@ -1,109 +1,111 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28010.2050
VisualStudioVersion = 15.0.27703.2026
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MemProcFS", "MemProcFS\MemProcFS.vcxproj", "{0EEC1AAA-D3BD-4DC1-8EAD-7629617A12A5}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MemProcFS", "MemProcFS\MemProcFS.vcxproj", "{A9CE6DD1-A834-4FFD-A4C2-50D9D2F14BFD}"
ProjectSection(ProjectDependencies) = postProject
{18BEBDF1-73F2-4ABB-BDBE-507ADAB32494} = {18BEBDF1-73F2-4ABB-BDBE-507ADAB32494}
{6326FCE0-1BA5-4AEC-9973-7783309FFD6B} = {6326FCE0-1BA5-4AEC-9973-7783309FFD6B}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmm", "vmm\vmm.vcxproj", "{18BEBDF1-73F2-4ABB-BDBE-507ADAB32494}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "m_vmemd", "m_vmemd\m_vmemd.vcxproj", "{41D93156-9DCB-4F19-BF02-993CEC361A81}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmm", "vmm\vmm.vcxproj", "{6326FCE0-1BA5-4AEC-9973-7783309FFD6B}"
ProjectSection(ProjectDependencies) = postProject
{18BEBDF1-73F2-4ABB-BDBE-507ADAB32494} = {18BEBDF1-73F2-4ABB-BDBE-507ADAB32494}
{3476ABD2-5DEA-43E6-A676-8BE25F74535A} = {3476ABD2-5DEA-43E6-A676-8BE25F74535A}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmmpyc", "vmmpyc\vmmpyc.vcxproj", "{8F227E6C-6156-4F7D-965F-BDB9B75FFB4E}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "m_vmemd", "m_vmemd\m_vmemd.vcxproj", "{BC6D11FF-3B1E-480E-A1AB-AAE5868FE9B3}"
ProjectSection(ProjectDependencies) = postProject
{18BEBDF1-73F2-4ABB-BDBE-507ADAB32494} = {18BEBDF1-73F2-4ABB-BDBE-507ADAB32494}
{6326FCE0-1BA5-4AEC-9973-7783309FFD6B} = {6326FCE0-1BA5-4AEC-9973-7783309FFD6B}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmmpycplugin", "vmmpycplugin\vmmpycplugin.vcxproj", "{D32F2480-E640-4239-96DA-E31CCA2F13BA}"
ProjectSection(ProjectDependencies) = postProject
{18BEBDF1-73F2-4ABB-BDBE-507ADAB32494} = {18BEBDF1-73F2-4ABB-BDBE-507ADAB32494}
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "python", "python", "{0E07FB2B-5955-4CAC-AD31-E8352D7912A3}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "python", "python", "{50E46B01-0786-4222-B8C8-8D1612DA8A3B}"
ProjectSection(SolutionItems) = preProject
files\vmmpy.py = files\vmmpy.py
files\vmmpy_example.py = files\vmmpy_example.py
files\vmmpyplugin.py = files\vmmpyplugin.py
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmm_example", "vmm_example\vmm_example.vcxproj", "{7B05E64E-569F-4EF5-8F37-FA5B39B64227}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmmpyc", "vmmpyc\vmmpyc.vcxproj", "{9E47796D-B834-470E-B437-0754BC14DF09}"
ProjectSection(ProjectDependencies) = postProject
{18BEBDF1-73F2-4ABB-BDBE-507ADAB32494} = {18BEBDF1-73F2-4ABB-BDBE-507ADAB32494}
{6326FCE0-1BA5-4AEC-9973-7783309FFD6B} = {6326FCE0-1BA5-4AEC-9973-7783309FFD6B}
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dissect.cstruct", "dissect.cstruct", "{28BE8236-5D12-4D09-B87D-5AB79A85B54A}"
ProjectSection(SolutionItems) = preProject
files\dissect\cstruct\__init__.py = files\dissect\cstruct\__init__.py
files\dissect\cstruct\cstruct.py = files\dissect\cstruct\cstruct.py
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmmpycplugin", "vmmpycplugin\vmmpycplugin.vcxproj", "{283FF01B-31A6-465A-A728-F187F974EFF4}"
ProjectSection(ProjectDependencies) = postProject
{6326FCE0-1BA5-4AEC-9973-7783309FFD6B} = {6326FCE0-1BA5-4AEC-9973-7783309FFD6B}
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "plugins.pym_procstruct", "plugins.pym_procstruct", "{BF8E8135-E8FA-49CF-A3CB-DA35B0581A77}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmm_example", "vmm_example\vmm_example.vcxproj", "{45CC506E-E97A-45B8-8050-B2C5BC8A4B15}"
ProjectSection(ProjectDependencies) = postProject
{6326FCE0-1BA5-4AEC-9973-7783309FFD6B} = {6326FCE0-1BA5-4AEC-9973-7783309FFD6B}
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "plugins.pym_procstruct", "plugins.pym_procstruct", "{7BEEEE90-F2CC-4ADD-BA8B-82599E3D1408}"
ProjectSection(SolutionItems) = preProject
files\plugins\pym_procstruct\__init__.py = files\plugins\pym_procstruct\__init__.py
files\plugins\pym_procstruct\pym_procstruct.py = files\plugins\pym_procstruct\pym_procstruct.py
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dissect.cstruct", "dissect.cstruct", "{A8B68178-FE06-42E2-80C9-2C936973B5FA}"
ProjectSection(SolutionItems) = preProject
files\dissect\cstruct\__init__.py = files\dissect\cstruct\__init__.py
files\dissect\cstruct\cstruct.py = files\dissect\cstruct\cstruct.py
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "leechcore", "..\LeechCore\leechcore\leechcore.vcxproj", "{3476ABD2-5DEA-43E6-A676-8BE25F74535A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "leechsvc", "..\LeechCore\leechsvc\leechsvc.vcxproj", "{4FAF78C0-D61B-41CE-830E-62C38DACDD52}"
ProjectSection(ProjectDependencies) = postProject
{3476ABD2-5DEA-43E6-A676-8BE25F74535A} = {3476ABD2-5DEA-43E6-A676-8BE25F74535A}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0EEC1AAA-D3BD-4DC1-8EAD-7629617A12A5}.Debug|x64.ActiveCfg = Debug|x64
{0EEC1AAA-D3BD-4DC1-8EAD-7629617A12A5}.Debug|x64.Build.0 = Debug|x64
{0EEC1AAA-D3BD-4DC1-8EAD-7629617A12A5}.Debug|x86.ActiveCfg = Debug|x64
{0EEC1AAA-D3BD-4DC1-8EAD-7629617A12A5}.Release|x64.ActiveCfg = Release|x64
{0EEC1AAA-D3BD-4DC1-8EAD-7629617A12A5}.Release|x64.Build.0 = Release|x64
{0EEC1AAA-D3BD-4DC1-8EAD-7629617A12A5}.Release|x86.ActiveCfg = Release|x64
{18BEBDF1-73F2-4ABB-BDBE-507ADAB32494}.Debug|x64.ActiveCfg = Debug|x64
{18BEBDF1-73F2-4ABB-BDBE-507ADAB32494}.Debug|x64.Build.0 = Debug|x64
{18BEBDF1-73F2-4ABB-BDBE-507ADAB32494}.Debug|x86.ActiveCfg = Debug|x64
{18BEBDF1-73F2-4ABB-BDBE-507ADAB32494}.Release|x64.ActiveCfg = Release|x64
{18BEBDF1-73F2-4ABB-BDBE-507ADAB32494}.Release|x64.Build.0 = Release|x64
{18BEBDF1-73F2-4ABB-BDBE-507ADAB32494}.Release|x86.ActiveCfg = Release|x64
{41D93156-9DCB-4F19-BF02-993CEC361A81}.Debug|x64.ActiveCfg = Debug|x64
{41D93156-9DCB-4F19-BF02-993CEC361A81}.Debug|x64.Build.0 = Debug|x64
{41D93156-9DCB-4F19-BF02-993CEC361A81}.Debug|x86.ActiveCfg = Debug|x64
{41D93156-9DCB-4F19-BF02-993CEC361A81}.Release|x64.ActiveCfg = Release|x64
{41D93156-9DCB-4F19-BF02-993CEC361A81}.Release|x64.Build.0 = Release|x64
{41D93156-9DCB-4F19-BF02-993CEC361A81}.Release|x86.ActiveCfg = Release|x64
{8F227E6C-6156-4F7D-965F-BDB9B75FFB4E}.Debug|x64.ActiveCfg = Debug|x64
{8F227E6C-6156-4F7D-965F-BDB9B75FFB4E}.Debug|x64.Build.0 = Debug|x64
{8F227E6C-6156-4F7D-965F-BDB9B75FFB4E}.Debug|x86.ActiveCfg = Debug|x64
{8F227E6C-6156-4F7D-965F-BDB9B75FFB4E}.Release|x64.ActiveCfg = Release|x64
{8F227E6C-6156-4F7D-965F-BDB9B75FFB4E}.Release|x64.Build.0 = Release|x64
{8F227E6C-6156-4F7D-965F-BDB9B75FFB4E}.Release|x86.ActiveCfg = Release|x64
{D32F2480-E640-4239-96DA-E31CCA2F13BA}.Debug|x64.ActiveCfg = Debug|x64
{D32F2480-E640-4239-96DA-E31CCA2F13BA}.Debug|x64.Build.0 = Debug|x64
{D32F2480-E640-4239-96DA-E31CCA2F13BA}.Debug|x86.ActiveCfg = Debug|x64
{D32F2480-E640-4239-96DA-E31CCA2F13BA}.Release|x64.ActiveCfg = Release|x64
{D32F2480-E640-4239-96DA-E31CCA2F13BA}.Release|x64.Build.0 = Release|x64
{D32F2480-E640-4239-96DA-E31CCA2F13BA}.Release|x86.ActiveCfg = Release|x64
{7B05E64E-569F-4EF5-8F37-FA5B39B64227}.Debug|x64.ActiveCfg = Debug|x64
{7B05E64E-569F-4EF5-8F37-FA5B39B64227}.Debug|x64.Build.0 = Debug|x64
{7B05E64E-569F-4EF5-8F37-FA5B39B64227}.Debug|x86.ActiveCfg = Debug|Win32
{7B05E64E-569F-4EF5-8F37-FA5B39B64227}.Debug|x86.Build.0 = Debug|Win32
{7B05E64E-569F-4EF5-8F37-FA5B39B64227}.Release|x64.ActiveCfg = Release|x64
{7B05E64E-569F-4EF5-8F37-FA5B39B64227}.Release|x64.Build.0 = Release|x64
{7B05E64E-569F-4EF5-8F37-FA5B39B64227}.Release|x86.ActiveCfg = Release|Win32
{7B05E64E-569F-4EF5-8F37-FA5B39B64227}.Release|x86.Build.0 = Release|Win32
{A9CE6DD1-A834-4FFD-A4C2-50D9D2F14BFD}.Debug|x64.ActiveCfg = Debug|x64
{A9CE6DD1-A834-4FFD-A4C2-50D9D2F14BFD}.Debug|x64.Build.0 = Debug|x64
{A9CE6DD1-A834-4FFD-A4C2-50D9D2F14BFD}.Release|x64.ActiveCfg = Release|x64
{A9CE6DD1-A834-4FFD-A4C2-50D9D2F14BFD}.Release|x64.Build.0 = Release|x64
{6326FCE0-1BA5-4AEC-9973-7783309FFD6B}.Debug|x64.ActiveCfg = Debug|x64
{6326FCE0-1BA5-4AEC-9973-7783309FFD6B}.Debug|x64.Build.0 = Debug|x64
{6326FCE0-1BA5-4AEC-9973-7783309FFD6B}.Release|x64.ActiveCfg = Release|x64
{6326FCE0-1BA5-4AEC-9973-7783309FFD6B}.Release|x64.Build.0 = Release|x64
{BC6D11FF-3B1E-480E-A1AB-AAE5868FE9B3}.Debug|x64.ActiveCfg = Debug|x64
{BC6D11FF-3B1E-480E-A1AB-AAE5868FE9B3}.Debug|x64.Build.0 = Debug|x64
{BC6D11FF-3B1E-480E-A1AB-AAE5868FE9B3}.Release|x64.ActiveCfg = Release|x64
{BC6D11FF-3B1E-480E-A1AB-AAE5868FE9B3}.Release|x64.Build.0 = Release|x64
{9E47796D-B834-470E-B437-0754BC14DF09}.Debug|x64.ActiveCfg = Debug|x64
{9E47796D-B834-470E-B437-0754BC14DF09}.Debug|x64.Build.0 = Debug|x64
{9E47796D-B834-470E-B437-0754BC14DF09}.Release|x64.ActiveCfg = Release|x64
{9E47796D-B834-470E-B437-0754BC14DF09}.Release|x64.Build.0 = Release|x64
{283FF01B-31A6-465A-A728-F187F974EFF4}.Debug|x64.ActiveCfg = Debug|x64
{283FF01B-31A6-465A-A728-F187F974EFF4}.Debug|x64.Build.0 = Debug|x64
{283FF01B-31A6-465A-A728-F187F974EFF4}.Release|x64.ActiveCfg = Release|x64
{283FF01B-31A6-465A-A728-F187F974EFF4}.Release|x64.Build.0 = Release|x64
{45CC506E-E97A-45B8-8050-B2C5BC8A4B15}.Debug|x64.ActiveCfg = Debug|x64
{45CC506E-E97A-45B8-8050-B2C5BC8A4B15}.Debug|x64.Build.0 = Debug|x64
{45CC506E-E97A-45B8-8050-B2C5BC8A4B15}.Release|x64.ActiveCfg = Release|x64
{45CC506E-E97A-45B8-8050-B2C5BC8A4B15}.Release|x64.Build.0 = Release|x64
{3476ABD2-5DEA-43E6-A676-8BE25F74535A}.Debug|x64.ActiveCfg = Debug|x64
{3476ABD2-5DEA-43E6-A676-8BE25F74535A}.Debug|x64.Build.0 = Debug|x64
{3476ABD2-5DEA-43E6-A676-8BE25F74535A}.Release|x64.ActiveCfg = Release|x64
{3476ABD2-5DEA-43E6-A676-8BE25F74535A}.Release|x64.Build.0 = Release|x64
{4FAF78C0-D61B-41CE-830E-62C38DACDD52}.Debug|x64.ActiveCfg = Debug|x64
{4FAF78C0-D61B-41CE-830E-62C38DACDD52}.Debug|x64.Build.0 = Debug|x64
{4FAF78C0-D61B-41CE-830E-62C38DACDD52}.Release|x64.ActiveCfg = Release|x64
{4FAF78C0-D61B-41CE-830E-62C38DACDD52}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{28BE8236-5D12-4D09-B87D-5AB79A85B54A} = {0E07FB2B-5955-4CAC-AD31-E8352D7912A3}
{BF8E8135-E8FA-49CF-A3CB-DA35B0581A77} = {0E07FB2B-5955-4CAC-AD31-E8352D7912A3}
{7BEEEE90-F2CC-4ADD-BA8B-82599E3D1408} = {50E46B01-0786-4222-B8C8-8D1612DA8A3B}
{A8B68178-FE06-42E2-80C9-2C936973B5FA} = {50E46B01-0786-4222-B8C8-8D1612DA8A3B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {25E47F6A-275C-46EB-9121-6EECCE1B8075}
SolutionGuid = {CE6C3AA7-477A-4329-B4E3-5F219ACF4063}
EndGlobalSection
EndGlobal
Binary file not shown.
+39 -8
View File
@@ -12,9 +12,9 @@
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{0EEC1AAA-D3BD-4DC1-8EAD-7629617A12A5}</ProjectGuid>
<ProjectGuid>{A9CE6DD1-A834-4FFD-A4C2-50D9D2F14BFD}</ProjectGuid>
<RootNamespace>MemProcFS</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
@@ -22,6 +22,7 @@
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
@@ -29,6 +30,7 @@
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@@ -45,7 +47,6 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>$(SolutionDir)\files\</OutDir>
<IntDir>$(SolutionDir)\files\temp\$(ProjectName)\</IntDir>
<LinkIncremental />
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>$(SolutionDir)\files\</OutDir>
@@ -56,11 +57,23 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<CompileAs>CompileAsC</CompileAs>
<ExceptionHandling>false</ExceptionHandling>
<PrecompiledHeader />
<PrecompiledHeaderFile />
<PrecompiledHeaderOutputFile />
</ClCompile>
<PostBuildEvent>
<Command>
</Command>
</PostBuildEvent>
<Link>
<ProgramDatabaseFile>$(OutDir)\lib\$(TargetName).pdb</ProgramDatabaseFile>
</Link>
<PreBuildEvent>
<Command>copy $(SolutionDir)\files\leechcore.h $(ProjectDir)\ /y
copy $(SolutionDir)\files\vmmdll.h $(ProjectDir)\ /y</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
@@ -69,25 +82,43 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<CompileAs>CompileAsC</CompileAs>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<ExceptionHandling>false</ExceptionHandling>
<PrecompiledHeader />
<PrecompiledHeaderFile />
<PrecompiledHeaderOutputFile />
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
<ProgramDatabaseFile>$(OutDir)\lib\$(TargetName).pdb</ProgramDatabaseFile>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
</Link>
<PostBuildEvent>
<Command>
</Command>
</PostBuildEvent>
<PreBuildEvent>
<Command>copy $(SolutionDir)\files\leechcore.h $(ProjectDir)\ /y
copy $(SolutionDir)\files\vmmdll.h $(ProjectDir)\ /y</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="memprocfs.c" />
<ClCompile Include="vfs.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="dokan.h" />
<ClInclude Include="fileinfo.h" />
<ClInclude Include="leechcore.h" />
<ClInclude Include="public.h" />
<ClInclude Include="version.h" />
<ClInclude Include="vfs.h" />
<ClInclude Include="vmmdll.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="memprocfs.c" />
<ClCompile Include="vfs.c" />
<ResourceCompile Include="MemProcFS.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
+23 -9
View File
@@ -14,13 +14,27 @@
<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="Header Files\dokan">
<UniqueIdentifier>{48be56a3-760b-4123-bfa4-2df9018c3445}</UniqueIdentifier>
<UniqueIdentifier>{3df63be8-ffcd-417a-a1f9-c8d774863692}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\vmm">
<UniqueIdentifier>{bb78aad0-c3f0-457d-beb5-0a916ec07fd7}</UniqueIdentifier>
<UniqueIdentifier>{ef93cbf4-5326-46d3-a5e0-6fb6d61d08f0}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\leechcore">
<UniqueIdentifier>{5c8e3ce6-1d2e-46ff-b5a6-a928f4c1569f}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="memprocfs.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vfs.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="vfs.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="dokan.h">
<Filter>Header Files\dokan</Filter>
</ClInclude>
@@ -33,16 +47,16 @@
<ClInclude Include="vmmdll.h">
<Filter>Header Files\vmm</Filter>
</ClInclude>
<ClInclude Include="vfs.h">
<ClInclude Include="leechcore.h">
<Filter>Header Files\leechcore</Filter>
</ClInclude>
<ClInclude Include="version.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="memprocfs.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vfs.c">
<Filter>Source Files</Filter>
</ClCompile>
<ResourceCompile Include="MemProcFS.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>
+6 -1
View File
@@ -1,4 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>
+8 -8
View File
@@ -55,7 +55,7 @@ extern "C" {
/** @{ */
/** The current Dokan version (ver 1.2.0). \ref DOKAN_OPTIONS.Version */
#define DOKAN_VERSION 120
#define DOKAN_VERSION 121
/** Minimum Dokan version (ver 1.1.0) accepted. */
#define DOKAN_MINIMUM_COMPATIBLE_VERSION 110
/** Maximum number of dokan instances.*/
@@ -101,22 +101,22 @@ extern "C" {
* \see DokanMain
*/
typedef struct _DOKAN_OPTIONS {
/** Version of the Dokan features requested (version "123" is equal to Dokan version 1.2.3). */
/** Version of the Dokan features requested without dots (version "123" is equal to Dokan version 1.2.3). */
USHORT Version;
/** Number of threads to be used internally by Dokan library. More threads will handle more events at the same time. */
/** Number of threads to be used by Dokan library internally. More threads will handle more events at the same time. */
USHORT ThreadCount;
/** Features enabled for the mount. See \ref DOKAN_OPTION. */
ULONG Options;
/** FileSystem can store anything here. */
ULONG64 GlobalContext;
/** Mount point. Can be "M:\" (drive letter) or "C:\mount\dokan" (path in NTFS). */
/** Mount point. It can be a driver letter like "M:\" or a folder path "C:\mount\dokan" on a NTFS partition. */
LPCWSTR MountPoint;
/**
* UNC Name for the Network Redirector
* \see <a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff556761(v=vs.85).aspx">Support for UNC Naming</a>
*/
LPCWSTR UNCName;
/** Max timeout in milliseconds of each request before Dokan gives up. */
/** Max timeout in milliseconds of each request before Dokan gives up to wait events to complete. */
ULONG Timeout;
/** Allocation Unit Size of the volume. This will affect the file size. */
ULONG AllocationUnitSize;
@@ -741,7 +741,7 @@ int DOKANAPI DokanMain(PDOKAN_OPTIONS DokanOptions,
* \brief Unmount a Dokan device from a driver letter.
*
* \param DriveLetter Dokan driver letter to unmount.
* \return \c TRUE if device was unmounted or False in case of failure or device not found.
* \return \c TRUE if device was unmounted or \c FALSE in case of failure or device not found.
*/
BOOL DOKANAPI DokanUnmount(WCHAR DriveLetter);
@@ -749,7 +749,7 @@ BOOL DOKANAPI DokanUnmount(WCHAR DriveLetter);
* \brief Unmount a Dokan device from a mount point
*
* \param MountPoint Mount point to unmount ("Z", "Z:", "Z:\", "Z:\MyMountPoint").
* \return \c TRUE if device was unmounted or False in case of failure or device not found.
* \return \c TRUE if device was unmounted or \c FALSE in case of failure or device not found.
*/
BOOL DOKANAPI DokanRemoveMountPoint(LPCWSTR MountPoint);
@@ -764,7 +764,7 @@ BOOL DOKANAPI DokanRemoveMountPoint(LPCWSTR MountPoint);
*
* \param MountPoint Mount point to unmount ("Z", "Z:", "Z:\", "Z:\MyMountPoint").
* \param Safe Process is not in DLL_PROCESS_DETACH state.
* \return True if device was unmounted or False in case of failure or device not found.
* \return \c TRUE if device was unmounted or \c FALSE in case of failure or device not found.
*/
BOOL DOKANAPI DokanRemoveMountPointEx(LPCWSTR MountPoint, BOOL Safe);
+466
View File
@@ -0,0 +1,466 @@
// leechcore.h : header file for the leechcore module - which purpose is to
// expose low-level device physical memory functionality.
//
// This library is thread-safe in all functions with the notable exceptions of
// the LeechCore_Open() and LeechCore_Close() functions. Some devices may allow
// multi-threaded access while in reality most devices are single-threaded and
// will control synchronization where necessary with locks.
//
// The library is initialized by calling LeechCore_Open with a LEECHCORE_CONFIG
// struct containing the correct configuration paramters. Note that the version
// and magic values must be set in addition to the szDevice configuration value
// Also, it may be possible to optionally connect to a remote leechcore service
// or instance over RPC by specifying a szRemote configuration value.
//
// ----------------------------------------------------------------------------
//
// Remote instance: szRemote configuration value. Connect to a remote leechcore
// instance by specifying a configuration value in the szRemote parameter. If a
// loaded already valid instance exists remotely this will be prioritized above
// the value in szDevice. If the acquisition device is not yet loaded by the
// remote instance the value in szDevice will be used. Normally, the connection
// will take place as a mutually authenticated encrypted connection secured by
// kerberos. If not possible or desirable the 'insecure' value may be specified
// to disable authentication and security.
// Syntax:
// rpc://<remote_spn>:<host>:<port> (port = optional, remote_spn = kerberos)
// (SPN of remote service or 'insecure' )
// Examples:
// rpc://insecure:remotehost.example.com (connect insecure to remote host )
// rpc://[email protected]:192.0.0.5 (connect secure to remote host )
// rpc://insecure:127.0.0.0:6666 (connect insecure non-default port)
//
// ----------------------------------------------------------------------------
//
// Device to connect to: szDevice contains the device to capture memory from.
// Supported memory acquisition devices are:
// USB3380 : hardware, read/write, 32-bit (4GB) addressing only. Requires a
// PCILeech flashed USB3380 device connected over USB and Google
// Android WinUSB drivers to be installed. Download and install from:
// http://developer.android.com/sdk/win-usb.html#download
// Syntax:
// USB3380
// USB3380://USB2 (force USB2 connection speed)
//
// FPGA : hardware, read/write - requires a PCILeech FPGA flashed hardware
// device as shown at: https://github.com/ufrisk/pcileech-fpga
// Also requires the FTD3XX.DLL from ftdichip to be placed in the
// same directory as the executable. Download from ftdichip at:
// http://www.ftdichip.com/Drivers/D3XX/FTD3XXLibrary_v1.2.0.6.zip
// Syntax:
// FGPA
// FPGA://<read_uS>[:<write_uS>[:<probe_uS>]] (values are optional)
//
// SP605TCP : hardware, read/write - connect to a remote SP605 FPGA over the
// network using the implementation created by @d_olex.
// https://github.com/Cr4sh/s6_pcie_microblaze
// Syntax:
// SP605TCP://<target_ip>[:<target_port>] (port is optional)
//
// RAWTCP : read/write - connect to a remote raw tcp device - such as HPE iLO
// that have been patched to support DMA as per blog entry below:
// https://www.synacktiv.com/posts/exploit/using-your-bmc-as-a-dma-device-plugging-pcileech-to-hpe-ilo-4.html
// Syntax:
// RAWTCP://<target_ip>[:<target_port>] (port is optional)
//
// HvSavedState : read-only - connect to a Hyper-V saved state file. In order
// to do so the .dll file 'vmsavedstatedumpprovider.dll' must be
// placed in same directory as the executable file.
//
// PMEM : load the rekall winpmem driver into the kernel and connect to it
// to acquire memory. The driver file 'winpmem_x64.sys' is found in
// the Rekall directory after most recent version has been installed.
// Copy 'winpmem_x64.sys' to the directory of leechcore.dll and run
// executable as elevated admin using syntax below:
// Syntax:
// PMEM (use winpmem_x64.sys in directory of executable)
// PMEM://<non_default_path_to_file_winpmem_x64.sys>
//
// TOTALMELTDOWN : read/write - requires a Windows 7 system vulnerable to the
// "Total Meltdown" vulnerability - CVE-2018-1038.
// Syntax:
// TOTALMELTDOWN
//
// FILE : use dump file, either a raw linear memory dump or full crash dump.
// Which format to use is auto-detected. If it looks like a full cash
// dump that format will be used, otherwise it will be assumed that a
// raw linear memory dump is to be used.
// Syntax:
// <filename> (no device-type prefix - just use the file name)
// FILE://<filename>
//
// DumpIt : DumpIt is a "virtual" device. It's only possible to use the DumpIt
// device if the main process containing LeechCore has been started
// with DumpIt in LiveKD mode.
// Example 1:
// DumpIt.exe /LIVEKD /A MemProcFS.exe
// Example 2:
// DumpIt.exe /LIVEKD /A LeechSvc.exe /C "interactive insecure"
// and then connect to remote service by:
// MemProcFS.exe -remote rpc://insecure:192.168.x.x -device DumpIt
//
// EXISTING : Attach to existing already loaded configuration. This is done
// instead of the default behaviour of closing any existing devices
// and initializing the new requested device. If no existing device
// exists the call to LeechCore_Open will fail.
// Syntax:
// EXISTING
//
//
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
// Header Version: 1.0
//
#ifndef __LEECHCORE_H__
#define __LEECHCORE_H__
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
//-----------------------------------------------------------------------------
// WINDOWS / LINUX COMPATIBILITY BELOW:
//-----------------------------------------------------------------------------
#ifdef _WIN32
#include <Windows.h>
typedef unsigned __int64 QWORD, *PQWORD;
#define DLLEXPORT __declspec(dllexport)
#endif /* _WIN32 */
#ifdef LINUX
#include <stdint.h>
#include <stddef.h>
typedef void VOID, *PVOID, *LPVOID;
typedef void *HANDLE, **PHANDLE;
typedef uint32_t BOOL, *PBOOL;
typedef uint8_t BYTE, *PBYTE;
typedef char CHAR, *PCHAR, *PSTR, *LPSTR;
typedef uint16_t WORD, *PWORD, USHORT, *PUSHORT;
typedef uint32_t DWORD, *PDWORD;
typedef long long unsigned int QWORD, *PQWORD, ULONG64, *PULONG64;
#define MAX_PATH 260
#define DLLEXPORT __attribute__((visibility("default")))
#define _In_
#define _Out_
#define _In_z_
#define _Inout_
#define _In_opt_
#define _Out_opt_
#define _Out_writes_(x)
#define _Check_return_opt_
#define _Printf_format_string_
#define _Inout_updates_bytes_(x)
#define _In_reads_(cbDataIn)
#define _Success_(return)
#endif /* LINUX */
//-----------------------------------------------------------------------------
// GENERAL HEADER DEFINES BELOW:
//-----------------------------------------------------------------------------
#define MEM_IO_SCATTER_HEADER_MAGIC 0xffff6548
#define MEM_IO_SCATTER_HEADER_VERSION 0x0003
typedef struct tdMEM_IO_SCATTER_HEADER {
DWORD magic; // magic
WORD version; // version
WORD Future1;
ULONG64 qwA; // base address.
DWORD cbMax; // bytes to read (DWORD boundry, max 0x1000); pb must have room for this.
DWORD cb; // bytes read into result buffer.
PBYTE pb; // ptr to 0x1000 sized buffer to receive read bytes.
PVOID pvReserved1; // reserved for use by caller.
PVOID pvReserved2; // reserved for use by caller.
PVOID Future2[8];
} MEM_IO_SCATTER_HEADER, *PMEM_IO_SCATTER_HEADER, **PPMEM_IO_SCATTER_HEADER;
//-----------------------------------------------------------------------------
// LEECHCORE INITIALIZATION / CLOSE FUNCTIONALITY BELOW:
//-----------------------------------------------------------------------------
typedef enum tdLEECHCORE_DEVICE {
LEECHCORE_DEVICE_NA = 0,
LEECHCORE_DEVICE_FILE = 1,
LEECHCORE_DEVICE_PMEM = 2,
LEECHCORE_DEVICE_FPGA = 3,
LEECHCORE_DEVICE_SP605_TCP = 4,
LEECHCORE_DEVICE_USB3380 = 5,
LEECHCORE_DEVICE_TOTALMELTDOWN = 6,
LEECHCORE_DEVICE_HVSAVEDSTATE = 7,
LEECHCORE_DEVICE_RAWTCP = 8,
} LEECHCORE_DEVICE;
#define LEECHCORE_CONFIG_MAGIC 0xffff6549
#define LEECHCORE_CONFIG_VERSION 0x0001
#define LEECHCORE_CONFIG_FLAG_PRINTF 0x0001
#define LEECHCORE_CONFIG_FLAG_PRINTF_VERBOSE_1 0x0002
#define LEECHCORE_CONFIG_FLAG_PRINTF_VERBOSE_2 0x0004
#define LEECHCORE_CONFIG_FLAG_PRINTF_VERBOSE_3 0x0008
#define LEECHCORE_CONFIG_FLAG_REMOTE_NO_COMPRESS 0x0010
typedef struct tdLEECHCORE_CONFIG {
DWORD magic; // set by caller.
WORD version; // set by caller.
WORD flags; // set by caller, updated by device.
ULONG64 paMax; // set by caller, updated by device.
ULONG64 cbMaxSizeMemIo; // set by caller, updated by device.
ULONG64 paMaxNative; // set by device.
LEECHCORE_DEVICE tpDevice; // set by device.
BOOL fWritable; // set by device. (is device writable?)
BOOL fVolatile; // set by device. (is device volatile / memory may change?)
BOOL fVolatileMaxAddress; // set by device. (is max address volatile? - poll changes with LEECHCORE_OPT_MEMORYINFO_ADDR_MAX)
BOOL fRemote; // set by device.
WORD VersionMajor; // set by device.
WORD VersionMinor; // set by device.
WORD VersionRevision; // set by device.
CHAR szDevice[MAX_PATH]; // set by caller.
CHAR szRemote[MAX_PATH]; // set by caller.
// optional 'printf' function pointer. if set to non null value 'printf'
// calls will be redirected. useful when logging to files.
_Check_return_opt_ int(*pfn_printf_opt)(_In_z_ _Printf_format_string_ char const* const _Format, ...); // set by caller.
} LEECHCORE_CONFIG, *PLEECHCORE_CONFIG;
typedef struct tdLEECHCORE_PAGESTAT_MINIMAL {
HANDLE h;
VOID(*pfnPageStatUpdate)(HANDLE h, ULONG64 pa, ULONG64 cPageSuccessAdd, ULONG64 cPageFailAdd);
} LEECHCORE_PAGESTAT_MINIMAL, *PLEECHCORE_PAGESTAT_MINIMAL;
/*
* Open a connection to the target device.
* -- pInformation
* -- result
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_Open(_Inout_ PLEECHCORE_CONFIG pConfig);
/*
* Clean up various device related stuff and deallocate memory buffers.
*/
DLLEXPORT VOID LeechCore_Close();
//-----------------------------------------------------------------------------
// LEECHCORE CORE READ AND WRITE FUNCTIONALITY BELOW:
//-----------------------------------------------------------------------------
#define LEECHCORE_FLAG_READ_RETRY 0x01
#define LEECHCORE_FLAG_WRITE_RETRY 0x01
#define LEECHCORE_FLAG_WRITE_VERIFY 0x02
/*
* Allocate a scatter buffer containing empty 0x1000-sized ppMEMs with address
* set to zero. Caller is responsible for calling LocalFree(ppMEMs).
* -- cMEMs
* -- pppMEMs = pointer to receive ppMEMs on success.
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_AllocScatterEmpty(_In_ DWORD cMEMs, _Out_ PPMEM_IO_SCATTER_HEADER *pppMEMs);
/*
* Read memory in various non-contigious locations specified by the items in the
* phDMAs array. Result for each unit of work will be given individually. No upper
* limit of number of items to read, but no performance boost will be given if
* above hardware limit. Max size of each unit of work is one 4k page (4096 bytes).
* -- ppMEMs = array of scatter read headers.
* -- cpMEMs = count of ppDMAs.
*/
DLLEXPORT VOID LeechCore_ReadScatter(_Inout_ PPMEM_IO_SCATTER_HEADER ppMEMs, _In_ DWORD cpMEMs);
/*
* Try read memory in a fairly optimal way considering device limits. The number
* of total successfully read bytes is returned. Failed reads will be zeroed out
* in the returned memory.
* -- pa
* -- pb
* -- cb
* -- return = the number of bytes successfully read.
*/
DLLEXPORT DWORD LeechCore_Read(_In_ ULONG64 pa, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb);
/*
* Try read memory in a fairly optimal way considering device limits. The number
* of total successfully read bytes is returned. Failed reads will be zeroed out
* in the returned memory.
* -- pa
* -- pb
* -- cb
* -- flags = 0 or LEECHCORE_FLAG_READ_RETRY
* -- pPageStat = optional minimal statistic struct to update.
* -- return = the number of bytes successfully read.
*/
DLLEXPORT DWORD LeechCore_ReadEx(_In_ ULONG64 pa, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _In_ DWORD flags, _In_opt_ PLEECHCORE_PAGESTAT_MINIMAL pPageStat);
/*
* Write data to the target system if supported by the device.
* -- pa
* -- pb
* -- cb
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_Write(_In_ ULONG64 pa, _In_ PBYTE pb, _In_ DWORD cb);
/*
* Write data to the target system if supported by the device.
* -- pa
* -- pb
* -- cb
* -- flags = 0 or LEECHCORE_FLAG_WRITE_*
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_WriteEx(_In_ ULONG64 pa, _In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD flags);
/*
* Probe the memory of the target system to check whether it's readable or not.
* Please note that not all devices support this natively.
* -- pa = address to start probe from.
* -- cPages = number of 4kB pages to probe.
* -- pbResultMap = result map, 1 byte represents 1 page, 0 = fail, 1 = success.
* (individual page elements in pbResultMap must be set to 0 [fail] on call
* for probe to take place on individual page).
* -- return = FALSE if not supported by underlying hardware, TRUE if supported.
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_Probe(_In_ QWORD pa, _In_ DWORD cPages, _Inout_updates_bytes_(cPages) PBYTE pbResultMap);
//-----------------------------------------------------------------------------
// GET/SET DEVICE OPTIONS BELOW. SOME OPTIONS ARE GENERAL LEECHCORE OPTIONS
// WHILE OTHER ARE DEVICE SPECIFIC. USE FUNCTIONS:
// LeechCore_GetOption() AND LeechCore_GetOption() TO GET/SET OPTIONS.
// FOR DEVICE-SPECIFIC OPTIONS PLEASE SEE INDIVIDUAL DEVICE FILES FOR MORE
// DETAILED INFORMATION.
//-----------------------------------------------------------------------------
#define LEECHCORE_OPT_CORE_PRINTF_ENABLE 0x80000001 // RW
#define LEECHCORE_OPT_CORE_VERBOSE 0x80000002 // RW
#define LEECHCORE_OPT_CORE_VERBOSE_EXTRA 0x80000003 // RW
#define LEECHCORE_OPT_CORE_VERBOSE_EXTRA_TLP 0x80000004 // RW
#define LEECHCORE_OPT_CORE_VERSION_MAJOR 0x01000001 // R
#define LEECHCORE_OPT_CORE_VERSION_MINOR 0x01000002 // R
#define LEECHCORE_OPT_CORE_VERSION_REVISION 0x01000003 // R
#define LEECHCORE_OPT_MEMORYINFO_VALID 0x02000001 // R
#define LEECHCORE_OPT_MEMORYINFO_ADDR_MAX 0x02000002 // R
#define LEECHCORE_OPT_MEMORYINFO_FLAG_32BIT 0x02000003 // R
#define LEECHCORE_OPT_MEMORYINFO_FLAG_PAE 0x02000004 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_VERSION_MINOR 0x02000005 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_VERSION_MAJOR 0x02000006 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_DTB 0x02000007 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_PFN 0x02000008 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_PsLoadedModuleList 0x02000009 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_PsActiveProcessHead 0x0200000a // R
#define LEECHCORE_OPT_MEMORYINFO_OS_MACHINE_IMAGE_TP 0x0200000b // R
#define LEECHCORE_OPT_MEMORYINFO_OS_NUM_PROCESSORS 0x0200000c // R
#define LEECHCORE_OPT_MEMORYINFO_OS_SYSTEMTIME 0x0200000d // R
#define LEECHCORE_OPT_MEMORYINFO_OS_UPTIME 0x0200000e // R
#define LEECHCORE_OPT_MEMORYINFO_OS_KERNELBASE 0x0200000f // R
#define LEECHCORE_OPT_MEMORYINFO_OS_KERNELHINT 0x02000010 // R
#define LEECHCORE_OPT_FPGA_PROBE_MAXPAGES 0x03000001 // RW
#define LEECHCORE_OPT_FPGA_RX_FLUSH_LIMIT 0x03000002 // RW
#define LEECHCORE_OPT_FPGA_MAX_SIZE_RX 0x03000003 // RW
#define LEECHCORE_OPT_FPGA_MAX_SIZE_TX 0x03000004 // RW
#define LEECHCORE_OPT_FPGA_DELAY_PROBE_READ 0x03000005 // RW - uS
#define LEECHCORE_OPT_FPGA_DELAY_PROBE_WRITE 0x03000006 // RW - uS
#define LEECHCORE_OPT_FPGA_DELAY_WRITE 0x03000007 // RW - uS
#define LEECHCORE_OPT_FPGA_DELAY_READ 0x03000008 // RW - uS
#define LEECHCORE_OPT_FPGA_RETRY_ON_ERROR 0x03000009 // RW
#define LEECHCORE_OPT_FPGA_DEVICE_ID 0x03000080 // R
#define LEECHCORE_OPT_FPGA_FPGA_ID 0x03000081 // R
#define LEECHCORE_OPT_FPGA_VERSION_MAJOR 0x03000082 // R
#define LEECHCORE_OPT_FPGA_VERSION_MINOR 0x03000083 // R
/*
* Set a device specific option value.
* -- fOption
* -- pqwValue = pointer to QWORD to receive option value.
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_GetOption(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue);
/*
* Set a device specific option value.
* -- fOption
* -- qwValue
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_SetOption(_In_ ULONG64 fOption, _In_ ULONG64 qwValue);
//-----------------------------------------------------------------------------
// TRANSFER DEVICE DEPENDANT COMMANDS OR DATA TO/FROM UNDERLYING DEVICES AND
// PERFORM ACTIONS USING THE LeechCore_CommandData() FUNCTION.
//-----------------------------------------------------------------------------
#define LEECHCORE_COMMANDDATA_FPGA_WRITE_TLP 0x00000101 // R
#define LEECHCORE_COMMANDDATA_FPGA_LISTEN_TLP 0x00000102 // R
#define LEECHCORE_COMMANDDATA_STATISTICS_GET 0x80000100 // R
#define LEECHCORE_STATISTICS_MAGIC 0xffff6550
#define LEECHCORE_STATISTICS_VERSION 0x0001
#define LEECHCORE_STATISTICS_ID_OPEN 0x00
#define LEECHCORE_STATISTICS_ID_READSCATTER 0x01
#define LEECHCORE_STATISTICS_ID_WRITE 0x02
#define LEECHCORE_STATISTICS_ID_PROBE 0x03
#define LEECHCORE_STATISTICS_ID_GETOPTION 0x04
#define LEECHCORE_STATISTICS_ID_SETOPTION 0x05
#define LEECHCORE_STATISTICS_ID_COMMANDDATA 0x06
#define LEECHCORE_STATISTICS_ID_MAX 0x06
static const LPSTR LEECHCORE_STATISTICS_NAME[] = {
"LeechCore_Open",
"LeechCore_ReadScatter",
"LeechCore_Write",
"LeechCore_Probe",
"LeechCore_GetOption",
"LeechCore_SetOption",
"LeechCore_CommandData"
};
typedef struct tdLEECHCORE_STATISTICS {
DWORD magic;
WORD version;
WORD Reserved0;
DWORD Reserved1;
QWORD qwFreq;
struct {
QWORD c;
QWORD tm; // total time in qwFreq ticks
} Call[0x10];
} LEECHCORE_STATISTICS, *PLEECHCORE_STATISTICS;
/*
* Transfer device dependant commands/data to/from the underlying device and
* perform device dependant actions.
* -- fOption
* -- cbDataIn
* -- pbDataIn
* -- pbDataOut
* -- cbDataOut
* -- pcbDataOut
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_CommandData(
_In_ ULONG64 fOption,
_In_reads_(cbDataIn) PBYTE pbDataIn,
_In_ DWORD cbDataIn,
_Out_writes_(cbDataOut) PBYTE pbDataOut,
_In_ DWORD cbDataOut,
_Out_ PDWORD pcbDataOut
);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __LEECHCORE_H__ */
+5 -10
View File
@@ -45,33 +45,28 @@ CHAR GetMountPoint(_In_ DWORD argc, _In_ char* argv[])
*/
int main(_In_ int argc, _In_ char* argv[])
{
// DEBUG STUFF BELOW:
//LPSTR szTMP[] = { "", "-device", "fpga" };
//LPSTR szTMP[] = { "", "-device", "c:\\temp\\WIN10-16299-248-1.pmem", "-v" };
//argv = szTMP;
//argc = sizeof(szTMP) / sizeof(LPSTR);
// MAIN FUNCTION PROPER BELOW:
BOOL result;
HMODULE hVMM;
VMMDLL_FUNCTIONS VmmDll;
LoadLibraryA("leechcore.dll");
hVMM = LoadLibraryExA("vmm.dll", NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR);
if(!hVMM) {
printf("MemProcFS: Error loading vmm.dll - ensure vmm.dll resides in the memprocfs.exe application directory!\n");
return 1;
}
VmmDll.InitializeReserved = (BOOL(*)(DWORD, LPSTR*))GetProcAddress(hVMM, "VMMDLL_InitializeReserved");
VmmDll.Initialize = (BOOL(*)(DWORD, LPSTR*))GetProcAddress(hVMM, "VMMDLL_Initialize");
VmmDll.ConfigGet = (BOOL(*)(ULONG64, PULONG64))GetProcAddress(hVMM, "VMMDLL_ConfigGet");
VmmDll.ConfigSet = (BOOL(*)(ULONG64, ULONG64))GetProcAddress(hVMM, "VMMDLL_ConfigSet");
VmmDll.VfsList = (BOOL(*)(LPCWSTR, PVMMDLL_VFS_FILELIST))GetProcAddress(hVMM, "VMMDLL_VfsList");
VmmDll.VfsRead = (DWORD(*)(LPCWSTR, LPVOID, DWORD, PDWORD, ULONG64))GetProcAddress(hVMM, "VMMDLL_VfsRead");
VmmDll.VfsWrite = (DWORD(*)(LPCWSTR, LPVOID, DWORD, PDWORD, ULONG64))GetProcAddress(hVMM, "VMMDLL_VfsWrite");
VmmDll.VfsInitializePlugins = (BOOL(*)())GetProcAddress(hVMM, "VMMDLL_VfsInitializePlugins");
if(!VmmDll.InitializeReserved || !VmmDll.ConfigGet || !VmmDll.VfsList || !VmmDll.VfsRead || !VmmDll.VfsWrite || !VmmDll.VfsInitializePlugins) {
if(!VmmDll.Initialize || !VmmDll.ConfigGet || !VmmDll.VfsList || !VmmDll.VfsRead || !VmmDll.VfsWrite || !VmmDll.VfsInitializePlugins) {
printf("MemProcFS: Error loading vmm.dll - invalid version of vmm.dll found!\n");
return 1;
}
argv[0] = "-vdll";
result = VmmDll.InitializeReserved(argc, argv);
argv[0] = "-printf";
result = VmmDll.Initialize(argc, argv);
if(!result) {
// any error message will already be shown by the InitializeReserved function.
return 1;
+12
View File
@@ -2,6 +2,7 @@
Dokan : user-mode file system library for Windows
Copyright (C) 2015 - 2018 Adrien J. <[email protected]> and Maxime C. <[email protected]>
Copyright (C) 2017 Google, Inc.
Copyright (C) 2007 - 2011 Hiroki Asakawa <[email protected]>
http://dokan-dev.github.io
@@ -70,6 +71,11 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#define IOCTL_MOUNTPOINT_CLEANUP \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80E, METHOD_BUFFERED, FILE_ANY_ACCESS)
// DeviceIoControl code to send to a keepalive handle to activate it (see the
// documentation for the keepalive flags in the DokanFCB struct).
#define FSCTL_ACTIVATE_KEEPALIVE \
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x80F, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define DRIVER_FUNC_INSTALL 0x01
#define DRIVER_FUNC_REMOVE 0x02
@@ -99,6 +105,8 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#define DOKAN_DISK_FILE_SYSTEM 0
#define DOKAN_NETWORK_FILE_SYSTEM 1
#define DOKAN_KEEPALIVE_FILE_NAME L"\\__drive_fs_keepalive"
/*
* This structure is used for copying UNICODE_STRING from the kernel mode driver
* into the user mode driver.
@@ -362,8 +370,10 @@ typedef struct _EVENT_START {
ULONG IrpTimeout;
} EVENT_START, *PEVENT_START;
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4201)
#endif
typedef struct _DOKAN_RENAME_INFORMATION {
#if (_WIN32_WINNT >= _WIN32_WINNT_WIN10_RS1)
union {
@@ -376,7 +386,9 @@ typedef struct _DOKAN_RENAME_INFORMATION {
ULONG FileNameLength;
WCHAR FileName[1];
} DOKAN_RENAME_INFORMATION, *PDOKAN_RENAME_INFORMATION;
#ifdef _MSC_VER
#pragma warning(pop)
#endif
typedef struct _DOKAN_LINK_INFORMATION {
BOOLEAN ReplaceIfExists;
+22
View File
@@ -0,0 +1,22 @@
#define STRINGIZE2(s) #s
#define STRINGIZE(s) STRINGIZE2(s)
#define VERSION_MAJOR 2
#define VERSION_MINOR 0
#define VERSION_REVISION 0
#define VERSION_BUILD 0
#define VER_FILE_DESCRIPTION_STR "The Memory Process File System"
#define VER_FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_BUILD
#define VER_FILE_VERSION_STR STRINGIZE(VERSION_MAJOR) \
"." STRINGIZE(VERSION_MINOR) \
"." STRINGIZE(VERSION_REVISION) \
"." STRINGIZE(VERSION_BUILD) \
#define VER_COMPANY_NAME_STR ""
#define VER_PRODUCTNAME_STR "MemProcFS"
#define VER_PRODUCT_VERSION VER_FILE_VERSION
#define VER_PRODUCT_VERSION_STR VER_FILE_VERSION_STR
#define VER_ORIGINAL_FILENAME_STR VER_PRODUCTNAME_STR ".exe"
#define VER_INTERNAL_NAME_STR VER_ORIGINAL_FILENAME_STR
#define VER_COPYRIGHT_STR "Copyright (c) Ulf Frisk 2018-2019"
+1 -1
View File
@@ -445,7 +445,7 @@ VOID VfsInitializeAndMount(_In_ CHAR chMountPoint, _In_ PVMMDLL_FUNCTIONS pVmmDl
// set options
pDokanOptions->Version = DOKAN_VERSION;
pDokanOptions->Options |= DOKAN_OPTION_NETWORK;
pDokanOptions->UNCName = L"\\\\frizk.net\\MemoryProcessFileSystem";
pDokanOptions->UNCName = L"MemoryProcessFileSystem";
wszMountPoint[0] = chMountPoint;
pDokanOptions->MountPoint = wszMountPoint;
pDokanOptions->Timeout = 60000;
+1 -1
View File
@@ -14,7 +14,7 @@ typedef unsigned __int64 QWORD, *PQWORD;
#define VMMVFS_CACHE_DIRECTORY_LIFETIME_PROC_MS 500
typedef struct tdVMMDLL_FUNCTIONS {
BOOL(*InitializeReserved)(_In_ DWORD argc, _In_ LPSTR argv[]);
BOOL(*Initialize)(_In_ DWORD argc, _In_ LPSTR argv[]);
BOOL(*VfsList)(_In_ LPCWSTR wcsPath, _Inout_ PVMMDLL_VFS_FILELIST pFileList);
DWORD(*VfsRead)(LPCWSTR wcsFileName, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset);
DWORD(*VfsWrite)(_In_ LPCWSTR wcsFileName, _In_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset);
+44 -108
View File
@@ -1,11 +1,14 @@
// vmmdll.h : header file to include in projects that use vmm.dll either as
// stand anlone projects or as native plugins to vmm.dll.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
// Header Version: 2.0
//
#include <windows.h>
#include "leechcore.h"
#ifndef __VMMDLL_H__
#define __VMMDLL_H__
@@ -19,52 +22,23 @@ extern "C" {
//-----------------------------------------------------------------------------
/*
* RESERVED FUNCTION! DO NOT USE!
* Call other VMMDLL_Intialize functions to initialize VMM.DLL and the memory
* process file system.
* Initialize VMM.DLL with command line parameters. For a more detailed info
* about the parameters please see github wiki for Memory Process File System
* and LeechCore. THIS IS THE PREFERED WAY OF INITIALIZING VMM.DLL
* Important parameters are:
* -vdll = show printf style outputs)
* -v -vv -vvv = extra verbosity levels)
* -device = device as on format for LeechCore - please see leechcore.h or
* Github documentation for additional information. Some values
* are: <file>, fpga, usb3380, hvsavedstate, totalmeltdown, pmem
* -remote = remote LeechCore instance - please see leechcore.h or Github
* documentation for additional information.
* -- argc
* -- argv
* -- return = success/fail
*/
_Success_(return)
BOOL VMMDLL_InitializeReserved(_In_ DWORD argc, _In_ LPSTR argv[]);
/*
* Initialize VMM.DLL from a memory dump file in raw format. VMM.DLL will be
* initialized in read-only mode. It's possible to optionally specify the page
* table base of the windows kernel (for full vmm features) or the page table
* base of a single 64-bit process in any x64 operating system. NB! usually it
* is not necessary to specify the PageTableBase - it will be auto-identified
* most often if the target is Windows.
* -- szFileName = the file name of the raw memory dump to use.
* -- szPageTableBaseOpt = optionally the Page Table Base of kernel or process
* as hex string. NB! this is usally not required. Example: "0x1ab000".
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeFile(_In_ LPSTR szFileName, _In_opt_ LPSTR szPageTableBaseOpt);
/*
* Intiailize VMM.DLL from a supported FPGA device over USB. VMM.DLL will be
* initialized in read/write mode upon success. Optionally it will be possible
* to specify the max physical address and the page table base of the kernel or
* process that should be investigated.
* NB! Requires pcileech.dll to be placed in the same directory as vmm.dll.
* -- szMaxPhysicalAddressOpt = max physical address of the target system as a
* hex string. Example: "0x8000000000". If zero value is given the max
* address will be auto-identified.
* -- szPageTableBaseOpt = optionally the Page Table Base of kernel or process
* as hex string. NB! this is usally not required. Example: "0x1ab000".
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeFPGA(_In_opt_ LPSTR szMaxPhysicalAddressOpt, _In_opt_ LPSTR szPageTableBaseOpt);
/*
* Initialize VMM.DLL from a the "Total Meltdown" CVE-2018-1038 vulnerability.
* NB! Requires pcileech.dll to be placed in the same directory as vmm.dll.
* initialized in read/write mode upon success.
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeTotalMeltdown();
BOOL VMMDLL_Initialize(_In_ DWORD argc, _In_ LPSTR argv[]);
/*
* Close an initialized instance of VMM.DLL and clean up all allocated resources
@@ -84,43 +58,29 @@ BOOL VMMDLL_Close();
/*
* Options used together with the functions: VMMDLL_GetOption & VMMDLL_SetOption
* If VMM.DLL is chained with PCILEECH.DLL then required values will be passed
* along to PCILEECH.DLL when necessary.
* Options are defined with either: VMMDLL_OPT_* in this header file or as
* MEMDEVICE_OPT_* in memdevice.h
* For more detailed information check the sources for individual device types.
*/
#define VMMDLL_OPT_DEVICE_FPGA_PROBE_MAXPAGES 0x01 // RW
#define VMMDLL_OPT_DEVICE_FPGA_RX_FLUSH_LIMIT 0x02 // RW
#define VMMDLL_OPT_DEVICE_FPGA_MAX_SIZE_RX 0x03 // RW
#define VMMDLL_OPT_DEVICE_FPGA_MAX_SIZE_TX 0x04 // RW
#define VMMDLL_OPT_DEVICE_FPGA_DELAY_PROBE_READ 0x05 // RW - uS
#define VMMDLL_OPT_DEVICE_FPGA_DELAY_PROBE_WRITE 0x06 // RW - uS
#define VMMDLL_OPT_DEVICE_FPGA_DELAY_WRITE 0x07 // RW - uS
#define VMMDLL_OPT_DEVICE_FPGA_DELAY_READ 0x08 // RW - uS
#define VMMDLL_OPT_DEVICE_FPGA_RETRY_ON_ERROR 0x09 // RW
#define VMMDLL_OPT_DEVICE_FPGA_DEVICE_ID 0x80 // R
#define VMMDLL_OPT_DEVICE_FPGA_FPGA_ID 0x81 // R
#define VMMDLL_OPT_DEVICE_FPGA_VERSION_MAJOR 0x82 // R
#define VMMDLL_OPT_DEVICE_FPGA_VERSION_MINOR 0x83 // R
#define VMMDLL_OPT_CORE_PRINTF_ENABLE 0x80000001 // RW
#define VMMDLL_OPT_CORE_VERBOSE 0x80000002 // RW
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA 0x80000003 // RW
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA_TLP 0x80000004 // RW
#define VMMDLL_OPT_CORE_MAX_NATIVE_ADDRESS 0x80000005 // R
#define VMMDLL_OPT_CORE_MAX_NATIVE_IOSIZE 0x80000006 // R
#define VMMDLL_OPT_CORE_SYSTEM 0x80000007 // R
#define VMMDLL_OPT_CORE_MEMORYMODEL 0x80000008 // R
#define VMMDLL_OPT_CORE_PRINTF_ENABLE 0x80000001 // RW
#define VMMDLL_OPT_CORE_VERBOSE 0x80000002 // RW
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA 0x80000003 // RW
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA_TLP 0x80000004 // RW
#define VMMDLL_OPT_CORE_MAX_NATIVE_ADDRESS 0x80000005 // R
#define VMMDLL_OPT_CORE_MAX_NATIVE_IOSIZE 0x80000006 // R
#define VMMDLL_OPT_CORE_SYSTEM 0x80000007 // R
#define VMMDLL_OPT_CORE_MEMORYMODEL 0x80000008 // R
#define VMMDLL_OPT_CONFIG_IS_REFRESH_ENABLED 0x40000001 // R - 1/0
#define VMMDLL_OPT_CONFIG_TICK_PERIOD 0x40000002 // RW - base tick period in ms
#define VMMDLL_OPT_CONFIG_READCACHE_TICKS 0x40000003 // RW - memory cache validity period (in ticks)
#define VMMDLL_OPT_CONFIG_TLBCACHE_TICKS 0x40000004 // RW - page table (tlb) cache validity period (in ticks)
#define VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_PARTIAL 0x40000005 // RW - process refresh (partial) period (in ticks)
#define VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_TOTAL 0x40000006 // RW - process refresh (full) period (in ticks)
#define VMMDLL_OPT_CONFIG_VMM_VERSION_MAJOR 0x40000007 // R
#define VMMDLL_OPT_CONFIG_VMM_VERSION_MINOR 0x40000008 // R
#define VMMDLL_OPT_CONFIG_VMM_VERSION_REVISION 0x40000009 // R
#define VMMDLL_OPT_CONFIG_STATISTICS_FUNCTIONCALL 0x4000000A // RW - enable function call statistics (.status/statistics_fncall file)
#define VMMDLL_OPT_CONFIG_IS_REFRESH_ENABLED 0x40000001 // R - 1/0
#define VMMDLL_OPT_CONFIG_TICK_PERIOD 0x40000002 // RW - base tick period in ms
#define VMMDLL_OPT_CONFIG_READCACHE_TICKS 0x40000003 // RW - memory cache validity period (in ticks)
#define VMMDLL_OPT_CONFIG_TLBCACHE_TICKS 0x40000004 // RW - page table (tlb) cache validity period (in ticks)
#define VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_PARTIAL 0x40000005 // RW - process refresh (partial) period (in ticks)
#define VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_TOTAL 0x40000006 // RW - process refresh (full) period (in ticks)
#define VMMDLL_OPT_CONFIG_VMM_VERSION_MAJOR 0x40000007 // R
#define VMMDLL_OPT_CONFIG_VMM_VERSION_MINOR 0x40000008 // R
#define VMMDLL_OPT_CONFIG_VMM_VERSION_REVISION 0x40000009 // R
#define VMMDLL_OPT_CONFIG_STATISTICS_FUNCTIONCALL 0x4000000A // RW - enable function call statistics (.status/statistics_fncall file)
static const LPSTR VMMDLL_MEMORYMODEL_TOSTRING[4] = { "N/A", "X86", "X86PAE", "X64" };
@@ -256,9 +216,9 @@ _Success_(return)
BOOL VMMDLL_VfsInitializePlugins();
#define VMMDLL_PLUGIN_CONTEXT_MAGIC 0xc0ffee663df9301c
#define VMMDLL_PLUGIN_CONTEXT_VERSION 1
#define VMMDLL_PLUGIN_CONTEXT_VERSION 2
#define VMMDLL_PLUGIN_REGINFO_MAGIC 0xc0ffee663df9301d
#define VMMDLL_PLUGIN_REGINFO_VERSION 2
#define VMMDLL_PLUGIN_REGINFO_VERSION 3
#define VMMDLL_PLUGIN_EVENT_VERBOSITYCHANGE 0x01
@@ -267,8 +227,6 @@ typedef struct tdVMMDLL_PLUGIN_CONTEXT {
WORD wVersion;
WORD wSize;
DWORD dwPID;
PHANDLE phModulePrivate;
PHANDLE phProcessPrivate;
PVOID pProcess;
LPSTR szModule;
LPSTR szPath;
@@ -289,7 +247,6 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
PVOID pvReserved2;
// general plugin registration info to be filled out by the plugin below:
struct {
HANDLE hModulePrivate;
CHAR szModuleName[32];
BOOL fRootModule;
BOOL fProcessModule;
@@ -301,9 +258,8 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
BOOL(*pfnList)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList);
NTSTATUS(*pfnRead)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset);
NTSTATUS(*pfnWrite)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset);
VOID(*pfnNotify)(_Inout_opt_ PHANDLE phModulePrivate, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent);
VOID(*pfnCloseHandleModule)(_Inout_opt_ PHANDLE phModulePrivate);
VOID(*pfnCloseHandleProcess)(_Inout_opt_ PHANDLE phModulePrivate, _Inout_ PHANDLE phProcessPrivate);
VOID(*pfnNotify)(_In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent);
VOID(*pfnClose)();
PVOID pvReserved1;
PVOID pvReserved2;
} reg_fn;
@@ -323,26 +279,6 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
#define VMMDLL_FLAG_NOCACHE 0x0001 // do not use the data cache (force reading from memory acquisition device)
#define VMMDLL_FLAG_ZEROPAD_ON_FAIL 0x0002 // zero pad failed physical memory reads and report success if read within range of physical memory.
#define VMMDLL_MEM_IO_SCATTER_HEADER_VERSION 2
typedef struct tdVMMDLL_MEM_IO_SCATTER_HEADER {
ULONG64 qwA; // base address (DWORD boundry).
DWORD cbMax; // bytes to read (DWORD boundry, max 0x1000); pbResult must have room for this.
DWORD cb; // bytes read into result buffer.
PBYTE pb; // ptr to 0x1000 sized buffer to receive read bytes.
PVOID pvReserved1; // reserved for use by caller.
PVOID pvReserved2; // reserved for use by caller.
WORD version; // version of struct
WORD Future1; // reserved for future use.
DWORD Future2; // reserved for future use.
ULONG64 qwDeviceA; // device-physical address (used by device layer).
struct {
PVOID pvReserved1;
PVOID pvReserved2;
BYTE pbReserved[32];
} sReserved; // reserved for future use.
} VMMDLL_MEM_IO_SCATTER_HEADER, *PVMMDLL_MEM_IO_SCATTER_HEADER, **PPVMMDLL_MEM_IO_SCATTER_HEADER;
/*
* Read memory in various non-contigious locations specified by the pointers to
* the items in the ppDMAs array. Result for each unit of work will be given
@@ -356,7 +292,7 @@ typedef struct tdVMMDLL_MEM_IO_SCATTER_HEADER {
* -- flags = optional flags as given by VMM_FLAG_*
* -- return = the number of successfully read items.
*/
DWORD VMMDLL_MemReadScatter(_In_ DWORD dwPID, _Inout_ PPVMMDLL_MEM_IO_SCATTER_HEADER ppMEMs, _In_ DWORD cpMEMs, _In_ DWORD flags);
DWORD VMMDLL_MemReadScatter(_In_ DWORD dwPID, _Inout_ PPMEM_IO_SCATTER_HEADER ppMEMs, _In_ DWORD cpMEMs, _In_ DWORD flags);
/*
* Read a single 4096-byte page of memory.
+31 -13
View File
@@ -2,9 +2,11 @@ The Memory Process File System:
===============================
The Memory Process File System is an easy and convenient way of accessing physical memory as files a virtual file system.
Easy trivial point and click memory analysis without the need for complicated commandline arguments! Access physical memory content and artifacts via files in a mounted virtual file system or via a feature rich .dll application library to include in your own projects!
Easy trivial point and click memory analysis without the need for complicated commandline arguments! Access memory content and artifacts via files in a mounted virtual file system or via a feature rich application library to include in your own projects!
<b>Analyze memory dump files</b> - or even <b>live memory in read-write mode</b> via linked [pcileech](https://github.com/ufrisk/pcileech/) and [pcileech-fpga](https://github.com/ufrisk/pcileech-fpga/) devices!
Analyze memory dump files, <b>live memory</b> via [DumpIt](https://www.comae.com/), loaded driver or even <b>live memory in read-write mode</b> via linked [PCILeech](https://github.com/ufrisk/pcileech/) and [PCILeech-FPGA](https://github.com/ufrisk/pcileech-fpga/) devices!
It's even possible to connect to a remote LeechService memory acquisition service over a secured connection - allowing for remote live memory incident response - even over higher latency low band-width connections!
Use your favorite tools to analyze memory - use your favorite hex editors, your python and powershell scripts, your disassemblers - all will work trivally with the Memory Process File System by just reading and writing files!
@@ -15,6 +17,8 @@ Include the Memory Process File System in your Python or C/C++ programming proje
<b>Please check out the [project wiki](https://github.com/ufrisk/MemProcFS/wiki)</b> for more in-depth detailed information about the file system itself, its API and its plugin modules!
<b>Please check out the [LeechCore project](https://github.com/ufrisk/LeechCore)</b> for information about supported memory acquisition methods and remote memory access via the LeechService.
Fast and easy memory analysis via mounted file system:
======================================================
No matter if you have no prior knowledge of memory analysis or are an advanced user the Memory Process File System (and the API) may be useful! Click around the memory objects in the file system
@@ -26,7 +30,7 @@ Extensive Python and C/C++ API:
Everything in the Memory Process File System is exposed as APIs. APIs exist for both C/C++ `vmmdll.h` and Python `vmmpy.py`. The file system itself is made available virtually via the API without the need to mount it. Specialized process analysis and process alteration functionality is made easy by calling API functionality. It is possible to read both virtual process memory as well as physical memory! The example below shows reading 0x20 bytes from physical address 0x1000:
```
>>> from vmmpy import *
>>> VmmPy_InitializeFile('c:/temp/win10_memdump.raw')
>>> VmmPy_Initialize('c:/temp/win10_memdump.raw')
>>> print(VmmPy_UtilFillHexAscii(VmmPy_MemRead(-1, 0x1000, 0x20)))
0000 e9 4d 06 00 01 00 00 00 01 00 00 00 3f 00 18 10 .M..........?...
0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
@@ -41,16 +45,20 @@ Installing:
## Windows
Download or clone the Memory Process File System github repository. <b>Pre-built binaries are found in the files folder.</b> If the Memory Process File System is used as an API it is only dependant on the Microsoft Visual C++ Redistributables for Visual Studio 2017 (see below).
The Memory Process File System is dependant in the <b>Microsoft Visual C++ Redistributables for Visual Studio 2017</b>. They can be downloaded from Microsoft [here](https://go.microsoft.com/fwlink/?LinkId=746572). Alternatively, if installing the Dokany file system driver please install the <b>DokanSetup_redist</b> version and it will install the required redistributables.
The Memory Process File System is dependant on the [LeechCore project](https://github.com/ufrisk/LeechCore) for memory acquisition. The necessary _leechcore.dll_ file is already pre-built and included in the files folder.
The Memory Process File System is also dependant in the <b>Microsoft Visual C++ Redistributables for Visual Studio 2017</b>. They can be downloaded from Microsoft [here](https://go.microsoft.com/fwlink/?LinkId=746572). Alternatively, if installing the Dokany file system driver please install the <b>DokanSetup_redist</b> version and it will install the required redistributables.
Mounting the file system requires the <b>Dokany file system library</b> to be installed. Please download and install the latest version of Dokany at: https://github.com/dokan-dev/dokany/releases/latest It is recommended to download and install the <b>DokanSetup_redist</b> version.
Python support requires Python 3.6. The user may specify the path to the Python 3.6 installation with the command line parameter `-pythonhome`, alternatively download [Python 3.6 - Windows x86-64 embeddable zip file](https://www.python.org/downloads/windows/) and unzip its contents into the `files/python36` folder when using Python modules in the file system. To use the Python API a normal Python 3.6 installation for Windows is required.
PCILeech FPGA will require hardware as well as the _pcileech.dll_ and _FTD3XX.dll_ files to be dropped in the files folder. Please check out the [PCILeech](https://github.com/ufrisk/pcileech) project for instructions.
To capture live memory (without PCILeech FPGA hardware) download [DumpIt](https://www.comae.com/) and start the Memory Process File System via the DumpIt /LIVEKD mode. Alternatively, get WinPMEM by downloading and installing the most recent version of [Rekall](https://github.com/google/rekall/releases) and copy the signed driver 'winpmem_x64.sys' from _C:\Program Files\Rekall\resources\WinPmem_ into the files folder. DumpIt is recommended over winpmem due to superior stability and lack of blue screens.
PCILeech FPGA will require hardware as well as _FTD3XX.dll_ to be dropped in the files folder. Please check out the [LeechCore](https://github.com/ufrisk/LeechCore) project for instructions.
## Linux
The memory process file system is not yet supported on Linux. Linux support is planned for both the C/C++ and Python API and is a prioritized work item. FUSE file system support will take longer.
The memory process file system is not yet supported on Linux.
Examples:
=========
@@ -59,21 +67,24 @@ Start the Memory Process File System from the command line - possibly by using o
Or register the memory dump extension with MemProcFS.exe so that the file system is mounted when double-clicking on a memory dump file!
- mount the memory dump file as default M: <br>`memprocfs.exe -device c:\temp\win10x64-dump.raw`
- mount the memory dump file as default M with extra verbosity: <br>`memprocfs.exe -device c:\temp\win10x64-dump.raw -v`
- mount the memory dump file as default M: with extra verbosity: <br>`memprocfs.exe -device c:\temp\win10x64-dump.raw -v`
- mount the memory dump file as default M: with extra extra verbosity: <br>`memprocfs.exe -device c:\temp\win10x64-dump.raw -v -vv`
- mount the memory dump file as S: <br>`memprocfs.exe -mount s -device c:\temp\win10x64-dump.raw`
- mount live target memory, in verbose read-only mode, with DumpIt in /LIVEKD mode: <br>`DumpIt.exe /LIVEKD /A memprocfs.exe /C "-v"`
- mount live target memory, in read-only mode, with WinPMEM driver: <br>`memprocfs.exe -device pmem`
- mount live target memory, in read/write mode, with PCILeech FPGA memory acquisition device: <br>`memprocfs.exe -device fpga`
- mount live target memory, in read/write mode, with TotalMeltdown vulnerability acquisition device: <br>`memprocfs.exe -device totalmeltdown`
- mount an arbitrary x64 memory dump by specifying the process or kernel page table base in the cr3 option: <br>`memprocfs.exe -device c:\temp\unknown-x64-dump.raw -cr3 0x1aa000`
Documentation:
==============
For additional documentation please check out the [project wiki](https://github.com/ufrisk/MemProcFS/wiki) for in-depth detailed information about the file system itself, its API and its plugin modules!
For additional documentation please check out the [project wiki](https://github.com/ufrisk/MemProcFS/wiki) for in-depth detailed information about the file system itself, its API and its plugin modules! For additional information about memory acqusition methods check out the [LeechCore project](https://github.com/ufrisk/LeechCore/)
Building:
=========
Pre-built binaries and other supporting files are found in the files folder. The Memory Process File System binaries are built with Visual Studio 2017. No binaries currently exists for Linux (future support - please see Current Limitations & Future Development below).
Detailed build instructions may be found in the [Wiki](https://github.com/ufrisk/MemProcFS/wiki) in the [Building](https://github.com/ufrisk/MemProcFS/wiki/Dev:-Building) section.
Detailed build instructions may be found in the [Wiki](https://github.com/ufrisk/MemProcFS/wiki) in the [Building](https://github.com/ufrisk/MemProcFS/wiki/Dev_Building) section.
Current Limitations & Future Development:
=========================================
@@ -82,17 +93,13 @@ The Memory Process File System is currently limited to analyzing Windows (32-bit
Please find some ideas for possible future expansions of the memory process file system listed below. This is a list of ideas - not a list of features that will be implemented. Even though some items are put as prioritized there is no guarantee that they will be implemented in a timely fashion.
### Prioritized items:
- Support for Microsoft crash dump format (full memory dump / DumpIt).
- More/new plugins.
- Linux support - .so files for easy and convenient Linux API access from both C/C++ and Python.
- Additional core functionality (exported functions in .DLL). Please request in Issues section if ideas exist.
### Other items:
- PFN support.
- Multithreading support in main library.
- Linux support in mounted FUSE file system.
- Support for analyzing x64 Linux, macOS and UEFI memory dumps.
- ~~Support for non-x64 memory models (such as x86 32-bit).~~
- Hash lookup of executable memory pages in DB.
Links:
@@ -100,6 +107,7 @@ Links:
* Blog: http://blog.frizk.net
* Twitter: https://twitter.com/UlfFrisk
* PCILeech: https://github.com/ufrisk/pcileech/
* LeechCore: https://github.com/ufrisk/LeechCore/
* YouTube: https://www.youtube.com/channel/UC2aAi-gjqvKiC7s7Opzv9rg
Changelog:
@@ -116,3 +124,13 @@ v1.2
* Improved auto-identification of memory model and Windows.
* Loaded kernel drivers in System process 'modules' sub-directory (all Windows versions).
* PE (exe/dll/sys) Sections and Data Directories as files in 'modules' sub-directory.
v2.0
* Major new release with multiple changes. Most noteworty are:
* Multi-Threading support.
* Performance optimizations.
* Memory acqusition via the [LeechCore](https://github.com/ufrisk/LeechCore/) library with additional support for:
* Live memory acquisition with DumpIt in /LIVEKD mode or loaded kernel driver.
* Support for Microsoft Crash Dumps - such as created by default by [Comae DumpIt](https://www.comae.com).
* Hyper-V save files.
* Remote capture via remotely installed LeechService.
Binary file not shown.
Binary file not shown.
+466
View File
@@ -0,0 +1,466 @@
// leechcore.h : header file for the leechcore module - which purpose is to
// expose low-level device physical memory functionality.
//
// This library is thread-safe in all functions with the notable exceptions of
// the LeechCore_Open() and LeechCore_Close() functions. Some devices may allow
// multi-threaded access while in reality most devices are single-threaded and
// will control synchronization where necessary with locks.
//
// The library is initialized by calling LeechCore_Open with a LEECHCORE_CONFIG
// struct containing the correct configuration paramters. Note that the version
// and magic values must be set in addition to the szDevice configuration value
// Also, it may be possible to optionally connect to a remote leechcore service
// or instance over RPC by specifying a szRemote configuration value.
//
// ----------------------------------------------------------------------------
//
// Remote instance: szRemote configuration value. Connect to a remote leechcore
// instance by specifying a configuration value in the szRemote parameter. If a
// loaded already valid instance exists remotely this will be prioritized above
// the value in szDevice. If the acquisition device is not yet loaded by the
// remote instance the value in szDevice will be used. Normally, the connection
// will take place as a mutually authenticated encrypted connection secured by
// kerberos. If not possible or desirable the 'insecure' value may be specified
// to disable authentication and security.
// Syntax:
// rpc://<remote_spn>:<host>:<port> (port = optional, remote_spn = kerberos)
// (SPN of remote service or 'insecure' )
// Examples:
// rpc://insecure:remotehost.example.com (connect insecure to remote host )
// rpc://[email protected]:192.0.0.5 (connect secure to remote host )
// rpc://insecure:127.0.0.0:6666 (connect insecure non-default port)
//
// ----------------------------------------------------------------------------
//
// Device to connect to: szDevice contains the device to capture memory from.
// Supported memory acquisition devices are:
// USB3380 : hardware, read/write, 32-bit (4GB) addressing only. Requires a
// PCILeech flashed USB3380 device connected over USB and Google
// Android WinUSB drivers to be installed. Download and install from:
// http://developer.android.com/sdk/win-usb.html#download
// Syntax:
// USB3380
// USB3380://USB2 (force USB2 connection speed)
//
// FPGA : hardware, read/write - requires a PCILeech FPGA flashed hardware
// device as shown at: https://github.com/ufrisk/pcileech-fpga
// Also requires the FTD3XX.DLL from ftdichip to be placed in the
// same directory as the executable. Download from ftdichip at:
// http://www.ftdichip.com/Drivers/D3XX/FTD3XXLibrary_v1.2.0.6.zip
// Syntax:
// FGPA
// FPGA://<read_uS>[:<write_uS>[:<probe_uS>]] (values are optional)
//
// SP605TCP : hardware, read/write - connect to a remote SP605 FPGA over the
// network using the implementation created by @d_olex.
// https://github.com/Cr4sh/s6_pcie_microblaze
// Syntax:
// SP605TCP://<target_ip>[:<target_port>] (port is optional)
//
// RAWTCP : read/write - connect to a remote raw tcp device - such as HPE iLO
// that have been patched to support DMA as per blog entry below:
// https://www.synacktiv.com/posts/exploit/using-your-bmc-as-a-dma-device-plugging-pcileech-to-hpe-ilo-4.html
// Syntax:
// RAWTCP://<target_ip>[:<target_port>] (port is optional)
//
// HvSavedState : read-only - connect to a Hyper-V saved state file. In order
// to do so the .dll file 'vmsavedstatedumpprovider.dll' must be
// placed in same directory as the executable file.
//
// PMEM : load the rekall winpmem driver into the kernel and connect to it
// to acquire memory. The driver file 'winpmem_x64.sys' is found in
// the Rekall directory after most recent version has been installed.
// Copy 'winpmem_x64.sys' to the directory of leechcore.dll and run
// executable as elevated admin using syntax below:
// Syntax:
// PMEM (use winpmem_x64.sys in directory of executable)
// PMEM://<non_default_path_to_file_winpmem_x64.sys>
//
// TOTALMELTDOWN : read/write - requires a Windows 7 system vulnerable to the
// "Total Meltdown" vulnerability - CVE-2018-1038.
// Syntax:
// TOTALMELTDOWN
//
// FILE : use dump file, either a raw linear memory dump or full crash dump.
// Which format to use is auto-detected. If it looks like a full cash
// dump that format will be used, otherwise it will be assumed that a
// raw linear memory dump is to be used.
// Syntax:
// <filename> (no device-type prefix - just use the file name)
// FILE://<filename>
//
// DumpIt : DumpIt is a "virtual" device. It's only possible to use the DumpIt
// device if the main process containing LeechCore has been started
// with DumpIt in LiveKD mode.
// Example 1:
// DumpIt.exe /LIVEKD /A MemProcFS.exe
// Example 2:
// DumpIt.exe /LIVEKD /A LeechSvc.exe /C "interactive insecure"
// and then connect to remote service by:
// MemProcFS.exe -remote rpc://insecure:192.168.x.x -device DumpIt
//
// EXISTING : Attach to existing already loaded configuration. This is done
// instead of the default behaviour of closing any existing devices
// and initializing the new requested device. If no existing device
// exists the call to LeechCore_Open will fail.
// Syntax:
// EXISTING
//
//
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
// Header Version: 1.0
//
#ifndef __LEECHCORE_H__
#define __LEECHCORE_H__
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
//-----------------------------------------------------------------------------
// WINDOWS / LINUX COMPATIBILITY BELOW:
//-----------------------------------------------------------------------------
#ifdef _WIN32
#include <Windows.h>
typedef unsigned __int64 QWORD, *PQWORD;
#define DLLEXPORT __declspec(dllexport)
#endif /* _WIN32 */
#ifdef LINUX
#include <stdint.h>
#include <stddef.h>
typedef void VOID, *PVOID, *LPVOID;
typedef void *HANDLE, **PHANDLE;
typedef uint32_t BOOL, *PBOOL;
typedef uint8_t BYTE, *PBYTE;
typedef char CHAR, *PCHAR, *PSTR, *LPSTR;
typedef uint16_t WORD, *PWORD, USHORT, *PUSHORT;
typedef uint32_t DWORD, *PDWORD;
typedef long long unsigned int QWORD, *PQWORD, ULONG64, *PULONG64;
#define MAX_PATH 260
#define DLLEXPORT __attribute__((visibility("default")))
#define _In_
#define _Out_
#define _In_z_
#define _Inout_
#define _In_opt_
#define _Out_opt_
#define _Out_writes_(x)
#define _Check_return_opt_
#define _Printf_format_string_
#define _Inout_updates_bytes_(x)
#define _In_reads_(cbDataIn)
#define _Success_(return)
#endif /* LINUX */
//-----------------------------------------------------------------------------
// GENERAL HEADER DEFINES BELOW:
//-----------------------------------------------------------------------------
#define MEM_IO_SCATTER_HEADER_MAGIC 0xffff6548
#define MEM_IO_SCATTER_HEADER_VERSION 0x0003
typedef struct tdMEM_IO_SCATTER_HEADER {
DWORD magic; // magic
WORD version; // version
WORD Future1;
ULONG64 qwA; // base address.
DWORD cbMax; // bytes to read (DWORD boundry, max 0x1000); pb must have room for this.
DWORD cb; // bytes read into result buffer.
PBYTE pb; // ptr to 0x1000 sized buffer to receive read bytes.
PVOID pvReserved1; // reserved for use by caller.
PVOID pvReserved2; // reserved for use by caller.
PVOID Future2[8];
} MEM_IO_SCATTER_HEADER, *PMEM_IO_SCATTER_HEADER, **PPMEM_IO_SCATTER_HEADER;
//-----------------------------------------------------------------------------
// LEECHCORE INITIALIZATION / CLOSE FUNCTIONALITY BELOW:
//-----------------------------------------------------------------------------
typedef enum tdLEECHCORE_DEVICE {
LEECHCORE_DEVICE_NA = 0,
LEECHCORE_DEVICE_FILE = 1,
LEECHCORE_DEVICE_PMEM = 2,
LEECHCORE_DEVICE_FPGA = 3,
LEECHCORE_DEVICE_SP605_TCP = 4,
LEECHCORE_DEVICE_USB3380 = 5,
LEECHCORE_DEVICE_TOTALMELTDOWN = 6,
LEECHCORE_DEVICE_HVSAVEDSTATE = 7,
LEECHCORE_DEVICE_RAWTCP = 8,
} LEECHCORE_DEVICE;
#define LEECHCORE_CONFIG_MAGIC 0xffff6549
#define LEECHCORE_CONFIG_VERSION 0x0001
#define LEECHCORE_CONFIG_FLAG_PRINTF 0x0001
#define LEECHCORE_CONFIG_FLAG_PRINTF_VERBOSE_1 0x0002
#define LEECHCORE_CONFIG_FLAG_PRINTF_VERBOSE_2 0x0004
#define LEECHCORE_CONFIG_FLAG_PRINTF_VERBOSE_3 0x0008
#define LEECHCORE_CONFIG_FLAG_REMOTE_NO_COMPRESS 0x0010
typedef struct tdLEECHCORE_CONFIG {
DWORD magic; // set by caller.
WORD version; // set by caller.
WORD flags; // set by caller, updated by device.
ULONG64 paMax; // set by caller, updated by device.
ULONG64 cbMaxSizeMemIo; // set by caller, updated by device.
ULONG64 paMaxNative; // set by device.
LEECHCORE_DEVICE tpDevice; // set by device.
BOOL fWritable; // set by device. (is device writable?)
BOOL fVolatile; // set by device. (is device volatile / memory may change?)
BOOL fVolatileMaxAddress; // set by device. (is max address volatile? - poll changes with LEECHCORE_OPT_MEMORYINFO_ADDR_MAX)
BOOL fRemote; // set by device.
WORD VersionMajor; // set by device.
WORD VersionMinor; // set by device.
WORD VersionRevision; // set by device.
CHAR szDevice[MAX_PATH]; // set by caller.
CHAR szRemote[MAX_PATH]; // set by caller.
// optional 'printf' function pointer. if set to non null value 'printf'
// calls will be redirected. useful when logging to files.
_Check_return_opt_ int(*pfn_printf_opt)(_In_z_ _Printf_format_string_ char const* const _Format, ...); // set by caller.
} LEECHCORE_CONFIG, *PLEECHCORE_CONFIG;
typedef struct tdLEECHCORE_PAGESTAT_MINIMAL {
HANDLE h;
VOID(*pfnPageStatUpdate)(HANDLE h, ULONG64 pa, ULONG64 cPageSuccessAdd, ULONG64 cPageFailAdd);
} LEECHCORE_PAGESTAT_MINIMAL, *PLEECHCORE_PAGESTAT_MINIMAL;
/*
* Open a connection to the target device.
* -- pInformation
* -- result
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_Open(_Inout_ PLEECHCORE_CONFIG pConfig);
/*
* Clean up various device related stuff and deallocate memory buffers.
*/
DLLEXPORT VOID LeechCore_Close();
//-----------------------------------------------------------------------------
// LEECHCORE CORE READ AND WRITE FUNCTIONALITY BELOW:
//-----------------------------------------------------------------------------
#define LEECHCORE_FLAG_READ_RETRY 0x01
#define LEECHCORE_FLAG_WRITE_RETRY 0x01
#define LEECHCORE_FLAG_WRITE_VERIFY 0x02
/*
* Allocate a scatter buffer containing empty 0x1000-sized ppMEMs with address
* set to zero. Caller is responsible for calling LocalFree(ppMEMs).
* -- cMEMs
* -- pppMEMs = pointer to receive ppMEMs on success.
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_AllocScatterEmpty(_In_ DWORD cMEMs, _Out_ PPMEM_IO_SCATTER_HEADER *pppMEMs);
/*
* Read memory in various non-contigious locations specified by the items in the
* phDMAs array. Result for each unit of work will be given individually. No upper
* limit of number of items to read, but no performance boost will be given if
* above hardware limit. Max size of each unit of work is one 4k page (4096 bytes).
* -- ppMEMs = array of scatter read headers.
* -- cpMEMs = count of ppDMAs.
*/
DLLEXPORT VOID LeechCore_ReadScatter(_Inout_ PPMEM_IO_SCATTER_HEADER ppMEMs, _In_ DWORD cpMEMs);
/*
* Try read memory in a fairly optimal way considering device limits. The number
* of total successfully read bytes is returned. Failed reads will be zeroed out
* in the returned memory.
* -- pa
* -- pb
* -- cb
* -- return = the number of bytes successfully read.
*/
DLLEXPORT DWORD LeechCore_Read(_In_ ULONG64 pa, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb);
/*
* Try read memory in a fairly optimal way considering device limits. The number
* of total successfully read bytes is returned. Failed reads will be zeroed out
* in the returned memory.
* -- pa
* -- pb
* -- cb
* -- flags = 0 or LEECHCORE_FLAG_READ_RETRY
* -- pPageStat = optional minimal statistic struct to update.
* -- return = the number of bytes successfully read.
*/
DLLEXPORT DWORD LeechCore_ReadEx(_In_ ULONG64 pa, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _In_ DWORD flags, _In_opt_ PLEECHCORE_PAGESTAT_MINIMAL pPageStat);
/*
* Write data to the target system if supported by the device.
* -- pa
* -- pb
* -- cb
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_Write(_In_ ULONG64 pa, _In_ PBYTE pb, _In_ DWORD cb);
/*
* Write data to the target system if supported by the device.
* -- pa
* -- pb
* -- cb
* -- flags = 0 or LEECHCORE_FLAG_WRITE_*
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_WriteEx(_In_ ULONG64 pa, _In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD flags);
/*
* Probe the memory of the target system to check whether it's readable or not.
* Please note that not all devices support this natively.
* -- pa = address to start probe from.
* -- cPages = number of 4kB pages to probe.
* -- pbResultMap = result map, 1 byte represents 1 page, 0 = fail, 1 = success.
* (individual page elements in pbResultMap must be set to 0 [fail] on call
* for probe to take place on individual page).
* -- return = FALSE if not supported by underlying hardware, TRUE if supported.
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_Probe(_In_ QWORD pa, _In_ DWORD cPages, _Inout_updates_bytes_(cPages) PBYTE pbResultMap);
//-----------------------------------------------------------------------------
// GET/SET DEVICE OPTIONS BELOW. SOME OPTIONS ARE GENERAL LEECHCORE OPTIONS
// WHILE OTHER ARE DEVICE SPECIFIC. USE FUNCTIONS:
// LeechCore_GetOption() AND LeechCore_GetOption() TO GET/SET OPTIONS.
// FOR DEVICE-SPECIFIC OPTIONS PLEASE SEE INDIVIDUAL DEVICE FILES FOR MORE
// DETAILED INFORMATION.
//-----------------------------------------------------------------------------
#define LEECHCORE_OPT_CORE_PRINTF_ENABLE 0x80000001 // RW
#define LEECHCORE_OPT_CORE_VERBOSE 0x80000002 // RW
#define LEECHCORE_OPT_CORE_VERBOSE_EXTRA 0x80000003 // RW
#define LEECHCORE_OPT_CORE_VERBOSE_EXTRA_TLP 0x80000004 // RW
#define LEECHCORE_OPT_CORE_VERSION_MAJOR 0x01000001 // R
#define LEECHCORE_OPT_CORE_VERSION_MINOR 0x01000002 // R
#define LEECHCORE_OPT_CORE_VERSION_REVISION 0x01000003 // R
#define LEECHCORE_OPT_MEMORYINFO_VALID 0x02000001 // R
#define LEECHCORE_OPT_MEMORYINFO_ADDR_MAX 0x02000002 // R
#define LEECHCORE_OPT_MEMORYINFO_FLAG_32BIT 0x02000003 // R
#define LEECHCORE_OPT_MEMORYINFO_FLAG_PAE 0x02000004 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_VERSION_MINOR 0x02000005 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_VERSION_MAJOR 0x02000006 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_DTB 0x02000007 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_PFN 0x02000008 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_PsLoadedModuleList 0x02000009 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_PsActiveProcessHead 0x0200000a // R
#define LEECHCORE_OPT_MEMORYINFO_OS_MACHINE_IMAGE_TP 0x0200000b // R
#define LEECHCORE_OPT_MEMORYINFO_OS_NUM_PROCESSORS 0x0200000c // R
#define LEECHCORE_OPT_MEMORYINFO_OS_SYSTEMTIME 0x0200000d // R
#define LEECHCORE_OPT_MEMORYINFO_OS_UPTIME 0x0200000e // R
#define LEECHCORE_OPT_MEMORYINFO_OS_KERNELBASE 0x0200000f // R
#define LEECHCORE_OPT_MEMORYINFO_OS_KERNELHINT 0x02000010 // R
#define LEECHCORE_OPT_FPGA_PROBE_MAXPAGES 0x03000001 // RW
#define LEECHCORE_OPT_FPGA_RX_FLUSH_LIMIT 0x03000002 // RW
#define LEECHCORE_OPT_FPGA_MAX_SIZE_RX 0x03000003 // RW
#define LEECHCORE_OPT_FPGA_MAX_SIZE_TX 0x03000004 // RW
#define LEECHCORE_OPT_FPGA_DELAY_PROBE_READ 0x03000005 // RW - uS
#define LEECHCORE_OPT_FPGA_DELAY_PROBE_WRITE 0x03000006 // RW - uS
#define LEECHCORE_OPT_FPGA_DELAY_WRITE 0x03000007 // RW - uS
#define LEECHCORE_OPT_FPGA_DELAY_READ 0x03000008 // RW - uS
#define LEECHCORE_OPT_FPGA_RETRY_ON_ERROR 0x03000009 // RW
#define LEECHCORE_OPT_FPGA_DEVICE_ID 0x03000080 // R
#define LEECHCORE_OPT_FPGA_FPGA_ID 0x03000081 // R
#define LEECHCORE_OPT_FPGA_VERSION_MAJOR 0x03000082 // R
#define LEECHCORE_OPT_FPGA_VERSION_MINOR 0x03000083 // R
/*
* Set a device specific option value.
* -- fOption
* -- pqwValue = pointer to QWORD to receive option value.
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_GetOption(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue);
/*
* Set a device specific option value.
* -- fOption
* -- qwValue
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_SetOption(_In_ ULONG64 fOption, _In_ ULONG64 qwValue);
//-----------------------------------------------------------------------------
// TRANSFER DEVICE DEPENDANT COMMANDS OR DATA TO/FROM UNDERLYING DEVICES AND
// PERFORM ACTIONS USING THE LeechCore_CommandData() FUNCTION.
//-----------------------------------------------------------------------------
#define LEECHCORE_COMMANDDATA_FPGA_WRITE_TLP 0x00000101 // R
#define LEECHCORE_COMMANDDATA_FPGA_LISTEN_TLP 0x00000102 // R
#define LEECHCORE_COMMANDDATA_STATISTICS_GET 0x80000100 // R
#define LEECHCORE_STATISTICS_MAGIC 0xffff6550
#define LEECHCORE_STATISTICS_VERSION 0x0001
#define LEECHCORE_STATISTICS_ID_OPEN 0x00
#define LEECHCORE_STATISTICS_ID_READSCATTER 0x01
#define LEECHCORE_STATISTICS_ID_WRITE 0x02
#define LEECHCORE_STATISTICS_ID_PROBE 0x03
#define LEECHCORE_STATISTICS_ID_GETOPTION 0x04
#define LEECHCORE_STATISTICS_ID_SETOPTION 0x05
#define LEECHCORE_STATISTICS_ID_COMMANDDATA 0x06
#define LEECHCORE_STATISTICS_ID_MAX 0x06
static const LPSTR LEECHCORE_STATISTICS_NAME[] = {
"LeechCore_Open",
"LeechCore_ReadScatter",
"LeechCore_Write",
"LeechCore_Probe",
"LeechCore_GetOption",
"LeechCore_SetOption",
"LeechCore_CommandData"
};
typedef struct tdLEECHCORE_STATISTICS {
DWORD magic;
WORD version;
WORD Reserved0;
DWORD Reserved1;
QWORD qwFreq;
struct {
QWORD c;
QWORD tm; // total time in qwFreq ticks
} Call[0x10];
} LEECHCORE_STATISTICS, *PLEECHCORE_STATISTICS;
/*
* Transfer device dependant commands/data to/from the underlying device and
* perform device dependant actions.
* -- fOption
* -- cbDataIn
* -- pbDataIn
* -- pbDataOut
* -- cbDataOut
* -- pcbDataOut
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_CommandData(
_In_ ULONG64 fOption,
_In_reads_(cbDataIn) PBYTE pbDataIn,
_In_ DWORD cbDataIn,
_Out_writes_(cbDataOut) PBYTE pbDataOut,
_In_ DWORD cbDataOut,
_Out_ PDWORD pcbDataOut
);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __LEECHCORE_H__ */
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+44 -108
View File
@@ -1,11 +1,14 @@
// vmmdll.h : header file to include in projects that use vmm.dll either as
// stand anlone projects or as native plugins to vmm.dll.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
// Header Version: 2.0
//
#include <windows.h>
#include "leechcore.h"
#ifndef __VMMDLL_H__
#define __VMMDLL_H__
@@ -19,52 +22,23 @@ extern "C" {
//-----------------------------------------------------------------------------
/*
* RESERVED FUNCTION! DO NOT USE!
* Call other VMMDLL_Intialize functions to initialize VMM.DLL and the memory
* process file system.
* Initialize VMM.DLL with command line parameters. For a more detailed info
* about the parameters please see github wiki for Memory Process File System
* and LeechCore. THIS IS THE PREFERED WAY OF INITIALIZING VMM.DLL
* Important parameters are:
* -vdll = show printf style outputs)
* -v -vv -vvv = extra verbosity levels)
* -device = device as on format for LeechCore - please see leechcore.h or
* Github documentation for additional information. Some values
* are: <file>, fpga, usb3380, hvsavedstate, totalmeltdown, pmem
* -remote = remote LeechCore instance - please see leechcore.h or Github
* documentation for additional information.
* -- argc
* -- argv
* -- return = success/fail
*/
_Success_(return)
BOOL VMMDLL_InitializeReserved(_In_ DWORD argc, _In_ LPSTR argv[]);
/*
* Initialize VMM.DLL from a memory dump file in raw format. VMM.DLL will be
* initialized in read-only mode. It's possible to optionally specify the page
* table base of the windows kernel (for full vmm features) or the page table
* base of a single 64-bit process in any x64 operating system. NB! usually it
* is not necessary to specify the PageTableBase - it will be auto-identified
* most often if the target is Windows.
* -- szFileName = the file name of the raw memory dump to use.
* -- szPageTableBaseOpt = optionally the Page Table Base of kernel or process
* as hex string. NB! this is usally not required. Example: "0x1ab000".
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeFile(_In_ LPSTR szFileName, _In_opt_ LPSTR szPageTableBaseOpt);
/*
* Intiailize VMM.DLL from a supported FPGA device over USB. VMM.DLL will be
* initialized in read/write mode upon success. Optionally it will be possible
* to specify the max physical address and the page table base of the kernel or
* process that should be investigated.
* NB! Requires pcileech.dll to be placed in the same directory as vmm.dll.
* -- szMaxPhysicalAddressOpt = max physical address of the target system as a
* hex string. Example: "0x8000000000". If zero value is given the max
* address will be auto-identified.
* -- szPageTableBaseOpt = optionally the Page Table Base of kernel or process
* as hex string. NB! this is usally not required. Example: "0x1ab000".
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeFPGA(_In_opt_ LPSTR szMaxPhysicalAddressOpt, _In_opt_ LPSTR szPageTableBaseOpt);
/*
* Initialize VMM.DLL from a the "Total Meltdown" CVE-2018-1038 vulnerability.
* NB! Requires pcileech.dll to be placed in the same directory as vmm.dll.
* initialized in read/write mode upon success.
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeTotalMeltdown();
BOOL VMMDLL_Initialize(_In_ DWORD argc, _In_ LPSTR argv[]);
/*
* Close an initialized instance of VMM.DLL and clean up all allocated resources
@@ -84,43 +58,29 @@ BOOL VMMDLL_Close();
/*
* Options used together with the functions: VMMDLL_GetOption & VMMDLL_SetOption
* If VMM.DLL is chained with PCILEECH.DLL then required values will be passed
* along to PCILEECH.DLL when necessary.
* Options are defined with either: VMMDLL_OPT_* in this header file or as
* MEMDEVICE_OPT_* in memdevice.h
* For more detailed information check the sources for individual device types.
*/
#define VMMDLL_OPT_DEVICE_FPGA_PROBE_MAXPAGES 0x01 // RW
#define VMMDLL_OPT_DEVICE_FPGA_RX_FLUSH_LIMIT 0x02 // RW
#define VMMDLL_OPT_DEVICE_FPGA_MAX_SIZE_RX 0x03 // RW
#define VMMDLL_OPT_DEVICE_FPGA_MAX_SIZE_TX 0x04 // RW
#define VMMDLL_OPT_DEVICE_FPGA_DELAY_PROBE_READ 0x05 // RW - uS
#define VMMDLL_OPT_DEVICE_FPGA_DELAY_PROBE_WRITE 0x06 // RW - uS
#define VMMDLL_OPT_DEVICE_FPGA_DELAY_WRITE 0x07 // RW - uS
#define VMMDLL_OPT_DEVICE_FPGA_DELAY_READ 0x08 // RW - uS
#define VMMDLL_OPT_DEVICE_FPGA_RETRY_ON_ERROR 0x09 // RW
#define VMMDLL_OPT_DEVICE_FPGA_DEVICE_ID 0x80 // R
#define VMMDLL_OPT_DEVICE_FPGA_FPGA_ID 0x81 // R
#define VMMDLL_OPT_DEVICE_FPGA_VERSION_MAJOR 0x82 // R
#define VMMDLL_OPT_DEVICE_FPGA_VERSION_MINOR 0x83 // R
#define VMMDLL_OPT_CORE_PRINTF_ENABLE 0x80000001 // RW
#define VMMDLL_OPT_CORE_VERBOSE 0x80000002 // RW
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA 0x80000003 // RW
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA_TLP 0x80000004 // RW
#define VMMDLL_OPT_CORE_MAX_NATIVE_ADDRESS 0x80000005 // R
#define VMMDLL_OPT_CORE_MAX_NATIVE_IOSIZE 0x80000006 // R
#define VMMDLL_OPT_CORE_SYSTEM 0x80000007 // R
#define VMMDLL_OPT_CORE_MEMORYMODEL 0x80000008 // R
#define VMMDLL_OPT_CORE_PRINTF_ENABLE 0x80000001 // RW
#define VMMDLL_OPT_CORE_VERBOSE 0x80000002 // RW
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA 0x80000003 // RW
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA_TLP 0x80000004 // RW
#define VMMDLL_OPT_CORE_MAX_NATIVE_ADDRESS 0x80000005 // R
#define VMMDLL_OPT_CORE_MAX_NATIVE_IOSIZE 0x80000006 // R
#define VMMDLL_OPT_CORE_SYSTEM 0x80000007 // R
#define VMMDLL_OPT_CORE_MEMORYMODEL 0x80000008 // R
#define VMMDLL_OPT_CONFIG_IS_REFRESH_ENABLED 0x40000001 // R - 1/0
#define VMMDLL_OPT_CONFIG_TICK_PERIOD 0x40000002 // RW - base tick period in ms
#define VMMDLL_OPT_CONFIG_READCACHE_TICKS 0x40000003 // RW - memory cache validity period (in ticks)
#define VMMDLL_OPT_CONFIG_TLBCACHE_TICKS 0x40000004 // RW - page table (tlb) cache validity period (in ticks)
#define VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_PARTIAL 0x40000005 // RW - process refresh (partial) period (in ticks)
#define VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_TOTAL 0x40000006 // RW - process refresh (full) period (in ticks)
#define VMMDLL_OPT_CONFIG_VMM_VERSION_MAJOR 0x40000007 // R
#define VMMDLL_OPT_CONFIG_VMM_VERSION_MINOR 0x40000008 // R
#define VMMDLL_OPT_CONFIG_VMM_VERSION_REVISION 0x40000009 // R
#define VMMDLL_OPT_CONFIG_STATISTICS_FUNCTIONCALL 0x4000000A // RW - enable function call statistics (.status/statistics_fncall file)
#define VMMDLL_OPT_CONFIG_IS_REFRESH_ENABLED 0x40000001 // R - 1/0
#define VMMDLL_OPT_CONFIG_TICK_PERIOD 0x40000002 // RW - base tick period in ms
#define VMMDLL_OPT_CONFIG_READCACHE_TICKS 0x40000003 // RW - memory cache validity period (in ticks)
#define VMMDLL_OPT_CONFIG_TLBCACHE_TICKS 0x40000004 // RW - page table (tlb) cache validity period (in ticks)
#define VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_PARTIAL 0x40000005 // RW - process refresh (partial) period (in ticks)
#define VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_TOTAL 0x40000006 // RW - process refresh (full) period (in ticks)
#define VMMDLL_OPT_CONFIG_VMM_VERSION_MAJOR 0x40000007 // R
#define VMMDLL_OPT_CONFIG_VMM_VERSION_MINOR 0x40000008 // R
#define VMMDLL_OPT_CONFIG_VMM_VERSION_REVISION 0x40000009 // R
#define VMMDLL_OPT_CONFIG_STATISTICS_FUNCTIONCALL 0x4000000A // RW - enable function call statistics (.status/statistics_fncall file)
static const LPSTR VMMDLL_MEMORYMODEL_TOSTRING[4] = { "N/A", "X86", "X86PAE", "X64" };
@@ -256,9 +216,9 @@ _Success_(return)
BOOL VMMDLL_VfsInitializePlugins();
#define VMMDLL_PLUGIN_CONTEXT_MAGIC 0xc0ffee663df9301c
#define VMMDLL_PLUGIN_CONTEXT_VERSION 1
#define VMMDLL_PLUGIN_CONTEXT_VERSION 2
#define VMMDLL_PLUGIN_REGINFO_MAGIC 0xc0ffee663df9301d
#define VMMDLL_PLUGIN_REGINFO_VERSION 2
#define VMMDLL_PLUGIN_REGINFO_VERSION 3
#define VMMDLL_PLUGIN_EVENT_VERBOSITYCHANGE 0x01
@@ -267,8 +227,6 @@ typedef struct tdVMMDLL_PLUGIN_CONTEXT {
WORD wVersion;
WORD wSize;
DWORD dwPID;
PHANDLE phModulePrivate;
PHANDLE phProcessPrivate;
PVOID pProcess;
LPSTR szModule;
LPSTR szPath;
@@ -289,7 +247,6 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
PVOID pvReserved2;
// general plugin registration info to be filled out by the plugin below:
struct {
HANDLE hModulePrivate;
CHAR szModuleName[32];
BOOL fRootModule;
BOOL fProcessModule;
@@ -301,9 +258,8 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
BOOL(*pfnList)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList);
NTSTATUS(*pfnRead)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset);
NTSTATUS(*pfnWrite)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset);
VOID(*pfnNotify)(_Inout_opt_ PHANDLE phModulePrivate, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent);
VOID(*pfnCloseHandleModule)(_Inout_opt_ PHANDLE phModulePrivate);
VOID(*pfnCloseHandleProcess)(_Inout_opt_ PHANDLE phModulePrivate, _Inout_ PHANDLE phProcessPrivate);
VOID(*pfnNotify)(_In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent);
VOID(*pfnClose)();
PVOID pvReserved1;
PVOID pvReserved2;
} reg_fn;
@@ -323,26 +279,6 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
#define VMMDLL_FLAG_NOCACHE 0x0001 // do not use the data cache (force reading from memory acquisition device)
#define VMMDLL_FLAG_ZEROPAD_ON_FAIL 0x0002 // zero pad failed physical memory reads and report success if read within range of physical memory.
#define VMMDLL_MEM_IO_SCATTER_HEADER_VERSION 2
typedef struct tdVMMDLL_MEM_IO_SCATTER_HEADER {
ULONG64 qwA; // base address (DWORD boundry).
DWORD cbMax; // bytes to read (DWORD boundry, max 0x1000); pbResult must have room for this.
DWORD cb; // bytes read into result buffer.
PBYTE pb; // ptr to 0x1000 sized buffer to receive read bytes.
PVOID pvReserved1; // reserved for use by caller.
PVOID pvReserved2; // reserved for use by caller.
WORD version; // version of struct
WORD Future1; // reserved for future use.
DWORD Future2; // reserved for future use.
ULONG64 qwDeviceA; // device-physical address (used by device layer).
struct {
PVOID pvReserved1;
PVOID pvReserved2;
BYTE pbReserved[32];
} sReserved; // reserved for future use.
} VMMDLL_MEM_IO_SCATTER_HEADER, *PVMMDLL_MEM_IO_SCATTER_HEADER, **PPVMMDLL_MEM_IO_SCATTER_HEADER;
/*
* Read memory in various non-contigious locations specified by the pointers to
* the items in the ppDMAs array. Result for each unit of work will be given
@@ -356,7 +292,7 @@ typedef struct tdVMMDLL_MEM_IO_SCATTER_HEADER {
* -- flags = optional flags as given by VMM_FLAG_*
* -- return = the number of successfully read items.
*/
DWORD VMMDLL_MemReadScatter(_In_ DWORD dwPID, _Inout_ PPVMMDLL_MEM_IO_SCATTER_HEADER ppMEMs, _In_ DWORD cpMEMs, _In_ DWORD flags);
DWORD VMMDLL_MemReadScatter(_In_ DWORD dwPID, _Inout_ PPMEM_IO_SCATTER_HEADER ppMEMs, _In_ DWORD cpMEMs, _In_ DWORD flags);
/*
* Read a single 4096-byte page of memory.
+18 -63
View File
@@ -62,26 +62,10 @@ def VmmPy_Close():
def VmmPy_InternalInitializeReserved(args, is_printf = True, is_verbose = False, is_verbose_extra = False, is_verbose_tlp = False, page_table_base = 0):
"""INTERNAL USE ONLY - DO NOT CALL DIRECTLY!
"""
if page_table_base > 0:
args.append("-cr3")
args.append(str(page_table_base))
if is_printf:
args.append("-vdll")
if is_verbose:
args.append("-v")
if is_verbose_extra:
args.append("-vv")
if is_verbose_tlp:
args.append("-vvv")
VMMPYC_InitializeReserved(args)
def VmmPy_InitializeFile(file_name, is_printf = True, is_verbose = False, is_verbose_extra = False, is_verbose_tlp = False, page_table_base = 0):
"""Initialize VmmPy and the Virtual Memory Manager VMM.DLL from a memory dump file.
def VmmPy_Initialize(args, is_printf = True, is_verbose = False, is_verbose_extra = False, is_verbose_tlp = False, page_table_base = 0):
"""Initialize VmmPy and the Virtual Memory Manager VMM.DLL with arguments as
in the argument list args. Important is the -device option and optionally
-remote option as closer described in the MemProcFS and LeechCore projects.
Keyword arguments:
file_name -- str: memory dump file to load.
@@ -92,50 +76,21 @@ def VmmPy_InitializeFile(file_name, is_printf = True, is_verbose = False, is_ver
page_table_base -- int: optional page directory base of the OS kernel or a x64 process.
Example:
VmmPy_InitializeFile("c:\\temp\\dump.raw")
VmmPy_Initialize(['c:\\temp\\dump.raw'])
VmmPy_Initialize(['-device', 'dumpit','-remote', 'rpc://insecure:remote.example.com'])
"""
args = ["", "-device", file_name]
VmmPy_InternalInitializeReserved(args, is_printf, is_verbose, is_verbose_extra, is_verbose_tlp, page_table_base)
def VmmPy_InitializeTotalMeltdown(is_printf = True, is_verbose = False, is_verbose_extra = False, is_verbose_tlp = False, page_table_base = 0):
"""Initialize VmmPy and the Virtual Memory Manager VMM.DLL from the "Total Meltdown" CVE-2018-1038 vulnerability.
NB! Read/Write mode will be enabled.
NB! Required a linked pcileech.dll
Keyword arguments:
is_printf -- bool: console output from vmm.dll is enabled.
is_verbose -- bool: verbose level.
is_verbose_extra -- bool: extra verbose level.
is_verbose_tlp -- bool: show FPGA TLPs or similar - super verbose!
page_table_base -- int: optional page directory base of the OS kernel or a x64 process.
Example:
VmmPy_InitializeFile("c:\\temp\\dump.raw")
"""
args = ["", "-device", "totalmeltdown"]
VmmPy_InternalInitializeReserved(args, is_printf, is_verbose, is_verbose_extra, is_verbose_tlp, page_table_base)
def VmmPy_InitializeFPGA(is_printf = True, is_verbose = False, is_verbose_extra = False, is_verbose_tlp = False, page_table_base = 0):
"""Initialize VmmPy and the Virtual Memory Manager VMM.DLL from a supported FPGA device over USB.
NB! Read/Write mode will be enabled.
NB! Required a linked pcileech.dll
Keyword arguments:
is_printf -- bool: console output from vmm.dll is enabled.
is_verbose -- bool: verbose level.
is_verbose_extra -- bool: extra verbose level.
is_verbose_tlp -- bool: show FPGA TLPs or similar - super verbose!
page_table_base -- int: optional page directory base of the OS kernel or a x64 process.
Example:
VmmPy_InitializeFile("c:\\temp\\dump.raw")
"""
args = ["", "-device", "fpga"]
VmmPy_InternalInitializeReserved(args, is_printf, is_verbose, is_verbose_extra, is_verbose_tlp, page_table_base)
if page_table_base > 0:
args.append("-cr3")
args.append(str(page_table_base))
if is_printf:
args.append("-printf")
if is_verbose:
args.append("-v")
if is_verbose_extra:
args.append("-vv")
if is_verbose_tlp:
args.append("-vvv")
VMMPYC_Initialize(args)
+3 -3
View File
@@ -45,9 +45,9 @@ def VmmPy_Example(dump_file_name):
print("--------------------------------------------------------------------")
print("Initialize VmmPy with the dump file specified. ")
input("Press Enter to continue...")
print("CALL: VmmPy_InitializeFile()")
VmmPy_InitializeFile(dump_file_name)
print("SUCCESS: VmmPy_InitializeFile()")
print("CALL: VmmPy_Initialize()")
VmmPy_Initialize(["-device", dump_file_name])
print("SUCCESS: VmmPy_Initialize()")
# GET CONFIG
print("--------------------------------------------------------------------")
BIN
View File
Binary file not shown.
Binary file not shown.
+466
View File
@@ -0,0 +1,466 @@
// leechcore.h : header file for the leechcore module - which purpose is to
// expose low-level device physical memory functionality.
//
// This library is thread-safe in all functions with the notable exceptions of
// the LeechCore_Open() and LeechCore_Close() functions. Some devices may allow
// multi-threaded access while in reality most devices are single-threaded and
// will control synchronization where necessary with locks.
//
// The library is initialized by calling LeechCore_Open with a LEECHCORE_CONFIG
// struct containing the correct configuration paramters. Note that the version
// and magic values must be set in addition to the szDevice configuration value
// Also, it may be possible to optionally connect to a remote leechcore service
// or instance over RPC by specifying a szRemote configuration value.
//
// ----------------------------------------------------------------------------
//
// Remote instance: szRemote configuration value. Connect to a remote leechcore
// instance by specifying a configuration value in the szRemote parameter. If a
// loaded already valid instance exists remotely this will be prioritized above
// the value in szDevice. If the acquisition device is not yet loaded by the
// remote instance the value in szDevice will be used. Normally, the connection
// will take place as a mutually authenticated encrypted connection secured by
// kerberos. If not possible or desirable the 'insecure' value may be specified
// to disable authentication and security.
// Syntax:
// rpc://<remote_spn>:<host>:<port> (port = optional, remote_spn = kerberos)
// (SPN of remote service or 'insecure' )
// Examples:
// rpc://insecure:remotehost.example.com (connect insecure to remote host )
// rpc://[email protected]:192.0.0.5 (connect secure to remote host )
// rpc://insecure:127.0.0.0:6666 (connect insecure non-default port)
//
// ----------------------------------------------------------------------------
//
// Device to connect to: szDevice contains the device to capture memory from.
// Supported memory acquisition devices are:
// USB3380 : hardware, read/write, 32-bit (4GB) addressing only. Requires a
// PCILeech flashed USB3380 device connected over USB and Google
// Android WinUSB drivers to be installed. Download and install from:
// http://developer.android.com/sdk/win-usb.html#download
// Syntax:
// USB3380
// USB3380://USB2 (force USB2 connection speed)
//
// FPGA : hardware, read/write - requires a PCILeech FPGA flashed hardware
// device as shown at: https://github.com/ufrisk/pcileech-fpga
// Also requires the FTD3XX.DLL from ftdichip to be placed in the
// same directory as the executable. Download from ftdichip at:
// http://www.ftdichip.com/Drivers/D3XX/FTD3XXLibrary_v1.2.0.6.zip
// Syntax:
// FGPA
// FPGA://<read_uS>[:<write_uS>[:<probe_uS>]] (values are optional)
//
// SP605TCP : hardware, read/write - connect to a remote SP605 FPGA over the
// network using the implementation created by @d_olex.
// https://github.com/Cr4sh/s6_pcie_microblaze
// Syntax:
// SP605TCP://<target_ip>[:<target_port>] (port is optional)
//
// RAWTCP : read/write - connect to a remote raw tcp device - such as HPE iLO
// that have been patched to support DMA as per blog entry below:
// https://www.synacktiv.com/posts/exploit/using-your-bmc-as-a-dma-device-plugging-pcileech-to-hpe-ilo-4.html
// Syntax:
// RAWTCP://<target_ip>[:<target_port>] (port is optional)
//
// HvSavedState : read-only - connect to a Hyper-V saved state file. In order
// to do so the .dll file 'vmsavedstatedumpprovider.dll' must be
// placed in same directory as the executable file.
//
// PMEM : load the rekall winpmem driver into the kernel and connect to it
// to acquire memory. The driver file 'winpmem_x64.sys' is found in
// the Rekall directory after most recent version has been installed.
// Copy 'winpmem_x64.sys' to the directory of leechcore.dll and run
// executable as elevated admin using syntax below:
// Syntax:
// PMEM (use winpmem_x64.sys in directory of executable)
// PMEM://<non_default_path_to_file_winpmem_x64.sys>
//
// TOTALMELTDOWN : read/write - requires a Windows 7 system vulnerable to the
// "Total Meltdown" vulnerability - CVE-2018-1038.
// Syntax:
// TOTALMELTDOWN
//
// FILE : use dump file, either a raw linear memory dump or full crash dump.
// Which format to use is auto-detected. If it looks like a full cash
// dump that format will be used, otherwise it will be assumed that a
// raw linear memory dump is to be used.
// Syntax:
// <filename> (no device-type prefix - just use the file name)
// FILE://<filename>
//
// DumpIt : DumpIt is a "virtual" device. It's only possible to use the DumpIt
// device if the main process containing LeechCore has been started
// with DumpIt in LiveKD mode.
// Example 1:
// DumpIt.exe /LIVEKD /A MemProcFS.exe
// Example 2:
// DumpIt.exe /LIVEKD /A LeechSvc.exe /C "interactive insecure"
// and then connect to remote service by:
// MemProcFS.exe -remote rpc://insecure:192.168.x.x -device DumpIt
//
// EXISTING : Attach to existing already loaded configuration. This is done
// instead of the default behaviour of closing any existing devices
// and initializing the new requested device. If no existing device
// exists the call to LeechCore_Open will fail.
// Syntax:
// EXISTING
//
//
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
// Header Version: 1.0
//
#ifndef __LEECHCORE_H__
#define __LEECHCORE_H__
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
//-----------------------------------------------------------------------------
// WINDOWS / LINUX COMPATIBILITY BELOW:
//-----------------------------------------------------------------------------
#ifdef _WIN32
#include <Windows.h>
typedef unsigned __int64 QWORD, *PQWORD;
#define DLLEXPORT __declspec(dllexport)
#endif /* _WIN32 */
#ifdef LINUX
#include <stdint.h>
#include <stddef.h>
typedef void VOID, *PVOID, *LPVOID;
typedef void *HANDLE, **PHANDLE;
typedef uint32_t BOOL, *PBOOL;
typedef uint8_t BYTE, *PBYTE;
typedef char CHAR, *PCHAR, *PSTR, *LPSTR;
typedef uint16_t WORD, *PWORD, USHORT, *PUSHORT;
typedef uint32_t DWORD, *PDWORD;
typedef long long unsigned int QWORD, *PQWORD, ULONG64, *PULONG64;
#define MAX_PATH 260
#define DLLEXPORT __attribute__((visibility("default")))
#define _In_
#define _Out_
#define _In_z_
#define _Inout_
#define _In_opt_
#define _Out_opt_
#define _Out_writes_(x)
#define _Check_return_opt_
#define _Printf_format_string_
#define _Inout_updates_bytes_(x)
#define _In_reads_(cbDataIn)
#define _Success_(return)
#endif /* LINUX */
//-----------------------------------------------------------------------------
// GENERAL HEADER DEFINES BELOW:
//-----------------------------------------------------------------------------
#define MEM_IO_SCATTER_HEADER_MAGIC 0xffff6548
#define MEM_IO_SCATTER_HEADER_VERSION 0x0003
typedef struct tdMEM_IO_SCATTER_HEADER {
DWORD magic; // magic
WORD version; // version
WORD Future1;
ULONG64 qwA; // base address.
DWORD cbMax; // bytes to read (DWORD boundry, max 0x1000); pb must have room for this.
DWORD cb; // bytes read into result buffer.
PBYTE pb; // ptr to 0x1000 sized buffer to receive read bytes.
PVOID pvReserved1; // reserved for use by caller.
PVOID pvReserved2; // reserved for use by caller.
PVOID Future2[8];
} MEM_IO_SCATTER_HEADER, *PMEM_IO_SCATTER_HEADER, **PPMEM_IO_SCATTER_HEADER;
//-----------------------------------------------------------------------------
// LEECHCORE INITIALIZATION / CLOSE FUNCTIONALITY BELOW:
//-----------------------------------------------------------------------------
typedef enum tdLEECHCORE_DEVICE {
LEECHCORE_DEVICE_NA = 0,
LEECHCORE_DEVICE_FILE = 1,
LEECHCORE_DEVICE_PMEM = 2,
LEECHCORE_DEVICE_FPGA = 3,
LEECHCORE_DEVICE_SP605_TCP = 4,
LEECHCORE_DEVICE_USB3380 = 5,
LEECHCORE_DEVICE_TOTALMELTDOWN = 6,
LEECHCORE_DEVICE_HVSAVEDSTATE = 7,
LEECHCORE_DEVICE_RAWTCP = 8,
} LEECHCORE_DEVICE;
#define LEECHCORE_CONFIG_MAGIC 0xffff6549
#define LEECHCORE_CONFIG_VERSION 0x0001
#define LEECHCORE_CONFIG_FLAG_PRINTF 0x0001
#define LEECHCORE_CONFIG_FLAG_PRINTF_VERBOSE_1 0x0002
#define LEECHCORE_CONFIG_FLAG_PRINTF_VERBOSE_2 0x0004
#define LEECHCORE_CONFIG_FLAG_PRINTF_VERBOSE_3 0x0008
#define LEECHCORE_CONFIG_FLAG_REMOTE_NO_COMPRESS 0x0010
typedef struct tdLEECHCORE_CONFIG {
DWORD magic; // set by caller.
WORD version; // set by caller.
WORD flags; // set by caller, updated by device.
ULONG64 paMax; // set by caller, updated by device.
ULONG64 cbMaxSizeMemIo; // set by caller, updated by device.
ULONG64 paMaxNative; // set by device.
LEECHCORE_DEVICE tpDevice; // set by device.
BOOL fWritable; // set by device. (is device writable?)
BOOL fVolatile; // set by device. (is device volatile / memory may change?)
BOOL fVolatileMaxAddress; // set by device. (is max address volatile? - poll changes with LEECHCORE_OPT_MEMORYINFO_ADDR_MAX)
BOOL fRemote; // set by device.
WORD VersionMajor; // set by device.
WORD VersionMinor; // set by device.
WORD VersionRevision; // set by device.
CHAR szDevice[MAX_PATH]; // set by caller.
CHAR szRemote[MAX_PATH]; // set by caller.
// optional 'printf' function pointer. if set to non null value 'printf'
// calls will be redirected. useful when logging to files.
_Check_return_opt_ int(*pfn_printf_opt)(_In_z_ _Printf_format_string_ char const* const _Format, ...); // set by caller.
} LEECHCORE_CONFIG, *PLEECHCORE_CONFIG;
typedef struct tdLEECHCORE_PAGESTAT_MINIMAL {
HANDLE h;
VOID(*pfnPageStatUpdate)(HANDLE h, ULONG64 pa, ULONG64 cPageSuccessAdd, ULONG64 cPageFailAdd);
} LEECHCORE_PAGESTAT_MINIMAL, *PLEECHCORE_PAGESTAT_MINIMAL;
/*
* Open a connection to the target device.
* -- pInformation
* -- result
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_Open(_Inout_ PLEECHCORE_CONFIG pConfig);
/*
* Clean up various device related stuff and deallocate memory buffers.
*/
DLLEXPORT VOID LeechCore_Close();
//-----------------------------------------------------------------------------
// LEECHCORE CORE READ AND WRITE FUNCTIONALITY BELOW:
//-----------------------------------------------------------------------------
#define LEECHCORE_FLAG_READ_RETRY 0x01
#define LEECHCORE_FLAG_WRITE_RETRY 0x01
#define LEECHCORE_FLAG_WRITE_VERIFY 0x02
/*
* Allocate a scatter buffer containing empty 0x1000-sized ppMEMs with address
* set to zero. Caller is responsible for calling LocalFree(ppMEMs).
* -- cMEMs
* -- pppMEMs = pointer to receive ppMEMs on success.
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_AllocScatterEmpty(_In_ DWORD cMEMs, _Out_ PPMEM_IO_SCATTER_HEADER *pppMEMs);
/*
* Read memory in various non-contigious locations specified by the items in the
* phDMAs array. Result for each unit of work will be given individually. No upper
* limit of number of items to read, but no performance boost will be given if
* above hardware limit. Max size of each unit of work is one 4k page (4096 bytes).
* -- ppMEMs = array of scatter read headers.
* -- cpMEMs = count of ppDMAs.
*/
DLLEXPORT VOID LeechCore_ReadScatter(_Inout_ PPMEM_IO_SCATTER_HEADER ppMEMs, _In_ DWORD cpMEMs);
/*
* Try read memory in a fairly optimal way considering device limits. The number
* of total successfully read bytes is returned. Failed reads will be zeroed out
* in the returned memory.
* -- pa
* -- pb
* -- cb
* -- return = the number of bytes successfully read.
*/
DLLEXPORT DWORD LeechCore_Read(_In_ ULONG64 pa, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb);
/*
* Try read memory in a fairly optimal way considering device limits. The number
* of total successfully read bytes is returned. Failed reads will be zeroed out
* in the returned memory.
* -- pa
* -- pb
* -- cb
* -- flags = 0 or LEECHCORE_FLAG_READ_RETRY
* -- pPageStat = optional minimal statistic struct to update.
* -- return = the number of bytes successfully read.
*/
DLLEXPORT DWORD LeechCore_ReadEx(_In_ ULONG64 pa, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _In_ DWORD flags, _In_opt_ PLEECHCORE_PAGESTAT_MINIMAL pPageStat);
/*
* Write data to the target system if supported by the device.
* -- pa
* -- pb
* -- cb
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_Write(_In_ ULONG64 pa, _In_ PBYTE pb, _In_ DWORD cb);
/*
* Write data to the target system if supported by the device.
* -- pa
* -- pb
* -- cb
* -- flags = 0 or LEECHCORE_FLAG_WRITE_*
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_WriteEx(_In_ ULONG64 pa, _In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD flags);
/*
* Probe the memory of the target system to check whether it's readable or not.
* Please note that not all devices support this natively.
* -- pa = address to start probe from.
* -- cPages = number of 4kB pages to probe.
* -- pbResultMap = result map, 1 byte represents 1 page, 0 = fail, 1 = success.
* (individual page elements in pbResultMap must be set to 0 [fail] on call
* for probe to take place on individual page).
* -- return = FALSE if not supported by underlying hardware, TRUE if supported.
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_Probe(_In_ QWORD pa, _In_ DWORD cPages, _Inout_updates_bytes_(cPages) PBYTE pbResultMap);
//-----------------------------------------------------------------------------
// GET/SET DEVICE OPTIONS BELOW. SOME OPTIONS ARE GENERAL LEECHCORE OPTIONS
// WHILE OTHER ARE DEVICE SPECIFIC. USE FUNCTIONS:
// LeechCore_GetOption() AND LeechCore_GetOption() TO GET/SET OPTIONS.
// FOR DEVICE-SPECIFIC OPTIONS PLEASE SEE INDIVIDUAL DEVICE FILES FOR MORE
// DETAILED INFORMATION.
//-----------------------------------------------------------------------------
#define LEECHCORE_OPT_CORE_PRINTF_ENABLE 0x80000001 // RW
#define LEECHCORE_OPT_CORE_VERBOSE 0x80000002 // RW
#define LEECHCORE_OPT_CORE_VERBOSE_EXTRA 0x80000003 // RW
#define LEECHCORE_OPT_CORE_VERBOSE_EXTRA_TLP 0x80000004 // RW
#define LEECHCORE_OPT_CORE_VERSION_MAJOR 0x01000001 // R
#define LEECHCORE_OPT_CORE_VERSION_MINOR 0x01000002 // R
#define LEECHCORE_OPT_CORE_VERSION_REVISION 0x01000003 // R
#define LEECHCORE_OPT_MEMORYINFO_VALID 0x02000001 // R
#define LEECHCORE_OPT_MEMORYINFO_ADDR_MAX 0x02000002 // R
#define LEECHCORE_OPT_MEMORYINFO_FLAG_32BIT 0x02000003 // R
#define LEECHCORE_OPT_MEMORYINFO_FLAG_PAE 0x02000004 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_VERSION_MINOR 0x02000005 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_VERSION_MAJOR 0x02000006 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_DTB 0x02000007 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_PFN 0x02000008 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_PsLoadedModuleList 0x02000009 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_PsActiveProcessHead 0x0200000a // R
#define LEECHCORE_OPT_MEMORYINFO_OS_MACHINE_IMAGE_TP 0x0200000b // R
#define LEECHCORE_OPT_MEMORYINFO_OS_NUM_PROCESSORS 0x0200000c // R
#define LEECHCORE_OPT_MEMORYINFO_OS_SYSTEMTIME 0x0200000d // R
#define LEECHCORE_OPT_MEMORYINFO_OS_UPTIME 0x0200000e // R
#define LEECHCORE_OPT_MEMORYINFO_OS_KERNELBASE 0x0200000f // R
#define LEECHCORE_OPT_MEMORYINFO_OS_KERNELHINT 0x02000010 // R
#define LEECHCORE_OPT_FPGA_PROBE_MAXPAGES 0x03000001 // RW
#define LEECHCORE_OPT_FPGA_RX_FLUSH_LIMIT 0x03000002 // RW
#define LEECHCORE_OPT_FPGA_MAX_SIZE_RX 0x03000003 // RW
#define LEECHCORE_OPT_FPGA_MAX_SIZE_TX 0x03000004 // RW
#define LEECHCORE_OPT_FPGA_DELAY_PROBE_READ 0x03000005 // RW - uS
#define LEECHCORE_OPT_FPGA_DELAY_PROBE_WRITE 0x03000006 // RW - uS
#define LEECHCORE_OPT_FPGA_DELAY_WRITE 0x03000007 // RW - uS
#define LEECHCORE_OPT_FPGA_DELAY_READ 0x03000008 // RW - uS
#define LEECHCORE_OPT_FPGA_RETRY_ON_ERROR 0x03000009 // RW
#define LEECHCORE_OPT_FPGA_DEVICE_ID 0x03000080 // R
#define LEECHCORE_OPT_FPGA_FPGA_ID 0x03000081 // R
#define LEECHCORE_OPT_FPGA_VERSION_MAJOR 0x03000082 // R
#define LEECHCORE_OPT_FPGA_VERSION_MINOR 0x03000083 // R
/*
* Set a device specific option value.
* -- fOption
* -- pqwValue = pointer to QWORD to receive option value.
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_GetOption(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue);
/*
* Set a device specific option value.
* -- fOption
* -- qwValue
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_SetOption(_In_ ULONG64 fOption, _In_ ULONG64 qwValue);
//-----------------------------------------------------------------------------
// TRANSFER DEVICE DEPENDANT COMMANDS OR DATA TO/FROM UNDERLYING DEVICES AND
// PERFORM ACTIONS USING THE LeechCore_CommandData() FUNCTION.
//-----------------------------------------------------------------------------
#define LEECHCORE_COMMANDDATA_FPGA_WRITE_TLP 0x00000101 // R
#define LEECHCORE_COMMANDDATA_FPGA_LISTEN_TLP 0x00000102 // R
#define LEECHCORE_COMMANDDATA_STATISTICS_GET 0x80000100 // R
#define LEECHCORE_STATISTICS_MAGIC 0xffff6550
#define LEECHCORE_STATISTICS_VERSION 0x0001
#define LEECHCORE_STATISTICS_ID_OPEN 0x00
#define LEECHCORE_STATISTICS_ID_READSCATTER 0x01
#define LEECHCORE_STATISTICS_ID_WRITE 0x02
#define LEECHCORE_STATISTICS_ID_PROBE 0x03
#define LEECHCORE_STATISTICS_ID_GETOPTION 0x04
#define LEECHCORE_STATISTICS_ID_SETOPTION 0x05
#define LEECHCORE_STATISTICS_ID_COMMANDDATA 0x06
#define LEECHCORE_STATISTICS_ID_MAX 0x06
static const LPSTR LEECHCORE_STATISTICS_NAME[] = {
"LeechCore_Open",
"LeechCore_ReadScatter",
"LeechCore_Write",
"LeechCore_Probe",
"LeechCore_GetOption",
"LeechCore_SetOption",
"LeechCore_CommandData"
};
typedef struct tdLEECHCORE_STATISTICS {
DWORD magic;
WORD version;
WORD Reserved0;
DWORD Reserved1;
QWORD qwFreq;
struct {
QWORD c;
QWORD tm; // total time in qwFreq ticks
} Call[0x10];
} LEECHCORE_STATISTICS, *PLEECHCORE_STATISTICS;
/*
* Transfer device dependant commands/data to/from the underlying device and
* perform device dependant actions.
* -- fOption
* -- cbDataIn
* -- pbDataIn
* -- pbDataOut
* -- cbDataOut
* -- pcbDataOut
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_CommandData(
_In_ ULONG64 fOption,
_In_reads_(cbDataIn) PBYTE pbDataIn,
_In_ DWORD cbDataIn,
_Out_writes_(cbDataOut) PBYTE pbDataOut,
_In_ DWORD cbDataOut,
_Out_ PDWORD pcbDataOut
);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __LEECHCORE_H__ */
+12 -10
View File
@@ -8,6 +8,8 @@
#include <stdio.h>
#include "vmmdll.h"
VMMDLL_MEMORYMODEL_TP g_VMemD_TpMemoryModel = VMMDLL_MEMORYMODEL_NA;
ULONG64 VMemD_GetBaseFromFileName(LPSTR sz)
{
if((strlen(sz) < 15) || (sz[0] != '0') || (sz[1] != 'x')) { return (ULONG64)-1; }
@@ -100,15 +102,7 @@ BOOL VMemD_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList)
return FALSE;
}
for(i = 0; i < cEntries; i++) {
if(32 == (ULONG64)*ctx->phModulePrivate) {
sprintf_s(
szBufferFileName,
MAX_PATH - 1,
"0x%08x%s%s.vmem",
(DWORD)pMemMap[i].AddrBase,
pMemMap[i].szTag[0] ? "-" : "",
pMemMap[i].szTag[0] ? pMemMap[i].szTag : "");
} else {
if(g_VMemD_TpMemoryModel == VMMDLL_MEMORYMODEL_X64) {
sprintf_s(
szBufferFileName,
MAX_PATH - 1,
@@ -116,6 +110,14 @@ BOOL VMemD_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList)
pMemMap[i].AddrBase,
pMemMap[i].szTag[0] ? "-" : "",
pMemMap[i].szTag[0] ? pMemMap[i].szTag : "");
} else if((g_VMemD_TpMemoryModel == VMMDLL_MEMORYMODEL_X86) || (g_VMemD_TpMemoryModel == VMMDLL_MEMORYMODEL_X86PAE)) {
sprintf_s(
szBufferFileName,
MAX_PATH - 1,
"0x%08x%s%s.vmem",
(DWORD)pMemMap[i].AddrBase,
pMemMap[i].szTag[0] ? "-" : "",
pMemMap[i].szTag[0] ? pMemMap[i].szTag : "");
}
VMMDLL_VfsList_AddFile(pFileList, szBufferFileName, (pMemMap[i].cPages << 12));
}
@@ -139,11 +141,11 @@ VOID InitializeVmmPlugin(_In_ PVMMDLL_PLUGIN_REGINFO pRegInfo)
// Ensure that the plugin support the memory model that is used. The plugin
// currently supports the 64-bit x64 and 32-bit x86 and x86-pae memory models.
if(!((pRegInfo->tpMemoryModel == VMMDLL_MEMORYMODEL_X64) || (pRegInfo->tpMemoryModel == VMMDLL_MEMORYMODEL_X86) || (pRegInfo->tpMemoryModel == VMMDLL_MEMORYMODEL_X86PAE))) { return; }
g_VMemD_TpMemoryModel = pRegInfo->tpMemoryModel;
strcpy_s(pRegInfo->reg_info.szModuleName, 32, "vmemd"); // module name - 'vmemd'.
pRegInfo->reg_info.fProcessModule = TRUE; // module shows in process directory.
pRegInfo->reg_fn.pfnList = VMemD_List; // List function supported.
pRegInfo->reg_fn.pfnRead = VMemD_Read; // Read function supported.
pRegInfo->reg_fn.pfnWrite = VMemD_Write; // Write function supported.
pRegInfo->reg_info.hModulePrivate = (HANDLE)(ULONG64)((pRegInfo->tpMemoryModel == VMMDLL_MEMORYMODEL_X64) ? 64 : 32); // use handle for "bitness".
pRegInfo->pfnPluginManager_Register(pRegInfo); // Register with the plugin maanger.
}
Binary file not shown.
+32 -10
View File
@@ -12,9 +12,9 @@
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{41D93156-9DCB-4F19-BF02-993CEC361A81}</ProjectGuid>
<ProjectGuid>{BC6D11FF-3B1E-480E-A1AB-AAE5868FE9B3}</ProjectGuid>
<RootNamespace>mvmemd</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
@@ -22,6 +22,7 @@
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
@@ -29,6 +30,7 @@
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@@ -45,7 +47,6 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>$(SolutionDir)\files\plugins\</OutDir>
<IntDir>$(SolutionDir)\files\temp\$(ProjectName)\</IntDir>
<LinkIncremental />
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>$(SolutionDir)\files\plugins\</OutDir>
@@ -59,10 +60,18 @@
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<AdditionalDependencies>$(SolutionDir)\files\vmm.lib</AdditionalDependencies>
<ProgramDatabaseFile>$(OutDir)\..\lib\$(TargetName).pdb</ProgramDatabaseFile>
<AdditionalDependencies>$(SolutionDir)\files\vmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ImportLibrary>$(OutDir)\..\lib\$(TargetName).lib</ImportLibrary>
<ProgramDatabaseFile>$(OutDir)\..\lib\$(TargetName).pdb</ProgramDatabaseFile>
</Link>
<PostBuildEvent>
<Command>
</Command>
</PostBuildEvent>
<PreBuildEvent>
<Command>copy $(SolutionDir)\files\leechcore.h $(ProjectDir)\ /y
copy $(SolutionDir)\files\vmmdll.h $(ProjectDir)\ /y</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
@@ -72,22 +81,35 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
<AdditionalDependencies>$(SolutionDir)\files\vmm.lib</AdditionalDependencies>
<GenerateDebugInformation>DebugFull</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)\..\lib\$(TargetName).pdb</ProgramDatabaseFile>
<AdditionalDependencies>$(SolutionDir)\files\vmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ImportLibrary>$(OutDir)\..\lib\$(TargetName).lib</ImportLibrary>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
<ProgramDatabaseFile>$(OutDir)\..\lib\$(TargetName).pdb</ProgramDatabaseFile>
</Link>
<PostBuildEvent>
<Command>
</Command>
</PostBuildEvent>
<PreBuildEvent>
<Command>copy $(SolutionDir)\files\leechcore.h $(ProjectDir)\ /y
copy $(SolutionDir)\files\vmmdll.h $(ProjectDir)\ /y</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="m_vmemd.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="leechcore.h" />
<ClInclude Include="version.h" />
<ClInclude Include="vmmdll.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="m_vmemd.c" />
<ResourceCompile Include="m_vmemd.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
+17 -6
View File
@@ -14,17 +14,28 @@
<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="Header Files\vmm">
<UniqueIdentifier>{2fec9e35-00d4-4c85-9715-a9582e63f7df}</UniqueIdentifier>
<UniqueIdentifier>{1d09101e-f5a9-4468-b8c7-9ed1f353cbf8}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="vmmdll.h">
<Filter>Header Files\vmm</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="m_vmemd.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="vmmdll.h">
<Filter>Header Files\vmm</Filter>
</ClInclude>
<ClInclude Include="leechcore.h">
<Filter>Header Files\vmm</Filter>
</ClInclude>
<ClInclude Include="version.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="m_vmemd.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>
+22
View File
@@ -0,0 +1,22 @@
#define STRINGIZE2(s) #s
#define STRINGIZE(s) STRINGIZE2(s)
#define VERSION_MAJOR 2
#define VERSION_MINOR 0
#define VERSION_REVISION 0
#define VERSION_BUILD 0
#define VER_FILE_DESCRIPTION_STR "The Memory Process File System : Plugin vmemd"
#define VER_FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_BUILD
#define VER_FILE_VERSION_STR STRINGIZE(VERSION_MAJOR) \
"." STRINGIZE(VERSION_MINOR) \
"." STRINGIZE(VERSION_REVISION) \
"." STRINGIZE(VERSION_BUILD) \
#define VER_COMPANY_NAME_STR ""
#define VER_PRODUCTNAME_STR "m_vmemd"
#define VER_PRODUCT_VERSION VER_FILE_VERSION
#define VER_PRODUCT_VERSION_STR VER_FILE_VERSION_STR
#define VER_ORIGINAL_FILENAME_STR VER_PRODUCTNAME_STR ".dll"
#define VER_INTERNAL_NAME_STR VER_ORIGINAL_FILENAME_STR
#define VER_COPYRIGHT_STR "Copyright (c) Ulf Frisk 2018-2019"
+44 -108
View File
@@ -1,11 +1,14 @@
// vmmdll.h : header file to include in projects that use vmm.dll either as
// stand anlone projects or as native plugins to vmm.dll.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
// Header Version: 2.0
//
#include <windows.h>
#include "leechcore.h"
#ifndef __VMMDLL_H__
#define __VMMDLL_H__
@@ -19,52 +22,23 @@ extern "C" {
//-----------------------------------------------------------------------------
/*
* RESERVED FUNCTION! DO NOT USE!
* Call other VMMDLL_Intialize functions to initialize VMM.DLL and the memory
* process file system.
* Initialize VMM.DLL with command line parameters. For a more detailed info
* about the parameters please see github wiki for Memory Process File System
* and LeechCore. THIS IS THE PREFERED WAY OF INITIALIZING VMM.DLL
* Important parameters are:
* -vdll = show printf style outputs)
* -v -vv -vvv = extra verbosity levels)
* -device = device as on format for LeechCore - please see leechcore.h or
* Github documentation for additional information. Some values
* are: <file>, fpga, usb3380, hvsavedstate, totalmeltdown, pmem
* -remote = remote LeechCore instance - please see leechcore.h or Github
* documentation for additional information.
* -- argc
* -- argv
* -- return = success/fail
*/
_Success_(return)
BOOL VMMDLL_InitializeReserved(_In_ DWORD argc, _In_ LPSTR argv[]);
/*
* Initialize VMM.DLL from a memory dump file in raw format. VMM.DLL will be
* initialized in read-only mode. It's possible to optionally specify the page
* table base of the windows kernel (for full vmm features) or the page table
* base of a single 64-bit process in any x64 operating system. NB! usually it
* is not necessary to specify the PageTableBase - it will be auto-identified
* most often if the target is Windows.
* -- szFileName = the file name of the raw memory dump to use.
* -- szPageTableBaseOpt = optionally the Page Table Base of kernel or process
* as hex string. NB! this is usally not required. Example: "0x1ab000".
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeFile(_In_ LPSTR szFileName, _In_opt_ LPSTR szPageTableBaseOpt);
/*
* Intiailize VMM.DLL from a supported FPGA device over USB. VMM.DLL will be
* initialized in read/write mode upon success. Optionally it will be possible
* to specify the max physical address and the page table base of the kernel or
* process that should be investigated.
* NB! Requires pcileech.dll to be placed in the same directory as vmm.dll.
* -- szMaxPhysicalAddressOpt = max physical address of the target system as a
* hex string. Example: "0x8000000000". If zero value is given the max
* address will be auto-identified.
* -- szPageTableBaseOpt = optionally the Page Table Base of kernel or process
* as hex string. NB! this is usally not required. Example: "0x1ab000".
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeFPGA(_In_opt_ LPSTR szMaxPhysicalAddressOpt, _In_opt_ LPSTR szPageTableBaseOpt);
/*
* Initialize VMM.DLL from a the "Total Meltdown" CVE-2018-1038 vulnerability.
* NB! Requires pcileech.dll to be placed in the same directory as vmm.dll.
* initialized in read/write mode upon success.
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeTotalMeltdown();
BOOL VMMDLL_Initialize(_In_ DWORD argc, _In_ LPSTR argv[]);
/*
* Close an initialized instance of VMM.DLL and clean up all allocated resources
@@ -84,43 +58,29 @@ BOOL VMMDLL_Close();
/*
* Options used together with the functions: VMMDLL_GetOption & VMMDLL_SetOption
* If VMM.DLL is chained with PCILEECH.DLL then required values will be passed
* along to PCILEECH.DLL when necessary.
* Options are defined with either: VMMDLL_OPT_* in this header file or as
* MEMDEVICE_OPT_* in memdevice.h
* For more detailed information check the sources for individual device types.
*/
#define VMMDLL_OPT_DEVICE_FPGA_PROBE_MAXPAGES 0x01 // RW
#define VMMDLL_OPT_DEVICE_FPGA_RX_FLUSH_LIMIT 0x02 // RW
#define VMMDLL_OPT_DEVICE_FPGA_MAX_SIZE_RX 0x03 // RW
#define VMMDLL_OPT_DEVICE_FPGA_MAX_SIZE_TX 0x04 // RW
#define VMMDLL_OPT_DEVICE_FPGA_DELAY_PROBE_READ 0x05 // RW - uS
#define VMMDLL_OPT_DEVICE_FPGA_DELAY_PROBE_WRITE 0x06 // RW - uS
#define VMMDLL_OPT_DEVICE_FPGA_DELAY_WRITE 0x07 // RW - uS
#define VMMDLL_OPT_DEVICE_FPGA_DELAY_READ 0x08 // RW - uS
#define VMMDLL_OPT_DEVICE_FPGA_RETRY_ON_ERROR 0x09 // RW
#define VMMDLL_OPT_DEVICE_FPGA_DEVICE_ID 0x80 // R
#define VMMDLL_OPT_DEVICE_FPGA_FPGA_ID 0x81 // R
#define VMMDLL_OPT_DEVICE_FPGA_VERSION_MAJOR 0x82 // R
#define VMMDLL_OPT_DEVICE_FPGA_VERSION_MINOR 0x83 // R
#define VMMDLL_OPT_CORE_PRINTF_ENABLE 0x80000001 // RW
#define VMMDLL_OPT_CORE_VERBOSE 0x80000002 // RW
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA 0x80000003 // RW
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA_TLP 0x80000004 // RW
#define VMMDLL_OPT_CORE_MAX_NATIVE_ADDRESS 0x80000005 // R
#define VMMDLL_OPT_CORE_MAX_NATIVE_IOSIZE 0x80000006 // R
#define VMMDLL_OPT_CORE_SYSTEM 0x80000007 // R
#define VMMDLL_OPT_CORE_MEMORYMODEL 0x80000008 // R
#define VMMDLL_OPT_CORE_PRINTF_ENABLE 0x80000001 // RW
#define VMMDLL_OPT_CORE_VERBOSE 0x80000002 // RW
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA 0x80000003 // RW
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA_TLP 0x80000004 // RW
#define VMMDLL_OPT_CORE_MAX_NATIVE_ADDRESS 0x80000005 // R
#define VMMDLL_OPT_CORE_MAX_NATIVE_IOSIZE 0x80000006 // R
#define VMMDLL_OPT_CORE_SYSTEM 0x80000007 // R
#define VMMDLL_OPT_CORE_MEMORYMODEL 0x80000008 // R
#define VMMDLL_OPT_CONFIG_IS_REFRESH_ENABLED 0x40000001 // R - 1/0
#define VMMDLL_OPT_CONFIG_TICK_PERIOD 0x40000002 // RW - base tick period in ms
#define VMMDLL_OPT_CONFIG_READCACHE_TICKS 0x40000003 // RW - memory cache validity period (in ticks)
#define VMMDLL_OPT_CONFIG_TLBCACHE_TICKS 0x40000004 // RW - page table (tlb) cache validity period (in ticks)
#define VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_PARTIAL 0x40000005 // RW - process refresh (partial) period (in ticks)
#define VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_TOTAL 0x40000006 // RW - process refresh (full) period (in ticks)
#define VMMDLL_OPT_CONFIG_VMM_VERSION_MAJOR 0x40000007 // R
#define VMMDLL_OPT_CONFIG_VMM_VERSION_MINOR 0x40000008 // R
#define VMMDLL_OPT_CONFIG_VMM_VERSION_REVISION 0x40000009 // R
#define VMMDLL_OPT_CONFIG_STATISTICS_FUNCTIONCALL 0x4000000A // RW - enable function call statistics (.status/statistics_fncall file)
#define VMMDLL_OPT_CONFIG_IS_REFRESH_ENABLED 0x40000001 // R - 1/0
#define VMMDLL_OPT_CONFIG_TICK_PERIOD 0x40000002 // RW - base tick period in ms
#define VMMDLL_OPT_CONFIG_READCACHE_TICKS 0x40000003 // RW - memory cache validity period (in ticks)
#define VMMDLL_OPT_CONFIG_TLBCACHE_TICKS 0x40000004 // RW - page table (tlb) cache validity period (in ticks)
#define VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_PARTIAL 0x40000005 // RW - process refresh (partial) period (in ticks)
#define VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_TOTAL 0x40000006 // RW - process refresh (full) period (in ticks)
#define VMMDLL_OPT_CONFIG_VMM_VERSION_MAJOR 0x40000007 // R
#define VMMDLL_OPT_CONFIG_VMM_VERSION_MINOR 0x40000008 // R
#define VMMDLL_OPT_CONFIG_VMM_VERSION_REVISION 0x40000009 // R
#define VMMDLL_OPT_CONFIG_STATISTICS_FUNCTIONCALL 0x4000000A // RW - enable function call statistics (.status/statistics_fncall file)
static const LPSTR VMMDLL_MEMORYMODEL_TOSTRING[4] = { "N/A", "X86", "X86PAE", "X64" };
@@ -256,9 +216,9 @@ _Success_(return)
BOOL VMMDLL_VfsInitializePlugins();
#define VMMDLL_PLUGIN_CONTEXT_MAGIC 0xc0ffee663df9301c
#define VMMDLL_PLUGIN_CONTEXT_VERSION 1
#define VMMDLL_PLUGIN_CONTEXT_VERSION 2
#define VMMDLL_PLUGIN_REGINFO_MAGIC 0xc0ffee663df9301d
#define VMMDLL_PLUGIN_REGINFO_VERSION 2
#define VMMDLL_PLUGIN_REGINFO_VERSION 3
#define VMMDLL_PLUGIN_EVENT_VERBOSITYCHANGE 0x01
@@ -267,8 +227,6 @@ typedef struct tdVMMDLL_PLUGIN_CONTEXT {
WORD wVersion;
WORD wSize;
DWORD dwPID;
PHANDLE phModulePrivate;
PHANDLE phProcessPrivate;
PVOID pProcess;
LPSTR szModule;
LPSTR szPath;
@@ -289,7 +247,6 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
PVOID pvReserved2;
// general plugin registration info to be filled out by the plugin below:
struct {
HANDLE hModulePrivate;
CHAR szModuleName[32];
BOOL fRootModule;
BOOL fProcessModule;
@@ -301,9 +258,8 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
BOOL(*pfnList)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList);
NTSTATUS(*pfnRead)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset);
NTSTATUS(*pfnWrite)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset);
VOID(*pfnNotify)(_Inout_opt_ PHANDLE phModulePrivate, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent);
VOID(*pfnCloseHandleModule)(_Inout_opt_ PHANDLE phModulePrivate);
VOID(*pfnCloseHandleProcess)(_Inout_opt_ PHANDLE phModulePrivate, _Inout_ PHANDLE phProcessPrivate);
VOID(*pfnNotify)(_In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent);
VOID(*pfnClose)();
PVOID pvReserved1;
PVOID pvReserved2;
} reg_fn;
@@ -323,26 +279,6 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
#define VMMDLL_FLAG_NOCACHE 0x0001 // do not use the data cache (force reading from memory acquisition device)
#define VMMDLL_FLAG_ZEROPAD_ON_FAIL 0x0002 // zero pad failed physical memory reads and report success if read within range of physical memory.
#define VMMDLL_MEM_IO_SCATTER_HEADER_VERSION 2
typedef struct tdVMMDLL_MEM_IO_SCATTER_HEADER {
ULONG64 qwA; // base address (DWORD boundry).
DWORD cbMax; // bytes to read (DWORD boundry, max 0x1000); pbResult must have room for this.
DWORD cb; // bytes read into result buffer.
PBYTE pb; // ptr to 0x1000 sized buffer to receive read bytes.
PVOID pvReserved1; // reserved for use by caller.
PVOID pvReserved2; // reserved for use by caller.
WORD version; // version of struct
WORD Future1; // reserved for future use.
DWORD Future2; // reserved for future use.
ULONG64 qwDeviceA; // device-physical address (used by device layer).
struct {
PVOID pvReserved1;
PVOID pvReserved2;
BYTE pbReserved[32];
} sReserved; // reserved for future use.
} VMMDLL_MEM_IO_SCATTER_HEADER, *PVMMDLL_MEM_IO_SCATTER_HEADER, **PPVMMDLL_MEM_IO_SCATTER_HEADER;
/*
* Read memory in various non-contigious locations specified by the pointers to
* the items in the ppDMAs array. Result for each unit of work will be given
@@ -356,7 +292,7 @@ typedef struct tdVMMDLL_MEM_IO_SCATTER_HEADER {
* -- flags = optional flags as given by VMM_FLAG_*
* -- return = the number of successfully read items.
*/
DWORD VMMDLL_MemReadScatter(_In_ DWORD dwPID, _Inout_ PPVMMDLL_MEM_IO_SCATTER_HEADER ppMEMs, _In_ DWORD cpMEMs, _In_ DWORD flags);
DWORD VMMDLL_MemReadScatter(_In_ DWORD dwPID, _Inout_ PPMEM_IO_SCATTER_HEADER ppMEMs, _In_ DWORD cpMEMs, _In_ DWORD flags);
/*
* Read a single 4096-byte page of memory.
-166
View File
@@ -1,166 +0,0 @@
// device.c : implementation related to memory acquisition devices.
//
// (c) Ulf Frisk, 2018
// Author: Ulf Frisk, [email protected]
//
#include "device.h"
#include "devicefile.h"
#include "devicepcileechdll.h"
#include "statistics.h"
#include "vmm.h"
VOID DeviceReadScatterMEM(_Inout_ PPMEM_IO_SCATTER_HEADER ppDMAs, _In_ DWORD cpDMAs, _Out_opt_ PDWORD pcpDMAsRead)
{
QWORD tmStart = Statistics_CallStart();
ctxMain->dev.pfnReadScatterMEM( ppDMAs, cpDMAs, pcpDMAsRead);
Statistics_CallEnd(STATISTICS_ID_DeviceReadScatterMEM, tmStart);
}
BOOL DeviceWriteMEM(_In_ QWORD qwAddr, _In_ PBYTE pb, _In_ DWORD cb)
{
BOOL result;
QWORD tmStart = Statistics_CallStart();
result = ctxMain->dev.pfnWriteMEM && ctxMain->dev.pfnWriteMEM(qwAddr, pb, cb);
Statistics_CallEnd(STATISTICS_ID_DeviceWriteMEM, tmStart);
return result;
}
VOID DeviceClose()
{
if(ctxMain->dev.pfnClose) {
ctxMain->dev.pfnClose();
}
}
/*
* Auto-identifies the maximum address by starting to try to read memory at 4GB
* and then by moving upwards. Reads should be minimized - but if "bad" hardware
* this may still (in very rare occurances) freeze the target computer if DMA
* device is used. Should only be called whenever needed - i.e. when the native
* device does not report a valid value in combination with the absence of user
* defined max address.
*/
QWORD DeviceAutoIdentifyMaxAddress()
{
DWORD i, cMEM;
QWORD qwCurrentAddress = 0x100000000, qwChunkSize = 0x100000000;
MEM_IO_SCATTER_HEADER pMEM[1], *ppMEM[1];
BYTE pbDummy[0x1000];
DWORD dwOFFSETS[] = { 0x0, 0x1000, 0x2000, 0x3000, 0x00010000, 0x00100000, 0x01000000, 0x10000000 };
DWORD cOFFSETS = sizeof(dwOFFSETS) / sizeof(DWORD);
// 1: set up
ZeroMemory(pMEM, sizeof(MEM_IO_SCATTER_HEADER));
pMEM->pb = pbDummy;
pMEM->cbMax = 0x1000;
*ppMEM = pMEM;
// 2: loop until fail on smallest chunk size (0x1000)
while(TRUE) {
for(i = 0; i < cOFFSETS; i++) {
pMEM->cb = 0;
pMEM->qwA = qwCurrentAddress + qwChunkSize + dwOFFSETS[i];
DeviceReadScatterMEM(ppMEM, 1, &cMEM);
if(cMEM) {
qwCurrentAddress += qwChunkSize;
break;
}
}
if(cMEM) { continue; }
if(qwChunkSize == 0x1000) {
return qwCurrentAddress + ((qwCurrentAddress == 0x100000000) ? 0 : 0xfff);
}
qwChunkSize >>= 1; // half chunk size
}
}
BOOL DeviceOpen()
{
BOOL result;
if((0 == _stricmp("fpga", ctxMain->cfg.szDevTpOrFileName)) || (0 == _stricmp("totalmeltdown", ctxMain->cfg.szDevTpOrFileName))) {
result = DevicePCILeechDll_Open(ctxMain);
} else {
result = DeviceFile_Open(ctxMain);
}
if(result) {
if((ctxMain->cfg.paAddrMax == 0x0000ffffffffffff) && (ctxMain->dev.paAddrMaxNative == 0x0000ffffffffffff)) {
// probe for max address - if needed and not already user supplied
ctxMain->dev.paAddrMaxNative = DeviceAutoIdentifyMaxAddress(ctxMain);
}
ctxMain->cfg.paAddrMax = min(ctxMain->cfg.paAddrMax, ctxMain->dev.paAddrMaxNative);
}
return result;
}
_Success_(return)
BOOL DeviceGetOption(_In_ QWORD fOption, _Out_ PQWORD pqwValue)
{
return ctxMain->dev.pfnGetOption && ctxMain->dev.pfnGetOption(fOption, pqwValue);
}
_Success_(return)
BOOL DeviceSetOption(_In_ QWORD fOption, _In_ QWORD qwValue)
{
return ctxMain->dev.pfnSetOption && ctxMain->dev.pfnSetOption(fOption, qwValue);
}
DWORD DeviceReadMEMEx_DoWork_Scatter(_In_ QWORD qwAddr, _Out_ PBYTE pb, _In_ DWORD cb, _Inout_opt_ PPAGE_STATISTICS pPageStat)
{
PBYTE pbBuffer;
PMEM_IO_SCATTER_HEADER pDMAs, *ppDMAs;
DWORD i, o, cDMAs, cDMAsRead;
cDMAs = cb >> 12;
pbBuffer = (PBYTE)LocalAlloc(LMEM_ZEROINIT, cDMAs * (sizeof(PMEM_IO_SCATTER_HEADER) + sizeof(MEM_IO_SCATTER_HEADER)));
if(!pbBuffer) { return 0; }
ppDMAs = (PMEM_IO_SCATTER_HEADER*)pbBuffer;
pDMAs = (PMEM_IO_SCATTER_HEADER)(pbBuffer + cDMAs * sizeof(PMEM_IO_SCATTER_HEADER));
for(i = 0, o = 0; i < cDMAs; i++, o += 0x1000) {
ppDMAs[i] = pDMAs + i;
pDMAs[i].qwA = qwAddr + o;
pDMAs[i].cbMax = min(0x1000, cb - o);
pDMAs[i].pb = pb + o;
}
DeviceReadScatterMEM(ppDMAs, cDMAs, &cDMAsRead);
for(i = 0; i < cDMAs; i++) {
if(pDMAs[i].cb == 0x1000) {
PageStatUpdate(pPageStat, pDMAs[i].qwA + 0x1000, 1, 0);
} else {
PageStatUpdate(pPageStat, pDMAs[i].qwA + 0x1000, 0, 1);
ZeroMemory(pDMAs[i].pb, pDMAs[i].cbMax);
}
}
LocalFree(pbBuffer);
return cDMAsRead << 12;
}
DWORD DeviceReadMEMEx_DoWork(_In_ QWORD qwAddr, _Out_ PBYTE pb, _In_ DWORD cb, _Inout_opt_ PPAGE_STATISTICS pPageStat, _In_ DWORD cbMaxSizeIo)
{
DWORD cbRd, cbRdOff;
DWORD cbChunk, cChunkTotal, cChunkSuccess = 0;
DWORD i, cbSuccess = 0;
// calculate current chunk sizes
cbChunk = ~0xfff & min(cb, cbMaxSizeIo);
cbChunk = (cbChunk > 0x3000) ? cbChunk : 0x1000;
cChunkTotal = (cb / cbChunk) + ((cb % cbChunk) ? 1 : 0);
// try read memory
memset(pb, 0, cb);
for(i = 0; i < cChunkTotal; i++) {
cbRdOff = i * cbChunk;
cbRd = ((i == cChunkTotal - 1) && (cb % cbChunk)) ? (cb % cbChunk) : cbChunk; // (last chunk may be smaller)
cbSuccess += DeviceReadMEMEx_DoWork_Scatter(qwAddr + cbRdOff, pb + cbRdOff, cbRd, pPageStat);
}
return cbSuccess;
}
DWORD DeviceReadMEMEx(_In_ QWORD qwAddr, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _Inout_opt_ PPAGE_STATISTICS pPageStat)
{
BYTE pbWorkaround[4096];
DWORD cbDataRead;
// read memory (with strange workaround for 1-page reads...)
if(cb > 0x1000) {
cbDataRead = DeviceReadMEMEx_DoWork(qwAddr, pb, cb, pPageStat, (DWORD)ctxMain->dev.qwMaxSizeMemIo);
} else {
// why is this working ??? if not here console is screwed up... (threading issue?)
cbDataRead = DeviceReadMEMEx_DoWork(qwAddr, pbWorkaround, 0x1000, pPageStat, (DWORD)ctxMain->dev.qwMaxSizeMemIo);
memcpy(pb, pbWorkaround, cb);
}
return cbDataRead;
}
-74
View File
@@ -1,74 +0,0 @@
// device.h : definitions related to memory acquisition devices.
//
// (c) Ulf Frisk, 2018
// Author: Ulf Frisk, [email protected]
//
#ifndef __DEVICE_H__
#define __DEVICE_H__
#include "vmm.h"
#include "statistics.h"
/*
* Open a connection to the target device.
* -- result
*/
BOOL DeviceOpen();
/*
* Clean up various device related stuff and deallocate memory buffers.
*/
VOID DeviceClose();
/*
* Read memory in various non-contigious locations specified by the items in the
* phDMAs array. Result for each unit of work will be given individually. No upper
* limit of number of items to read, but no performance boost will be given if
* above hardware limit. Max size of each unit of work is one 4k page (4096 bytes).
* -- ppMEMs = array of scatter read headers.
* -- cpMEMs = count of ppDMAs.
* -- pcpMEMsRead = optional count of number of successfully read ppMEMs.
*/
VOID DeviceReadScatterMEM(_Inout_ PPMEM_IO_SCATTER_HEADER ppMEMs, _In_ DWORD cpMEMs, _Out_opt_ PDWORD pcpMEMsRead);
/*
* Try read memory in a fairly optimal way considering device limits. The number
* of total successfully read bytes is returned. Failed reads will be zeroed out
* in the returned memory.
* -- qwAddr
* -- pb
* -- cb
* -- pPageStat = optional page statistics
* -- return = the number of bytes successfully read.
*/
DWORD DeviceReadMEMEx(_In_ QWORD qwAddr, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _Inout_opt_ PPAGE_STATISTICS pPageStat);
/*
* Write data to the target system using DMA.
* -- qwAddr
* -- pb
* -- cb
* -- return
*/
BOOL DeviceWriteMEM(_In_ QWORD qwAddr, _In_ PBYTE pb, _In_ DWORD cb);
/*
* Set a device specific option value. Please see individual device header files
* for a list of the possible device specific options.
* -- fOption
* -- pqwValue = pointer to QWORD to receive option value.
* -- return
*/
_Success_(return)
BOOL DeviceGetOption(_In_ QWORD fOption, _Out_ PQWORD pqwValue);
/*
* Set a device specific option value. Please see individual device header files
* for a list of the possible device specific options.
* -- fOption
* -- qwValue
* -- return
*/
_Success_(return)
BOOL DeviceSetOption(_In_ QWORD fOption, _In_ QWORD qwValue);
#endif /* __DEVICE_H__ */
-82
View File
@@ -1,82 +0,0 @@
// devicefile.c : implementation related to file backed memory acquisition device.
//
// (c) Ulf Frisk, 2018
// Author: Ulf Frisk, [email protected]
//
#include "devicefile.h"
#include "util.h"
#include "vmm.h"
typedef struct tdDEVICE_CONTEXT_FILE {
FILE *pFile;
QWORD cbFile;
LPSTR szFileName;
} DEVICE_CONTEXT_FILE, *PDEVICE_CONTEXT_FILE;
VOID DeviceFile_ReadScatterMEM(_Inout_ PPMEM_IO_SCATTER_HEADER ppMEMs, _In_ DWORD cpMEMs, _Out_opt_ PDWORD pcMEMsRead)
{
PDEVICE_CONTEXT_FILE ctxFile = (PDEVICE_CONTEXT_FILE)ctxMain->dev.hDevice;
DWORD i, cbToRead, c = 0;
PMEM_IO_SCATTER_HEADER pMEM;
for(i = 0; i < cpMEMs; i++) {
pMEM = ppMEMs[i];
if(pMEM->qwA >= ctxFile->cbFile) { continue; }
cbToRead = (DWORD)min(pMEM->cb, ctxFile->cbFile - pMEM->qwA);
if(pMEM->qwA != _ftelli64(ctxFile->pFile)) {
if(_fseeki64(ctxFile->pFile, pMEM->qwA, SEEK_SET)) { continue; }
}
pMEM->cb = (DWORD)fread(pMEM->pb, 1, pMEM->cbMax, ctxFile->pFile);
if(ctxMain->cfg.fVerboseExtraTlp) {
vmmprintf(
"devicefile.c!DeviceFile_ReadScatterMEM: READ:\n" \
" file='%s'\n" \
" offset=%016llx req_len=%08x rsp_len=%08x\n",
ctxFile->szFileName,
pMEM->qwA,
pMEM->cbMax,
pMEM->cb
);
Util_PrintHexAscii(pMEM->pb, pMEM->cb, 0);
}
c += (ppMEMs[i]->cb >= ppMEMs[i]->cbMax) ? 1 : 0;
}
if(pcMEMsRead) {
*pcMEMsRead = c;
}
}
VOID DeviceFile_Close()
{
PDEVICE_CONTEXT_FILE ctxFile = (PDEVICE_CONTEXT_FILE)ctxMain->dev.hDevice;
if(!ctxFile) { return; }
fclose(ctxFile->pFile);
LocalFree(ctxFile);
ctxMain->dev.hDevice = 0;
}
BOOL DeviceFile_Open()
{
PDEVICE_CONTEXT_FILE ctxFile;
ctxFile = (PDEVICE_CONTEXT_FILE)LocalAlloc(LMEM_ZEROINIT, sizeof(DEVICE_CONTEXT_FILE));
if(!ctxFile) { return FALSE; }
// open backing file
if(fopen_s(&ctxFile->pFile, ctxMain->cfg.szDevTpOrFileName, "rb") || !ctxFile->pFile) { goto fail; }
if(_fseeki64(ctxFile->pFile, 0, SEEK_END)) { goto fail; } // seek to end of file
ctxFile->cbFile = _ftelli64(ctxFile->pFile); // get current file pointer
if(ctxFile->cbFile < 0x1000) { goto fail; }
ctxFile->szFileName = ctxMain->cfg.szDevTpOrFileName;
ctxMain->dev.hDevice = (HANDLE)ctxFile;
// set callback functions and fix up config
ctxMain->dev.tp = VMM_DEVICE_FILE;
ctxMain->dev.qwMaxSizeMemIo = 0x00100000; // 1MB
ctxMain->dev.paAddrMaxNative = ctxFile->cbFile;
ctxMain->dev.pfnClose = DeviceFile_Close;
ctxMain->dev.pfnReadScatterMEM = DeviceFile_ReadScatterMEM;
vmmprintfv("DEVICE: Successfully opened file: '%s'.\n", ctxMain->cfg.szDevTpOrFileName);
return TRUE;
fail:
if(ctxFile->pFile) { fclose(ctxFile->pFile); }
LocalFree(ctxFile);
printf("DEVICE: ERROR: Failed opening file: '%s'.\n", ctxMain->cfg.szDevTpOrFileName);
return FALSE;
}
-16
View File
@@ -1,16 +0,0 @@
// devicefile.h : definitions related to file backed memory acquisition device.
//
// (c) Ulf Frisk, 2018
// Author: Ulf Frisk, [email protected]
//
#ifndef __DEVICEFILE_H__
#define __DEVICEFILE_H__
#include "vmm.h"
/*
* Open a "connection" to the file.
* -- result
*/
BOOL DeviceFile_Open();
#endif /* __DEVICEFILE_H__ */
-152
View File
@@ -1,152 +0,0 @@
// devicepcileechdll.c : implementation related to PCILeech DLL memory acquisition device.
//
// (c) Ulf Frisk, 2018
// Author: Ulf Frisk, [email protected]
//
#include "devicepcileechdll.h"
#include "pcileech_dll.h"
#include "vmm.h"
typedef struct tdDEVICE_CONTEXT_PCILEECH_DLL {
HMODULE hPCILeechDll;
LPSTR(*PCILeech_GetVersion)();
BOOL(*PCILeech_InitializeInternalReserved)(_In_ DWORD argc, _In_ char* argv[]);
BOOL(*PCILeech_Close)();
BOOL(*PCIleech_DeviceConfigGet)(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue);
BOOL(*PCILeech_DeviceConfigSet)(_In_ ULONG64 fOption, _In_ ULONG64 qwValue);
BOOL(*PCILeech_DeviceWriteMEM)(_In_ ULONG64 qwAddr, _In_ PBYTE pb, _In_ DWORD cb);
DWORD(*PCILeech_DeviceReadScatterMEM)(_Inout_ PPMEM_IO_SCATTER_HEADER ppMEMs, _In_ DWORD cpMEMs);
} DEVICE_CONTEXT_PCILEECH_DLL, *PDEVICE_CONTEXT_PCILEECH_DLL;
BOOL DevicePCILeechDll_WriteMEM(_In_ QWORD qwAddr, _In_ PBYTE pb, _In_ DWORD cb)
{
PDEVICE_CONTEXT_PCILEECH_DLL ctxDll = (PDEVICE_CONTEXT_PCILEECH_DLL)ctxMain->dev.hDevice;
if(!ctxDll) { return FALSE; }
return ctxDll->PCILeech_DeviceWriteMEM(qwAddr, pb, cb);
}
VOID DevicePCILeechDll_ReadScatterMEM(_Inout_ PPMEM_IO_SCATTER_HEADER ppMEMs, _In_ DWORD cpMEMs, _Out_opt_ PDWORD pcMEMsRead)
{
DWORD cMEMsRead;
PDEVICE_CONTEXT_PCILEECH_DLL ctxDll = (PDEVICE_CONTEXT_PCILEECH_DLL)ctxMain->dev.hDevice;
if(!ctxDll) {
if(pcMEMsRead) { *pcMEMsRead = 0; }
return;
}
cMEMsRead = ctxDll->PCILeech_DeviceReadScatterMEM(ppMEMs, cpMEMs);
if(pcMEMsRead) {
*pcMEMsRead = cMEMsRead;
}
}
BOOL DevicePCILeechDll_GetOption(_In_ QWORD fOption, _Out_ PQWORD pqwValue)
{
PDEVICE_CONTEXT_PCILEECH_DLL ctxDll = (PDEVICE_CONTEXT_PCILEECH_DLL)ctxMain->dev.hDevice;
if(!ctxDll) { *pqwValue = 0; return FALSE; }
return ctxDll->PCIleech_DeviceConfigGet(fOption, pqwValue);
}
BOOL DevicePCILeechDll_SetOption(_In_ QWORD fOption, _In_ QWORD qwValue)
{
PDEVICE_CONTEXT_PCILEECH_DLL ctxDll = (PDEVICE_CONTEXT_PCILEECH_DLL)ctxMain->dev.hDevice;
if(!ctxDll) { return FALSE; }
return ctxDll->PCILeech_DeviceConfigSet(fOption, qwValue);
}
VOID DevicePCILeechDll_Close()
{
PDEVICE_CONTEXT_PCILEECH_DLL ctxDll = (PDEVICE_CONTEXT_PCILEECH_DLL)ctxMain->dev.hDevice;
if(!ctxDll) { return; }
ctxDll->PCILeech_Close();
FreeLibrary(ctxDll->hPCILeechDll);
LocalFree(ctxDll);
ZeroMemory(&ctxMain->dev, sizeof(ctxMain->dev));
}
BOOL DevicePCILeechDll_Open()
{
BOOL result;
DWORD cDllParams = 0;
LPSTR szDllVersion, szDllParams[0x10];
PDEVICE_CONTEXT_PCILEECH_DLL ctxDll;
ctxDll = (PDEVICE_CONTEXT_PCILEECH_DLL)LocalAlloc(LMEM_ZEROINIT, sizeof(DEVICE_CONTEXT_PCILEECH_DLL));
if(!ctxDll) { return FALSE; }
// Load PCILeech DLL
ctxDll->hPCILeechDll = LoadLibraryA("pcileech.dll");
if(!ctxDll->hPCILeechDll) {
vmmprintf("DEVICE: ERROR: Failed loading pcileech.dll - not found!\n");
goto fail;
}
// Retrieve version number
ctxDll->PCILeech_GetVersion = (LPSTR(*)())GetProcAddress(ctxDll->hPCILeechDll, "PCILeech_GetVersion");
if(!ctxDll->PCILeech_GetVersion) {
vmmprintf("DEVICE: ERROR: Failed loading pcileech.dll - version number inaccessible!\n");
goto fail;
}
szDllVersion = ctxDll->PCILeech_GetVersion();
if(strncmp(szDllVersion, "3.", 2)) { // major version = 3 required (exactly)
vmmprintf("DEVICE: ERROR: Failed loading pcileech.dll - version number (major) mismatch!\n");
vmmprintf(" Please ensure most recent version of memprocfs.exe and pcileech.dll\n");
goto fail;
}
if(atoi(szDllVersion + 2) < 6) { // minor version = 6 required (at minimum)
vmmprintf("DEVICE: ERROR: Failed loading pcileech.dll - version number (minor) mismatch!\n");
vmmprintf(" Please ensure most recent version of memprocfs.exe and pcileech.dll\n");
goto fail;
}
// Load required functions
ctxDll->PCILeech_InitializeInternalReserved = (BOOL(*)(DWORD,char**))GetProcAddress(ctxDll->hPCILeechDll, "PCILeech_InitializeInternalReserved");
ctxDll->PCILeech_Close = (BOOL(*)())GetProcAddress(ctxDll->hPCILeechDll, "PCILeech_Close");
ctxDll->PCIleech_DeviceConfigGet = (BOOL(*)(ULONG64, PULONG64))GetProcAddress(ctxDll->hPCILeechDll, "PCIleech_DeviceConfigGet");
ctxDll->PCILeech_DeviceConfigSet = (BOOL(*)(ULONG64, ULONG64))GetProcAddress(ctxDll->hPCILeechDll, "PCILeech_DeviceConfigSet");
ctxDll->PCILeech_DeviceWriteMEM = (BOOL(*)(ULONG64, PBYTE, DWORD))GetProcAddress(ctxDll->hPCILeechDll, "PCILeech_DeviceWriteMEM");
ctxDll->PCILeech_DeviceReadScatterMEM = (DWORD(*)(PPMEM_IO_SCATTER_HEADER, DWORD))GetProcAddress(ctxDll->hPCILeechDll, "PCILeech_DeviceReadScatterMEM");
if(!(ctxDll->PCILeech_InitializeInternalReserved && ctxDll->PCILeech_Close && ctxDll->PCIleech_DeviceConfigGet &&
ctxDll->PCILeech_DeviceConfigSet && ctxDll->PCILeech_DeviceWriteMEM && ctxDll->PCILeech_DeviceReadScatterMEM))
{
vmmprintf("DEVICE: ERROR: Failed loading pcileech.dll - missing function(s)!\n");
goto fail;
}
// Initialize DLL: 1 - enable dll printf
ctxDll->PCILeech_DeviceConfigSet(PCILEECH_DEVICE_CORE_PRINTF_ENABLE, ctxMain->cfg.fVerboseDll ? 1 : 0);
// Initialize DLL: 2 - initialize context
szDllParams[cDllParams++] = "";
szDllParams[cDllParams++] = "dll_library_use";
if(ctxMain->cfg.fVerbose) { szDllParams[cDllParams++] = "-v"; }
if(ctxMain->cfg.fVerboseExtra) { szDllParams[cDllParams++] = "-vv"; }
if(ctxMain->cfg.fVerboseExtraTlp) { szDllParams[cDllParams++] = "-vvv"; }
szDllParams[cDllParams++] = "-device";
szDllParams[cDllParams++] = ctxMain->cfg.szDevTpOrFileName;
if(!ctxDll->PCILeech_InitializeInternalReserved(cDllParams, szDllParams)) {
vmmprintf("DEVICE: ERROR: Failed initializing pcileech.dll!PCILeech_InitializeInternalReserved\n");
goto fail;
}
// Initialize DLL: 3 - get max address and io size
result = ctxDll->PCIleech_DeviceConfigGet(PCILEECH_DEVICE_CORE_MAX_NATIVE_ADDRESS, &ctxMain->dev.paAddrMaxNative);
if(!result || (ctxMain->dev.paAddrMaxNative <= 0x00100000)) {
vmmprintf("DEVICE: ERROR: Failed initializing pcileech.dll - max physical memory too low - %016llx\n", ctxMain->dev.paAddrMaxNative);
goto fail;
}
result = ctxDll->PCIleech_DeviceConfigGet(PCILEECH_DEVICE_CORE_MAX_NATIVE_IOSIZE, &ctxMain->dev.qwMaxSizeMemIo);
if(!result || (ctxMain->dev.qwMaxSizeMemIo < 0x1000)) {
vmmprintf("DEVICE: ERROR: Failed initializing pcileech.dll - max iosize too low - %016llx\n", ctxMain->dev.qwMaxSizeMemIo);
goto fail;
}
// set callback functions and fix up config
ctxMain->dev.hDevice = (HANDLE)ctxDll;
ctxMain->dev.tp = VMM_DEVICE_PCILEECH_DLL;
ctxMain->dev.pfnClose = DevicePCILeechDll_Close;
ctxMain->dev.pfnGetOption = DevicePCILeechDll_GetOption;
ctxMain->dev.pfnSetOption = DevicePCILeechDll_SetOption;
ctxMain->dev.pfnWriteMEM = DevicePCILeechDll_WriteMEM;
ctxMain->dev.pfnReadScatterMEM = DevicePCILeechDll_ReadScatterMEM;
vmmprintfv("DEVICE: Successfully opened pcileech.dll\n");
return TRUE;
fail:
if(ctxDll->hPCILeechDll) { FreeLibrary(ctxDll->hPCILeechDll); }
LocalFree(ctxDll);
ZeroMemory(&ctxMain->dev, sizeof(ctxMain->dev));
return FALSE;
}
-16
View File
@@ -1,16 +0,0 @@
// devicepcileechdll.h : definitions related to PCILeech DLL memory acquisition device.
//
// (c) Ulf Frisk, 2018
// Author: Ulf Frisk, [email protected]
//
#ifndef __DEVICEPCILEECHDLL_H__
#define __DEVICEPCILEECHDLL_H__
#include "vmm.h"
/*
* Open a "connection" to the PCILeech DLL.
* -- result
*/
BOOL DevicePCILeechDll_Open();
#endif /* __DEVICEPCILEECHDLL_H__ */
+466
View File
@@ -0,0 +1,466 @@
// leechcore.h : header file for the leechcore module - which purpose is to
// expose low-level device physical memory functionality.
//
// This library is thread-safe in all functions with the notable exceptions of
// the LeechCore_Open() and LeechCore_Close() functions. Some devices may allow
// multi-threaded access while in reality most devices are single-threaded and
// will control synchronization where necessary with locks.
//
// The library is initialized by calling LeechCore_Open with a LEECHCORE_CONFIG
// struct containing the correct configuration paramters. Note that the version
// and magic values must be set in addition to the szDevice configuration value
// Also, it may be possible to optionally connect to a remote leechcore service
// or instance over RPC by specifying a szRemote configuration value.
//
// ----------------------------------------------------------------------------
//
// Remote instance: szRemote configuration value. Connect to a remote leechcore
// instance by specifying a configuration value in the szRemote parameter. If a
// loaded already valid instance exists remotely this will be prioritized above
// the value in szDevice. If the acquisition device is not yet loaded by the
// remote instance the value in szDevice will be used. Normally, the connection
// will take place as a mutually authenticated encrypted connection secured by
// kerberos. If not possible or desirable the 'insecure' value may be specified
// to disable authentication and security.
// Syntax:
// rpc://<remote_spn>:<host>:<port> (port = optional, remote_spn = kerberos)
// (SPN of remote service or 'insecure' )
// Examples:
// rpc://insecure:remotehost.example.com (connect insecure to remote host )
// rpc://[email protected]:192.0.0.5 (connect secure to remote host )
// rpc://insecure:127.0.0.0:6666 (connect insecure non-default port)
//
// ----------------------------------------------------------------------------
//
// Device to connect to: szDevice contains the device to capture memory from.
// Supported memory acquisition devices are:
// USB3380 : hardware, read/write, 32-bit (4GB) addressing only. Requires a
// PCILeech flashed USB3380 device connected over USB and Google
// Android WinUSB drivers to be installed. Download and install from:
// http://developer.android.com/sdk/win-usb.html#download
// Syntax:
// USB3380
// USB3380://USB2 (force USB2 connection speed)
//
// FPGA : hardware, read/write - requires a PCILeech FPGA flashed hardware
// device as shown at: https://github.com/ufrisk/pcileech-fpga
// Also requires the FTD3XX.DLL from ftdichip to be placed in the
// same directory as the executable. Download from ftdichip at:
// http://www.ftdichip.com/Drivers/D3XX/FTD3XXLibrary_v1.2.0.6.zip
// Syntax:
// FGPA
// FPGA://<read_uS>[:<write_uS>[:<probe_uS>]] (values are optional)
//
// SP605TCP : hardware, read/write - connect to a remote SP605 FPGA over the
// network using the implementation created by @d_olex.
// https://github.com/Cr4sh/s6_pcie_microblaze
// Syntax:
// SP605TCP://<target_ip>[:<target_port>] (port is optional)
//
// RAWTCP : read/write - connect to a remote raw tcp device - such as HPE iLO
// that have been patched to support DMA as per blog entry below:
// https://www.synacktiv.com/posts/exploit/using-your-bmc-as-a-dma-device-plugging-pcileech-to-hpe-ilo-4.html
// Syntax:
// RAWTCP://<target_ip>[:<target_port>] (port is optional)
//
// HvSavedState : read-only - connect to a Hyper-V saved state file. In order
// to do so the .dll file 'vmsavedstatedumpprovider.dll' must be
// placed in same directory as the executable file.
//
// PMEM : load the rekall winpmem driver into the kernel and connect to it
// to acquire memory. The driver file 'winpmem_x64.sys' is found in
// the Rekall directory after most recent version has been installed.
// Copy 'winpmem_x64.sys' to the directory of leechcore.dll and run
// executable as elevated admin using syntax below:
// Syntax:
// PMEM (use winpmem_x64.sys in directory of executable)
// PMEM://<non_default_path_to_file_winpmem_x64.sys>
//
// TOTALMELTDOWN : read/write - requires a Windows 7 system vulnerable to the
// "Total Meltdown" vulnerability - CVE-2018-1038.
// Syntax:
// TOTALMELTDOWN
//
// FILE : use dump file, either a raw linear memory dump or full crash dump.
// Which format to use is auto-detected. If it looks like a full cash
// dump that format will be used, otherwise it will be assumed that a
// raw linear memory dump is to be used.
// Syntax:
// <filename> (no device-type prefix - just use the file name)
// FILE://<filename>
//
// DumpIt : DumpIt is a "virtual" device. It's only possible to use the DumpIt
// device if the main process containing LeechCore has been started
// with DumpIt in LiveKD mode.
// Example 1:
// DumpIt.exe /LIVEKD /A MemProcFS.exe
// Example 2:
// DumpIt.exe /LIVEKD /A LeechSvc.exe /C "interactive insecure"
// and then connect to remote service by:
// MemProcFS.exe -remote rpc://insecure:192.168.x.x -device DumpIt
//
// EXISTING : Attach to existing already loaded configuration. This is done
// instead of the default behaviour of closing any existing devices
// and initializing the new requested device. If no existing device
// exists the call to LeechCore_Open will fail.
// Syntax:
// EXISTING
//
//
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
// Header Version: 1.0
//
#ifndef __LEECHCORE_H__
#define __LEECHCORE_H__
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
//-----------------------------------------------------------------------------
// WINDOWS / LINUX COMPATIBILITY BELOW:
//-----------------------------------------------------------------------------
#ifdef _WIN32
#include <Windows.h>
typedef unsigned __int64 QWORD, *PQWORD;
#define DLLEXPORT __declspec(dllexport)
#endif /* _WIN32 */
#ifdef LINUX
#include <stdint.h>
#include <stddef.h>
typedef void VOID, *PVOID, *LPVOID;
typedef void *HANDLE, **PHANDLE;
typedef uint32_t BOOL, *PBOOL;
typedef uint8_t BYTE, *PBYTE;
typedef char CHAR, *PCHAR, *PSTR, *LPSTR;
typedef uint16_t WORD, *PWORD, USHORT, *PUSHORT;
typedef uint32_t DWORD, *PDWORD;
typedef long long unsigned int QWORD, *PQWORD, ULONG64, *PULONG64;
#define MAX_PATH 260
#define DLLEXPORT __attribute__((visibility("default")))
#define _In_
#define _Out_
#define _In_z_
#define _Inout_
#define _In_opt_
#define _Out_opt_
#define _Out_writes_(x)
#define _Check_return_opt_
#define _Printf_format_string_
#define _Inout_updates_bytes_(x)
#define _In_reads_(cbDataIn)
#define _Success_(return)
#endif /* LINUX */
//-----------------------------------------------------------------------------
// GENERAL HEADER DEFINES BELOW:
//-----------------------------------------------------------------------------
#define MEM_IO_SCATTER_HEADER_MAGIC 0xffff6548
#define MEM_IO_SCATTER_HEADER_VERSION 0x0003
typedef struct tdMEM_IO_SCATTER_HEADER {
DWORD magic; // magic
WORD version; // version
WORD Future1;
ULONG64 qwA; // base address.
DWORD cbMax; // bytes to read (DWORD boundry, max 0x1000); pb must have room for this.
DWORD cb; // bytes read into result buffer.
PBYTE pb; // ptr to 0x1000 sized buffer to receive read bytes.
PVOID pvReserved1; // reserved for use by caller.
PVOID pvReserved2; // reserved for use by caller.
PVOID Future2[8];
} MEM_IO_SCATTER_HEADER, *PMEM_IO_SCATTER_HEADER, **PPMEM_IO_SCATTER_HEADER;
//-----------------------------------------------------------------------------
// LEECHCORE INITIALIZATION / CLOSE FUNCTIONALITY BELOW:
//-----------------------------------------------------------------------------
typedef enum tdLEECHCORE_DEVICE {
LEECHCORE_DEVICE_NA = 0,
LEECHCORE_DEVICE_FILE = 1,
LEECHCORE_DEVICE_PMEM = 2,
LEECHCORE_DEVICE_FPGA = 3,
LEECHCORE_DEVICE_SP605_TCP = 4,
LEECHCORE_DEVICE_USB3380 = 5,
LEECHCORE_DEVICE_TOTALMELTDOWN = 6,
LEECHCORE_DEVICE_HVSAVEDSTATE = 7,
LEECHCORE_DEVICE_RAWTCP = 8,
} LEECHCORE_DEVICE;
#define LEECHCORE_CONFIG_MAGIC 0xffff6549
#define LEECHCORE_CONFIG_VERSION 0x0001
#define LEECHCORE_CONFIG_FLAG_PRINTF 0x0001
#define LEECHCORE_CONFIG_FLAG_PRINTF_VERBOSE_1 0x0002
#define LEECHCORE_CONFIG_FLAG_PRINTF_VERBOSE_2 0x0004
#define LEECHCORE_CONFIG_FLAG_PRINTF_VERBOSE_3 0x0008
#define LEECHCORE_CONFIG_FLAG_REMOTE_NO_COMPRESS 0x0010
typedef struct tdLEECHCORE_CONFIG {
DWORD magic; // set by caller.
WORD version; // set by caller.
WORD flags; // set by caller, updated by device.
ULONG64 paMax; // set by caller, updated by device.
ULONG64 cbMaxSizeMemIo; // set by caller, updated by device.
ULONG64 paMaxNative; // set by device.
LEECHCORE_DEVICE tpDevice; // set by device.
BOOL fWritable; // set by device. (is device writable?)
BOOL fVolatile; // set by device. (is device volatile / memory may change?)
BOOL fVolatileMaxAddress; // set by device. (is max address volatile? - poll changes with LEECHCORE_OPT_MEMORYINFO_ADDR_MAX)
BOOL fRemote; // set by device.
WORD VersionMajor; // set by device.
WORD VersionMinor; // set by device.
WORD VersionRevision; // set by device.
CHAR szDevice[MAX_PATH]; // set by caller.
CHAR szRemote[MAX_PATH]; // set by caller.
// optional 'printf' function pointer. if set to non null value 'printf'
// calls will be redirected. useful when logging to files.
_Check_return_opt_ int(*pfn_printf_opt)(_In_z_ _Printf_format_string_ char const* const _Format, ...); // set by caller.
} LEECHCORE_CONFIG, *PLEECHCORE_CONFIG;
typedef struct tdLEECHCORE_PAGESTAT_MINIMAL {
HANDLE h;
VOID(*pfnPageStatUpdate)(HANDLE h, ULONG64 pa, ULONG64 cPageSuccessAdd, ULONG64 cPageFailAdd);
} LEECHCORE_PAGESTAT_MINIMAL, *PLEECHCORE_PAGESTAT_MINIMAL;
/*
* Open a connection to the target device.
* -- pInformation
* -- result
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_Open(_Inout_ PLEECHCORE_CONFIG pConfig);
/*
* Clean up various device related stuff and deallocate memory buffers.
*/
DLLEXPORT VOID LeechCore_Close();
//-----------------------------------------------------------------------------
// LEECHCORE CORE READ AND WRITE FUNCTIONALITY BELOW:
//-----------------------------------------------------------------------------
#define LEECHCORE_FLAG_READ_RETRY 0x01
#define LEECHCORE_FLAG_WRITE_RETRY 0x01
#define LEECHCORE_FLAG_WRITE_VERIFY 0x02
/*
* Allocate a scatter buffer containing empty 0x1000-sized ppMEMs with address
* set to zero. Caller is responsible for calling LocalFree(ppMEMs).
* -- cMEMs
* -- pppMEMs = pointer to receive ppMEMs on success.
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_AllocScatterEmpty(_In_ DWORD cMEMs, _Out_ PPMEM_IO_SCATTER_HEADER *pppMEMs);
/*
* Read memory in various non-contigious locations specified by the items in the
* phDMAs array. Result for each unit of work will be given individually. No upper
* limit of number of items to read, but no performance boost will be given if
* above hardware limit. Max size of each unit of work is one 4k page (4096 bytes).
* -- ppMEMs = array of scatter read headers.
* -- cpMEMs = count of ppDMAs.
*/
DLLEXPORT VOID LeechCore_ReadScatter(_Inout_ PPMEM_IO_SCATTER_HEADER ppMEMs, _In_ DWORD cpMEMs);
/*
* Try read memory in a fairly optimal way considering device limits. The number
* of total successfully read bytes is returned. Failed reads will be zeroed out
* in the returned memory.
* -- pa
* -- pb
* -- cb
* -- return = the number of bytes successfully read.
*/
DLLEXPORT DWORD LeechCore_Read(_In_ ULONG64 pa, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb);
/*
* Try read memory in a fairly optimal way considering device limits. The number
* of total successfully read bytes is returned. Failed reads will be zeroed out
* in the returned memory.
* -- pa
* -- pb
* -- cb
* -- flags = 0 or LEECHCORE_FLAG_READ_RETRY
* -- pPageStat = optional minimal statistic struct to update.
* -- return = the number of bytes successfully read.
*/
DLLEXPORT DWORD LeechCore_ReadEx(_In_ ULONG64 pa, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _In_ DWORD flags, _In_opt_ PLEECHCORE_PAGESTAT_MINIMAL pPageStat);
/*
* Write data to the target system if supported by the device.
* -- pa
* -- pb
* -- cb
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_Write(_In_ ULONG64 pa, _In_ PBYTE pb, _In_ DWORD cb);
/*
* Write data to the target system if supported by the device.
* -- pa
* -- pb
* -- cb
* -- flags = 0 or LEECHCORE_FLAG_WRITE_*
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_WriteEx(_In_ ULONG64 pa, _In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD flags);
/*
* Probe the memory of the target system to check whether it's readable or not.
* Please note that not all devices support this natively.
* -- pa = address to start probe from.
* -- cPages = number of 4kB pages to probe.
* -- pbResultMap = result map, 1 byte represents 1 page, 0 = fail, 1 = success.
* (individual page elements in pbResultMap must be set to 0 [fail] on call
* for probe to take place on individual page).
* -- return = FALSE if not supported by underlying hardware, TRUE if supported.
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_Probe(_In_ QWORD pa, _In_ DWORD cPages, _Inout_updates_bytes_(cPages) PBYTE pbResultMap);
//-----------------------------------------------------------------------------
// GET/SET DEVICE OPTIONS BELOW. SOME OPTIONS ARE GENERAL LEECHCORE OPTIONS
// WHILE OTHER ARE DEVICE SPECIFIC. USE FUNCTIONS:
// LeechCore_GetOption() AND LeechCore_GetOption() TO GET/SET OPTIONS.
// FOR DEVICE-SPECIFIC OPTIONS PLEASE SEE INDIVIDUAL DEVICE FILES FOR MORE
// DETAILED INFORMATION.
//-----------------------------------------------------------------------------
#define LEECHCORE_OPT_CORE_PRINTF_ENABLE 0x80000001 // RW
#define LEECHCORE_OPT_CORE_VERBOSE 0x80000002 // RW
#define LEECHCORE_OPT_CORE_VERBOSE_EXTRA 0x80000003 // RW
#define LEECHCORE_OPT_CORE_VERBOSE_EXTRA_TLP 0x80000004 // RW
#define LEECHCORE_OPT_CORE_VERSION_MAJOR 0x01000001 // R
#define LEECHCORE_OPT_CORE_VERSION_MINOR 0x01000002 // R
#define LEECHCORE_OPT_CORE_VERSION_REVISION 0x01000003 // R
#define LEECHCORE_OPT_MEMORYINFO_VALID 0x02000001 // R
#define LEECHCORE_OPT_MEMORYINFO_ADDR_MAX 0x02000002 // R
#define LEECHCORE_OPT_MEMORYINFO_FLAG_32BIT 0x02000003 // R
#define LEECHCORE_OPT_MEMORYINFO_FLAG_PAE 0x02000004 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_VERSION_MINOR 0x02000005 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_VERSION_MAJOR 0x02000006 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_DTB 0x02000007 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_PFN 0x02000008 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_PsLoadedModuleList 0x02000009 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_PsActiveProcessHead 0x0200000a // R
#define LEECHCORE_OPT_MEMORYINFO_OS_MACHINE_IMAGE_TP 0x0200000b // R
#define LEECHCORE_OPT_MEMORYINFO_OS_NUM_PROCESSORS 0x0200000c // R
#define LEECHCORE_OPT_MEMORYINFO_OS_SYSTEMTIME 0x0200000d // R
#define LEECHCORE_OPT_MEMORYINFO_OS_UPTIME 0x0200000e // R
#define LEECHCORE_OPT_MEMORYINFO_OS_KERNELBASE 0x0200000f // R
#define LEECHCORE_OPT_MEMORYINFO_OS_KERNELHINT 0x02000010 // R
#define LEECHCORE_OPT_FPGA_PROBE_MAXPAGES 0x03000001 // RW
#define LEECHCORE_OPT_FPGA_RX_FLUSH_LIMIT 0x03000002 // RW
#define LEECHCORE_OPT_FPGA_MAX_SIZE_RX 0x03000003 // RW
#define LEECHCORE_OPT_FPGA_MAX_SIZE_TX 0x03000004 // RW
#define LEECHCORE_OPT_FPGA_DELAY_PROBE_READ 0x03000005 // RW - uS
#define LEECHCORE_OPT_FPGA_DELAY_PROBE_WRITE 0x03000006 // RW - uS
#define LEECHCORE_OPT_FPGA_DELAY_WRITE 0x03000007 // RW - uS
#define LEECHCORE_OPT_FPGA_DELAY_READ 0x03000008 // RW - uS
#define LEECHCORE_OPT_FPGA_RETRY_ON_ERROR 0x03000009 // RW
#define LEECHCORE_OPT_FPGA_DEVICE_ID 0x03000080 // R
#define LEECHCORE_OPT_FPGA_FPGA_ID 0x03000081 // R
#define LEECHCORE_OPT_FPGA_VERSION_MAJOR 0x03000082 // R
#define LEECHCORE_OPT_FPGA_VERSION_MINOR 0x03000083 // R
/*
* Set a device specific option value.
* -- fOption
* -- pqwValue = pointer to QWORD to receive option value.
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_GetOption(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue);
/*
* Set a device specific option value.
* -- fOption
* -- qwValue
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_SetOption(_In_ ULONG64 fOption, _In_ ULONG64 qwValue);
//-----------------------------------------------------------------------------
// TRANSFER DEVICE DEPENDANT COMMANDS OR DATA TO/FROM UNDERLYING DEVICES AND
// PERFORM ACTIONS USING THE LeechCore_CommandData() FUNCTION.
//-----------------------------------------------------------------------------
#define LEECHCORE_COMMANDDATA_FPGA_WRITE_TLP 0x00000101 // R
#define LEECHCORE_COMMANDDATA_FPGA_LISTEN_TLP 0x00000102 // R
#define LEECHCORE_COMMANDDATA_STATISTICS_GET 0x80000100 // R
#define LEECHCORE_STATISTICS_MAGIC 0xffff6550
#define LEECHCORE_STATISTICS_VERSION 0x0001
#define LEECHCORE_STATISTICS_ID_OPEN 0x00
#define LEECHCORE_STATISTICS_ID_READSCATTER 0x01
#define LEECHCORE_STATISTICS_ID_WRITE 0x02
#define LEECHCORE_STATISTICS_ID_PROBE 0x03
#define LEECHCORE_STATISTICS_ID_GETOPTION 0x04
#define LEECHCORE_STATISTICS_ID_SETOPTION 0x05
#define LEECHCORE_STATISTICS_ID_COMMANDDATA 0x06
#define LEECHCORE_STATISTICS_ID_MAX 0x06
static const LPSTR LEECHCORE_STATISTICS_NAME[] = {
"LeechCore_Open",
"LeechCore_ReadScatter",
"LeechCore_Write",
"LeechCore_Probe",
"LeechCore_GetOption",
"LeechCore_SetOption",
"LeechCore_CommandData"
};
typedef struct tdLEECHCORE_STATISTICS {
DWORD magic;
WORD version;
WORD Reserved0;
DWORD Reserved1;
QWORD qwFreq;
struct {
QWORD c;
QWORD tm; // total time in qwFreq ticks
} Call[0x10];
} LEECHCORE_STATISTICS, *PLEECHCORE_STATISTICS;
/*
* Transfer device dependant commands/data to/from the underlying device and
* perform device dependant actions.
* -- fOption
* -- cbDataIn
* -- pbDataIn
* -- pbDataOut
* -- cbDataOut
* -- pcbDataOut
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_CommandData(
_In_ ULONG64 fOption,
_In_reads_(cbDataIn) PBYTE pbDataIn,
_In_ DWORD cbDataIn,
_Out_writes_(cbDataOut) PBYTE pbDataOut,
_In_ DWORD cbDataOut,
_Out_ PDWORD pcbDataOut
);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __LEECHCORE_H__ */
+150 -142
View File
@@ -1,11 +1,12 @@
// m_ldrmodules.c : implementation of the ldrmodules built-in module.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
#include "m_ldrmodules.h"
#include "pluginmanager.h"
#include "vmm.h"
#include "vmmproc.h"
#include "vmmwin.h"
#include "vmmvfs.h"
#include "util.h"
@@ -14,71 +15,37 @@
#define LDRMODULES_CACHE_TP_EAT 1
#define LDRMODULES_CACHE_TP_IAT 2
#define LDRMODULES_NUM_CACHE 8
typedef struct tdLDRMODULES_CACHE_ENTRY {
DWORD dwCounter;
DWORD dwPID;
CHAR szDll[MAX_PATH];
typedef struct tdOBLDRMODULES_CACHE_ENTRY {
VMMOB ObHdr;
CHAR szDll[32];
DWORD tp;
DWORD cb;
PBYTE pb;
} LDRMODULES_CACHE_ENTRY, *PLDRMODULES_CACHE_ENTRY;
BYTE pb[];
} OBLDRMODULES_CACHE_ENTRY, *POBLDRMODULES_CACHE_ENTRY;
/*
* CloseHandleModule : function as specified by the module manager. The module
* manager will call into this callback function whenever the module should be
* unloaded. Any private handle stored in phModulePrivate should be deallocated.
* -- phModulePrivate
*/
VOID LdrModule_CloseHandleModule(_Inout_opt_ PHANDLE phModulePrivate)
{
DWORD i;
PLDRMODULES_CACHE_ENTRY pCache;
if(!phModulePrivate || !*phModulePrivate) { return; }
pCache = (PLDRMODULES_CACHE_ENTRY)*phModulePrivate;
for(i = 0; i < LDRMODULES_NUM_CACHE; i++) {
LocalFree(pCache[i].pb);
}
LocalFree(pCache);
*phModulePrivate = NULL;
}
PLDRMODULES_CACHE_ENTRY LdrModule_GetCacheEntry(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ LPSTR szDll, _In_ DWORD tp)
{
DWORD i, iMin = 0, iMax = 0, iEmpty = (DWORD)-1;
PLDRMODULES_CACHE_ENTRY e, pCache;
pCache = (PLDRMODULES_CACHE_ENTRY)*ctx->phModulePrivate;
// find existing cached item
for(i = 0; i < LDRMODULES_NUM_CACHE; i++) {
e = pCache + i;
if((e->dwPID == ctx->dwPID) && (e->tp == tp) && e->pb && !strcmp(e->szDll, szDll)) {
return e;
}
if(e->dwCounter < pCache[iMin].dwCounter) { iMin = i; }
if(e->dwCounter > pCache[iMax].dwCounter) { iMax = i; }
if(!e->pb) { iEmpty = i; }
}
// reserve and prepare new item
i = (iEmpty < LDRMODULES_NUM_CACHE) ? iEmpty : iMin;
e = pCache + i;
LocalFree(e->pb);
ZeroMemory(e, sizeof(LDRMODULES_CACHE_ENTRY));
e->dwCounter = pCache[iMax].dwCounter + 1;
e->dwPID = ctx->dwPID;
e->tp = tp;
strncpy_s(e->szDll, MAX_PATH, szDll, MAX_PATH);
return e;
}
#define LDRMODULES_MAX_IATEAT 0x10000
PLDRMODULES_CACHE_ENTRY LdrModule_GetEAT(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ PVMM_MODULEMAP_ENTRY pModule)
/*
* Retrieve a OBLDRMODULES_CACHE_ENTRY object for the Export Address Table (EAT).
* CALLER DECREF: return
* -- ctx
* -- pModule
* -- return
*/
POBLDRMODULES_CACHE_ENTRY LdrModule_GetEAT(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ PVMM_MODULEMAP_ENTRY pModule)
{
DWORD i, o, cEATs;
PVMMPROC_WINDOWS_EAT_ENTRY pEATs = NULL;
PLDRMODULES_CACHE_ENTRY pCacheEntry;
POBLDRMODULES_CACHE_ENTRY pObCacheEntry = NULL;
PVMM_PROCESS pProcess = (PVMM_PROCESS)ctx->pProcess;
// 1: retrieve cache
pCacheEntry = LdrModule_GetCacheEntry(ctx, pModule->szName, LDRMODULES_CACHE_TP_EAT);
if(pCacheEntry->pb) { return pCacheEntry; }
pObCacheEntry = VmmObContainer_GetOb(&pProcess->Plugin.ObCLdrModulesDisplayCache);
if(pObCacheEntry && (pObCacheEntry->tp == LDRMODULES_CACHE_TP_EAT) && !_strnicmp(pObCacheEntry->szDll, pModule->szName, 32)) {
return pObCacheEntry;
}
VmmOb_DECREF(pObCacheEntry);
pObCacheEntry = NULL;
// 2: retrieve exported functions
cEATs = LDRMODULES_MAX_IATEAT;
pEATs = LocalAlloc(0, LDRMODULES_MAX_IATEAT * sizeof(VMMPROC_WINDOWS_EAT_ENTRY));
@@ -86,35 +53,51 @@ PLDRMODULES_CACHE_ENTRY LdrModule_GetEAT(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ P
VmmWin_PE_LoadEAT_DisplayBuffer(ctx->pProcess, pModule, pEATs, &cEATs);
if(!cEATs) { goto fail; }
// 3: fill "display buffer"
pCacheEntry->cb = cEATs * 64 + 1;
pCacheEntry->pb = LocalAlloc(0, pCacheEntry->cb);
if(!pCacheEntry->pb) { goto fail; }
pObCacheEntry = VmmOb_Alloc('EA', LMEM_ZEROINIT, sizeof(OBLDRMODULES_CACHE_ENTRY) + (QWORD)cEATs * 64 + 1, NULL, NULL);
if(!pObCacheEntry) { goto fail; }
pObCacheEntry->tp = LDRMODULES_CACHE_TP_EAT;
pObCacheEntry->cb = cEATs * 64 + 1;
memcpy(pObCacheEntry->szDll, pModule->szName, 32);
for(i = 0, o = 0; i < cEATs; i++) {
o += snprintf(
pCacheEntry->pb + o,
pCacheEntry->cb - o,
pObCacheEntry->pb + o,
pObCacheEntry->cb - o,
"%04x %016llx %-40.40s \n", // 64 bytes (chars) / line (function)
(WORD)i,
pModule->BaseAddress + pEATs[i].vaFunctionOffset,
pEATs[i].szFunction
);
}
pCacheEntry->cb = o;
pObCacheEntry->cb = o;
LocalFree(pEATs);
return pCacheEntry;
VmmObContainer_SetOb(&pProcess->Plugin.ObCLdrModulesDisplayCache, pObCacheEntry);
return pObCacheEntry;
fail:
VmmOb_DECREF(pObCacheEntry);
LocalFree(pEATs);
return NULL;
}
PLDRMODULES_CACHE_ENTRY LdrModule_GetIAT(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ PVMM_MODULEMAP_ENTRY pModule)
/*
* Retrieve a OBLDRMODULES_CACHE_ENTRY object for the Import Address Table (IAT).
* CALLER DECREF: return
* -- ctx
* -- pModule
* -- return
*/
POBLDRMODULES_CACHE_ENTRY LdrModule_GetIAT(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ PVMM_MODULEMAP_ENTRY pModule)
{
DWORD i, o, cIATs;
PVMMWIN_IAT_ENTRY pIATs = NULL;
PLDRMODULES_CACHE_ENTRY pCacheEntry;
POBLDRMODULES_CACHE_ENTRY pObCacheEntry = NULL;
PVMM_PROCESS pProcess = (PVMM_PROCESS)ctx->pProcess;
// 1: retrieve cache
pCacheEntry = LdrModule_GetCacheEntry(ctx, pModule->szName, LDRMODULES_CACHE_TP_IAT);
if(pCacheEntry->pb) { return pCacheEntry; }
pObCacheEntry = VmmObContainer_GetOb(&pProcess->Plugin.ObCLdrModulesDisplayCache);
if(pObCacheEntry && (pObCacheEntry->tp == LDRMODULES_CACHE_TP_IAT) && !_strnicmp(pObCacheEntry->szDll, pModule->szName, 32)) {
return pObCacheEntry;
}
VmmOb_DECREF(pObCacheEntry);
pObCacheEntry = NULL;
// 2: retrieve exported functions
cIATs = LDRMODULES_MAX_IATEAT;
pIATs = LocalAlloc(0, LDRMODULES_MAX_IATEAT * sizeof(VMMWIN_IAT_ENTRY));
@@ -122,13 +105,15 @@ PLDRMODULES_CACHE_ENTRY LdrModule_GetIAT(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ P
VmmWin_PE_LoadIAT_DisplayBuffer(ctx->pProcess, pModule, pIATs, &cIATs);
if(!cIATs) { goto fail; }
// 3: fill "display buffer"
pCacheEntry->cb = cIATs * 128 + 1;
pCacheEntry->pb = LocalAlloc(0, pCacheEntry->cb);
if(!pCacheEntry->pb) { goto fail; }
pObCacheEntry = VmmOb_Alloc('IA', LMEM_ZEROINIT, sizeof(OBLDRMODULES_CACHE_ENTRY) + (QWORD)cIATs * 128 + 1, NULL, NULL);
if(!pObCacheEntry) { goto fail; }
pObCacheEntry->tp = LDRMODULES_CACHE_TP_IAT;
pObCacheEntry->cb = cIATs * 128 + 1;
memcpy(pObCacheEntry->szDll, pModule->szName, 32);
for(i = 0, o = 0; i < cIATs; i++) {
o += snprintf(
pCacheEntry->pb + o,
pCacheEntry->cb - o,
pObCacheEntry->pb + o,
pObCacheEntry->cb - o,
"%04x %016llx %-40.40s %-64.64s\n", // 128 bytes (chars) / line (function)
(WORD)i,
pIATs[i].vaFunction,
@@ -136,10 +121,12 @@ PLDRMODULES_CACHE_ENTRY LdrModule_GetIAT(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ P
pIATs[i].szModule
);
}
pCacheEntry->cb = o;
pObCacheEntry->cb = o;
LocalFree(pIATs);
return pCacheEntry;
VmmObContainer_SetOb(&pProcess->Plugin.ObCLdrModulesDisplayCache, pObCacheEntry);
return pObCacheEntry;
fail:
VmmOb_DECREF(pObCacheEntry);
LocalFree(pIATs);
return NULL;
}
@@ -195,21 +182,23 @@ NTSTATUS LdrModules_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_
DWORD i;
CHAR _szBuf[MAX_PATH] = { 0 };
LPSTR szPath1, szPath2;
PVMMOB_MODULEMAP pObModuleMap = NULL;
PVMM_PROCESS pProcess = (PVMM_PROCESS)ctx->pProcess;
*pcbWrite = 0;
Util_PathSplit2(ctx->szPath, _szBuf, &szPath1, &szPath2);
if(szPath1[0] && szPath2[0]) {
for(i = 0; i < pProcess->cModuleMap; i++) {
if(0 == strncmp(szPath1, pProcess->pModuleMap[i].szName, MAX_PATH)) {
if(szPath1[0] && szPath2[0] && VmmProc_ModuleMapGet(pProcess, &pObModuleMap)) {
for(i = 0; i < pObModuleMap->cMap; i++) {
if(0 == strncmp(szPath1, pObModuleMap->pMap[i].szName, MAX_PATH)) {
if(!_strnicmp(szPath2, "sectionsd\\", 10)) {
LdrModules_Write_SectionsD(pProcess, pProcess->pModuleMap + i, szPath2 + 10, pb, cb, pcbWrite, cbOffset);
LdrModules_Write_SectionsD(pProcess, pObModuleMap->pMap + i, szPath2 + 10, pb, cb, pcbWrite, cbOffset);
}
if(!_strnicmp(szPath2, "directoriesd\\", 13)) {
LdrModules_Write_DirectoriesD(pProcess, pProcess->pModuleMap + i, szPath2 + 13, pb, cb, pcbWrite, cbOffset);
LdrModules_Write_DirectoriesD(pProcess, pObModuleMap->pMap + i, szPath2 + 13, pb, cb, pcbWrite, cbOffset);
}
break;
}
}
VmmOb_DECREF(pObModuleMap);
}
return VMM_STATUS_SUCCESS;
}
@@ -250,6 +239,60 @@ NTSTATUS LdrModules_Read_SectionsD(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MODULEM
return LdrModules_Read_MemFile(pProcess, pModule->BaseAddress + SectionHeader.VirtualAddress, SectionHeader.Misc.VirtualSize, pb, cb, pcbRead, cbOffset);
}
NTSTATUS LdrModules_Read_2(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ PVMMOB_MODULEMAP pObModuleMap, _In_ LPSTR szPath1, _In_ LPSTR szPath2, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset)
{
NTSTATUS nt;
DWORD i, cbBuffer;
BYTE pbBuffer[0x800];
PVMM_MODULEMAP_ENTRY pModule;
POBLDRMODULES_CACHE_ENTRY pObCacheEntry = NULL;
PVMM_PROCESS pProcess = (PVMM_PROCESS)ctx->pProcess;
for(i = 0; i < pObModuleMap->cMap; i++) {
pModule = pObModuleMap->pMap + i;
if(0 == strncmp(szPath1, pModule->szName, MAX_PATH)) {
if(!_stricmp(szPath2, "base")) {
return Util_VfsReadFile_FromQWORD(pModule->BaseAddress, pb, cb, pcbRead, cbOffset, FALSE);
}
if(!_stricmp(szPath2, "entry")) {
return Util_VfsReadFile_FromQWORD(pModule->EntryPoint, pb, cb, pcbRead, cbOffset, FALSE);
}
if(!_stricmp(szPath2, "size")) {
return Util_VfsReadFile_FromDWORD(pModule->SizeOfImage, pb, cb, pcbRead, cbOffset, FALSE);
}
if(!_stricmp(szPath2, "directories")) {
VmmWin_PE_DIRECTORY_DisplayBuffer(ctx->pProcess, pModule, pbBuffer, 0x400, &cbBuffer, NULL);
return Util_VfsReadFile_FromPBYTE(pbBuffer, cbBuffer, pb, cb, pcbRead, cbOffset);
}
if(!_stricmp(szPath2, "export")) {
pObCacheEntry = LdrModule_GetEAT(ctx, pModule);
if(!pObCacheEntry) { return VMMDLL_STATUS_FILE_INVALID; }
nt = Util_VfsReadFile_FromPBYTE(pObCacheEntry->pb, pObCacheEntry->cb, pb, cb, pcbRead, cbOffset);
VmmOb_DECREF(pObCacheEntry);
return nt;
}
if(!_stricmp(szPath2, "import")) {
pObCacheEntry = LdrModule_GetIAT(ctx, pModule);
if(!pObCacheEntry) { return VMMDLL_STATUS_FILE_INVALID; }
nt = Util_VfsReadFile_FromPBYTE(pObCacheEntry->pb, pObCacheEntry->cb, pb, cb, pcbRead, cbOffset);
VmmOb_DECREF(pObCacheEntry);
return nt;
}
if(!_stricmp(szPath2, "sections")) {
VmmWin_PE_SECTION_DisplayBuffer(ctx->pProcess, pModule, pbBuffer, 0x800, &cbBuffer, NULL, NULL);
return Util_VfsReadFile_FromPBYTE(pbBuffer, cbBuffer, pb, cb, pcbRead, cbOffset);
}
if(!_strnicmp(szPath2, "sectionsd\\", 10)) {
return LdrModules_Read_SectionsD(pProcess, pModule, szPath2 + 10, pb, cb, pcbRead, cbOffset);
}
if(!_strnicmp(szPath2, "directoriesd\\", 13)) {
return LdrModules_Read_DirectoriesD(pProcess, pModule, szPath2 + 13, pb, cb, pcbRead, cbOffset);
}
return VMMDLL_STATUS_FILE_INVALID;
}
}
return VMMDLL_STATUS_FILE_INVALID;
}
/*
* Read : function as specified by the module manager. The module manager will
* call into this callback function whenever a read shall occur from a "file".
@@ -262,53 +305,16 @@ NTSTATUS LdrModules_Read_SectionsD(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MODULEM
*/
NTSTATUS LdrModules_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset)
{
DWORD i, cbBuffer;
BYTE pbBuffer[0x800];
NTSTATUS nt;
CHAR _szBuf[MAX_PATH] = { 0 };
LPSTR szPath1, szPath2;
PLDRMODULES_CACHE_ENTRY pCacheEntry;
PVMM_PROCESS pProcess = (PVMM_PROCESS)ctx->pProcess;
PVMMOB_MODULEMAP pObModuleMap = NULL;
Util_PathSplit2(ctx->szPath, _szBuf, &szPath1, &szPath2);
*pcbRead = 0;
if(szPath1[0] && szPath2[0]) {
for(i = 0; i < pProcess->cModuleMap; i++) {
if(0 == strncmp(szPath1, pProcess->pModuleMap[i].szName, MAX_PATH)) {
if(!_stricmp(szPath2, "base")) {
return Util_VfsReadFile_FromQWORD(pProcess->pModuleMap[i].BaseAddress, pb, cb, pcbRead, cbOffset, FALSE);
}
if(!_stricmp(szPath2, "entry")) {
return Util_VfsReadFile_FromQWORD(pProcess->pModuleMap[i].EntryPoint, pb, cb, pcbRead, cbOffset, FALSE);
}
if(!_stricmp(szPath2, "size")) {
return Util_VfsReadFile_FromDWORD(pProcess->pModuleMap[i].SizeOfImage, pb, cb, pcbRead, cbOffset, FALSE);
}
if(!_stricmp(szPath2, "directories")) {
VmmWin_PE_DIRECTORY_DisplayBuffer(ctx->pProcess, pProcess->pModuleMap + i, pbBuffer, 0x400, &cbBuffer, NULL);
return Util_VfsReadFile_FromPBYTE(pbBuffer, cbBuffer, pb, cb, pcbRead, cbOffset);
}
if(!_stricmp(szPath2, "export")) {
pCacheEntry = LdrModule_GetEAT(ctx, pProcess->pModuleMap + i);
if(!pCacheEntry) { return VMMDLL_STATUS_FILE_INVALID; }
return Util_VfsReadFile_FromPBYTE(pCacheEntry->pb, pCacheEntry->cb, pb, cb, pcbRead, cbOffset);
}
if(!_stricmp(szPath2, "import")) {
pCacheEntry = LdrModule_GetIAT(ctx, pProcess->pModuleMap + i);
if(!pCacheEntry) { return VMMDLL_STATUS_FILE_INVALID; }
return Util_VfsReadFile_FromPBYTE(pCacheEntry->pb, pCacheEntry->cb, pb, cb, pcbRead, cbOffset);
}
if(!_stricmp(szPath2, "sections")) {
VmmWin_PE_SECTION_DisplayBuffer(ctx->pProcess, pProcess->pModuleMap + i, pbBuffer, 0x800, &cbBuffer, NULL, NULL);
return Util_VfsReadFile_FromPBYTE(pbBuffer, cbBuffer, pb, cb, pcbRead, cbOffset);
}
if(!_strnicmp(szPath2, "sectionsd\\", 10)) {
return LdrModules_Read_SectionsD(pProcess, pProcess->pModuleMap + i, szPath2 + 10, pb, cb, pcbRead, cbOffset);
}
if(!_strnicmp(szPath2, "directoriesd\\", 13)) {
return LdrModules_Read_DirectoriesD(pProcess, pProcess->pModuleMap + i, szPath2 + 13, pb, cb, pcbRead, cbOffset);
}
return VMMDLL_STATUS_FILE_INVALID;
}
}
if(szPath1[0] && szPath2[0] && VmmProc_ModuleMapGet((PVMM_PROCESS)ctx->pProcess, &pObModuleMap)) {
nt = LdrModules_Read_2(ctx, pObModuleMap, szPath1, szPath2, pb, cb, pcbRead, cbOffset);
VmmOb_DECREF(pObModuleMap);
return nt;
}
return VMMDLL_STATUS_FILE_INVALID;
}
@@ -326,52 +332,54 @@ BOOL LdrModules_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList)
DWORD c, i;
CHAR _szBuf[MAX_PATH] = { 0 };
LPSTR szPath1, szPath2;
PVMMOB_MODULEMAP pObModuleMap = NULL;
PVMM_MODULEMAP_ENTRY pModule = NULL;
PIMAGE_SECTION_HEADER pSections = NULL;
IMAGE_DATA_DIRECTORY pDataDirectories[16];
PVMM_PROCESS pProcess = (PVMM_PROCESS)ctx->pProcess;
if(!VmmProc_ModuleMapGet(pProcess, &pObModuleMap)) { goto fail; }
// modules root directory -> add directory per DLL
if(!ctx->szPath[0]) {
for(i = 0; i < pProcess->cModuleMap; i++) {
VMMDLL_VfsList_AddDirectory(pFileList, pProcess->pModuleMap[i].szName);
for(i = 0; i < pObModuleMap->cMap; i++) {
VMMDLL_VfsList_AddDirectory(pFileList, pObModuleMap->pMap[i].szName);
}
return TRUE;
goto success;
}
// individual module directory -> list files
Util_PathSplit2(ctx->szPath, _szBuf, &szPath1, &szPath2);
for(i = 0; i < pProcess->cModuleMap; i++) {
if(0 == strncmp(szPath1, pProcess->pModuleMap[i].szName, 32)) {
pModule = pProcess->pModuleMap + i;
for(i = 0; i < pObModuleMap->cMap; i++) {
if(0 == strncmp(szPath1, pObModuleMap->pMap[i].szName, 32)) {
pModule = pObModuleMap->pMap + i;
break;
}
}
if(!pModule) { return FALSE; }
if(!pModule) { goto fail; }
// module-specific 'root' directory
if(!szPath2[0]) {
VmmWin_PE_SetSizeSectionIATEAT_DisplayBuffer(ctx->pProcess, pProcess->pModuleMap + i);
VmmWin_PE_SetSizeSectionIATEAT_DisplayBuffer(ctx->pProcess, pObModuleMap->pMap + i);
VMMDLL_VfsList_AddFile(pFileList, "base", 16);
VMMDLL_VfsList_AddFile(pFileList, "entry", 16);
VMMDLL_VfsList_AddFile(pFileList, "size", 8);
VMMDLL_VfsList_AddFile(pFileList, "directories", 864);
VMMDLL_VfsList_AddFile(pFileList, "export", pProcess->pModuleMap[i].cbDisplayBufferEAT);
VMMDLL_VfsList_AddFile(pFileList, "import", pProcess->pModuleMap[i].cbDisplayBufferIAT);
VMMDLL_VfsList_AddFile(pFileList, "sections", pProcess->pModuleMap[i].cbDisplayBufferSections);
VMMDLL_VfsList_AddFile(pFileList, "export", pObModuleMap->pMap[i].cbDisplayBufferEAT);
VMMDLL_VfsList_AddFile(pFileList, "import", pObModuleMap->pMap[i].cbDisplayBufferIAT);
VMMDLL_VfsList_AddFile(pFileList, "sections", pObModuleMap->pMap[i].cbDisplayBufferSections);
VMMDLL_VfsList_AddDirectory(pFileList, "sectionsd");
VMMDLL_VfsList_AddDirectory(pFileList, "directoriesd");
return TRUE;
goto success;
}
// module-specific 'sectiond' directory
if(szPath2[0] && !strcmp(szPath2, "sectionsd")) {
_szBuf[8] = 0;
c = PE_SectionGetNumberOf(pProcess, pModule->BaseAddress);
if(!(pSections = LocalAlloc(0, c * sizeof(IMAGE_SECTION_HEADER)))) { return FALSE; }
if(!(pSections = LocalAlloc(0, c * sizeof(IMAGE_SECTION_HEADER)))) { goto fail; }
VmmWin_PE_SECTION_DisplayBuffer(pProcess, pModule, NULL, 0, NULL, &c, pSections);
for(i = 0; i < c; i++) {
*(PQWORD)_szBuf = *(PQWORD)pSections[i].Name;
VMMDLL_VfsList_AddFile(pFileList, _szBuf, pSections[i].Misc.VirtualSize);
}
LocalFree(pSections);
return TRUE;
goto success;
}
// module-specific 'directoriesd' directory
if(szPath2[0] && !strcmp(szPath2, "directoriesd")) {
@@ -379,9 +387,14 @@ BOOL LdrModules_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList)
for(i = 0; i < 16; i++) {
VMMDLL_VfsList_AddFile(pFileList, (LPSTR)PE_DATA_DIRECTORIES[i], pDataDirectories[i].Size);
}
return TRUE;
goto success;
}
fail:
VmmOb_DECREF(pObModuleMap);
return FALSE;
success:
VmmOb_DECREF(pObModuleMap);
return TRUE;
}
/*
@@ -394,17 +407,12 @@ BOOL LdrModules_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList)
*/
VOID M_LdrModules_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI)
{
PLDRMODULES_CACHE_ENTRY pCache;
if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; }
if((pRI->tpSystem != VMM_SYSTEM_WINDOWS_X64) && (pRI->tpSystem != VMM_SYSTEM_WINDOWS_X86)) { return; }
pCache = LocalAlloc(LMEM_ZEROINIT, LDRMODULES_NUM_CACHE * sizeof(LDRMODULES_CACHE_ENTRY));
if(!pCache) { return; }
strcpy_s(pRI->reg_info.szModuleName, 32, "modules"); // module name
pRI->reg_info.fProcessModule = TRUE; // module shows in process directory
pRI->reg_info.hModulePrivate = pCache; // module private handle (for cache)
pRI->reg_fn.pfnList = LdrModules_List; // List function supported
pRI->reg_fn.pfnRead = LdrModules_Read; // Read function supported
pRI->reg_fn.pfnWrite = LdrModules_Write; // Write function supported
pRI->reg_fn.pfnCloseHandleModule = LdrModule_CloseHandleModule; // Close module private handle supported
pRI->pfnPluginManager_Register(pRI);
}
+1 -1
View File
@@ -1,6 +1,6 @@
// m_ldrmodules.h : definitions related to the ldrmodules built-in module.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
#ifndef __M_LDRMODULES_H__
+4 -4
View File
@@ -1,6 +1,6 @@
// m_status.c : implementation of the .status built-in module.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
@@ -121,10 +121,10 @@ NTSTATUS MStatus_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ DWO
return Util_VfsReadFile_FromBOOL(ctxMain->cfg.fVerboseExtraTlp, pb, cb, pcbRead, cbOffset);
}
if(!_stricmp(ctx->szPath, "native_max_address")) {
return Util_VfsReadFile_FromQWORD(ctxMain->dev.paAddrMaxNative, pb, cb, pcbRead, cbOffset, FALSE);
return Util_VfsReadFile_FromQWORD(ctxMain->dev.paMaxNative, pb, cb, pcbRead, cbOffset, FALSE);
}
if(!_stricmp(ctx->szPath, "native_max_iosize")) {
return Util_VfsReadFile_FromQWORD(ctxMain->dev.qwMaxSizeMemIo, pb, cb, pcbRead, cbOffset, FALSE);
return Util_VfsReadFile_FromQWORD(ctxMain->dev.cbMaxSizeMemIo, pb, cb, pcbRead, cbOffset, FALSE);
}
}
return VMMDLL_STATUS_FILE_INVALID;
@@ -172,7 +172,7 @@ NTSTATUS MStatus_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ LPVOID pb, _In_ DWO
if(nt == VMMDLL_STATUS_SUCCESS) {
ctxVmm->flags &= ~VMM_FLAG_PROCESS_SHOW_TERMINATED;
ctxVmm->flags |= fEnable ? VMM_FLAG_PROCESS_SHOW_TERMINATED : 0;
VmmProc_Refresh(FALSE, TRUE);
VmmProc_Refresh(TRUE);
}
return nt;
}
+1 -1
View File
@@ -1,6 +1,6 @@
// m_status.h : definitions related to the .status built-in module.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
#ifndef __M_STATUS_H__
+41 -76
View File
@@ -1,6 +1,6 @@
// m_virt2phys.c : implementation of the virt2phys built-in module.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
#include "m_virt2phys.h"
@@ -9,29 +9,6 @@
#include "vmm.h"
#include "vmmvfs.h"
/*
* Virt2Phys_GetContext is an internal function which retrieves (or allocates)
* a pointer to a VMM_VIRT2PHYS_INFORMATION structure. If it does not exist and
* no "Dummy" is supplied a new VMM_VIRT2PHYS_INFORMATION is allocated & stored
* in the handle pointed by phProcessPrivate. This may later be free'd when the
* module manager calls the Virt2Phys_CloseHandleProcess function.
* -- phProcessPrivate
* -- pDummy
* -- return
*/
PVMM_VIRT2PHYS_INFORMATION Virt2Phys_GetContext(_Inout_ PHANDLE phProcessPrivate, _Out_opt_ PVMM_VIRT2PHYS_INFORMATION pDummy)
{
if(*phProcessPrivate) {
return (PVMM_VIRT2PHYS_INFORMATION)*phProcessPrivate;
}
if(pDummy) {
ZeroMemory(pDummy, sizeof(VMM_VIRT2PHYS_INFORMATION));
return pDummy;
}
*phProcessPrivate = (HANDLE)LocalAlloc(LMEM_ZEROINIT, sizeof(VMM_VIRT2PHYS_INFORMATION));
return (PVMM_VIRT2PHYS_INFORMATION)*phProcessPrivate;
}
/*
* Read : function as specified by the module manager. The module manager will
* call into this callback function whenever a read shall occur from a "file".
@@ -48,21 +25,24 @@ NTSTATUS Virt2Phys_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ D
DWORD cbBuffer;
PBYTE pbSourceData;
BYTE pbBuffer[0x1000];
VMM_VIRT2PHYS_INFORMATION Virt2PhysInfo_Dummy, *pVirt2PhysInfo;
pVirt2PhysInfo = Virt2Phys_GetContext(ctx->phProcessPrivate, &Virt2PhysInfo_Dummy);
PVMMOB_MEM pObPT = NULL;
PVMM_PROCESS pProcess = (PVMM_PROCESS)ctx->pProcess;
VMM_VIRT2PHYS_INFORMATION Virt2PhysInfo = { 0 };
Virt2PhysInfo.va = pProcess->pObProcessPersistent->Plugin.vaVirt2Phys;
VmmVirt2PhysGetInformation(pProcess, &Virt2PhysInfo);
if(!_stricmp(ctx->szPath, "virt")) {
switch(ctxVmm->tpMemoryModel) {
case VMM_MEMORYMODEL_X64:
return Util_VfsReadFile_FromQWORD(pVirt2PhysInfo->va, pb, cb, pcbRead, cbOffset, FALSE);
return Util_VfsReadFile_FromQWORD(Virt2PhysInfo.va, pb, cb, pcbRead, cbOffset, FALSE);
break;
case VMM_MEMORYMODEL_X86:
case VMM_MEMORYMODEL_X86PAE:
return Util_VfsReadFile_FromDWORD((DWORD)pVirt2PhysInfo->va, pb, cb, pcbRead, cbOffset, FALSE);
return Util_VfsReadFile_FromDWORD((DWORD)Virt2PhysInfo.va, pb, cb, pcbRead, cbOffset, FALSE);
break;
}
}
if(!_stricmp(ctx->szPath, "phys")) {
return Util_VfsReadFile_FromQWORD(pVirt2PhysInfo->pas[0], pb, cb, pcbRead, cbOffset, FALSE);
return Util_VfsReadFile_FromQWORD(Virt2PhysInfo.pas[0], pb, cb, pcbRead, cbOffset, FALSE);
}
if(!_stricmp(ctx->szPath, "map")) {
switch(ctxVmm->tpMemoryModel) {
@@ -75,11 +55,11 @@ NTSTATUS Virt2Phys_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ D
"PD %016llx +%03x %016llx\n" \
"PT %016llx +%03x %016llx\n" \
"PAGE %016llx\n",
pVirt2PhysInfo->pas[4], pVirt2PhysInfo->iPTEs[4] << 3, pVirt2PhysInfo->PTEs[4],
pVirt2PhysInfo->pas[3], pVirt2PhysInfo->iPTEs[3] << 3, pVirt2PhysInfo->PTEs[3],
pVirt2PhysInfo->pas[2], pVirt2PhysInfo->iPTEs[2] << 3, pVirt2PhysInfo->PTEs[2],
pVirt2PhysInfo->pas[1], pVirt2PhysInfo->iPTEs[1] << 3, pVirt2PhysInfo->PTEs[1],
pVirt2PhysInfo->pas[0]
Virt2PhysInfo.pas[4], Virt2PhysInfo.iPTEs[4] << 3, Virt2PhysInfo.PTEs[4],
Virt2PhysInfo.pas[3], Virt2PhysInfo.iPTEs[3] << 3, Virt2PhysInfo.PTEs[3],
Virt2PhysInfo.pas[2], Virt2PhysInfo.iPTEs[2] << 3, Virt2PhysInfo.PTEs[2],
Virt2PhysInfo.pas[1], Virt2PhysInfo.iPTEs[1] << 3, Virt2PhysInfo.PTEs[1],
Virt2PhysInfo.pas[0]
);
break;
case VMM_MEMORYMODEL_X86PAE:
@@ -90,10 +70,10 @@ NTSTATUS Virt2Phys_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ D
"PD %016llx +%03x %016llx\n" \
"PT %016llx +%03x %016llx\n" \
"PAGE %016llx\n",
pVirt2PhysInfo->pas[3], pVirt2PhysInfo->iPTEs[3] << 3, pVirt2PhysInfo->PTEs[3],
pVirt2PhysInfo->pas[2], pVirt2PhysInfo->iPTEs[2] << 3, pVirt2PhysInfo->PTEs[2],
pVirt2PhysInfo->pas[1], pVirt2PhysInfo->iPTEs[1] << 3, pVirt2PhysInfo->PTEs[1],
pVirt2PhysInfo->pas[0]
Virt2PhysInfo.pas[3], Virt2PhysInfo.iPTEs[3] << 3, Virt2PhysInfo.PTEs[3],
Virt2PhysInfo.pas[2], Virt2PhysInfo.iPTEs[2] << 3, Virt2PhysInfo.PTEs[2],
Virt2PhysInfo.pas[1], Virt2PhysInfo.iPTEs[1] << 3, Virt2PhysInfo.PTEs[1],
Virt2PhysInfo.pas[0]
);
break;
case VMM_MEMORYMODEL_X86:
@@ -103,9 +83,9 @@ NTSTATUS Virt2Phys_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ D
"PD %016llx +%03x %08x\n" \
"PT %016llx +%03x %08x\n" \
"PAGE %016llx\n",
pVirt2PhysInfo->pas[2], pVirt2PhysInfo->iPTEs[2] << 2, (DWORD)pVirt2PhysInfo->PTEs[2],
pVirt2PhysInfo->pas[1], pVirt2PhysInfo->iPTEs[1] << 2, (DWORD)pVirt2PhysInfo->PTEs[1],
pVirt2PhysInfo->pas[0]
Virt2PhysInfo.pas[2], Virt2PhysInfo.iPTEs[2] << 2, (DWORD)Virt2PhysInfo.PTEs[2],
Virt2PhysInfo.pas[1], Virt2PhysInfo.iPTEs[1] << 2, (DWORD)Virt2PhysInfo.PTEs[1],
Virt2PhysInfo.pas[0]
);
break;
}
@@ -120,11 +100,16 @@ NTSTATUS Virt2Phys_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ D
if((ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X86PAE) && (iPML > 3)) { return VMMDLL_STATUS_FILE_INVALID; }
ZeroMemory(pbBuffer, 0x1000);
pbSourceData = pbBuffer;
if(iPML && (pVirt2PhysInfo->pas[iPML] & ~0xfff)) {
pbSourceData = VmmTlbGetPageTable(pVirt2PhysInfo->pas[iPML] & ~0xfff, FALSE);
if(iPML && (Virt2PhysInfo.pas[iPML] & ~0xfff)) {
pObPT = VmmTlbGetPageTable(Virt2PhysInfo.pas[iPML] & ~0xfff, FALSE);
if(pObPT) {
memcpy(pbSourceData, pObPT->pb, 0x1000);
VmmOb_DECREF(pObPT);
pObPT = NULL;
}
}
if(!_stricmp(ctx->szPath, "page") && (pVirt2PhysInfo->pas[0] & ~0xfff)) {
VmmReadPhysicalPage(pVirt2PhysInfo->pas[0] & ~0xfff, pbBuffer);
if(!_stricmp(ctx->szPath, "page") && (Virt2PhysInfo.pas[0] & ~0xfff)) {
VmmReadPhysicalPage(Virt2PhysInfo.pas[0] & ~0xfff, pbBuffer);
}
if(iPML || !_stricmp(ctx->szPath, "page")) {
return Util_VfsReadFile_FromPBYTE(pbSourceData, 0x1000, pb, cb, pcbRead, cbOffset);
@@ -133,8 +118,7 @@ NTSTATUS Virt2Phys_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ D
}
/*
* Write to the "virt" virtual file - a new virtual address is written. Triggers
* an update of the cached virtual to physical translation information.
* Write to the "virt" virtual file - update stored persistent address.
* -- ctx
* -- pb
* -- cb
@@ -146,26 +130,21 @@ NTSTATUS Virt2Phys_WriteVA(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ LPVOID pb, _In_
{
PVMM_PROCESS pProcess = (PVMM_PROCESS)ctx->pProcess;
BYTE pbBuffer[17];
PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo;
VMM_MEMORYMODEL_TP tp = ctxVmm->tpMemoryModel;
if((tp == VMM_MEMORYMODEL_X64) && (cbOffset < 16)) {
pVirt2PhysInfo = Virt2Phys_GetContext(ctx->phProcessPrivate, NULL);
*pcbWrite = cb;
snprintf(pbBuffer, 17, "%016llx", pVirt2PhysInfo->va);
snprintf(pbBuffer, 17, "%016llx", pProcess->pObProcessPersistent->Plugin.vaVirt2Phys);
cb = (DWORD)min(16 - cbOffset, cb);
memcpy(pbBuffer + cbOffset, pb, cb);
pbBuffer[16] = 0;
pVirt2PhysInfo->va = strtoull(pbBuffer, NULL, 16);
VmmVirt2PhysGetInformation(pProcess, pVirt2PhysInfo);
pProcess->pObProcessPersistent->Plugin.vaVirt2Phys = strtoull(pbBuffer, NULL, 16);
} else if ((tp == VMM_MEMORYMODEL_X86) || (tp == VMM_MEMORYMODEL_X86PAE)) {
pVirt2PhysInfo = Virt2Phys_GetContext(ctx->phProcessPrivate, NULL);
*pcbWrite = cb;
snprintf(pbBuffer, 9, "%08x", (DWORD)pVirt2PhysInfo->va);
snprintf(pbBuffer, 9, "%08x", (DWORD)pProcess->pObProcessPersistent->Plugin.vaVirt2Phys);
cb = (DWORD)min(8 - cbOffset, cb);
memcpy(pbBuffer + cbOffset, pb, cb);
pbBuffer[8] = 0;
pVirt2PhysInfo->va = strtoul(pbBuffer, NULL, 16);
VmmVirt2PhysGetInformation(pProcess, pVirt2PhysInfo);
pProcess->pObProcessPersistent->Plugin.vaVirt2Phys = strtoul(pbBuffer, NULL, 16);
} else {
*pcbWrite = 0;
}
@@ -185,11 +164,13 @@ NTSTATUS Virt2Phys_WriteVA(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ LPVOID pb, _In_
NTSTATUS Virt2Phys_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset)
{
DWORD i;
VMM_VIRT2PHYS_INFORMATION Virt2PhysInfo_Dummy, *pVirt2PhysInfo;
PVMM_PROCESS pProcess = (PVMM_PROCESS)ctx->pProcess;
VMM_VIRT2PHYS_INFORMATION Virt2PhysInfo = { 0 };
if(!_stricmp(ctx->szPath, "virt")) {
return Virt2Phys_WriteVA(ctx, pb, cb, pcbWrite, cbOffset);
}
pVirt2PhysInfo = Virt2Phys_GetContext(ctx->phProcessPrivate, &Virt2PhysInfo_Dummy);
Virt2PhysInfo.va = pProcess->pObProcessPersistent->Plugin.vaVirt2Phys;
VmmVirt2PhysGetInformation(pProcess, &Virt2PhysInfo);
i = 0xff;
if(!_stricmp(ctx->szPath, "pt_pml4")) { i = 4; }
if(!_stricmp(ctx->szPath, "pt_pdpt")) { i = 3; }
@@ -197,10 +178,10 @@ NTSTATUS Virt2Phys_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ LPVOID pb, _In_ D
if(!_stricmp(ctx->szPath, "pt_pt")) { i = 1; }
if(!_stricmp(ctx->szPath, "page")) { i = 0; }
if(i > 4) { return VMMDLL_STATUS_FILE_INVALID; }
if(pVirt2PhysInfo->pas[i] < 0x1000) { return VMMDLL_STATUS_FILE_INVALID; }
if(Virt2PhysInfo.pas[i] < 0x1000) { return VMMDLL_STATUS_FILE_INVALID; }
if(cbOffset > 0x1000) { return VMMDLL_STATUS_END_OF_FILE; }
*pcbWrite = (DWORD)min(cb, 0x1000 - cbOffset);
VmmWritePhysical(pVirt2PhysInfo->pas[i] + cbOffset, pb, *pcbWrite);
VmmWritePhysical(Virt2PhysInfo.pas[i] + cbOffset, pb, *pcbWrite);
return *pcbWrite ? VMMDLL_STATUS_SUCCESS : VMMDLL_STATUS_END_OF_FILE;
}
@@ -251,21 +232,6 @@ BOOL Virt2Phys_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList)
return TRUE;
}
/*
* CloseHandleProcess : function as specified by the module manager. The module
* manager will call into this callback function whenever a process specific
* handle shall be closed. Please note that only the memory pointed to by the
* parameter phProcessPrivate shall be free'd.
* -- ctx
* -- phModulePrivate
* -- phProcessPrivate = memory to be free'd.
*/
VOID Virt2Phys_CloseHandleProcess(_In_opt_ PHANDLE phModulePrivate, _Inout_ PHANDLE phProcessPrivate)
{
LocalFree(*phProcessPrivate);
*phProcessPrivate = 0;
}
/*
* Initialization function. The module manager shall call into this function
* when the module shall be initialized. If the module wish to initialize it
@@ -283,6 +249,5 @@ VOID M_Virt2Phys_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI)
pRI->reg_fn.pfnList = Virt2Phys_List; // List function supported
pRI->reg_fn.pfnRead = Virt2Phys_Read; // Read function supported
pRI->reg_fn.pfnWrite = Virt2Phys_Write; // Write function supported
pRI->reg_fn.pfnCloseHandleProcess = Virt2Phys_CloseHandleProcess; // Close process module private handle supported
pRI->pfnPluginManager_Register(pRI);
}
+1 -1
View File
@@ -1,6 +1,6 @@
// m_virt2phys.h : definitions related to the virt2phys built-in module.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
#ifndef __M_VIRT2PHYS_H__
+248 -148
View File
@@ -1,10 +1,12 @@
// mm_x64.c : implementation of the x64 / IA32e / long-mode paging / memory model.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
#include "device.h"
#include "vmm.h"
#include "vmmproc.h"
#define MMX64_MEMMAP_DISPLAYBUFFER_LINE_LENGTH 89
/*
* Tries to verify that a loaded page table is correct. If just a bit strange
@@ -19,15 +21,13 @@ BOOL MmX64_TlbPageTableVerify(_Inout_ PBYTE pb, _In_ QWORD pa, _In_ BOOL fSelfRe
ptes = (PQWORD)pb;
for(i = 0; i < 512; i++) {
pte = *(ptes + i);
if((pte & 0x01) && ((0x000fffffffffffff & pte) > ctxMain->cfg.paAddrMax)) {
if((pte & 0x01) && ((0x000fffffffffffff & pte) > ctxMain->dev.paMax)) {
// A bad PTE, or memory allocated above the physical address max
// limit. This may be just trash in the page table in which case
// we clear this faulty entry. If too may bad PTEs are found this
// is most probably not a page table - zero it out but let it
// remain in cache to prevent performance degrading reloads...
if(ctxVmm) {
vmmprintfvv("VMM: vmm.c!VmmTlbPageTableVerify: BAD PTE %016llx at PA: %016llx i: %i\n", *(ptes + i), pa, i);
}
vmmprintfvv_fn("VMM: BAD PTE %016llx at PA: %016llx i: %i\n", *(ptes + i), pa, i);
*(ptes + i) = (QWORD)0;
c++;
if(c > 16) { break; }
@@ -38,7 +38,7 @@ BOOL MmX64_TlbPageTableVerify(_Inout_ PBYTE pb, _In_ QWORD pa, _In_ BOOL fSelfRe
}
if((c > 16) || (fSelfRefReq && !fSelfRef)) {
if(ctxVmm) {
vmmprintfvv("VMM: vmm.c!VmmTlbPageTableVerify: BAD PT PAGE at PA: %016llx\n", pa);
vmmprintfvv_fn("VMM: BAD PT PAGE at PA: %016llx\n", pa);
}
ZeroMemory(pb, 4096);
return FALSE;
@@ -50,17 +50,17 @@ BOOL MmX64_TlbPageTableVerify(_Inout_ PBYTE pb, _In_ QWORD pa, _In_ BOOL fSelfRe
typedef struct tdMMX64_TLB_SPIDER_STAGE_INTERNAL {
QWORD c;
PMEM_IO_SCATTER_HEADER ppDMAs[MMX64_TLB_SIZE_STAGEBUF];
PVMM_CACHE_ENTRY ppEntrys[MMX64_TLB_SIZE_STAGEBUF];
PMEM_IO_SCATTER_HEADER ppMEMs[MMX64_TLB_SIZE_STAGEBUF];
PVMMOB_MEM ppObMEMs[MMX64_TLB_SIZE_STAGEBUF];
} MMX64_TLB_SPIDER_STAGE_INTERNAL, *PMMX64_TLB_SPIDER_STAGE_INTERNAL;
VOID MmX64_TlbSpider_ReadToCache(PMMX64_TLB_SPIDER_STAGE_INTERNAL pTlbSpiderStage)
{
QWORD i;
DeviceReadScatterMEM(pTlbSpiderStage->ppDMAs, (DWORD)pTlbSpiderStage->c, NULL);
LeechCore_ReadScatter(pTlbSpiderStage->ppMEMs, (DWORD)pTlbSpiderStage->c);
for(i = 0; i < pTlbSpiderStage->c; i++) {
MmX64_TlbPageTableVerify(pTlbSpiderStage->ppEntrys[i]->h.pb, pTlbSpiderStage->ppEntrys[i]->h.qwA, FALSE);
VmmCachePut(ctxVmm->ptTLB, pTlbSpiderStage->ppEntrys[i]);
MmX64_TlbPageTableVerify(pTlbSpiderStage->ppObMEMs[i]->h.pb, pTlbSpiderStage->ppObMEMs[i]->h.qwA, FALSE);
VmmCacheReserveReturn(pTlbSpiderStage->ppObMEMs[i]);
}
pTlbSpiderStage->c = 0;
}
@@ -68,14 +68,14 @@ VOID MmX64_TlbSpider_ReadToCache(PMMX64_TLB_SPIDER_STAGE_INTERNAL pTlbSpiderStag
BOOL MmX64_TlbSpider_Stage(_In_ QWORD pa, _In_ BYTE iPML, _In_ BOOL fUserOnly, PMMX64_TLB_SPIDER_STAGE_INTERNAL pTlbSpiderStage)
{
BOOL fSpiderComplete = TRUE;
PMEM_IO_SCATTER_HEADER pt;
PVMMOB_MEM ptObMEM;
QWORD i, pe;
// 1: retrieve from cache, add to staging if not found
pt = VmmCacheGet(ctxVmm->ptTLB, pa);
if(!pt) {
pTlbSpiderStage->ppEntrys[pTlbSpiderStage->c] = VmmCacheReserve(ctxVmm->ptTLB);
pTlbSpiderStage->ppDMAs[pTlbSpiderStage->c] = &pTlbSpiderStage->ppEntrys[pTlbSpiderStage->c]->h;
pTlbSpiderStage->ppDMAs[pTlbSpiderStage->c]->qwA = pa;
ptObMEM = VmmCacheGet(VMM_CACHE_TAG_TLB, pa);
if(!ptObMEM) {
pTlbSpiderStage->ppObMEMs[pTlbSpiderStage->c] = VmmCacheReserve(VMM_CACHE_TAG_TLB);
pTlbSpiderStage->ppMEMs[pTlbSpiderStage->c] = &pTlbSpiderStage->ppObMEMs[pTlbSpiderStage->c]->h;
pTlbSpiderStage->ppMEMs[pTlbSpiderStage->c]->qwA = pa;
pTlbSpiderStage->c++;
if(pTlbSpiderStage->c == MMX64_TLB_SIZE_STAGEBUF) {
MmX64_TlbSpider_ReadToCache(pTlbSpiderStage);
@@ -83,14 +83,18 @@ BOOL MmX64_TlbSpider_Stage(_In_ QWORD pa, _In_ BYTE iPML, _In_ BOOL fUserOnly, P
return FALSE;
}
// 2: walk trough all entries for PML4, PDPT, PD
if(iPML == 1) { return TRUE; }
for(i = 0; i < 0x1000; i += 8) {
pe = *(PQWORD)(pt->pb + i);
if(iPML == 1) {
VmmOb_DECREF(ptObMEM);
return TRUE;
}
for(i = 0; i < 512; i++) {
pe = ptObMEM->pqw[i];
if(!(pe & 0x01)) { continue; } // not valid
if(pe & 0x80) { continue; } // not valid ptr to (PDPT || PD || PT)
if(fUserOnly && !(pe & 0x04)) { continue; } // supervisor page when fUserOnly -> not valid
fSpiderComplete = MmX64_TlbSpider_Stage(pe & 0x0000fffffffff000, iPML - 1, fUserOnly, pTlbSpiderStage) && fSpiderComplete;
}
VmmOb_DECREF(ptObMEM);
return fSpiderComplete;
}
@@ -98,37 +102,154 @@ BOOL MmX64_TlbSpider_Stage(_In_ QWORD pa, _In_ BYTE iPML, _In_ BOOL fUserOnly, P
* Iterate over PML4, PTPT, PD (3 times in total) to first stage uncached pages
* and then commit them to the cache.
*/
VOID MmX64_TlbSpider(_In_ QWORD paDTB, _In_ BOOL fUserOnly)
VOID MmX64_TlbSpider(_In_ PVMM_PROCESS pProcess)
{
DWORD i = 0;
BOOL result = FALSE;
PMMX64_TLB_SPIDER_STAGE_INTERNAL pTlbSpiderStage;
if(pProcess->fTlbSpiderDone) { return; }
if(!(pTlbSpiderStage = (PMMX64_TLB_SPIDER_STAGE_INTERNAL)LocalAlloc(LMEM_ZEROINIT, sizeof(MMX64_TLB_SPIDER_STAGE_INTERNAL)))) { return; }
while(!result && (i < 3)) {
result = MmX64_TlbSpider_Stage(paDTB, 4, fUserOnly, pTlbSpiderStage);
result = MmX64_TlbSpider_Stage(pProcess->paDTB, 4, pProcess->fUserOnly, pTlbSpiderStage);
if(pTlbSpiderStage->c) {
MmX64_TlbSpider_ReadToCache(pTlbSpiderStage);
}
i++;
}
LocalFree(pTlbSpiderStage);
pProcess->fTlbSpiderDone = TRUE;
}
const QWORD MMX64_PAGETABLEMAP_PML_REGION_SIZE[5] = { 0, 12, 21, 30, 39 };
VOID MmX64_MapInitialize_Index(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MEMMAP_ENTRY pMemMap, _In_ PDWORD pcMemMap, _In_ QWORD vaBase, _In_ BYTE iPML, _In_ QWORD PTEs[512], _In_ BOOL fSupervisorPML, _In_ QWORD paMax)
{
PVMMOB_MEM pObNextPT;
QWORD i, pte, va;
BOOL fUserOnly, fNextSupervisorPML;
PVMM_MEMMAP_ENTRY pMemMapEntry = pMemMap + *pcMemMap - 1;
if(!pProcess->fTlbSpiderDone) {
VmmTlbSpider(pProcess);
}
fUserOnly = pProcess->fUserOnly;
for(i = 0; i < 512; i++) {
pte = PTEs[i];
if(!(pte & 0x01)) { continue; }
if((pte & 0x0000fffffffff000) > paMax) { continue; }
if(fSupervisorPML) { pte = pte & 0xfffffffffffffffb; }
if(fUserOnly && !(pte & 0x04)) { continue; }
va = vaBase + (i << MMX64_PAGETABLEMAP_PML_REGION_SIZE[iPML]);
// maps page
if((iPML == 1) || (pte & 0x80) /* PS */) {
if(iPML == 4) { continue; } // not supported - PML4 cannot map page directly
if((*pcMemMap == 0) ||
(pMemMapEntry->fPage != (pte & VMM_MEMMAP_PAGE_MASK)) ||
(va != pMemMapEntry->AddrBase + (pMemMapEntry->cPages << 12))) {
if(*pcMemMap + 1 >= VMM_MEMMAP_ENTRIES_MAX) { return; }
pMemMapEntry = pMemMap + *pcMemMap;
pMemMapEntry->AddrBase = va;
pMemMapEntry->fPage = pte & VMM_MEMMAP_PAGE_MASK;
pMemMapEntry->cPages = 1ULL << (MMX64_PAGETABLEMAP_PML_REGION_SIZE[iPML] - 12);
*pcMemMap = *pcMemMap + 1;
if(*pcMemMap >= VMM_MEMMAP_ENTRIES_MAX - 1) {
return;
}
continue;
}
pMemMapEntry->cPages += 1ULL << (MMX64_PAGETABLEMAP_PML_REGION_SIZE[iPML] - 12);
continue;
}
// maps page table (PDPT, PD, PT)
fNextSupervisorPML = !(pte & 0x04);
pObNextPT = VmmTlbGetPageTable(pte & 0x0000fffffffff000, FALSE);
if(!pObNextPT) { continue; }
MmX64_MapInitialize_Index(pProcess, pMemMap, pcMemMap, va, iPML - 1, pObNextPT->pqw, fNextSupervisorPML, paMax);
VmmOb_DECREF(pObNextPT);
pMemMapEntry = pMemMap + *pcMemMap - 1;
}
}
VOID MmX64_MapCloseObCallback(_In_ PVOID pVmmOb)
{
PVMMOB_MEMMAP pObMemMap = (PVMMOB_MEMMAP)pVmmOb;
if(pObMemMap->pObDisplay) {
VmmOb_DECREF(pObMemMap->pObDisplay);
}
}
_Success_(return)
BOOL MmX64_MapInitialize(_In_ PVMM_PROCESS pProcess)
{
QWORD i;
DWORD cMemMap = 0;
PVMMOB_MEM pObPML4;
PVMM_MEMMAP_ENTRY pMemMap = NULL;
PVMMOB_MEMMAP pObMemMap = NULL;
// already existing?
if(pProcess && pProcess->pObMemMap) {
return pProcess->pObMemMap->fValid;
}
EnterCriticalSection(&pProcess->LockUpdate);
if(pProcess && pProcess->pObMemMap) {
LeaveCriticalSection(&pProcess->LockUpdate);
return pProcess->pObMemMap->fValid;
}
// allocate temporary buffer and walk page tables
pObPML4 = VmmTlbGetPageTable(pProcess->paDTB, FALSE);
if(pObPML4) {
pMemMap = (PVMM_MEMMAP_ENTRY)LocalAlloc(LMEM_ZEROINIT, VMM_MEMMAP_ENTRIES_MAX * sizeof(VMM_MEMMAP_ENTRY));
if(pMemMap) {
MmX64_MapInitialize_Index(pProcess, pMemMap, &cMemMap, 0, 4, pObPML4->pqw, FALSE, ctxMain->dev.paMax);
for(i = 0; i < cMemMap; i++) { // fixup sign extension for kernel addresses
if(pMemMap[i].AddrBase & 0x0000800000000000) {
pMemMap[i].AddrBase |= 0xffff000000000000;
}
}
}
VmmOb_DECREF(pObPML4);
}
// allocate VmmOb depending on result
pObMemMap = VmmOb_Alloc('MM', 0, sizeof(VMMOB_MEMMAP) + cMemMap * sizeof(VMM_MEMMAP_ENTRY), MmX64_MapCloseObCallback, NULL);
if(!pObMemMap) {
LeaveCriticalSection(&pProcess->LockUpdate);
LocalFree(pMemMap);
return FALSE;
}
pObMemMap->fValid = cMemMap > 0;
pObMemMap->fTagModules = FALSE;
pObMemMap->fTagScan = FALSE;
pObMemMap->cMap = cMemMap;
pObMemMap->cbDisplay = cMemMap * MMX64_MEMMAP_DISPLAYBUFFER_LINE_LENGTH;
pObMemMap->pObDisplay = NULL;
if(cMemMap > 0) {
memcpy(pObMemMap->pMap, pMemMap, cMemMap * sizeof(VMM_MEMMAP_ENTRY));
}
LocalFree(pMemMap);
pProcess->pObMemMap = pObMemMap;
LeaveCriticalSection(&pProcess->LockUpdate);
return pObMemMap->fValid;
}
/*
* Map a tag into the sorted memory map in O(log2) operations. Supply only one
* of szTag or wszTag.
* Map a tag into the sorted memory map in O(log2) operations. Supply only one of szTag or wszTag.
* -- pProcess
* -- vaBase
* -- vaLimit = limit == vaBase + size (== top address in range +1)
* -- szTag
* -- wszTag
* -- fWoW64
* -- fOverwrite
*/
VOID MmX64_MapTag(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaBase, _In_ QWORD vaLimit, _In_opt_ LPSTR szTag, _In_opt_ LPWSTR wszTag, _In_opt_ BOOL fWoW64)
VOID MmX64_MapTag(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaBase, _In_ QWORD vaLimit, _In_opt_ LPSTR szTag, _In_opt_ LPWSTR wszTag, _In_ BOOL fWoW64, _In_ BOOL fOverwrite)
{
// NB! update here may take placey without acquiring the process 'LockUpdate'
// Data is not super important so it should be ok. Also, in many cases the
// lock will already be acquired by MapGetEntries function.
PVMM_MEMMAP_ENTRY pMap;
QWORD i, lvl, cMap;
pMap = pProcess->pMemMap;
cMap = pProcess->cMemMap;
if(!MmX64_MapInitialize(pProcess)) { return; }
pMap = pProcess->pObMemMap->pMap;
cMap = pProcess->pObMemMap->cMap;
if(!pMap || !cMap) { return; }
// 1: locate base
lvl = 1;
@@ -150,7 +271,7 @@ VOID MmX64_MapTag(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaBase, _In_ QWORD vaLi
}
// 3: fill in tag
while((i < cMap) && (pMap[i].AddrBase + (pMap[i].cPages << 12) <= vaLimit)) {
if(pMap[i].AddrBase >= vaBase) {
if((pMap[i].AddrBase >= vaBase) && (fOverwrite || !pMap[i].szTag[0])) {
pMap[i].fWoW64 = fWoW64;
if(wszTag) {
snprintf(pMap[i].szTag, 31, "%S", wszTag);
@@ -163,131 +284,107 @@ VOID MmX64_MapTag(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaBase, _In_ QWORD vaLi
}
}
VOID MmX64_MapDisplayBufferGenerate(_In_ PVMM_PROCESS pProcess)
_Success_(return)
BOOL MmX64_MapGetEntries(_In_ PVMM_PROCESS pProcess, _In_ DWORD flags, _Out_ PVMMOB_MEMMAP *ppObMemMap)
{
DWORD i;
PVMM_MODULEMAP_ENTRY pModule;
PVMMOB_MODULEMAP pObModuleMap;
if(!MmX64_MapInitialize(pProcess)) { return FALSE; }
if((!pProcess->pObMemMap->fTagModules && (flags & VMM_MEMMAP_FLAG_MODULES)) || (!pProcess->pObMemMap->fTagScan && (flags & VMM_MEMMAP_FLAG_SCAN))) {
EnterCriticalSection(&pProcess->LockUpdate);
if(!pProcess->pObMemMap->fTagModules && (flags & VMM_MEMMAP_FLAG_MODULES)) {
pProcess->pObMemMap->fTagModules = TRUE;
if(VmmProc_ModuleMapGet(pProcess, &pObModuleMap)) {
// update memory map with names
for(i = 0; i < pObModuleMap->cMap; i++) {
pModule = pObModuleMap->pMap + i;
MmX64_MapTag(pProcess, pModule->BaseAddress, pModule->BaseAddress + pModule->SizeOfImage, pModule->szName, NULL, pModule->fWoW64, FALSE);
}
VmmOb_DECREF(pObModuleMap);
}
}
if(!pProcess->pObMemMap->fTagScan && (flags & VMM_MEMMAP_FLAG_SCAN)) {
pProcess->pObMemMap->fTagScan = TRUE;
VmmProc_ScanTagsMemMap(pProcess);
}
LeaveCriticalSection(&pProcess->LockUpdate);
}
*ppObMemMap = VmmOb_INCREF(pProcess->pObMemMap);
return TRUE;
}
_Success_(return)
BOOL MmX64_MapGetDisplay(_In_ PVMM_PROCESS pProcess, _In_ DWORD flags, _Out_ PVMMOB_PDATA *ppObDisplay)
{
DWORD i, o = 0;
PBYTE pbBuffer;
if(!pProcess->cMemMap || !pProcess->pMemMap) { return; }
pProcess->cbMemMapDisplayCache = 0;
LocalFree(pProcess->pbMemMapDisplayCache);
pProcess->pbMemMapDisplayCache = NULL;
pbBuffer = LocalAlloc(LMEM_ZEROINIT, 89 * pProcess->cMemMap);
if(!pbBuffer) { return; }
for(i = 0; i < pProcess->cMemMap; i++) {
o += snprintf(
pbBuffer + o,
89,
"%04x %8x %016llx-%016llx %sr%s%s%s%s\n",
i,
(DWORD)pProcess->pMemMap[i].cPages,
pProcess->pMemMap[i].AddrBase,
pProcess->pMemMap[i].AddrBase + (pProcess->pMemMap[i].cPages << 12) - 1,
pProcess->pMemMap[i].fPage & VMM_MEMMAP_FLAG_PAGE_NS ? "-" : "s",
pProcess->pMemMap[i].fPage & VMM_MEMMAP_FLAG_PAGE_W ? "w" : "-",
pProcess->pMemMap[i].fPage & VMM_MEMMAP_FLAG_PAGE_NX ? "-" : "x",
pProcess->pMemMap[i].szTag[0] ? (pProcess->pMemMap[i].fWoW64 ? " 32 " : " ") : "",
pProcess->pMemMap[i].szTag
);
PVMMOB_MEMMAP pObMemMap = NULL;
PVMMOB_PDATA pObDisplay = NULL;
// memory map display data already exists
if(!MmX64_MapInitialize(pProcess)) { return FALSE; }
if(pProcess->pObMemMap->pObDisplay) {
*ppObDisplay = VmmOb_INCREF(pProcess->pObMemMap->pObDisplay);
return TRUE;
}
pProcess->pbMemMapDisplayCache = LocalAlloc(0, o);
if(!pProcess->pbMemMapDisplayCache) { goto fail; }
memcpy(pProcess->pbMemMapDisplayCache, pbBuffer, o);
pProcess->cbMemMapDisplayCache = o;
fail:
LocalFree(pbBuffer);
}
PVMM_MEMMAP_ENTRY MmX64_MapGetEntry(_In_ PVMM_PROCESS pProcess, _In_ QWORD va)
{
QWORD i, ce;
PVMM_MEMMAP_ENTRY pe;
if(!pProcess->pMemMap) { return NULL; }
ce = pProcess->cMemMap;
for(i = 0; i < ce; i++) {
pe = pProcess->pMemMap + i;
if((pe->AddrBase >= va) && (va <= pe->AddrBase + (pe->cPages << 12))) {
return pe;
}
}
return NULL;
}
const QWORD MMX64_PAGETABLEMAP_PML_REGION_SIZE[5] = { 0, 12, 21, 30, 39 };
VOID MmX64_MapInitialize_Index(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaBase, _In_ BYTE iPML, _In_ QWORD PTEs[512], _In_ BOOL fSupervisorPML, _In_ QWORD paMax)
{
PBYTE pbNextPageTable;
QWORD i, pte, va;
BOOL fUserOnly, fNextSupervisorPML;
QWORD cMemMap = pProcess->cMemMap;
PVMM_MEMMAP_ENTRY pMemMap = pProcess->pMemMap;
PVMM_MEMMAP_ENTRY pMemMapEntry = pMemMap + cMemMap - 1;
fUserOnly = pProcess->fUserOnly;
for(i = 0; i < 512; i++) {
pte = PTEs[i];
if(!(pte & 0x01)) { continue; }
if((pte & 0x0000fffffffff000) > paMax) { continue; }
if(fSupervisorPML) { pte = pte & 0xfffffffffffffffb; }
if(fUserOnly && !(pte & 0x04)) { continue; }
va = vaBase + (i << MMX64_PAGETABLEMAP_PML_REGION_SIZE[iPML]);
// maps page
if((iPML == 1) || (pte & 0x80) /* PS */) {
if(iPML == 4) { continue; } // not supported - PML4 cannot map page directly
if((cMemMap == 0) ||
(pMemMapEntry->fPage != (pte & VMM_MEMMAP_FLAG_PAGE_MASK)) ||
(va != pMemMapEntry->AddrBase + (pMemMapEntry->cPages << 12))) {
if(cMemMap + 1 >= VMM_MEMMAP_ENTRIES_MAX) { return; }
pMemMapEntry = pProcess->pMemMap + cMemMap;
pMemMapEntry->AddrBase = va;
pMemMapEntry->fPage = pte & VMM_MEMMAP_FLAG_PAGE_MASK;
pMemMapEntry->cPages = 1ULL << (MMX64_PAGETABLEMAP_PML_REGION_SIZE[iPML] - 12);
pProcess->cMemMap++;
cMemMap++;
continue;
// create new memory map display data
EnterCriticalSection(&pProcess->LockUpdate);
if(!pProcess->pObMemMap->pObDisplay) {
if(MmX64_MapGetEntries(pProcess, flags, &pObMemMap)) {
pObDisplay = VmmOb_Alloc('MD', LMEM_ZEROINIT, pObMemMap->cbDisplay, NULL, NULL);
if(pObDisplay) {
for(i = 0; i < pObMemMap->cMap; i++) {
if(o + MMX64_MEMMAP_DISPLAYBUFFER_LINE_LENGTH > pObMemMap->cbDisplay) {
vmmprintf_fn("ERROR: SHOULD NOT HAPPEN! LENGTH DIFFERS #1: %i %i\n", o + MMX64_MEMMAP_DISPLAYBUFFER_LINE_LENGTH, pObMemMap->cbDisplay);
VmmOb_DECREF(pObDisplay);
pObDisplay = NULL;
goto fail;
}
o += snprintf(
pObDisplay->pbData + o,
pObMemMap->cbDisplay - o - MMX64_MEMMAP_DISPLAYBUFFER_LINE_LENGTH,
"%04x %8x %016llx-%016llx %sr%s%s%s%-32s\n",
i,
(DWORD)pObMemMap->pMap[i].cPages,
pObMemMap->pMap[i].AddrBase,
pObMemMap->pMap[i].AddrBase + (pObMemMap->pMap[i].cPages << 12) - 1,
pObMemMap->pMap[i].fPage & VMM_MEMMAP_PAGE_NS ? "-" : "s",
pObMemMap->pMap[i].fPage & VMM_MEMMAP_PAGE_W ? "w" : "-",
pObMemMap->pMap[i].fPage & VMM_MEMMAP_PAGE_NX ? "-" : "x",
pObMemMap->pMap[i].szTag[0] ? (pObMemMap->pMap[i].fWoW64 ? " 32 " : " ") : " ",
pObMemMap->pMap[i].szTag
);
}
if(o != pObMemMap->cbDisplay) {
vmmprintf_fn("ERROR: SHOULD NOT HAPPEN! LENGTH DIFFERS #2: %i %i\n", o, pObMemMap->cbDisplay);
VmmOb_DECREF(pObDisplay);
pObDisplay = NULL;
goto fail;
}
}
pMemMapEntry->cPages += 1ULL << (MMX64_PAGETABLEMAP_PML_REGION_SIZE[iPML] - 12);
continue;
}
// maps page table (PDPT, PD, PT)
fNextSupervisorPML = !(pte & 0x04);
if(!(pbNextPageTable = VmmTlbGetPageTable(pte & 0x0000fffffffff000, FALSE))) { continue; }
MmX64_MapInitialize_Index(pProcess, va, iPML - 1, (PQWORD)pbNextPageTable, fNextSupervisorPML, paMax);
cMemMap = pProcess->cMemMap;
pMemMapEntry = pProcess->pMemMap + cMemMap - 1;
pProcess->pObMemMap->pObDisplay = pObDisplay;
}
}
VOID MmX64_MapInitialize(_In_ PVMM_PROCESS pProcess)
{
QWORD i, cMemMap;
PBYTE pbPML4;
pProcess->cbMemMapDisplayCache = 0;
LocalFree(pProcess->pbMemMapDisplayCache);
pProcess->pbMemMapDisplayCache = NULL;
LocalFree(pProcess->pMemMap);
pProcess->cMemMap = 0;
pProcess->pMemMap = (PVMM_MEMMAP_ENTRY)LocalAlloc(LMEM_ZEROINIT, VMM_MEMMAP_ENTRIES_MAX * sizeof(VMM_MEMMAP_ENTRY));
if(!pProcess->pMemMap) { return; }
pbPML4 = VmmTlbGetPageTable(pProcess->paDTB, FALSE);
if(!pbPML4) { return; }
MmX64_MapInitialize_Index(pProcess, 0, 4, (PQWORD)pbPML4, FALSE, ctxMain->cfg.paAddrMax);
cMemMap = pProcess->cMemMap;
for(i = 0; i < cMemMap; i++) { // fixup sign extension for kernel addresses
if(pProcess->pMemMap[i].AddrBase & 0x0000800000000000) {
pProcess->pMemMap[i].AddrBase |= 0xffff000000000000;
}
fail:
VmmOb_DECREF(pObMemMap);
LeaveCriticalSection(&pProcess->LockUpdate);
if(pProcess->pObMemMap->pObDisplay) {
*ppObDisplay = VmmOb_INCREF(pProcess->pObMemMap->pObDisplay);
return TRUE;
}
return FALSE;
}
_Success_(return)
BOOL MmX64_Virt2Phys(_In_ QWORD paPT, _In_ BOOL fUserOnly, _In_ BYTE iPML, _In_ QWORD va, _Out_ PQWORD ppa)
{
QWORD pte, i, qwMask;
PBYTE pbPTEs;
PVMMOB_MEM pObPTEs;
if(iPML == (BYTE)-1) { iPML = 4; }
if(!(pbPTEs = VmmTlbGetPageTable(paPT & 0x0000fffffffff000, FALSE))) { return FALSE; }
pObPTEs = VmmTlbGetPageTable(paPT & 0x0000fffffffff000, FALSE);
if(!pObPTEs) { return FALSE; }
i = 0x1ff & (va >> MMX64_PAGETABLEMAP_PML_REGION_SIZE[iPML]);
pte = ((PQWORD)pbPTEs)[i];
pte = pObPTEs->pqw[i];
VmmOb_DECREF(pObPTEs);
if(!(pte & 0x01)) { return FALSE; } // NOT VALID
if(fUserOnly && !(pte & 0x04)) { return FALSE; } // SUPERVISOR PAGE & USER MODE REQ
if(pte & 0x000f000000000000) { return FALSE; } // RESERVED
@@ -305,7 +402,7 @@ BOOL MmX64_Virt2Phys(_In_ QWORD paPT, _In_ BOOL fUserOnly, _In_ BYTE iPML, _In_
VOID MmX64_Virt2PhysGetInformation_DoWork(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo, _In_ BYTE iPML, _In_ QWORD PTEs[512])
{
QWORD pte, i, qwMask;
PBYTE pbNextPageTable;
PVMMOB_MEM pObNextPT;
i = 0x1ff & (pVirt2PhysInfo->va >> MMX64_PAGETABLEMAP_PML_REGION_SIZE[iPML]);
pte = PTEs[i];
pVirt2PhysInfo->iPTEs[iPML] = (WORD)i;
@@ -321,22 +418,26 @@ VOID MmX64_Virt2PhysGetInformation_DoWork(_Inout_ PVMM_PROCESS pProcess, _Inout_
pVirt2PhysInfo->pas[0] = pVirt2PhysInfo->pas[0] | (qwMask & pVirt2PhysInfo->va); // FILL LOWER ADDRESS BITS
return;
}
if(!(pbNextPageTable = VmmTlbGetPageTable(pte & 0x0000fffffffff000, FALSE))) { return; }
pObNextPT = VmmTlbGetPageTable(pte & 0x0000fffffffff000, FALSE);
if(!pObNextPT) { return; }
pVirt2PhysInfo->pas[iPML - 1] = pte & 0x0000fffffffff000;
MmX64_Virt2PhysGetInformation_DoWork(pProcess, pVirt2PhysInfo, iPML - 1, (PQWORD)pbNextPageTable);
MmX64_Virt2PhysGetInformation_DoWork(pProcess, pVirt2PhysInfo, iPML - 1, pObNextPT->pqw);
VmmOb_DECREF(pObNextPT);
}
VOID MmX64_Virt2PhysGetInformation(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo)
{
QWORD va;
PBYTE pbPML4;
PVMMOB_MEM pObPML4;
va = pVirt2PhysInfo->va;
ZeroMemory(pVirt2PhysInfo, sizeof(VMM_VIRT2PHYS_INFORMATION));
pVirt2PhysInfo->tpMemoryModel = VMM_MEMORYMODEL_X64;
pVirt2PhysInfo->va = va;
pVirt2PhysInfo->pas[4] = pProcess->paDTB;
if(!(pbPML4 = VmmTlbGetPageTable(pProcess->paDTB, FALSE))) { return; }
MmX64_Virt2PhysGetInformation_DoWork(pProcess, pVirt2PhysInfo, 4, (PQWORD)pbPML4);
pObPML4 = VmmTlbGetPageTable(pProcess->paDTB, FALSE);
if(!pObPML4) { return; }
MmX64_Virt2PhysGetInformation_DoWork(pProcess, pVirt2PhysInfo, 4, pObPML4->pqw);
VmmOb_DECREF(pObPML4);
}
VOID MmX64_Close()
@@ -351,14 +452,13 @@ VOID MmX64_Initialize()
if(ctxVmm->fnMemoryModel.pfnClose) {
ctxVmm->fnMemoryModel.pfnClose();
}
ctxVmm->fnMemoryModel.pfnInitialize = MmX64_Initialize;
ctxVmm->fnMemoryModel.pfnClose = MmX64_Close;
ctxVmm->fnMemoryModel.pfnVirt2Phys = MmX64_Virt2Phys;
ctxVmm->fnMemoryModel.pfnVirt2PhysGetInformation = MmX64_Virt2PhysGetInformation;
ctxVmm->fnMemoryModel.pfnMapInitialize = MmX64_MapInitialize;
ctxVmm->fnMemoryModel.pfnMapTag = MmX64_MapTag;
ctxVmm->fnMemoryModel.pfnMapGetEntry = MmX64_MapGetEntry;
ctxVmm->fnMemoryModel.pfnMapDisplayBufferGenerate = MmX64_MapDisplayBufferGenerate;
ctxVmm->fnMemoryModel.pfnMapGetEntries = MmX64_MapGetEntries;
ctxVmm->fnMemoryModel.pfnMapGetDisplay = MmX64_MapGetDisplay;
ctxVmm->fnMemoryModel.pfnTlbSpider = MmX64_TlbSpider;
ctxVmm->fnMemoryModel.pfnTlbPageTableVerify = MmX64_TlbPageTableVerify;
ctxVmm->tpMemoryModel = VMM_MEMORYMODEL_X64;
+1 -1
View File
@@ -1,6 +1,6 @@
// mm_x64.h : definitions related to the x64 / IA32e / long-mode paging / memory model.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
#ifndef __MM_X64_H__
+227 -133
View File
@@ -1,10 +1,12 @@
// mm_x86.c : implementation of the x86 32-bit protected mode memory model.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
#include "device.h"
#include "vmm.h"
#include "vmmproc.h"
#define MMX86_MEMMAP_DISPLAYBUFFER_LINE_LENGTH 70
/*
* Tries to verify that a loaded page table is correct. If just a bit strange
@@ -19,17 +21,17 @@ BOOL MmX86_TlbPageTableVerify(_Inout_ PBYTE pb, _In_ QWORD pa, _In_ BOOL fSelfRe
typedef struct tdMMX86_TLB_SPIDER_STAGE_INTERNAL {
QWORD c;
PMEM_IO_SCATTER_HEADER ppDMAs[VMMX64_TLB_SIZE_STAGEBUF];
PVMM_CACHE_ENTRY ppEntrys[VMMX64_TLB_SIZE_STAGEBUF];
PMEM_IO_SCATTER_HEADER ppMEMs[VMMX64_TLB_SIZE_STAGEBUF];
PVMMOB_MEM ppObMEMs[VMMX64_TLB_SIZE_STAGEBUF];
} MMX86_TLB_SPIDER_STAGE_INTERNAL, *PMMX86_TLB_SPIDER_STAGE_INTERNAL;
VOID MmX86_TlbSpider_ReadToCache(PMMX86_TLB_SPIDER_STAGE_INTERNAL pTlbSpiderStage)
{
QWORD i;
DeviceReadScatterMEM(pTlbSpiderStage->ppDMAs, (DWORD)pTlbSpiderStage->c, NULL);
LeechCore_ReadScatter(pTlbSpiderStage->ppMEMs, (DWORD)pTlbSpiderStage->c);
for(i = 0; i < pTlbSpiderStage->c; i++) {
MmX86_TlbPageTableVerify(pTlbSpiderStage->ppEntrys[i]->h.pb, pTlbSpiderStage->ppEntrys[i]->h.qwA, FALSE);
VmmCachePut(ctxVmm->ptTLB, pTlbSpiderStage->ppEntrys[i]);
MmX86_TlbPageTableVerify(pTlbSpiderStage->ppObMEMs[i]->h.pb, pTlbSpiderStage->ppObMEMs[i]->h.qwA, FALSE);
VmmCacheReserveReturn(pTlbSpiderStage->ppObMEMs[i]);
}
pTlbSpiderStage->c = 0;
}
@@ -37,48 +39,153 @@ VOID MmX86_TlbSpider_ReadToCache(PMMX86_TLB_SPIDER_STAGE_INTERNAL pTlbSpiderStag
/*
* Iterate over the PD to retrieve uncached PT pages and then commit them to the cache.
*/
VOID MmX86_TlbSpider(_In_ QWORD paDTB, _In_ BOOL fUserOnly)
VOID MmX86_TlbSpider(_In_ PVMM_PROCESS pProcess)
{
PBYTE pbPD;
PMMX86_TLB_SPIDER_STAGE_INTERNAL pTlbSpiderStage = NULL;
PVMMOB_MEM pObPD = NULL;
DWORD i, pte;
PMEM_IO_SCATTER_HEADER pt;
PMMX86_TLB_SPIDER_STAGE_INTERNAL pTlbSpiderStage;
if(pProcess->fTlbSpiderDone) { return; }
if(!(pTlbSpiderStage = (PMMX86_TLB_SPIDER_STAGE_INTERNAL)LocalAlloc(LMEM_ZEROINIT, sizeof(MMX86_TLB_SPIDER_STAGE_INTERNAL)))) { return; }
pbPD = VmmTlbGetPageTable(paDTB & 0xfffff000, FALSE);
if(!pbPD) { return; }
for(i = 0; i < 0x1000; i += 8) {
pte = *(PDWORD)(pbPD + i);
pObPD = VmmTlbGetPageTable(pProcess->paDTB & 0xfffff000, FALSE);
if(!pObPD) { goto fail; }
for(i = 0; i < 1024; i++) {
pte = pObPD->pdw[i];
if(!(pte & 0x01)) { continue; } // not valid
if(pte & 0x80) { continue; } // not valid ptr to PT
if(fUserOnly && !(pte & 0x04)) { continue; } // supervisor page when fUserOnly -> not valid
pt = VmmCacheGet(ctxVmm->ptTLB, pte & 0xfffff000);
if(!pt) {
pTlbSpiderStage->ppEntrys[pTlbSpiderStage->c] = VmmCacheReserve(ctxVmm->ptTLB);
pTlbSpiderStage->ppDMAs[pTlbSpiderStage->c] = &pTlbSpiderStage->ppEntrys[pTlbSpiderStage->c]->h;
pTlbSpiderStage->ppDMAs[pTlbSpiderStage->c]->qwA = pte & 0xfffff000;
if(pProcess->fUserOnly && !(pte & 0x04)) { continue; } // supervisor page when fUserOnly -> not valid
if(!VmmCacheExists(VMM_CACHE_TAG_TLB, pte & 0xfffff000)) {
pTlbSpiderStage->ppObMEMs[pTlbSpiderStage->c] = VmmCacheReserve(VMM_CACHE_TAG_TLB);
pTlbSpiderStage->ppMEMs[pTlbSpiderStage->c] = &pTlbSpiderStage->ppObMEMs[pTlbSpiderStage->c]->h;
pTlbSpiderStage->ppMEMs[pTlbSpiderStage->c]->qwA = pte & 0xfffff000;
pTlbSpiderStage->c++;
}
}
MmX86_TlbSpider_ReadToCache(pTlbSpiderStage);
pProcess->fTlbSpiderDone = TRUE;
fail:
LocalFree(pTlbSpiderStage);
VmmOb_DECREF(pObPD);
}
const QWORD MMX86_PAGETABLEMAP_PML_REGION_SIZE[3] = { 0, 12, 22 };
VOID MmX86_MapInitialize_Index(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MEMMAP_ENTRY pMemMap, _In_ PDWORD pcMemMap, _In_ DWORD vaBase, _In_ BYTE iPML, _In_ DWORD PTEs[1024], _In_ BOOL fSupervisorPML, _In_ QWORD paMax)
{
PVMMOB_MEM pObNextPT;
DWORD i, va, pte;
BOOL fUserOnly, fNextSupervisorPML;
PVMM_MEMMAP_ENTRY pMemMapEntry = pMemMap + *pcMemMap - 1;
fUserOnly = pProcess->fUserOnly;
for(i = 0; i < 1024; i++) {
pte = PTEs[i];
if(!(pte & 0x01)) { continue; }
if((pte & 0xfffff000) > paMax) { continue; }
if(fSupervisorPML) { pte = pte & 0xfffffffb; }
if(fUserOnly && !(pte & 0x04)) { continue; }
va = vaBase + (i << MMX86_PAGETABLEMAP_PML_REGION_SIZE[iPML]);
if((iPML == 1) || (pte & 0x80) /* PS */) {
if((*pcMemMap == 0) ||
(pMemMapEntry->fPage != (pte & VMM_MEMMAP_PAGE_MASK)) ||
(va != pMemMapEntry->AddrBase + (pMemMapEntry->cPages << 12))) {
if(*pcMemMap + 1 >= VMM_MEMMAP_ENTRIES_MAX) { return; }
pMemMapEntry = pMemMap + *pcMemMap;
pMemMapEntry->AddrBase = va;
pMemMapEntry->fPage = pte & VMM_MEMMAP_PAGE_MASK;
pMemMapEntry->cPages = 1ULL << (MMX86_PAGETABLEMAP_PML_REGION_SIZE[iPML] - 12);
*pcMemMap = *pcMemMap + 1;
if(*pcMemMap >= VMM_MEMMAP_ENTRIES_MAX - 1) { return; }
continue;
}
pMemMapEntry->cPages += 1ULL << (MMX86_PAGETABLEMAP_PML_REGION_SIZE[iPML] - 12);
continue;
}
// maps page table
fNextSupervisorPML = !(pte & 0x04);
pObNextPT = VmmTlbGetPageTable(pte & 0xfffff000, FALSE);
if(!pObNextPT) { continue; }
MmX86_MapInitialize_Index(pProcess, pMemMap, pcMemMap, va, 1, pObNextPT->pdw, fNextSupervisorPML, paMax);
VmmOb_DECREF(pObNextPT);
pMemMapEntry = pMemMap + *pcMemMap - 1;
}
}
VOID MmX86_MapCloseObCallback(_In_ PVOID pVmmOb)
{
PVMMOB_MEMMAP pObMemMap = (PVMMOB_MEMMAP)pVmmOb;
if(pObMemMap->pObDisplay) {
VmmOb_DECREF(pObMemMap->pObDisplay);
}
}
_Success_(return)
BOOL MmX86_MapInitialize(_In_ PVMM_PROCESS pProcess)
{
PVMMOB_MEM pObPD;
DWORD cMemMap = 0;
PVMM_MEMMAP_ENTRY pMemMap = NULL;
PVMMOB_MEMMAP pObMemMap = NULL;
// already existing?
if(pProcess && pProcess->pObMemMap) {
return pProcess->pObMemMap->fValid;
}
EnterCriticalSection(&pProcess->LockUpdate);
if(pProcess && pProcess->pObMemMap) {
LeaveCriticalSection(&pProcess->LockUpdate);
return pProcess->pObMemMap->fValid;
}
// allocate temporary buffer and walk page tables
VmmTlbSpider(pProcess);
pObPD = VmmTlbGetPageTable(pProcess->paDTB & 0xfffff000, FALSE);
if(pObPD) {
pMemMap = (PVMM_MEMMAP_ENTRY)LocalAlloc(LMEM_ZEROINIT, VMM_MEMMAP_ENTRIES_MAX * sizeof(VMM_MEMMAP_ENTRY));
if(pMemMap) {
MmX86_MapInitialize_Index(pProcess, pMemMap, &cMemMap, 0, 2, pObPD->pdw, FALSE, ctxMain->dev.paMax);
}
VmmOb_DECREF(pObPD);
}
// allocate VmmOb depending on result
pObMemMap = VmmOb_Alloc('MM', 0, sizeof(VMMOB_MEMMAP) + cMemMap * sizeof(VMM_MEMMAP_ENTRY), MmX86_MapCloseObCallback, NULL);
if(!pObMemMap) {
LeaveCriticalSection(&pProcess->LockUpdate);
LocalFree(pMemMap);
return FALSE;
}
pObMemMap->fValid = cMemMap > 0;
pObMemMap->fTagModules = FALSE;
pObMemMap->fTagScan = FALSE;
pObMemMap->cMap = cMemMap;
pObMemMap->cbDisplay = cMemMap * MMX86_MEMMAP_DISPLAYBUFFER_LINE_LENGTH;
pObMemMap->pObDisplay = NULL;
if(cMemMap > 0) {
memcpy(pObMemMap->pMap, pMemMap, cMemMap * sizeof(VMM_MEMMAP_ENTRY));
}
LocalFree(pMemMap);
pProcess->pObMemMap = pObMemMap;
LeaveCriticalSection(&pProcess->LockUpdate);
return pObMemMap->fValid;
}
/*
* Map a tag into the sorted memory map in O(log2) operations. Supply only one
* of szTag or wszTag.
* Map a tag into the sorted memory map in O(log2) operations. Supply only one of szTag or wszTag.
* -- pProcess
* -- vaBase
* -- vaLimit = limit == vaBase + size (== top address in range +1)
* -- szTag
* -- wszTag
* -- fWoW64
* -- fOverwrite
*/
VOID MmX86_MapTag(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaBase, _In_ QWORD vaLimit, _In_opt_ LPSTR szTag, _In_opt_ LPWSTR wszTag, _In_opt_ BOOL fWoW64)
VOID MmX86_MapTag(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaBase, _In_ QWORD vaLimit, _In_opt_ LPSTR szTag, _In_opt_ LPWSTR wszTag, _In_ BOOL fWoW64, _In_ BOOL fOverwrite)
{
// NB! update here may take placey without acquiring the process 'LockUpdate'
// Data is not super important so it should be ok. Also, in many cases the
// lock will already be acquired by MapGetEntries function.
PVMM_MEMMAP_ENTRY pMap;
QWORD i, lvl, cMap;
if(!MmX86_MapInitialize(pProcess)) { return; }
if((vaBase > 0xffffffff) || (vaLimit > 0xffffffff)) { return; }
pMap = pProcess->pMemMap;
cMap = pProcess->cMemMap;
pMap = pProcess->pObMemMap->pMap;
cMap = pProcess->pObMemMap->cMap;
if(!pMap || !cMap) { return; }
// 1: locate base
lvl = 1;
@@ -100,7 +207,7 @@ VOID MmX86_MapTag(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaBase, _In_ QWORD vaLi
}
// 3: fill in tag
while((i < cMap) && (pMap[i].AddrBase + (pMap[i].cPages << 12) <= vaLimit)) {
if(pMap[i].AddrBase >= vaBase) {
if((pMap[i].AddrBase >= vaBase) && (fOverwrite || !pMap[i].szTag[0])) {
if(wszTag) {
snprintf(pMap[i].szTag, 31, "%S", wszTag);
}
@@ -112,121 +219,108 @@ VOID MmX86_MapTag(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaBase, _In_ QWORD vaLi
}
}
VOID MmX86_MapDisplayBufferGenerate(_In_ PVMM_PROCESS pProcess)
_Success_(return)
BOOL MmX86_MapGetEntries(_In_ PVMM_PROCESS pProcess, _In_ DWORD flags, _Out_ PVMMOB_MEMMAP *ppObMemMap)
{
DWORD i;
PVMM_MODULEMAP_ENTRY pModule;
PVMMOB_MODULEMAP pObModuleMap;
if(!MmX86_MapInitialize(pProcess)) { return FALSE; }
if((!pProcess->pObMemMap->fTagModules && (flags & VMM_MEMMAP_FLAG_MODULES)) || (!pProcess->pObMemMap->fTagScan && (flags & VMM_MEMMAP_FLAG_SCAN))) {
EnterCriticalSection(&pProcess->LockUpdate);
if(!pProcess->pObMemMap->fTagModules && (flags & VMM_MEMMAP_FLAG_MODULES)) {
pProcess->pObMemMap->fTagModules = TRUE;
if(VmmProc_ModuleMapGet(pProcess, &pObModuleMap)) {
// update memory map with names
for(i = 0; i < pObModuleMap->cMap; i++) {
pModule = pObModuleMap->pMap + i;
MmX86_MapTag(pProcess, pModule->BaseAddress, pModule->BaseAddress + pModule->SizeOfImage, pModule->szName, NULL, FALSE, FALSE);
}
VmmOb_DECREF(pObModuleMap);
}
}
if(!pProcess->pObMemMap->fTagScan && (flags & VMM_MEMMAP_FLAG_SCAN)) {
pProcess->pObMemMap->fTagScan = TRUE;
VmmProc_ScanTagsMemMap(pProcess);
}
LeaveCriticalSection(&pProcess->LockUpdate);
}
*ppObMemMap = VmmOb_INCREF(pProcess->pObMemMap);
return TRUE;
}
_Success_(return)
BOOL MmX86_MapGetDisplay(_In_ PVMM_PROCESS pProcess, _In_ DWORD flags, _Out_ PVMMOB_PDATA *ppObDisplay)
{
DWORD i, o = 0;
PBYTE pbBuffer;
if(!pProcess->cMemMap || !pProcess->pMemMap) { return; }
pProcess->cbMemMapDisplayCache = 0;
LocalFree(pProcess->pbMemMapDisplayCache);
pProcess->pbMemMapDisplayCache = NULL;
pbBuffer = LocalAlloc(LMEM_ZEROINIT, 70 * pProcess->cMemMap);
if(!pbBuffer) { return; }
for(i = 0; i < pProcess->cMemMap; i++) {
o += snprintf(
pbBuffer + o,
70,
"%04x %8x %08x-%08x %sr%sx %s\n",
i,
(DWORD)pProcess->pMemMap[i].cPages,
(DWORD)pProcess->pMemMap[i].AddrBase,
(DWORD)(pProcess->pMemMap[i].AddrBase + (pProcess->pMemMap[i].cPages << 12) - 1),
pProcess->pMemMap[i].fPage & VMM_MEMMAP_FLAG_PAGE_NS ? "-" : "s",
pProcess->pMemMap[i].fPage & VMM_MEMMAP_FLAG_PAGE_W ? "w" : "-",
pProcess->pMemMap[i].szTag
);
PVMMOB_MEMMAP pObMemMap = NULL;
PVMMOB_PDATA pObDisplay = NULL;
// memory map display data already exists
if(!MmX86_MapInitialize(pProcess)) { return FALSE; }
if(pProcess->pObMemMap->pObDisplay) {
*ppObDisplay = VmmOb_INCREF(pProcess->pObMemMap->pObDisplay);
return TRUE;
}
pProcess->pbMemMapDisplayCache = LocalAlloc(0, o);
if(!pProcess->pbMemMapDisplayCache) { goto fail; }
memcpy(pProcess->pbMemMapDisplayCache, pbBuffer, o);
pProcess->cbMemMapDisplayCache = o;
fail:
LocalFree(pbBuffer);
}
PVMM_MEMMAP_ENTRY MmX86_MapGetEntry(_In_ PVMM_PROCESS pProcess, _In_ QWORD va)
{
QWORD i, ce;
PVMM_MEMMAP_ENTRY pe;
if(!pProcess->pMemMap) { return NULL; }
ce = pProcess->cMemMap;
for(i = 0; i < ce; i++) {
pe = pProcess->pMemMap + i;
if((pe->AddrBase >= va) && (va <= pe->AddrBase + (pe->cPages << 12))) {
return pe;
}
}
return NULL;
}
const QWORD MMX86_PAGETABLEMAP_PML_REGION_SIZE[3] = { 0, 12, 22 };
VOID MmX86_MapInitialize_Index(_In_ PVMM_PROCESS pProcess, _In_ DWORD vaBase, _In_ BYTE iPML, _In_ DWORD PTEs[1024], _In_ BOOL fSupervisorPML, _In_ QWORD paMax)
{
PBYTE pbNextPageTable;
DWORD i, va, pte;
BOOL fUserOnly, fNextSupervisorPML;
QWORD cMemMap = pProcess->cMemMap;
PVMM_MEMMAP_ENTRY pMemMap = pProcess->pMemMap;
PVMM_MEMMAP_ENTRY pMemMapEntry = pMemMap + cMemMap - 1;
fUserOnly = pProcess->fUserOnly;
for(i = 0; i < 1024; i++) {
pte = PTEs[i];
if(!(pte & 0x01)) { continue; }
if((pte & 0xfffff000) > paMax) { continue; }
if(fSupervisorPML) { pte = pte & 0xfffffffb; }
if(fUserOnly && !(pte & 0x04)) { continue; }
va = vaBase + (i << MMX86_PAGETABLEMAP_PML_REGION_SIZE[iPML]);
if((iPML == 1) || (pte & 0x80) /* PS */) {
if((cMemMap == 0) ||
(pMemMapEntry->fPage != (pte & VMM_MEMMAP_FLAG_PAGE_MASK)) ||
(va != pMemMapEntry->AddrBase + (pMemMapEntry->cPages << 12))) {
if(cMemMap + 1 >= VMM_MEMMAP_ENTRIES_MAX) { return; }
pMemMapEntry = pProcess->pMemMap + cMemMap;
pMemMapEntry->AddrBase = va;
pMemMapEntry->fPage = pte & VMM_MEMMAP_FLAG_PAGE_MASK;
pMemMapEntry->cPages = 1ULL << (MMX86_PAGETABLEMAP_PML_REGION_SIZE[iPML] - 12);
pProcess->cMemMap++;
cMemMap++;
continue;
// create new memory map display data
EnterCriticalSection(&pProcess->LockUpdate);
if(!pProcess->pObMemMap->pObDisplay) {
if(MmX86_MapGetEntries(pProcess, flags, &pObMemMap)) {
pObDisplay = VmmOb_Alloc('MD', LMEM_ZEROINIT, pObMemMap->cbDisplay, NULL, NULL);
if(pObDisplay) {
for(i = 0; i < pObMemMap->cMap; i++) {
if(o + MMX86_MEMMAP_DISPLAYBUFFER_LINE_LENGTH > pObMemMap->cbDisplay) {
vmmprintf_fn("ERROR: SHOULD NOT HAPPEN! LENGTH DIFFERS #1: %i %i\n", o + MMX86_MEMMAP_DISPLAYBUFFER_LINE_LENGTH, pObMemMap->cbDisplay);
VmmOb_DECREF(pObDisplay);
pObDisplay = NULL;
goto fail;
}
o += snprintf(
pObDisplay->pbData + o,
pObMemMap->cbDisplay - o - MMX86_MEMMAP_DISPLAYBUFFER_LINE_LENGTH,
"%04x %8x %08x-%08x %sr%sx %-32s\n",
i,
(DWORD)pObMemMap->pMap[i].cPages,
(DWORD)pObMemMap->pMap[i].AddrBase,
(DWORD)(pObMemMap->pMap[i].AddrBase + (pObMemMap->pMap[i].cPages << 12) - 1),
pObMemMap->pMap[i].fPage & VMM_MEMMAP_PAGE_NS ? "-" : "s",
pObMemMap->pMap[i].fPage & VMM_MEMMAP_PAGE_W ? "w" : "-",
pObMemMap->pMap[i].szTag
);
}
if(o != pObMemMap->cbDisplay) {
vmmprintf_fn("ERROR: SHOULD NOT HAPPEN! LENGTH DIFFERS #2: %i %i\n", o, pObMemMap->cbDisplay);
VmmOb_DECREF(pObDisplay);
pObDisplay = NULL;
goto fail;
}
}
pMemMapEntry->cPages += 1ULL << (MMX86_PAGETABLEMAP_PML_REGION_SIZE[iPML] - 12);
continue;
}
// maps page table
fNextSupervisorPML = !(pte & 0x04);
if(!(pbNextPageTable = VmmTlbGetPageTable(pte & 0xfffff000, FALSE))) { continue; }
MmX86_MapInitialize_Index(pProcess, va, 1, (PDWORD)pbNextPageTable, fNextSupervisorPML, paMax);
cMemMap = pProcess->cMemMap;
pMemMapEntry = pProcess->pMemMap + cMemMap - 1;
pProcess->pObMemMap->pObDisplay = pObDisplay;
}
}
VOID MmX86_MapInitialize(_In_ PVMM_PROCESS pProcess)
{
PBYTE pbPD;
pProcess->cbMemMapDisplayCache = 0;
LocalFree(pProcess->pbMemMapDisplayCache);
pProcess->pbMemMapDisplayCache = NULL;
LocalFree(pProcess->pMemMap);
pProcess->cMemMap = 0;
pProcess->pMemMap = (PVMM_MEMMAP_ENTRY)LocalAlloc(LMEM_ZEROINIT, VMM_MEMMAP_ENTRIES_MAX * sizeof(VMM_MEMMAP_ENTRY));
if(!pProcess->pMemMap) { return; }
if(!(pbPD = VmmTlbGetPageTable(pProcess->paDTB & 0xfffff000, FALSE))) { return; }
MmX86_MapInitialize_Index(pProcess, 0, 2, (PDWORD)pbPD, FALSE, ctxMain->cfg.paAddrMax);
fail:
VmmOb_DECREF(pObMemMap);
LeaveCriticalSection(&pProcess->LockUpdate);
if(pProcess->pObMemMap->pObDisplay) {
*ppObDisplay = VmmOb_INCREF(pProcess->pObMemMap->pObDisplay);
return TRUE;
}
return FALSE;
}
_Success_(return)
BOOL MmX86_Virt2Phys(_In_ QWORD paPT, _In_ BOOL fUserOnly, _In_ BYTE iPML, _In_ QWORD va, _Out_ PQWORD ppa)
{
DWORD pte, i;
PBYTE pbPTEs;
PVMMOB_MEM pObPTEs;
//PBYTE pbPTEs;
if(va > 0xffffffff) { return FALSE; }
if(paPT > 0xffffffff) { return FALSE; }
if(iPML == (BYTE)-1) { iPML = 2; }
if(!(pbPTEs = VmmTlbGetPageTable(paPT & 0xfffff000, FALSE))) { return FALSE; }
pObPTEs = VmmTlbGetPageTable(paPT & 0xfffff000, FALSE);
if(!pObPTEs) { return FALSE; }
i = 0x3ff & (va >> MMX86_PAGETABLEMAP_PML_REGION_SIZE[iPML]);
pte = ((PDWORD)pbPTEs)[i];
pte = pObPTEs->pdw[i];
VmmOb_DECREF(pObPTEs);
if(!(pte & 0x01)) { return FALSE; } // NOT VALID
if(fUserOnly && !(pte & 0x04)) { return FALSE; } // SUPERVISOR PAGE & USER MODE REQ
if((iPML == 2) && !(pte & 0x80) /* PS */) {
@@ -244,11 +338,13 @@ BOOL MmX86_Virt2Phys(_In_ QWORD paPT, _In_ BOOL fUserOnly, _In_ BYTE iPML, _In_
VOID MmX86_Virt2PhysGetInformation_DoWork(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo, _In_ BYTE iPML, _In_ QWORD paPT)
{
PDWORD PTEs;
PVMMOB_MEM pObPTEs;
DWORD pte, i;
if(!(PTEs = (PDWORD)VmmTlbGetPageTable(paPT, FALSE))) { return; }
pObPTEs = VmmTlbGetPageTable(paPT, FALSE);
if(!pObPTEs) { return; }
i = 0x3ff & (pVirt2PhysInfo->va >> MMX86_PAGETABLEMAP_PML_REGION_SIZE[iPML]);
pte = PTEs[i];
pte = pObPTEs->pdw[i];
VmmOb_DECREF(pObPTEs);
pVirt2PhysInfo->pas[iPML] = paPT;
pVirt2PhysInfo->iPTEs[iPML] = (WORD)i;
pVirt2PhysInfo->PTEs[iPML] = pte;
@@ -289,14 +385,12 @@ VOID MmX86_Initialize()
if(ctxVmm->fnMemoryModel.pfnClose) {
ctxVmm->fnMemoryModel.pfnClose();
}
ctxVmm->fnMemoryModel.pfnInitialize = MmX86_Initialize;
ctxVmm->fnMemoryModel.pfnClose = MmX86_Close;
ctxVmm->fnMemoryModel.pfnVirt2Phys = MmX86_Virt2Phys;
ctxVmm->fnMemoryModel.pfnVirt2PhysGetInformation = MmX86_Virt2PhysGetInformation;
ctxVmm->fnMemoryModel.pfnMapInitialize = MmX86_MapInitialize;
ctxVmm->fnMemoryModel.pfnMapTag = MmX86_MapTag;
ctxVmm->fnMemoryModel.pfnMapGetEntry = MmX86_MapGetEntry;
ctxVmm->fnMemoryModel.pfnMapDisplayBufferGenerate = MmX86_MapDisplayBufferGenerate;
ctxVmm->fnMemoryModel.pfnMapGetEntries = MmX86_MapGetEntries;
ctxVmm->fnMemoryModel.pfnMapGetDisplay = MmX86_MapGetDisplay;
ctxVmm->fnMemoryModel.pfnTlbSpider = MmX86_TlbSpider;
ctxVmm->fnMemoryModel.pfnTlbPageTableVerify = MmX86_TlbPageTableVerify;
ctxVmm->tpMemoryModel = VMM_MEMORYMODEL_X86;
+1 -1
View File
@@ -1,6 +1,6 @@
// mm_x86.h : definitions related to the x86 32-bit protected mode memory model.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
#ifndef __MM_X86_H__
+256 -148
View File
@@ -1,10 +1,12 @@
// mm_x86pae.c : implementation of the x86 PAE (Physical Address Extension) 32-bit protected mode memory model.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
#include "device.h"
#include "vmm.h"
#include "vmmproc.h"
#define MMX86PAE_MEMMAP_DISPLAYBUFFER_LINE_LENGTH 70
/*
* Tries to verify that a loaded page table is correct. If just a bit strange
@@ -19,17 +21,17 @@ BOOL MmX86PAE_TlbPageTableVerify(_Inout_ PBYTE pb, _In_ QWORD pa, _In_ BOOL fSel
typedef struct tdMMX86PAE_TLB_SPIDER_STAGE_INTERNAL {
QWORD c;
PMEM_IO_SCATTER_HEADER ppDMAs[VMMX64_TLB_SIZE_STAGEBUF];
PVMM_CACHE_ENTRY ppEntrys[VMMX64_TLB_SIZE_STAGEBUF];
PMEM_IO_SCATTER_HEADER ppMEMs[VMMX64_TLB_SIZE_STAGEBUF];
PVMMOB_MEM ppObMEMs[VMMX64_TLB_SIZE_STAGEBUF];
} MMX86PAE_TLB_SPIDER_STAGE_INTERNAL, *PMMX86PAE_TLB_SPIDER_STAGE_INTERNAL;
VOID MmX86PAE_TlbSpider_ReadToCache(PMMX86PAE_TLB_SPIDER_STAGE_INTERNAL pTlbSpiderStage)
{
QWORD i;
DeviceReadScatterMEM(pTlbSpiderStage->ppDMAs, (DWORD)pTlbSpiderStage->c, NULL);
LeechCore_ReadScatter(pTlbSpiderStage->ppMEMs, (DWORD)pTlbSpiderStage->c);
for(i = 0; i < pTlbSpiderStage->c; i++) {
MmX86PAE_TlbPageTableVerify(pTlbSpiderStage->ppEntrys[i]->h.pb, pTlbSpiderStage->ppEntrys[i]->h.qwA, FALSE);
VmmCachePut(ctxVmm->ptTLB, pTlbSpiderStage->ppEntrys[i]);
MmX86PAE_TlbPageTableVerify(pTlbSpiderStage->ppObMEMs[i]->h.pb, pTlbSpiderStage->ppObMEMs[i]->h.qwA, FALSE);
VmmCacheReserveReturn(pTlbSpiderStage->ppObMEMs[i]);
}
pTlbSpiderStage->c = 0;
}
@@ -37,41 +39,46 @@ VOID MmX86PAE_TlbSpider_ReadToCache(PMMX86PAE_TLB_SPIDER_STAGE_INTERNAL pTlbSpid
BOOL MmX86PAE_TlbSpider_PD_PT(_In_ QWORD pa, _In_ BYTE iPML, _In_ BOOL fUserOnly, PMMX86PAE_TLB_SPIDER_STAGE_INTERNAL pTlbSpiderStage)
{
BOOL fSpiderComplete = TRUE;
PMEM_IO_SCATTER_HEADER pt;
PVMMOB_MEM pObPT;
QWORD i, pte;
// 1: retrieve from cache, add to staging if not found
pt = VmmCacheGet(ctxVmm->ptTLB, pa);
if(!pt) {
pTlbSpiderStage->ppEntrys[pTlbSpiderStage->c] = VmmCacheReserve(ctxVmm->ptTLB);
pTlbSpiderStage->ppDMAs[pTlbSpiderStage->c] = &pTlbSpiderStage->ppEntrys[pTlbSpiderStage->c]->h;
pTlbSpiderStage->ppDMAs[pTlbSpiderStage->c]->qwA = pa;
pObPT = VmmCacheGet(VMM_CACHE_TAG_TLB, pa);
if(!pObPT) {
pTlbSpiderStage->ppObMEMs[pTlbSpiderStage->c] = VmmCacheReserve(VMM_CACHE_TAG_TLB);
pTlbSpiderStage->ppMEMs[pTlbSpiderStage->c] = &pTlbSpiderStage->ppObMEMs[pTlbSpiderStage->c]->h;
pTlbSpiderStage->ppMEMs[pTlbSpiderStage->c]->qwA = pa;
pTlbSpiderStage->c++;
if(pTlbSpiderStage->c == VMMX64_TLB_SIZE_STAGEBUF) {
MmX86PAE_TlbSpider_ReadToCache(pTlbSpiderStage);
}
return FALSE;
}
if(iPML == 1) { return TRUE; }
if(iPML == 1) {
VmmOb_DECREF(pObPT);
return TRUE;
}
// 2: walk trough all entries for PD
for(i = 0; i < 0x1000; i += 8) {
pte = *(PQWORD)(pt->pb + i);
for(i = 0; i < 512; i++) {
pte = pObPT->pqw[i];
if(!(pte & 0x01)) { continue; } // not valid
if(pte & 0x80) { continue; } // not valid ptr to PT
if(fUserOnly && !(pte & 0x04)) { continue; } // supervisor page when fUserOnly -> not valid
fSpiderComplete = MmX86PAE_TlbSpider_PD_PT(pte & 0x0000fffffffff000, 1, fUserOnly, pTlbSpiderStage) && fSpiderComplete;
}
VmmOb_DECREF(pObPT);
return fSpiderComplete;
}
BOOL MmX86PAE_TlbSpider_PDPT(_In_ QWORD paDTB, _In_ BOOL fUserOnly, PMMX86PAE_TLB_SPIDER_STAGE_INTERNAL pTlbSpiderStage)
{
BOOL fSpiderComplete = TRUE;
QWORD i, pte;
PVMMOB_MEM pObPDPT;
PBYTE pbPDPT;
QWORD i, pte;
// 1: retrieve PDPT
pbPDPT = VmmTlbGetPageTable(paDTB & 0xfffff000, FALSE);
if(!pbPDPT) { return FALSE; }
pbPDPT += paDTB & 0xfe0;
pObPDPT = VmmTlbGetPageTable(paDTB & 0xfffff000, FALSE);
if(!pObPDPT) { return FALSE; }
pbPDPT = pObPDPT->pb + (paDTB & 0xfe0);
// 2: walk through all four (4) PDPTEs
for(i = 0; i < 0x20; i += 8) {
pte = *(PQWORD)(pbPDPT + i);
@@ -79,6 +86,7 @@ BOOL MmX86PAE_TlbSpider_PDPT(_In_ QWORD paDTB, _In_ BOOL fUserOnly, PMMX86PAE_TL
if(pte & 0xffff0000000001e6) { continue; } // RESERVED BITS IN PDPTE
fSpiderComplete = MmX86PAE_TlbSpider_PD_PT(pte & 0x0000fffffffff000, 2, fUserOnly, pTlbSpiderStage) && fSpiderComplete;
}
VmmOb_DECREF(pObPDPT);
return fSpiderComplete;
}
@@ -86,38 +94,155 @@ BOOL MmX86PAE_TlbSpider_PDPT(_In_ QWORD paDTB, _In_ BOOL fUserOnly, PMMX86PAE_TL
* Iterate over PTPT, PD (3 times in total) to first stage uncached pages
* and then commit them to the cache.
*/
VOID MmX86PAE_TlbSpider(_In_ QWORD paDTB, _In_ BOOL fUserOnly)
VOID MmX86PAE_TlbSpider(_In_ PVMM_PROCESS pProcess)
{
DWORD i = 0;
BOOL result = FALSE;
PMMX86PAE_TLB_SPIDER_STAGE_INTERNAL pTlbSpiderStage;
if(pProcess->fTlbSpiderDone) { return; }
if(!(pTlbSpiderStage = (PMMX86PAE_TLB_SPIDER_STAGE_INTERNAL)LocalAlloc(LMEM_ZEROINIT, sizeof(MMX86PAE_TLB_SPIDER_STAGE_INTERNAL)))) { return; }
while(!result && (i < 3)) {
result = MmX86PAE_TlbSpider_PDPT(paDTB, fUserOnly, pTlbSpiderStage);
result = MmX86PAE_TlbSpider_PDPT(pProcess->paDTB, pProcess->fUserOnly, pTlbSpiderStage);
if(pTlbSpiderStage->c) {
MmX86PAE_TlbSpider_ReadToCache(pTlbSpiderStage);
}
i++;
}
LocalFree(pTlbSpiderStage);
pProcess->fTlbSpiderDone = TRUE;
}
const QWORD MMX86PAE_PAGETABLEMAP_PML_REGION_SIZE[4] = { 0, 12, 21, 30 };
VOID MmX86PAE_MapInitialize_Index(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MEMMAP_ENTRY pMemMap, _In_ PDWORD pcMemMap, _In_ DWORD vaBase, _In_ BYTE iPML, _In_ QWORD PTEs[512], _In_ BOOL fSupervisorPML, _In_ QWORD paMax)
{
PVMMOB_MEM pObNextPT;
DWORD i, va;
QWORD pte;
BOOL fUserOnly, fNextSupervisorPML;
PVMM_MEMMAP_ENTRY pMemMapEntry = pMemMap + *pcMemMap - 1;
fUserOnly = pProcess->fUserOnly;
for(i = 0; i < 512; i++) {
if((iPML == 3) && (i > 3)) { break; } // MAX 4 ENTRIES IN PDPT
pte = PTEs[i];
if(!(pte & 0x01)) { continue; }
if((pte & 0x0000fffffffff000) > paMax) { continue; }
if(iPML == 3) {
// PDPT: (iPML = 3)
if(pte & 0xffff0000000001e6) { continue; } // RESERVED BITS IN PDPTE
va = i * 0x40000000;
} else {
// PT or PD: (iPML = 1..2)
if(fSupervisorPML) { pte = pte & 0xfffffffffffffffb; }
if(fUserOnly && !(pte & 0x04)) { continue; }
va = vaBase + (i << MMX86PAE_PAGETABLEMAP_PML_REGION_SIZE[iPML]);
// maps page
if((iPML == 1) || (pte & 0x80) /* PS */) {
if((*pcMemMap == 0) ||
(pMemMapEntry->fPage != (pte & VMM_MEMMAP_PAGE_MASK)) ||
(va != pMemMapEntry->AddrBase + (pMemMapEntry->cPages << 12))) {
if(*pcMemMap + 1 >= VMM_MEMMAP_ENTRIES_MAX) { return; }
pMemMapEntry = pMemMap + *pcMemMap;
pMemMapEntry->AddrBase = va;
pMemMapEntry->fPage = pte & VMM_MEMMAP_PAGE_MASK;
pMemMapEntry->cPages = 1ULL << (MMX86PAE_PAGETABLEMAP_PML_REGION_SIZE[iPML] - 12);
*pcMemMap = *pcMemMap + 1;
if(*pcMemMap >= VMM_MEMMAP_ENTRIES_MAX - 1) { return; }
continue;
}
pMemMapEntry->cPages += 1ULL << (MMX86PAE_PAGETABLEMAP_PML_REGION_SIZE[iPML] - 12);
continue;
}
}
// maps page table (PD, PT)
fNextSupervisorPML = (iPML != 3) && !(pte & 0x04);
pObNextPT = VmmTlbGetPageTable(pte & 0x0000fffffffff000, FALSE);
if(!pObNextPT) { continue; }
MmX86PAE_MapInitialize_Index(pProcess, pMemMap, pcMemMap, va, iPML - 1, pObNextPT->pqw, fNextSupervisorPML, paMax);
VmmOb_DECREF(pObNextPT);
pMemMapEntry = pMemMap + *pcMemMap - 1;
}
}
VOID MmX86PAE_MapCloseObCallback(_In_ PVOID pVmmOb)
{
PVMMOB_MEMMAP pObMemMap = (PVMMOB_MEMMAP)pVmmOb;
if(pObMemMap->pObDisplay) {
VmmOb_DECREF(pObMemMap->pObDisplay);
}
}
_Success_(return)
BOOL MmX86PAE_MapInitialize(_In_ PVMM_PROCESS pProcess)
{
DWORD cMemMap = 0;
PBYTE pbPDPT;
PVMMOB_MEM pObPDPT;
PVMM_MEMMAP_ENTRY pMemMap = NULL;
PVMMOB_MEMMAP pObMemMap = NULL;
// already existing?
if(pProcess && pProcess->pObMemMap) {
return pProcess->pObMemMap->fValid;
}
EnterCriticalSection(&pProcess->LockUpdate);
if(pProcess && pProcess->pObMemMap) {
LeaveCriticalSection(&pProcess->LockUpdate);
return pProcess->pObMemMap->fValid;
}
// allocate temporary buffer and walk page tables
VmmTlbSpider(pProcess);
pObPDPT = VmmTlbGetPageTable(pProcess->paDTB & 0xfffff000, FALSE);
if(pObPDPT) {
pMemMap = (PVMM_MEMMAP_ENTRY)LocalAlloc(LMEM_ZEROINIT, VMM_MEMMAP_ENTRIES_MAX * sizeof(VMM_MEMMAP_ENTRY));
if(pMemMap) {
pbPDPT = pObPDPT->pb + (pProcess->paDTB & 0xfe0); // ADJUST PDPT TO 32-BYTE BOUNDARY
MmX86PAE_MapInitialize_Index(pProcess, pMemMap, &cMemMap, 0, 3, (PQWORD)pbPDPT, FALSE, ctxMain->dev.paMax);
}
VmmOb_DECREF(pObPDPT);
}
// allocate VmmOb depending on result
pObMemMap = VmmOb_Alloc('MM', 0, sizeof(VMMOB_MEMMAP) + cMemMap * sizeof(VMM_MEMMAP_ENTRY), MmX86PAE_MapCloseObCallback, NULL);
if(!pObMemMap) {
LeaveCriticalSection(&pProcess->LockUpdate);
LocalFree(pMemMap);
return FALSE;
}
pObMemMap->fValid = cMemMap > 0;
pObMemMap->fTagModules = FALSE;
pObMemMap->fTagScan = FALSE;
pObMemMap->cMap = cMemMap;
pObMemMap->cbDisplay = cMemMap * MMX86PAE_MEMMAP_DISPLAYBUFFER_LINE_LENGTH;
pObMemMap->pObDisplay = NULL;
if(cMemMap > 0) {
memcpy(pObMemMap->pMap, pMemMap, cMemMap * sizeof(VMM_MEMMAP_ENTRY));
}
LocalFree(pMemMap);
pProcess->pObMemMap = pObMemMap;
LeaveCriticalSection(&pProcess->LockUpdate);
return pObMemMap->fValid;
}
/*
* Map a tag into the sorted memory map in O(log2) operations. Supply only one
* of szTag or wszTag.
* Map a tag into the sorted memory map in O(log2) operations. Supply only one of szTag or wszTag.
* -- pProcess
* -- vaBase
* -- vaLimit = limit == vaBase + size (== top address in range +1)
* -- szTag
* -- wszTag
* -- fWoW64
* -- fOverwrite
*/
VOID MmX86PAE_MapTag(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaBase, _In_ QWORD vaLimit, _In_opt_ LPSTR szTag, _In_opt_ LPWSTR wszTag, _In_opt_ BOOL fWoW64)
VOID MmX86PAE_MapTag(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaBase, _In_ QWORD vaLimit, _In_opt_ LPSTR szTag, _In_opt_ LPWSTR wszTag, _In_ BOOL fWoW64, _In_ BOOL fOverwrite)
{
// NB! update here may take placey without acquiring the process 'LockUpdate'
// Data is not super important so it should be ok. Also, in many cases the
// lock will already be acquired by MapGetEntries function.
PVMM_MEMMAP_ENTRY pMap;
QWORD i, lvl, cMap;
if(!MmX86PAE_MapInitialize(pProcess)) { return; }
if((vaBase > 0xffffffff) || (vaLimit > 0xffffffff)) { return; }
pMap = pProcess->pMemMap;
cMap = pProcess->cMemMap;
pMap = pProcess->pObMemMap->pMap;
cMap = pProcess->pObMemMap->cMap;
if(!pMap || !cMap) { return; }
// 1: locate base
lvl = 1;
@@ -139,7 +264,7 @@ VOID MmX86PAE_MapTag(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaBase, _In_ QWORD v
}
// 3: fill in tag
while((i < cMap) && (pMap[i].AddrBase + (pMap[i].cPages << 12) <= vaLimit)) {
if(pMap[i].AddrBase >= vaBase) {
if((pMap[i].AddrBase >= vaBase) && (fOverwrite || !pMap[i].szTag[0])) {
if(wszTag) {
snprintf(pMap[i].szTag, 31, "%S", wszTag);
}
@@ -151,142 +276,122 @@ VOID MmX86PAE_MapTag(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaBase, _In_ QWORD v
}
}
VOID MmX86PAE_MapDisplayBufferGenerate(_In_ PVMM_PROCESS pProcess)
_Success_(return)
BOOL MmX86PAE_MapGetEntries(_In_ PVMM_PROCESS pProcess, _In_ DWORD flags, _Out_ PVMMOB_MEMMAP *ppObMemMap)
{
DWORD i, o = 0;
PBYTE pbBuffer;
if(!pProcess->cMemMap || !pProcess->pMemMap) { return; }
pProcess->cbMemMapDisplayCache = 0;
LocalFree(pProcess->pbMemMapDisplayCache);
pProcess->pbMemMapDisplayCache = NULL;
pbBuffer = LocalAlloc(LMEM_ZEROINIT, 70 * pProcess->cMemMap);
if(!pbBuffer) { return; }
for(i = 0; i < pProcess->cMemMap; i++) {
o += snprintf(
pbBuffer + o,
70,
"%04x %8x %08x-%08x %sr%s%s %s\n",
i,
(DWORD)pProcess->pMemMap[i].cPages,
(DWORD)pProcess->pMemMap[i].AddrBase,
(DWORD)(pProcess->pMemMap[i].AddrBase + (pProcess->pMemMap[i].cPages << 12) - 1),
pProcess->pMemMap[i].fPage & VMM_MEMMAP_FLAG_PAGE_NS ? "-" : "s",
pProcess->pMemMap[i].fPage & VMM_MEMMAP_FLAG_PAGE_W ? "w" : "-",
pProcess->pMemMap[i].fPage & VMM_MEMMAP_FLAG_PAGE_NX ? "-" : "x",
pProcess->pMemMap[i].szTag
);
}
pProcess->pbMemMapDisplayCache = LocalAlloc(0, o);
if(!pProcess->pbMemMapDisplayCache) { goto fail; }
memcpy(pProcess->pbMemMapDisplayCache, pbBuffer, o);
pProcess->cbMemMapDisplayCache = o;
fail:
LocalFree(pbBuffer);
}
PVMM_MEMMAP_ENTRY MmX86PAE_MapGetEntry(_In_ PVMM_PROCESS pProcess, _In_ QWORD va)
{
QWORD i, ce;
PVMM_MEMMAP_ENTRY pe;
if(!pProcess->pMemMap) { return NULL; }
ce = pProcess->cMemMap;
for(i = 0; i < ce; i++) {
pe = pProcess->pMemMap + i;
if((pe->AddrBase >= va) && (va <= pe->AddrBase + (pe->cPages << 12))) {
return pe;
}
}
return NULL;
}
const QWORD MMX86PAE_PAGETABLEMAP_PML_REGION_SIZE[4] = { 0, 12, 21, 30 };
VOID MmX86PAE_MapInitialize_Index(_In_ PVMM_PROCESS pProcess, _In_ DWORD vaBase, _In_ BYTE iPML, _In_ QWORD PTEs[512], _In_ BOOL fSupervisorPML, _In_ QWORD paMax)
{
PBYTE pbNextPageTable;
DWORD i, va;
QWORD pte;
BOOL fUserOnly, fNextSupervisorPML;
QWORD cMemMap = pProcess->cMemMap;
PVMM_MEMMAP_ENTRY pMemMap = pProcess->pMemMap;
PVMM_MEMMAP_ENTRY pMemMapEntry = pMemMap + cMemMap - 1;
fUserOnly = pProcess->fUserOnly;
for(i = 0; i < 512; i++) {
if((iPML == 3) && (i > 3)) { break; } // MAX 4 ENTRIES IN PDPT
pte = PTEs[i];
if(!(pte & 0x01)) { continue; }
if((pte & 0x0000fffffffff000) > paMax) { continue; }
if(iPML == 3) {
// PDPT: (iPML = 3)
if(pte & 0xffff0000000001e6) { continue; } // RESERVED BITS IN PDPTE
va = i * 0x40000000;
} else {
// PT or PD: (iPML = 1..2)
if(fSupervisorPML) { pte = pte & 0xfffffffffffffffb; }
if(fUserOnly && !(pte & 0x04)) { continue; }
va = vaBase + (i << MMX86PAE_PAGETABLEMAP_PML_REGION_SIZE[iPML]);
// maps page
if((iPML == 1) || (pte & 0x80) /* PS */) {
if((cMemMap == 0) ||
(pMemMapEntry->fPage != (pte & VMM_MEMMAP_FLAG_PAGE_MASK)) ||
(va != pMemMapEntry->AddrBase + (pMemMapEntry->cPages << 12))) {
if(cMemMap + 1 >= VMM_MEMMAP_ENTRIES_MAX) { return; }
pMemMapEntry = pProcess->pMemMap + cMemMap;
pMemMapEntry->AddrBase = va;
pMemMapEntry->fPage = pte & VMM_MEMMAP_FLAG_PAGE_MASK;
pMemMapEntry->cPages = 1ULL << (MMX86PAE_PAGETABLEMAP_PML_REGION_SIZE[iPML] - 12);
pProcess->cMemMap++;
cMemMap++;
continue;
DWORD i;
PVMM_MODULEMAP_ENTRY pModule;
PVMMOB_MODULEMAP pObModuleMap;
if(!MmX86PAE_MapInitialize(pProcess)) { return FALSE; }
if((!pProcess->pObMemMap->fTagModules && (flags & VMM_MEMMAP_FLAG_MODULES)) || (!pProcess->pObMemMap->fTagScan && (flags & VMM_MEMMAP_FLAG_SCAN))) {
EnterCriticalSection(&pProcess->LockUpdate);
if(!pProcess->pObMemMap->fTagModules && (flags & VMM_MEMMAP_FLAG_MODULES)) {
pProcess->pObMemMap->fTagModules = TRUE;
if(VmmProc_ModuleMapGet(pProcess, &pObModuleMap)) {
// update memory map with names
for(i = 0; i < pObModuleMap->cMap; i++) {
pModule = pObModuleMap->pMap + i;
MmX86PAE_MapTag(pProcess, pModule->BaseAddress, pModule->BaseAddress + pModule->SizeOfImage, pModule->szName, NULL, FALSE, FALSE);
}
pMemMapEntry->cPages += 1ULL << (MMX86PAE_PAGETABLEMAP_PML_REGION_SIZE[iPML] - 12);
continue;
VmmOb_DECREF(pObModuleMap);
}
}
// maps page table (PD, PT)
fNextSupervisorPML = (iPML != 3) && !(pte & 0x04);
if(!(pbNextPageTable = VmmTlbGetPageTable(pte & 0x0000fffffffff000, FALSE))) { continue; }
MmX86PAE_MapInitialize_Index(pProcess, va, iPML - 1, (PQWORD)pbNextPageTable, fNextSupervisorPML, paMax);
cMemMap = pProcess->cMemMap;
pMemMapEntry = pProcess->pMemMap + cMemMap - 1;
if(!pProcess->pObMemMap->fTagScan && (flags & VMM_MEMMAP_FLAG_SCAN)) {
pProcess->pObMemMap->fTagScan = TRUE;
VmmProc_ScanTagsMemMap(pProcess);
}
LeaveCriticalSection(&pProcess->LockUpdate);
}
*ppObMemMap = VmmOb_INCREF(pProcess->pObMemMap);
return TRUE;
}
VOID MmX86PAE_MapInitialize(_In_ PVMM_PROCESS pProcess)
_Success_(return)
BOOL MmX86PAE_MapGetDisplay(_In_ PVMM_PROCESS pProcess, _In_ DWORD flags, _Out_ PVMMOB_PDATA *ppObDisplay)
{
PBYTE pbPDPT;
pProcess->cbMemMapDisplayCache = 0;
LocalFree(pProcess->pbMemMapDisplayCache);
pProcess->pbMemMapDisplayCache = NULL;
LocalFree(pProcess->pMemMap);
pProcess->cMemMap = 0;
pProcess->pMemMap = (PVMM_MEMMAP_ENTRY)LocalAlloc(LMEM_ZEROINIT, VMM_MEMMAP_ENTRIES_MAX * sizeof(VMM_MEMMAP_ENTRY));
if(!pProcess->pMemMap) { return; }
if(!(pbPDPT = VmmTlbGetPageTable(pProcess->paDTB & 0xfffff000, FALSE))) { return; }
pbPDPT += pProcess->paDTB & 0xfe0; // ADJUST PDPT TO 32-BYTE BOUNDARY
MmX86PAE_MapInitialize_Index(pProcess, 0, 3, (PQWORD)pbPDPT, FALSE, ctxMain->cfg.paAddrMax);
DWORD i, o = 0;
PVMMOB_MEMMAP pObMemMap = NULL;
PVMMOB_PDATA pObDisplay = NULL;
// memory map display data already exists
if(!MmX86PAE_MapInitialize(pProcess)) { return FALSE; }
if(pProcess->pObMemMap->pObDisplay) {
*ppObDisplay = VmmOb_INCREF(pProcess->pObMemMap->pObDisplay);
return TRUE;
}
// create new memory map display data
EnterCriticalSection(&pProcess->LockUpdate);
if(!pProcess->pObMemMap->pObDisplay) {
if(MmX86PAE_MapGetEntries(pProcess, flags, &pObMemMap)) {
pObDisplay = VmmOb_Alloc('MD', LMEM_ZEROINIT, pObMemMap->cbDisplay, NULL, NULL);
if(pObDisplay) {
for(i = 0; i < pObMemMap->cMap; i++) {
if(o + MMX86PAE_MEMMAP_DISPLAYBUFFER_LINE_LENGTH > pObMemMap->cbDisplay) {
vmmprintf_fn("ERROR: SHOULD NOT HAPPEN! LENGTH DIFFERS #1: %i %i\n", o + MMX86PAE_MEMMAP_DISPLAYBUFFER_LINE_LENGTH, pObMemMap->cbDisplay);
VmmOb_DECREF(pObDisplay);
pObDisplay = NULL;
goto fail;
}
o += snprintf(
pObDisplay->pbData + o,
pObMemMap->cbDisplay - o - MMX86PAE_MEMMAP_DISPLAYBUFFER_LINE_LENGTH,
"%04x %8x %08x-%08x %sr%s%s %-32s\n",
i,
(DWORD)pObMemMap->pMap[i].cPages,
(DWORD)pObMemMap->pMap[i].AddrBase,
(DWORD)(pObMemMap->pMap[i].AddrBase + (pObMemMap->pMap[i].cPages << 12) - 1),
pObMemMap->pMap[i].fPage & VMM_MEMMAP_PAGE_NS ? "-" : "s",
pObMemMap->pMap[i].fPage & VMM_MEMMAP_PAGE_W ? "w" : "-",
pObMemMap->pMap[i].fPage & VMM_MEMMAP_PAGE_NX ? "-" : "x",
pObMemMap->pMap[i].szTag
);
}
if(o != pObMemMap->cbDisplay) {
vmmprintf_fn("ERROR: SHOULD NOT HAPPEN! LENGTH DIFFERS #2: %i %i\n", o, pObMemMap->cbDisplay);
VmmOb_DECREF(pObDisplay);
pObDisplay = NULL;
goto fail;
}
}
}
pProcess->pObMemMap->pObDisplay = pObDisplay;
}
fail:
VmmOb_DECREF(pObMemMap);
LeaveCriticalSection(&pProcess->LockUpdate);
if(pProcess->pObMemMap->pObDisplay) {
*ppObDisplay = VmmOb_INCREF(pProcess->pObMemMap->pObDisplay);
return TRUE;
}
return FALSE;
}
_Success_(return)
BOOL MmX86PAE_Virt2Phys(_In_ QWORD paPT, _In_ BOOL fUserOnly, _In_ BYTE iPML, _In_ QWORD va, _Out_ PQWORD ppa)
{
QWORD pte, i, qwMask;
PBYTE pbPTEs;
QWORD pte, i, qwMask;
PVMMOB_MEM pObPTEs;
if(va > 0xffffffff) { return FALSE; }
if(iPML == (BYTE)-1) { iPML = 3; }
if(!(pbPTEs = VmmTlbGetPageTable(paPT & 0x0000fffffffff000, FALSE))) { return FALSE; }
pObPTEs = VmmTlbGetPageTable(paPT & 0x0000fffffffff000, FALSE);
if(!pObPTEs) { return FALSE; }
i = 0x1ff & (va >> MMX86PAE_PAGETABLEMAP_PML_REGION_SIZE[iPML]);
if(iPML == 3) {
// PDPT
if(i > 3) { return FALSE; } // MAX 4 ENTRIES IN PDPT
pbPTEs += paPT & 0xfe0; // ADJUST PDPT TO 32-BYTE BOUNDARY
if(i > 3) { // MAX 4 ENTRIES IN PDPT
VmmOb_DECREF(pObPTEs);
return FALSE;
}
pbPTEs = pObPTEs->pb + (paPT & 0xfe0); // ADJUST PDPT TO 32-BYTE BOUNDARY
pte = ((PQWORD)pbPTEs)[i];
VmmOb_DECREF(pObPTEs);
if(!(pte & 0x01)) { return FALSE; } // NOT VALID
if(pte & 0xffff0000000001e6) { return FALSE; } // RESERVED BITS IN PDPTE
return MmX86PAE_Virt2Phys(pte, fUserOnly, 2, va, ppa);
}
// PT or PD
pte = ((PQWORD)pbPTEs)[i];
pte = pObPTEs->pqw[i];
VmmOb_DECREF(pObPTEs);
if(!(pte & 0x01)) { return FALSE; } // NOT VALID
if(fUserOnly && !(pte & 0x04)) { return FALSE; } // SUPERVISOR PAGE & USER MODE REQ
if(pte & 0x000f000000000000) { return FALSE; } // RESERVED
@@ -303,7 +408,7 @@ BOOL MmX86PAE_Virt2Phys(_In_ QWORD paPT, _In_ BOOL fUserOnly, _In_ BYTE iPML, _I
VOID MmX86PAE_Virt2PhysGetInformation_DoWork(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo, _In_ BYTE iPML, _In_ QWORD PTEs[512])
{
QWORD pte, i, qwMask;
PBYTE pbNextPageTable;
PVMMOB_MEM pObNextPT;
i = 0x1ff & (pVirt2PhysInfo->va >> MMX86PAE_PAGETABLEMAP_PML_REGION_SIZE[iPML]);
if((iPML == 3) && (i > 3)) { return; } // MAX 4 ENTRIES IN PDPT
pte = PTEs[i];
@@ -325,23 +430,27 @@ VOID MmX86PAE_Virt2PhysGetInformation_DoWork(_Inout_ PVMM_PROCESS pProcess, _Ino
return;
}
}
if(!(pbNextPageTable = VmmTlbGetPageTable(pte & 0x0000fffffffff000, FALSE))) { return; }
pObNextPT = VmmTlbGetPageTable(pte & 0x0000fffffffff000, FALSE);
if(!pObNextPT) { return; }
pVirt2PhysInfo->pas[iPML - 1] = pte & 0x0000fffffffff000;
MmX86PAE_Virt2PhysGetInformation_DoWork(pProcess, pVirt2PhysInfo, iPML - 1, (PQWORD)pbNextPageTable);
MmX86PAE_Virt2PhysGetInformation_DoWork(pProcess, pVirt2PhysInfo, iPML - 1, pObNextPT->pqw);
VmmOb_DECREF(pObNextPT);
}
VOID MmX86PAE_Virt2PhysGetInformation(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo)
{
QWORD va;
PBYTE pbPDPT;
PVMMOB_MEM pObPML4;
if(pVirt2PhysInfo->va > 0xffffffff) { return; }
va = pVirt2PhysInfo->va;
ZeroMemory(pVirt2PhysInfo, sizeof(VMM_VIRT2PHYS_INFORMATION));
pVirt2PhysInfo->tpMemoryModel = VMM_MEMORYMODEL_X86PAE;
pVirt2PhysInfo->va = va;
pVirt2PhysInfo->pas[3] = pProcess->paDTB;
if(!(pbPDPT = VmmTlbGetPageTable(pProcess->paDTB & 0xfffff000, FALSE))) { return; }
MmX86PAE_Virt2PhysGetInformation_DoWork(pProcess, pVirt2PhysInfo, 3, (PQWORD)(pbPDPT + (pProcess->paDTB & 0xfe0)));
pObPML4 = VmmTlbGetPageTable(pProcess->paDTB & 0xfffff000, FALSE);
if(!pObPML4) { return; }
MmX86PAE_Virt2PhysGetInformation_DoWork(pProcess, pVirt2PhysInfo, 3, (PQWORD)(pObPML4->pb + (pProcess->paDTB & 0xfe0)));
VmmOb_DECREF(pObPML4);
}
VOID MmX86PAE_Close()
@@ -356,14 +465,13 @@ VOID MmX86PAE_Initialize()
if(ctxVmm->fnMemoryModel.pfnClose) {
ctxVmm->fnMemoryModel.pfnClose();
}
ctxVmm->fnMemoryModel.pfnInitialize = MmX86PAE_Initialize;
ctxVmm->fnMemoryModel.pfnClose = MmX86PAE_Close;
ctxVmm->fnMemoryModel.pfnVirt2Phys = MmX86PAE_Virt2Phys;
ctxVmm->fnMemoryModel.pfnVirt2PhysGetInformation = MmX86PAE_Virt2PhysGetInformation;
ctxVmm->fnMemoryModel.pfnMapInitialize = MmX86PAE_MapInitialize;
ctxVmm->fnMemoryModel.pfnMapTag = MmX86PAE_MapTag;
ctxVmm->fnMemoryModel.pfnMapGetEntry = MmX86PAE_MapGetEntry;
ctxVmm->fnMemoryModel.pfnMapDisplayBufferGenerate = MmX86PAE_MapDisplayBufferGenerate;
ctxVmm->fnMemoryModel.pfnMapGetEntries = MmX86PAE_MapGetEntries;
ctxVmm->fnMemoryModel.pfnMapGetDisplay = MmX86PAE_MapGetDisplay;
ctxVmm->fnMemoryModel.pfnTlbSpider = MmX86PAE_TlbSpider;
ctxVmm->fnMemoryModel.pfnTlbPageTableVerify = MmX86PAE_TlbPageTableVerify;
ctxVmm->tpMemoryModel = VMM_MEMORYMODEL_X86PAE;
+1 -1
View File
@@ -1,6 +1,6 @@
// mm_x86pae.h : definitions related to the x86 PAE (Physical Address Extension) 32-bit protected mode memory model.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
#ifndef __MM_X86PAE_H__
-398
View File
@@ -1,398 +0,0 @@
// pcileech_dll.h : defines related to dynamic link library (dll) functionality.
// Please use together with pcileech.dll in other projects.
// Please see pcileech_dll_example.c for integration examples.
//
// Version 3.5
// (c) Ulf Frisk, 2018
// Author: Ulf Frisk, [email protected]
//
#ifndef __PCILEECH_DLL_H__
#define __PCILEECH_DLL_H__
#include <windows.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/*
* Retrieve the current version of PCILeech.
* -- return = the current version of PCILeech in ascii text.
*/
LPSTR PCILeech_GetVersion();
/*
* Initialize PCILeech from a memory dump file in raw format. PCILeech will be
* initialized in read-only mode. It's possible to optionally specify the page
* table base of the windows kernel (for full vmm features) or the page table
* base of a single 64-bit process in any x64 operating system. NB! usually it
* is not necessary to specify the PageTableBase - it will be auto-identified
* most often if the target is Windows.
* -- szFileName = the file name of the raw memory dump to use.
* -- szPageTableBaseOpt = optionally the Page Table Base of kernel or process
* as hex string. NB! this is usally not required. Example: "0x1ab000".
* -- return = success/fail.
*/
BOOL PCILeech_InitializeFromFile(_In_ LPSTR szFileName, _In_opt_ LPSTR szPageTableBaseOpt);
/*
* Intiailize PCILeech from a supported FPGA device over USB. PCIleech will be
* initialized in read/write mode upon success. Optionally it will be possible
* to specify the max physical address and the page table base of the kernel or
* process that should be investigated.
* -- szMaxPhysicalAddressOpt = max physical address of the target system as a
* hex string. Example: "0x8000000000".
* -- szPageTableBaseOpt = optionally the Page Table Base of kernel or process
* as hex string. NB! this is usally not required. Example: "0x1ab000".
* -- return = success/fail.
*/
BOOL PCILeech_InitializeFPGA(_In_opt_ LPSTR szMaxPhysicalAddressOpt, _In_opt_ LPSTR szPageTableBaseOpt);
/*
* Intiailize PCILeech from a the "Total Meltdown" CVE-2018-1038 vulnerability.
* initialized in read/write mode upon success.
* -- return = success/fail.
*/
BOOL PCILeech_InitializeTotalMeltdown();
/*
* Initialize PCIleech from a USB3380 device. The functionality of a USB3380
* device is limited to DMA in the 32-bit physical address space below 4GB.
* As such the USB3380 cannot be used together with the VMM functionality.
* Furthermore; if undreadable memory such as memory holes or PCIe space is to
* be read the USB3380 device will freeze and require a complete power cycle.
* Despite limitations the USB330 will work together with the functions:
* PCILeech_DeviceReadMEM and PCILeech_DeviceWriteMEM.
*/
BOOL PCILeech_InitializeUSB3380();
/*
* Shut down the PCILeech functionality and clean up allocated resources. This
* should always be called before the DLL is unloaded (unless upon process exit)
* to ensure resources are cleaned up.
*/
BOOL PCILeech_Close();
/*
* For internal use only - do not use!
*/
BOOL PCILeech_InitializeInternalReserved(_In_ DWORD argc, _In_ char* argv[]);
/*
* Device specific options used together with the PCILeech_DeviceGetOption and
* PCILeech_DeviceSetOption functions. For more detailed information check the
* sources for the individual device types.
*/
#define PCILEECH_DEVICE_OPT_FPGA_PROBE_MAXPAGES 0x01 // RW
#define PCILEECH_DEVICE_OPT_FPGA_RX_FLUSH_LIMIT 0x02 // RW
#define PCILEECH_DEVICE_OPT_FPGA_MAX_SIZE_RX 0x03 // RW
#define PCILEECH_DEVICE_OPT_FPGA_MAX_SIZE_TX 0x04 // RW
#define PCILEECH_DEVICE_OPT_FPGA_DELAY_PROBE_READ 0x05 // RW uS
#define PCILEECH_DEVICE_OPT_FPGA_DELAY_PROBE_WRITE 0x06 // RW uS
#define PCILEECH_DEVICE_OPT_FPGA_DELAY_WRITE 0x07 // RW uS
#define PCILEECH_DEVICE_OPT_FPGA_DELAY_READ 0x08 // RW uS
#define PCILEECH_DEVICE_OPT_FPGA_RETRY_ON_ERROR 0x09 // RW
#define PCILEECH_DEVICE_OPT_FPGA_DEVICE_ID 0x80 // R
#define PCILEECH_DEVICE_OPT_FPGA_FPGA_ID 0x81 // R
#define PCILEECH_DEVICE_OPT_FPGA_VERSION_MAJOR 0x82 // R
#define PCILEECH_DEVICE_OPT_FPGA_VERSION_MINOR 0x83 // R
#define PCILEECH_DEVICE_CORE_PRINTF_ENABLE 0x80000001 // RW
#define PCILEECH_DEVICE_CORE_VERBOSE 0x80000002 // RW
#define PCILEECH_DEVICE_CORE_VERBOSE_EXTRA 0x80000003 // RW
#define PCILEECH_DEVICE_CORE_VERBOSE_EXTRA_TLP 0x80000004 // RW
#define PCILEECH_DEVICE_CORE_MAX_NATIVE_ADDRESS 0x80000005 // R
#define PCILEECH_DEVICE_CORE_MAX_NATIVE_IOSIZE 0x80000006 // R
/*
* Set a device specific option value. Please see defines PCILEECH_DEVICE_OPT_*
* for information about valid option values. Please note that option values
* may overlap between different device types with different meanings.
* -- fOption
* -- pqwValue = pointer to ULONG64 to receive option value.
* -- return = success/fail.
*/
BOOL PCIleech_DeviceConfigGet(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue);
/*
* Set a device specific option value. Please see defines PCILEECH_DEVICE_OPT_*
* for information about valid option values. Please note that option values
* may overlap between different device types with different meanings.
* -- fOption
* -- qwValue
* -- return = success/fail.
*/
BOOL PCILeech_DeviceConfigSet(_In_ ULONG64 fOption, _In_ ULONG64 qwValue);
/*
* Write target physical memory. Minimum granularity: byte.
* -- qwAddr = the physical address to write to in the target system.
* -- pb = bytes to write
* -- cb = number of bytes to write.
* -- return = success/fail.
*/
BOOL PCILeech_DeviceWriteMEM(_In_ ULONG64 qwAddr, _In_ PBYTE pb, _In_ DWORD cb);
/*
* Read target physical memory. Minimum granularity: page (4kB).
* -- qwAddr = physical address in target system to read.
* -- pb = pre-allocated buffer to place result in.
* -- cb = length of data to read, must not be larger than pb.
* -- return = success/fail.
*/
BOOL PCILeech_DeviceReadMEM(_In_ ULONG64 qwAddr, _Out_ PBYTE pb, _In_ DWORD cb);
typedef struct tdPCILEECH_MEM_IO_SCATTER_HEADER {
ULONG64 qwA; // base address (DWORD boundry).
DWORD cbMax; // bytes to read (DWORD boundry, max 0x1000); pbResult must have room for this.
DWORD cb; // bytes read into result buffer.
PVOID pvReserved1; // reserved for use by caller.
PVOID pvReserved2; // reserved for use by caller.
PBYTE pb; // ptr to 0x1000 sized buffer to receive read bytes.
} PCILEECH_MEM_IO_SCATTER_HEADER, *PPCILEECH_MEM_IO_SCATTER_HEADER, **PPPCILEECH_MEM_IO_SCATTER_HEADER;
/*
* Read memory in various non-contigious locations specified by the pointers to
* the items in the ppDMAs array. Result for each unit of work will be given
* individually. No upper limit of number of items to read, but no performance
* boost will be given if above hardware limit. Max size of each unit of work is
* one 4k page (4096 bytes).
* -- ppMEMs = array of scatter read headers.
* -- cpMEMs = count of ppDMAs.
* -- pcpDMAsRead = optional count of number of successfully read ppDMAs.
* -- return = the number of successfully read items.
*/
DWORD PCILeech_DeviceReadScatterMEM(_Inout_ PPPCILEECH_MEM_IO_SCATTER_HEADER ppMEMs, _In_ DWORD cpMEMs);
/*
* Initialize the Virtual Memory Manager (VMM). This will try to auto-identify
* the operating system, parse and enumerate its processes in order to make it
* available through the PCILeech_VMM* functions.
* If auto-identifying of a Windows sytem fails please try initialize PCILeech
* with the address of the kernel page table in the szPageTableBaseOpt parameter
* in a call to the PCIleech_Initialize* functions. The page table base may be
* obtained (sometimes) from pcileech.exe by running the identify command.
* -- return = success/fail.
*/
BOOL PCILeech_VmmInitialize();
/*
* Close the Virtual Memory Manager (VMM) and clean up resources. This must be
* done before PCILeech_VmmInitialize() is called again. This is not necessary
* if PCILeech is completely closed by a call to PCILeech_Close() - which will
* take care of all necessary cleanup activitities.
*/
BOOL PCILeech_VmmClose();
#define PCILEECH_VMM_CONFIG_IS_REFRESH_ENABLED 1 // read-only, 1/0
#define PCILEECH_VMM_CONFIG_TICK_PERIOD 2 // read-write, base tick period in ms
#define PCILEECH_VMM_CONFIG_READCACHE_TICKS 3 // read-write, memory cache validity period (in ticks)
#define PCILEECH_VMM_CONFIG_TLBCACHE_TICKS 4 // read-write, page table (tlb) cache validity period (in ticks)
#define PCILEECH_VMM_CONFIG_PROCCACHE_TICKS_PARTIAL 5 // read-write, process refresh (partial) period (in ticks)
#define PCILEECH_VMM_CONFIG_PROCCACHE_TICKS_TOTAL 6 // read-write, process refresh (full) period (in ticks)
/*
* Retrieve a configuration value from the PCILeech DLL.
* -- dwConfigOption = configuration option as specified by PCILEECH_VMM_CONFIG*
* -- pdwConfigValue = pointer to DWORD that will receive configuration value.
* -- return = success/fail.
*/
BOOL PCILeech_VmmConfigGet(_In_ DWORD dwConfigOption, _Out_ PDWORD pdwConfigValue);
/*
* Set a configuration value in the PCILeech DLL. Note that not all values are
* possible to set - some are read-only. Setting a read-only value will result
* in fuction returning failure.
* -- dwConfigOption = configuration option as specified by PCILEECH_VMM_CONFIG*
* -- dwConfigValue = configuration value to set.
* -- return = success/fail.
*/
BOOL PCILeech_VmmConfigSet(_In_ DWORD dwConfigOption, _In_ DWORD dwConfigValue);
// FLAG used to supress the default read cache in calls to PCILeech_VmmReadEx()
// which will lead to the read being fetched from the target system always.
// Cached page tables (used for translating virtual2physical) are still used.
#define VMM_FLAG_NOCACHE 0x0001
/*
* Read a single 4096-byte page of virtual memory.
* -- dwPID
* -- qwVA
* -- pbPage
* -- return = success/fail (depending if all requested bytes are read or not).
*/
BOOL PCILeech_VmmReadPage(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_bytecount_(4096) PBYTE pbPage);
/*
* Read a virtually contigious arbitrary amount of memory.
* -- dwPID
* -- qwVA
* -- pb
* -- cb
* -- return = success/fail (depending if all requested bytes are read or not).
*/
BOOL PCILeech_VmmRead(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DWORD cb);
/*
* Read a virtually contigious amount of memory and report the number of bytes
* read in pcbRead.
* -- dwPID
* -- qwVA
* -- pb
* -- cb
* -- pcbRead
* -- flags = flags as in VMM_FLAG_*
* -- return = success/fail. NB! reads may report as success even if 0 bytes are
* read - it's recommended to verify pcbReadOpt parameter.
*/
BOOL PCILeech_VmmReadEx(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ ULONG64 flags);
/*
* Write a virtually contigious arbitrary amount of memory. Please note some
* virtual memory - such as pages of executables (such as DLLs) may be shared
* between different virtual memory over different processes. As an example a
* write to kernel32.dll in one process is likely to affect kernel32 in the
* whole system - in all processes. Heaps and Stacks and other memory are
* usually safe to write to. Please take care when writing to memory!
* -- dwPID
* -- qwVA
* -- pb
* -- cb
* -- return = TRUE on success, FALSE on partial or zero write.
*/
BOOL PCILeech_VmmWrite(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DWORD cb);
/*
* Translate a virtual address to a physical address by walking the page tables
* of the specified process.
* -- dwPID
* -- qwVA
* -- pqwPA
* -- return = success/fail.
*/
BOOL PCILeech_VmmVirt2Phys(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PULONG64 pqwPA);
// flags to check for existence in the fPage field of PCILEECH_VMM_MEMMAP_ENTRY
#define PCIEECH_VMM_MEMMAP_FLAG_PAGE_W 0x0000000000000002
#define PCIEECH_VMM_MEMMAP_FLAG_PAGE_NS 0x0000000000000004
#define PCIEECH_VMM_MEMMAP_FLAG_PAGE_NX 0x8000000000000000
#define PCIEECH_VMM_MEMMAP_FLAG_PAGE_MASK 0x8000000000000006
typedef struct tdPCILEECH_VMM_MEMMAP_ENTRY {
ULONG64 AddrBase;
ULONG64 cPages;
ULONG64 fPage;
BOOL fWoW64;
CHAR szName[32];
} PCILEECH_VMM_MEMMAP_ENTRY, *PPCILEECH_VMM_MEMMAP_ENTRY;
/*
* Retrieve memory map entries from the specified process. Memory map entries
* are copied into the user supplied buffer that must be at least of size:
* sizeof(PCILEECH_VMM_MEMMAP_ENTRY)*pcMemMapEntries bytes.
* If the pMemMapEntries is set to NULL the number of memory map entries will be
* given in the pcMemMapEntries parameter.
* -- dwPID
* -- pMemMapEntries = buffer of minimum length sizeof(PCILEECH_VMM_MEMMAP_ENTRY)*pcMemMapEntries, or NULL.
* -- pcMemMapEntries = pointer to number of memory map entries.
* -- fIdentifyModules = try identify modules as well (= slower)
* -- return = success/fail.
*/
BOOL PCILeech_VmmProcessGetMemoryMap(_In_ DWORD dwPID, _Out_ PPCILEECH_VMM_MEMMAP_ENTRY pMemMapEntries, _Inout_ PULONG64 pcMemMapEntries, _In_ BOOL fIdentifyModules);
typedef struct tdPCILEECH_VMM_MODULEMAP_ENTRY {
ULONG64 BaseAddress;
ULONG64 EntryPoint;
DWORD SizeOfImage;
BOOL fWoW64;
CHAR szName[32];
} PCILEECH_VMM_MODULEMAP_ENTRY, *PPCILEECH_VMM_MODULEMAP_ENTRY;
/*
* Retrieve the module entries from the specified process. The module entries
* are copied into the user supplied buffer that must be at least of size:
* sizeof(PCILEECH_VMM_MODULEMAP_ENTRY)*pcModuleEntries bytes long. If the
* pcModuleEntries is set to NULL the number of module entries will be given
* in the pcModuleEntries parameter.
* -- dwPID
* -- pModuleEntries = buffer of minimum length sizeof(PCILEECH_VMM_MODULEMAP_ENTRY)*pcModuleEntries, or NULL.
* -- pcModuleEntries = pointer to number of memory map entries.
* -- return = success/fail.
*/
BOOL PCILeech_VmmProcessGetModuleMap(_In_ DWORD dwPID, _Out_ PPCILEECH_VMM_MODULEMAP_ENTRY pModuleEntries, _Inout_ PULONG64 pcModuleEntries);
/*
* Retrieve a module (.exe or .dll or similar) given a module name.
* -- dwPID
* -- szModuleName
* -- pModuleEntry
* -- return = success/fail.
*/
BOOL PCILeech_VmmProcessGetModuleFromName(_In_ DWORD dwPID, _In_ LPSTR szModuleName, _Out_ PPCILEECH_VMM_MODULEMAP_ENTRY pModuleEntry);
/*
* Retrieve an active process given it's name. Please note that if multiple
* processes with the same name exists only one will be returned. If required to
* parse all processes with the same name please iterate over the PID list by
* calling PCILeech_VmmProcessListPIDs together with PCIleech_VmmProcessInfo.
* -- szProcName = process name (truncated max 15 chars) case insensitive.
* -- pdwPID = pointer that will receive PID on success.
* -- return
*/
BOOL PCILeech_VmmProcessGetFromName(_In_ LPSTR szProcName, _Out_ PDWORD pdwPID);
/*
* List the PIDs in the system.
* -- pPIDs = DWORD array of at least number of PIDs in system, or NULL.
* -- pcPIDs = size of (in number of DWORDs) pPIDs array on entry, number of PIDs in system on exit.
* -- return = success/fail.
*/
BOOL PCILeech_VmmProcessListPIDs(_Out_ PDWORD pPIDs, _Inout_ PULONG64 pcPIDs);
/*
* Retrieve various process information from a PID. Process information such as
* name, page directory bases and the process state may be retrieved. Parameters,
* except for dwPID are optional.
* -- dwPID
* -- szNameOpt
* -- pqwPageDirectoryBaseOpt
* -- pqwPageDirectoryBaseUserOpt
* -- pdwStateOpt
* -- return = success/fail.
*/
BOOL PCIleech_VmmProcessInfo(_In_ DWORD dwPID, _Out_opt_ CHAR szNameOpt[16], _Out_opt_ PULONG64 pqwPageDirectoryBaseOpt, _Out_opt_ PULONG64 pqwPageDirectoryBaseUserOpt, _Out_opt_ PDWORD pdwStateOpt);
typedef struct tdPCILEECH_VMM_EAT_ENTRY {
DWORD vaFunctionOffset;
CHAR szFunction[40];
} PCILEECH_VMM_EAT_ENTRY, *PPCILEECH_VMM_EAT_ENTRY;
typedef struct tdPCILEECH_VMM_IAT_ENTRY {
ULONG64 vaFunction;
CHAR szFunction[40];
CHAR szModule[64];
} PCILEECH_VMM_IAT_ENTRY, *PPCILEECH_VMM_IAT_ENTRY;
/*
* Retrieve information about: Data Directories, Sections, Export Address Table
* and Import Address Table (IAT).
* If the pData == NULL upon entry the number of entries of the pData array must
* have in order to be able to hold the data is returned.
* -- dwPID
* -- szModule
* -- pData
* -- cData
* -- pcData
* -- return = success/fail.
*/
BOOL PCIleech_VmmProcess_GetDirectories(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PIMAGE_DATA_DIRECTORY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
BOOL PCIleech_VmmProcess_GetSections(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PIMAGE_SECTION_HEADER pData, _In_ DWORD cData, _Out_ PDWORD pcData);
BOOL PCIleech_VmmProcess_GetEAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PPCILEECH_VMM_EAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
BOOL PCIleech_VmmProcess_GetIAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PPCILEECH_VMM_IAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __PCILEECH_DLL_H__ */
+7 -6
View File
@@ -2,7 +2,7 @@
// in virtual address space. This may mostly (but not exclusively) be
// used by Windows functionality.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
@@ -47,7 +47,7 @@ QWORD PE_GetProcAddress(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In
PIMAGE_NT_HEADERS64 ntHeader64;
PDWORD pdwRVAAddrNames, pdwRVAAddrFunctions;
PWORD pwNameOrdinals;
DWORD i, cbProcName, cbExportDirectoryOffset;
DWORD i, cbProcName, cbExportDirectoryOffset, cbRead = 0;
LPSTR sz;
QWORD vaFnPtr;
QWORD vaExportDirectory;
@@ -66,7 +66,8 @@ QWORD PE_GetProcAddress(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In
}
if((cbExportDirectory < sizeof(IMAGE_EXPORT_DIRECTORY)) || (cbExportDirectory > 0x01000000) || (vaExportDirectory == vaModuleBase) || (vaExportDirectory > vaModuleBase + 0x80000000)) { goto cleanup; }
if(!(pbExportDirectory = LocalAlloc(0, cbExportDirectory))) { goto cleanup; }
if(!VmmRead(pProcess, vaExportDirectory, pbExportDirectory, cbExportDirectory)) { goto cleanup; }
VmmReadEx(pProcess, vaExportDirectory, pbExportDirectory, cbExportDirectory, &cbRead, VMM_FLAG_ZEROPAD_ON_FAIL);
if(!cbRead) { goto cleanup; }
PIMAGE_EXPORT_DIRECTORY exp = (PIMAGE_EXPORT_DIRECTORY)pbExportDirectory;
if(!exp || !exp->NumberOfNames || !exp->AddressOfNames) { goto cleanup; }
vaRVAAddrNames = vaModuleBase + exp->AddressOfNames;
@@ -177,7 +178,7 @@ DWORD PE_EatGetNumberOfEx(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _
}
_Success_(return)
BOOL PE_GetModuleNameEx(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ BOOL fOnFailDummyName, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt, _Out_writes_(MAX_PATH) PCHAR szModuleName, _Out_opt_ PDWORD pdwSize)
BOOL PE_GetModuleNameEx(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ BOOL fOnFailDummyName, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt, _Out_writes_(cszModuleName) PCHAR szModuleName, _In_ DWORD cszModuleName, _Out_opt_ PDWORD pdwSize)
{
BOOL f32;
BYTE pbModuleHeader[0x1000] = { 0 };
@@ -209,8 +210,8 @@ BOOL PE_GetModuleNameEx(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In
if(!VmmRead(pProcess, vaExportDirectory, pbExportDirectory, sizeof(IMAGE_EXPORT_DIRECTORY))) { goto fail; }
exp = (PIMAGE_EXPORT_DIRECTORY)pbExportDirectory;
if(!exp || !exp->Name || exp->Name > cbImageSize) { goto fail; }
szModuleName[MAX_PATH - 1] = 0;
if(!VmmRead(pProcess, vaModuleBase + exp->Name, szModuleName, MAX_PATH - 1)) { goto fail; }
szModuleName[cszModuleName - 1] = 0;
if(!VmmRead(pProcess, vaModuleBase + exp->Name, szModuleName, cszModuleName - 1)) { goto fail; }
return TRUE;
fail:
if(fOnFailDummyName) {
+9 -4
View File
@@ -2,13 +2,17 @@
// virtual address space. This may mostly (but not exclusively) be used
// by Windows functionality.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
#ifndef __PE_H__
#define __PE_H__
#include "vmm.h"
#define CONTAINING_RECORD32(address, type, field) ((DWORD)( \
(DWORD)(QWORD)(address) - \
(DWORD)(QWORD)(&((type *)0)->field)))
static const LPCSTR PE_DATA_DIRECTORIES[16] = { "EXPORT", "IMPORT", "RESOURCE", "EXCEPTION", "SECURITY", "BASERELOC", "DEBUG", "ARCHITECTURE", "GLOBALPTR", "TLS", "LOAD_CONFIG", "BOUND_IMPORT", "IAT", "DELAY_IMPORT", "COM_DESCRIPTOR", "RESERVED" };
/*
@@ -35,15 +39,16 @@ QWORD PE_GetProcAddress(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In
* -- fOnFailDummyName
* -- pbModuleHeaderOpt
* -- szModuleName
* -- cszModuleName
* -- pdwSize
* -- return
*/
_Success_(return)
BOOL PE_GetModuleNameEx(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ BOOL fOnFailDummyName, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt, _Out_writes_(MAX_PATH) PCHAR szModuleName, _Out_opt_ PDWORD pdwSize);
BOOL PE_GetModuleNameEx(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ BOOL fOnFailDummyName, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt, _Out_writes_(cszModuleName) PCHAR szModuleName, _In_ DWORD cszModuleName, _Out_opt_ PDWORD pdwSize);
_Success_(return)
inline BOOL PE_GetModuleName(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _Out_writes_(MAX_PATH) PCHAR szModuleName)
inline BOOL PE_GetModuleName(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _Out_writes_(cszModuleName) PCHAR szModuleName, _In_ DWORD cszModuleName)
{
return PE_GetModuleNameEx(pProcess, vaModuleBase, FALSE, NULL, szModuleName, NULL);
return PE_GetModuleNameEx(pProcess, vaModuleBase, FALSE, NULL, szModuleName, cszModuleName, NULL);
}
/*
+38 -113
View File
@@ -1,6 +1,6 @@
// pluginmanager.h : implementation of the plugin manager for memory process file system plugins.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
#include "pluginmanager.h"
@@ -33,59 +33,31 @@
// ----------------------------------------------------------------------------
// MODULES CORE FUNCTIONALITY - DEFINES BELOW:
// ----------------------------------------------------------------------------
#define PLUGIN_CONFIG_NUM_PROCESS_CACHE 23
typedef struct tdVMMM_PROCESS_CACHE_ENTRY {
struct tdVMMM_PROCESS_CACHE_ENTRY *FLink;
HANDLE hModuleProcPrivate;
DWORD dwPID;
} VMMM_PROCESS_CACHE_ENTRY, *PVMMM_PROCESS_CACHE_ENTRY;
typedef struct tdPLUGIN_LISTENTRY {
struct tdPLUGIN_LISTENTRY *FLink;
HMODULE hDLL;
HANDLE hModulePrivate;
CHAR szModuleName[32];
BOOL fRootModule;
BOOL fProcessModule;
BOOL(*pfnList)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList);
NTSTATUS(*pfnRead)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset);
NTSTATUS(*pfnWrite)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset);
VOID(*pfnNotify)(_Inout_opt_ PHANDLE phModulePrivate, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent);
VOID(*pfnCloseHandleModule)(_Inout_opt_ PHANDLE phModulePrivate);
VOID(*pfnCloseHandleProcess)(_Inout_opt_ PHANDLE phModulePrivate, _Inout_ PHANDLE phProcessPrivate);
VMMM_PROCESS_CACHE_ENTRY ModuleProcCache[PLUGIN_CONFIG_NUM_PROCESS_CACHE];
VOID(*pfnNotify)(_In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent);
VOID(*pfnClose)();
} PLUGIN_LISTENTRY, *PPLUGIN_LISTENTRY;
// ----------------------------------------------------------------------------
// MODULES CORE FUNCTIONALITY - IMPLEMENTATION BELOW:
// ----------------------------------------------------------------------------
PHANDLE PluginManager_ProcCacheGet(_Inout_ PPLUGIN_LISTENTRY pModule, _In_ DWORD dwPID)
{
PVMMM_PROCESS_CACHE_ENTRY e;
e = &pModule->ModuleProcCache[dwPID % PLUGIN_CONFIG_NUM_PROCESS_CACHE];
while(e) {
if(!e->hModuleProcPrivate || (e->dwPID == dwPID)) {
e->dwPID = dwPID;
return &e->hModuleProcPrivate;
}
if(!e->FLink) {
e->FLink = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMM_PROCESS_CACHE_ENTRY));
}
e = e->FLink;
}
return NULL;
}
VOID PluginManager_ContextInitialize(_Out_ PVMMDLL_PLUGIN_CONTEXT ctx, PPLUGIN_LISTENTRY pModule, _In_opt_ PVMM_PROCESS pProcess, _In_ LPSTR szPath, _In_ BOOL fDll)
VOID PluginManager_ContextInitialize(_Out_ PVMMDLL_PLUGIN_CONTEXT ctx, PPLUGIN_LISTENTRY pModule, _In_opt_ PVMM_PROCESS pProcess, _In_ LPSTR szPath)
{
ctx->magic = VMMDLL_PLUGIN_CONTEXT_MAGIC;
ctx->wVersion = VMMDLL_PLUGIN_CONTEXT_VERSION;
ctx->wSize = sizeof(VMMDLL_PLUGIN_CONTEXT);
ctx->dwPID = (pProcess ? pProcess->dwPID : (DWORD)-1);
ctx->phModulePrivate = &pModule->hModulePrivate;
ctx->pProcess = fDll ? NULL : pProcess;
ctx->phProcessPrivate = pProcess ? PluginManager_ProcCacheGet(pModule, ctx->dwPID) : NULL;
ctx->pProcess = pModule->hDLL ? NULL : pProcess;
ctx->szModule = pModule->szModuleName;
ctx->szPath = szPath;
}
@@ -112,21 +84,11 @@ BOOL PluginManager_List(_In_opt_ PVMM_PROCESS pProcess, _In_ LPSTR szModule, _In
pModule = pModule->FLink;
continue;
}
if(!_stricmp(szModule, pModule->szModuleName)) {
if(pModule->pfnList) {
if(pModule->hDLL) {
PluginManager_ContextInitialize(&ctx, pModule, pProcess, (szPath ? szPath : ""), TRUE);
VmmLockRelease();
result = pModule->pfnList(&ctx, pFileList);
VmmLockAcquire();
Statistics_CallEnd(STATISTICS_ID_PluginManager_List, tmStart);
return result;
} else {
PluginManager_ContextInitialize(&ctx, pModule, pProcess, (szPath ? szPath : ""), FALSE);
Statistics_CallEnd(STATISTICS_ID_PluginManager_List, tmStart);
return pModule->pfnList(&ctx, pFileList);
}
}
if(pModule->pfnList && !_stricmp(szModule, pModule->szModuleName)) {
PluginManager_ContextInitialize(&ctx, pModule, pProcess, (szPath ? szPath : ""));
result = pModule->pfnList(&ctx, pFileList);
Statistics_CallEnd(STATISTICS_ID_PluginManager_List, tmStart);
return result;
}
pModule = pModule->FLink;
}
@@ -145,21 +107,11 @@ NTSTATUS PluginManager_Read(_In_opt_ PVMM_PROCESS pProcess, _In_ LPSTR szModule,
pModule = pModule->FLink;
continue;
}
if(!_stricmp(szModule, pModule->szModuleName)) {
if(pModule->pfnRead) {
if(pModule->hDLL) {
PluginManager_ContextInitialize(&ctx, pModule, pProcess, (szPath ? szPath : ""), TRUE);
VmmLockRelease();
nt = pModule->pfnRead(&ctx, pb, cb, pcbRead, cbOffset);
VmmLockAcquire();
Statistics_CallEnd(STATISTICS_ID_PluginManager_Read, tmStart);
return nt;
} else {
PluginManager_ContextInitialize(&ctx, pModule, pProcess, (szPath ? szPath : ""), FALSE);
Statistics_CallEnd(STATISTICS_ID_PluginManager_Read, tmStart);
return pModule->pfnRead(&ctx, pb, cb, pcbRead, cbOffset);
}
}
if(pModule->pfnRead && !_stricmp(szModule, pModule->szModuleName)) {
PluginManager_ContextInitialize(&ctx, pModule, pProcess, (szPath ? szPath : ""));
nt = pModule->pfnRead(&ctx, pb, cb, pcbRead, cbOffset);
Statistics_CallEnd(STATISTICS_ID_PluginManager_Read, tmStart);
return nt;
}
pModule = pModule->FLink;
}
@@ -178,19 +130,11 @@ NTSTATUS PluginManager_Write(_In_opt_ PVMM_PROCESS pProcess, _In_ LPSTR szModule
pModule = pModule->FLink;
continue;
}
if(!_stricmp(szModule, pModule->szModuleName)) {
if(pModule->hDLL) {
PluginManager_ContextInitialize(&ctx, pModule, pProcess, (szPath ? szPath : ""), TRUE);
VmmLockRelease();
nt = pModule->pfnWrite(&ctx, pb, cb, pcbWrite, cbOffset);
VmmLockAcquire();
Statistics_CallEnd(STATISTICS_ID_PluginManager_Write, tmStart);
return nt;
} else {
PluginManager_ContextInitialize(&ctx, pModule, pProcess, (szPath ? szPath : ""), FALSE);
Statistics_CallEnd(STATISTICS_ID_PluginManager_Write, tmStart);
return pModule->pfnWrite(&ctx, pb, cb, pcbWrite, cbOffset);
}
if(pModule->pfnWrite && !_stricmp(szModule, pModule->szModuleName)) {
PluginManager_ContextInitialize(&ctx, pModule, pProcess, (szPath ? szPath : ""));
nt = pModule->pfnWrite(&ctx, pb, cb, pcbWrite, cbOffset);
Statistics_CallEnd(STATISTICS_ID_PluginManager_Write, tmStart);
return nt;
}
pModule = pModule->FLink;
}
@@ -204,13 +148,7 @@ BOOL PluginManager_Notify(_In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DW
PPLUGIN_LISTENTRY pModule = (PPLUGIN_LISTENTRY)ctxVmm->pVmmVfsModuleList;
while(pModule) {
if(pModule->pfnNotify) {
if(pModule->hDLL) {
VmmLockRelease();
pModule->pfnNotify(&pModule->hModulePrivate, fEvent, pvEvent, cbEvent);
VmmLockAcquire();
} else {
pModule->pfnNotify(&pModule->hModulePrivate, fEvent, pvEvent, cbEvent);
}
pModule->pfnNotify(fEvent, pvEvent, cbEvent);
}
pModule = pModule->FLink;
}
@@ -245,7 +183,6 @@ BOOL PluginManager_Register(_In_ PVMMDLL_PLUGIN_REGINFO pRegInfo)
}
// 2: register module
pModule->hDLL = pRegInfo->hDLL;
pModule->hModulePrivate = pRegInfo->reg_info.hModulePrivate;
strncpy_s(pModule->szModuleName, 32, pRegInfo->reg_info.szModuleName, 32);
pModule->fRootModule = pRegInfo->reg_info.fRootModule;
pModule->fProcessModule = pRegInfo->reg_info.fProcessModule;
@@ -253,8 +190,7 @@ BOOL PluginManager_Register(_In_ PVMMDLL_PLUGIN_REGINFO pRegInfo)
pModule->pfnRead = pRegInfo->reg_fn.pfnRead;
pModule->pfnWrite = pRegInfo->reg_fn.pfnWrite;
pModule->pfnNotify = pRegInfo->reg_fn.pfnNotify;
pModule->pfnCloseHandleModule = pRegInfo->reg_fn.pfnCloseHandleModule;
pModule->pfnCloseHandleProcess = pRegInfo->reg_fn.pfnCloseHandleProcess;
pModule->pfnClose = pRegInfo->reg_fn.pfnClose;
vmmprintfv("PluginManager: Loaded %s module '%s'.\n", (pModule->hDLL ? "native" : "built-in"), pModule->szModuleName);
pModule->FLink = (PPLUGIN_LISTENTRY)ctxVmm->pVmmVfsModuleList;
ctxVmm->pVmmVfsModuleList = pModule;
@@ -263,28 +199,17 @@ BOOL PluginManager_Register(_In_ PVMMDLL_PLUGIN_REGINFO pRegInfo)
VOID PluginManager_Close()
{
DWORD i;
PPLUGIN_LISTENTRY pm;
PVMMM_PROCESS_CACHE_ENTRY pe;
while((pm = (PPLUGIN_LISTENTRY)ctxVmm->pVmmVfsModuleList)) {
// 1: Detach current module list entry from list
ctxVmm->pVmmVfsModuleList = pm->FLink;
// 2: Close process specific module handles
if(pm->pfnCloseHandleProcess) {
for(i = 0; i < PLUGIN_CONFIG_NUM_PROCESS_CACHE; i++) {
while((pe = pm->ModuleProcCache[i].FLink)) {
pm->ModuleProcCache[i].FLink = pe->FLink;
if(pe->hModuleProcPrivate) { pm->pfnCloseHandleProcess(pm->hModulePrivate, pe->hModuleProcPrivate); }
LocalFree(pe);
}
if(pm->ModuleProcCache[i].hModuleProcPrivate) { pm->pfnCloseHandleProcess(pm->hModulePrivate, pm->ModuleProcCache[i].hModuleProcPrivate); }
}
// 2: Close module callback
if(pm->pfnClose) {
pm->pfnClose();
}
// 3: Close module specific handle
if(pm->pfnCloseHandleModule && pm->hModulePrivate) { pm->pfnCloseHandleModule(pm->hModulePrivate); }
// 4: FreeLibrary (if last module belonging to specific Library)
// 3: FreeLibrary (if last module belonging to specific Library)
if(pm->hDLL && !PluginManager_ModuleExists(pm->hDLL, NULL)) { FreeLibrary(pm->hDLL); }
// 5: LocalFree this ListEntry
// 4: LocalFree this ListEntry
LocalFree(pm);
}
}
@@ -309,25 +234,25 @@ VOID PluginManager_Initialize_Python()
VOID(*pfnInitializeVmmPlugin)(_In_ PVMMDLL_PLUGIN_REGINFO pRegInfo);
// 1: Locate Python by trying user-defined path
if(ctxMain->cfg.szPythonPath[0]) {
ZeroMemory(szPythonPath, MAX_PATH);
strcpy_s(szPythonPath, MAX_PATH, ctxMain->cfg.szPythonPath);
strcat_s(szPythonPath, MAX_PATH, "\\python36.dll");
ZeroMemory(szPythonPath, _countof(szPythonPath));
strcpy_s(szPythonPath, _countof(szPythonPath), ctxMain->cfg.szPythonPath);
strcat_s(szPythonPath, _countof(szPythonPath), "\\python36.dll");
hDllPython = LoadLibraryExA(szPythonPath, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
if(!hDllPython) {
ZeroMemory(ctxMain->cfg.szPythonPath, MAX_PATH);
ZeroMemory(ctxMain->cfg.szPythonPath, _countof(ctxMain->cfg.szPythonPath));
vmmprintf("PluginManager: Python initialization failed. Python 3.6 not found on user specified path.\n");
return;
}
}
// 2: Try locate Python by checking the python36 sub-directory relative to the current executable (.exe).
if(0 == ctxMain->cfg.szPythonPath[0]) {
ZeroMemory(szPythonPath, MAX_PATH);
ZeroMemory(szPythonPath, _countof(szPythonPath));
Util_GetPathDll(szPythonPath, NULL);
strcat_s(szPythonPath, MAX_PATH, "python36\\python36.dll");
strcat_s(szPythonPath, _countof(szPythonPath), "python36\\python36.dll");
hDllPython = LoadLibraryExA(szPythonPath, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
if(hDllPython) {
Util_GetPathDll(ctxMain->cfg.szPythonPath, NULL);
strcat_s(ctxMain->cfg.szPythonPath, MAX_PATH, "python36\\");
strcat_s(ctxMain->cfg.szPythonPath, _countof(ctxMain->cfg.szPythonPath), "python36\\");
}
}
// 3: Try locate Python by loading from the current path.
@@ -388,14 +313,14 @@ BOOL PluginManager_Initialize()
M_Status_Initialize(&ri);
// 2: process dll modules
Util_GetPathDll(szPath, NULL);
cchPathBase = (DWORD)strnlen(szPath, MAX_PATH - 1);
strcat_s(szPath, MAX_PATH, "plugins\\m_*.dll");
cchPathBase = (DWORD)strnlen(szPath, _countof(szPath) - 1);
strcat_s(szPath, _countof(szPath), "plugins\\m_*.dll");
hFindFile = FindFirstFileA(szPath, &FindData);
if(hFindFile != INVALID_HANDLE_VALUE) {
do {
szPath[cchPathBase] = '\0';
strcat_s(szPath, MAX_PATH, "plugins\\");
strcat_s(szPath, MAX_PATH, FindData.cFileName);
strcat_s(szPath, _countof(szPath), "plugins\\");
strcat_s(szPath, _countof(szPath), FindData.cFileName);
hDLL = LoadLibraryExA(szPath, 0, 0);
if(!hDLL) {
vmmprintfvv("PluginManager: FAIL: Load DLL: '%s' - missing dependencies?\n", FindData.cFileName);
+1 -1
View File
@@ -1,6 +1,6 @@
// pluginmanager.h : definitions for the plugin manager for memory process file system plugins.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
#ifndef __PLUGINMANAGER_H__
+14
View File
@@ -0,0 +1,14 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by vmm.rc
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
+34 -7
View File
@@ -1,6 +1,6 @@
// statistics.c : implementation of statistics related functionality.
//
// (c) Ulf Frisk, 2016-2018
// (c) Ulf Frisk, 2016-2019
// Author: Ulf Frisk, [email protected]
//
#include "statistics.h"
@@ -213,9 +213,7 @@ const LPSTR NAMES_VMM_STATISTICS_CALL[] = {
"PluginManager_List",
"PluginManager_Read",
"PluginManager_Write",
"PluginManager_Notify",
"DeviceReadScatterMEM",
"DeviceWriteMEM"
"PluginManager_Notify"
};
typedef struct tdCALLSTAT {
@@ -256,18 +254,21 @@ VOID Statistics_CallEnd(_In_ DWORD fId, QWORD tmCallStart)
if(fId > STATISTICS_ID_MAX) { return; }
if(tmCallStart == 0) { return; }
pStat = ((PCALLSTAT)ctxMain->pvStatistics) + fId;
pStat->c++;
InterlockedIncrement64(&pStat->c);
QueryPerformanceCounter((PLARGE_INTEGER)&tmNow);
pStat->tm += tmNow - tmCallStart;
InterlockedAdd64(&pStat->tm, tmNow - tmCallStart);
}
VOID Statistics_CallToString(_In_opt_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcb)
{
BOOL result;
QWORD qwFreq, uS;
DWORD i, o = 0;
PCALLSTAT pStat;
LEECHCORE_STATISTICS LeechCoreStatistics = { 0 };
DWORD cbLeechCoreStatistics = sizeof(LEECHCORE_STATISTICS);
if(!pb) {
*pcb = 71 * (STATISTICS_ID_MAX + 5);
*pcb = 71 * (STATISTICS_ID_MAX + LEECHCORE_STATISTICS_ID_MAX + 6);
return;
}
QueryPerformanceFrequency((PLARGE_INTEGER)&qwFreq);
@@ -280,6 +281,7 @@ VOID Statistics_CallToString(_In_opt_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcb)
"======================================================================\n",
ctxMain->pvStatistics ? "ENABLED " : "DISABLED"
);
// statistics
for(i = 0; i <= STATISTICS_ID_MAX; i++) {
if(ctxMain->pvStatistics) {
pStat = ((PCALLSTAT)ctxMain->pvStatistics) + i;
@@ -304,5 +306,30 @@ VOID Statistics_CallToString(_In_opt_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcb)
NAMES_VMM_STATISTICS_CALL[i],
0, 0, 0ULL);
}
// leechcore statistics
result = LeechCore_CommandData(LEECHCORE_COMMANDDATA_STATISTICS_GET, NULL, 0, (PBYTE)&LeechCoreStatistics, cbLeechCoreStatistics, &cbLeechCoreStatistics);
if(result && (LeechCoreStatistics.magic == LEECHCORE_STATISTICS_MAGIC) && (LeechCoreStatistics.version == LEECHCORE_STATISTICS_VERSION) && LeechCoreStatistics.qwFreq) {
for(i = 0; i <= LEECHCORE_STATISTICS_ID_MAX; i++) {
if(LeechCoreStatistics.Call[i].c) {
uS = (LeechCoreStatistics.Call[i].tm * 1000000ULL) / LeechCoreStatistics.qwFreq;
o += snprintf(
pb + o,
cb - o,
"%-32.32s %8i %8i %16lli\n",
LEECHCORE_STATISTICS_NAME[i],
(DWORD)LeechCoreStatistics.Call[i].c,
(DWORD)(uS / LeechCoreStatistics.Call[i].c),
uS
);
} else {
o += snprintf(
pb + o,
cb - o,
"%-32.32s %8i %8i %16lli\n",
LEECHCORE_STATISTICS_NAME[i],
0, 0, 0ULL);
}
}
}
*pcb = o;
}
+2 -4
View File
@@ -1,6 +1,6 @@
// statistics.h : definitions of statistics related functionality.
//
// (c) Ulf Frisk, 2016-2018
// (c) Ulf Frisk, 2016-2019
// Author: Ulf Frisk, [email protected]
//
#ifndef __STATISTICS_H__
@@ -86,9 +86,7 @@ VOID PageStatUpdate(_Inout_opt_ PPAGE_STATISTICS ps, _In_ QWORD qwAddr, _In_ QWO
#define STATISTICS_ID_PluginManager_Read 0x14
#define STATISTICS_ID_PluginManager_Write 0x15
#define STATISTICS_ID_PluginManager_Notify 0x16
#define STATISTICS_ID_DeviceReadScatterMEM 0x17
#define STATISTICS_ID_DeviceWriteMEM 0x18
#define STATISTICS_ID_MAX 0x18
#define STATISTICS_ID_MAX 0x16
#define STATISTICS_ID_NOLOG 0xffffffff
VOID Statistics_CallSetEnabled(_In_ BOOL fEnabled);
+2 -2
View File
@@ -1,6 +1,6 @@
// util.c : implementation of various utility functions.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
#include "util.h"
@@ -86,7 +86,7 @@ VOID Util_PrintHexAscii(_In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset
Util_FillHexAscii(pb, cb, cbInitialOffset, NULL, &szMax);
if(!(sz = LocalAlloc(0, szMax))) { return; }
Util_FillHexAscii(pb, cb, cbInitialOffset, sz, &szMax);
vmmprintf(sz);
vmmprintf("%s", sz);
LocalFree(sz);
}
+1 -1
View File
@@ -1,6 +1,6 @@
// util.h : definitions of various utility functions.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
#ifndef __UTIL_H__
+22
View File
@@ -0,0 +1,22 @@
#define STRINGIZE2(s) #s
#define STRINGIZE(s) STRINGIZE2(s)
#define VERSION_MAJOR 2
#define VERSION_MINOR 0
#define VERSION_REVISION 0
#define VERSION_BUILD 0
#define VER_FILE_DESCRIPTION_STR "The Memory Process File System : Core"
#define VER_FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_BUILD
#define VER_FILE_VERSION_STR STRINGIZE(VERSION_MAJOR) \
"." STRINGIZE(VERSION_MINOR) \
"." STRINGIZE(VERSION_REVISION) \
"." STRINGIZE(VERSION_BUILD) \
#define VER_COMPANY_NAME_STR ""
#define VER_PRODUCTNAME_STR "vmm"
#define VER_PRODUCT_VERSION VER_FILE_VERSION
#define VER_PRODUCT_VERSION_STR VER_FILE_VERSION_STR
#define VER_ORIGINAL_FILENAME_STR VER_PRODUCTNAME_STR ".dll"
#define VER_INTERNAL_NAME_STR VER_ORIGINAL_FILENAME_STR
#define VER_COPYRIGHT_STR "Copyright (c) Ulf Frisk 2018-2019"
+1063 -420
View File
File diff suppressed because it is too large Load Diff
+355 -168
View File
@@ -1,34 +1,17 @@
// vmm.h : definitions related to virtual memory management support.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
#ifndef __VMM_H__
#define __VMM_H__
#include <windows.h>
#include <stdio.h>
#include "leechcore.h"
typedef unsigned __int64 QWORD, *PQWORD;
#define MEM_IO_SCATTER_HEADER_VERSION 2
typedef struct tdMEM_IO_SCATTER_HEADER {
ULONG64 qwA; // base address (DWORD boundry).
DWORD cbMax; // bytes to read (DWORD boundry, max 0x1000); pbResult must have room for this.
DWORD cb; // bytes read into result buffer.
PBYTE pb; // ptr to 0x1000 sized buffer to receive read bytes.
PVOID pvReserved1; // reserved for use by caller.
PVOID pvReserved2; // reserved for use by caller.
WORD version; // version of struct
WORD Future1; // reserved for future use.
DWORD Future2; // reserved for future use.
ULONG64 qwDeviceA; // device-physical address (used by device layer).
struct {
PVOID pvReserved1;
PVOID pvReserved2;
BYTE pbReserved[32];
} sReserved; // reserved for future use.
} MEM_IO_SCATTER_HEADER, *PMEM_IO_SCATTER_HEADER, **PPMEM_IO_SCATTER_HEADER;
#define VMM_MULTITHREAD_ENABLE
#define VMMOB_DEBUG
// ----------------------------------------------------------------------------
// VMM configuration constants and struct definitions below:
@@ -44,10 +27,14 @@ typedef struct tdMEM_IO_SCATTER_HEADER {
#define VMM_PROCESS_OS_ALLOC_PTR_MAX 0x4 // max number of operating system specific pointers that must be free'd
#define VMM_MEMMAP_ENTRIES_MAX 0x4000
#define VMM_MEMMAP_FLAG_PAGE_W 0x0000000000000002
#define VMM_MEMMAP_FLAG_PAGE_NS 0x0000000000000004
#define VMM_MEMMAP_FLAG_PAGE_NX 0x8000000000000000
#define VMM_MEMMAP_FLAG_PAGE_MASK 0x8000000000000006
#define VMM_MEMMAP_PAGE_W 0x0000000000000002
#define VMM_MEMMAP_PAGE_NS 0x0000000000000004
#define VMM_MEMMAP_PAGE_NX 0x8000000000000000
#define VMM_MEMMAP_PAGE_MASK 0x8000000000000006
#define VMM_MEMMAP_FLAG_MODULES 0x0001
#define VMM_MEMMAP_FLAG_SCAN 0x0002
#define VMM_MEMMAP_FLAG_ALL (VMM_MEMMAP_FLAG_MODULES | VMM_MEMMAP_FLAG_SCAN)
#define VMM_CACHE_TABLESIZE 0x4011 // (not even # to prevent clogging at specific table 'hash' buckets)
#define VMM_CACHE_TLB_ENTRIES 0x4000 // -> 64MB of cached data
@@ -57,9 +44,7 @@ typedef struct tdMEM_IO_SCATTER_HEADER {
#define VMM_FLAG_ZEROPAD_ON_FAIL 0x0002 // zero pad failed physical memory reads and report success if read within range of physical memory.
#define VMM_FLAG_PROCESS_SHOW_TERMINATED 0x0004 // show terminated processes in the process list (if they can be found).
#define VMM_VERSION_MAJOR 1
#define VMM_VERSION_MINOR 2
#define VMM_VERSION_REVISION 1
#define PAGE_SIZE 0x1000
static const LPSTR VMM_MEMORYMODEL_TOSTRING[4] = { "N/A", "X86", "X86PAE", "X64" };
@@ -99,67 +84,146 @@ typedef struct tdVMM_MODULEMAP_ENTRY {
DWORD cbDisplayBufferSections;
} VMM_MODULEMAP_ENTRY, *PVMM_MODULEMAP_ENTRY;
typedef struct tdVMMOB {
BYTE Reserved[0x1c];
DWORD cbData;
} VMMOB, *PVMMOB;
typedef struct tdVMMOBCONTAINER {
CRITICAL_SECTION Lock;
PVMMOB pVmmOb;
} VMMOBCONTAINER, *PVMMOBCONTAINER;
typedef struct tdVMMDATALIST {
DWORD iNext;
QWORD Value;
} VMMDATALIST, *PVMMDATALIST;
typedef struct tdVMMOB_DATA {
BYTE Reserved[0x1c];
DWORD cbData;
union {
BYTE pbData[];
DWORD pdwData[];
QWORD pqwData[];
VMMDATALIST pList[];
};
} VMMOB_DATA, *PVMMOB_PDATA;
typedef struct tdVMMOB_DATASET {
VMMOB ObHdr;
BOOL fUnique;
DWORD c;
DWORD cMax;
DWORD iListStart;
PVMMOB_PDATA pObData;
} VMMOB_DATASET, *PVMMOB_DATASET;
typedef struct tdVMMOB_MEMMAP {
BYTE Reserved[0x1c];
DWORD cbData;
BOOL fValid; // map is valid (did not fail initialization)
BOOL fTagModules; // map contains tags from modules.
BOOL fTagScan; // map contains tags from scan.
DWORD cMap; // # map entries.
DWORD cbDisplay; // byte count of display map (even if not existing yet).
PVMMOB_PDATA pObDisplay; // human readable memory map.
VMM_MEMMAP_ENTRY pMap[]; // map entries
} VMMOB_MEMMAP, *PVMMOB_MEMMAP;
typedef struct tdVMMOB_MODULEMAP {
BYTE Reserved[0x1c];
DWORD cbData;
BOOL fValid; // map is valid (did not fail initialization).
DWORD cMap; // # map entries.
DWORD cbDisplay; // size of 'text' module map.
PBYTE pbDisplay; // 'text' module map stored in-object after pMap).
VMM_MODULEMAP_ENTRY pMap[]; // map entries
} VMMOB_MODULEMAP, *PVMMOB_MODULEMAP;
// 'static' process information that should be kept even in the ase of a total
// process refresh. Only use for information that may never change or things
// that may not affect analysis (like cache preload addresses that only may
// speed things up - but not change analysis result). May also be used by
// internal plugins to store persistent information in various plugin-internal
// thread safe ways. Use with extreme care!
typedef struct tdVMMOB_PROCESS_PERSISTENT {
VMMOB ObHdr;
VMMOBCONTAINER ObCLdrModulesCachePrefetch32;
VMMOBCONTAINER ObCLdrModulesCachePrefetch64;
struct {
QWORD vaVirt2Phys;
} Plugin;
} VMMOB_PROCESS_PERSISTENT, *PVMMOB_PROCESS_PERSISTENT;
typedef struct tdVMM_PROCESS {
VMMOB ObHdr;
CRITICAL_SECTION LockUpdate;
DWORD dwPID;
DWORD dwState; // state of process, 0 = running
QWORD paDTB;
QWORD paDTB_UserOpt;
CHAR szName[16];
BOOL _i_fMigrated;
BOOL fUserOnly;
BOOL fSpiderPageTableDone;
BOOL fTlbSpiderDone;
BOOL fFileCacheDisabled;
// memmap related pointers (free must be called separately)
QWORD cMemMap;
PVMM_MEMMAP_ENTRY pMemMap;
PBYTE pbMemMapDisplayCache;
QWORD cbMemMapDisplayCache;
// module map (free must be called separately)
QWORD cModuleMap;
PVMM_MODULEMAP_ENTRY pModuleMap;
PVMMOB_MEMMAP pObMemMap;
PVMMOB_MODULEMAP pObModuleMap;
PVMMOB_PROCESS_PERSISTENT pObProcessPersistent; // Always exists
union {
struct {
PVOID pvReserved[VMM_PROCESS_OS_ALLOC_PTR_MAX]; // os-specific buffer to be allocated if needed (free'd by VmmClose)
} unk;
struct {
PBYTE pbLdrModulesDisplayCache;
PVOID pbReserved[VMM_PROCESS_OS_ALLOC_PTR_MAX - 1];
DWORD cbLdrModulesDisplayCache;
QWORD vaEPROCESS;
QWORD vaPEB;
DWORD vaPEB32; // WoW64 only
DWORD vaPEB32; // WoW64 only
QWORD vaENTRY;
BOOL fWow64;
} win;
} os;
struct {
VMMOBCONTAINER ObCLdrModulesDisplayCache;
} Plugin;
} VMM_PROCESS, *PVMM_PROCESS;
typedef struct tdVMM_PROCESS_TABLE {
SIZE_T c;
WORD iFLink;
WORD iFLinkM[VMM_PROCESSTABLE_ENTRIES_MAX];
PVMM_PROCESS M[VMM_PROCESSTABLE_ENTRIES_MAX];
struct tdVMM_PROCESS_TABLE *ptNew;
} VMM_PROCESS_TABLE, *PVMM_PROCESS_TABLE;
#define VMM_CACHE2_REGIONS 17
#define VMM_CACHE2_BUCKETS 2039
#define VMM_CACHE2_MAX_ENTRIES 0x8000
#define VMM_CACHE_ENTRY_MAGIC 0x29d50298c4921034
#define VMM_CACHE_TAG_PHYS 'Ph'
#define VMM_CACHE_TAG_TLB 'Tb'
typedef struct tdVMM_CACHE_ENTRY {
QWORD qwMAGIC;
struct tdVMM_CACHE_ENTRY *FLink;
struct tdVMM_CACHE_ENTRY *BLink;
struct tdVMM_CACHE_ENTRY *AgeFLink;
struct tdVMM_CACHE_ENTRY *AgeBLink;
QWORD tm;
typedef struct tdVMMOB_MEM {
BYTE Reserved[0x1c];
DWORD cbData;
SLIST_ENTRY SListTotal;
SLIST_ENTRY SListEmpty;
struct tdVMMOB_MEM *FLink;
struct tdVMMOB_MEM *BLink;
struct tdVMMOB_MEM *AgeFLink;
struct tdVMMOB_MEM *AgeBLink;
MEM_IO_SCATTER_HEADER h;
BYTE pb[0x1000];
} VMM_CACHE_ENTRY, *PVMM_CACHE_ENTRY, **PPVMM_CACHE_ENTRY;
union {
BYTE pb[0x1000];
DWORD pdw[0x400];
QWORD pqw[0x200];
};
} VMMOB_MEM, *PVMMOB_MEM, **PPVMMOB_MEM;
typedef struct tdVMM_CACHE_TABLE {
PVMM_CACHE_ENTRY M[VMM_CACHE_TABLESIZE];
PVMM_CACHE_ENTRY AgeFLink;
PVMM_CACHE_ENTRY AgeBLink;
PVMM_CACHE_ENTRY S;
SLIST_HEADER ListHeadEmpty;
SLIST_HEADER ListHeadTotal;
DWORD cEmpty;
DWORD cTotal;
BOOL fActive;
WORD tag;
WORD iReclaimLast;
struct {
DWORD c;
DWORD dwFuture;
CRITICAL_SECTION Lock;
PVMMOB_MEM AgeFLink;
PVMMOB_MEM AgeBLink;
PVMMOB_MEM B[VMM_CACHE2_BUCKETS];
} R[VMM_CACHE2_REGIONS];
} VMM_CACHE_TABLE, *PVMM_CACHE_TABLE;
typedef struct tdVMM_VIRT2PHYS_INFORMATION {
@@ -171,15 +235,14 @@ typedef struct tdVMM_VIRT2PHYS_INFORMATION {
} VMM_VIRT2PHYS_INFORMATION, *PVMM_VIRT2PHYS_INFORMATION;
typedef struct tdVMM_MEMORYMODEL_FUNCTIONS {
VOID(*pfnInitialize)();
VOID(*pfnClose)();
BOOL(*pfnVirt2Phys)(_In_ QWORD paDTB, _In_ BOOL fUserOnly, _In_ BYTE iPML, _In_ QWORD va, _Out_ PQWORD ppa);
VOID(*pfnVirt2PhysGetInformation)(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo);
VOID(*pfnMapInitialize)(_In_ PVMM_PROCESS pProcess);
VOID(*pfnMapTag)(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaBase, _In_ QWORD vaLimit, _In_opt_ LPSTR szTag, _In_opt_ LPWSTR wszTag, _In_opt_ BOOL fWoW64);
PVMM_MEMMAP_ENTRY(*pfnMapGetEntry)(_In_ PVMM_PROCESS pProcess, _In_ QWORD va);
VOID(*pfnMapDisplayBufferGenerate)(_In_ PVMM_PROCESS pProcess);
VOID(*pfnTlbSpider)(_In_ QWORD paDTB, _In_ BOOL fUserOnly);
VOID(*pfnMapTag)(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaBase, _In_ QWORD vaLimit, _In_opt_ LPSTR szTag, _In_opt_ LPWSTR wszTag, _In_ BOOL fWoW64, _In_ BOOL fOverwrite);
BOOL(*pfnMapGetEntries)(_In_ PVMM_PROCESS pProcess, _In_ DWORD flags, _Out_ PVMMOB_MEMMAP *ppObMemMap);
BOOL(*pfnMapGetDisplay)(_In_ PVMM_PROCESS pProcess, _In_ DWORD flags, _Out_ PVMMOB_PDATA *ppObDisplay);
VOID(*pfnTlbSpider)(_In_ PVMM_PROCESS pProcess);
BOOL(*pfnTlbPageTableVerify)(_Inout_ PBYTE pb, _In_ QWORD pa, _In_ BOOL fSelfRefReq);
} VMM_MEMORYMODEL_FUNCTIONS;
@@ -189,36 +252,17 @@ typedef struct tdVMM_MEMORYMODEL_FUNCTIONS {
typedef struct tdVmmConfig {
CHAR szMountPoint[1];
CHAR szDevTpOrFileName[MAX_PATH];
CHAR szPythonPath[MAX_PATH];
QWORD paCR3;
QWORD paAddrMax;
// flags below
BOOL fCommandIdentify;
BOOL fVerboseDll;
BOOL fVerbose;
BOOL fVerboseExtra;
BOOL fVerboseExtraTlp;
BOOL fDisableBackgroundRefresh;
} VMMCONFIG, *PVMMCONFIG;
typedef enum tdVMM_DEVICE_TYPE {
VMM_DEVICE_NA,
VMM_DEVICE_FILE,
VMM_DEVICE_PCILEECH_DLL,
} VMM_DEVICE_TYPE;
typedef struct tdVmmDeviceConfig {
HANDLE hDevice;
QWORD paAddrMaxNative;
QWORD qwMaxSizeMemIo;
VMM_DEVICE_TYPE tp;
VOID(*pfnReadScatterMEM)(_Inout_ PPMEM_IO_SCATTER_HEADER ppDMAs, _In_ DWORD cpDMAs, _Out_opt_ PDWORD pcpDMAsRead);
BOOL(*pfnWriteMEM)(_In_ QWORD qwAddr, _In_ PBYTE pb, _In_ DWORD cb);
VOID(*pfnClose)();
BOOL(*pfnGetOption)(_In_ QWORD fOption, _Out_ PQWORD pqwValue);
BOOL(*pfnSetOption)(_In_ QWORD fOption, _In_ QWORD qwValue);
} VMMDEVICE_CONFIG, *PVMMDEVICE_CONFIG;
typedef struct tdVMM_STATISTICS {
QWORD cPhysCacheHit;
QWORD cPhysReadSuccess;
@@ -233,11 +277,25 @@ typedef struct tdVMM_STATISTICS {
QWORD cRefreshProcessFull;
} VMM_STATISTICS, *PVMM_STATISTICS;
typedef struct tdVMM_WIN_EPROCESS_OFFSET {
BOOL fValid;
WORD cbMaxOffset;
WORD State;
WORD DTB;
WORD Name;
WORD PID;
WORD FLink;
WORD BLink;
WORD PEB;
WORD DTB_User;
} VMM_WIN_EPROCESS_OFFSET, *PVMM_WIN_EPROCESS_OFFSET;
typedef struct tdVMM_KERNELINFO {
QWORD paDTB;
QWORD vaBase;
QWORD cbSize;
// optional non-required values below
VMM_WIN_EPROCESS_OFFSET OffsetEPROCESS;
QWORD vaEntry;
QWORD vaPsLoadedModuleList;
QWORD vaKDBG;
@@ -245,10 +303,7 @@ typedef struct tdVMM_KERNELINFO {
typedef struct tdVMM_CONTEXT {
CRITICAL_SECTION MasterLock;
PVMM_PROCESS_TABLE ptPROC;
PVMM_CACHE_TABLE ptTLB;
PVMM_CACHE_TABLE ptPHYS;
BOOL fReadOnly;
VMMOBCONTAINER PROC; // contains VMM_PROCESS_TABLE
VMM_MEMORYMODEL_FUNCTIONS fnMemoryModel;
VMM_MEMORYMODEL_TP tpMemoryModel;
BOOL f32;
@@ -266,11 +321,14 @@ typedef struct tdVMM_CONTEXT {
VMM_STATISTICS stat;
VMM_KERNELINFO kernel;
PVOID pVmmVfsModuleList;
VMMOBCONTAINER ObCEPROCESSCachePrefetch;
VMM_CACHE_TABLE PHYS;
VMM_CACHE_TABLE TLB;
} VMM_CONTEXT, *PVMM_CONTEXT;
typedef struct tdVMM_MAIN_CONTEXT {
VMMCONFIG cfg;
VMMDEVICE_CONFIG dev;
LEECHCORE_CONFIG dev;
PVOID pvStatistics;
} VMM_MAIN_CONTEXT, *PVMM_MAIN_CONTEXT;
@@ -281,34 +339,154 @@ typedef struct tdVMM_MAIN_CONTEXT {
PVMM_CONTEXT ctxVmm;
PVMM_MAIN_CONTEXT ctxMain;
#define vmmprintf(format, ...) { if(ctxMain->cfg.fVerboseDll) { printf(format, ##__VA_ARGS__); } }
#define vmmprintfv(format, ...) { if(ctxMain->cfg.fVerbose) { printf(format, ##__VA_ARGS__); } }
#define vmmprintfvv(format, ...) { if(ctxMain->cfg.fVerboseExtra) { printf(format, ##__VA_ARGS__); } }
#define vmmprintfvvv(format, ...) { if(ctxMain->cfg.fVerboseExtraTlp) { printf(format, ##__VA_ARGS__); } }
#define vmmprintf(format, ...) { if(ctxMain->cfg.fVerboseDll) { printf(format, ##__VA_ARGS__); } }
#define vmmprintfv(format, ...) { if(ctxMain->cfg.fVerbose) { printf(format, ##__VA_ARGS__); } }
#define vmmprintfvv(format, ...) { if(ctxMain->cfg.fVerboseExtra) { printf(format, ##__VA_ARGS__); } }
#define vmmprintfvvv(format, ...) { if(ctxMain->cfg.fVerboseExtraTlp) { printf(format, ##__VA_ARGS__); } }
#define vmmprintf_fn(format, ...) vmmprintf("%s: "format, __func__, ##__VA_ARGS__);
#define vmmprintfv_fn(format, ...) vmmprintfv("%s: "format, __func__, ##__VA_ARGS__);
#define vmmprintfvv_fn(format, ...) vmmprintfvv("%s: "format, __func__, ##__VA_ARGS__);
#define vmmprintfvvv_fn(format, ...) vmmprintfvvv("%s: "format, __func__, ##__VA_ARGS__);
// ----------------------------------------------------------------------------
// VMM reserved for memory model use only functions below:
// CACHE AND TLB FUNCTIONALITY BELOW:
// ----------------------------------------------------------------------------
PMEM_IO_SCATTER_HEADER VmmCacheGet(_In_ PVMM_CACHE_TABLE t, _In_ QWORD qwA);
VOID VmmCachePut(_Inout_ PVMM_CACHE_TABLE t, _In_ PVMM_CACHE_ENTRY e);
PVMM_CACHE_ENTRY VmmCacheReserve(_Inout_ PVMM_CACHE_TABLE t);
/*
* Retrieve an item from the cache.
* CALLER DECREF: return
* -- wTblTag
* -- qwA
* -- return
*/
PVMMOB_MEM VmmCacheGet(_In_ WORD wTblTag, _In_ QWORD qwA);
/*
* Retrieve a page table (0x1000 bytes) via the TLB cache.
* CALLER DECREF: return
* -- pa
* -- fCacheOnly = if set do not make a request to underlying device if not in cache.
* -- return
*/
PVMMOB_MEM VmmTlbGetPageTable(_In_ QWORD pa, _In_ BOOL fCacheOnly);
/*
* Check if an address page exists in the indicated cache.
* -- wTblTag
* -- qwA
* -- return
*/
BOOL VmmCacheExists(_In_ WORD wTblTag, _In_ QWORD qwA);
/*
* Check out an empty memory cache item from the cache. NB! once the item is
* filled (successfully or unsuccessfully) it must be returned to the cache with
* VmmCacheReserveReturn and must _NOT_ otherwise be DEFREF'ed.
* CALLER DECREF SPECIAL: return
* -- wTblTag
* -- return
*/
PVMMOB_MEM VmmCacheReserve(_In_ WORD wTblTag);
/*
* Return an entry retrieved with VmmCacheReserve to the cache.
* NB! no other items may be returned with this function!
* FUNCTION DECREF SPECIAL: pOb
* -- pOb
*/
VOID VmmCacheReserveReturn(_In_opt_ PVMMOB_MEM pOb);
// ----------------------------------------------------------------------------
// VMM object manager function definitions below:
// ----------------------------------------------------------------------------
/*
* Allocate a new vmm object manager memory object.
* -- tag = tag identifying the type of object.
* -- uFlags = flags as given by LocalAlloc.
* -- uBytes = bytes of object (excluding object header).
* -- pfnRef_0 = optional callback for cleanup o be called before object is destroyed.
* (if object contains objects which references should be decremented
before destruction of this 'parent' object).
* -- pfnRef_1 = optional callback for when object reach refcount = 1 at DECREF.
* -- return = allocated object on success, with refcount = 1, - NULL on fail.
*/
PVOID VmmOb_Alloc(_In_ WORD tag, _In_ UINT uFlags, _In_ SIZE_T uBytes, _In_opt_ VOID(*pfnRef_0)(_In_ PVOID pVmmOb), _In_opt_ VOID(*pfnRef_1)(_In_ PVOID pVmmOb));
/*
* Increase the reference count of a vmm object by one.
* -- pVmmOb
* -- return
*/
PVOID VmmOb_INCREF(PVOID pVmmOb);
/*
* Decrease the reference count of a vmm object by one.
* NB! Do not use object after DECREF - other threads might have also DECREF'ed
* the object at same time making it to be free'd - making the memory invalid.
*/
VOID VmmOb_DECREF(PVOID pVmmOb);
/*
* Retrieve an enclosed VmmOb from the given pVmmObContainer. Reference count
* of the retrieved VmmOb must be decremented by caller after use is completed!
*/
PVOID VmmObContainer_GetOb(_In_ PVMMOBCONTAINER pVmmObContainer);
/*
* Set or Replace a VmmOb in the pVmmObContainer.
*/
VOID VmmObContainer_SetOb(_In_ PVMMOBCONTAINER pVmmObContainer, _In_opt_ PVOID pVmmOb);
/*
* Allocate a VmmObDataSet and optionally set it to only contain unique items.
* CALLER_DECREF: return
* -- fUnique = set will only contain unique values.
* -- return
*/
PVMMOB_DATASET VmmObDataSet_Alloc(_In_ BOOL fUnique);
/*
* Insert a value into a VmmObDataSet.
* This function is not meant to be called in a multi-threaded context.
* -- pDataSet
* -- v
* -- return = insertion was successful.
*/
BOOL VmmObDataSet_Put(_In_ PVMMOB_DATASET pDataSet, _In_ QWORD v);
// ----------------------------------------------------------------------------
// VMM function definitions below:
// ----------------------------------------------------------------------------
#ifdef VMM_MULTITHREAD_ENABLE
#define VmmLockAcquire() // no need to acquire lock if multithreaded access is ok
#define VmmLockRelease() // no need to acquire lock if multithreaded access is ok
#else /* VMM_MULTITHREAD_ENABLE */
/*
* Acquire the VMM master lock. Required if interoperating with the VMM from a
* function that has not already acquired the lock. Lock must be relased in a
* fairly short amount of time in order for the VMM to continue working.
* !!! MUST NEVER BE ACQUIRED FOR LENGTHY AMOUNT OF TIMES !!!
*/
VOID VmmLockAcquire();
inline VOID VmmLockAcquire()
{
EnterCriticalSection(&ctxVmm->MasterLock);
}
/*
* Release VMM master lock that has previously been acquired by VmmLockAcquire.
*/
VOID VmmLockRelease();
inline VOID VmmLockRelease()
{
LeaveCriticalSection(&ctxVmm->MasterLock);
}
#endif /* VMM_MULTITHREAD_ENABLE */
/*
* Write a virtually contigious arbitrary amount of memory.
@@ -404,14 +582,6 @@ VOID VmmReadScatterPhysical(_Inout_ PPMEM_IO_SCATTER_HEADER ppMEMsPhys, _In_ DWO
*/
BOOL VmmReadPhysicalPage(_In_ QWORD qwPA, _Inout_bytecount_(4096) PBYTE pbPage);
/*
* Retrieve a page table (0x1000 bytes) via the TLB cache.
* -- pa
* -- fCacheOnly = if set do not make a request to underlying device if not in cache.
* -- return
*/
PBYTE VmmTlbGetPageTable(_In_ QWORD pa, _In_ BOOL fCacheOnly);
/*
* Translate a virtual address to a physical address by walking the page tables.
* -- paDTB
@@ -445,14 +615,12 @@ inline BOOL VmmVirt2Phys(_In_ PVMM_PROCESS pProcess, _In_ QWORD va, _Out_ PQWORD
* Spider the TLB (page table cache) to load all page table pages into the cache.
* This is done to speed up various subsequent virtual memory accesses.
* NB! pages may fall out of the cache if it's in heavy use or doe to timing.
* -- paDTB = physical adderss of the Directory Table Base (DTB) to spider.
(aka. Page Mapping Level 4 table in x64).
* -- fUserOnly = only spider user-mode (ring3) pages, no kernel pages.
* -- pProcess
*/
inline VOID VmmTlbSpider(_In_ QWORD paDTB, _In_ BOOL fUserOnly)
inline VOID VmmTlbSpider(_In_ PVMM_PROCESS pProcess)
{
if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_NA) { return; }
ctxVmm->fnMemoryModel.pfnTlbSpider(paDTB, fUserOnly);
ctxVmm->fnMemoryModel.pfnTlbSpider(pProcess);
}
/*
@@ -480,17 +648,6 @@ inline VOID VmmVirt2PhysGetInformation(_Inout_ PVMM_PROCESS pProcess, _Inout_ PV
ctxVmm->fnMemoryModel.pfnVirt2PhysGetInformation(pProcess, pVirt2PhysInfo);
}
/*
* Initialize the memory map for a specific process. This may take some time
* especially for kernel/system processes.
* -- pProcess
*/
inline VOID VmmMapInitialize(_In_ PVMM_PROCESS pProcess)
{
if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_NA) { return; }
ctxVmm->fnMemoryModel.pfnMapInitialize(pProcess);
}
/*
* Map a tag into the sorted memory map in O(log2) operations. Supply only one
* of szTag or wszTag. Tags are usually module/dll name.
@@ -500,57 +657,79 @@ inline VOID VmmMapInitialize(_In_ PVMM_PROCESS pProcess)
* -- szTag
* -- wszTag
* -- fWoW64
* -- fOverwrite
*/
inline VOID VmmMapTag(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaBase, _In_ QWORD vaLimit, _In_opt_ LPSTR szTag, _In_opt_ LPWSTR wszTag, _In_opt_ BOOL fWoW64)
inline VOID VmmMemMapTag(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaBase, _In_ QWORD vaLimit, _In_opt_ LPSTR szTag, _In_opt_ LPWSTR wszTag, _In_opt_ BOOL fWoW64, _In_ BOOL fOverwrite)
{
if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_NA) { return; }
ctxVmm->fnMemoryModel.pfnMapTag(pProcess, vaBase, vaLimit, szTag, wszTag, fWoW64);
ctxVmm->fnMemoryModel.pfnMapTag(pProcess, vaBase, vaLimit, szTag, wszTag, fWoW64, fOverwrite);
}
/*
* Retrieve a memory map entry info given a specific address.
* Retrieve the memory map.
* CALLER DECREF: ppObMemMap
* -- pProcess
* -- qwVA
* -- return = the memory map entry or NULL if not found.
*/
inline PVMM_MEMMAP_ENTRY VmmMapGetEntry(_In_ PVMM_PROCESS pProcess, _In_ QWORD va)
{
if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_NA) { return NULL; }
return ctxVmm->fnMemoryModel.pfnMapGetEntry(pProcess, va);
}
/*
* Generate the human-readable text byte-buffer representing an already existing
* memory map in the process. This memory map must have been initialized with a
* separate call to VmmMapInitialize.
* -- pProcess
*/
inline VOID VmmMapDisplayBufferGenerate(_In_ PVMM_PROCESS pProcess)
{
if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_NA) { return; }
ctxVmm->fnMemoryModel.pfnMapDisplayBufferGenerate(pProcess);
}
/*
* Create or re-create the entire process table. This will clean the complete and
* all existing processes will be cleared.
* -- flags
* -- ppObMemMap
* -- return
*/
BOOL VmmProcessCreateTable();
_Success_(return)
inline BOOL VmmMemMapGetEntries(_In_ PVMM_PROCESS pProcess, _In_ DWORD flags, _Out_ PVMMOB_MEMMAP *ppObMemMap)
{
if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_NA) { return FALSE; }
return ctxVmm->fnMemoryModel.pfnMapGetEntries(pProcess, flags, ppObMemMap);
}
/*
* Retrieve a human-readable memory map as text in buffer.
* CALLER DECREF: ppObDisplay
* -- pProcess
* -- flags = flags as specified by VMM_MAP_FLAGS*
* -- ppObDisplay
* -- return
*/
_Success_(return)
inline BOOL VmmMemMapGetDisplay(_In_ PVMM_PROCESS pProcess, _In_ DWORD flags, _Out_ PVMMOB_PDATA *ppObDisplay)
{
if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_NA) { return FALSE; }
return ctxVmm->fnMemoryModel.pfnMapGetDisplay(pProcess, flags, ppObDisplay);
}
/*
* Retrieve an existing process given a process id (PID).
* CALLER DECREF: return
* -- dwPID
* -- return = a process struct, or NULL if not found.
*/
PVMM_PROCESS VmmProcessGet(_In_ DWORD dwPID);
/*
* Create a new process item. New process items are created in a separate data
* structure and won't become visible to the "Process" functions until after the
* VmmProcessCreateFinish have been called.
* Retrieve the next process given a process. This may be useful when iterating
* over a process list. NB! Listing of next item may fail prematurely if the
* previous process is terminated while having a reference to it.
* FUNCTION DECREF: pProcess
* CALLER DECREF: return
* -- pProcess = a process struct, or NULL if first.
NB! function DECREF's pProcess and must not be used after call!
* -- return = a process struct, or NULL if not found.
*/
PVMM_PROCESS VmmProcessCreateEntry(_In_ DWORD dwPID, _In_ DWORD dwState, _In_ QWORD paDTB, _In_ QWORD paDTB_UserOpt, _In_ CHAR szName[16], _In_ BOOL fUserOnly, _In_ BOOL fSpiderPageTableDone);
PVMM_PROCESS VmmProcessGetNext(_In_opt_ PVMM_PROCESS pProcess);
/*
* Create a new process object. New process object are created in a separate
* data structure and won't become visible to the "Process" functions until
* after the VmmProcessCreateFinish have been called.
* CALLER DECREF: return
* -- fTotalRefresh = create a completely new entry - i.e. do not copy any form
* of data from the old entry such as module and memory maps.
* -- dwPID
* -- dwState
* -- paDTB
* -- paDTB_UserOpt
* -- szName
* -- fUserOnly = user mode process (hide supervisor pages from view)
*/
PVMM_PROCESS VmmProcessCreateEntry(_In_ BOOL fTotalRefresh, _In_ DWORD dwPID, _In_ DWORD dwState, _In_ QWORD paDTB, _In_ QWORD paDTB_UserOpt, _In_ CHAR szName[16], _In_ BOOL fUserOnly);
/*
* Activate the pending, not yet active, processes added by VmmProcessCreateEntry.
@@ -563,20 +742,28 @@ VOID VmmProcessCreateFinish();
* -- pPIDs = user allocated DWORD array to receive result, or NULL.
* -- pcPIDs = ptr to number of DWORDs in pPIDs on entry - number of PIDs in system on exit.
*/
VOID VmmProcessListPIDs(_Out_opt_ PDWORD pPIDs, _Inout_ PSIZE_T pcPIDs);
VOID VmmProcessListPIDs(_Out_writes_opt_(*pcPIDs) PDWORD pPIDs, _Inout_ PSIZE_T pcPIDs);
/*
/*
* Clear the specified cache from all entries.
* -- fTLB
* -- fPHYS
* -- wTblTag
*/
VOID VmmCacheClear( _In_ BOOL fTLB, _In_ BOOL fPHYS);
VOID VmmCacheClear(_In_ WORD wTblTag);
/*
* Invalidate cache entries belonging to a specific physical address.
* -- pa
*/
VOID VmmCacheInvalidate( _In_ QWORD pa);
VOID VmmCacheInvalidate(_In_ QWORD pa);
/*
* Prefetch a set of addresses contained in pObPrefetchAddresses into the cache.
* This is useful when reading data from somewhat known addresses over higher
* latency connections.
* -- pProcess
* -- pObPrefetchAddresses
*/
VOID VmmCachePrefetch(_In_ PVMM_PROCESS pProcess, _In_opt_ PVMMOB_DATASET pObPrefetchAddresses);
/*
* Initialize the memory model specified and discard any previous memory models
BIN
View File
Binary file not shown.
+49 -29
View File
@@ -12,9 +12,10 @@
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{18BEBDF1-73F2-4ABB-BDBE-507ADAB32494}</ProjectGuid>
<ProjectGuid>{6326FCE0-1BA5-4AEC-9973-7783309FFD6B}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>vmm</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
@@ -22,6 +23,7 @@
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
@@ -29,6 +31,7 @@
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@@ -43,101 +46,118 @@
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)\files\</OutDir>
<IntDir>$(SolutionDir)\files\temp\$(ProjectName)\</IntDir>
<TargetExt>.dll</TargetExt>
<LinkIncremental />
<ExecutablePath>$(VC_ExecutablePath_x64);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(FxCopDir);$(PATH)</ExecutablePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>$(SolutionDir)\files\</OutDir>
<IntDir>$(SolutionDir)\files\temp\$(ProjectName)\</IntDir>
<TargetExt>.dll</TargetExt>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<PreprocessorDefinitions>_DEBUG;VMM_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<CompileAs>CompileAsC</CompileAs>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ModuleDefinitionFile>vmmdll.def</ModuleDefinitionFile>
<LinkTimeCodeGeneration>
</LinkTimeCodeGeneration>
<ProgramDatabaseFile>$(OutDir)\lib\$(TargetName).pdb</ProgramDatabaseFile>
<ImportLibrary>$(OutDir)\lib\$(TargetName).lib</ImportLibrary>
<AdditionalDependencies>$(SolutionDir)\files\leechcore.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>copy "$(OutDir)\lib\vmm.lib" "$(OutDir)\vmm.lib" /y</Command>
<Command>
copy "$(OutDir)\lib\vmm.lib" "$(OutDir)\vmm.lib" /y</Command>
</PostBuildEvent>
<PreBuildEvent>
<Command>copy $(SolutionDir)\files\leechcore.h $(ProjectDir)\ /y
copy $(ProjectDir)\vmmdll.h $(SolutionDir)\files\ /y</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<PreprocessorDefinitions>NDEBUG;VMM_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<CompileAs>CompileAsC</CompileAs>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ModuleDefinitionFile>vmmdll.def</ModuleDefinitionFile>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
<ProgramDatabaseFile>$(OutDir)\lib\$(TargetName).pdb</ProgramDatabaseFile>
<ImportLibrary>$(OutDir)\lib\$(TargetName).lib</ImportLibrary>
<AdditionalDependencies>$(SolutionDir)\files\leechcore.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>copy "$(OutDir)\lib\vmm.lib" "$(OutDir)\vmm.lib" /y</Command>
<Command>
copy "$(OutDir)\lib\vmm.lib" "$(OutDir)\vmm.lib" /y</Command>
</PostBuildEvent>
<PreBuildEvent>
<Command>copy $(SolutionDir)\files\leechcore.h $(ProjectDir)\ /y
copy $(ProjectDir)\vmmdll.h $(SolutionDir)\files\ /y</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<None Include="vmmdll.def" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="device.h" />
<ClInclude Include="devicefile.h" />
<ClInclude Include="devicepcileechdll.h" />
<ClInclude Include="leechcore.h" />
<ClInclude Include="mm_x64.h" />
<ClInclude Include="mm_x86.h" />
<ClInclude Include="mm_x86pae.h" />
<ClInclude Include="m_ldrmodules.h" />
<ClInclude Include="m_status.h" />
<ClInclude Include="m_virt2phys.h" />
<ClInclude Include="pcileech_dll.h" />
<ClInclude Include="pe.h" />
<ClInclude Include="pluginmanager.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="statistics.h" />
<ClInclude Include="util.h" />
<ClInclude Include="pluginmanager.h" />
<ClInclude Include="version.h" />
<ClInclude Include="vmm.h" />
<ClInclude Include="vmmdll.h" />
<ClInclude Include="m_ldrmodules.h" />
<ClInclude Include="vmmproc.h" />
<ClInclude Include="vmmvfs.h" />
<ClInclude Include="vmmwin.h" />
<ClInclude Include="vmmvfs.h" />
<ClInclude Include="m_virt2phys.h" />
<ClInclude Include="vmmwininit.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="device.c" />
<ClCompile Include="devicefile.c" />
<ClCompile Include="devicepcileechdll.c" />
<ClCompile Include="mm_x64.c" />
<ClCompile Include="mm_x86.c" />
<ClCompile Include="mm_x86pae.c" />
<ClCompile Include="m_ldrmodules.c" />
<ClCompile Include="m_status.c" />
<ClCompile Include="m_virt2phys.c" />
<ClCompile Include="pe.c" />
<ClCompile Include="pluginmanager.c" />
<ClCompile Include="statistics.c" />
<ClCompile Include="util.c" />
<ClCompile Include="vmm.c" />
<ClCompile Include="vmmdll.c" />
<ClCompile Include="m_ldrmodules.c" />
<ClCompile Include="vmmproc.c" />
<ClCompile Include="vmmvfs.c" />
<ClCompile Include="vmmwin.c" />
<ClCompile Include="vmmvfs.c" />
<ClCompile Include="pluginmanager.c" />
<ClCompile Include="m_virt2phys.c" />
<ClCompile Include="vmmwininit.c" />
</ItemGroup>
<ItemGroup>
<None Include="vmmdll.def" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="vmm.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
+47 -54
View File
@@ -13,38 +13,12 @@
<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="Header Files\pcileech">
<UniqueIdentifier>{bc9b7cdb-d6b1-4bb5-9c1a-6f105979cac4}</UniqueIdentifier>
<Filter Include="Header Files\leechcore">
<UniqueIdentifier>{aedb4365-6f4c-4a1b-b130-a1d3adc27bf6}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="vmmdll.def">
<Filter>Resource Files</Filter>
</None>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pcileech_dll.h">
<Filter>Header Files\pcileech</Filter>
</ClInclude>
<ClInclude Include="device.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="devicefile.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="devicepcileechdll.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="m_ldrmodules.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="m_status.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="m_virt2phys.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="pluginmanager.h">
<ClInclude Include="vmmdll.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="statistics.h">
@@ -62,6 +36,18 @@
<ClInclude Include="vmmvfs.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="pluginmanager.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="m_ldrmodules.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="m_status.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="m_virt2phys.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="mm_x64.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -74,36 +60,24 @@
<ClInclude Include="pe.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vmmdll.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vmmwin.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vmmwininit.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="leechcore.h">
<Filter>Header Files\leechcore</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="version.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="device.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="devicefile.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="devicepcileechdll.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="m_ldrmodules.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="m_status.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="m_virt2phys.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="pluginmanager.c">
<ClCompile Include="vmmdll.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="statistics.c">
@@ -115,15 +89,24 @@
<ClCompile Include="vmm.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vmmdll.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vmmproc.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vmmvfs.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="m_virt2phys.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="m_ldrmodules.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="m_status.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="pluginmanager.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="mm_x64.c">
<Filter>Source Files</Filter>
</ClCompile>
@@ -143,4 +126,14 @@
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="vmmdll.def">
<Filter>Resource Files</Filter>
</None>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="vmm.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>
+6 -1
View File
@@ -1,4 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>
+187 -169
View File
@@ -1,15 +1,16 @@
// vmmdll.h : implementation of core dynamic link library (dll) functionality
// of the virtual memory manager (VMM) for The Memory Process File System.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
#include "vmmdll.h"
#include "device.h"
#include "pluginmanager.h"
#include "util.h"
#include "pe.h"
#include "statistics.h"
#include "version.h"
#include "vmm.h"
#include "vmmproc.h"
#include "vmmwin.h"
@@ -66,7 +67,7 @@ BOOL VmmDll_ConfigIntialize(_In_ DWORD argc, _In_ char* argv[])
if(0 == _stricmp(argv[i], "")) {
i++;
continue;
} else if(0 == _stricmp(argv[i], "-vdll")) {
} else if(0 == _stricmp(argv[i], "-printf")) {
ctxMain->cfg.fVerboseDll = TRUE;
i++;
continue;
@@ -86,6 +87,10 @@ BOOL VmmDll_ConfigIntialize(_In_ DWORD argc, _In_ char* argv[])
ctxMain->cfg.fCommandIdentify = TRUE;
i++;
continue;
} else if(0 == _stricmp(argv[i], "-norefresh")) {
ctxMain->cfg.fDisableBackgroundRefresh = TRUE;
i++;
continue;
} else if(i + 1 >= argc) {
return FALSE;
} else if(0 == strcmp(argv[i], "-cr3")) {
@@ -93,11 +98,15 @@ BOOL VmmDll_ConfigIntialize(_In_ DWORD argc, _In_ char* argv[])
i += 2;
continue;
} else if(0 == strcmp(argv[i], "-max")) {
ctxMain->cfg.paAddrMax = Util_GetNumeric(argv[i + 1]);
ctxMain->dev.paMax = Util_GetNumeric(argv[i + 1]);
i += 2;
continue;
} else if(0 == strcmp(argv[i], "-device")) {
strcpy_s(ctxMain->cfg.szDevTpOrFileName, MAX_PATH, argv[i + 1]);
} else if((0 == strcmp(argv[i], "-device")) || (0 == strcmp(argv[i], "-z"))) {
strcpy_s(ctxMain->dev.szDevice, MAX_PATH, argv[i + 1]);
i += 2;
continue;
} else if(0 == strcmp(argv[i], "-remote")) {
strcpy_s(ctxMain->dev.szRemote, MAX_PATH, argv[i + 1]);
i += 2;
continue;
} else if(0 == strcmp(argv[i], "-pythonpath")) {
@@ -117,12 +126,18 @@ BOOL VmmDll_ConfigIntialize(_In_ DWORD argc, _In_ char* argv[])
} else {
ctxMain->cfg.szMountPoint[0] = 'M';
}
if(ctxMain->cfg.paAddrMax == 0) { ctxMain->cfg.paAddrMax = 0x0000ffffffffffff; }
if(ctxMain->cfg.paAddrMax < 0x00100000) { return FALSE; }
if(ctxMain->dev.paMax == 0) { ctxMain->dev.paMax = 0x0000ffffffffffff; }
if(ctxMain->dev.paMax < 0x00100000) { return FALSE; }
ctxMain->cfg.fVerbose = ctxMain->cfg.fVerbose && ctxMain->cfg.fVerboseDll;
ctxMain->cfg.fVerboseExtra = ctxMain->cfg.fVerboseExtra && ctxMain->cfg.fVerboseDll;
ctxMain->cfg.fVerboseExtraTlp = ctxMain->cfg.fVerboseExtraTlp && ctxMain->cfg.fVerboseDll;
return (ctxMain->cfg.szDevTpOrFileName[0] != 0);
ctxMain->dev.magic = LEECHCORE_CONFIG_MAGIC;
ctxMain->dev.version = LEECHCORE_CONFIG_VERSION;
ctxMain->dev.flags |= ctxMain->cfg.fVerboseDll ? LEECHCORE_CONFIG_FLAG_PRINTF : 0;
ctxMain->dev.flags |= ctxMain->cfg.fVerbose ? LEECHCORE_CONFIG_FLAG_PRINTF_VERBOSE_1 : 0;
ctxMain->dev.flags |= ctxMain->cfg.fVerboseExtra ? LEECHCORE_CONFIG_FLAG_PRINTF_VERBOSE_2 : 0;
ctxMain->dev.flags |= ctxMain->cfg.fVerboseExtraTlp ? LEECHCORE_CONFIG_FLAG_PRINTF_VERBOSE_3 : 0;
return (ctxMain->dev.szDevice[0] != 0);
}
VOID VmmDll_PrintHelp()
@@ -131,9 +146,9 @@ VOID VmmDll_PrintHelp()
" \n" \
" THE MEMORY PROCESS FILE SYSTEM v%i.%i.%i COMMAND LINE REFERENCE: \n" \
" The Memory Process File System may be used in stand-alone mode with support \n" \
" for memory dump files or together with PCILeech if pcileech.dll is placed in \n" \
" the application directory. For information about PCILeech and requirements \n" \
" please consult the separate PCILeech documenation. \n" \
" for memory dump files, local memory via rekall winpmem driver or together with\n" \
" PCILeech if pcileech.dll is placed in the application directory. For infor- \n" \
" mation about PCILeech please consult the separate PCILeech documentation. \n" \
" ----- \n" \
" The Memory Process File System (c) 2018 Ulf Frisk \n" \
" License: GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 \n" \
@@ -144,17 +159,22 @@ VOID VmmDll_PrintHelp()
" The recommended way to use the Memory Process File System is to specify the \n" \
" memory acquisition device in the -device option and possibly more options. \n" \
" Example 1: MemProcFS.exe -device c:\\temp\\memdump-win10x64.pmem \n" \
" Example 2: MemProcFS.exe -device c:\\temp\\memdump-winXPx86.pmem -v -vv \n" \
" Example 2: MemProcFS.exe -device c:\\temp\\memdump-winXPx86.dumpit -v -vv \n" \
" Example 3: MemProcFS.exe -device FPGA \n" \
" Example 4: MemProcFS.exe -device PMEM://c:\\temp\\winpmem_x64.sys \n" \
" The Memory Process File System may also be started the memory dump file name \n" \
" as the only option. This allows to make file extensions associated so that \n" \
" they may be opened by double-clicking on them. This mode allows no options. \n" \
" Example 4: MemProcFS.exe c:\\dumps\\memdump-win7x64.pmem \n" \
" Example 4: MemProcFS.exe c:\\dumps\\memdump-win7x64.dumpit \n" \
" ----- \n" \
" Valid options: \n" \
" -device: select memory acquisition device or raw memory dump file to use. \n" \
" Valid options: <memory_dump_file>, FPGA, TOTALMELTDOWN \n" \
" -device: select memory acquisition device or memory dump file to use. \n" \
" Valid options: <memory_dump_file>, PMEM, FPGA, TOTALMELTDOWN \n" \
" --- \n" \
" <memory_dump_file> = memory dump file name optionally including path.\n" \
" PMEM = use rekall winpmem 'winpmem_x64.sys' to aquire live memory. \n" \
" PMEM://c:\\path\\to\\winpmem_x64.sys = path to rekall winpmem driver.\n" \
" --- \n" \
" Below acquisition devices require pcileech.dll and are not built-in: \n" \
" TOTALMELTDOWN = use CVE-2018-1038 (vulnerable windows 7 only) \n" \
" FPGA = use PCILeech PCIe DMA hardware memory acquisition device. \n" \
@@ -176,7 +196,7 @@ VOID VmmDll_PrintHelp()
" This may help if the default auto-detect is not working. \n" \
" Option has no value. Example: -identify \n" \
" \n",
VMM_VERSION_MAJOR, VMM_VERSION_MINOR, VMM_VERSION_REVISION
VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION
);
}
@@ -187,14 +207,14 @@ VOID VmmDll_FreeContext()
}
if(ctxMain) {
Statistics_CallSetEnabled(FALSE);
DeviceClose();
LeechCore_Close();
LocalFree(ctxMain);
ctxMain = NULL;
}
}
_Success_(return)
BOOL VMMDLL_InitializeReserved(_In_ DWORD argc, _In_ LPSTR argv[])
BOOL VMMDLL_Initialize(_In_ DWORD argc, _In_ LPSTR argv[])
{
ctxMain = LocalAlloc(LMEM_ZEROINIT, sizeof(VMM_MAIN_CONTEXT));
if(!ctxMain) {
@@ -207,7 +227,7 @@ BOOL VMMDLL_InitializeReserved(_In_ DWORD argc, _In_ LPSTR argv[])
return FALSE;
}
// ctxMain.cfg context is inintialized from here onwards - vmmprintf is working!
if(!DeviceOpen()) {
if(!LeechCore_Open(&ctxMain->dev)) {
vmmprintf("MemProcFS: Failed to connect to memory acquisition device.\n");
VmmDll_FreeContext();
return FALSE;
@@ -226,24 +246,6 @@ BOOL VMMDLL_InitializeReserved(_In_ DWORD argc, _In_ LPSTR argv[])
return TRUE;
}
_Success_(return)
BOOL VMMDLL_InitializeFile(_In_ LPSTR szFileName, _In_opt_ LPSTR szPageTableBaseOpt)
{
return VMMDLL_InitializeReserved(5, (LPSTR[]) { "", "-device", szFileName, "-cr3", (szPageTableBaseOpt ? szPageTableBaseOpt : "0") });
}
_Success_(return)
BOOL VMMDLL_InitializeFPGA(_In_opt_ LPSTR szMaxPhysicalAddressOpt, _In_opt_ LPSTR szPageTableBaseOpt)
{
return VMMDLL_InitializeReserved(7, (LPSTR[]) { "", "-device", "fpga", "-cr3", (szPageTableBaseOpt ? szPageTableBaseOpt : "0"), "-max", (szMaxPhysicalAddressOpt ? szMaxPhysicalAddressOpt : "0") });
}
_Success_(return)
BOOL VMMDLL_InitializeTotalMeltdown()
{
return VMMDLL_InitializeReserved(3, (LPSTR[]) { "", "-device", "totalmeltdown" });
}
_Success_(return)
BOOL VMMDLL_Close()
{
@@ -292,13 +294,13 @@ BOOL VMMDLL_ConfigGet(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue)
if(!pqwValue) { return FALSE; }
if(fOption & 0x40000000) {
if(fOption == VMMDLL_OPT_CONFIG_VMM_VERSION_MAJOR) {
*pqwValue = VMM_VERSION_MAJOR;
*pqwValue = VERSION_MAJOR;
return TRUE;
} else if(fOption == VMMDLL_OPT_CONFIG_VMM_VERSION_MINOR) {
*pqwValue = VMM_VERSION_MINOR;
*pqwValue = VERSION_MINOR;
return TRUE;
} else if(fOption == VMMDLL_OPT_CONFIG_VMM_VERSION_REVISION) {
*pqwValue = VMM_VERSION_REVISION;
*pqwValue = VERSION_REVISION;
return TRUE;
}
}
@@ -323,10 +325,10 @@ BOOL VMMDLL_ConfigGet(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue)
*pqwValue = ctxMain->cfg.fVerboseExtraTlp ? 1 : 0;
return TRUE;
case VMMDLL_OPT_CORE_MAX_NATIVE_ADDRESS:
*pqwValue = ctxMain->dev.paAddrMaxNative;
*pqwValue = ctxMain->dev.paMaxNative;
return TRUE;
case VMMDLL_OPT_CORE_MAX_NATIVE_IOSIZE:
*pqwValue = ctxMain->dev.qwMaxSizeMemIo;
*pqwValue = ctxMain->dev.cbMaxSizeMemIo;
return TRUE;
case VMMDLL_OPT_CORE_SYSTEM:
*pqwValue = ctxVmm->tpSystem;
@@ -339,7 +341,7 @@ BOOL VMMDLL_ConfigGet(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue)
}
}
// non-recognized option - possibly a device option to pass along to pcileech.dll
return DeviceGetOption(fOption, pqwValue);
return LeechCore_GetOption(fOption, pqwValue);
}
_Success_(return)
@@ -378,9 +380,9 @@ BOOL VMMDLL_ConfigSet(_In_ ULONG64 fOption, _In_ ULONG64 qwValue)
if(fOption & 0x40000000) {
return VMMDLL_ConfigSet_VmmCore(fOption, qwValue);
}
// core options affecting both vmm.dll and pcileech.dll
// core options affecting both vmm.dll and leechcore.dll
if(fOption & 0x80000000) {
DeviceSetOption(fOption, qwValue); // also set option in pcileech.dll (if existing).
LeechCore_SetOption(fOption, qwValue);
switch(fOption) {
case VMMDLL_OPT_CORE_PRINTF_ENABLE:
ctxMain->cfg.fVerboseDll = qwValue ? TRUE : FALSE;
@@ -410,8 +412,8 @@ BOOL VMMDLL_ConfigSet(_In_ ULONG64 fOption, _In_ ULONG64 qwValue)
return FALSE;
}
}
// non-recognized option - possibly a device option to pass along to pcileech.dll
return DeviceSetOption(fOption, qwValue);
// non-recognized option - possibly a device option to pass along to memdevice.dll
return LeechCore_SetOption(fOption, qwValue);
}
//-----------------------------------------------------------------------------
@@ -488,21 +490,22 @@ BOOL VMMDLL_VfsInitializePlugins()
// VMM CORE FUNCTIONALITY BELOW:
//-----------------------------------------------------------------------------
DWORD VMMDLL_MemReadScatter(_In_ DWORD dwPID, _Inout_ PPVMMDLL_MEM_IO_SCATTER_HEADER ppMEMs, _In_ DWORD cpMEMs, _In_ DWORD flags)
DWORD VMMDLL_MemReadScatter(_In_ DWORD dwPID, _Inout_ PPMEM_IO_SCATTER_HEADER ppMEMs, _In_ DWORD cpMEMs, _In_ DWORD flags)
{
DWORD i, cMEMs;
PVMM_PROCESS pProcess = NULL;
PVMM_PROCESS pObProcess = NULL;
if(!ctxVmm) { return 0; }
VmmLockAcquire();
if(dwPID == -1) {
VmmReadScatterPhysical((PPMEM_IO_SCATTER_HEADER)ppMEMs, cpMEMs, flags);
VmmReadScatterPhysical(ppMEMs, cpMEMs, flags);
} else {
pProcess = VmmProcessGet(dwPID);
if(!pProcess) {
pObProcess = VmmProcessGet(dwPID);
if(!pObProcess) {
VmmLockRelease();
return FALSE;
}
VmmReadScatterVirtual(pProcess, (PPMEM_IO_SCATTER_HEADER)ppMEMs, cpMEMs, flags);
VmmReadScatterVirtual(pObProcess, ppMEMs, cpMEMs, flags);
VmmOb_DECREF(pObProcess);
}
for(i = 0, cMEMs = 0; i < cpMEMs; i++) {
if(ppMEMs[i]->cb == ppMEMs[i]->cbMax) {
@@ -516,12 +519,13 @@ DWORD VMMDLL_MemReadScatter(_In_ DWORD dwPID, _Inout_ PPVMMDLL_MEM_IO_SCATTER_HE
_Success_(return)
BOOL VMMDLL_MemReadEx_Impl(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ ULONG64 flags)
{
PVMM_PROCESS pProcess = NULL;
PVMM_PROCESS pObProcess = NULL;
if(dwPID != -1) {
pProcess = VmmProcessGet(dwPID);
if(!pProcess) { return FALSE; }
pObProcess = VmmProcessGet(dwPID);
if(!pObProcess) { return FALSE; }
}
VmmReadEx(pProcess, qwVA, pb, cb, pcbReadOpt, flags);
VmmReadEx(pObProcess, qwVA, pb, cb, pcbReadOpt, flags);
VmmOb_DECREF(pObProcess);
return TRUE;
}
@@ -550,12 +554,15 @@ BOOL VMMDLL_MemReadPage(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_bytecount_(4
_Success_(return)
BOOL VMMDLL_MemWrite_Impl(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _In_ PBYTE pb, _In_ DWORD cb)
{
PVMM_PROCESS pProcess = NULL;
BOOL result;
PVMM_PROCESS pObProcess = NULL;
if(dwPID != -1) {
pProcess = VmmProcessGet(dwPID);
if(!pProcess) { return FALSE; }
pObProcess = VmmProcessGet(dwPID);
if(!pObProcess) { return FALSE; }
}
return VmmWrite(pProcess, qwVA, pb, cb);
result = VmmWrite(pObProcess, qwVA, pb, cb);
VmmOb_DECREF(pObProcess);
return result;
}
_Success_(return)
@@ -569,9 +576,12 @@ BOOL VMMDLL_MemWrite(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _In_ PBYTE pb, _In_ DW
_Success_(return)
BOOL VMMDLL_MemVirt2Phys_Impl(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PULONG64 pqwPA)
{
PVMM_PROCESS pProcess = VmmProcessGet(dwPID);
if(!pProcess) { return FALSE; }
return VmmVirt2Phys(pProcess, qwVA, pqwPA);
BOOL result;
PVMM_PROCESS pObProcess = VmmProcessGet(dwPID);
if(!pObProcess) { return FALSE; }
result = VmmVirt2Phys(pObProcess, qwVA, pqwPA);
VmmOb_DECREF(pObProcess);
return result;
}
_Success_(return)
@@ -589,26 +599,25 @@ BOOL VMMDLL_MemVirt2Phys(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PULONG64 pqw
_Success_(return)
BOOL VMMDLL_ProcessGetMemoryMap_Impl(_In_ DWORD dwPID, _Out_opt_ PVMMDLL_MEMMAP_ENTRY pMemMapEntries, _Inout_ PULONG64 pcMemMapEntries, _In_ BOOL fIdentifyModules)
{
PVMM_PROCESS pProcess = VmmProcessGet(dwPID);
if(!pProcess) { return FALSE; }
if(!pProcess->pMemMap || !pProcess->cMemMap) {
if(!pProcess->fSpiderPageTableDone) {
VmmTlbSpider(pProcess->paDTB, pProcess->fUserOnly);
pProcess->fSpiderPageTableDone = TRUE;
}
VmmMapInitialize(pProcess);
if(fIdentifyModules) {
VmmProc_InitializeModuleNames(pProcess);
}
}
PVMM_PROCESS pObProcess = NULL;
PVMMOB_MEMMAP pObMap = NULL;
pObProcess = VmmProcessGet(dwPID);
if(!pObProcess) { return FALSE; }
if(!VmmMemMapGetEntries(pObProcess, fIdentifyModules ? VMM_MEMMAP_FLAG_ALL : 0, &pObMap)) { goto fail; }
if(!pMemMapEntries) {
*pcMemMapEntries = pProcess->cMemMap;
*pcMemMapEntries = pObMap->cMap;
} else {
if(!pProcess->pMemMap || (*pcMemMapEntries < pProcess->cMemMap)) { return FALSE; }
memcpy(pMemMapEntries, pProcess->pMemMap, sizeof(VMMDLL_MEMMAP_ENTRY) * pProcess->cMemMap);
*pcMemMapEntries = pProcess->cMemMap;
if(!pObMap->cMap || (*pcMemMapEntries < pObMap->cMap)) { goto fail; }
memcpy(pMemMapEntries, pObMap->pMap, sizeof(VMMDLL_MEMMAP_ENTRY) * pObMap->cMap);
*pcMemMapEntries = pObMap->cMap;
}
VmmOb_DECREF(pObMap);
VmmOb_DECREF(pObProcess);
return TRUE;
fail:
VmmOb_DECREF(pObMap);
VmmOb_DECREF(pObProcess);
return FALSE;
}
_Success_(return)
@@ -622,20 +631,26 @@ BOOL VMMDLL_ProcessGetMemoryMap(_In_ DWORD dwPID, _Out_opt_ PVMMDLL_MEMMAP_ENTRY
_Success_(return)
BOOL VMMDLL_ProcessGetMemoryMapEntry_Impl(_In_ DWORD dwPID, _Out_ PVMMDLL_MEMMAP_ENTRY pMemMapEntry, _In_ ULONG64 va, _In_ BOOL fIdentifyModules)
{
PVMM_PROCESS pProcess = VmmProcessGet(dwPID);
PVMM_MEMMAP_ENTRY e;
if(!pProcess) { return FALSE; }
if(fIdentifyModules) {
VmmMapInitialize(pProcess);
VmmProc_InitializeModuleNames(pProcess);
PVMM_PROCESS pObProcess = NULL;
DWORD i;
PVMMOB_MEMMAP pObMap = NULL;
PVMM_MEMMAP_ENTRY pe;
pObProcess = VmmProcessGet(dwPID);
if(!pObProcess) { return FALSE; }
if(!VmmMemMapGetEntries(pObProcess, fIdentifyModules ? VMM_MEMMAP_FLAG_ALL : 0, &pObMap)) {goto fail; }
for(i = 0; i < pObMap->cMap; i++) {
pe = pObMap->pMap + i;
if((pe->AddrBase >= va) && (va <= pe->AddrBase + (pe->cPages << 12))) {
memcpy(pMemMapEntry, pe, sizeof(VMM_MEMMAP_ENTRY));
VmmOb_DECREF(pObMap);
VmmOb_DECREF(pObProcess);
return TRUE;
}
}
if(!pProcess->pMemMap) {
VmmMapInitialize(pProcess);
}
e = VmmMapGetEntry(pProcess, va);
if(!e) { return FALSE; }
memcpy(pMemMapEntry, e, sizeof(VMM_MEMMAP_ENTRY));
return TRUE;
fail:
VmmOb_DECREF(pObMap);
VmmOb_DECREF(pObProcess);
return FALSE;
}
_Success_(return)
@@ -647,28 +662,33 @@ BOOL VMMDLL_ProcessGetMemoryMapEntry(_In_ DWORD dwPID, _Out_ PVMMDLL_MEMMAP_ENTR
}
_Success_(return)
BOOL VMMDLL_ProcessGetModuleMap_Impl(_In_ DWORD dwPID, _Out_opt_ PVMMDLL_MODULEMAP_ENTRY pModuleEntries, _Inout_ PULONG64 pcModuleEntries)
BOOL VMMDLL_ProcessGetModuleMap_Impl(_In_ DWORD dwPID, _Out_writes_opt_(*pcModuleEntries) PVMMDLL_MODULEMAP_ENTRY pModuleEntries, _Inout_ PULONG64 pcModuleEntries)
{
ULONG64 i;
PVMM_PROCESS pProcess = VmmProcessGet(dwPID);
if(!pProcess) { return FALSE; }
PVMM_PROCESS pObProcess = NULL;
PVMMOB_MODULEMAP pObModuleMap;
if(!pcModuleEntries) { return FALSE; }
if(!pProcess->pModuleMap || !pProcess->cModuleMap) {
if(!pProcess->fSpiderPageTableDone) {
VmmTlbSpider(pProcess->paDTB, pProcess->fUserOnly);
pProcess->fSpiderPageTableDone = TRUE;
pObProcess = VmmProcessGet(dwPID);
if(!pObProcess) { return FALSE; }
if(VmmProc_ModuleMapGet(pObProcess, &pObModuleMap)) {
if(!pModuleEntries) {
*pcModuleEntries = pObModuleMap->cMap;
} else {
if(!pObModuleMap->pMap || (*pcModuleEntries < pObModuleMap->cMap)) {
VmmOb_DECREF(pObModuleMap);
VmmOb_DECREF(pObProcess);
return FALSE;
}
for(i = 0; i < pObModuleMap->cMap; i++) {
memcpy(pModuleEntries + i, pObModuleMap->pMap + i, sizeof(VMMDLL_MODULEMAP_ENTRY));
}
*pcModuleEntries = pObModuleMap->cMap;
}
VmmProc_InitializeModuleNames(pProcess);
}
if(!pModuleEntries) {
*pcModuleEntries = pProcess->cModuleMap;
VmmOb_DECREF(pObModuleMap);
} else {
if(!pProcess->pModuleMap || (*pcModuleEntries < pProcess->cModuleMap)) { return FALSE; }
for(i = 0; i < pProcess->cModuleMap; i++) {
memcpy(pModuleEntries + i, pProcess->pModuleMap + i, sizeof(VMMDLL_MODULEMAP_ENTRY));
}
*pcModuleEntries = pProcess->cModuleMap;
*pcModuleEntries = 0;
}
VmmOb_DECREF(pObProcess);
return TRUE;
}
@@ -730,16 +750,12 @@ BOOL VMMDLL_PidList(_Out_opt_ PDWORD pPIDs, _Inout_ PULONG64 pcPIDs)
_Success_(return)
BOOL VMMDLL_PidGetFromName_Impl(_In_ LPSTR szProcName, _Out_ PDWORD pdwPID)
{
DWORD i, pdwPIDs[1024];
SIZE_T cPIDs = 1024;
PVMM_PROCESS pProcess;
VmmProcessListPIDs(pdwPIDs, &cPIDs);
for(i = 0; i < cPIDs; i++) {
pProcess = VmmProcessGet(pdwPIDs[i]);
if(!pProcess) { return FALSE; }
if(_strnicmp(szProcName, pProcess->szName, 15)) { continue; }
if(pProcess->dwState) { continue; }
*pdwPID = pdwPIDs[i];
PVMM_PROCESS pObProcess = NULL;
while((pObProcess = VmmProcessGetNext(pObProcess))) {
if(_strnicmp(szProcName, pObProcess->szName, 15)) { continue; }
if(pObProcess->dwState) { continue; }
*pdwPID = pObProcess->dwPID;
VmmOb_DECREF(pObProcess);
return TRUE;
}
return FALSE;
@@ -756,7 +772,7 @@ BOOL VMMDLL_PidGetFromName(_In_ LPSTR szProcName, _Out_ PDWORD pdwPID)
_Success_(return)
BOOL VMMDLL_ProcessGetInformation_Impl(_In_ DWORD dwPID, _Inout_opt_ PVMMDLL_PROCESS_INFORMATION pInfo, _In_ PSIZE_T pcbProcessInfo)
{
PVMM_PROCESS pProcess;
PVMM_PROCESS pObProcess = NULL;
if(!pcbProcessInfo) { return FALSE; }
if(!pInfo) {
*pcbProcessInfo = sizeof(VMMDLL_PROCESS_INFORMATION);
@@ -765,34 +781,35 @@ BOOL VMMDLL_ProcessGetInformation_Impl(_In_ DWORD dwPID, _Inout_opt_ PVMMDLL_PRO
if(*pcbProcessInfo < sizeof(VMMDLL_PROCESS_INFORMATION)) { return FALSE; }
if(pInfo->magic != VMMDLL_PROCESS_INFORMATION_MAGIC) { return FALSE; }
if(pInfo->wVersion != VMMDLL_PROCESS_INFORMATION_VERSION) { return FALSE; }
if(!(pProcess = VmmProcessGet(dwPID))) { return FALSE; }
if(!(pObProcess = VmmProcessGet(dwPID))) { return FALSE; }
ZeroMemory(pInfo, sizeof(VMMDLL_PROCESS_INFORMATION_MAGIC));
// set general parameters
pInfo->wVersion = VMMDLL_PROCESS_INFORMATION_VERSION;
pInfo->wSize = sizeof(VMMDLL_PROCESS_INFORMATION);
pInfo->tpMemoryModel = ctxVmm->tpMemoryModel;
pInfo->tpSystem = ctxVmm->tpSystem;
pInfo->fUserOnly = pProcess->fUserOnly;
pInfo->fUserOnly = pObProcess->fUserOnly;
pInfo->dwPID = dwPID;
pInfo->dwState = pProcess->dwState;
pInfo->paDTB = pProcess->paDTB;
pInfo->paDTB_UserOpt = pProcess->paDTB_UserOpt;
memcpy(pInfo->szName, pProcess->szName, sizeof(pInfo->szName));
pInfo->dwState = pObProcess->dwState;
pInfo->paDTB = pObProcess->paDTB;
pInfo->paDTB_UserOpt = pObProcess->paDTB_UserOpt;
memcpy(pInfo->szName, pObProcess->szName, sizeof(pInfo->szName));
// set operating system specific parameters
switch(ctxVmm->tpSystem) {
case VMM_SYSTEM_WINDOWS_X64:
pInfo->os.win.fWow64 = pProcess->os.win.fWow64;
pInfo->os.win.vaENTRY = pProcess->os.win.vaENTRY;
pInfo->os.win.vaEPROCESS = pProcess->os.win.vaEPROCESS;
pInfo->os.win.vaPEB = pProcess->os.win.vaPEB;
pInfo->os.win.vaPEB32 = pProcess->os.win.vaPEB32;
pInfo->os.win.fWow64 = pObProcess->os.win.fWow64;
pInfo->os.win.vaENTRY = pObProcess->os.win.vaENTRY;
pInfo->os.win.vaEPROCESS = pObProcess->os.win.vaEPROCESS;
pInfo->os.win.vaPEB = pObProcess->os.win.vaPEB;
pInfo->os.win.vaPEB32 = pObProcess->os.win.vaPEB32;
break;
case VMM_SYSTEM_WINDOWS_X86:
pInfo->os.win.vaENTRY = pProcess->os.win.vaENTRY;
pInfo->os.win.vaEPROCESS = pProcess->os.win.vaEPROCESS;
pInfo->os.win.vaPEB = pProcess->os.win.vaPEB;
pInfo->os.win.vaENTRY = pObProcess->os.win.vaENTRY;
pInfo->os.win.vaEPROCESS = pObProcess->os.win.vaEPROCESS;
pInfo->os.win.vaPEB = pObProcess->os.win.vaPEB;
break;
}
VmmOb_DECREF(pObProcess);
return TRUE;
}
@@ -821,61 +838,62 @@ BOOL VMMDLL_ProcessGet_Directories_Sections_IAT_EAT_Impl(
)
{
DWORD i;
PVMMOB_MODULEMAP pObModuleMap = NULL;
PVMM_MODULEMAP_ENTRY pModule = NULL;
PVMM_PROCESS pProcess = VmmProcessGet(dwPID);
if(!pProcess) { return FALSE; }
// genereate module map (if required)
if(!pProcess->pModuleMap || !pProcess->cModuleMap) {
if(!pProcess->fSpiderPageTableDone) {
VmmTlbSpider(pProcess->paDTB, pProcess->fUserOnly);
pProcess->fSpiderPageTableDone = TRUE;
}
VmmProc_InitializeModuleNames(pProcess);
if(!pProcess->pModuleMap || !pProcess->cModuleMap) { return FALSE; }
}
PVMM_PROCESS pObProcess = NULL;
pObProcess = VmmProcessGet(dwPID);
if(!pObProcess) { goto fail; }
// fetch requested module
for(i = 0; i < pProcess->cModuleMap; i++) {
if(!_stricmp(pProcess->pModuleMap[i].szName, szModule)) {
pModule = &pProcess->pModuleMap[i];
if(!VmmProc_ModuleMapGet(pObProcess, &pObModuleMap)) { goto fail; }
for(i = 0; i < pObModuleMap->cMap; i++) {
if(!_stricmp(pObModuleMap->pMap[i].szName, szModule)) {
pModule = pObModuleMap->pMap + i;
}
}
if(!pModule) { return FALSE; }
if(!pModule) { goto fail; }
// data directories
if(fDataDirectory) {
if(!pDataDirectory) { *pcData = 16; return TRUE; }
if(cData < 16) { return FALSE; }
VmmWin_PE_DIRECTORY_DisplayBuffer(pProcess, pModule, NULL, 0, NULL, pDataDirectory);
if(!pDataDirectory) { *pcData = 16; goto success; }
if(cData < 16) { goto fail; }
VmmWin_PE_DIRECTORY_DisplayBuffer(pObProcess, pModule, NULL, 0, NULL, pDataDirectory);
*pcData = 16;
return TRUE;
goto success;
}
// sections
if(fSections) {
i = PE_SectionGetNumberOf(pProcess, pModule->BaseAddress);
if(!pSections) { *pcData = i; return TRUE; }
if(cData < i) { return FALSE; }
VmmWin_PE_SECTION_DisplayBuffer(pProcess, pModule, NULL, 0, NULL, &cData, pSections);
i = PE_SectionGetNumberOf(pObProcess, pModule->BaseAddress);
if(!pSections) { *pcData = i; goto success; }
if(cData < i) { goto fail; }
VmmWin_PE_SECTION_DisplayBuffer(pObProcess, pModule, NULL, 0, NULL, &cData, pSections);
*pcData = cData;
return TRUE;
goto success;
}
// export address table (EAT)
if(fEAT) {
i = PE_EatGetNumberOf(pProcess, pModule->BaseAddress);
if(!pEAT) { *pcData = i; return TRUE; }
if(cData < i) { return FALSE; }
VmmWin_PE_LoadEAT_DisplayBuffer(pProcess, pModule, (PVMMPROC_WINDOWS_EAT_ENTRY)pEAT, &cData);
i = PE_EatGetNumberOf(pObProcess, pModule->BaseAddress);
if(!pEAT) { *pcData = i; goto success; }
if(cData < i) { goto fail; }
VmmWin_PE_LoadEAT_DisplayBuffer(pObProcess, pModule, (PVMMPROC_WINDOWS_EAT_ENTRY)pEAT, &cData);
*pcData = cData;
return TRUE;
goto success;
}
// import address table (IAT)
if(fIAT) {
i = PE_IatGetNumberOf(pProcess, pModule->BaseAddress);
if(!pIAT) { *pcData = i; return TRUE; }
if(cData < i) { return FALSE; }
VmmWin_PE_LoadIAT_DisplayBuffer(pProcess, pModule, (PVMMWIN_IAT_ENTRY)pIAT, &cData);
i = PE_IatGetNumberOf(pObProcess, pModule->BaseAddress);
if(!pIAT) { *pcData = i; goto success; }
if(cData < i) { goto fail; }
VmmWin_PE_LoadIAT_DisplayBuffer(pObProcess, pModule, (PVMMWIN_IAT_ENTRY)pIAT, &cData);
*pcData = cData;
return TRUE;
goto success;
}
fail:
VmmOb_DECREF(pObModuleMap);
VmmOb_DECREF(pObProcess);
return FALSE;
success:
VmmOb_DECREF(pObModuleMap);
VmmOb_DECREF(pObProcess);
return TRUE;
}
_Success_(return)
+1 -4
View File
@@ -1,9 +1,6 @@
LIBRARY VMM
EXPORTS
VMMDLL_InitializeReserved
VMMDLL_InitializeFile
VMMDLL_InitializeFPGA
VMMDLL_InitializeTotalMeltdown
VMMDLL_Initialize
VMMDLL_Close
VMMDLL_ConfigGet
+44 -108
View File
@@ -1,11 +1,14 @@
// vmmdll.h : header file to include in projects that use vmm.dll either as
// stand anlone projects or as native plugins to vmm.dll.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
// Header Version: 2.0
//
#include <windows.h>
#include "leechcore.h"
#ifndef __VMMDLL_H__
#define __VMMDLL_H__
@@ -19,52 +22,23 @@ extern "C" {
//-----------------------------------------------------------------------------
/*
* RESERVED FUNCTION! DO NOT USE!
* Call other VMMDLL_Intialize functions to initialize VMM.DLL and the memory
* process file system.
* Initialize VMM.DLL with command line parameters. For a more detailed info
* about the parameters please see github wiki for Memory Process File System
* and LeechCore. THIS IS THE PREFERED WAY OF INITIALIZING VMM.DLL
* Important parameters are:
* -vdll = show printf style outputs)
* -v -vv -vvv = extra verbosity levels)
* -device = device as on format for LeechCore - please see leechcore.h or
* Github documentation for additional information. Some values
* are: <file>, fpga, usb3380, hvsavedstate, totalmeltdown, pmem
* -remote = remote LeechCore instance - please see leechcore.h or Github
* documentation for additional information.
* -- argc
* -- argv
* -- return = success/fail
*/
_Success_(return)
BOOL VMMDLL_InitializeReserved(_In_ DWORD argc, _In_ LPSTR argv[]);
/*
* Initialize VMM.DLL from a memory dump file in raw format. VMM.DLL will be
* initialized in read-only mode. It's possible to optionally specify the page
* table base of the windows kernel (for full vmm features) or the page table
* base of a single 64-bit process in any x64 operating system. NB! usually it
* is not necessary to specify the PageTableBase - it will be auto-identified
* most often if the target is Windows.
* -- szFileName = the file name of the raw memory dump to use.
* -- szPageTableBaseOpt = optionally the Page Table Base of kernel or process
* as hex string. NB! this is usally not required. Example: "0x1ab000".
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeFile(_In_ LPSTR szFileName, _In_opt_ LPSTR szPageTableBaseOpt);
/*
* Intiailize VMM.DLL from a supported FPGA device over USB. VMM.DLL will be
* initialized in read/write mode upon success. Optionally it will be possible
* to specify the max physical address and the page table base of the kernel or
* process that should be investigated.
* NB! Requires pcileech.dll to be placed in the same directory as vmm.dll.
* -- szMaxPhysicalAddressOpt = max physical address of the target system as a
* hex string. Example: "0x8000000000". If zero value is given the max
* address will be auto-identified.
* -- szPageTableBaseOpt = optionally the Page Table Base of kernel or process
* as hex string. NB! this is usally not required. Example: "0x1ab000".
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeFPGA(_In_opt_ LPSTR szMaxPhysicalAddressOpt, _In_opt_ LPSTR szPageTableBaseOpt);
/*
* Initialize VMM.DLL from a the "Total Meltdown" CVE-2018-1038 vulnerability.
* NB! Requires pcileech.dll to be placed in the same directory as vmm.dll.
* initialized in read/write mode upon success.
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeTotalMeltdown();
BOOL VMMDLL_Initialize(_In_ DWORD argc, _In_ LPSTR argv[]);
/*
* Close an initialized instance of VMM.DLL and clean up all allocated resources
@@ -84,43 +58,29 @@ BOOL VMMDLL_Close();
/*
* Options used together with the functions: VMMDLL_GetOption & VMMDLL_SetOption
* If VMM.DLL is chained with PCILEECH.DLL then required values will be passed
* along to PCILEECH.DLL when necessary.
* Options are defined with either: VMMDLL_OPT_* in this header file or as
* MEMDEVICE_OPT_* in memdevice.h
* For more detailed information check the sources for individual device types.
*/
#define VMMDLL_OPT_DEVICE_FPGA_PROBE_MAXPAGES 0x01 // RW
#define VMMDLL_OPT_DEVICE_FPGA_RX_FLUSH_LIMIT 0x02 // RW
#define VMMDLL_OPT_DEVICE_FPGA_MAX_SIZE_RX 0x03 // RW
#define VMMDLL_OPT_DEVICE_FPGA_MAX_SIZE_TX 0x04 // RW
#define VMMDLL_OPT_DEVICE_FPGA_DELAY_PROBE_READ 0x05 // RW - uS
#define VMMDLL_OPT_DEVICE_FPGA_DELAY_PROBE_WRITE 0x06 // RW - uS
#define VMMDLL_OPT_DEVICE_FPGA_DELAY_WRITE 0x07 // RW - uS
#define VMMDLL_OPT_DEVICE_FPGA_DELAY_READ 0x08 // RW - uS
#define VMMDLL_OPT_DEVICE_FPGA_RETRY_ON_ERROR 0x09 // RW
#define VMMDLL_OPT_DEVICE_FPGA_DEVICE_ID 0x80 // R
#define VMMDLL_OPT_DEVICE_FPGA_FPGA_ID 0x81 // R
#define VMMDLL_OPT_DEVICE_FPGA_VERSION_MAJOR 0x82 // R
#define VMMDLL_OPT_DEVICE_FPGA_VERSION_MINOR 0x83 // R
#define VMMDLL_OPT_CORE_PRINTF_ENABLE 0x80000001 // RW
#define VMMDLL_OPT_CORE_VERBOSE 0x80000002 // RW
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA 0x80000003 // RW
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA_TLP 0x80000004 // RW
#define VMMDLL_OPT_CORE_MAX_NATIVE_ADDRESS 0x80000005 // R
#define VMMDLL_OPT_CORE_MAX_NATIVE_IOSIZE 0x80000006 // R
#define VMMDLL_OPT_CORE_SYSTEM 0x80000007 // R
#define VMMDLL_OPT_CORE_MEMORYMODEL 0x80000008 // R
#define VMMDLL_OPT_CORE_PRINTF_ENABLE 0x80000001 // RW
#define VMMDLL_OPT_CORE_VERBOSE 0x80000002 // RW
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA 0x80000003 // RW
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA_TLP 0x80000004 // RW
#define VMMDLL_OPT_CORE_MAX_NATIVE_ADDRESS 0x80000005 // R
#define VMMDLL_OPT_CORE_MAX_NATIVE_IOSIZE 0x80000006 // R
#define VMMDLL_OPT_CORE_SYSTEM 0x80000007 // R
#define VMMDLL_OPT_CORE_MEMORYMODEL 0x80000008 // R
#define VMMDLL_OPT_CONFIG_IS_REFRESH_ENABLED 0x40000001 // R - 1/0
#define VMMDLL_OPT_CONFIG_TICK_PERIOD 0x40000002 // RW - base tick period in ms
#define VMMDLL_OPT_CONFIG_READCACHE_TICKS 0x40000003 // RW - memory cache validity period (in ticks)
#define VMMDLL_OPT_CONFIG_TLBCACHE_TICKS 0x40000004 // RW - page table (tlb) cache validity period (in ticks)
#define VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_PARTIAL 0x40000005 // RW - process refresh (partial) period (in ticks)
#define VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_TOTAL 0x40000006 // RW - process refresh (full) period (in ticks)
#define VMMDLL_OPT_CONFIG_VMM_VERSION_MAJOR 0x40000007 // R
#define VMMDLL_OPT_CONFIG_VMM_VERSION_MINOR 0x40000008 // R
#define VMMDLL_OPT_CONFIG_VMM_VERSION_REVISION 0x40000009 // R
#define VMMDLL_OPT_CONFIG_STATISTICS_FUNCTIONCALL 0x4000000A // RW - enable function call statistics (.status/statistics_fncall file)
#define VMMDLL_OPT_CONFIG_IS_REFRESH_ENABLED 0x40000001 // R - 1/0
#define VMMDLL_OPT_CONFIG_TICK_PERIOD 0x40000002 // RW - base tick period in ms
#define VMMDLL_OPT_CONFIG_READCACHE_TICKS 0x40000003 // RW - memory cache validity period (in ticks)
#define VMMDLL_OPT_CONFIG_TLBCACHE_TICKS 0x40000004 // RW - page table (tlb) cache validity period (in ticks)
#define VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_PARTIAL 0x40000005 // RW - process refresh (partial) period (in ticks)
#define VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_TOTAL 0x40000006 // RW - process refresh (full) period (in ticks)
#define VMMDLL_OPT_CONFIG_VMM_VERSION_MAJOR 0x40000007 // R
#define VMMDLL_OPT_CONFIG_VMM_VERSION_MINOR 0x40000008 // R
#define VMMDLL_OPT_CONFIG_VMM_VERSION_REVISION 0x40000009 // R
#define VMMDLL_OPT_CONFIG_STATISTICS_FUNCTIONCALL 0x4000000A // RW - enable function call statistics (.status/statistics_fncall file)
static const LPSTR VMMDLL_MEMORYMODEL_TOSTRING[4] = { "N/A", "X86", "X86PAE", "X64" };
@@ -256,9 +216,9 @@ _Success_(return)
BOOL VMMDLL_VfsInitializePlugins();
#define VMMDLL_PLUGIN_CONTEXT_MAGIC 0xc0ffee663df9301c
#define VMMDLL_PLUGIN_CONTEXT_VERSION 1
#define VMMDLL_PLUGIN_CONTEXT_VERSION 2
#define VMMDLL_PLUGIN_REGINFO_MAGIC 0xc0ffee663df9301d
#define VMMDLL_PLUGIN_REGINFO_VERSION 2
#define VMMDLL_PLUGIN_REGINFO_VERSION 3
#define VMMDLL_PLUGIN_EVENT_VERBOSITYCHANGE 0x01
@@ -267,8 +227,6 @@ typedef struct tdVMMDLL_PLUGIN_CONTEXT {
WORD wVersion;
WORD wSize;
DWORD dwPID;
PHANDLE phModulePrivate;
PHANDLE phProcessPrivate;
PVOID pProcess;
LPSTR szModule;
LPSTR szPath;
@@ -289,7 +247,6 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
PVOID pvReserved2;
// general plugin registration info to be filled out by the plugin below:
struct {
HANDLE hModulePrivate;
CHAR szModuleName[32];
BOOL fRootModule;
BOOL fProcessModule;
@@ -301,9 +258,8 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
BOOL(*pfnList)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList);
NTSTATUS(*pfnRead)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset);
NTSTATUS(*pfnWrite)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset);
VOID(*pfnNotify)(_Inout_opt_ PHANDLE phModulePrivate, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent);
VOID(*pfnCloseHandleModule)(_Inout_opt_ PHANDLE phModulePrivate);
VOID(*pfnCloseHandleProcess)(_Inout_opt_ PHANDLE phModulePrivate, _Inout_ PHANDLE phProcessPrivate);
VOID(*pfnNotify)(_In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent);
VOID(*pfnClose)();
PVOID pvReserved1;
PVOID pvReserved2;
} reg_fn;
@@ -323,26 +279,6 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
#define VMMDLL_FLAG_NOCACHE 0x0001 // do not use the data cache (force reading from memory acquisition device)
#define VMMDLL_FLAG_ZEROPAD_ON_FAIL 0x0002 // zero pad failed physical memory reads and report success if read within range of physical memory.
#define VMMDLL_MEM_IO_SCATTER_HEADER_VERSION 2
typedef struct tdVMMDLL_MEM_IO_SCATTER_HEADER {
ULONG64 qwA; // base address (DWORD boundry).
DWORD cbMax; // bytes to read (DWORD boundry, max 0x1000); pbResult must have room for this.
DWORD cb; // bytes read into result buffer.
PBYTE pb; // ptr to 0x1000 sized buffer to receive read bytes.
PVOID pvReserved1; // reserved for use by caller.
PVOID pvReserved2; // reserved for use by caller.
WORD version; // version of struct
WORD Future1; // reserved for future use.
DWORD Future2; // reserved for future use.
ULONG64 qwDeviceA; // device-physical address (used by device layer).
struct {
PVOID pvReserved1;
PVOID pvReserved2;
BYTE pbReserved[32];
} sReserved; // reserved for future use.
} VMMDLL_MEM_IO_SCATTER_HEADER, *PVMMDLL_MEM_IO_SCATTER_HEADER, **PPVMMDLL_MEM_IO_SCATTER_HEADER;
/*
* Read memory in various non-contigious locations specified by the pointers to
* the items in the ppDMAs array. Result for each unit of work will be given
@@ -356,7 +292,7 @@ typedef struct tdVMMDLL_MEM_IO_SCATTER_HEADER {
* -- flags = optional flags as given by VMM_FLAG_*
* -- return = the number of successfully read items.
*/
DWORD VMMDLL_MemReadScatter(_In_ DWORD dwPID, _Inout_ PPVMMDLL_MEM_IO_SCATTER_HEADER ppMEMs, _In_ DWORD cpMEMs, _In_ DWORD flags);
DWORD VMMDLL_MemReadScatter(_In_ DWORD dwPID, _Inout_ PPMEM_IO_SCATTER_HEADER ppMEMs, _In_ DWORD cpMEMs, _In_ DWORD flags);
/*
* Read a single 4096-byte page of memory.
+103 -72
View File
@@ -1,13 +1,12 @@
// vfsproc.c : implementation of functions related to operating system and process parsing of virtual memory.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
#include "vmmproc.h"
#include "vmmwin.h"
#include "vmmwininit.h"
#include "device.h"
#include "statistics.h"
#include "util.h"
@@ -22,105 +21,112 @@
*/
BOOL VmmProcUserCR3TryInitialize64()
{
PVMM_PROCESS pProcess;
PVMM_PROCESS pObProcess;
VmmInitializeMemoryModel(VMM_MEMORYMODEL_X64);
pProcess = VmmProcessCreateEntry(0, 0, ctxMain->cfg.paCR3, 0, "unknown_process", FALSE, TRUE);
pObProcess = VmmProcessCreateEntry(TRUE, 0, 0, ctxMain->cfg.paCR3, 0, "unknown_process", FALSE);
VmmProcessCreateFinish();
if(!pProcess) {
if(!pObProcess) {
vmmprintfv("VmmProc: FAIL: Initialization of Process failed from user-defined CR3 %016llx.\n", ctxMain->cfg.paCR3);
VmmInitializeMemoryModel(VMM_MEMORYMODEL_NA);
return FALSE;
}
VmmTlbSpider(pProcess->paDTB, FALSE);
VmmTlbSpider(pObProcess);
VmmOb_DECREF(pObProcess);
ctxVmm->tpSystem = VMM_SYSTEM_UNKNOWN_X64;
ctxVmm->kernel.paDTB = ctxMain->cfg.paCR3;
return TRUE;
}
BOOL VmmProc_Refresh(_In_ BOOL fProcessList, _In_ BOOL fProcessFull)
BOOL VmmProc_Refresh(_In_ BOOL fRefreshTotal)
{
PVMM_PROCESS pSystemProcess;
QWORD paSystemPML4, vaSystemEPROCESS;
if(fProcessList) {
ctxVmm->stat.cRefreshProcessPartial++;
// Windows OS
if((ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X64) || (ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X86)) {
pSystemProcess = VmmProcessGet(4);
if(pSystemProcess) {
VmmWin_EnumerateEPROCESS(pSystemProcess);
vmmprintfvv("VmmProc: vmmproc.c!VmmProcCacheUpdaterThread FlushProcessList\n");
}
}
}
if(fProcessFull) {
ctxVmm->stat.cRefreshProcessFull++;
// Windows OS
if((ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X64) || (ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X86)) {
pSystemProcess = VmmProcessGet(4);
if(pSystemProcess) {
paSystemPML4 = pSystemProcess->paDTB;
vaSystemEPROCESS = pSystemProcess->os.win.vaEPROCESS;
// spider TLB and set up initial system process and enumerate EPROCESS
VmmTlbSpider(paSystemPML4, FALSE);
pSystemProcess = VmmProcessCreateEntry(4, 0, paSystemPML4, 0, "System", FALSE, TRUE);
if(!pSystemProcess) { return FALSE; }
pSystemProcess->os.win.vaEPROCESS = vaSystemEPROCESS;
VmmWin_EnumerateEPROCESS(pSystemProcess);
vmmprintfvv("vmmproc.c!VmmProc_Refresh FlushProcessListAndBuffers\n");
}
}
// Single user-defined X64 process
BOOL result;
PVMM_PROCESS pObProcessSystem;
// statistic count
if(!fRefreshTotal) { InterlockedIncrement64(&ctxVmm->stat.cRefreshProcessPartial); }
if(fRefreshTotal) { InterlockedIncrement64(&ctxVmm->stat.cRefreshProcessFull); }
// Single user-defined X64 process
if(fRefreshTotal) {
if(ctxVmm->tpSystem == VMM_SYSTEM_UNKNOWN_X64) {
VmmProcessCreateTable();
VmmProcUserCR3TryInitialize64();
}
}
// Windows OS
if((ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X64) || (ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X86)) {
vmmprintfvv_fn("ProcessRefresh: %s\n", (fRefreshTotal ? "Total" : "Partial"));
pObProcessSystem = VmmProcessGet(4);
if(!pObProcessSystem) {
vmmprintf_fn("FAIL - SYSTEM PROCESS NOT FOUND - SHOULD NOT HAPPEN\n");
return FALSE;
}
result = VmmWin_EnumerateEPROCESS(pObProcessSystem, fRefreshTotal);
VmmOb_DECREF(pObProcessSystem);
}
return TRUE;
}
#define VMMPROC_UPDATERTHREAD_PERIOD 100
#define VMMPROC_UPDATERTHREAD_PHYSCACHE (500 / VMMPROC_UPDATERTHREAD_PERIOD) // 0.5s
#define VMMPROC_UPDATERTHREAD_TLB (5 * 1000 / VMMPROC_UPDATERTHREAD_PERIOD) // 5s
#define VMMPROC_UPDATERTHREAD_PROC_REFRESHLIST (5 * 1000 / VMMPROC_UPDATERTHREAD_PERIOD) // 5s
#define VMMPROC_UPDATERTHREAD_PROC_REFRESHTOTAL (15 * 1000 / VMMPROC_UPDATERTHREAD_PERIOD) // 15s
// Initial hard coded values that seems to be working nicely below. These values
// may be changed in config options or by editing files in the .status directory.
#define VMMPROC_UPDATERTHREAD_LOCAL_PERIOD 100
#define VMMPROC_UPDATERTHREAD_LOCAL_PHYSCACHE (500 / VMMPROC_UPDATERTHREAD_LOCAL_PERIOD) // 0.5s
#define VMMPROC_UPDATERTHREAD_LOCAL_TLB (5 * 1000 / VMMPROC_UPDATERTHREAD_LOCAL_PERIOD) // 5s
#define VMMPROC_UPDATERTHREAD_LOCAL_PROC_REFRESHLIST (5 * 1000 / VMMPROC_UPDATERTHREAD_LOCAL_PERIOD) // 5s
#define VMMPROC_UPDATERTHREAD_LOCAL_PROC_REFRESHTOTAL (15 * 1000 / VMMPROC_UPDATERTHREAD_LOCAL_PERIOD) // 15s
#define VMMPROC_UPDATERTHREAD_REMOTE_PERIOD 100
#define VMMPROC_UPDATERTHREAD_REMOTE_PHYSCACHE (15 * 1000 / VMMPROC_UPDATERTHREAD_REMOTE_PERIOD) // 15s
#define VMMPROC_UPDATERTHREAD_REMOTE_TLB (3 * 60 * 1000 / VMMPROC_UPDATERTHREAD_REMOTE_PERIOD) // 3m
#define VMMPROC_UPDATERTHREAD_REMOTE_PROC_REFRESHLIST (15 * 1000 / VMMPROC_UPDATERTHREAD_REMOTE_PERIOD) // 15s
#define VMMPROC_UPDATERTHREAD_REMOTE_PROC_REFRESHTOTAL (3 * 60 * 1000 / VMMPROC_UPDATERTHREAD_REMOTE_PERIOD) // 3m
DWORD VmmProcCacheUpdaterThread()
{
QWORD i = 0;
BOOL fPHYS, fTLB, fProcList, fProcTotal;
QWORD i = 0, paMax;
BOOL fPHYS, fTLB, fProcPartial, fProcTotal;
vmmprintfv("VmmProc: Start periodic cache flushing.\n");
ctxVmm->ThreadProcCache.cMs_TickPeriod = VMMPROC_UPDATERTHREAD_PERIOD;
ctxVmm->ThreadProcCache.cTick_Phys = VMMPROC_UPDATERTHREAD_PHYSCACHE;
ctxVmm->ThreadProcCache.cTick_TLB = VMMPROC_UPDATERTHREAD_TLB;
ctxVmm->ThreadProcCache.cTick_ProcPartial = VMMPROC_UPDATERTHREAD_PROC_REFRESHLIST;
ctxVmm->ThreadProcCache.cTick_ProcTotal = VMMPROC_UPDATERTHREAD_PROC_REFRESHTOTAL;
if(ctxMain->dev.fRemote) {
ctxVmm->ThreadProcCache.cMs_TickPeriod = VMMPROC_UPDATERTHREAD_REMOTE_PERIOD;
ctxVmm->ThreadProcCache.cTick_Phys = VMMPROC_UPDATERTHREAD_REMOTE_PHYSCACHE;
ctxVmm->ThreadProcCache.cTick_TLB = VMMPROC_UPDATERTHREAD_REMOTE_TLB;
ctxVmm->ThreadProcCache.cTick_ProcPartial = VMMPROC_UPDATERTHREAD_REMOTE_PROC_REFRESHLIST;
ctxVmm->ThreadProcCache.cTick_ProcTotal = VMMPROC_UPDATERTHREAD_REMOTE_PROC_REFRESHTOTAL;
} else {
ctxVmm->ThreadProcCache.cMs_TickPeriod = VMMPROC_UPDATERTHREAD_LOCAL_PERIOD;
ctxVmm->ThreadProcCache.cTick_Phys = VMMPROC_UPDATERTHREAD_LOCAL_PHYSCACHE;
ctxVmm->ThreadProcCache.cTick_TLB = VMMPROC_UPDATERTHREAD_LOCAL_TLB;
ctxVmm->ThreadProcCache.cTick_ProcPartial = VMMPROC_UPDATERTHREAD_LOCAL_PROC_REFRESHLIST;
ctxVmm->ThreadProcCache.cTick_ProcTotal = VMMPROC_UPDATERTHREAD_LOCAL_PROC_REFRESHTOTAL;
}
while(ctxVmm->ThreadProcCache.fEnabled) {
Sleep(ctxVmm->ThreadProcCache.cMs_TickPeriod);
i++;
fTLB = !(i % ctxVmm->ThreadProcCache.cTick_TLB);
fPHYS = !(i % ctxVmm->ThreadProcCache.cTick_Phys);
fProcTotal = !(i % ctxVmm->ThreadProcCache.cTick_ProcTotal);
fProcList = !(i % ctxVmm->ThreadProcCache.cTick_ProcPartial) && !fProcTotal;
fProcPartial = !(i % ctxVmm->ThreadProcCache.cTick_ProcPartial) && !fProcTotal;
EnterCriticalSection(&ctxVmm->MasterLock);
// PHYS / TLB cache clear
if(fPHYS || fTLB) {
VmmCacheClear(fTLB, fPHYS);
ctxVmm->stat.cRefreshPhys += fPHYS ? 1 : 0;
ctxVmm->stat.cRefreshTlb += fTLB ? 1 : 0;
if(fPHYS) {
VmmCacheClear(VMM_CACHE_TAG_PHYS);
InterlockedIncrement64(&ctxVmm->stat.cRefreshPhys);
}
if(fTLB) {
VmmCacheClear(VMM_CACHE_TAG_TLB);
InterlockedIncrement64(&ctxVmm->stat.cRefreshTlb);
}
// refresh proc list
if(fProcList) {
VmmProc_Refresh(TRUE, FALSE);
}
// total refresh of entire proc cache
if(fProcTotal) {
if(!VmmProc_Refresh(FALSE, TRUE)) {
if(fProcPartial || fProcTotal) {
if(!VmmProc_Refresh(fProcTotal)) {
vmmprintf("VmmProc: Failed to refresh memory process file system - aborting.\n");
VmmProcessCreateFinish();
ctxVmm->ThreadProcCache.fEnabled = FALSE;
LeaveCriticalSection(&ctxVmm->MasterLock);
goto fail;
}
// update max physical address (if volatile).
if(ctxMain->dev.fVolatileMaxAddress) {
if(LeechCore_GetOption(LEECHCORE_OPT_MEMORYINFO_ADDR_MAX, &paMax) && (paMax > 0x01000000)) {
ctxMain->dev.paMax = paMax;
}
}
}
LeaveCriticalSection(&ctxVmm->MasterLock);
}
@@ -130,10 +136,31 @@ fail:
return 0;
}
VOID VmmProc_InitializeModuleNames(_In_ PVMM_PROCESS pProcess)
VOID VmmProc_ModuleMapInitialize(_In_ PVMM_PROCESS pProcess)
{
if((ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X64) || (ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X86)) {
VmmWin_InitializeModuleNames(pProcess);
VmmTlbSpider(pProcess);
VmmWin_ModuleMapInitialize(pProcess);
}
}
_Success_(return)
BOOL VmmProc_ModuleMapGet(_In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MODULEMAP *ppObModuleMap)
{
if(!pProcess->pObModuleMap) {
VmmProc_ModuleMapInitialize(pProcess);
}
if(pProcess->pObModuleMap && pProcess->pObModuleMap->fValid) {
*ppObModuleMap = VmmOb_INCREF(pProcess->pObModuleMap);
return TRUE;
}
return FALSE;
}
VOID VmmProc_ScanTagsMemMap(_In_ PVMM_PROCESS pProcess)
{
if((ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X64) || (ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X86)) {
VmmWin_ScanTagsMemMap(pProcess);
}
}
@@ -153,9 +180,10 @@ BOOL VmmProcInitialize()
}
}
// set up cache maintenance in the form of a separate worker thread in case
// the backend is a writeable device (FPGA). File devices are read-only so
// far so full caching is enabled since they are considered to be read-only.
if(result && !ctxVmm->fReadOnly) {
// the backend is a writeable device (FPGA). If the underlying device isn't
// volatile then there is no need to update! NB! Files are not considered
// to be volatile.
if(result && ctxMain->dev.fVolatile && !ctxMain->cfg.fDisableBackgroundRefresh) {
ctxVmm->ThreadProcCache.fEnabled = TRUE;
ctxVmm->ThreadProcCache.hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)VmmProcCacheUpdaterThread, ctxVmm, 0, NULL);
if(!ctxVmm->ThreadProcCache.hThread) { ctxVmm->ThreadProcCache.fEnabled = FALSE; }
@@ -199,6 +227,7 @@ BOOL VmmProcPHYS_ScanForKernel(_Out_ PQWORD ppaPML4, _In_ QWORD paBase, _In_ QWO
QWORD o, i, paCurrent;
PBYTE pbBuffer8M = NULL;
PPAGE_STATISTICS pPageStat = NULL;
LEECHCORE_PAGESTAT_MINIMAL PageStatMinimal;
BOOL result;
// initialize / allocate memory
pbBuffer8M = LocalAlloc(0, 0x800000);
@@ -206,9 +235,11 @@ BOOL VmmProcPHYS_ScanForKernel(_Out_ PQWORD ppaPML4, _In_ QWORD paBase, _In_ QWO
if(!pbBuffer8M || !pPageStat) { goto fail; }
paCurrent = paBase;
PageStatInitialize(pPageStat, paCurrent, paMax, szDescription, FALSE, FALSE);
PageStatMinimal.h = (HANDLE)pPageStat;
PageStatMinimal.pfnPageStatUpdate = PageStatUpdate;
// loop kmd-find
for(; paCurrent < paMax; paCurrent += 0x00800000) {
if(!DeviceReadMEMEx(paCurrent, pbBuffer8M, 0x00800000, pPageStat)) { continue; }
if(!LeechCore_ReadEx(paCurrent, pbBuffer8M, 0x00800000, 0, &PageStatMinimal)) { continue; }
for(o = 0; o < 0x00800000; o += 0x1000) {
// Scan for windows EPROCESS (to get DirectoryBase/PML4)
for(i = 0; i < 0x1000; i += 8) {
@@ -241,8 +272,8 @@ BOOL VmmProcIdentify()
"IDENTIFY: Scanning to identify target operating system and page directories...\n"
" Currently supported oprerating systems:\n"
" - Windows (64-bit).\n");
if(ctxMain->cfg.paAddrMax > 0x100000000) {
result = VmmProcPHYS_ScanForKernel(&paPML4, 0x100000000, ctxMain->cfg.paAddrMax, "Scanning 4GB+ to Identify (1/2) ...");
if(ctxMain->dev.paMax > 0x100000000) {
result = VmmProcPHYS_ScanForKernel(&paPML4, 0x100000000, ctxMain->dev.paMax, "Scanning 4GB+ to Identify (1/2) ...");
}
if(!result) {
result = VmmProcPHYS_ScanForKernel(&paPML4, 0x01000000, 0x100000000, "Scanning 0-4GB to Identify (2/2) ...");
+21 -6
View File
@@ -1,6 +1,6 @@
// vmmproc.h : definitions related to operating system and process parsing of virtual memory
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
#ifndef __VMMPROC_H__
@@ -9,17 +9,32 @@
/*
* Force a refresh of the process list.
* -- fProcessList = partial refresh of processes should be done.
* -- fProcessFull = full refresh of processes should be done.
* -- fRefreshTotal = full refresh of processes should be done instead of partial.
* -- return
*/
BOOL VmmProc_Refresh(_In_ BOOL fProcessList, _In_ BOOL fProcessFull);
BOOL VmmProc_Refresh(_In_ BOOL fRefreshTotal);
/*
* Load operating system dependant module names, such as parsed from PE or ELF
* into the proper display caches, and also into the memory map.
* into the modules map.
*/
VOID VmmProc_InitializeModuleNames(_In_ PVMM_PROCESS pProcess);
VOID VmmProc_ModuleMapInitialize(_In_ PVMM_PROCESS pProcess);
/*
* Retrieve the module map. Map is generated on-demand if not already existing.
* CALLER DECREF: ppObModuleMap
* -- pProcess
* -- ppObModuleMap
* -- return
*/
_Success_(return)
BOOL VmmProc_ModuleMapGet(_In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MODULEMAP *ppObModuleMap);
/*
* Scan additional process information (not already in the initialized modulemap)
* and put the result into the memory map.
*/
VOID VmmProc_ScanTagsMemMap(_In_ PVMM_PROCESS pProcess);
/*
* Tries to automatically identify the operating system given by the supplied
+72 -71
View File
@@ -1,6 +1,6 @@
// vmmvfs.c : implementation related to virtual memory management / virtual file system interfacing.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
#include "vmm.h"
@@ -67,15 +67,14 @@ BOOL VmmVfs_UtilVmmGetPidDirFile(_In_ LPCWSTR wcsFileName, _Out_ PVMMVFS_PATH pP
// FUNCTIONALITY RELATED TO: READ
// ----------------------------------------------------------------------------
NTSTATUS VmmVfsReadFileProcess(_In_ PVMMVFS_PATH pPath, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset)
NTSTATUS VmmVfsReadFileProcess(_In_ PVMM_PROCESS pProcess, _In_ PVMMVFS_PATH pPath, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset)
{
PVMM_PROCESS pProcess;
NTSTATUS nt;
BYTE pbBuffer[0x800];
DWORD cbBuffer;
PVMMOB_PDATA pObMemMapDisplay;
PVMMOB_MODULEMAP pObModuleMap;
ZeroMemory(pbBuffer, 48);
if(!ctxVmm) { return VMM_STATUS_FILE_INVALID; }
pProcess = VmmProcessGet(pPath->dwPID);
if(!pProcess) { return VMM_STATUS_FILE_INVALID; }
// read memory from "vmem" file
if(!_stricmp(pPath->szPath1, "vmem")) {
if((ctxVmm->tpMemoryModel != VMM_MEMORYMODEL_X64) && (cbOffset + cb >= 0x100000000)) {
@@ -88,13 +87,10 @@ NTSTATUS VmmVfsReadFileProcess(_In_ PVMMVFS_PATH pPath, _Out_ LPVOID pb, _In_ DW
}
// read the memory map
if(!_stricmp(pPath->szPath1, "map")) {
if(!pProcess->pbMemMapDisplayCache) {
VmmMapDisplayBufferGenerate(pProcess);
if(!pProcess->pbMemMapDisplayCache) {
return VMM_STATUS_FILE_INVALID;
}
}
return Util_VfsReadFile_FromPBYTE(pProcess->pbMemMapDisplayCache, pProcess->cbMemMapDisplayCache, pb, cb, pcbRead, cbOffset);
if(!VmmMemMapGetDisplay(pProcess, VMM_MEMMAP_FLAG_ALL, &pObMemMapDisplay)) { return VMMDLL_STATUS_FILE_INVALID; }
nt = Util_VfsReadFile_FromPBYTE(pObMemMapDisplay->pbData, pObMemMapDisplay->cbData, pb, cb, pcbRead, cbOffset);
VmmOb_DECREF(pObMemMapDisplay);
return nt;
}
// read genereal numeric values from files, pml4, pid, name, virt
if(!_stricmp(pPath->szPath1, "dtb")) {
@@ -130,8 +126,10 @@ NTSTATUS VmmVfsReadFileProcess(_In_ PVMMVFS_PATH pPath, _Out_ LPVOID pb, _In_ DW
if(!_stricmp(pPath->szPath1, "win-peb")) {
return Util_VfsReadFile_FromQWORD(pProcess->os.win.vaPEB, pb, cb, pcbRead, cbOffset, FALSE);
}
if(!_stricmp(pPath->szPath1, "win-modules") && pProcess->os.win.pbLdrModulesDisplayCache) {
return Util_VfsReadFile_FromPBYTE(pProcess->os.win.pbLdrModulesDisplayCache, pProcess->os.win.cbLdrModulesDisplayCache, pb, cb, pcbRead, cbOffset);
if(!_stricmp(pPath->szPath1, "win-modules") && VmmProc_ModuleMapGet(pProcess, &pObModuleMap)) {
nt = Util_VfsReadFile_FromPBYTE(pObModuleMap->pbDisplay, pObModuleMap->cbDisplay, pb, cb, pcbRead, cbOffset);
VmmOb_DECREF(pObModuleMap);
return nt;
}
if(!_stricmp(pPath->szPath1, "win-peb32")) {
return Util_VfsReadFile_FromDWORD(pProcess->os.win.vaPEB32, pb, cb, pcbRead, cbOffset, FALSE);
@@ -147,8 +145,10 @@ NTSTATUS VmmVfsReadFileProcess(_In_ PVMMVFS_PATH pPath, _Out_ LPVOID pb, _In_ DW
if(!_stricmp(pPath->szPath1, "win-peb")) {
return Util_VfsReadFile_FromDWORD((DWORD)pProcess->os.win.vaPEB, pb, cb, pcbRead, cbOffset, FALSE);
}
if(!_stricmp(pPath->szPath1, "win-modules") && pProcess->os.win.pbLdrModulesDisplayCache) {
return Util_VfsReadFile_FromPBYTE(pProcess->os.win.pbLdrModulesDisplayCache, pProcess->os.win.cbLdrModulesDisplayCache, pb, cb, pcbRead, cbOffset);
if(!_stricmp(pPath->szPath1, "win-modules") && VmmProc_ModuleMapGet(pProcess, &pObModuleMap)) {
nt = Util_VfsReadFile_FromPBYTE(pObModuleMap->pbDisplay, pObModuleMap->cbDisplay, pb, cb, pcbRead, cbOffset);
VmmOb_DECREF(pObModuleMap);
return nt;
}
}
// no hit - call down the loadable modules chain for potential hits
@@ -161,6 +161,7 @@ NTSTATUS VmmVfs_Read(LPCWSTR wcsFileName, _Out_ LPVOID pb, _In_ DWORD cb, _Out_
VMMVFS_PATH path;
CHAR _szBuf[MAX_PATH];
LPSTR szModule, szModulePath;
PVMM_PROCESS pObProcess;
if(!ctxVmm) { return nt; }
// read '\\pmem' - physical memory file:
if(!_wcsicmp(wcsFileName, L"\\pmem")) {
@@ -169,9 +170,12 @@ NTSTATUS VmmVfs_Read(LPCWSTR wcsFileName, _Out_ LPVOID pb, _In_ DWORD cb, _Out_
}
// read files in process directories:
if(!_wcsnicmp(wcsFileName, L"\\name", 5) || !_wcsnicmp(wcsFileName, L"\\pid", 4)) {
if(!ctxVmm->ptPROC) { return nt; }
if(!VmmVfs_UtilVmmGetPidDirFile(wcsFileName, &path)) { return nt; }
return VmmVfsReadFileProcess(&path, pb, cb, pcbRead, cbOffset);
pObProcess = VmmProcessGet(path.dwPID);
if(!pObProcess) { return VMM_STATUS_FILE_INVALID; }
nt = VmmVfsReadFileProcess(pObProcess, &path, pb, cb, pcbRead, cbOffset);
VmmOb_DECREF(pObProcess);
return nt;
}
// list files in any non-process modules directories
Util_PathSplit2_WCHAR((LPWSTR)(wcsFileName + 1), _szBuf, &szModule, &szModulePath);
@@ -182,13 +186,9 @@ NTSTATUS VmmVfs_Read(LPCWSTR wcsFileName, _Out_ LPVOID pb, _In_ DWORD cb, _Out_
// FUNCTIONALITY RELATED TO: WRITE
// ----------------------------------------------------------------------------
NTSTATUS VmmVfsWriteFileProcess(_In_ PVMMVFS_PATH pPath, _In_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset)
NTSTATUS VmmVfsWriteFileProcess(_In_ PVMM_PROCESS pProcess, _In_ PVMMVFS_PATH pPath, _In_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset)
{
PVMM_PROCESS pProcess;
BOOL fFound, result;
if(!pPath->szPath1) { return VMM_STATUS_FILE_INVALID; }
pProcess = VmmProcessGet(pPath->dwPID);
if(!pProcess) { return VMM_STATUS_FILE_INVALID; }
// read only files - report zero bytes written
fFound =
!_stricmp(pPath->szPath1, "map") ||
@@ -227,6 +227,7 @@ NTSTATUS VmmVfs_Write(LPCWSTR wcsFileName, _In_ LPVOID pb, _In_ DWORD cb, _Out_
BOOL result;
VMMVFS_PATH path;
CHAR _szBuf[MAX_PATH];
PVMM_PROCESS pObProcess;
LPSTR szModule, szModulePath;
if(!ctxVmm) { return nt; }
// read '\\pmem' - physical memory file:
@@ -237,9 +238,11 @@ NTSTATUS VmmVfs_Write(LPCWSTR wcsFileName, _In_ LPVOID pb, _In_ DWORD cb, _Out_
}
// read files in process directories:
if(!_wcsnicmp(wcsFileName, L"\\name", 5) || !_wcsnicmp(wcsFileName, L"\\pid", 4)) {
if(!ctxVmm->ptPROC) { return nt; }
if(!VmmVfs_UtilVmmGetPidDirFile(wcsFileName, &path)) { return nt; }
return VmmVfsWriteFileProcess(&path, pb, cb, pcbWrite, cbOffset);
if(!VmmVfs_UtilVmmGetPidDirFile(wcsFileName, &path) || !path.szPath1) { return nt; }
pObProcess = VmmProcessGet(path.dwPID);
if(!pObProcess) { return VMM_STATUS_FILE_INVALID; }
nt = VmmVfsWriteFileProcess(pObProcess, &path, pb, cb, pcbWrite, cbOffset);
return nt;
}
// list files in any non-process modules directories
Util_PathSplit2_WCHAR((LPWSTR)(wcsFileName + 1), _szBuf, &szModule, &szModulePath);
@@ -252,6 +255,7 @@ NTSTATUS VmmVfs_Write(LPCWSTR wcsFileName, _In_ LPVOID pb, _In_ DWORD cb, _Out_
VOID VmmVfsListFiles_OsSpecific(_In_ PVMM_PROCESS pProcess, _Inout_ PHANDLE pFileList)
{
PVMMOB_MODULEMAP pObModuleMap;
// WINDOWS
if(ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X64) {
VMMDLL_VfsList_AddFile(pFileList, "win-eprocess", 16);
@@ -262,8 +266,11 @@ VOID VmmVfsListFiles_OsSpecific(_In_ PVMM_PROCESS pProcess, _Inout_ PHANDLE pFil
if(pProcess->os.win.vaPEB) {
VMMDLL_VfsList_AddFile(pFileList, "win-peb", 16);
}
if(pProcess->os.win.cbLdrModulesDisplayCache) {
VMMDLL_VfsList_AddFile(pFileList, "win-modules", pProcess->os.win.cbLdrModulesDisplayCache);
if(VmmProc_ModuleMapGet(pProcess, &pObModuleMap)) {
if(pObModuleMap->cbDisplay) {
VMMDLL_VfsList_AddFile(pFileList, "win-modules", pObModuleMap->cbDisplay);
}
VmmOb_DECREF(pObModuleMap);
}
// 32-bit PEB and modules
if(pProcess->os.win.vaPEB32) {
@@ -279,57 +286,44 @@ VOID VmmVfsListFiles_OsSpecific(_In_ PVMM_PROCESS pProcess, _Inout_ PHANDLE pFil
if(pProcess->os.win.vaPEB) {
VMMDLL_VfsList_AddFile(pFileList, "win-peb", 8);
}
if(pProcess->os.win.cbLdrModulesDisplayCache) {
VMMDLL_VfsList_AddFile(pFileList, "win-modules", pProcess->os.win.cbLdrModulesDisplayCache);
if(VmmProc_ModuleMapGet(pProcess, &pObModuleMap)) {
if(pObModuleMap->cbDisplay) {
VMMDLL_VfsList_AddFile(pFileList, "win-modules", pObModuleMap->cbDisplay);
}
VmmOb_DECREF(pObModuleMap);
}
}
}
_Success_(return)
BOOL VmmVfsListFilesProcess(_In_ PVMMVFS_PATH pPath, _Inout_ PHANDLE pFileList)
BOOL VmmVfsListFilesProcessRoot(_In_ PVMMVFS_PATH pPath, _Inout_ PHANDLE pFileList)
{
PVMM_PROCESS pProcess;
WORD iProcess;
PVMM_PROCESS pObProcess = NULL;
CHAR szBufferFileName[MAX_PATH];
if(!ctxVmm || !ctxVmm->ptPROC) { return FALSE; }
// populate root node - list processes as directories
if(pPath->fRoot) {
iProcess = ctxVmm->ptPROC->iFLink;
pProcess = ctxVmm->ptPROC->M[iProcess];
while(pProcess) {
{
if(pPath->fNamePID) {
if(pProcess->dwState) {
sprintf_s(szBufferFileName, MAX_PATH - 1, "%s-(%x)-%i", pProcess->szName, pProcess->dwState, pProcess->dwPID);
} else {
sprintf_s(szBufferFileName, MAX_PATH - 1, "%s-%i", pProcess->szName, pProcess->dwPID);
}
} else {
sprintf_s(szBufferFileName, MAX_PATH - 1, "%i", pProcess->dwPID);
}
VMMDLL_VfsList_AddDirectory(pFileList, szBufferFileName);
while((pObProcess = VmmProcessGetNext(pObProcess))) {
if(pPath->fNamePID) {
if(pObProcess->dwState) {
sprintf_s(szBufferFileName, MAX_PATH - 1, "%s-(%x)-%i", pObProcess->szName, pObProcess->dwState, pObProcess->dwPID);
} else {
sprintf_s(szBufferFileName, MAX_PATH - 1, "%s-%i", pObProcess->szName, pObProcess->dwPID);
}
iProcess = ctxVmm->ptPROC->iFLinkM[iProcess];
pProcess = ctxVmm->ptPROC->M[iProcess];
if(!iProcess || iProcess == ctxVmm->ptPROC->iFLink) { break; }
} else {
sprintf_s(szBufferFileName, MAX_PATH - 1, "%i", pObProcess->dwPID);
}
return TRUE;
}
// generate memmap, if not already done. required by following steps
pProcess = VmmProcessGet(pPath->dwPID);
if(!pProcess) { return FALSE; }
if(!pProcess->pMemMap || !pProcess->cMemMap) {
if(!pProcess->fSpiderPageTableDone) {
VmmTlbSpider(pProcess->paDTB, pProcess->fUserOnly);
pProcess->fSpiderPageTableDone = TRUE;
}
VmmMapInitialize(pProcess);
VmmProc_InitializeModuleNames(pProcess);
VmmMapDisplayBufferGenerate(pProcess);
VMMDLL_VfsList_AddDirectory(pFileList, szBufferFileName);
}
return TRUE;
}
_Success_(return)
BOOL VmmVfsListFilesProcess(_In_ PVMM_PROCESS pProcess, _In_ PVMMVFS_PATH pPath, _Inout_ PHANDLE pFileList)
{
PVMMOB_MEMMAP pObMemMap = NULL;
// populate process directory - list standard files and subdirectories
if(!pPath->szPath1) {
VMMDLL_VfsList_AddFile(pFileList, "map", pProcess->cbMemMapDisplayCache);
VmmMemMapGetEntries(pProcess, 0, &pObMemMap);
VMMDLL_VfsList_AddFile(pFileList, "map", (pObMemMap ? pObMemMap->cbDisplay : 0));
VmmOb_DECREF(pObMemMap);
VMMDLL_VfsList_AddFile(pFileList, "name", 16);
VMMDLL_VfsList_AddFile(pFileList, "pid", 10);
if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X64) {
@@ -354,7 +348,7 @@ BOOL VmmVfsListFilesRoot(_Inout_ PHANDLE pFileList)
{
VMMDLL_VfsList_AddDirectory(pFileList, "name");
VMMDLL_VfsList_AddDirectory(pFileList, "pid");
VMMDLL_VfsList_AddFile(pFileList, "pmem", ctxMain->cfg.paAddrMax);
VMMDLL_VfsList_AddFile(pFileList, "pmem", ctxMain->dev.paMax);
PluginManager_ListAll(NULL, pFileList);
return TRUE;
}
@@ -364,6 +358,7 @@ BOOL VmmVfs_List(_In_ LPCWSTR wcsPath, _Inout_ PHANDLE pFileList)
BOOL result = FALSE;
VMMVFS_PATH path;
CHAR _szBuf[MAX_PATH];
PVMM_PROCESS pObProcess;
LPSTR szModule, szModulePath;
if(!ctxVmm) { return FALSE; }
// list files in root directory
@@ -372,9 +367,15 @@ BOOL VmmVfs_List(_In_ LPCWSTR wcsPath, _Inout_ PHANDLE pFileList)
}
// list files in name or pid directories:
if(!_wcsnicmp(wcsPath, L"\\name", 5) || !_wcsnicmp(wcsPath, L"\\pid", 4)) {
if(!ctxVmm->ptPROC) { return FALSE; }
if(!VmmVfs_UtilVmmGetPidDirFile(wcsPath, &path)) { return FALSE; }
return VmmVfsListFilesProcess(&path, pFileList);
if(path.fRoot) {
return VmmVfsListFilesProcessRoot(&path, pFileList);
}
pObProcess = VmmProcessGet(path.dwPID);
if(!pObProcess) { return FALSE; }
result = VmmVfsListFilesProcess(pObProcess, &path, pFileList);
VmmOb_DECREF(pObProcess);
return result;
}
// list files in any non-process modules directories
Util_PathSplit2_WCHAR((LPWSTR)(wcsPath + 1), _szBuf, &szModule, &szModulePath);
+1 -1
View File
@@ -1,6 +1,6 @@
// vmmvfs.h : definitions related to virtual memory management / virtual file system interfacing.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
#ifndef __VMMVFS_H__
+668 -318
View File
File diff suppressed because it is too large Load Diff
+29 -7
View File
@@ -1,7 +1,7 @@
// vmmwin.h : definitions related to windows operating system and processes.
// parsing of virtual memory. Windows related features only.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
#ifndef __VMMWIN_H__
@@ -38,7 +38,7 @@ VOID VmmWin_PE_SetSizeSectionIATEAT_DisplayBuffer(_In_ PVMM_PROCESS pProcess, _I
* -- pEATs
* -- pcEATs = number max items of pEATs on entry, number of actual items of pEATs on exit
*/
VOID VmmWin_PE_LoadEAT_DisplayBuffer(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_MODULEMAP_ENTRY pModule, _Out_ PVMMPROC_WINDOWS_EAT_ENTRY pEATs, _Inout_ PDWORD pcEATs);
VOID VmmWin_PE_LoadEAT_DisplayBuffer(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_MODULEMAP_ENTRY pModule, _Out_writes_opt_(*pcEATs) PVMMPROC_WINDOWS_EAT_ENTRY pEATs, _Inout_ PDWORD pcEATs);
/*
* Walk the import address table (IAT) from a given pProcess and store it in the
@@ -48,7 +48,7 @@ VOID VmmWin_PE_LoadEAT_DisplayBuffer(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM
* -- pIATs
* -- pcIATs = number max items of pIATs on entry, number of actual items of pIATs on exit
*/
VOID VmmWin_PE_LoadIAT_DisplayBuffer(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_MODULEMAP_ENTRY pModule, _Out_ PVMMWIN_IAT_ENTRY pIATs, _Inout_ PDWORD pcIATs);
VOID VmmWin_PE_LoadIAT_DisplayBuffer(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_MODULEMAP_ENTRY pModule, _Out_writes_(*pcIATs) PVMMWIN_IAT_ENTRY pIATs, _Inout_ PDWORD pcIATs);
/*
* Fill the pbDisplayBuffer with a human readable version of the data directories.
@@ -61,7 +61,13 @@ VOID VmmWin_PE_LoadIAT_DisplayBuffer(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM
* -- pcbDisplayBuffer
* -- pDataDirectoryOpt
*/
VOID VmmWin_PE_DIRECTORY_DisplayBuffer(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MODULEMAP_ENTRY pModule, _Out_opt_ PBYTE pbDisplayBufferOpt, _In_ DWORD cbDisplayBufferMax, _Out_opt_ PDWORD pcbDisplayBuffer, _Out_writes_opt_(16) PIMAGE_DATA_DIRECTORY pDataDirectoryOpt);
VOID VmmWin_PE_DIRECTORY_DisplayBuffer(
_In_ PVMM_PROCESS pProcess,
_In_ PVMM_MODULEMAP_ENTRY pModule,
_Out_writes_bytes_opt_(*pcbDisplayBuffer) PBYTE pbDisplayBufferOpt,
_In_ DWORD cbDisplayBufferMax,
_Out_opt_ PDWORD pcbDisplayBuffer,
_Out_writes_opt_(16) PIMAGE_DATA_DIRECTORY pDataDirectoryOpt);
/*
* Fill the pbDisplayBuffer with a human readable version of the PE sections.
@@ -74,7 +80,14 @@ VOID VmmWin_PE_DIRECTORY_DisplayBuffer(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MOD
* -- pcSectionsOpt = size of buffer pSectionsOpt on entry, # returned entries on exit
* -- pSectionsOpt
*/
VOID VmmWin_PE_SECTION_DisplayBuffer(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MODULEMAP_ENTRY pModule, _Out_opt_ PBYTE pbDisplayBufferOpt, _In_ DWORD cbDisplayBufferMax, _Out_opt_ PDWORD pcbDisplayBuffer, _Inout_opt_ PDWORD pcSectionsOpt, _Out_opt_ PIMAGE_SECTION_HEADER pSectionsOpt);
VOID VmmWin_PE_SECTION_DisplayBuffer(
_In_ PVMM_PROCESS pProcess,
_In_ PVMM_MODULEMAP_ENTRY pModule,
_Out_writes_bytes_opt_(*pcbDisplayBuffer) PBYTE pbDisplayBufferOpt,
_In_ DWORD cbDisplayBufferMax,
_Out_opt_ PDWORD pcbDisplayBuffer,
_Inout_opt_ PDWORD pcSectionsOpt,
_Out_writes_opt_(*pcSectionsOpt) PIMAGE_SECTION_HEADER pSectionsOpt);
/*
* Initialize the module names into the ctxVMM. This is performed by a PEB/Ldr
@@ -82,15 +95,24 @@ VOID VmmWin_PE_SECTION_DisplayBuffer(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MODUL
* obfuscated.
* -- pProcess
*/
VOID VmmWin_InitializeModuleNames(_In_ PVMM_PROCESS pProcess);
VOID VmmWin_ModuleMapInitialize(_In_ PVMM_PROCESS pProcess);
/*
* Scan the process for various information that is put into the memory map. It
* is recommended to initialize the ModuleMap before calling this function so it
* can skip trying do double work identifying already known modules.
* -- pProcess
*/
VOID VmmWin_ScanTagsMemMap(_In_ PVMM_PROCESS pProcess);
/*
* Try walk the EPROCESS list in the Windows kernel to enumerate processes into
* the VMM/PROC file system.
* NB! This may be done to refresh an existing PID cache hence migration code.
* -- fTotalRefresh = create completely new process entries (instead of updating).
* -- pSystemProcess
* -- return
*/
BOOL VmmWin_EnumerateEPROCESS(_In_ PVMM_PROCESS pSystemProcess);
BOOL VmmWin_EnumerateEPROCESS(_In_ PVMM_PROCESS pSystemProcess, _In_ BOOL fRefreshTotal);
#endif /* __VMMWIN_H__ */
+90 -62
View File
@@ -2,21 +2,19 @@
// systems. Contains functions for detecting DTB and Memory Model
// as well as the Windows kernel base and core functionality.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
#include "vmm.h"
#include "vmmwin.h"
#include "device.h"
#include "pe.h"
#include "util.h"
/*
* Scan a page table hierarchy between virtual addresses between vaMin and vaMax
* for the first occurence of large 2MB pages. This is usually 'ntoskrnl.exe' if
* the OS is Windows. 'ntoskrnl.exe' is loaded between the virtual addresses:
* 0xFFFFF80000000000-0xFFFFF803FFFFFFFF
* the OS is Windows. 'ntoskrnl.exe'.
* -- paTable = set to: physical address of PML4
* -- vaBase = set to 0
* -- vaMin = 0xFFFFF80000000000 (if windows kernel)
@@ -28,13 +26,14 @@
VOID VmmWinInit_FindNtosScan64_LargePageWalk(_In_ QWORD paTable, _In_ QWORD vaBase, _In_ QWORD vaMin, _In_ QWORD vaMax, _In_ BYTE iPML, _Inout_ PQWORD pvaBase, _Inout_ PQWORD pcbSize)
{
const QWORD PML_REGION_SIZE[5] = { 0, 12, 21, 30, 39 };
QWORD i, pte, *ptes, vaCurrent, vaSizeRegion;
ptes = (PQWORD)VmmTlbGetPageTable(paTable, FALSE);
if(!ptes) { return; }
QWORD i, pte, vaCurrent, vaSizeRegion;
PVMMOB_MEM pObPTEs = NULL;
pObPTEs = VmmTlbGetPageTable(paTable, FALSE);
if(!pObPTEs) { return; }
if(iPML == 4) {
*pvaBase = 0;
*pcbSize = 0;
if(!VmmTlbPageTableVerify((PBYTE)ptes, paTable, TRUE)) { return; }
if(!VmmTlbPageTableVerify(pObPTEs->pb, paTable, TRUE)) { goto finish; }
vaBase = 0;
}
for(i = 0; i < 512; i++) {
@@ -42,11 +41,11 @@ VOID VmmWinInit_FindNtosScan64_LargePageWalk(_In_ QWORD paTable, _In_ QWORD vaBa
vaSizeRegion = 1ULL << PML_REGION_SIZE[iPML];
vaCurrent = vaBase + (i << PML_REGION_SIZE[iPML]);
vaCurrent |= (vaCurrent & 0x0000800000000000) ? 0xffff000000000000 : 0; // sign extend
if(*pvaBase && (vaCurrent > (*pvaBase + *pcbSize))) { return; }
if(*pvaBase && (vaCurrent > (*pvaBase + *pcbSize))) { goto finish; }
if(vaCurrent < vaMin) { continue; }
if(vaCurrent > vaMax) { return; }
if(vaCurrent > vaMax) { goto finish; }
// check PTEs
pte = ptes[i];
pte = pObPTEs->pqw[i];
if(!(pte & 0x01)) { continue; } // NOT VALID
if(iPML == 2) {
if(!(pte & 0x80)) { continue; }
@@ -58,13 +57,15 @@ VOID VmmWinInit_FindNtosScan64_LargePageWalk(_In_ QWORD paTable, _In_ QWORD vaBa
VmmWinInit_FindNtosScan64_LargePageWalk(pte & 0x0000fffffffff000, vaCurrent, vaMin, vaMax, iPML - 1, pvaBase, pcbSize);
}
}
finish:
VmmOb_DECREF(pObPTEs);
}
/*
* Sometimes the PageDirectoryBase (PML4) is known, but the kernel location may
* be unknown. This functions walks the page table in the area in which ntoskrnl
* is loaded (0xFFFFF80000000000-0xFFFFF803FFFFFFFF) looking for 2MB large pages
* If an area in 2MB pages are found it is scanned for the ntoskrnl.exe base.
* is loaded looking for 2MB large pages. If an area in 2MB pages are found it
* is scanned for the ntoskrnl.exe base.
* -- pSystemProcess
* -- return = virtual address of ntoskrnl.exe base if successful, otherwise 0.
*/
@@ -77,7 +78,7 @@ QWORD VmmWinInit_FindNtosScan64(PVMM_PROCESS pSystemProcess)
while(TRUE) {
vaBase = 0;
cbSize = 0;
VmmWinInit_FindNtosScan64_LargePageWalk(pSystemProcess->paDTB, 0, vaCurrentMin, 0xFFFFF803FFFFFFFF, 4, &vaBase, &cbSize);
VmmWinInit_FindNtosScan64_LargePageWalk(pSystemProcess->paDTB, 0, vaCurrentMin, 0xFFFFF807FFFFFFFF, 4, &vaBase, &cbSize);
if(!vaBase) { return 0; }
vaCurrentMin = vaBase + cbSize;
if(cbSize >= 0x01000000) { continue; } // too big
@@ -90,7 +91,7 @@ QWORD VmmWinInit_FindNtosScan64(PVMM_PROCESS pSystemProcess)
if(*(PWORD)(pb + p) != 0x5a4d) { continue; } // MZ header
for(o = 0; o < 0x1000; o += 8) {
if(*(PQWORD)(pb + p + o) == 0x45444F434C4F4F50) { // POOLCODE
PE_GetModuleNameEx(pSystemProcess, vaBase + p, FALSE, pb + p, szModuleName, NULL);
PE_GetModuleNameEx(pSystemProcess, vaBase + p, FALSE, pb + p, szModuleName, _countof(szModuleName), NULL);
if(!_stricmp(szModuleName, "ntoskrnl.exe")) {
LocalFree(pb);
return vaBase + p;
@@ -110,12 +111,11 @@ QWORD VmmWinInit_FindNtosScan64(PVMM_PROCESS pSystemProcess)
* -- pSystemProcess
* -- return = virtual address of ntoskrnl.exe base if successful, otherwise 0
*/
QWORD VmmWinInit_FindNtosScanHint64(_In_ PVMM_PROCESS pSystemProcess)
QWORD VmmWinInit_FindNtosScanHint64(_In_ PVMM_PROCESS pSystemProcess, _In_ QWORD vaHint)
{
PBYTE pb;
QWORD vaBase, o, p, vaNtosBase = 0;
DWORD cbRead;
QWORD vaHint = ctxVmm->kernel.vaEntry;
CHAR szModuleName[MAX_PATH] = { 0 };
pb = LocalAlloc(0, 0x00200000);
if(!pb) { goto cleanup; }
@@ -131,7 +131,7 @@ QWORD VmmWinInit_FindNtosScanHint64(_In_ PVMM_PROCESS pSystemProcess)
if(*(PWORD)(pb + p) != 0x5a4d) { continue; } // MZ header
for(o = 0; o < 0x1000; o += 8) {
if(*(PQWORD)(pb + p + o) == 0x45444F434C4F4F50) { // POOLCODE
PE_GetModuleNameEx(pSystemProcess, vaBase + p, FALSE, pb + p, szModuleName, NULL);
PE_GetModuleNameEx(pSystemProcess, vaBase + p, FALSE, pb + p, szModuleName, _countof(szModuleName), NULL);
if(!_stricmp(szModuleName, "ntoskrnl.exe")) {
LocalFree(pb);
return vaBase + p;
@@ -168,7 +168,7 @@ DWORD VmmWinInit_FindNtosScan32(_In_ PVMM_PROCESS pSystemProcess)
if(*(PWORD)(pb + p) != 0x5a4d) { continue; } // MZ header
for(o = 0; o < 0x1000; o += 8) {
if(*(PQWORD)(pb + p + o) == 0x45444F434C4F4F50) { // POOLCODE
PE_GetModuleNameEx(pSystemProcess, 0x80000000ULL + p, FALSE, pb + p, szModuleName, NULL);
PE_GetModuleNameEx(pSystemProcess, 0x80000000ULL + p, FALSE, pb + p, szModuleName, _countof(szModuleName), NULL);
if(!_stricmp(szModuleName, "ntoskrnl.exe")) {
LocalFree(pb);
return 0x80000000 + p;
@@ -182,39 +182,47 @@ DWORD VmmWinInit_FindNtosScan32(_In_ PVMM_PROCESS pSystemProcess)
/*
* Scan for the 'ntoskrnl.exe' by using the DTB and memory model information
* from the ctxVmm.
* -- ppSystemProcess = ptr to receive pSystemProcess upon success.
* -- return
* from the ctxVmm. Return the system process (if found).
* CALLER DECREF: return
* -- return = system process - NB! CALLER must DECREF!
*/
BOOL VmmWinInit_FindNtosScan(_Out_ PVMM_PROCESS *ppSystemProcess)
PVMM_PROCESS VmmWinInit_FindNtosScan()
{
QWORD vaKernelBase = 0, cbKernelSize;
PVMM_PROCESS pSystemProcess;
*ppSystemProcess = NULL;
QWORD vaKernelBase = 0, cbKernelSize, vaKernelHint;
PVMM_PROCESS pObSystemProcess = NULL;
// 1: Pre-initialize System PID (required by VMM)
pSystemProcess = VmmProcessCreateEntry(4, 0, ctxVmm->kernel.paDTB, 0, "System", FALSE, TRUE);
if(!pSystemProcess) { return FALSE; }
pObSystemProcess = VmmProcessCreateEntry(TRUE, 4, 0, ctxVmm->kernel.paDTB, 0, "System", FALSE);
if(!pObSystemProcess) { return NULL; }
VmmProcessCreateFinish();
// 2: Spider DTB to speed things up.
VmmTlbSpider(ctxVmm->kernel.paDTB, FALSE);
VmmTlbSpider(pObSystemProcess);
// 3: Find the base of 'ntoskrnl.exe'
if(VMM_MEMORYMODEL_X64 == ctxVmm->tpMemoryModel) {
if(ctxVmm->kernel.vaEntry) {
vaKernelBase = VmmWinInit_FindNtosScanHint64(pSystemProcess);
LeechCore_GetOption(LEECHCORE_OPT_MEMORYINFO_OS_KERNELBASE, &vaKernelBase);
if(!vaKernelBase) {
vaKernelHint = ctxVmm->kernel.vaEntry;
if(!vaKernelHint) { LeechCore_GetOption(LEECHCORE_OPT_MEMORYINFO_OS_KERNELHINT, &vaKernelHint); }
if(!vaKernelHint) { LeechCore_GetOption(LEECHCORE_OPT_MEMORYINFO_OS_PsActiveProcessHead, &vaKernelHint); }
if(!vaKernelHint) { LeechCore_GetOption(LEECHCORE_OPT_MEMORYINFO_OS_PsLoadedModuleList, &vaKernelHint); }
if(vaKernelHint) {
vaKernelBase = VmmWinInit_FindNtosScanHint64(pObSystemProcess, vaKernelHint);
}
}
if(!vaKernelBase) {
vaKernelBase = VmmWinInit_FindNtosScan64(pSystemProcess);
vaKernelBase = VmmWinInit_FindNtosScan64(pObSystemProcess);
}
} else {
vaKernelBase = VmmWinInit_FindNtosScan32(pSystemProcess);
vaKernelBase = VmmWinInit_FindNtosScan32(pObSystemProcess);
}
if(!vaKernelBase) { return FALSE; }
cbKernelSize = PE_GetSize(pSystemProcess, vaKernelBase);
if(!cbKernelSize) { return FALSE; }
*ppSystemProcess = pSystemProcess;
if(!vaKernelBase) { goto fail; }
cbKernelSize = PE_GetSize(pObSystemProcess, vaKernelBase);
if(!cbKernelSize) { goto fail; }
ctxVmm->kernel.vaBase = vaKernelBase;
ctxVmm->kernel.cbSize = cbKernelSize;
return TRUE;
return pObSystemProcess;
fail:
VmmOb_DECREF(pObSystemProcess);
return NULL;
}
/*
@@ -265,16 +273,16 @@ BOOL VmmWinInit_DTB_FindValidate_X64(_In_ QWORD pa, _In_reads_(0x1000) PBYTE pbP
DWORD c, i;
BOOL fSelfRef = FALSE;
QWORD pte, paMax;
paMax = ctxMain->cfg.paAddrMax;
paMax = ctxMain->dev.paMax;
// check for user-mode page table with PDPT below max physical address and not NX.
pte = *(PQWORD)pbPage;
if(((pte & 0x8000000000000087) != 0x07) || ((pte & 0x0000fffffffff000) > paMax)) { return FALSE; }
if(((pte & 0x0000000000000087) != 0x07) || ((pte & 0x0000fffffffff000) > paMax)) { return FALSE; }
for(c = 0, i = 0x800; i < 0x1000; i += 8) { // minimum number of supervisor entries above 0x800
pte = *(PQWORD)(pbPage + i);
// check for user-mode page table with PDPT below max physical address and not NX.
if(((pte & 0x8000ff0000000087) == 0x03) && ((pte & 0x0000fffffffff000) > paMax)) { c++; }
if(((pte & 0x8000ff0000000087) == 0x03) && ((pte & 0x0000fffffffff000) < paMax)) { c++; }
// check for self-referential entry
if((*(PQWORD)(pbPage + i) & 0x8000fffffffff083) == pa + 0x03) { fSelfRef = TRUE; }
if((*(PQWORD)(pbPage + i) & 0x0000fffffffff083) == pa + 0x03) { fSelfRef = TRUE; }
}
return fSelfRef && (c >= 6);
}
@@ -315,7 +323,7 @@ BOOL VmmWinInit_DTB_FindValidate()
PBYTE pb16M;
if(!(pb16M = LocalAlloc(LMEM_ZEROINIT, 0x01000000))) { return FALSE; }
// 1: try locate DTB via X64 low stub in lower 1MB
DeviceReadMEMEx(0, pb16M, 0x00100000, NULL);
LeechCore_Read(0, pb16M, 0x00100000);
if(VmmWinInit_DTB_FindValidate_X64_LowStub(pb16M)) {
VmmInitializeMemoryModel(VMM_MEMORYMODEL_X64);
paDTB = ctxVmm->kernel.paDTB;
@@ -325,7 +333,7 @@ BOOL VmmWinInit_DTB_FindValidate()
if(!paDTB) {
for(pa = 0; pa < 0x01000000; pa += 0x1000) {
if(pa == 0x00100000) {
DeviceReadMEMEx(0x00100000, pb16M + 0x00100000, 0x00f00000, NULL);
LeechCore_Read(0x00100000, pb16M + 0x00100000, 0x00f00000);
}
if(VmmWinInit_DTB_FindValidate_X64(pa, pb16M + pa)) {
VmmInitializeMemoryModel(VMM_MEMORYMODEL_X64);
@@ -369,7 +377,8 @@ BOOL VmmWinInit_DTB_FindValidate()
BOOL VmmWinInit_DTB_Validate(QWORD paDTB)
{
BYTE pb[0x1000];
DeviceReadMEMEx(0, pb, 0x1000, NULL);
paDTB = paDTB & ~0xfff;
if(!LeechCore_Read(paDTB, pb, 0x1000)) { return FALSE; }
if(VmmWinInit_DTB_FindValidate_X64(paDTB, pb)) {
VmmInitializeMemoryModel(VMM_MEMORYMODEL_X64);
ctxVmm->kernel.paDTB = paDTB;
@@ -392,14 +401,26 @@ BOOL VmmWinInit_FindPsLoadedModuleListKDBG(_In_ PVMM_PROCESS pSystemProcess)
{
PBYTE pbData = NULL, pbKDBG;
IMAGE_SECTION_HEADER SectionHeader;
DWORD o;
QWORD va;
// 1: Try locate 'PsLoadedModuleList' by exported kernel symbol. If this is
DWORD o, va32 = 0;
QWORD va, va64 = 0;
// 1: Try locate 'PsLoadedModuleList' by querying the microsoft crash dump
// file used. This will fail if another memory acqusition device is used.
if(LeechCore_GetOption(LEECHCORE_OPT_MEMORYINFO_OS_PsLoadedModuleList, &va) && va) {
if(ctxVmm->f32 && VmmRead(pSystemProcess, va, (PBYTE)&va32, 4) && (va32 > 0x80000000)) {
ctxVmm->kernel.vaPsLoadedModuleList = va32;
return TRUE;
}
if(!ctxVmm->f32 && VmmRead(pSystemProcess, va, (PBYTE)&va64, 8) && (va64 > 0xffff800000000000)) {
ctxVmm->kernel.vaPsLoadedModuleList = va64;
return TRUE;
}
}
// 2: Try locate 'PsLoadedModuleList' by exported kernel symbol. If this is
// possible it's most probably Windows 10 and KDBG will be encrypted so
// no need to continue looking for it.
ctxVmm->kernel.vaPsLoadedModuleList = PE_GetProcAddress(pSystemProcess, ctxVmm->kernel.vaBase, "PsLoadedModuleList");
if(ctxVmm->kernel.vaPsLoadedModuleList) { return TRUE; }
// 2: Try locate 'KDBG' by looking in 'ntoskrnl.exe' '.text' section. This
// 3: Try locate 'KDBG' by looking in 'ntoskrnl.exe' '.text' section. This
// is the normal way of finding it on 64-bit Windows below Windows 10.
// This also works on 32-bit Windows versions - so use this method for
// simplicity rather than using a separate 32-bit method.
@@ -435,50 +456,57 @@ fail:
*/
BOOL VmmWinInit_TryInitialize(_In_opt_ QWORD paDTBOpt)
{
PVMM_PROCESS pSystemProcess = NULL;
PVMM_PROCESS pObSystemProcess = NULL;
QWORD vaPsInitialSystemProcess, vaSystemEPROCESS;
// Fetch Directory Base (DTB (PML4)) and initialize Memory Model.
if(paDTBOpt) {
if(!VmmWinInit_DTB_Validate(paDTBOpt)) {
vmmprintfv("VmmWinInit_TryInitialize: Initialization Failed. Unable to verify user-supplied DTB. #1\n");
vmmprintfv("VmmWinInit_TryInitialize: Initialization Failed. Unable to verify user-supplied (0x%016llx) DTB. #1\n", paDTBOpt);
goto fail;
}
} else {
} else if(LeechCore_GetOption(LEECHCORE_OPT_MEMORYINFO_OS_DTB, &paDTBOpt)) {
if(!VmmWinInit_DTB_Validate(paDTBOpt)) {
vmmprintfv("VmmWinInit_TryInitialize: Warning: Unable to verify crash-dump supplied DTB. (0x%016llx) #1\n", paDTBOpt);
goto fail;
}
} else if(!ctxVmm->kernel.paDTB) {
if(!VmmWinInit_DTB_FindValidate()) {
vmmprintfv("VmmWinInit_TryInitialize: Initialization Failed. Unable to locate valid DTB. #2\n");
goto fail;
}
}
vmmprintfvv("VmmWinInit_TryInitialize: INFO: DTB located at: %016llx. MemoryModel: %s\n", ctxVmm->kernel.paDTB, VMM_MEMORYMODEL_TOSTRING[ctxVmm->tpMemoryModel]);
vmmprintfvv_fn("INFO: DTB located at: %016llx. MemoryModel: %s\n", ctxVmm->kernel.paDTB, VMM_MEMORYMODEL_TOSTRING[ctxVmm->tpMemoryModel]);
// Fetch 'ntoskrnl.exe' base address
if(!VmmWinInit_FindNtosScan(&pSystemProcess)) {
if(!(pObSystemProcess = VmmWinInit_FindNtosScan())) {
vmmprintfv("VmmWinInit_TryInitialize: Initialization Failed. Unable to locate ntoskrnl.exe. #3\n");
goto fail;
}
vmmprintfvv("VmmWinInit_TryInitialize: INFO: NTOS located at: %016llx.\n", ctxVmm->kernel.vaBase);
vmmprintfvv_fn("INFO: NTOS located at: %016llx.\n", ctxVmm->kernel.vaBase);
// Locate System EPROCESS
vaPsInitialSystemProcess = PE_GetProcAddress(pSystemProcess, ctxVmm->kernel.vaBase, "PsInitialSystemProcess");
if(!VmmRead(pSystemProcess, vaPsInitialSystemProcess, (PBYTE)&vaSystemEPROCESS, 8)) {
vaPsInitialSystemProcess = PE_GetProcAddress(pObSystemProcess, ctxVmm->kernel.vaBase, "PsInitialSystemProcess");
if(!VmmRead(pObSystemProcess, vaPsInitialSystemProcess, (PBYTE)&vaSystemEPROCESS, 8)) {
vmmprintfv("VmmWinInit_TryInitialize: Initialization Failed. Unable to locate EPROCESS. #4\n");
goto fail;
}
if((VMM_MEMORYMODEL_X86 == ctxVmm->tpMemoryModel) || (VMM_MEMORYMODEL_X86PAE == ctxVmm->tpMemoryModel)) {
vaSystemEPROCESS &= 0xffffffff;
}
pSystemProcess->os.win.vaEPROCESS = vaSystemEPROCESS;
vmmprintfvv("VmmWinInit_TryInitialize: INFO: PsInitialSystemProcess located at %016llx.\n", vaPsInitialSystemProcess);
vmmprintfvv("VmmWinInit_TryInitialize: INFO: EPROCESS located at %016llx.\n", vaSystemEPROCESS);
pObSystemProcess->os.win.vaEPROCESS = vaSystemEPROCESS;
vmmprintfvv_fn("INFO: PsInitialSystemProcess located at %016llx.\n", vaPsInitialSystemProcess);
vmmprintfvv_fn("INFO: EPROCESS located at %016llx.\n", vaSystemEPROCESS);
// Enumerate processes
if(!VmmWin_EnumerateEPROCESS(pSystemProcess)) {
if(!VmmWin_EnumerateEPROCESS(pObSystemProcess, TRUE)) {
vmmprintfv("VmmWinInit: Initialization Failed. Unable to walk EPROCESS. #5\n");
goto fail;
}
ctxVmm->tpSystem = (VMM_MEMORYMODEL_X64 == ctxVmm->tpMemoryModel) ? VMM_SYSTEM_WINDOWS_X64 : VMM_SYSTEM_WINDOWS_X86;
// Optionally fetch PsLoadedModuleList / KDBG
VmmWinInit_FindPsLoadedModuleListKDBG(pSystemProcess);
VmmWinInit_FindPsLoadedModuleListKDBG(pObSystemProcess);
VmmOb_DECREF(pObSystemProcess);
return TRUE;
fail:
VmmInitializeMemoryModel(VMM_MEMORYMODEL_NA); // clean memory model
ZeroMemory(&ctxVmm->kernel, sizeof(VMM_KERNELINFO));
VmmOb_DECREF(pObSystemProcess);
return FALSE;
}
+1 -1
View File
@@ -2,7 +2,7 @@
// systems. Contains functions for detecting DTB and Memory Model
// as well as the Windows kernel base and core functionality.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
+466
View File
@@ -0,0 +1,466 @@
// leechcore.h : header file for the leechcore module - which purpose is to
// expose low-level device physical memory functionality.
//
// This library is thread-safe in all functions with the notable exceptions of
// the LeechCore_Open() and LeechCore_Close() functions. Some devices may allow
// multi-threaded access while in reality most devices are single-threaded and
// will control synchronization where necessary with locks.
//
// The library is initialized by calling LeechCore_Open with a LEECHCORE_CONFIG
// struct containing the correct configuration paramters. Note that the version
// and magic values must be set in addition to the szDevice configuration value
// Also, it may be possible to optionally connect to a remote leechcore service
// or instance over RPC by specifying a szRemote configuration value.
//
// ----------------------------------------------------------------------------
//
// Remote instance: szRemote configuration value. Connect to a remote leechcore
// instance by specifying a configuration value in the szRemote parameter. If a
// loaded already valid instance exists remotely this will be prioritized above
// the value in szDevice. If the acquisition device is not yet loaded by the
// remote instance the value in szDevice will be used. Normally, the connection
// will take place as a mutually authenticated encrypted connection secured by
// kerberos. If not possible or desirable the 'insecure' value may be specified
// to disable authentication and security.
// Syntax:
// rpc://<remote_spn>:<host>:<port> (port = optional, remote_spn = kerberos)
// (SPN of remote service or 'insecure' )
// Examples:
// rpc://insecure:remotehost.example.com (connect insecure to remote host )
// rpc://[email protected]:192.0.0.5 (connect secure to remote host )
// rpc://insecure:127.0.0.0:6666 (connect insecure non-default port)
//
// ----------------------------------------------------------------------------
//
// Device to connect to: szDevice contains the device to capture memory from.
// Supported memory acquisition devices are:
// USB3380 : hardware, read/write, 32-bit (4GB) addressing only. Requires a
// PCILeech flashed USB3380 device connected over USB and Google
// Android WinUSB drivers to be installed. Download and install from:
// http://developer.android.com/sdk/win-usb.html#download
// Syntax:
// USB3380
// USB3380://USB2 (force USB2 connection speed)
//
// FPGA : hardware, read/write - requires a PCILeech FPGA flashed hardware
// device as shown at: https://github.com/ufrisk/pcileech-fpga
// Also requires the FTD3XX.DLL from ftdichip to be placed in the
// same directory as the executable. Download from ftdichip at:
// http://www.ftdichip.com/Drivers/D3XX/FTD3XXLibrary_v1.2.0.6.zip
// Syntax:
// FGPA
// FPGA://<read_uS>[:<write_uS>[:<probe_uS>]] (values are optional)
//
// SP605TCP : hardware, read/write - connect to a remote SP605 FPGA over the
// network using the implementation created by @d_olex.
// https://github.com/Cr4sh/s6_pcie_microblaze
// Syntax:
// SP605TCP://<target_ip>[:<target_port>] (port is optional)
//
// RAWTCP : read/write - connect to a remote raw tcp device - such as HPE iLO
// that have been patched to support DMA as per blog entry below:
// https://www.synacktiv.com/posts/exploit/using-your-bmc-as-a-dma-device-plugging-pcileech-to-hpe-ilo-4.html
// Syntax:
// RAWTCP://<target_ip>[:<target_port>] (port is optional)
//
// HvSavedState : read-only - connect to a Hyper-V saved state file. In order
// to do so the .dll file 'vmsavedstatedumpprovider.dll' must be
// placed in same directory as the executable file.
//
// PMEM : load the rekall winpmem driver into the kernel and connect to it
// to acquire memory. The driver file 'winpmem_x64.sys' is found in
// the Rekall directory after most recent version has been installed.
// Copy 'winpmem_x64.sys' to the directory of leechcore.dll and run
// executable as elevated admin using syntax below:
// Syntax:
// PMEM (use winpmem_x64.sys in directory of executable)
// PMEM://<non_default_path_to_file_winpmem_x64.sys>
//
// TOTALMELTDOWN : read/write - requires a Windows 7 system vulnerable to the
// "Total Meltdown" vulnerability - CVE-2018-1038.
// Syntax:
// TOTALMELTDOWN
//
// FILE : use dump file, either a raw linear memory dump or full crash dump.
// Which format to use is auto-detected. If it looks like a full cash
// dump that format will be used, otherwise it will be assumed that a
// raw linear memory dump is to be used.
// Syntax:
// <filename> (no device-type prefix - just use the file name)
// FILE://<filename>
//
// DumpIt : DumpIt is a "virtual" device. It's only possible to use the DumpIt
// device if the main process containing LeechCore has been started
// with DumpIt in LiveKD mode.
// Example 1:
// DumpIt.exe /LIVEKD /A MemProcFS.exe
// Example 2:
// DumpIt.exe /LIVEKD /A LeechSvc.exe /C "interactive insecure"
// and then connect to remote service by:
// MemProcFS.exe -remote rpc://insecure:192.168.x.x -device DumpIt
//
// EXISTING : Attach to existing already loaded configuration. This is done
// instead of the default behaviour of closing any existing devices
// and initializing the new requested device. If no existing device
// exists the call to LeechCore_Open will fail.
// Syntax:
// EXISTING
//
//
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
// Header Version: 1.0
//
#ifndef __LEECHCORE_H__
#define __LEECHCORE_H__
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
//-----------------------------------------------------------------------------
// WINDOWS / LINUX COMPATIBILITY BELOW:
//-----------------------------------------------------------------------------
#ifdef _WIN32
#include <Windows.h>
typedef unsigned __int64 QWORD, *PQWORD;
#define DLLEXPORT __declspec(dllexport)
#endif /* _WIN32 */
#ifdef LINUX
#include <stdint.h>
#include <stddef.h>
typedef void VOID, *PVOID, *LPVOID;
typedef void *HANDLE, **PHANDLE;
typedef uint32_t BOOL, *PBOOL;
typedef uint8_t BYTE, *PBYTE;
typedef char CHAR, *PCHAR, *PSTR, *LPSTR;
typedef uint16_t WORD, *PWORD, USHORT, *PUSHORT;
typedef uint32_t DWORD, *PDWORD;
typedef long long unsigned int QWORD, *PQWORD, ULONG64, *PULONG64;
#define MAX_PATH 260
#define DLLEXPORT __attribute__((visibility("default")))
#define _In_
#define _Out_
#define _In_z_
#define _Inout_
#define _In_opt_
#define _Out_opt_
#define _Out_writes_(x)
#define _Check_return_opt_
#define _Printf_format_string_
#define _Inout_updates_bytes_(x)
#define _In_reads_(cbDataIn)
#define _Success_(return)
#endif /* LINUX */
//-----------------------------------------------------------------------------
// GENERAL HEADER DEFINES BELOW:
//-----------------------------------------------------------------------------
#define MEM_IO_SCATTER_HEADER_MAGIC 0xffff6548
#define MEM_IO_SCATTER_HEADER_VERSION 0x0003
typedef struct tdMEM_IO_SCATTER_HEADER {
DWORD magic; // magic
WORD version; // version
WORD Future1;
ULONG64 qwA; // base address.
DWORD cbMax; // bytes to read (DWORD boundry, max 0x1000); pb must have room for this.
DWORD cb; // bytes read into result buffer.
PBYTE pb; // ptr to 0x1000 sized buffer to receive read bytes.
PVOID pvReserved1; // reserved for use by caller.
PVOID pvReserved2; // reserved for use by caller.
PVOID Future2[8];
} MEM_IO_SCATTER_HEADER, *PMEM_IO_SCATTER_HEADER, **PPMEM_IO_SCATTER_HEADER;
//-----------------------------------------------------------------------------
// LEECHCORE INITIALIZATION / CLOSE FUNCTIONALITY BELOW:
//-----------------------------------------------------------------------------
typedef enum tdLEECHCORE_DEVICE {
LEECHCORE_DEVICE_NA = 0,
LEECHCORE_DEVICE_FILE = 1,
LEECHCORE_DEVICE_PMEM = 2,
LEECHCORE_DEVICE_FPGA = 3,
LEECHCORE_DEVICE_SP605_TCP = 4,
LEECHCORE_DEVICE_USB3380 = 5,
LEECHCORE_DEVICE_TOTALMELTDOWN = 6,
LEECHCORE_DEVICE_HVSAVEDSTATE = 7,
LEECHCORE_DEVICE_RAWTCP = 8,
} LEECHCORE_DEVICE;
#define LEECHCORE_CONFIG_MAGIC 0xffff6549
#define LEECHCORE_CONFIG_VERSION 0x0001
#define LEECHCORE_CONFIG_FLAG_PRINTF 0x0001
#define LEECHCORE_CONFIG_FLAG_PRINTF_VERBOSE_1 0x0002
#define LEECHCORE_CONFIG_FLAG_PRINTF_VERBOSE_2 0x0004
#define LEECHCORE_CONFIG_FLAG_PRINTF_VERBOSE_3 0x0008
#define LEECHCORE_CONFIG_FLAG_REMOTE_NO_COMPRESS 0x0010
typedef struct tdLEECHCORE_CONFIG {
DWORD magic; // set by caller.
WORD version; // set by caller.
WORD flags; // set by caller, updated by device.
ULONG64 paMax; // set by caller, updated by device.
ULONG64 cbMaxSizeMemIo; // set by caller, updated by device.
ULONG64 paMaxNative; // set by device.
LEECHCORE_DEVICE tpDevice; // set by device.
BOOL fWritable; // set by device. (is device writable?)
BOOL fVolatile; // set by device. (is device volatile / memory may change?)
BOOL fVolatileMaxAddress; // set by device. (is max address volatile? - poll changes with LEECHCORE_OPT_MEMORYINFO_ADDR_MAX)
BOOL fRemote; // set by device.
WORD VersionMajor; // set by device.
WORD VersionMinor; // set by device.
WORD VersionRevision; // set by device.
CHAR szDevice[MAX_PATH]; // set by caller.
CHAR szRemote[MAX_PATH]; // set by caller.
// optional 'printf' function pointer. if set to non null value 'printf'
// calls will be redirected. useful when logging to files.
_Check_return_opt_ int(*pfn_printf_opt)(_In_z_ _Printf_format_string_ char const* const _Format, ...); // set by caller.
} LEECHCORE_CONFIG, *PLEECHCORE_CONFIG;
typedef struct tdLEECHCORE_PAGESTAT_MINIMAL {
HANDLE h;
VOID(*pfnPageStatUpdate)(HANDLE h, ULONG64 pa, ULONG64 cPageSuccessAdd, ULONG64 cPageFailAdd);
} LEECHCORE_PAGESTAT_MINIMAL, *PLEECHCORE_PAGESTAT_MINIMAL;
/*
* Open a connection to the target device.
* -- pInformation
* -- result
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_Open(_Inout_ PLEECHCORE_CONFIG pConfig);
/*
* Clean up various device related stuff and deallocate memory buffers.
*/
DLLEXPORT VOID LeechCore_Close();
//-----------------------------------------------------------------------------
// LEECHCORE CORE READ AND WRITE FUNCTIONALITY BELOW:
//-----------------------------------------------------------------------------
#define LEECHCORE_FLAG_READ_RETRY 0x01
#define LEECHCORE_FLAG_WRITE_RETRY 0x01
#define LEECHCORE_FLAG_WRITE_VERIFY 0x02
/*
* Allocate a scatter buffer containing empty 0x1000-sized ppMEMs with address
* set to zero. Caller is responsible for calling LocalFree(ppMEMs).
* -- cMEMs
* -- pppMEMs = pointer to receive ppMEMs on success.
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_AllocScatterEmpty(_In_ DWORD cMEMs, _Out_ PPMEM_IO_SCATTER_HEADER *pppMEMs);
/*
* Read memory in various non-contigious locations specified by the items in the
* phDMAs array. Result for each unit of work will be given individually. No upper
* limit of number of items to read, but no performance boost will be given if
* above hardware limit. Max size of each unit of work is one 4k page (4096 bytes).
* -- ppMEMs = array of scatter read headers.
* -- cpMEMs = count of ppDMAs.
*/
DLLEXPORT VOID LeechCore_ReadScatter(_Inout_ PPMEM_IO_SCATTER_HEADER ppMEMs, _In_ DWORD cpMEMs);
/*
* Try read memory in a fairly optimal way considering device limits. The number
* of total successfully read bytes is returned. Failed reads will be zeroed out
* in the returned memory.
* -- pa
* -- pb
* -- cb
* -- return = the number of bytes successfully read.
*/
DLLEXPORT DWORD LeechCore_Read(_In_ ULONG64 pa, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb);
/*
* Try read memory in a fairly optimal way considering device limits. The number
* of total successfully read bytes is returned. Failed reads will be zeroed out
* in the returned memory.
* -- pa
* -- pb
* -- cb
* -- flags = 0 or LEECHCORE_FLAG_READ_RETRY
* -- pPageStat = optional minimal statistic struct to update.
* -- return = the number of bytes successfully read.
*/
DLLEXPORT DWORD LeechCore_ReadEx(_In_ ULONG64 pa, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _In_ DWORD flags, _In_opt_ PLEECHCORE_PAGESTAT_MINIMAL pPageStat);
/*
* Write data to the target system if supported by the device.
* -- pa
* -- pb
* -- cb
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_Write(_In_ ULONG64 pa, _In_ PBYTE pb, _In_ DWORD cb);
/*
* Write data to the target system if supported by the device.
* -- pa
* -- pb
* -- cb
* -- flags = 0 or LEECHCORE_FLAG_WRITE_*
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_WriteEx(_In_ ULONG64 pa, _In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD flags);
/*
* Probe the memory of the target system to check whether it's readable or not.
* Please note that not all devices support this natively.
* -- pa = address to start probe from.
* -- cPages = number of 4kB pages to probe.
* -- pbResultMap = result map, 1 byte represents 1 page, 0 = fail, 1 = success.
* (individual page elements in pbResultMap must be set to 0 [fail] on call
* for probe to take place on individual page).
* -- return = FALSE if not supported by underlying hardware, TRUE if supported.
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_Probe(_In_ QWORD pa, _In_ DWORD cPages, _Inout_updates_bytes_(cPages) PBYTE pbResultMap);
//-----------------------------------------------------------------------------
// GET/SET DEVICE OPTIONS BELOW. SOME OPTIONS ARE GENERAL LEECHCORE OPTIONS
// WHILE OTHER ARE DEVICE SPECIFIC. USE FUNCTIONS:
// LeechCore_GetOption() AND LeechCore_GetOption() TO GET/SET OPTIONS.
// FOR DEVICE-SPECIFIC OPTIONS PLEASE SEE INDIVIDUAL DEVICE FILES FOR MORE
// DETAILED INFORMATION.
//-----------------------------------------------------------------------------
#define LEECHCORE_OPT_CORE_PRINTF_ENABLE 0x80000001 // RW
#define LEECHCORE_OPT_CORE_VERBOSE 0x80000002 // RW
#define LEECHCORE_OPT_CORE_VERBOSE_EXTRA 0x80000003 // RW
#define LEECHCORE_OPT_CORE_VERBOSE_EXTRA_TLP 0x80000004 // RW
#define LEECHCORE_OPT_CORE_VERSION_MAJOR 0x01000001 // R
#define LEECHCORE_OPT_CORE_VERSION_MINOR 0x01000002 // R
#define LEECHCORE_OPT_CORE_VERSION_REVISION 0x01000003 // R
#define LEECHCORE_OPT_MEMORYINFO_VALID 0x02000001 // R
#define LEECHCORE_OPT_MEMORYINFO_ADDR_MAX 0x02000002 // R
#define LEECHCORE_OPT_MEMORYINFO_FLAG_32BIT 0x02000003 // R
#define LEECHCORE_OPT_MEMORYINFO_FLAG_PAE 0x02000004 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_VERSION_MINOR 0x02000005 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_VERSION_MAJOR 0x02000006 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_DTB 0x02000007 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_PFN 0x02000008 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_PsLoadedModuleList 0x02000009 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_PsActiveProcessHead 0x0200000a // R
#define LEECHCORE_OPT_MEMORYINFO_OS_MACHINE_IMAGE_TP 0x0200000b // R
#define LEECHCORE_OPT_MEMORYINFO_OS_NUM_PROCESSORS 0x0200000c // R
#define LEECHCORE_OPT_MEMORYINFO_OS_SYSTEMTIME 0x0200000d // R
#define LEECHCORE_OPT_MEMORYINFO_OS_UPTIME 0x0200000e // R
#define LEECHCORE_OPT_MEMORYINFO_OS_KERNELBASE 0x0200000f // R
#define LEECHCORE_OPT_MEMORYINFO_OS_KERNELHINT 0x02000010 // R
#define LEECHCORE_OPT_FPGA_PROBE_MAXPAGES 0x03000001 // RW
#define LEECHCORE_OPT_FPGA_RX_FLUSH_LIMIT 0x03000002 // RW
#define LEECHCORE_OPT_FPGA_MAX_SIZE_RX 0x03000003 // RW
#define LEECHCORE_OPT_FPGA_MAX_SIZE_TX 0x03000004 // RW
#define LEECHCORE_OPT_FPGA_DELAY_PROBE_READ 0x03000005 // RW - uS
#define LEECHCORE_OPT_FPGA_DELAY_PROBE_WRITE 0x03000006 // RW - uS
#define LEECHCORE_OPT_FPGA_DELAY_WRITE 0x03000007 // RW - uS
#define LEECHCORE_OPT_FPGA_DELAY_READ 0x03000008 // RW - uS
#define LEECHCORE_OPT_FPGA_RETRY_ON_ERROR 0x03000009 // RW
#define LEECHCORE_OPT_FPGA_DEVICE_ID 0x03000080 // R
#define LEECHCORE_OPT_FPGA_FPGA_ID 0x03000081 // R
#define LEECHCORE_OPT_FPGA_VERSION_MAJOR 0x03000082 // R
#define LEECHCORE_OPT_FPGA_VERSION_MINOR 0x03000083 // R
/*
* Set a device specific option value.
* -- fOption
* -- pqwValue = pointer to QWORD to receive option value.
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_GetOption(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue);
/*
* Set a device specific option value.
* -- fOption
* -- qwValue
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_SetOption(_In_ ULONG64 fOption, _In_ ULONG64 qwValue);
//-----------------------------------------------------------------------------
// TRANSFER DEVICE DEPENDANT COMMANDS OR DATA TO/FROM UNDERLYING DEVICES AND
// PERFORM ACTIONS USING THE LeechCore_CommandData() FUNCTION.
//-----------------------------------------------------------------------------
#define LEECHCORE_COMMANDDATA_FPGA_WRITE_TLP 0x00000101 // R
#define LEECHCORE_COMMANDDATA_FPGA_LISTEN_TLP 0x00000102 // R
#define LEECHCORE_COMMANDDATA_STATISTICS_GET 0x80000100 // R
#define LEECHCORE_STATISTICS_MAGIC 0xffff6550
#define LEECHCORE_STATISTICS_VERSION 0x0001
#define LEECHCORE_STATISTICS_ID_OPEN 0x00
#define LEECHCORE_STATISTICS_ID_READSCATTER 0x01
#define LEECHCORE_STATISTICS_ID_WRITE 0x02
#define LEECHCORE_STATISTICS_ID_PROBE 0x03
#define LEECHCORE_STATISTICS_ID_GETOPTION 0x04
#define LEECHCORE_STATISTICS_ID_SETOPTION 0x05
#define LEECHCORE_STATISTICS_ID_COMMANDDATA 0x06
#define LEECHCORE_STATISTICS_ID_MAX 0x06
static const LPSTR LEECHCORE_STATISTICS_NAME[] = {
"LeechCore_Open",
"LeechCore_ReadScatter",
"LeechCore_Write",
"LeechCore_Probe",
"LeechCore_GetOption",
"LeechCore_SetOption",
"LeechCore_CommandData"
};
typedef struct tdLEECHCORE_STATISTICS {
DWORD magic;
WORD version;
WORD Reserved0;
DWORD Reserved1;
QWORD qwFreq;
struct {
QWORD c;
QWORD tm; // total time in qwFreq ticks
} Call[0x10];
} LEECHCORE_STATISTICS, *PLEECHCORE_STATISTICS;
/*
* Transfer device dependant commands/data to/from the underlying device and
* perform device dependant actions.
* -- fOption
* -- cbDataIn
* -- pbDataIn
* -- pbDataOut
* -- cbDataOut
* -- pcbDataOut
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_CommandData(
_In_ ULONG64 fOption,
_In_reads_(cbDataIn) PBYTE pbDataIn,
_In_ DWORD cbDataIn,
_Out_writes_(cbDataOut) PBYTE pbDataOut,
_In_ DWORD cbDataOut,
_Out_ PDWORD pcbDataOut
);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __LEECHCORE_H__ */
+36 -66
View File
@@ -1,14 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.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>
@@ -20,29 +12,17 @@
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{7B05E64E-569F-4EF5-8F37-FA5B39B64227}</ProjectGuid>
<ProjectGuid>{45CC506E-E97A-45B8-8050-B2C5BC8A4B15}</ProjectGuid>
<RootNamespace>vmmexample</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
@@ -50,18 +30,13 @@
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
@@ -77,6 +52,26 @@
<OutDir>$(SolutionDir)\files\</OutDir>
<IntDir>$(SolutionDir)\files\temp\$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<AdditionalDependencies>$(SolutionDir)\files\vmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ProgramDatabaseFile>$(OutDir)\lib\$(TargetName).pdb</ProgramDatabaseFile>
</Link>
<PostBuildEvent>
<Command>
</Command>
</PostBuildEvent>
<PreBuildEvent>
<Command>copy $(SolutionDir)\files\leechcore.h $(ProjectDir)\ /y
copy $(SolutionDir)\files\vmmdll.h $(ProjectDir)\ /y</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
@@ -89,50 +84,25 @@
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<ProgramDatabaseFile>$(OutDir)\lib\$(TargetName).pdb</ProgramDatabaseFile>
<AdditionalDependencies>$(SolutionDir)\files\vmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
<AdditionalDependencies>$(SolutionDir)\files\vmm.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<ProgramDatabaseFile>$(OutDir)\lib\$(TargetName).pdb</ProgramDatabaseFile>
<AdditionalDependencies>$(SolutionDir)\files\vmm.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
<PostBuildEvent>
<Command>
</Command>
</PostBuildEvent>
<PreBuildEvent>
<Command>copy $(SolutionDir)\files\leechcore.h $(ProjectDir)\ /y
copy $(SolutionDir)\files\vmmdll.h $(ProjectDir)\ /y</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="vmmdll_example.c" />
<ClInclude Include="leechcore.h" />
<ClInclude Include="vmmdll.h" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="vmmdll.h" />
<ClCompile Include="vmmdll_example.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
+9 -6
View File
@@ -14,17 +14,20 @@
<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="Header Files\vmm">
<UniqueIdentifier>{dd6bdb7f-228f-409d-9a7b-4bd9742210f4}</UniqueIdentifier>
<UniqueIdentifier>{2dda230c-a689-4065-8a56-84c4b1a989b8}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="vmmdll.h">
<Filter>Header Files\vmm</Filter>
</ClInclude>
<ClInclude Include="leechcore.h">
<Filter>Header Files\vmm</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="vmmdll_example.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="vmmdll.h">
<Filter>Header Files\vmm</Filter>
</ClInclude>
</ItemGroup>
</Project>
+6 -1
View File
@@ -1,4 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>
+44 -108
View File
@@ -1,11 +1,14 @@
// vmmdll.h : header file to include in projects that use vmm.dll either as
// stand anlone projects or as native plugins to vmm.dll.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
// Header Version: 2.0
//
#include <windows.h>
#include "leechcore.h"
#ifndef __VMMDLL_H__
#define __VMMDLL_H__
@@ -19,52 +22,23 @@ extern "C" {
//-----------------------------------------------------------------------------
/*
* RESERVED FUNCTION! DO NOT USE!
* Call other VMMDLL_Intialize functions to initialize VMM.DLL and the memory
* process file system.
* Initialize VMM.DLL with command line parameters. For a more detailed info
* about the parameters please see github wiki for Memory Process File System
* and LeechCore. THIS IS THE PREFERED WAY OF INITIALIZING VMM.DLL
* Important parameters are:
* -vdll = show printf style outputs)
* -v -vv -vvv = extra verbosity levels)
* -device = device as on format for LeechCore - please see leechcore.h or
* Github documentation for additional information. Some values
* are: <file>, fpga, usb3380, hvsavedstate, totalmeltdown, pmem
* -remote = remote LeechCore instance - please see leechcore.h or Github
* documentation for additional information.
* -- argc
* -- argv
* -- return = success/fail
*/
_Success_(return)
BOOL VMMDLL_InitializeReserved(_In_ DWORD argc, _In_ LPSTR argv[]);
/*
* Initialize VMM.DLL from a memory dump file in raw format. VMM.DLL will be
* initialized in read-only mode. It's possible to optionally specify the page
* table base of the windows kernel (for full vmm features) or the page table
* base of a single 64-bit process in any x64 operating system. NB! usually it
* is not necessary to specify the PageTableBase - it will be auto-identified
* most often if the target is Windows.
* -- szFileName = the file name of the raw memory dump to use.
* -- szPageTableBaseOpt = optionally the Page Table Base of kernel or process
* as hex string. NB! this is usally not required. Example: "0x1ab000".
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeFile(_In_ LPSTR szFileName, _In_opt_ LPSTR szPageTableBaseOpt);
/*
* Intiailize VMM.DLL from a supported FPGA device over USB. VMM.DLL will be
* initialized in read/write mode upon success. Optionally it will be possible
* to specify the max physical address and the page table base of the kernel or
* process that should be investigated.
* NB! Requires pcileech.dll to be placed in the same directory as vmm.dll.
* -- szMaxPhysicalAddressOpt = max physical address of the target system as a
* hex string. Example: "0x8000000000". If zero value is given the max
* address will be auto-identified.
* -- szPageTableBaseOpt = optionally the Page Table Base of kernel or process
* as hex string. NB! this is usally not required. Example: "0x1ab000".
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeFPGA(_In_opt_ LPSTR szMaxPhysicalAddressOpt, _In_opt_ LPSTR szPageTableBaseOpt);
/*
* Initialize VMM.DLL from a the "Total Meltdown" CVE-2018-1038 vulnerability.
* NB! Requires pcileech.dll to be placed in the same directory as vmm.dll.
* initialized in read/write mode upon success.
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeTotalMeltdown();
BOOL VMMDLL_Initialize(_In_ DWORD argc, _In_ LPSTR argv[]);
/*
* Close an initialized instance of VMM.DLL and clean up all allocated resources
@@ -84,43 +58,29 @@ BOOL VMMDLL_Close();
/*
* Options used together with the functions: VMMDLL_GetOption & VMMDLL_SetOption
* If VMM.DLL is chained with PCILEECH.DLL then required values will be passed
* along to PCILEECH.DLL when necessary.
* Options are defined with either: VMMDLL_OPT_* in this header file or as
* MEMDEVICE_OPT_* in memdevice.h
* For more detailed information check the sources for individual device types.
*/
#define VMMDLL_OPT_DEVICE_FPGA_PROBE_MAXPAGES 0x01 // RW
#define VMMDLL_OPT_DEVICE_FPGA_RX_FLUSH_LIMIT 0x02 // RW
#define VMMDLL_OPT_DEVICE_FPGA_MAX_SIZE_RX 0x03 // RW
#define VMMDLL_OPT_DEVICE_FPGA_MAX_SIZE_TX 0x04 // RW
#define VMMDLL_OPT_DEVICE_FPGA_DELAY_PROBE_READ 0x05 // RW - uS
#define VMMDLL_OPT_DEVICE_FPGA_DELAY_PROBE_WRITE 0x06 // RW - uS
#define VMMDLL_OPT_DEVICE_FPGA_DELAY_WRITE 0x07 // RW - uS
#define VMMDLL_OPT_DEVICE_FPGA_DELAY_READ 0x08 // RW - uS
#define VMMDLL_OPT_DEVICE_FPGA_RETRY_ON_ERROR 0x09 // RW
#define VMMDLL_OPT_DEVICE_FPGA_DEVICE_ID 0x80 // R
#define VMMDLL_OPT_DEVICE_FPGA_FPGA_ID 0x81 // R
#define VMMDLL_OPT_DEVICE_FPGA_VERSION_MAJOR 0x82 // R
#define VMMDLL_OPT_DEVICE_FPGA_VERSION_MINOR 0x83 // R
#define VMMDLL_OPT_CORE_PRINTF_ENABLE 0x80000001 // RW
#define VMMDLL_OPT_CORE_VERBOSE 0x80000002 // RW
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA 0x80000003 // RW
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA_TLP 0x80000004 // RW
#define VMMDLL_OPT_CORE_MAX_NATIVE_ADDRESS 0x80000005 // R
#define VMMDLL_OPT_CORE_MAX_NATIVE_IOSIZE 0x80000006 // R
#define VMMDLL_OPT_CORE_SYSTEM 0x80000007 // R
#define VMMDLL_OPT_CORE_MEMORYMODEL 0x80000008 // R
#define VMMDLL_OPT_CORE_PRINTF_ENABLE 0x80000001 // RW
#define VMMDLL_OPT_CORE_VERBOSE 0x80000002 // RW
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA 0x80000003 // RW
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA_TLP 0x80000004 // RW
#define VMMDLL_OPT_CORE_MAX_NATIVE_ADDRESS 0x80000005 // R
#define VMMDLL_OPT_CORE_MAX_NATIVE_IOSIZE 0x80000006 // R
#define VMMDLL_OPT_CORE_SYSTEM 0x80000007 // R
#define VMMDLL_OPT_CORE_MEMORYMODEL 0x80000008 // R
#define VMMDLL_OPT_CONFIG_IS_REFRESH_ENABLED 0x40000001 // R - 1/0
#define VMMDLL_OPT_CONFIG_TICK_PERIOD 0x40000002 // RW - base tick period in ms
#define VMMDLL_OPT_CONFIG_READCACHE_TICKS 0x40000003 // RW - memory cache validity period (in ticks)
#define VMMDLL_OPT_CONFIG_TLBCACHE_TICKS 0x40000004 // RW - page table (tlb) cache validity period (in ticks)
#define VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_PARTIAL 0x40000005 // RW - process refresh (partial) period (in ticks)
#define VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_TOTAL 0x40000006 // RW - process refresh (full) period (in ticks)
#define VMMDLL_OPT_CONFIG_VMM_VERSION_MAJOR 0x40000007 // R
#define VMMDLL_OPT_CONFIG_VMM_VERSION_MINOR 0x40000008 // R
#define VMMDLL_OPT_CONFIG_VMM_VERSION_REVISION 0x40000009 // R
#define VMMDLL_OPT_CONFIG_STATISTICS_FUNCTIONCALL 0x4000000A // RW - enable function call statistics (.status/statistics_fncall file)
#define VMMDLL_OPT_CONFIG_IS_REFRESH_ENABLED 0x40000001 // R - 1/0
#define VMMDLL_OPT_CONFIG_TICK_PERIOD 0x40000002 // RW - base tick period in ms
#define VMMDLL_OPT_CONFIG_READCACHE_TICKS 0x40000003 // RW - memory cache validity period (in ticks)
#define VMMDLL_OPT_CONFIG_TLBCACHE_TICKS 0x40000004 // RW - page table (tlb) cache validity period (in ticks)
#define VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_PARTIAL 0x40000005 // RW - process refresh (partial) period (in ticks)
#define VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_TOTAL 0x40000006 // RW - process refresh (full) period (in ticks)
#define VMMDLL_OPT_CONFIG_VMM_VERSION_MAJOR 0x40000007 // R
#define VMMDLL_OPT_CONFIG_VMM_VERSION_MINOR 0x40000008 // R
#define VMMDLL_OPT_CONFIG_VMM_VERSION_REVISION 0x40000009 // R
#define VMMDLL_OPT_CONFIG_STATISTICS_FUNCTIONCALL 0x4000000A // RW - enable function call statistics (.status/statistics_fncall file)
static const LPSTR VMMDLL_MEMORYMODEL_TOSTRING[4] = { "N/A", "X86", "X86PAE", "X64" };
@@ -256,9 +216,9 @@ _Success_(return)
BOOL VMMDLL_VfsInitializePlugins();
#define VMMDLL_PLUGIN_CONTEXT_MAGIC 0xc0ffee663df9301c
#define VMMDLL_PLUGIN_CONTEXT_VERSION 1
#define VMMDLL_PLUGIN_CONTEXT_VERSION 2
#define VMMDLL_PLUGIN_REGINFO_MAGIC 0xc0ffee663df9301d
#define VMMDLL_PLUGIN_REGINFO_VERSION 2
#define VMMDLL_PLUGIN_REGINFO_VERSION 3
#define VMMDLL_PLUGIN_EVENT_VERBOSITYCHANGE 0x01
@@ -267,8 +227,6 @@ typedef struct tdVMMDLL_PLUGIN_CONTEXT {
WORD wVersion;
WORD wSize;
DWORD dwPID;
PHANDLE phModulePrivate;
PHANDLE phProcessPrivate;
PVOID pProcess;
LPSTR szModule;
LPSTR szPath;
@@ -289,7 +247,6 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
PVOID pvReserved2;
// general plugin registration info to be filled out by the plugin below:
struct {
HANDLE hModulePrivate;
CHAR szModuleName[32];
BOOL fRootModule;
BOOL fProcessModule;
@@ -301,9 +258,8 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
BOOL(*pfnList)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList);
NTSTATUS(*pfnRead)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset);
NTSTATUS(*pfnWrite)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset);
VOID(*pfnNotify)(_Inout_opt_ PHANDLE phModulePrivate, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent);
VOID(*pfnCloseHandleModule)(_Inout_opt_ PHANDLE phModulePrivate);
VOID(*pfnCloseHandleProcess)(_Inout_opt_ PHANDLE phModulePrivate, _Inout_ PHANDLE phProcessPrivate);
VOID(*pfnNotify)(_In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent);
VOID(*pfnClose)();
PVOID pvReserved1;
PVOID pvReserved2;
} reg_fn;
@@ -323,26 +279,6 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
#define VMMDLL_FLAG_NOCACHE 0x0001 // do not use the data cache (force reading from memory acquisition device)
#define VMMDLL_FLAG_ZEROPAD_ON_FAIL 0x0002 // zero pad failed physical memory reads and report success if read within range of physical memory.
#define VMMDLL_MEM_IO_SCATTER_HEADER_VERSION 2
typedef struct tdVMMDLL_MEM_IO_SCATTER_HEADER {
ULONG64 qwA; // base address (DWORD boundry).
DWORD cbMax; // bytes to read (DWORD boundry, max 0x1000); pbResult must have room for this.
DWORD cb; // bytes read into result buffer.
PBYTE pb; // ptr to 0x1000 sized buffer to receive read bytes.
PVOID pvReserved1; // reserved for use by caller.
PVOID pvReserved2; // reserved for use by caller.
WORD version; // version of struct
WORD Future1; // reserved for future use.
DWORD Future2; // reserved for future use.
ULONG64 qwDeviceA; // device-physical address (used by device layer).
struct {
PVOID pvReserved1;
PVOID pvReserved2;
BYTE pbReserved[32];
} sReserved; // reserved for future use.
} VMMDLL_MEM_IO_SCATTER_HEADER, *PVMMDLL_MEM_IO_SCATTER_HEADER, **PPVMMDLL_MEM_IO_SCATTER_HEADER;
/*
* Read memory in various non-contigious locations specified by the pointers to
* the items in the ppDMAs array. Result for each unit of work will be given
@@ -356,7 +292,7 @@ typedef struct tdVMMDLL_MEM_IO_SCATTER_HEADER {
* -- flags = optional flags as given by VMM_FLAG_*
* -- return = the number of successfully read items.
*/
DWORD VMMDLL_MemReadScatter(_In_ DWORD dwPID, _Inout_ PPVMMDLL_MEM_IO_SCATTER_HEADER ppMEMs, _In_ DWORD cpMEMs, _In_ DWORD flags);
DWORD VMMDLL_MemReadScatter(_In_ DWORD dwPID, _Inout_ PPMEM_IO_SCATTER_HEADER ppMEMs, _In_ DWORD cpMEMs, _In_ DWORD flags);
/*
* Read a single 4096-byte page of memory.
+22 -22
View File
@@ -18,7 +18,7 @@
// Ensure only one is active below at one single time!
// INITIALIZE_FROM_FILE contains file name to a raw memory dump.
// ----------------------------------------------------------------------------
#define _INITIALIZE_FROM_FILE "z:\\media\\vm\\memdump\\WIN10-17134-48-1.raw"
#define _INITIALIZE_FROM_FILE "c:\\temp\\win10.raw"
//#define _INITIALIZE_FROM_FPGA
//#define _INITIALIZE_FROM_TOTALMELTDOWN
@@ -72,7 +72,7 @@ int main(_In_ int argc, _In_ char* argv[])
printf("#01: Initialize from file: \n");
ShowKeyPress();
printf("CALL: VMMDLL_InitializeFile\n");
result = VMMDLL_InitializeFile(_INITIALIZE_FROM_FILE, NULL);
result = VMMDLL_Initialize(3, (LPSTR[]){ "", "-device", _INITIALIZE_FROM_FILE });
if(result) {
printf("SUCCESS: VMMDLL_InitializeFile\n");
} else {
@@ -299,17 +299,17 @@ int main(_In_ int argc, _In_ char* argv[])
}
// Retrieve the module of crypt32.dll by its name. Note it is also possible
// Retrieve the module of kernel32.dll by its name. Note it is also possible
// to retrieve it by retrieving the complete module map (list) and iterate
// over it. But if the name of the module is known this is more convenient.
// This required that the PEB and LDR list in-process haven't been tampered
// with ...
printf("------------------------------------------------------------\n");
printf("#07: Get by name 'crypt32.dll' in 'explorer.exe'. \n");
printf("#07: Get by name 'kernel32.dll' in 'explorer.exe'. \n");
ShowKeyPress();
VMMDLL_MODULEMAP_ENTRY ModuleEntry;
printf("CALL: VMMDLL_ProcessGetModuleFromName\n");
result = VMMDLL_ProcessGetModuleFromName(dwPID, "crypt32.dll", &ModuleEntry);
result = VMMDLL_ProcessGetModuleFromName(dwPID, "kernel32.dll", &ModuleEntry);
if(result) {
printf("SUCCESS: VMMDLL_ProcessGetModuleFromName\n");
printf(" MODULE_NAME BASE SIZE ENTRY\n");
@@ -328,12 +328,12 @@ int main(_In_ int argc, _In_ char* argv[])
}
// Retrieve the memory at the base of crypt32.dll previously fetched and
// Retrieve the memory at the base of kernel32.dll previously fetched and
// display the first 0x200 bytes of it. This read is fetched from the cache
// by default (if possible). If reads should be forced from the DMA device
// please specify the flag: VMM_FLAG_NOCACHE
printf("------------------------------------------------------------\n");
printf("#08: Read 0x200 bytes of 'crypt32.dll' in 'explorer.exe'. \n");
printf("#08: Read 0x200 bytes of 'kernel32.dll' in 'explorer.exe'. \n");
ShowKeyPress();
DWORD cRead;
printf("CALL: VMMDLL_MemReadEx\n");
@@ -348,14 +348,14 @@ int main(_In_ int argc, _In_ char* argv[])
}
// List the sections from the module of crypt32.dll.
// List the sections from the module of kernel32.dll.
printf("------------------------------------------------------------\n");
printf("#09: List sections of 'crypt32.dll' in 'explorer.exe'. \n");
printf("#09: List sections of 'kernel32.dll' in 'explorer.exe'. \n");
ShowKeyPress();
DWORD cSections;
PIMAGE_SECTION_HEADER pSectionHeaders;
printf("CALL: VMMDLL_ProcessGetSections #1\n");
result = VMMDLL_ProcessGetSections(dwPID, "crypt32.dll", NULL, 0, &cSections);
result = VMMDLL_ProcessGetSections(dwPID, "kernel32.dll", NULL, 0, &cSections);
if(result) {
printf("SUCCESS: VMMDLL_ProcessGetSections #1\n");
printf(" Count = %lli\n", cModules);
@@ -369,7 +369,7 @@ int main(_In_ int argc, _In_ char* argv[])
return 1;
}
printf("CALL: VMMDLL_ProcessGetSections #2\n");
result = VMMDLL_ProcessGetSections(dwPID, "crypt32.dll", pSectionHeaders, cSections, &cSections);
result = VMMDLL_ProcessGetSections(dwPID, "kernel32.dll", pSectionHeaders, cSections, &cSections);
if(result) {
printf("SUCCESS: VMMDLL_ProcessGetSections #2\n");
printf(" # NAME OFFSET SIZE RWX\n");
@@ -392,17 +392,17 @@ int main(_In_ int argc, _In_ char* argv[])
}
// Retrieve and display the data directories of crypt32.dll. The number of
// Retrieve and display the data directories of kernel32.dll. The number of
// data directories in a PE is always 16 - so this can be used to simplify
// calling the functionality somewhat.
printf("------------------------------------------------------------\n");
printf("#10: List directories of 'crypt32.dll' in 'explorer.exe'. \n");
printf("#10: List directories of 'kernel32.dll' in 'explorer.exe'. \n");
ShowKeyPress();
LPCSTR DIRECTORIES[16] = { "EXPORT", "IMPORT", "RESOURCE", "EXCEPTION", "SECURITY", "BASERELOC", "DEBUG", "ARCHITECTURE", "GLOBALPTR", "TLS", "LOAD_CONFIG", "BOUND_IMPORT", "IAT", "DELAY_IMPORT", "COM_DESCRIPTOR", "RESERVED" };
DWORD cDirectories;
IMAGE_DATA_DIRECTORY pDirectories[16];
printf("CALL: VMMDLL_ProcessGetDirectories\n");
result = VMMDLL_ProcessGetDirectories(dwPID, "crypt32.dll", pDirectories, 16, &cDirectories);
result = VMMDLL_ProcessGetDirectories(dwPID, "kernel32.dll", pDirectories, 16, &cDirectories);
if(result) {
printf("SUCCESS: PCIleech_VmmProcess_GetDirectories\n");
printf(" # NAME OFFSET SIZE\n");
@@ -422,14 +422,14 @@ int main(_In_ int argc, _In_ char* argv[])
}
// Retrieve the export address table (EAT) of crypt32.dll
// Retrieve the export address table (EAT) of kernel32.dll
printf("------------------------------------------------------------\n");
printf("#11: exports of 'crypt32.dll' in 'explorer.exe'. \n");
printf("#11: exports of 'kernel32.dll' in 'explorer.exe'. \n");
ShowKeyPress();
DWORD cEATs;
PVMMDLL_EAT_ENTRY pEATs;
printf("CALL: VMMDLL_ProcessGetEAT #1\n");
result = VMMDLL_ProcessGetEAT(dwPID, "crypt32.dll", NULL, 0, &cEATs);
result = VMMDLL_ProcessGetEAT(dwPID, "kernel32.dll", NULL, 0, &cEATs);
if(result) {
printf("SUCCESS: VMMDLL_ProcessGetEAT #1\n");
printf(" Count = %i\n", cEATs);
@@ -443,7 +443,7 @@ int main(_In_ int argc, _In_ char* argv[])
return 1;
}
printf("CALL: VMMDLL_ProcessGetEAT #2\n");
result = VMMDLL_ProcessGetEAT(dwPID, "crypt32.dll", pEATs, cEATs, &cEATs);
result = VMMDLL_ProcessGetEAT(dwPID, "kernel32.dll", pEATs, cEATs, &cEATs);
if(result) {
printf("SUCCESS: VMMDLL_ProcessGetEAT #2\n");
printf(" # OFFSET NAME\n");
@@ -462,14 +462,14 @@ int main(_In_ int argc, _In_ char* argv[])
}
// Retrieve the import address table (IAT) of crypt32.dll
// Retrieve the import address table (IAT) of kernel32.dll
printf("------------------------------------------------------------\n");
printf("#12: imports of 'crypt32.dll' in 'explorer.exe'. \n");
printf("#12: imports of 'kernel32.dll' in 'explorer.exe'. \n");
ShowKeyPress();
DWORD cIATs;
PVMMDLL_IAT_ENTRY pIATs;
printf("CALL: VMMDLL_ProcessGetIAT #1\n");
result = VMMDLL_ProcessGetIAT(dwPID, "crypt32.dll", NULL, 0, &cIATs);
result = VMMDLL_ProcessGetIAT(dwPID, "kernel32.dll", NULL, 0, &cIATs);
if(result) {
printf("SUCCESS: VMMDLL_ProcessGetIAT #1\n");
printf(" Count = %i\n", cIATs);
@@ -483,7 +483,7 @@ int main(_In_ int argc, _In_ char* argv[])
return 1;
}
printf("CALL: VMMDLL_ProcessGetIAT #2\n");
result = VMMDLL_ProcessGetIAT(dwPID, "crypt32.dll", pIATs, cIATs, &cIATs);
result = VMMDLL_ProcessGetIAT(dwPID, "kernel32.dll", pIATs, cIATs, &cIATs);
if(result) {
printf("SUCCESS: VMMDLL_ProcessGetIAT #2\n");
printf(" # VIRTUAL_ADDRESS MODULE!NAME\n");
+466
View File
@@ -0,0 +1,466 @@
// leechcore.h : header file for the leechcore module - which purpose is to
// expose low-level device physical memory functionality.
//
// This library is thread-safe in all functions with the notable exceptions of
// the LeechCore_Open() and LeechCore_Close() functions. Some devices may allow
// multi-threaded access while in reality most devices are single-threaded and
// will control synchronization where necessary with locks.
//
// The library is initialized by calling LeechCore_Open with a LEECHCORE_CONFIG
// struct containing the correct configuration paramters. Note that the version
// and magic values must be set in addition to the szDevice configuration value
// Also, it may be possible to optionally connect to a remote leechcore service
// or instance over RPC by specifying a szRemote configuration value.
//
// ----------------------------------------------------------------------------
//
// Remote instance: szRemote configuration value. Connect to a remote leechcore
// instance by specifying a configuration value in the szRemote parameter. If a
// loaded already valid instance exists remotely this will be prioritized above
// the value in szDevice. If the acquisition device is not yet loaded by the
// remote instance the value in szDevice will be used. Normally, the connection
// will take place as a mutually authenticated encrypted connection secured by
// kerberos. If not possible or desirable the 'insecure' value may be specified
// to disable authentication and security.
// Syntax:
// rpc://<remote_spn>:<host>:<port> (port = optional, remote_spn = kerberos)
// (SPN of remote service or 'insecure' )
// Examples:
// rpc://insecure:remotehost.example.com (connect insecure to remote host )
// rpc://[email protected]:192.0.0.5 (connect secure to remote host )
// rpc://insecure:127.0.0.0:6666 (connect insecure non-default port)
//
// ----------------------------------------------------------------------------
//
// Device to connect to: szDevice contains the device to capture memory from.
// Supported memory acquisition devices are:
// USB3380 : hardware, read/write, 32-bit (4GB) addressing only. Requires a
// PCILeech flashed USB3380 device connected over USB and Google
// Android WinUSB drivers to be installed. Download and install from:
// http://developer.android.com/sdk/win-usb.html#download
// Syntax:
// USB3380
// USB3380://USB2 (force USB2 connection speed)
//
// FPGA : hardware, read/write - requires a PCILeech FPGA flashed hardware
// device as shown at: https://github.com/ufrisk/pcileech-fpga
// Also requires the FTD3XX.DLL from ftdichip to be placed in the
// same directory as the executable. Download from ftdichip at:
// http://www.ftdichip.com/Drivers/D3XX/FTD3XXLibrary_v1.2.0.6.zip
// Syntax:
// FGPA
// FPGA://<read_uS>[:<write_uS>[:<probe_uS>]] (values are optional)
//
// SP605TCP : hardware, read/write - connect to a remote SP605 FPGA over the
// network using the implementation created by @d_olex.
// https://github.com/Cr4sh/s6_pcie_microblaze
// Syntax:
// SP605TCP://<target_ip>[:<target_port>] (port is optional)
//
// RAWTCP : read/write - connect to a remote raw tcp device - such as HPE iLO
// that have been patched to support DMA as per blog entry below:
// https://www.synacktiv.com/posts/exploit/using-your-bmc-as-a-dma-device-plugging-pcileech-to-hpe-ilo-4.html
// Syntax:
// RAWTCP://<target_ip>[:<target_port>] (port is optional)
//
// HvSavedState : read-only - connect to a Hyper-V saved state file. In order
// to do so the .dll file 'vmsavedstatedumpprovider.dll' must be
// placed in same directory as the executable file.
//
// PMEM : load the rekall winpmem driver into the kernel and connect to it
// to acquire memory. The driver file 'winpmem_x64.sys' is found in
// the Rekall directory after most recent version has been installed.
// Copy 'winpmem_x64.sys' to the directory of leechcore.dll and run
// executable as elevated admin using syntax below:
// Syntax:
// PMEM (use winpmem_x64.sys in directory of executable)
// PMEM://<non_default_path_to_file_winpmem_x64.sys>
//
// TOTALMELTDOWN : read/write - requires a Windows 7 system vulnerable to the
// "Total Meltdown" vulnerability - CVE-2018-1038.
// Syntax:
// TOTALMELTDOWN
//
// FILE : use dump file, either a raw linear memory dump or full crash dump.
// Which format to use is auto-detected. If it looks like a full cash
// dump that format will be used, otherwise it will be assumed that a
// raw linear memory dump is to be used.
// Syntax:
// <filename> (no device-type prefix - just use the file name)
// FILE://<filename>
//
// DumpIt : DumpIt is a "virtual" device. It's only possible to use the DumpIt
// device if the main process containing LeechCore has been started
// with DumpIt in LiveKD mode.
// Example 1:
// DumpIt.exe /LIVEKD /A MemProcFS.exe
// Example 2:
// DumpIt.exe /LIVEKD /A LeechSvc.exe /C "interactive insecure"
// and then connect to remote service by:
// MemProcFS.exe -remote rpc://insecure:192.168.x.x -device DumpIt
//
// EXISTING : Attach to existing already loaded configuration. This is done
// instead of the default behaviour of closing any existing devices
// and initializing the new requested device. If no existing device
// exists the call to LeechCore_Open will fail.
// Syntax:
// EXISTING
//
//
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
// Header Version: 1.0
//
#ifndef __LEECHCORE_H__
#define __LEECHCORE_H__
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
//-----------------------------------------------------------------------------
// WINDOWS / LINUX COMPATIBILITY BELOW:
//-----------------------------------------------------------------------------
#ifdef _WIN32
#include <Windows.h>
typedef unsigned __int64 QWORD, *PQWORD;
#define DLLEXPORT __declspec(dllexport)
#endif /* _WIN32 */
#ifdef LINUX
#include <stdint.h>
#include <stddef.h>
typedef void VOID, *PVOID, *LPVOID;
typedef void *HANDLE, **PHANDLE;
typedef uint32_t BOOL, *PBOOL;
typedef uint8_t BYTE, *PBYTE;
typedef char CHAR, *PCHAR, *PSTR, *LPSTR;
typedef uint16_t WORD, *PWORD, USHORT, *PUSHORT;
typedef uint32_t DWORD, *PDWORD;
typedef long long unsigned int QWORD, *PQWORD, ULONG64, *PULONG64;
#define MAX_PATH 260
#define DLLEXPORT __attribute__((visibility("default")))
#define _In_
#define _Out_
#define _In_z_
#define _Inout_
#define _In_opt_
#define _Out_opt_
#define _Out_writes_(x)
#define _Check_return_opt_
#define _Printf_format_string_
#define _Inout_updates_bytes_(x)
#define _In_reads_(cbDataIn)
#define _Success_(return)
#endif /* LINUX */
//-----------------------------------------------------------------------------
// GENERAL HEADER DEFINES BELOW:
//-----------------------------------------------------------------------------
#define MEM_IO_SCATTER_HEADER_MAGIC 0xffff6548
#define MEM_IO_SCATTER_HEADER_VERSION 0x0003
typedef struct tdMEM_IO_SCATTER_HEADER {
DWORD magic; // magic
WORD version; // version
WORD Future1;
ULONG64 qwA; // base address.
DWORD cbMax; // bytes to read (DWORD boundry, max 0x1000); pb must have room for this.
DWORD cb; // bytes read into result buffer.
PBYTE pb; // ptr to 0x1000 sized buffer to receive read bytes.
PVOID pvReserved1; // reserved for use by caller.
PVOID pvReserved2; // reserved for use by caller.
PVOID Future2[8];
} MEM_IO_SCATTER_HEADER, *PMEM_IO_SCATTER_HEADER, **PPMEM_IO_SCATTER_HEADER;
//-----------------------------------------------------------------------------
// LEECHCORE INITIALIZATION / CLOSE FUNCTIONALITY BELOW:
//-----------------------------------------------------------------------------
typedef enum tdLEECHCORE_DEVICE {
LEECHCORE_DEVICE_NA = 0,
LEECHCORE_DEVICE_FILE = 1,
LEECHCORE_DEVICE_PMEM = 2,
LEECHCORE_DEVICE_FPGA = 3,
LEECHCORE_DEVICE_SP605_TCP = 4,
LEECHCORE_DEVICE_USB3380 = 5,
LEECHCORE_DEVICE_TOTALMELTDOWN = 6,
LEECHCORE_DEVICE_HVSAVEDSTATE = 7,
LEECHCORE_DEVICE_RAWTCP = 8,
} LEECHCORE_DEVICE;
#define LEECHCORE_CONFIG_MAGIC 0xffff6549
#define LEECHCORE_CONFIG_VERSION 0x0001
#define LEECHCORE_CONFIG_FLAG_PRINTF 0x0001
#define LEECHCORE_CONFIG_FLAG_PRINTF_VERBOSE_1 0x0002
#define LEECHCORE_CONFIG_FLAG_PRINTF_VERBOSE_2 0x0004
#define LEECHCORE_CONFIG_FLAG_PRINTF_VERBOSE_3 0x0008
#define LEECHCORE_CONFIG_FLAG_REMOTE_NO_COMPRESS 0x0010
typedef struct tdLEECHCORE_CONFIG {
DWORD magic; // set by caller.
WORD version; // set by caller.
WORD flags; // set by caller, updated by device.
ULONG64 paMax; // set by caller, updated by device.
ULONG64 cbMaxSizeMemIo; // set by caller, updated by device.
ULONG64 paMaxNative; // set by device.
LEECHCORE_DEVICE tpDevice; // set by device.
BOOL fWritable; // set by device. (is device writable?)
BOOL fVolatile; // set by device. (is device volatile / memory may change?)
BOOL fVolatileMaxAddress; // set by device. (is max address volatile? - poll changes with LEECHCORE_OPT_MEMORYINFO_ADDR_MAX)
BOOL fRemote; // set by device.
WORD VersionMajor; // set by device.
WORD VersionMinor; // set by device.
WORD VersionRevision; // set by device.
CHAR szDevice[MAX_PATH]; // set by caller.
CHAR szRemote[MAX_PATH]; // set by caller.
// optional 'printf' function pointer. if set to non null value 'printf'
// calls will be redirected. useful when logging to files.
_Check_return_opt_ int(*pfn_printf_opt)(_In_z_ _Printf_format_string_ char const* const _Format, ...); // set by caller.
} LEECHCORE_CONFIG, *PLEECHCORE_CONFIG;
typedef struct tdLEECHCORE_PAGESTAT_MINIMAL {
HANDLE h;
VOID(*pfnPageStatUpdate)(HANDLE h, ULONG64 pa, ULONG64 cPageSuccessAdd, ULONG64 cPageFailAdd);
} LEECHCORE_PAGESTAT_MINIMAL, *PLEECHCORE_PAGESTAT_MINIMAL;
/*
* Open a connection to the target device.
* -- pInformation
* -- result
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_Open(_Inout_ PLEECHCORE_CONFIG pConfig);
/*
* Clean up various device related stuff and deallocate memory buffers.
*/
DLLEXPORT VOID LeechCore_Close();
//-----------------------------------------------------------------------------
// LEECHCORE CORE READ AND WRITE FUNCTIONALITY BELOW:
//-----------------------------------------------------------------------------
#define LEECHCORE_FLAG_READ_RETRY 0x01
#define LEECHCORE_FLAG_WRITE_RETRY 0x01
#define LEECHCORE_FLAG_WRITE_VERIFY 0x02
/*
* Allocate a scatter buffer containing empty 0x1000-sized ppMEMs with address
* set to zero. Caller is responsible for calling LocalFree(ppMEMs).
* -- cMEMs
* -- pppMEMs = pointer to receive ppMEMs on success.
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_AllocScatterEmpty(_In_ DWORD cMEMs, _Out_ PPMEM_IO_SCATTER_HEADER *pppMEMs);
/*
* Read memory in various non-contigious locations specified by the items in the
* phDMAs array. Result for each unit of work will be given individually. No upper
* limit of number of items to read, but no performance boost will be given if
* above hardware limit. Max size of each unit of work is one 4k page (4096 bytes).
* -- ppMEMs = array of scatter read headers.
* -- cpMEMs = count of ppDMAs.
*/
DLLEXPORT VOID LeechCore_ReadScatter(_Inout_ PPMEM_IO_SCATTER_HEADER ppMEMs, _In_ DWORD cpMEMs);
/*
* Try read memory in a fairly optimal way considering device limits. The number
* of total successfully read bytes is returned. Failed reads will be zeroed out
* in the returned memory.
* -- pa
* -- pb
* -- cb
* -- return = the number of bytes successfully read.
*/
DLLEXPORT DWORD LeechCore_Read(_In_ ULONG64 pa, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb);
/*
* Try read memory in a fairly optimal way considering device limits. The number
* of total successfully read bytes is returned. Failed reads will be zeroed out
* in the returned memory.
* -- pa
* -- pb
* -- cb
* -- flags = 0 or LEECHCORE_FLAG_READ_RETRY
* -- pPageStat = optional minimal statistic struct to update.
* -- return = the number of bytes successfully read.
*/
DLLEXPORT DWORD LeechCore_ReadEx(_In_ ULONG64 pa, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _In_ DWORD flags, _In_opt_ PLEECHCORE_PAGESTAT_MINIMAL pPageStat);
/*
* Write data to the target system if supported by the device.
* -- pa
* -- pb
* -- cb
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_Write(_In_ ULONG64 pa, _In_ PBYTE pb, _In_ DWORD cb);
/*
* Write data to the target system if supported by the device.
* -- pa
* -- pb
* -- cb
* -- flags = 0 or LEECHCORE_FLAG_WRITE_*
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_WriteEx(_In_ ULONG64 pa, _In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD flags);
/*
* Probe the memory of the target system to check whether it's readable or not.
* Please note that not all devices support this natively.
* -- pa = address to start probe from.
* -- cPages = number of 4kB pages to probe.
* -- pbResultMap = result map, 1 byte represents 1 page, 0 = fail, 1 = success.
* (individual page elements in pbResultMap must be set to 0 [fail] on call
* for probe to take place on individual page).
* -- return = FALSE if not supported by underlying hardware, TRUE if supported.
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_Probe(_In_ QWORD pa, _In_ DWORD cPages, _Inout_updates_bytes_(cPages) PBYTE pbResultMap);
//-----------------------------------------------------------------------------
// GET/SET DEVICE OPTIONS BELOW. SOME OPTIONS ARE GENERAL LEECHCORE OPTIONS
// WHILE OTHER ARE DEVICE SPECIFIC. USE FUNCTIONS:
// LeechCore_GetOption() AND LeechCore_GetOption() TO GET/SET OPTIONS.
// FOR DEVICE-SPECIFIC OPTIONS PLEASE SEE INDIVIDUAL DEVICE FILES FOR MORE
// DETAILED INFORMATION.
//-----------------------------------------------------------------------------
#define LEECHCORE_OPT_CORE_PRINTF_ENABLE 0x80000001 // RW
#define LEECHCORE_OPT_CORE_VERBOSE 0x80000002 // RW
#define LEECHCORE_OPT_CORE_VERBOSE_EXTRA 0x80000003 // RW
#define LEECHCORE_OPT_CORE_VERBOSE_EXTRA_TLP 0x80000004 // RW
#define LEECHCORE_OPT_CORE_VERSION_MAJOR 0x01000001 // R
#define LEECHCORE_OPT_CORE_VERSION_MINOR 0x01000002 // R
#define LEECHCORE_OPT_CORE_VERSION_REVISION 0x01000003 // R
#define LEECHCORE_OPT_MEMORYINFO_VALID 0x02000001 // R
#define LEECHCORE_OPT_MEMORYINFO_ADDR_MAX 0x02000002 // R
#define LEECHCORE_OPT_MEMORYINFO_FLAG_32BIT 0x02000003 // R
#define LEECHCORE_OPT_MEMORYINFO_FLAG_PAE 0x02000004 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_VERSION_MINOR 0x02000005 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_VERSION_MAJOR 0x02000006 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_DTB 0x02000007 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_PFN 0x02000008 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_PsLoadedModuleList 0x02000009 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_PsActiveProcessHead 0x0200000a // R
#define LEECHCORE_OPT_MEMORYINFO_OS_MACHINE_IMAGE_TP 0x0200000b // R
#define LEECHCORE_OPT_MEMORYINFO_OS_NUM_PROCESSORS 0x0200000c // R
#define LEECHCORE_OPT_MEMORYINFO_OS_SYSTEMTIME 0x0200000d // R
#define LEECHCORE_OPT_MEMORYINFO_OS_UPTIME 0x0200000e // R
#define LEECHCORE_OPT_MEMORYINFO_OS_KERNELBASE 0x0200000f // R
#define LEECHCORE_OPT_MEMORYINFO_OS_KERNELHINT 0x02000010 // R
#define LEECHCORE_OPT_FPGA_PROBE_MAXPAGES 0x03000001 // RW
#define LEECHCORE_OPT_FPGA_RX_FLUSH_LIMIT 0x03000002 // RW
#define LEECHCORE_OPT_FPGA_MAX_SIZE_RX 0x03000003 // RW
#define LEECHCORE_OPT_FPGA_MAX_SIZE_TX 0x03000004 // RW
#define LEECHCORE_OPT_FPGA_DELAY_PROBE_READ 0x03000005 // RW - uS
#define LEECHCORE_OPT_FPGA_DELAY_PROBE_WRITE 0x03000006 // RW - uS
#define LEECHCORE_OPT_FPGA_DELAY_WRITE 0x03000007 // RW - uS
#define LEECHCORE_OPT_FPGA_DELAY_READ 0x03000008 // RW - uS
#define LEECHCORE_OPT_FPGA_RETRY_ON_ERROR 0x03000009 // RW
#define LEECHCORE_OPT_FPGA_DEVICE_ID 0x03000080 // R
#define LEECHCORE_OPT_FPGA_FPGA_ID 0x03000081 // R
#define LEECHCORE_OPT_FPGA_VERSION_MAJOR 0x03000082 // R
#define LEECHCORE_OPT_FPGA_VERSION_MINOR 0x03000083 // R
/*
* Set a device specific option value.
* -- fOption
* -- pqwValue = pointer to QWORD to receive option value.
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_GetOption(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue);
/*
* Set a device specific option value.
* -- fOption
* -- qwValue
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_SetOption(_In_ ULONG64 fOption, _In_ ULONG64 qwValue);
//-----------------------------------------------------------------------------
// TRANSFER DEVICE DEPENDANT COMMANDS OR DATA TO/FROM UNDERLYING DEVICES AND
// PERFORM ACTIONS USING THE LeechCore_CommandData() FUNCTION.
//-----------------------------------------------------------------------------
#define LEECHCORE_COMMANDDATA_FPGA_WRITE_TLP 0x00000101 // R
#define LEECHCORE_COMMANDDATA_FPGA_LISTEN_TLP 0x00000102 // R
#define LEECHCORE_COMMANDDATA_STATISTICS_GET 0x80000100 // R
#define LEECHCORE_STATISTICS_MAGIC 0xffff6550
#define LEECHCORE_STATISTICS_VERSION 0x0001
#define LEECHCORE_STATISTICS_ID_OPEN 0x00
#define LEECHCORE_STATISTICS_ID_READSCATTER 0x01
#define LEECHCORE_STATISTICS_ID_WRITE 0x02
#define LEECHCORE_STATISTICS_ID_PROBE 0x03
#define LEECHCORE_STATISTICS_ID_GETOPTION 0x04
#define LEECHCORE_STATISTICS_ID_SETOPTION 0x05
#define LEECHCORE_STATISTICS_ID_COMMANDDATA 0x06
#define LEECHCORE_STATISTICS_ID_MAX 0x06
static const LPSTR LEECHCORE_STATISTICS_NAME[] = {
"LeechCore_Open",
"LeechCore_ReadScatter",
"LeechCore_Write",
"LeechCore_Probe",
"LeechCore_GetOption",
"LeechCore_SetOption",
"LeechCore_CommandData"
};
typedef struct tdLEECHCORE_STATISTICS {
DWORD magic;
WORD version;
WORD Reserved0;
DWORD Reserved1;
QWORD qwFreq;
struct {
QWORD c;
QWORD tm; // total time in qwFreq ticks
} Call[0x10];
} LEECHCORE_STATISTICS, *PLEECHCORE_STATISTICS;
/*
* Transfer device dependant commands/data to/from the underlying device and
* perform device dependant actions.
* -- fOption
* -- cbDataIn
* -- pbDataIn
* -- pbDataOut
* -- cbDataOut
* -- pcbDataOut
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_CommandData(
_In_ ULONG64 fOption,
_In_reads_(cbDataIn) PBYTE pbDataIn,
_In_ DWORD cbDataIn,
_Out_writes_(cbDataOut) PBYTE pbDataOut,
_In_ DWORD cbDataOut,
_Out_ PDWORD pcbDataOut
);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __LEECHCORE_H__ */
+22
View File
@@ -0,0 +1,22 @@
#define STRINGIZE2(s) #s
#define STRINGIZE(s) STRINGIZE2(s)
#define VERSION_MAJOR 2
#define VERSION_MINOR 0
#define VERSION_REVISION 0
#define VERSION_BUILD 0
#define VER_FILE_DESCRIPTION_STR "The Memory Process File System : Python API"
#define VER_FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_BUILD
#define VER_FILE_VERSION_STR STRINGIZE(VERSION_MAJOR) \
"." STRINGIZE(VERSION_MINOR) \
"." STRINGIZE(VERSION_REVISION) \
"." STRINGIZE(VERSION_BUILD) \
#define VER_COMPANY_NAME_STR ""
#define VER_PRODUCTNAME_STR "vmmpyc"
#define VER_PRODUCT_VERSION VER_FILE_VERSION
#define VER_PRODUCT_VERSION_STR VER_FILE_VERSION_STR
#define VER_ORIGINAL_FILENAME_STR VER_PRODUCTNAME_STR ".dll"
#define VER_INTERNAL_NAME_STR VER_ORIGINAL_FILENAME_STR
#define VER_COPYRIGHT_STR "Copyright (c) Ulf Frisk 2018-2019"
+44 -108
View File
@@ -1,11 +1,14 @@
// vmmdll.h : header file to include in projects that use vmm.dll either as
// stand anlone projects or as native plugins to vmm.dll.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
// Header Version: 2.0
//
#include <windows.h>
#include "leechcore.h"
#ifndef __VMMDLL_H__
#define __VMMDLL_H__
@@ -19,52 +22,23 @@ extern "C" {
//-----------------------------------------------------------------------------
/*
* RESERVED FUNCTION! DO NOT USE!
* Call other VMMDLL_Intialize functions to initialize VMM.DLL and the memory
* process file system.
* Initialize VMM.DLL with command line parameters. For a more detailed info
* about the parameters please see github wiki for Memory Process File System
* and LeechCore. THIS IS THE PREFERED WAY OF INITIALIZING VMM.DLL
* Important parameters are:
* -vdll = show printf style outputs)
* -v -vv -vvv = extra verbosity levels)
* -device = device as on format for LeechCore - please see leechcore.h or
* Github documentation for additional information. Some values
* are: <file>, fpga, usb3380, hvsavedstate, totalmeltdown, pmem
* -remote = remote LeechCore instance - please see leechcore.h or Github
* documentation for additional information.
* -- argc
* -- argv
* -- return = success/fail
*/
_Success_(return)
BOOL VMMDLL_InitializeReserved(_In_ DWORD argc, _In_ LPSTR argv[]);
/*
* Initialize VMM.DLL from a memory dump file in raw format. VMM.DLL will be
* initialized in read-only mode. It's possible to optionally specify the page
* table base of the windows kernel (for full vmm features) or the page table
* base of a single 64-bit process in any x64 operating system. NB! usually it
* is not necessary to specify the PageTableBase - it will be auto-identified
* most often if the target is Windows.
* -- szFileName = the file name of the raw memory dump to use.
* -- szPageTableBaseOpt = optionally the Page Table Base of kernel or process
* as hex string. NB! this is usally not required. Example: "0x1ab000".
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeFile(_In_ LPSTR szFileName, _In_opt_ LPSTR szPageTableBaseOpt);
/*
* Intiailize VMM.DLL from a supported FPGA device over USB. VMM.DLL will be
* initialized in read/write mode upon success. Optionally it will be possible
* to specify the max physical address and the page table base of the kernel or
* process that should be investigated.
* NB! Requires pcileech.dll to be placed in the same directory as vmm.dll.
* -- szMaxPhysicalAddressOpt = max physical address of the target system as a
* hex string. Example: "0x8000000000". If zero value is given the max
* address will be auto-identified.
* -- szPageTableBaseOpt = optionally the Page Table Base of kernel or process
* as hex string. NB! this is usally not required. Example: "0x1ab000".
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeFPGA(_In_opt_ LPSTR szMaxPhysicalAddressOpt, _In_opt_ LPSTR szPageTableBaseOpt);
/*
* Initialize VMM.DLL from a the "Total Meltdown" CVE-2018-1038 vulnerability.
* NB! Requires pcileech.dll to be placed in the same directory as vmm.dll.
* initialized in read/write mode upon success.
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeTotalMeltdown();
BOOL VMMDLL_Initialize(_In_ DWORD argc, _In_ LPSTR argv[]);
/*
* Close an initialized instance of VMM.DLL and clean up all allocated resources
@@ -84,43 +58,29 @@ BOOL VMMDLL_Close();
/*
* Options used together with the functions: VMMDLL_GetOption & VMMDLL_SetOption
* If VMM.DLL is chained with PCILEECH.DLL then required values will be passed
* along to PCILEECH.DLL when necessary.
* Options are defined with either: VMMDLL_OPT_* in this header file or as
* MEMDEVICE_OPT_* in memdevice.h
* For more detailed information check the sources for individual device types.
*/
#define VMMDLL_OPT_DEVICE_FPGA_PROBE_MAXPAGES 0x01 // RW
#define VMMDLL_OPT_DEVICE_FPGA_RX_FLUSH_LIMIT 0x02 // RW
#define VMMDLL_OPT_DEVICE_FPGA_MAX_SIZE_RX 0x03 // RW
#define VMMDLL_OPT_DEVICE_FPGA_MAX_SIZE_TX 0x04 // RW
#define VMMDLL_OPT_DEVICE_FPGA_DELAY_PROBE_READ 0x05 // RW - uS
#define VMMDLL_OPT_DEVICE_FPGA_DELAY_PROBE_WRITE 0x06 // RW - uS
#define VMMDLL_OPT_DEVICE_FPGA_DELAY_WRITE 0x07 // RW - uS
#define VMMDLL_OPT_DEVICE_FPGA_DELAY_READ 0x08 // RW - uS
#define VMMDLL_OPT_DEVICE_FPGA_RETRY_ON_ERROR 0x09 // RW
#define VMMDLL_OPT_DEVICE_FPGA_DEVICE_ID 0x80 // R
#define VMMDLL_OPT_DEVICE_FPGA_FPGA_ID 0x81 // R
#define VMMDLL_OPT_DEVICE_FPGA_VERSION_MAJOR 0x82 // R
#define VMMDLL_OPT_DEVICE_FPGA_VERSION_MINOR 0x83 // R
#define VMMDLL_OPT_CORE_PRINTF_ENABLE 0x80000001 // RW
#define VMMDLL_OPT_CORE_VERBOSE 0x80000002 // RW
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA 0x80000003 // RW
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA_TLP 0x80000004 // RW
#define VMMDLL_OPT_CORE_MAX_NATIVE_ADDRESS 0x80000005 // R
#define VMMDLL_OPT_CORE_MAX_NATIVE_IOSIZE 0x80000006 // R
#define VMMDLL_OPT_CORE_SYSTEM 0x80000007 // R
#define VMMDLL_OPT_CORE_MEMORYMODEL 0x80000008 // R
#define VMMDLL_OPT_CORE_PRINTF_ENABLE 0x80000001 // RW
#define VMMDLL_OPT_CORE_VERBOSE 0x80000002 // RW
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA 0x80000003 // RW
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA_TLP 0x80000004 // RW
#define VMMDLL_OPT_CORE_MAX_NATIVE_ADDRESS 0x80000005 // R
#define VMMDLL_OPT_CORE_MAX_NATIVE_IOSIZE 0x80000006 // R
#define VMMDLL_OPT_CORE_SYSTEM 0x80000007 // R
#define VMMDLL_OPT_CORE_MEMORYMODEL 0x80000008 // R
#define VMMDLL_OPT_CONFIG_IS_REFRESH_ENABLED 0x40000001 // R - 1/0
#define VMMDLL_OPT_CONFIG_TICK_PERIOD 0x40000002 // RW - base tick period in ms
#define VMMDLL_OPT_CONFIG_READCACHE_TICKS 0x40000003 // RW - memory cache validity period (in ticks)
#define VMMDLL_OPT_CONFIG_TLBCACHE_TICKS 0x40000004 // RW - page table (tlb) cache validity period (in ticks)
#define VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_PARTIAL 0x40000005 // RW - process refresh (partial) period (in ticks)
#define VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_TOTAL 0x40000006 // RW - process refresh (full) period (in ticks)
#define VMMDLL_OPT_CONFIG_VMM_VERSION_MAJOR 0x40000007 // R
#define VMMDLL_OPT_CONFIG_VMM_VERSION_MINOR 0x40000008 // R
#define VMMDLL_OPT_CONFIG_VMM_VERSION_REVISION 0x40000009 // R
#define VMMDLL_OPT_CONFIG_STATISTICS_FUNCTIONCALL 0x4000000A // RW - enable function call statistics (.status/statistics_fncall file)
#define VMMDLL_OPT_CONFIG_IS_REFRESH_ENABLED 0x40000001 // R - 1/0
#define VMMDLL_OPT_CONFIG_TICK_PERIOD 0x40000002 // RW - base tick period in ms
#define VMMDLL_OPT_CONFIG_READCACHE_TICKS 0x40000003 // RW - memory cache validity period (in ticks)
#define VMMDLL_OPT_CONFIG_TLBCACHE_TICKS 0x40000004 // RW - page table (tlb) cache validity period (in ticks)
#define VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_PARTIAL 0x40000005 // RW - process refresh (partial) period (in ticks)
#define VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_TOTAL 0x40000006 // RW - process refresh (full) period (in ticks)
#define VMMDLL_OPT_CONFIG_VMM_VERSION_MAJOR 0x40000007 // R
#define VMMDLL_OPT_CONFIG_VMM_VERSION_MINOR 0x40000008 // R
#define VMMDLL_OPT_CONFIG_VMM_VERSION_REVISION 0x40000009 // R
#define VMMDLL_OPT_CONFIG_STATISTICS_FUNCTIONCALL 0x4000000A // RW - enable function call statistics (.status/statistics_fncall file)
static const LPSTR VMMDLL_MEMORYMODEL_TOSTRING[4] = { "N/A", "X86", "X86PAE", "X64" };
@@ -256,9 +216,9 @@ _Success_(return)
BOOL VMMDLL_VfsInitializePlugins();
#define VMMDLL_PLUGIN_CONTEXT_MAGIC 0xc0ffee663df9301c
#define VMMDLL_PLUGIN_CONTEXT_VERSION 1
#define VMMDLL_PLUGIN_CONTEXT_VERSION 2
#define VMMDLL_PLUGIN_REGINFO_MAGIC 0xc0ffee663df9301d
#define VMMDLL_PLUGIN_REGINFO_VERSION 2
#define VMMDLL_PLUGIN_REGINFO_VERSION 3
#define VMMDLL_PLUGIN_EVENT_VERBOSITYCHANGE 0x01
@@ -267,8 +227,6 @@ typedef struct tdVMMDLL_PLUGIN_CONTEXT {
WORD wVersion;
WORD wSize;
DWORD dwPID;
PHANDLE phModulePrivate;
PHANDLE phProcessPrivate;
PVOID pProcess;
LPSTR szModule;
LPSTR szPath;
@@ -289,7 +247,6 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
PVOID pvReserved2;
// general plugin registration info to be filled out by the plugin below:
struct {
HANDLE hModulePrivate;
CHAR szModuleName[32];
BOOL fRootModule;
BOOL fProcessModule;
@@ -301,9 +258,8 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
BOOL(*pfnList)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList);
NTSTATUS(*pfnRead)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset);
NTSTATUS(*pfnWrite)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset);
VOID(*pfnNotify)(_Inout_opt_ PHANDLE phModulePrivate, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent);
VOID(*pfnCloseHandleModule)(_Inout_opt_ PHANDLE phModulePrivate);
VOID(*pfnCloseHandleProcess)(_Inout_opt_ PHANDLE phModulePrivate, _Inout_ PHANDLE phProcessPrivate);
VOID(*pfnNotify)(_In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent);
VOID(*pfnClose)();
PVOID pvReserved1;
PVOID pvReserved2;
} reg_fn;
@@ -323,26 +279,6 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
#define VMMDLL_FLAG_NOCACHE 0x0001 // do not use the data cache (force reading from memory acquisition device)
#define VMMDLL_FLAG_ZEROPAD_ON_FAIL 0x0002 // zero pad failed physical memory reads and report success if read within range of physical memory.
#define VMMDLL_MEM_IO_SCATTER_HEADER_VERSION 2
typedef struct tdVMMDLL_MEM_IO_SCATTER_HEADER {
ULONG64 qwA; // base address (DWORD boundry).
DWORD cbMax; // bytes to read (DWORD boundry, max 0x1000); pbResult must have room for this.
DWORD cb; // bytes read into result buffer.
PBYTE pb; // ptr to 0x1000 sized buffer to receive read bytes.
PVOID pvReserved1; // reserved for use by caller.
PVOID pvReserved2; // reserved for use by caller.
WORD version; // version of struct
WORD Future1; // reserved for future use.
DWORD Future2; // reserved for future use.
ULONG64 qwDeviceA; // device-physical address (used by device layer).
struct {
PVOID pvReserved1;
PVOID pvReserved2;
BYTE pbReserved[32];
} sReserved; // reserved for future use.
} VMMDLL_MEM_IO_SCATTER_HEADER, *PVMMDLL_MEM_IO_SCATTER_HEADER, **PPVMMDLL_MEM_IO_SCATTER_HEADER;
/*
* Read memory in various non-contigious locations specified by the pointers to
* the items in the ppDMAs array. Result for each unit of work will be given
@@ -356,7 +292,7 @@ typedef struct tdVMMDLL_MEM_IO_SCATTER_HEADER {
* -- flags = optional flags as given by VMM_FLAG_*
* -- return = the number of successfully read items.
*/
DWORD VMMDLL_MemReadScatter(_In_ DWORD dwPID, _Inout_ PPVMMDLL_MEM_IO_SCATTER_HEADER ppMEMs, _In_ DWORD cpMEMs, _In_ DWORD flags);
DWORD VMMDLL_MemReadScatter(_In_ DWORD dwPID, _Inout_ PPMEM_IO_SCATTER_HEADER ppMEMs, _In_ DWORD cpMEMs, _In_ DWORD flags);
/*
* Read a single 4096-byte page of memory.
+12 -12
View File
@@ -15,7 +15,7 @@
// [STR] -> None
static PyObject*
VMMPYC_InitializeReserved(PyObject *self, PyObject *args)
VMMPYC_Initialize(PyObject *self, PyObject *args)
{
PyObject *pyList, *pyString;
BOOL result;
@@ -25,7 +25,7 @@ VMMPYC_InitializeReserved(PyObject *self, PyObject *args)
cDstArgs = (DWORD)PyList_Size(pyList);
if(cDstArgs == 0) {
Py_DECREF(pyList);
return PyErr_Format(PyExc_RuntimeError, "VMMPYC_InitializeReserved: Required argument list is empty.");
return PyErr_Format(PyExc_RuntimeError, "VMMPYC_Initialize: Required argument list is empty.");
}
// allocate & initialize buffer+basic
pszDstArgs = (LPSTR*)LocalAlloc(LMEM_ZEROINIT, sizeof(LPSTR) * cDstArgs);
@@ -38,13 +38,13 @@ VMMPYC_InitializeReserved(PyObject *self, PyObject *args)
pyString = PyList_GetItem(pyList, i); // borrowed reference
if(!PyUnicode_Check(pyString)) {
Py_DECREF(pyList);
return PyErr_Format(PyExc_RuntimeError, "VMMPYC_InitializeReserved: Argument list contains non string item.");
return PyErr_Format(PyExc_RuntimeError, "VMMPYC_Initialize: Argument list contains non string item.");
}
pszDstArgs[i] = (char*)PyUnicode_1BYTE_DATA(pyString);
}
Py_DECREF(pyList);
result = VMMDLL_InitializeReserved(cDstArgs, pszDstArgs);
if(!result) { return PyErr_Format(PyExc_RuntimeError, "VMMPYC_InitializeReserved: Initialization of VMM failed."); }
result = VMMDLL_Initialize(cDstArgs, pszDstArgs);
if(!result) { return PyErr_Format(PyExc_RuntimeError, "VMMPYC_Initialize: Initialization of VMM failed."); }
return Py_BuildValue("s", NULL); // None returned on success.
}
@@ -98,8 +98,8 @@ VMMPYC_MemReadScatter(PyObject *self, PyObject *args)
BOOL result;
DWORD dwPID, cMEMs, flags = 0;
ULONG64 i, qwA;
PVMMDLL_MEM_IO_SCATTER_HEADER pMEM, pMEMs;
PPVMMDLL_MEM_IO_SCATTER_HEADER ppMEMs;
PMEM_IO_SCATTER_HEADER pMEM, pMEMs;
PPMEM_IO_SCATTER_HEADER ppMEMs;
PBYTE pb, pbDataBuffer;
if(!PyArg_ParseTuple(args, "kO!|k", &dwPID, &PyList_Type, &pyListSrc, &flags)) { return NULL; } // borrowed reference
cMEMs = (DWORD)PyList_Size(pyListSrc);
@@ -108,14 +108,14 @@ VMMPYC_MemReadScatter(PyObject *self, PyObject *args)
return PyList_New(0);
}
// allocate & initialize buffer+basic
pb = LocalAlloc(0, cMEMs * (sizeof(PVMMDLL_MEM_IO_SCATTER_HEADER) + sizeof(VMMDLL_MEM_IO_SCATTER_HEADER) + 0x1000));
pb = LocalAlloc(0, cMEMs * (sizeof(PMEM_IO_SCATTER_HEADER) + sizeof(MEM_IO_SCATTER_HEADER) + 0x1000));
if(!pb) {
Py_DECREF(pyListSrc);
return PyErr_NoMemory();
}
ppMEMs = (PPVMMDLL_MEM_IO_SCATTER_HEADER)pb;
pMEMs = (PVMMDLL_MEM_IO_SCATTER_HEADER)(pb + cMEMs * sizeof(PVMMDLL_MEM_IO_SCATTER_HEADER));
pbDataBuffer = pb + cMEMs * (sizeof(PVMMDLL_MEM_IO_SCATTER_HEADER) + sizeof(VMMDLL_MEM_IO_SCATTER_HEADER));
ppMEMs = (PPMEM_IO_SCATTER_HEADER)pb;
pMEMs = (PMEM_IO_SCATTER_HEADER)(pb + cMEMs * sizeof(PMEM_IO_SCATTER_HEADER));
pbDataBuffer = pb + cMEMs * (sizeof(PMEM_IO_SCATTER_HEADER) + sizeof(MEM_IO_SCATTER_HEADER));
ZeroMemory(pb, pbDataBuffer - pb);
// iterate over # entries and build scatter data structure
for(i = 0; i < cMEMs; i++) {
@@ -824,7 +824,7 @@ VMMPYC_VfsList(PyObject *self, PyObject *args)
//-----------------------------------------------------------------------------
static PyMethodDef VMMPYC_EmbMethods[] = {
{"VMMPYC_InitializeReserved", VMMPYC_InitializeReserved, METH_VARARGS, "Initialize the VMM"},
{"VMMPYC_Initialize", VMMPYC_Initialize, METH_VARARGS, "Initialize the VMM"},
{"VMMPYC_ConfigGet", VMMPYC_ConfigGet, METH_VARARGS, "Get a device specific option value."},
{"VMMPYC_ConfigSet", VMMPYC_ConfigSet, METH_VARARGS, "Set a device specific option value."},
{"VMMPYC_MemReadScatter", VMMPYC_MemReadScatter, METH_VARARGS, "Read multiple 4kB page sized and aligned chunks of memory given as an address list."},
BIN
View File
Binary file not shown.
+35 -8
View File
@@ -12,9 +12,9 @@
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{8F227E6C-6156-4F7D-965F-BDB9B75FFB4E}</ProjectGuid>
<ProjectGuid>{9E47796D-B834-470E-B437-0754BC14DF09}</ProjectGuid>
<RootNamespace>vmmpyc</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
@@ -22,6 +22,7 @@
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
@@ -29,6 +30,7 @@
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@@ -46,16 +48,15 @@
<OutDir>$(SolutionDir)\files\</OutDir>
<IntDir>$(SolutionDir)\files\temp\$(ProjectName)\</IntDir>
<TargetExt>.pyd</TargetExt>
<IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);C:\Program Files (x86)\Microsoft Visual Studio\Shared\Python36_64\include\;</IncludePath>
<LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;C:\Program Files (x86)\Microsoft Visual Studio\Shared\Python36_64\libs;</LibraryPath>
<LinkIncremental />
<IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);$(WindowsSDK_IncludePath);C:\Program Files (x86)\Microsoft Visual Studio\Shared\Python36_64\include\;C:\Program Files\Python36\include</IncludePath>
<LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;C:\Program Files (x86)\Microsoft Visual Studio\Shared\Python36_64\libs;C:\Program Files\Python36\libs;</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>$(SolutionDir)\files\</OutDir>
<IntDir>$(SolutionDir)\files\temp\$(ProjectName)\</IntDir>
<TargetExt>.pyd</TargetExt>
<IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);C:\Program Files (x86)\Microsoft Visual Studio\Shared\Python36_64\include\;</IncludePath>
<LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;C:\Program Files (x86)\Microsoft Visual Studio\Shared\Python36_64\libs;</LibraryPath>
<IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);$(WindowsSDK_IncludePath);C:\Program Files (x86)\Microsoft Visual Studio\Shared\Python36_64\include\;C:\Program Files\Python36\include</IncludePath>
<LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;C:\Program Files (x86)\Microsoft Visual Studio\Shared\Python36_64\libs;C:\Program Files\Python36\libs;</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
@@ -66,9 +67,19 @@
</ClCompile>
<Link>
<AdditionalDependencies>$(SolutionDir)\files\vmm.lib</AdditionalDependencies>
<IgnoreAllDefaultLibraries>
</IgnoreAllDefaultLibraries>
<ProgramDatabaseFile>$(OutDir)\lib\$(TargetName).pdb</ProgramDatabaseFile>
<ImportLibrary>$(OutDir)\lib\$(TargetName).lib</ImportLibrary>
</Link>
<PostBuildEvent>
<Command>
</Command>
</PostBuildEvent>
<PreBuildEvent>
<Command>copy $(SolutionDir)\files\leechcore.h $(ProjectDir)\ /y
copy $(SolutionDir)\files\vmmdll.h $(ProjectDir)\ /y</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
@@ -78,22 +89,38 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>$(SolutionDir)\files\vmm.lib</AdditionalDependencies>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
<IgnoreAllDefaultLibraries>
</IgnoreAllDefaultLibraries>
<ProgramDatabaseFile>$(OutDir)\lib\$(TargetName).pdb</ProgramDatabaseFile>
<ImportLibrary>$(OutDir)\lib\$(TargetName).lib</ImportLibrary>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
</Link>
<PostBuildEvent>
<Command>
</Command>
</PostBuildEvent>
<PreBuildEvent>
<Command>copy $(SolutionDir)\files\leechcore.h $(ProjectDir)\ /y
copy $(SolutionDir)\files\vmmdll.h $(ProjectDir)\ /y</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="leechcore.h" />
<ClInclude Include="version.h" />
<ClInclude Include="vmmdll.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="vmmpyc.c" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="vmmpyc.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
+12 -1
View File
@@ -14,17 +14,28 @@
<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="Header Files\vmm">
<UniqueIdentifier>{b6c15f41-24a1-401e-8ad1-c4b158f9d770}</UniqueIdentifier>
<UniqueIdentifier>{e9dc36c3-ddaf-4793-bc7a-ca2ded590236}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="vmmdll.h">
<Filter>Header Files\vmm</Filter>
</ClInclude>
<ClInclude Include="leechcore.h">
<Filter>Header Files\vmm</Filter>
</ClInclude>
<ClInclude Include="version.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="vmmpyc.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="vmmpyc.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>
+6 -1
View File
@@ -1,4 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>
+466
View File
@@ -0,0 +1,466 @@
// leechcore.h : header file for the leechcore module - which purpose is to
// expose low-level device physical memory functionality.
//
// This library is thread-safe in all functions with the notable exceptions of
// the LeechCore_Open() and LeechCore_Close() functions. Some devices may allow
// multi-threaded access while in reality most devices are single-threaded and
// will control synchronization where necessary with locks.
//
// The library is initialized by calling LeechCore_Open with a LEECHCORE_CONFIG
// struct containing the correct configuration paramters. Note that the version
// and magic values must be set in addition to the szDevice configuration value
// Also, it may be possible to optionally connect to a remote leechcore service
// or instance over RPC by specifying a szRemote configuration value.
//
// ----------------------------------------------------------------------------
//
// Remote instance: szRemote configuration value. Connect to a remote leechcore
// instance by specifying a configuration value in the szRemote parameter. If a
// loaded already valid instance exists remotely this will be prioritized above
// the value in szDevice. If the acquisition device is not yet loaded by the
// remote instance the value in szDevice will be used. Normally, the connection
// will take place as a mutually authenticated encrypted connection secured by
// kerberos. If not possible or desirable the 'insecure' value may be specified
// to disable authentication and security.
// Syntax:
// rpc://<remote_spn>:<host>:<port> (port = optional, remote_spn = kerberos)
// (SPN of remote service or 'insecure' )
// Examples:
// rpc://insecure:remotehost.example.com (connect insecure to remote host )
// rpc://[email protected]:192.0.0.5 (connect secure to remote host )
// rpc://insecure:127.0.0.0:6666 (connect insecure non-default port)
//
// ----------------------------------------------------------------------------
//
// Device to connect to: szDevice contains the device to capture memory from.
// Supported memory acquisition devices are:
// USB3380 : hardware, read/write, 32-bit (4GB) addressing only. Requires a
// PCILeech flashed USB3380 device connected over USB and Google
// Android WinUSB drivers to be installed. Download and install from:
// http://developer.android.com/sdk/win-usb.html#download
// Syntax:
// USB3380
// USB3380://USB2 (force USB2 connection speed)
//
// FPGA : hardware, read/write - requires a PCILeech FPGA flashed hardware
// device as shown at: https://github.com/ufrisk/pcileech-fpga
// Also requires the FTD3XX.DLL from ftdichip to be placed in the
// same directory as the executable. Download from ftdichip at:
// http://www.ftdichip.com/Drivers/D3XX/FTD3XXLibrary_v1.2.0.6.zip
// Syntax:
// FGPA
// FPGA://<read_uS>[:<write_uS>[:<probe_uS>]] (values are optional)
//
// SP605TCP : hardware, read/write - connect to a remote SP605 FPGA over the
// network using the implementation created by @d_olex.
// https://github.com/Cr4sh/s6_pcie_microblaze
// Syntax:
// SP605TCP://<target_ip>[:<target_port>] (port is optional)
//
// RAWTCP : read/write - connect to a remote raw tcp device - such as HPE iLO
// that have been patched to support DMA as per blog entry below:
// https://www.synacktiv.com/posts/exploit/using-your-bmc-as-a-dma-device-plugging-pcileech-to-hpe-ilo-4.html
// Syntax:
// RAWTCP://<target_ip>[:<target_port>] (port is optional)
//
// HvSavedState : read-only - connect to a Hyper-V saved state file. In order
// to do so the .dll file 'vmsavedstatedumpprovider.dll' must be
// placed in same directory as the executable file.
//
// PMEM : load the rekall winpmem driver into the kernel and connect to it
// to acquire memory. The driver file 'winpmem_x64.sys' is found in
// the Rekall directory after most recent version has been installed.
// Copy 'winpmem_x64.sys' to the directory of leechcore.dll and run
// executable as elevated admin using syntax below:
// Syntax:
// PMEM (use winpmem_x64.sys in directory of executable)
// PMEM://<non_default_path_to_file_winpmem_x64.sys>
//
// TOTALMELTDOWN : read/write - requires a Windows 7 system vulnerable to the
// "Total Meltdown" vulnerability - CVE-2018-1038.
// Syntax:
// TOTALMELTDOWN
//
// FILE : use dump file, either a raw linear memory dump or full crash dump.
// Which format to use is auto-detected. If it looks like a full cash
// dump that format will be used, otherwise it will be assumed that a
// raw linear memory dump is to be used.
// Syntax:
// <filename> (no device-type prefix - just use the file name)
// FILE://<filename>
//
// DumpIt : DumpIt is a "virtual" device. It's only possible to use the DumpIt
// device if the main process containing LeechCore has been started
// with DumpIt in LiveKD mode.
// Example 1:
// DumpIt.exe /LIVEKD /A MemProcFS.exe
// Example 2:
// DumpIt.exe /LIVEKD /A LeechSvc.exe /C "interactive insecure"
// and then connect to remote service by:
// MemProcFS.exe -remote rpc://insecure:192.168.x.x -device DumpIt
//
// EXISTING : Attach to existing already loaded configuration. This is done
// instead of the default behaviour of closing any existing devices
// and initializing the new requested device. If no existing device
// exists the call to LeechCore_Open will fail.
// Syntax:
// EXISTING
//
//
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
// Header Version: 1.0
//
#ifndef __LEECHCORE_H__
#define __LEECHCORE_H__
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
//-----------------------------------------------------------------------------
// WINDOWS / LINUX COMPATIBILITY BELOW:
//-----------------------------------------------------------------------------
#ifdef _WIN32
#include <Windows.h>
typedef unsigned __int64 QWORD, *PQWORD;
#define DLLEXPORT __declspec(dllexport)
#endif /* _WIN32 */
#ifdef LINUX
#include <stdint.h>
#include <stddef.h>
typedef void VOID, *PVOID, *LPVOID;
typedef void *HANDLE, **PHANDLE;
typedef uint32_t BOOL, *PBOOL;
typedef uint8_t BYTE, *PBYTE;
typedef char CHAR, *PCHAR, *PSTR, *LPSTR;
typedef uint16_t WORD, *PWORD, USHORT, *PUSHORT;
typedef uint32_t DWORD, *PDWORD;
typedef long long unsigned int QWORD, *PQWORD, ULONG64, *PULONG64;
#define MAX_PATH 260
#define DLLEXPORT __attribute__((visibility("default")))
#define _In_
#define _Out_
#define _In_z_
#define _Inout_
#define _In_opt_
#define _Out_opt_
#define _Out_writes_(x)
#define _Check_return_opt_
#define _Printf_format_string_
#define _Inout_updates_bytes_(x)
#define _In_reads_(cbDataIn)
#define _Success_(return)
#endif /* LINUX */
//-----------------------------------------------------------------------------
// GENERAL HEADER DEFINES BELOW:
//-----------------------------------------------------------------------------
#define MEM_IO_SCATTER_HEADER_MAGIC 0xffff6548
#define MEM_IO_SCATTER_HEADER_VERSION 0x0003
typedef struct tdMEM_IO_SCATTER_HEADER {
DWORD magic; // magic
WORD version; // version
WORD Future1;
ULONG64 qwA; // base address.
DWORD cbMax; // bytes to read (DWORD boundry, max 0x1000); pb must have room for this.
DWORD cb; // bytes read into result buffer.
PBYTE pb; // ptr to 0x1000 sized buffer to receive read bytes.
PVOID pvReserved1; // reserved for use by caller.
PVOID pvReserved2; // reserved for use by caller.
PVOID Future2[8];
} MEM_IO_SCATTER_HEADER, *PMEM_IO_SCATTER_HEADER, **PPMEM_IO_SCATTER_HEADER;
//-----------------------------------------------------------------------------
// LEECHCORE INITIALIZATION / CLOSE FUNCTIONALITY BELOW:
//-----------------------------------------------------------------------------
typedef enum tdLEECHCORE_DEVICE {
LEECHCORE_DEVICE_NA = 0,
LEECHCORE_DEVICE_FILE = 1,
LEECHCORE_DEVICE_PMEM = 2,
LEECHCORE_DEVICE_FPGA = 3,
LEECHCORE_DEVICE_SP605_TCP = 4,
LEECHCORE_DEVICE_USB3380 = 5,
LEECHCORE_DEVICE_TOTALMELTDOWN = 6,
LEECHCORE_DEVICE_HVSAVEDSTATE = 7,
LEECHCORE_DEVICE_RAWTCP = 8,
} LEECHCORE_DEVICE;
#define LEECHCORE_CONFIG_MAGIC 0xffff6549
#define LEECHCORE_CONFIG_VERSION 0x0001
#define LEECHCORE_CONFIG_FLAG_PRINTF 0x0001
#define LEECHCORE_CONFIG_FLAG_PRINTF_VERBOSE_1 0x0002
#define LEECHCORE_CONFIG_FLAG_PRINTF_VERBOSE_2 0x0004
#define LEECHCORE_CONFIG_FLAG_PRINTF_VERBOSE_3 0x0008
#define LEECHCORE_CONFIG_FLAG_REMOTE_NO_COMPRESS 0x0010
typedef struct tdLEECHCORE_CONFIG {
DWORD magic; // set by caller.
WORD version; // set by caller.
WORD flags; // set by caller, updated by device.
ULONG64 paMax; // set by caller, updated by device.
ULONG64 cbMaxSizeMemIo; // set by caller, updated by device.
ULONG64 paMaxNative; // set by device.
LEECHCORE_DEVICE tpDevice; // set by device.
BOOL fWritable; // set by device. (is device writable?)
BOOL fVolatile; // set by device. (is device volatile / memory may change?)
BOOL fVolatileMaxAddress; // set by device. (is max address volatile? - poll changes with LEECHCORE_OPT_MEMORYINFO_ADDR_MAX)
BOOL fRemote; // set by device.
WORD VersionMajor; // set by device.
WORD VersionMinor; // set by device.
WORD VersionRevision; // set by device.
CHAR szDevice[MAX_PATH]; // set by caller.
CHAR szRemote[MAX_PATH]; // set by caller.
// optional 'printf' function pointer. if set to non null value 'printf'
// calls will be redirected. useful when logging to files.
_Check_return_opt_ int(*pfn_printf_opt)(_In_z_ _Printf_format_string_ char const* const _Format, ...); // set by caller.
} LEECHCORE_CONFIG, *PLEECHCORE_CONFIG;
typedef struct tdLEECHCORE_PAGESTAT_MINIMAL {
HANDLE h;
VOID(*pfnPageStatUpdate)(HANDLE h, ULONG64 pa, ULONG64 cPageSuccessAdd, ULONG64 cPageFailAdd);
} LEECHCORE_PAGESTAT_MINIMAL, *PLEECHCORE_PAGESTAT_MINIMAL;
/*
* Open a connection to the target device.
* -- pInformation
* -- result
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_Open(_Inout_ PLEECHCORE_CONFIG pConfig);
/*
* Clean up various device related stuff and deallocate memory buffers.
*/
DLLEXPORT VOID LeechCore_Close();
//-----------------------------------------------------------------------------
// LEECHCORE CORE READ AND WRITE FUNCTIONALITY BELOW:
//-----------------------------------------------------------------------------
#define LEECHCORE_FLAG_READ_RETRY 0x01
#define LEECHCORE_FLAG_WRITE_RETRY 0x01
#define LEECHCORE_FLAG_WRITE_VERIFY 0x02
/*
* Allocate a scatter buffer containing empty 0x1000-sized ppMEMs with address
* set to zero. Caller is responsible for calling LocalFree(ppMEMs).
* -- cMEMs
* -- pppMEMs = pointer to receive ppMEMs on success.
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_AllocScatterEmpty(_In_ DWORD cMEMs, _Out_ PPMEM_IO_SCATTER_HEADER *pppMEMs);
/*
* Read memory in various non-contigious locations specified by the items in the
* phDMAs array. Result for each unit of work will be given individually. No upper
* limit of number of items to read, but no performance boost will be given if
* above hardware limit. Max size of each unit of work is one 4k page (4096 bytes).
* -- ppMEMs = array of scatter read headers.
* -- cpMEMs = count of ppDMAs.
*/
DLLEXPORT VOID LeechCore_ReadScatter(_Inout_ PPMEM_IO_SCATTER_HEADER ppMEMs, _In_ DWORD cpMEMs);
/*
* Try read memory in a fairly optimal way considering device limits. The number
* of total successfully read bytes is returned. Failed reads will be zeroed out
* in the returned memory.
* -- pa
* -- pb
* -- cb
* -- return = the number of bytes successfully read.
*/
DLLEXPORT DWORD LeechCore_Read(_In_ ULONG64 pa, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb);
/*
* Try read memory in a fairly optimal way considering device limits. The number
* of total successfully read bytes is returned. Failed reads will be zeroed out
* in the returned memory.
* -- pa
* -- pb
* -- cb
* -- flags = 0 or LEECHCORE_FLAG_READ_RETRY
* -- pPageStat = optional minimal statistic struct to update.
* -- return = the number of bytes successfully read.
*/
DLLEXPORT DWORD LeechCore_ReadEx(_In_ ULONG64 pa, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _In_ DWORD flags, _In_opt_ PLEECHCORE_PAGESTAT_MINIMAL pPageStat);
/*
* Write data to the target system if supported by the device.
* -- pa
* -- pb
* -- cb
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_Write(_In_ ULONG64 pa, _In_ PBYTE pb, _In_ DWORD cb);
/*
* Write data to the target system if supported by the device.
* -- pa
* -- pb
* -- cb
* -- flags = 0 or LEECHCORE_FLAG_WRITE_*
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_WriteEx(_In_ ULONG64 pa, _In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD flags);
/*
* Probe the memory of the target system to check whether it's readable or not.
* Please note that not all devices support this natively.
* -- pa = address to start probe from.
* -- cPages = number of 4kB pages to probe.
* -- pbResultMap = result map, 1 byte represents 1 page, 0 = fail, 1 = success.
* (individual page elements in pbResultMap must be set to 0 [fail] on call
* for probe to take place on individual page).
* -- return = FALSE if not supported by underlying hardware, TRUE if supported.
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_Probe(_In_ QWORD pa, _In_ DWORD cPages, _Inout_updates_bytes_(cPages) PBYTE pbResultMap);
//-----------------------------------------------------------------------------
// GET/SET DEVICE OPTIONS BELOW. SOME OPTIONS ARE GENERAL LEECHCORE OPTIONS
// WHILE OTHER ARE DEVICE SPECIFIC. USE FUNCTIONS:
// LeechCore_GetOption() AND LeechCore_GetOption() TO GET/SET OPTIONS.
// FOR DEVICE-SPECIFIC OPTIONS PLEASE SEE INDIVIDUAL DEVICE FILES FOR MORE
// DETAILED INFORMATION.
//-----------------------------------------------------------------------------
#define LEECHCORE_OPT_CORE_PRINTF_ENABLE 0x80000001 // RW
#define LEECHCORE_OPT_CORE_VERBOSE 0x80000002 // RW
#define LEECHCORE_OPT_CORE_VERBOSE_EXTRA 0x80000003 // RW
#define LEECHCORE_OPT_CORE_VERBOSE_EXTRA_TLP 0x80000004 // RW
#define LEECHCORE_OPT_CORE_VERSION_MAJOR 0x01000001 // R
#define LEECHCORE_OPT_CORE_VERSION_MINOR 0x01000002 // R
#define LEECHCORE_OPT_CORE_VERSION_REVISION 0x01000003 // R
#define LEECHCORE_OPT_MEMORYINFO_VALID 0x02000001 // R
#define LEECHCORE_OPT_MEMORYINFO_ADDR_MAX 0x02000002 // R
#define LEECHCORE_OPT_MEMORYINFO_FLAG_32BIT 0x02000003 // R
#define LEECHCORE_OPT_MEMORYINFO_FLAG_PAE 0x02000004 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_VERSION_MINOR 0x02000005 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_VERSION_MAJOR 0x02000006 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_DTB 0x02000007 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_PFN 0x02000008 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_PsLoadedModuleList 0x02000009 // R
#define LEECHCORE_OPT_MEMORYINFO_OS_PsActiveProcessHead 0x0200000a // R
#define LEECHCORE_OPT_MEMORYINFO_OS_MACHINE_IMAGE_TP 0x0200000b // R
#define LEECHCORE_OPT_MEMORYINFO_OS_NUM_PROCESSORS 0x0200000c // R
#define LEECHCORE_OPT_MEMORYINFO_OS_SYSTEMTIME 0x0200000d // R
#define LEECHCORE_OPT_MEMORYINFO_OS_UPTIME 0x0200000e // R
#define LEECHCORE_OPT_MEMORYINFO_OS_KERNELBASE 0x0200000f // R
#define LEECHCORE_OPT_MEMORYINFO_OS_KERNELHINT 0x02000010 // R
#define LEECHCORE_OPT_FPGA_PROBE_MAXPAGES 0x03000001 // RW
#define LEECHCORE_OPT_FPGA_RX_FLUSH_LIMIT 0x03000002 // RW
#define LEECHCORE_OPT_FPGA_MAX_SIZE_RX 0x03000003 // RW
#define LEECHCORE_OPT_FPGA_MAX_SIZE_TX 0x03000004 // RW
#define LEECHCORE_OPT_FPGA_DELAY_PROBE_READ 0x03000005 // RW - uS
#define LEECHCORE_OPT_FPGA_DELAY_PROBE_WRITE 0x03000006 // RW - uS
#define LEECHCORE_OPT_FPGA_DELAY_WRITE 0x03000007 // RW - uS
#define LEECHCORE_OPT_FPGA_DELAY_READ 0x03000008 // RW - uS
#define LEECHCORE_OPT_FPGA_RETRY_ON_ERROR 0x03000009 // RW
#define LEECHCORE_OPT_FPGA_DEVICE_ID 0x03000080 // R
#define LEECHCORE_OPT_FPGA_FPGA_ID 0x03000081 // R
#define LEECHCORE_OPT_FPGA_VERSION_MAJOR 0x03000082 // R
#define LEECHCORE_OPT_FPGA_VERSION_MINOR 0x03000083 // R
/*
* Set a device specific option value.
* -- fOption
* -- pqwValue = pointer to QWORD to receive option value.
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_GetOption(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue);
/*
* Set a device specific option value.
* -- fOption
* -- qwValue
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_SetOption(_In_ ULONG64 fOption, _In_ ULONG64 qwValue);
//-----------------------------------------------------------------------------
// TRANSFER DEVICE DEPENDANT COMMANDS OR DATA TO/FROM UNDERLYING DEVICES AND
// PERFORM ACTIONS USING THE LeechCore_CommandData() FUNCTION.
//-----------------------------------------------------------------------------
#define LEECHCORE_COMMANDDATA_FPGA_WRITE_TLP 0x00000101 // R
#define LEECHCORE_COMMANDDATA_FPGA_LISTEN_TLP 0x00000102 // R
#define LEECHCORE_COMMANDDATA_STATISTICS_GET 0x80000100 // R
#define LEECHCORE_STATISTICS_MAGIC 0xffff6550
#define LEECHCORE_STATISTICS_VERSION 0x0001
#define LEECHCORE_STATISTICS_ID_OPEN 0x00
#define LEECHCORE_STATISTICS_ID_READSCATTER 0x01
#define LEECHCORE_STATISTICS_ID_WRITE 0x02
#define LEECHCORE_STATISTICS_ID_PROBE 0x03
#define LEECHCORE_STATISTICS_ID_GETOPTION 0x04
#define LEECHCORE_STATISTICS_ID_SETOPTION 0x05
#define LEECHCORE_STATISTICS_ID_COMMANDDATA 0x06
#define LEECHCORE_STATISTICS_ID_MAX 0x06
static const LPSTR LEECHCORE_STATISTICS_NAME[] = {
"LeechCore_Open",
"LeechCore_ReadScatter",
"LeechCore_Write",
"LeechCore_Probe",
"LeechCore_GetOption",
"LeechCore_SetOption",
"LeechCore_CommandData"
};
typedef struct tdLEECHCORE_STATISTICS {
DWORD magic;
WORD version;
WORD Reserved0;
DWORD Reserved1;
QWORD qwFreq;
struct {
QWORD c;
QWORD tm; // total time in qwFreq ticks
} Call[0x10];
} LEECHCORE_STATISTICS, *PLEECHCORE_STATISTICS;
/*
* Transfer device dependant commands/data to/from the underlying device and
* perform device dependant actions.
* -- fOption
* -- cbDataIn
* -- pbDataIn
* -- pbDataOut
* -- cbDataOut
* -- pcbDataOut
* -- return
*/
_Success_(return)
DLLEXPORT BOOL LeechCore_CommandData(
_In_ ULONG64 fOption,
_In_reads_(cbDataIn) PBYTE pbDataIn,
_In_ DWORD cbDataIn,
_Out_writes_(cbDataOut) PBYTE pbDataOut,
_In_ DWORD cbDataOut,
_Out_ PDWORD pcbDataOut
);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __LEECHCORE_H__ */
+22
View File
@@ -0,0 +1,22 @@
#define STRINGIZE2(s) #s
#define STRINGIZE(s) STRINGIZE2(s)
#define VERSION_MAJOR 2
#define VERSION_MINOR 0
#define VERSION_REVISION 0
#define VERSION_BUILD 0
#define VER_FILE_DESCRIPTION_STR "The Memory Process File System : Python Plugin Manager"
#define VER_FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_BUILD
#define VER_FILE_VERSION_STR STRINGIZE(VERSION_MAJOR) \
"." STRINGIZE(VERSION_MINOR) \
"." STRINGIZE(VERSION_REVISION) \
"." STRINGIZE(VERSION_BUILD) \
#define VER_COMPANY_NAME_STR ""
#define VER_PRODUCTNAME_STR "vmmpycplugin"
#define VER_PRODUCT_VERSION VER_FILE_VERSION
#define VER_PRODUCT_VERSION_STR VER_FILE_VERSION_STR
#define VER_ORIGINAL_FILENAME_STR VER_PRODUCTNAME_STR ".dll"
#define VER_INTERNAL_NAME_STR VER_ORIGINAL_FILENAME_STR
#define VER_COPYRIGHT_STR "Copyright (c) Ulf Frisk 2018-2019"
+44 -108
View File
@@ -1,11 +1,14 @@
// vmmdll.h : header file to include in projects that use vmm.dll either as
// stand anlone projects or as native plugins to vmm.dll.
//
// (c) Ulf Frisk, 2018
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, [email protected]
//
// Header Version: 2.0
//
#include <windows.h>
#include "leechcore.h"
#ifndef __VMMDLL_H__
#define __VMMDLL_H__
@@ -19,52 +22,23 @@ extern "C" {
//-----------------------------------------------------------------------------
/*
* RESERVED FUNCTION! DO NOT USE!
* Call other VMMDLL_Intialize functions to initialize VMM.DLL and the memory
* process file system.
* Initialize VMM.DLL with command line parameters. For a more detailed info
* about the parameters please see github wiki for Memory Process File System
* and LeechCore. THIS IS THE PREFERED WAY OF INITIALIZING VMM.DLL
* Important parameters are:
* -vdll = show printf style outputs)
* -v -vv -vvv = extra verbosity levels)
* -device = device as on format for LeechCore - please see leechcore.h or
* Github documentation for additional information. Some values
* are: <file>, fpga, usb3380, hvsavedstate, totalmeltdown, pmem
* -remote = remote LeechCore instance - please see leechcore.h or Github
* documentation for additional information.
* -- argc
* -- argv
* -- return = success/fail
*/
_Success_(return)
BOOL VMMDLL_InitializeReserved(_In_ DWORD argc, _In_ LPSTR argv[]);
/*
* Initialize VMM.DLL from a memory dump file in raw format. VMM.DLL will be
* initialized in read-only mode. It's possible to optionally specify the page
* table base of the windows kernel (for full vmm features) or the page table
* base of a single 64-bit process in any x64 operating system. NB! usually it
* is not necessary to specify the PageTableBase - it will be auto-identified
* most often if the target is Windows.
* -- szFileName = the file name of the raw memory dump to use.
* -- szPageTableBaseOpt = optionally the Page Table Base of kernel or process
* as hex string. NB! this is usally not required. Example: "0x1ab000".
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeFile(_In_ LPSTR szFileName, _In_opt_ LPSTR szPageTableBaseOpt);
/*
* Intiailize VMM.DLL from a supported FPGA device over USB. VMM.DLL will be
* initialized in read/write mode upon success. Optionally it will be possible
* to specify the max physical address and the page table base of the kernel or
* process that should be investigated.
* NB! Requires pcileech.dll to be placed in the same directory as vmm.dll.
* -- szMaxPhysicalAddressOpt = max physical address of the target system as a
* hex string. Example: "0x8000000000". If zero value is given the max
* address will be auto-identified.
* -- szPageTableBaseOpt = optionally the Page Table Base of kernel or process
* as hex string. NB! this is usally not required. Example: "0x1ab000".
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeFPGA(_In_opt_ LPSTR szMaxPhysicalAddressOpt, _In_opt_ LPSTR szPageTableBaseOpt);
/*
* Initialize VMM.DLL from a the "Total Meltdown" CVE-2018-1038 vulnerability.
* NB! Requires pcileech.dll to be placed in the same directory as vmm.dll.
* initialized in read/write mode upon success.
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeTotalMeltdown();
BOOL VMMDLL_Initialize(_In_ DWORD argc, _In_ LPSTR argv[]);
/*
* Close an initialized instance of VMM.DLL and clean up all allocated resources
@@ -84,43 +58,29 @@ BOOL VMMDLL_Close();
/*
* Options used together with the functions: VMMDLL_GetOption & VMMDLL_SetOption
* If VMM.DLL is chained with PCILEECH.DLL then required values will be passed
* along to PCILEECH.DLL when necessary.
* Options are defined with either: VMMDLL_OPT_* in this header file or as
* MEMDEVICE_OPT_* in memdevice.h
* For more detailed information check the sources for individual device types.
*/
#define VMMDLL_OPT_DEVICE_FPGA_PROBE_MAXPAGES 0x01 // RW
#define VMMDLL_OPT_DEVICE_FPGA_RX_FLUSH_LIMIT 0x02 // RW
#define VMMDLL_OPT_DEVICE_FPGA_MAX_SIZE_RX 0x03 // RW
#define VMMDLL_OPT_DEVICE_FPGA_MAX_SIZE_TX 0x04 // RW
#define VMMDLL_OPT_DEVICE_FPGA_DELAY_PROBE_READ 0x05 // RW - uS
#define VMMDLL_OPT_DEVICE_FPGA_DELAY_PROBE_WRITE 0x06 // RW - uS
#define VMMDLL_OPT_DEVICE_FPGA_DELAY_WRITE 0x07 // RW - uS
#define VMMDLL_OPT_DEVICE_FPGA_DELAY_READ 0x08 // RW - uS
#define VMMDLL_OPT_DEVICE_FPGA_RETRY_ON_ERROR 0x09 // RW
#define VMMDLL_OPT_DEVICE_FPGA_DEVICE_ID 0x80 // R
#define VMMDLL_OPT_DEVICE_FPGA_FPGA_ID 0x81 // R
#define VMMDLL_OPT_DEVICE_FPGA_VERSION_MAJOR 0x82 // R
#define VMMDLL_OPT_DEVICE_FPGA_VERSION_MINOR 0x83 // R
#define VMMDLL_OPT_CORE_PRINTF_ENABLE 0x80000001 // RW
#define VMMDLL_OPT_CORE_VERBOSE 0x80000002 // RW
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA 0x80000003 // RW
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA_TLP 0x80000004 // RW
#define VMMDLL_OPT_CORE_MAX_NATIVE_ADDRESS 0x80000005 // R
#define VMMDLL_OPT_CORE_MAX_NATIVE_IOSIZE 0x80000006 // R
#define VMMDLL_OPT_CORE_SYSTEM 0x80000007 // R
#define VMMDLL_OPT_CORE_MEMORYMODEL 0x80000008 // R
#define VMMDLL_OPT_CORE_PRINTF_ENABLE 0x80000001 // RW
#define VMMDLL_OPT_CORE_VERBOSE 0x80000002 // RW
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA 0x80000003 // RW
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA_TLP 0x80000004 // RW
#define VMMDLL_OPT_CORE_MAX_NATIVE_ADDRESS 0x80000005 // R
#define VMMDLL_OPT_CORE_MAX_NATIVE_IOSIZE 0x80000006 // R
#define VMMDLL_OPT_CORE_SYSTEM 0x80000007 // R
#define VMMDLL_OPT_CORE_MEMORYMODEL 0x80000008 // R
#define VMMDLL_OPT_CONFIG_IS_REFRESH_ENABLED 0x40000001 // R - 1/0
#define VMMDLL_OPT_CONFIG_TICK_PERIOD 0x40000002 // RW - base tick period in ms
#define VMMDLL_OPT_CONFIG_READCACHE_TICKS 0x40000003 // RW - memory cache validity period (in ticks)
#define VMMDLL_OPT_CONFIG_TLBCACHE_TICKS 0x40000004 // RW - page table (tlb) cache validity period (in ticks)
#define VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_PARTIAL 0x40000005 // RW - process refresh (partial) period (in ticks)
#define VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_TOTAL 0x40000006 // RW - process refresh (full) period (in ticks)
#define VMMDLL_OPT_CONFIG_VMM_VERSION_MAJOR 0x40000007 // R
#define VMMDLL_OPT_CONFIG_VMM_VERSION_MINOR 0x40000008 // R
#define VMMDLL_OPT_CONFIG_VMM_VERSION_REVISION 0x40000009 // R
#define VMMDLL_OPT_CONFIG_STATISTICS_FUNCTIONCALL 0x4000000A // RW - enable function call statistics (.status/statistics_fncall file)
#define VMMDLL_OPT_CONFIG_IS_REFRESH_ENABLED 0x40000001 // R - 1/0
#define VMMDLL_OPT_CONFIG_TICK_PERIOD 0x40000002 // RW - base tick period in ms
#define VMMDLL_OPT_CONFIG_READCACHE_TICKS 0x40000003 // RW - memory cache validity period (in ticks)
#define VMMDLL_OPT_CONFIG_TLBCACHE_TICKS 0x40000004 // RW - page table (tlb) cache validity period (in ticks)
#define VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_PARTIAL 0x40000005 // RW - process refresh (partial) period (in ticks)
#define VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_TOTAL 0x40000006 // RW - process refresh (full) period (in ticks)
#define VMMDLL_OPT_CONFIG_VMM_VERSION_MAJOR 0x40000007 // R
#define VMMDLL_OPT_CONFIG_VMM_VERSION_MINOR 0x40000008 // R
#define VMMDLL_OPT_CONFIG_VMM_VERSION_REVISION 0x40000009 // R
#define VMMDLL_OPT_CONFIG_STATISTICS_FUNCTIONCALL 0x4000000A // RW - enable function call statistics (.status/statistics_fncall file)
static const LPSTR VMMDLL_MEMORYMODEL_TOSTRING[4] = { "N/A", "X86", "X86PAE", "X64" };
@@ -256,9 +216,9 @@ _Success_(return)
BOOL VMMDLL_VfsInitializePlugins();
#define VMMDLL_PLUGIN_CONTEXT_MAGIC 0xc0ffee663df9301c
#define VMMDLL_PLUGIN_CONTEXT_VERSION 1
#define VMMDLL_PLUGIN_CONTEXT_VERSION 2
#define VMMDLL_PLUGIN_REGINFO_MAGIC 0xc0ffee663df9301d
#define VMMDLL_PLUGIN_REGINFO_VERSION 2
#define VMMDLL_PLUGIN_REGINFO_VERSION 3
#define VMMDLL_PLUGIN_EVENT_VERBOSITYCHANGE 0x01
@@ -267,8 +227,6 @@ typedef struct tdVMMDLL_PLUGIN_CONTEXT {
WORD wVersion;
WORD wSize;
DWORD dwPID;
PHANDLE phModulePrivate;
PHANDLE phProcessPrivate;
PVOID pProcess;
LPSTR szModule;
LPSTR szPath;
@@ -289,7 +247,6 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
PVOID pvReserved2;
// general plugin registration info to be filled out by the plugin below:
struct {
HANDLE hModulePrivate;
CHAR szModuleName[32];
BOOL fRootModule;
BOOL fProcessModule;
@@ -301,9 +258,8 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
BOOL(*pfnList)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList);
NTSTATUS(*pfnRead)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset);
NTSTATUS(*pfnWrite)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset);
VOID(*pfnNotify)(_Inout_opt_ PHANDLE phModulePrivate, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent);
VOID(*pfnCloseHandleModule)(_Inout_opt_ PHANDLE phModulePrivate);
VOID(*pfnCloseHandleProcess)(_Inout_opt_ PHANDLE phModulePrivate, _Inout_ PHANDLE phProcessPrivate);
VOID(*pfnNotify)(_In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent);
VOID(*pfnClose)();
PVOID pvReserved1;
PVOID pvReserved2;
} reg_fn;
@@ -323,26 +279,6 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
#define VMMDLL_FLAG_NOCACHE 0x0001 // do not use the data cache (force reading from memory acquisition device)
#define VMMDLL_FLAG_ZEROPAD_ON_FAIL 0x0002 // zero pad failed physical memory reads and report success if read within range of physical memory.
#define VMMDLL_MEM_IO_SCATTER_HEADER_VERSION 2
typedef struct tdVMMDLL_MEM_IO_SCATTER_HEADER {
ULONG64 qwA; // base address (DWORD boundry).
DWORD cbMax; // bytes to read (DWORD boundry, max 0x1000); pbResult must have room for this.
DWORD cb; // bytes read into result buffer.
PBYTE pb; // ptr to 0x1000 sized buffer to receive read bytes.
PVOID pvReserved1; // reserved for use by caller.
PVOID pvReserved2; // reserved for use by caller.
WORD version; // version of struct
WORD Future1; // reserved for future use.
DWORD Future2; // reserved for future use.
ULONG64 qwDeviceA; // device-physical address (used by device layer).
struct {
PVOID pvReserved1;
PVOID pvReserved2;
BYTE pbReserved[32];
} sReserved; // reserved for future use.
} VMMDLL_MEM_IO_SCATTER_HEADER, *PVMMDLL_MEM_IO_SCATTER_HEADER, **PPVMMDLL_MEM_IO_SCATTER_HEADER;
/*
* Read memory in various non-contigious locations specified by the pointers to
* the items in the ppDMAs array. Result for each unit of work will be given
@@ -356,7 +292,7 @@ typedef struct tdVMMDLL_MEM_IO_SCATTER_HEADER {
* -- flags = optional flags as given by VMM_FLAG_*
* -- return = the number of successfully read items.
*/
DWORD VMMDLL_MemReadScatter(_In_ DWORD dwPID, _Inout_ PPVMMDLL_MEM_IO_SCATTER_HEADER ppMEMs, _In_ DWORD cpMEMs, _In_ DWORD flags);
DWORD VMMDLL_MemReadScatter(_In_ DWORD dwPID, _Inout_ PPMEM_IO_SCATTER_HEADER ppMEMs, _In_ DWORD cpMEMs, _In_ DWORD flags);
/*
* Read a single 4096-byte page of memory.

Some files were not shown because too many files have changed in this diff Show More