263 lines
8.6 KiB
C++
263 lines
8.6 KiB
C++
#include <iostream>
|
|
#include <windows.h>
|
|
#include <imagehlp.h>
|
|
|
|
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;
|
|
}
|