#include #include #include 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; } 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; } 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; } 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)); } 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; } 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]; DWORD bytesRead; ReadFile(file, buffer, fileSize, &bytesRead, NULL); CloseHandle(file); if (bytesRead != fileSize) { printLastError(); delete[] buffer; return 1; } 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("Locating Sections... "); DWORD sectionTable = peHeader + 0x18 + 224; WORD sectionCount = readInt(peHeader + 6); printf("%u\n", sectionCount); DWORD virtualAddresses[sectionCount]; DWORD realAddresses[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; 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 exportsCount = readDWORD(exportTable + 20); 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); if (exportsCount != functionCount) { printf("DLL already contains ordinal exports"); delete[] buffer; return 1; } printf("Done\n"); printf("Patching Ordinals... "); DWORD ordinalBase = -1; DWORD ordinalEnd = 0; DWORD exportAddresses[exportsCount]; for (int i = 0; i < functionCount; ++i) { DWORD namePtr = readAddress(virtualAddresses, realAddresses, sectionCount, namePointerTable + i * 4); LPSTR name = readString(namePtr); if (strstr(name, "ordinal") == name) { DWORD ordinal = std::stoi(name + 7); if (ordinal < ordinalBase) { ordinalBase = ordinal; } if (ordinal > ordinalEnd) { ordinalEnd = ordinal; } } exportAddresses[i] = readDWORD(exportAddressTable + i * 4); writeDWORD(exportAddressTable + i * 4, NULL); delete[] name; } for (int i = 0; i < functionCount; ++i) { DWORD namePtr = readAddress(virtualAddresses, realAddresses, sectionCount, namePointerTable + i * 4); LPSTR name = readString(namePtr); DWORD realOrdinal; if (strstr(name, "ordinal") == name) { DWORD ordinal = std::stoi(name + 7); DWORD stringAddr = /*readAddress(virtualAddresses, realAddresses, sectionCount, */exportAddresses[i] - (readDWORD(peHeader + 0x18 + 96) - exportTable);//); LPSTR forwardString = readString(stringAddr); char* delimiter = strchr(forwardString, '.'); if (delimiter == NULL) { printf("Ordinal Forward String has unexpected format"); delete[] buffer; return 1; } buffer[stringAddr + (delimiter - forwardString) + 1] = '#'; delete[] forwardString; realOrdinal = ordinal - ordinalBase; } else if (strstr(name, "_ordFiller") == name) { writeInt(ordinalTable + i * 2, 0); delete[] name; continue; } else { ordinalEnd++; realOrdinal = ordinalEnd - ordinalBase; } writeInt(ordinalTable + i * 2, realOrdinal); writeDWORD(exportAddressTable + realOrdinal * 4, exportAddresses[i]); delete[] name; } writeDWORD(exportTable + 16, ordinalBase); 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; }