Files
BCompat/main.cpp
2026-03-12 12:07:23 +01:00

1051 lines
40 KiB
C++

#include <iostream>
#include <windows.h>
#include <imagehlp.h>
#include "Zydis/Zydis.h"
#define BCOMPAT_REGISTRY_KEY L"\\Registry\\Machine\\Software\\BCompat\\Functions"
#define FUNCTION_NAME_SIZE 64
#define PATCH_SECTION_SIZE 512
BYTE *buffer;
void printLastError() {
DWORD error = GetLastError();
if (error == ERROR_FILE_NOT_FOUND) {
printf("File not found\n");
} else if (error == ERROR_ACCESS_DENIED) {
printf("Access to file denied\n");
} else {
printf("Error: %lu\n", error);
}
}
int readInt(const DWORD pos) {
return buffer[pos] | buffer[pos + 1] << 8;
}
void writeInt(const DWORD pos, const int value) {
buffer[pos] = value & 0xff;
buffer[pos + 1] = value >> 8;
}
void writeInt(const DWORD pos, LPDWORD offset, const int value) {
writeInt(pos + *offset, value);
*offset += 2;
}
DWORD readDWORD(const DWORD pos) {
return buffer[pos] | buffer[pos + 1] << 8 | buffer[pos + 2] << 16 | buffer[pos + 3] << 24;
}
void writeDWORD(const DWORD pos, const DWORD value) {
buffer[pos] = value & 0xff;
buffer[pos + 1] = value >> 8 & 0xff;
buffer[pos + 2] = value >> 16 & 0xff;
buffer[pos + 3] = value >> 24 & 0xff;
}
void writeDWORD(const DWORD pos, LPDWORD offset, const DWORD value) {
writeDWORD(pos + *offset, value);
*offset += 4;
}
LPSTR readString(DWORD pos) {
int size = 32;
char* string = new char[size];
int i = 0;
while (i == 0 || string[i - 1] != '\0') {
if (i >= size) {
size += 32;
char* newString = new char[size];
memcpy(newString, string, size - 32);
delete[] string;
string = newString;
}
string[i] = buffer[pos + i];
i++;
}
return string;
}
void writeString(const DWORD pos, LPDWORD offset, const char *string) {
DWORD length = strlen(string);
for (int i = 0; i <= length; i++) {
buffer[pos + *offset + i] = string[i];
}
*offset += length + 1;
}
void writeUnicodeString(const DWORD pos, LPDWORD offset, const wchar_t *string) {
DWORD length = wcslen(string) + 1;
for (int i = 0; i < length; i++) {
writeInt(pos, offset, string[i]);
}
}
DWORD getRealAddress(DWORD *virtualAddresses, DWORD *realAddresses, DWORD sectionCount, DWORD address) {
int section = 0;
for (int i = 0; i < sectionCount; ++i) {
if (virtualAddresses[i] <= address) {
section = i;
}
}
return address - virtualAddresses[section] + realAddresses[section];
}
DWORD readAddress(DWORD *virtualAddresses, DWORD *realAddresses, DWORD sectionCount, DWORD pos) {
return getRealAddress(virtualAddresses, realAddresses, sectionCount, readDWORD(pos));
}
DWORD getExportedFunction(DWORD *virtualAddresses, DWORD *realAddresses, DWORD sectionCount, DWORD exportAddressTable, DWORD namePointerTable, DWORD ordinalTable, DWORD functionCount, const char *functionName) {
printf("Locating %s... ", functionName);
WORD ordinal = 0;
for (DWORD i = 0; i < functionCount; i++) {
DWORD namePtr = readAddress(virtualAddresses, realAddresses, sectionCount, namePointerTable + i * 4);
LPSTR name = readString(namePtr);
if (strcmp(name, functionName) == 0) {
ordinal = readInt(ordinalTable + i * 2);
delete[] name;
break;
}
delete[] name;
}
if (ordinal == 0) {
printf("Not found in export table");
delete[] buffer;
exit(1);
}
DWORD function = readDWORD(exportAddressTable + ordinal * 4);
printf("0x%lx\n", function);
return function;
}
DWORD getWrappedFunction(DWORD fileSize, DWORD wrapperFunction, const char *functionName) {
printf("Locating %s... ", functionName);
DWORD function = 0;
{
int i = 0;
ZydisDisassembledInstruction instruction;
while (ZYAN_SUCCESS(ZydisDisassembleIntel(ZYDIS_MACHINE_MODE_LEGACY_32, wrapperFunction + i, buffer + wrapperFunction + i, fileSize - wrapperFunction - i, &instruction))) {
if (instruction.info.mnemonic == ZYDIS_MNEMONIC_CALL) {
if (function != NULL) {
printf("Unexpected code structure");
delete[] buffer;
exit(1);
}
ZyanU64 address;
ZydisCalcAbsoluteAddress(&instruction.info, &instruction.operands[0], wrapperFunction + i, &address);
function = address;
} else if (instruction.info.mnemonic == ZYDIS_MNEMONIC_RET) {
if (function == NULL) {
printf("Could not find CALL");
delete[] buffer;
exit(1);
}
break;
}
i += instruction.info.length;
}
}
printf("0x%lx\n", function);
return function;
}
boolean writeFile(const LPTSTR name, const BYTE *buffer, const DWORD fileSize) {
HANDLE file = CreateFile(name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (file == INVALID_HANDLE_VALUE) {
printLastError();
delete[] buffer;
return false;
}
if (!WriteFile(file, buffer, fileSize, NULL, NULL)) {
printLastError();
CloseHandle(file);
delete[] buffer;
return false;
}
CloseHandle(file);
return true;
}
void writeJumpAddress(const DWORD pos, const DWORD virtualPos, const DWORD target) {
writeDWORD(pos, target - (virtualPos + 4));
}
void writeJumpAddress(const DWORD pos, const DWORD virtualPos, LPDWORD offset, const DWORD target) {
writeJumpAddress(pos + *offset, virtualPos + *offset, target);
*offset += 4;
}
void ensureAlignment(const DWORD pos, LPDWORD offset) {
DWORD i = (pos + *offset) % 4;
if (i > 0) {
*offset += 4 - i;
}
}
int main() {
LPTSTR cmdLine = GetCommandLine();
LPTSTR space = strrchr(cmdLine, ' ');
if (space == NULL) {
printf("Error: No Path provided\n");
return 0;
}
LPTSTR originalFile = space + sizeof(TCHAR);
if (strlen(originalFile) > MAX_PATH - 10 * sizeof(TCHAR)) {
printf("Error: File name is too long\n");
return 1;
}
printf("Copying original file... ");
TCHAR patchedFile[MAX_PATH];
sprintf(patchedFile, "%s.patched", originalFile);
if (!CopyFile(originalFile, patchedFile, FALSE)) {
printLastError();
return 1;
}
printf("Done\n");
printf("Opening file for patching... ");
HANDLE file = CreateFile(patchedFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (file == INVALID_HANDLE_VALUE) {
printLastError();
return 1;
}
DWORD fileSize = GetFileSize(file, NULL);
if (fileSize == INVALID_FILE_SIZE) {
printLastError();
return 1;
}
buffer = new BYTE[fileSize + PATCH_SECTION_SIZE];
DWORD bytesRead;
ReadFile(file, buffer, fileSize, &bytesRead, NULL);
CloseHandle(file);
if (bytesRead != fileSize) {
printLastError();
delete[] buffer;
return 1;
}
fileSize += PATCH_SECTION_SIZE ;
printf("Done\n");
printf("Locating PE Header... ");
if (fileSize < 2 || buffer[0] != 'M' || buffer[1] != 'Z') {
printf("Not a valid DLL (Invalid MZ Header)");
delete[] buffer;
return 1;
}
DWORD peHeader = readDWORD(0x3C);
if (fileSize <= peHeader + 3 || buffer[peHeader] != 'P' || buffer[peHeader + 1] != 'E' || buffer[peHeader + 2] != '\0' || buffer[peHeader + 3] != '\0') {
printf("Not a valid DLL (Invalid PE Header)");
delete[] buffer;
return 1;
}
if (fileSize <= peHeader + 0x19 || readInt(peHeader + 0x18) != 0x10b) {
printf("Unsupported DLL (Not a normal executable)");
delete[] buffer;
return 1;
}
printf("0x%lx\n", peHeader);
printf("Reading Base Image location... ");
DWORD imageBase = readDWORD(peHeader + 0x18 + 28);
printf("0x%lx\n", imageBase);
printf("Locating Sections... ");
DWORD sectionTable = peHeader + 0x18 + 224;
WORD sectionCount = readInt(peHeader + 6);
printf("%u\n", sectionCount);
DWORD virtualAddresses[sectionCount];
DWORD realAddresses[sectionCount];
DWORD realSectionSizes[sectionCount];
DWORD virtualSectionSizes[sectionCount];
for (DWORD i = 0; i < sectionCount; i++) {
LPSTR name = readString(sectionTable + i * 40);
printf("Locating %s Section... ", name);
delete[] name;
DWORD virtualAddress = readDWORD(sectionTable + i * 40 + 12);
DWORD realAddress = readDWORD(sectionTable + i * 40 + 20);
virtualAddresses[i] = virtualAddress;
realAddresses[i] = realAddress;
realSectionSizes[i] = readDWORD(sectionTable + i * 40 + 16);
virtualSectionSizes[i] = readDWORD(sectionTable + i * 40 + 8);
printf("0x%lx / %lu\n", virtualAddress, realAddress);
}
printf("Locating Export Address Table... ");
DWORD exportTable = readAddress(virtualAddresses, realAddresses, sectionCount, peHeader + 0x18 + 96);
printf("0x%lx\n", exportTable);
printf("Reading Export Address Table... ");
DWORD functionCount = readDWORD(exportTable + 24);
DWORD exportAddressTable = readAddress(virtualAddresses, realAddresses, sectionCount, exportTable + 28);
DWORD namePointerTable = readAddress(virtualAddresses, realAddresses, sectionCount, exportTable + 32);
DWORD ordinalTable = readAddress(virtualAddresses, realAddresses, sectionCount, exportTable + 36);
printf("Done\n");
DWORD ldrGetProcedureAddress = getExportedFunction(virtualAddresses, realAddresses, sectionCount,
exportAddressTable, namePointerTable, ordinalTable, functionCount, "LdrGetProcedureAddress");
DWORD ldrpGetProcedureAddress = getWrappedFunction(fileSize, ldrGetProcedureAddress, "LdrpGetProcedureAddress");
DWORD rtlImageDirectoryEntryToData = getExportedFunction(virtualAddresses, realAddresses, sectionCount,
exportAddressTable, namePointerTable, ordinalTable, functionCount, "RtlImageDirectoryEntryToData");
printf("Locating LdrpSnapThunk... ");
DWORD pSnapThunk = 0;
{
int i = 0;
int found = 0;
ZydisDisassembledInstruction instruction;
while (ZYAN_SUCCESS(ZydisDisassembleIntel(ZYDIS_MACHINE_MODE_LEGACY_32, ldrpGetProcedureAddress + i, buffer + ldrpGetProcedureAddress + i, fileSize - ldrpGetProcedureAddress - i, &instruction))) {
if (instruction.info.mnemonic == ZYDIS_MNEMONIC_CALL) {
ZyanU64 address;
ZydisCalcAbsoluteAddress(&instruction.info, &instruction.operands[0], ldrpGetProcedureAddress + i, &address);
if (address == rtlImageDirectoryEntryToData) {
if (found > 0 || pSnapThunk != NULL) {
printf("Unexpected code structure");
delete[] buffer;
return 1;
}
found = 1;
} else if (found == 1) { //__local_unwind2
found++;
} else {
if (found == 2) {
pSnapThunk = address;
}
found = 0;
}
} else if (instruction.info.mnemonic == ZYDIS_MNEMONIC_RET) {
if (pSnapThunk == NULL) {
printf("Could not find CALL");
delete[] buffer;
return 1;
}
break;
}
i += instruction.info.length;
}
}
printf("0x%lx\n", pSnapThunk);
printf("Locating patch point... ");
DWORD patchPoint = 0;
{
int i = 0;
ZydisDisassembledInstruction instruction;
while (ZYAN_SUCCESS(ZydisDisassembleIntel(ZYDIS_MACHINE_MODE_LEGACY_32, pSnapThunk + i, buffer + pSnapThunk + i, fileSize - pSnapThunk - i, &instruction))) {
if (instruction.info.mnemonic == ZYDIS_MNEMONIC_MOV) {
if (instruction.operands[0].mem.disp.value == -20) { //ImportName = ...
patchPoint = instruction.runtime_address + instruction.info.length;
break;
}
} else if (instruction.info.mnemonic == ZYDIS_MNEMONIC_RET) {
printf("Unexpected code structure");
delete[] buffer;
return 1;
}
i += instruction.info.length;
}
}
printf("0x%lx\n", patchPoint);
printf("Checking how many bytes to replace... ");
DWORD targetSize = 5;
DWORD patchSize = 0;
{
int i = 0;
ZydisDisassembledInstruction instruction;
while (ZYAN_SUCCESS(ZydisDisassembleIntel(ZYDIS_MACHINE_MODE_LEGACY_32, patchPoint + i, buffer + patchPoint + i, fileSize - patchPoint - i, &instruction))) {
if (instruction.info.mnemonic == ZYDIS_MNEMONIC_RET) {
printf("Unexpected end of function");
delete[] buffer;
return 1;
}
i += instruction.info.length;
if (i >= targetSize) {
patchSize = i;
break;
}
}
}
printf("%lu\n", patchSize);
printf("Locating LdrpSnapThunk end... ");
DWORD ldrpSnapThunkEnd = 0;
{
int i = 0;
ZydisDisassembledInstruction instruction;
while (ZYAN_SUCCESS(ZydisDisassembleIntel(ZYDIS_MACHINE_MODE_LEGACY_32, pSnapThunk + i, buffer + pSnapThunk + i, fileSize - pSnapThunk - i, &instruction))) {
if (instruction.info.mnemonic == ZYDIS_MNEMONIC_POP) {
if (instruction.operands[0].reg.value == ZYDIS_REGISTER_EDI) { //POP EDI
if (ldrpSnapThunkEnd != NULL) {
printf("Unexpected code structure");
delete[] buffer;
return 1;
}
ldrpSnapThunkEnd = instruction.runtime_address;
}
} else if (instruction.info.mnemonic == ZYDIS_MNEMONIC_RET) {
if (ldrpSnapThunkEnd == NULL) {
printf("Unexpected end of function");
delete[] buffer;
return 1;
}
break;
}
i += instruction.info.length;
}
}
printf("0x%lx\n", ldrpSnapThunkEnd);
printf("Adding .patch section... ");
DWORD freeSpace = realAddresses[sectionCount - 1] + realSectionSizes[sectionCount - 1];
DWORD virtualFreeSpace = virtualAddresses[sectionCount - 1] + virtualSectionSizes[sectionCount - 1];
virtualFreeSpace = virtualFreeSpace + 0x1000 - virtualFreeSpace % 0x1000;
{
writeInt(peHeader + 6, sectionCount + 1);
writeDWORD(peHeader + 0x18 + 56, readDWORD(peHeader + 0x18 + 56) + PATCH_SECTION_SIZE);
DWORD patchSectionHeader = sectionTable + sectionCount * 40;
DWORD i = 0;
writeString(patchSectionHeader, &i, ".patch");
for (int x = 0; x < 7 - strlen(".patch"); x++) {
buffer[patchSectionHeader + i++] = 0x00;
}
writeDWORD(patchSectionHeader, &i, PATCH_SECTION_SIZE);
writeDWORD(patchSectionHeader, &i, virtualFreeSpace);
writeDWORD(patchSectionHeader, &i, PATCH_SECTION_SIZE);
writeDWORD(patchSectionHeader, &i, freeSpace);
writeDWORD(patchSectionHeader, &i, 0);
writeDWORD(patchSectionHeader, &i, 0);
writeInt(patchSectionHeader, &i, 0);
writeInt(patchSectionHeader, &i, 0);
writeDWORD(patchSectionHeader, &i, IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ);
}
printf("0x%lx\n", freeSpace);
DWORD strcmp = getExportedFunction(virtualAddresses, realAddresses, sectionCount,
exportAddressTable, namePointerTable, ordinalTable, functionCount, "strcmp");
DWORD ntOpenKey = getExportedFunction(virtualAddresses, realAddresses, sectionCount,
exportAddressTable, namePointerTable, ordinalTable, functionCount, "NtOpenKey");
DWORD strcpy = getExportedFunction(virtualAddresses, realAddresses, sectionCount,
exportAddressTable, namePointerTable, ordinalTable, functionCount, "strcpy");
DWORD strcat = getExportedFunction(virtualAddresses, realAddresses, sectionCount,
exportAddressTable, namePointerTable, ordinalTable, functionCount, "strcat");
DWORD rtlInitAnsiString = getExportedFunction(virtualAddresses, realAddresses, sectionCount,
exportAddressTable, namePointerTable, ordinalTable, functionCount, "RtlInitAnsiString");
DWORD rtlAnsiStringToUnicodeString = getExportedFunction(virtualAddresses, realAddresses, sectionCount,
exportAddressTable, namePointerTable, ordinalTable, functionCount, "RtlAnsiStringToUnicodeString");
DWORD ntQueryValueKey = getExportedFunction(virtualAddresses, realAddresses, sectionCount,
exportAddressTable, namePointerTable, ordinalTable, functionCount, "NtQueryValueKey");
DWORD ldrLoadDll = getExportedFunction(virtualAddresses, realAddresses, sectionCount,
exportAddressTable, namePointerTable, ordinalTable, functionCount, "LdrLoadDll");
DWORD ldrpLoadDll = getWrappedFunction(fileSize, ldrLoadDll, "LdrpLoadDll");
DWORD rtlInitUnicodeString = getExportedFunction(virtualAddresses, realAddresses, sectionCount,
exportAddressTable, namePointerTable, ordinalTable, functionCount, "RtlInitUnicodeString");
printf("Locating LdrpWalkImportDescriptor... ");
DWORD ldrpWalkImportDescriptor = 0;
{
int i = 0;
int found = 0;
ZydisDisassembledInstruction instruction;
while (ZYAN_SUCCESS(ZydisDisassembleIntel(ZYDIS_MACHINE_MODE_LEGACY_32, ldrpLoadDll + i, buffer + ldrpLoadDll + i, fileSize - ldrpLoadDll - i, &instruction))) {
if (instruction.info.mnemonic == ZYDIS_MNEMONIC_CALL) {
ZyanU64 address;
ZydisCalcAbsoluteAddress(&instruction.info, &instruction.operands[0], ldrpLoadDll + i, &address);
if (address == rtlInitUnicodeString) {
if (found > 0 || ldrpWalkImportDescriptor != NULL) {
printf("Unexpected code structure");
delete[] buffer;
return 1;
}
found = 1;
} else if (found == 1) { //LdrpCheckForLoadedDll
found++;
} else if (found == 2) { //LdrpMapDll
found++;
} else if (found == 3) { //__local_unwind2
found++;
} else {
if (found == 4) {
ldrpWalkImportDescriptor = address;
}
found = 0;
}
} else if (instruction.info.mnemonic == ZYDIS_MNEMONIC_RET) {
if (ldrpWalkImportDescriptor == NULL) {
printf("Could not find CALL");
delete[] buffer;
return 1;
}
break;
}
i += instruction.info.length;
}
}
printf("0x%lx\n", ldrpWalkImportDescriptor);
/*printf("Disabling bound imports... ");
DWORD boundImportsPatch = 0;
{
int i = 0;
ZydisDisassembledInstruction instruction;
while (ZYAN_SUCCESS(ZydisDisassembleIntel(ZYDIS_MACHINE_MODE_LEGACY_32, ldrpWalkImportDescriptor + i, buffer + ldrpWalkImportDescriptor + i, fileSize - ldrpWalkImportDescriptor - i, &instruction))) {
if (instruction.info.mnemonic == ZYDIS_MNEMONIC_MOV) {
if (instruction.operands[0].mem.base == ZYDIS_REGISTER_EBP &&
instruction.operands[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE && instruction.operands[1].imm.value.u == 0) { //stale = false
if (boundImportsPatch != NULL) {
printf("Unexpected code structure");
delete[] buffer;
return 1;
}
boundImportsPatch = ldrpWalkImportDescriptor + i;
}
} else if (instruction.info.mnemonic == ZYDIS_MNEMONIC_RET) {
if (boundImportsPatch == NULL) {
printf("Could not find patch point");
delete[] buffer;
return 1;
}
break;
}
i += instruction.info.length;
}
}
buffer[boundImportsPatch + 3] = 0x01;
printf("0x%lx\n", boundImportsPatch);*/
/*printf("Disabling bound imports... ");
DWORD boundImportsPatch = 0;
{
int i = 0;
ZydisDisassembledInstruction instruction;
while (ZYAN_SUCCESS(ZydisDisassembleIntel(ZYDIS_MACHINE_MODE_LEGACY_32, ldrpWalkImportDescriptor + i, buffer + ldrpWalkImportDescriptor + i, fileSize - ldrpWalkImportDescriptor - i, &instruction))) {
if (instruction.info.mnemonic == ZYDIS_MNEMONIC_CMP) {
if (instruction.operands[0].mem.base == ZYDIS_REGISTER_EBP && instruction.operands[0].mem.disp.value == -2 &&
instruction.operands[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE && instruction.operands[1].imm.value.u == 0) {//stale = false
if (boundImportsPatch != NULL) {
printf("Unexpected code structure");
delete[] buffer;
return 1;
}
boundImportsPatch = ldrpWalkImportDescriptor + i;
}
} else if (instruction.info.mnemonic == ZYDIS_MNEMONIC_RET) {
if (boundImportsPatch == NULL) {
printf("Could not find patch point");
delete[] buffer;
return 1;
}
break;
}
i += instruction.info.length;
}
}
buffer[boundImportsPatch + 6] = 0x90;
buffer[boundImportsPatch + 7] = 0x90;
buffer[boundImportsPatch + 8] = 0x90;
buffer[boundImportsPatch + 9] = 0x90;
buffer[boundImportsPatch + 10] = 0x90;
buffer[boundImportsPatch + 11] = 0x90;
printf("0x%lx\n", boundImportsPatch);*/
DWORD dbgBreakPoint = getExportedFunction(virtualAddresses, realAddresses, sectionCount,
exportAddressTable, namePointerTable, ordinalTable, functionCount, "DbgBreakPoint");
printf("Locating LdrpLoadImportModule... ");
DWORD ldrpLoadImportModule = 0;
{
int i = 0;
bool found = false;
ZydisDisassembledInstruction instruction;
while (ZYAN_SUCCESS(ZydisDisassembleIntel(ZYDIS_MACHINE_MODE_LEGACY_32, ldrpWalkImportDescriptor + i, buffer + ldrpWalkImportDescriptor + i, fileSize - ldrpWalkImportDescriptor - i, &instruction))) {
if (instruction.info.mnemonic == ZYDIS_MNEMONIC_CALL) {
ZyanU64 address;
ZydisCalcAbsoluteAddress(&instruction.info, &instruction.operands[0], ldrpWalkImportDescriptor + i, &address);
if (address == dbgBreakPoint) {
if (found || ldrpLoadImportModule != NULL) {
printf("Unexpected code structure");
delete[] buffer;
return 1;
}
found = true;
} else if (found) {
ldrpLoadImportModule = address;
found = false;
}
} else if (instruction.info.mnemonic == ZYDIS_MNEMONIC_RET) {
if (ldrpLoadImportModule == NULL) {
printf("Could not find CALL");
delete[] buffer;
return 1;
}
break;
}
i += instruction.info.length;
}
}
printf("0x%lx\n", ldrpLoadImportModule);
DWORD ntCurrentTeb = getExportedFunction(virtualAddresses, realAddresses, sectionCount,
exportAddressTable, namePointerTable, ordinalTable, functionCount, "NtCurrentTeb");
printf("Patching free space... ");
DWORD patchEntrypointAddress;
{
DWORD i = 0;
//ADD ESP, 0x4
buffer[freeSpace + i++] = 0x83;
buffer[freeSpace + i++] = 0xc4;
buffer[freeSpace + i++] = 0x04;
//ADD ESP, 0x4
buffer[freeSpace + i++] = 0x83;
buffer[freeSpace + i++] = 0xc4;
buffer[freeSpace + i++] = 0x04;
DWORD patchEnd = virtualFreeSpace + i;
//POP EDI
buffer[freeSpace + i++] = 0x5f;
//POP ESI
buffer[freeSpace + i++] = 0x5e;
//POP EAX
buffer[freeSpace + i++] = 0x58;
for (int x = 0; x < patchSize; x++) {
buffer[freeSpace + i++] = buffer[patchPoint + x];
}
//JMP
buffer[freeSpace + i++] = 0xe9;
writeJumpAddress(freeSpace, virtualFreeSpace, &i, patchPoint + patchSize);
patchEntrypointAddress = virtualFreeSpace + i;
//PUSH EAX
buffer[freeSpace + i++] = 0x50;
//PUSH ESI
buffer[freeSpace + i++] = 0x56;
//PUSH EDI
buffer[freeSpace + i++] = 0x57;
//MOV EAX, DllName
buffer[freeSpace + i++] = 0x8b;
buffer[freeSpace + i++] = 0x45;
buffer[freeSpace + i++] = 0x24;
//TEST EAX EAX
buffer[freeSpace + i++] = 0x85;
buffer[freeSpace + i++] = 0xc0;
//JZ PatchEnd
buffer[freeSpace + i++] = 0x0f;
buffer[freeSpace + i++] = 0x84;
writeJumpAddress(freeSpace, virtualFreeSpace, &i, patchEnd);
//JMP over "bcompat.dll"
buffer[freeSpace + i++] = 0xe9;
DWORD jumpPos = freeSpace + i;
i += 4;
DWORD dllString = virtualFreeSpace + i;
writeString(freeSpace, &i, "bcompat.dll");
writeJumpAddress(jumpPos, jumpPos, freeSpace + i);
//PUSH "bcompat.dll"
buffer[freeSpace + i++] = 0x68;
writeDWORD(freeSpace, &i, imageBase + dllString);
//PUSH EAX
buffer[freeSpace + i++] = 0x50;
//CALL strcmp
buffer[freeSpace + i++] = 0xe8;
writeJumpAddress(freeSpace, virtualFreeSpace, &i, strcmp);
//ADD ESP, 8
buffer[freeSpace + i++] = 0x83;
buffer[freeSpace + i++] = 0xc4;
buffer[freeSpace + i++] = 0x08;
//TEST EAX EAX
buffer[freeSpace + i++] = 0x85;
buffer[freeSpace + i++] = 0xc0;
//JZ PatchEnd
buffer[freeSpace + i++] = 0x0f;
buffer[freeSpace + i++] = 0x84;
writeJumpAddress(freeSpace, virtualFreeSpace, &i, patchEnd);
//JMP over
buffer[freeSpace + i++] = 0xe9;
jumpPos = freeSpace + i;
i += 4;
ensureAlignment(freeSpace, &i);
DWORD keyName = virtualFreeSpace + i;
writeUnicodeString(freeSpace, &i, BCOMPAT_REGISTRY_KEY);
//UNICODE_STRING
ensureAlignment(freeSpace, &i);
DWORD keyString = virtualFreeSpace + i;
buffer[freeSpace + i++] = wcslen(BCOMPAT_REGISTRY_KEY) * sizeof(wchar_t); //Length
buffer[freeSpace + i++] = 0x00;
buffer[freeSpace + i++] = (wcslen(BCOMPAT_REGISTRY_KEY) + 1) * sizeof(wchar_t); //MaximumLength
buffer[freeSpace + i++] = 0x00;
writeDWORD(freeSpace, &i, imageBase + keyName); //Buffer
//OBJECT_ATTRIBUTES
DWORD objectAttributes = virtualFreeSpace + i;
writeDWORD(freeSpace, &i, 0x18); //Length
writeDWORD(freeSpace, &i, 0x00); //RootDirectory
writeDWORD(freeSpace, &i, imageBase + keyString); //ObjectName
writeDWORD(freeSpace, &i, 0x40); //Attributes
writeDWORD(freeSpace, &i, 0x00); //SecurityDescriptor
writeDWORD(freeSpace, &i, 0x00); //SecurityQualityOfService
writeJumpAddress(jumpPos, jumpPos, freeSpace + i);
//SUB ESP, 4
buffer[freeSpace + i++] = 0x83;
buffer[freeSpace + i++] = 0xec;
buffer[freeSpace + i++] = 0x04;
//LEA EAX, [ESP]
buffer[freeSpace + i++] = 0x8d;
buffer[freeSpace + i++] = 0x04;
buffer[freeSpace + i++] = 0x24;
//PUSH POBJECT_ATTRIBUTES
buffer[freeSpace + i++] = 0x68;
writeDWORD(freeSpace, &i, imageBase + objectAttributes);
//PUSH 0x20019
buffer[freeSpace + i++] = 0x68;
writeDWORD(freeSpace, &i, 0x20019);
//PUSH EAX
buffer[freeSpace + i++] = 0x50;
//CALL NtOpenKey
buffer[freeSpace + i++] = 0xe8;
writeJumpAddress(freeSpace, virtualFreeSpace, &i, ntOpenKey);
//TEST EAX EAX
buffer[freeSpace + i++] = 0x85;
buffer[freeSpace + i++] = 0xc0;
//JS PatchEnd
buffer[freeSpace + i++] = 0x0f;
buffer[freeSpace + i++] = 0x88;
writeJumpAddress(freeSpace, virtualFreeSpace, &i, patchEnd - 3);
//SUB ESP, FUNCTION_NAME_SIZE
buffer[freeSpace + i++] = 0x83;
buffer[freeSpace + i++] = 0xec;
buffer[freeSpace + i++] = FUNCTION_NAME_SIZE;
//LEA ESI, [ESP]
buffer[freeSpace + i++] = 0x8d;
buffer[freeSpace + i++] = 0x34;
buffer[freeSpace + i++] = 0x24;
//MOV EAX, [DllName]
buffer[freeSpace + i++] = 0x8b;
buffer[freeSpace + i++] = 0x45;
buffer[freeSpace + i++] = 0x24;
//PUSH EAX
buffer[freeSpace + i++] = 0x50;
//PUSH ESI
buffer[freeSpace + i++] = 0x56;
//CALL strcpy
buffer[freeSpace + i++] = 0xe8;
writeJumpAddress(freeSpace, virtualFreeSpace, &i, strcpy);
//ADD ESP, 8
buffer[freeSpace + i++] = 0x83;
buffer[freeSpace + i++] = 0xc4;
buffer[freeSpace + i++] = 0x08;
//MOV EAX, [ImportName]
buffer[freeSpace + i++] = 0x8b;
buffer[freeSpace + i++] = 0x45;
buffer[freeSpace + i++] = 0xec;
//PUSH EAX
buffer[freeSpace + i++] = 0x50;
//PUSH ESI
buffer[freeSpace + i++] = 0x56;
//CALL strcat
buffer[freeSpace + i++] = 0xe8;
writeJumpAddress(freeSpace, virtualFreeSpace, &i, strcat);
//ADD ESP, 8
buffer[freeSpace + i++] = 0x83;
buffer[freeSpace + i++] = 0xc4;
buffer[freeSpace + i++] = 0x08;
//SUB ESP, 8
buffer[freeSpace + i++] = 0x83;
buffer[freeSpace + i++] = 0xec;
buffer[freeSpace + i++] = 0x08;
//LEA EDI, [ESP]
buffer[freeSpace + i++] = 0x8d;
buffer[freeSpace + i++] = 0x3c;
buffer[freeSpace + i++] = 0x24;
//PUSH ESI
buffer[freeSpace + i++] = 0x56;
//PUSH EDI
buffer[freeSpace + i++] = 0x57;
//CALL RtlInitAnsiString
buffer[freeSpace + i++] = 0xe8;
writeJumpAddress(freeSpace, virtualFreeSpace, &i, rtlInitAnsiString);
//SUB ESP, 8
buffer[freeSpace + i++] = 0x83;
buffer[freeSpace + i++] = 0xec;
buffer[freeSpace + i++] = 0x08;
//LEA EAX, [ESP]
buffer[freeSpace + i++] = 0x8d;
buffer[freeSpace + i++] = 0x04;
buffer[freeSpace + i++] = 0x24;
//PUSH 1
buffer[freeSpace + i++] = 0x6a;
buffer[freeSpace + i++] = 0x01;
//PUSH EDI
buffer[freeSpace + i++] = 0x57;
//PUSH EAX
buffer[freeSpace + i++] = 0x50;
//CALL RtlAnsiStringToUnicodeString
buffer[freeSpace + i++] = 0xe8;
writeJumpAddress(freeSpace, virtualFreeSpace, &i, rtlAnsiStringToUnicodeString);
//MOV EDI, [ESP+0x50]
buffer[freeSpace + i++] = 0x8b;
buffer[freeSpace + i++] = 0x7c;
buffer[freeSpace + i++] = 0x24;
buffer[freeSpace + i++] = 0x50;
//SUB ESP, 4
buffer[freeSpace + i++] = 0x83;
buffer[freeSpace + i++] = 0xec;
buffer[freeSpace + i++] = 0x04;
//LEA EAX, [ESP]
buffer[freeSpace + i++] = 0x8d;
buffer[freeSpace + i++] = 0x04;
buffer[freeSpace + i++] = 0x24;
//PUSH EAX
buffer[freeSpace + i++] = 0x50;
//PUSH 0
buffer[freeSpace + i++] = 0x6a;
buffer[freeSpace + i++] = 0x00;
//PUSH 0
buffer[freeSpace + i++] = 0x6a;
buffer[freeSpace + i++] = 0x00;
//PUSH 0
buffer[freeSpace + i++] = 0x6a;
buffer[freeSpace + i++] = 0x00;
//LEA EAX, [ESP+0x14]
buffer[freeSpace + i++] = 0x8d;
buffer[freeSpace + i++] = 0x44;
buffer[freeSpace + i++] = 0x24;
buffer[freeSpace + i++] = 0x14;
//PUSH EAX
buffer[freeSpace + i++] = 0x50;
//PUSH EDI
buffer[freeSpace + i++] = 0x57;
//CALL NtQueryValueKey
buffer[freeSpace + i++] = 0xe8;
writeJumpAddress(freeSpace, virtualFreeSpace, &i, ntQueryValueKey);
//ADD ESP, 0x58
buffer[freeSpace + i++] = 0x83;
buffer[freeSpace + i++] = 0xc4;
buffer[freeSpace + i++] = FUNCTION_NAME_SIZE + 0x18;
//CMP EAX, 0xc0000023
buffer[freeSpace + i++] = 0x3d;
buffer[freeSpace + i++] = 0x23;
buffer[freeSpace + i++] = 0x00;
buffer[freeSpace + i++] = 0x00;
buffer[freeSpace + i++] = 0xc0;
//JNZ PatchEnd
buffer[freeSpace + i++] = 0x0f;
buffer[freeSpace + i++] = 0x85;
writeJumpAddress(freeSpace, virtualFreeSpace, &i, patchEnd);
//SUB ESP, 0x8
buffer[freeSpace + i++] = 0x83;
buffer[freeSpace + i++] = 0xec;
buffer[freeSpace + i++] = 0x08;
//LEA EDI, [ESP]
buffer[freeSpace + i++] = 0x8d;
buffer[freeSpace + i++] = 0x3c;
buffer[freeSpace + i++] = 0x24;
//LEA EAX, [ESP+0x4]
buffer[freeSpace + i++] = 0x8d;
buffer[freeSpace + i++] = 0x44;
buffer[freeSpace + i++] = 0x24;
buffer[freeSpace + i++] = 0x04;
//PUSH EAX
buffer[freeSpace + i++] = 0x50;
//PUSH EDI
buffer[freeSpace + i++] = 0x57;
//MOV EAX, ImportBase
buffer[freeSpace + i++] = 0x8b;
buffer[freeSpace + i++] = 0x45;
buffer[freeSpace + i++] = 0xc;
//PUSH EAX
buffer[freeSpace + i++] = 0x50;
//PUSH "bcompat.dll"
buffer[freeSpace + i++] = 0x68;
writeDWORD(freeSpace, &i, imageBase + dllString);
//PUSH 0
buffer[freeSpace + i++] = 0x6a;
buffer[freeSpace + i++] = 0x00;
//CALL LdrpLoadImportModule
buffer[freeSpace + i++] = 0xe8;
writeJumpAddress(freeSpace, virtualFreeSpace, &i, ldrpLoadImportModule);
//MOV EDI, [ESP]
buffer[freeSpace + i++] = 0x8b;
buffer[freeSpace + i++] = 0x3c;
buffer[freeSpace + i++] = 0x24;
//TEST EAX EAX
buffer[freeSpace + i++] = 0x85;
buffer[freeSpace + i++] = 0xc0;
//JS PatchEnd
buffer[freeSpace + i++] = 0x0f;
buffer[freeSpace + i++] = 0x88;
writeJumpAddress(freeSpace, virtualFreeSpace, &i, patchEnd - 6);
//CMP byte ptr [ESP+0x4], 0
buffer[freeSpace + i++] = 0x80;
buffer[freeSpace + i++] = 0x7c;
buffer[freeSpace + i++] = 0x24;
buffer[freeSpace + i++] = 0x04;
buffer[freeSpace + i++] = 0x00;
//ADD ESP, 0x8
buffer[freeSpace + i++] = 0x83;
buffer[freeSpace + i++] = 0xc4;
buffer[freeSpace + i++] = 0x08;
//ADD EDI, 0x10
buffer[freeSpace + i++] = 0x83;
buffer[freeSpace + i++] = 0xc7;
buffer[freeSpace + i++] = 0x10;
//JZ SKIP_INIT
buffer[freeSpace + i++] = 0x0f;
buffer[freeSpace + i++] = 0x84;
jumpPos = freeSpace + i;
i += 4;
//CALL NtCurrentTeb
buffer[freeSpace + i++] = 0xe8;
writeJumpAddress(freeSpace, virtualFreeSpace, &i, ntCurrentTeb);
//MOV ESI, [EAX + 0x30] //PEB
buffer[freeSpace + i++] = 0x8b;
buffer[freeSpace + i++] = 0x70;
buffer[freeSpace + i++] = 0x30;
//MOV ESI, [ESI + 0xc] //Ldr
buffer[freeSpace + i++] = 0x8b;
buffer[freeSpace + i++] = 0x76;
buffer[freeSpace + i++] = 0x0c;
//ADD ESI, 0x1c //InInitializationOrderModuleList
buffer[freeSpace + i++] = 0x83;
buffer[freeSpace + i++] = 0xc6;
buffer[freeSpace + i++] = 0x1c;
//MOV EAX, [ESI + 0x4]
buffer[freeSpace + i++] = 0x8b;
buffer[freeSpace + i++] = 0x46;
buffer[freeSpace + i++] = 0x04;
//MOV [EDI], ESI
buffer[freeSpace + i++] = 0x89;
buffer[freeSpace + i++] = 0x37;
//MOV [EDI + 0x4], EAX
buffer[freeSpace + i++] = 0x89;
buffer[freeSpace + i++] = 0x47;
buffer[freeSpace + i++] = 0x04;
//MOV [EAX], EDI
buffer[freeSpace + i++] = 0x89;
buffer[freeSpace + i++] = 0x38;
//MOV [ESI + 0x4], EDI
buffer[freeSpace + i++] = 0x89;
buffer[freeSpace + i++] = 0x7e;
buffer[freeSpace + i++] = 0x04;
writeJumpAddress(jumpPos, jumpPos, freeSpace + i);
//SUB ESP, 0x4
buffer[freeSpace + i++] = 0x83;
buffer[freeSpace + i++] = 0xec;
buffer[freeSpace + i++] = 0x04;
//LEA EAX, [ESP]
buffer[freeSpace + i++] = 0x8d;
buffer[freeSpace + i++] = 0x04;
buffer[freeSpace + i++] = 0x24;
//PUSH EAX
buffer[freeSpace + i++] = 0x50;
//PUSH 0
buffer[freeSpace + i++] = 0x6a;
buffer[freeSpace + i++] = 0x00;
//PUSH 1
buffer[freeSpace + i++] = 0x6a;
buffer[freeSpace + i++] = 0x01;
//ADD EDI, 0x8 //DllBase
buffer[freeSpace + i++] = 0x83;
buffer[freeSpace + i++] = 0xc7;
buffer[freeSpace + i++] = 0x08;
//mov EDI, [EDI]
buffer[freeSpace + i++] = 0x8b;
buffer[freeSpace + i++] = 0x3f;
//PUSH EDI
buffer[freeSpace + i++] = 0x57;
//CALL RtlImageDirectoryEntryToData
buffer[freeSpace + i++] = 0xe8;
writeJumpAddress(freeSpace, virtualFreeSpace, &i, rtlImageDirectoryEntryToData);
//MOV ESI, [ESP]
buffer[freeSpace + i++] = 0x8b;
buffer[freeSpace + i++] = 0x34;
buffer[freeSpace + i++] = 0x24;
//PUSH "bcompat.dll"
buffer[freeSpace + i++] = 0x68;
writeDWORD(freeSpace, &i, imageBase + dllString);
//PUSH StaticSnap
buffer[freeSpace + i++] = 0xff;
buffer[freeSpace + i++] = 0x75;
buffer[freeSpace + i++] = 0x20;
//PUSH ESI
buffer[freeSpace + i++] = 0x56,
//PUSH EAX
buffer[freeSpace + i++] = 0x50;
//PUSH Thunk
buffer[freeSpace + i++] = 0xff;
buffer[freeSpace + i++] = 0x75;
buffer[freeSpace + i++] = 0x14;
//PUSH OriginalThunk
buffer[freeSpace + i++] = 0xff;
buffer[freeSpace + i++] = 0x75;
buffer[freeSpace + i++] = 0x10;
//PUSH ImageBase
buffer[freeSpace + i++] = 0xff;
buffer[freeSpace + i++] = 0x75;
buffer[freeSpace + i++] = 0x0c;
//PUSH EDI
buffer[freeSpace + i++] = 0x57;
//CALL LdrpSnapThunk
buffer[freeSpace + i++] = 0xe8;
writeJumpAddress(freeSpace, virtualFreeSpace, &i, pSnapThunk);
//buffer[freeSpace + i++] = 0xcc;
//ADD ESP, 0x4
buffer[freeSpace + i++] = 0x83;
buffer[freeSpace + i++] = 0xc4;
buffer[freeSpace + i++] = 0x04;
//POP EDI
buffer[freeSpace + i++] = 0x5f;
//POP ESI
buffer[freeSpace + i++] = 0x5e;
//POP EAX
buffer[freeSpace + i++] = 0x58;
//buffer[freeSpace + i++] = 0xcc;
//JMP LdrpSnapThunk - End
buffer[freeSpace + i++] = 0xe9;
writeJumpAddress(freeSpace, virtualFreeSpace, &i, ldrpSnapThunkEnd);
printf("Done (%lu Bytes left)\n", PATCH_SECTION_SIZE - i);
}
printf("Patching LdrpSnapThunk... ");
buffer[patchPoint] = 0xe9;
writeJumpAddress(patchPoint + 1, patchPoint + 1, patchEntrypointAddress);
for (int i = 5; i < patchSize; i++) {
buffer[patchPoint + i] = 0x90;
}
printf("Done\n");
printf("Writing to patched file... ");
if (!writeFile(patchedFile, buffer, fileSize)) {
return 1;
}
printf("Done\n");
printf("Generating checksum... ");
DWORD originalChecksum;
DWORD checksum;
if (MapFileAndCheckSum(patchedFile, &originalChecksum, &checksum) != CHECKSUM_SUCCESS) {
printLastError();
return 1;
}
printf("0x%lx\n", checksum);
printf("Writing checksum to patched file... ");
writeDWORD(peHeader + 0x18 + 64, checksum);
if (!writeFile(patchedFile, buffer, fileSize)) {
return 1;
}
printf("Finished\n");
delete[] buffer;
return 0;
}