#include #include #include #include // lowercases a string (used by processbyname) void makelower(char* string) { DWORD x; for (x = 0; x < strlen(string); x++) if ((string[x] >= 'A') && (string[x] <= 'Z')) string[x] += ('a' - 'A'); } // this function opens a process by name rather than by pid. // input name must be all lowercase. HANDLE processbyname(const char* name) { DWORD pid; PROCESSENTRY32 pe; pe.dwSize = sizeof(PROCESSENTRY32); int x; HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (Process32First(snap, &pe)) { do { for (x = strlen(pe.szExeFile); x >= 0; x--) if (pe.szExeFile[x] == '\\') break; makelower(pe.szExeFile); if (!strcmp(&pe.szExeFile[x + 1], name)) pid = pe.th32ProcessID; } while (Process32Next(snap, &pe)); } CloseHandle(snap); return OpenProcess(PROCESS_ALL_ACCESS, false, pid); } typedef struct { char name[8]; DWORD virtualSize; DWORD virtualOffset; DWORD fileSize; DWORD fileOffset; DWORD relocations; DWORD lineNumbers; WORD numRelocations; WORD numLineNumbers; DWORD flags; } OBJINFO; int __stdcall WinMain(HINSTANCE hInst, HINSTANCE, char* cmd, int) { printf("> anti-gameguard psobb launcher\n\n"); // variables.... STARTUPINFO si; PROCESS_INFORMATION pi; HWND window = NULL; DWORD bytesread; ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); // delete the GameGuard folder to make it re-download itself printf("> deleting gameguard folder\n"); SHFILEOPSTRUCT fileop; fileop.hwnd = NULL; fileop.wFunc = FO_DELETE; fileop.pFrom = "GameGuard\0\0"; fileop.pTo = NULL; fileop.fFlags = FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT; SHFileOperation(&fileop); // launch online.exe printf("> running online.exe\n"); if (!CreateProcess("online.exe", NULL, NULL, NULL, false, DETACHED_PROCESS, NULL, NULL, &si, &pi)) return -1; WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); // open psobb.exe printf("> finding psobb.exe\n"); pi.hProcess = processbyname("psobb.exe"); if (!pi.hProcess) return -1; // find the PE header DWORD imageBase = 0x00400000; DWORD peHeaderOffset; // [imageBase + 0x3C] if (ReadProcessMemory(pi.hProcess, (void*)(imageBase + 0x3C), &peHeaderOffset, 4, &bytesread) == 0) return -1; printf("> pe header at %08lX\n", peHeaderOffset); // check the PE sig and read a few fields DWORD peSignature; // [imageBase + peHeaderOffset] WORD numSections; // [imageBase + peHeaderOffset + 6] WORD optHeaderSize; // [imageBase + peHeaderOffset + 20] if (ReadProcessMemory(pi.hProcess, (void*)(imageBase + peHeaderOffset), &peSignature, 4, &bytesread) == 0) return -1; if (ReadProcessMemory(pi.hProcess, (void*)(imageBase + peHeaderOffset + 6), &numSections, 2, &bytesread) == 0) return -1; if (ReadProcessMemory(pi.hProcess, (void*)(imageBase + peHeaderOffset + 20), &optHeaderSize, 2, &bytesread) == 0) return -1; printf("> signature %08lX, number of sections %04X, header size %04X\n", peSignature, numSections, optHeaderSize); // read the section headers DWORD x, y, z; OBJINFO objectHeaders[numSections]; // [imageBase + peHeaderOffset + optHeaderSize + 0x18] if (ReadProcessMemory(pi.hProcess, (void*)(imageBase + peHeaderOffset + optHeaderSize + 0x18), &objectHeaders, sizeof(OBJINFO) * numSections, &bytesread) == 0) return -1; for (x = 0; x < numSections; x++) printf("> section %lu \"%-8.8s\": mem %08lX:%08lX, file %08lX:%08lX\n", x, objectHeaders[x].name, objectHeaders[x].virtualOffset + imageBase, objectHeaders[x].virtualSize, objectHeaders[x].fileOffset, objectHeaders[x].fileSize); // get gameguard window printf("> finding GameGuard window\n"); RECT rc1,rc2 = {0, 0, 210, 113}; POINT pt = {10, 10}; char classname[MAX_PATH]; x = 0; while (!window) { window = WindowFromPoint(pt); GetClassName(window, classname, MAX_PATH); GetWindowRect(window, &rc1); if (strcmp(classname, "#32770")) window = NULL; if (memcmp(&rc1, &rc2, sizeof(RECT))) window = NULL; Sleep(50); x++; if (x > 80) return -1; // 4 seconds } // patterns to find/replace // the find mask indicates what should be compared - effectively, an 0x00 // means that the corresponding byte may be anything in the target process. // an 0x00 in the replace mask means that the corresponding byte is not // modified in the replace phase. BYTE findPatt[] = {0x55, 0x07, 0x00, 0x00, 0x0F, 0x85, 0x00, 0x00, 0x00, 0x00}; BYTE findMask[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF}; BYTE repPatt[] = {0x55, 0x07, 0x00, 0x00, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; BYTE repMask[] = {0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; // keep trying until psobb.exe is decompressed DWORD startTime = GetTickCount(); DWORD numMatches = 0; printf("> searching for patch locations\n"); while ((GetTickCount() < startTime + 10000) && !numMatches) { // search for matches in each section for (x = 0; x < numSections; x++) { // read the section data BYTE* data = (BYTE*)malloc(objectHeaders[x].virtualSize); if (ReadProcessMemory(pi.hProcess, (void*)(imageBase + objectHeaders[x].virtualOffset), data, objectHeaders[x].virtualSize, &bytesread) == 0) return -1; // search the section for the pattern for (y = 0; y < objectHeaders[x].virtualSize - sizeof(findPatt); y++) { for (z = 0; z < sizeof(findPatt); z++) if ((data[y + z] & findMask[z]) != (findPatt[z] & findMask[z])) break; if (z != sizeof(findPatt)) continue; // found a match; apply the patch! for (z = 0; z < sizeof(repPatt); z++) data[y + z] = (data[y + z] & ~repMask[z]) | (repPatt[z] & repMask[z]); if (WriteProcessMemory(pi.hProcess, (void*)(imageBase + objectHeaders[x].virtualOffset + y), &data[y], sizeof(repPatt), &bytesread) == 0) return -1; printf("> pattern found in section %lu, offset %08lX (abs %08lX)\n", x, y, imageBase + objectHeaders[x].virtualOffset + y); numMatches++; } free(data); } Sleep(0); } // close gameguard printf("> closing GameGuard window\n"); SendMessage(window,WM_COMMAND,0x000003EE,(long)GetDlgItem(window,0x000003EE)); CloseHandle(pi.hProcess); return 0; }