#include #include #include #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; }