VOID scanSendChatMessage_ScanProc(INT iItem, HWND hwndDlg, PBYTE pbFile) { PIMAGE_NT_HEADERS pNtHdr = PIMAGE_NT_HEADERS(pbFile + PIMAGE_DOS_HEADER(pbFile)->e_lfanew); PIMAGE_SECTION_HEADER pSecHdr = PIMAGE_SECTION_HEADER(pNtHdr + 1); PBYTE pbCode = RvaToPointer(pbFile, pSecHdr[0].VirtualAddress); DWORD dwCodeSize = pSecHdr[0].SizeOfRawData; PBYTE pbRData = RvaToPointer(pbFile, pSecHdr[1].VirtualAddress); DWORD dwRDataSize = pSecHdr[1].SizeOfRawData; PBYTE pbData = RvaToPointer(pbFile, pSecHdr[2].VirtualAddress); DWORD dwDataSize = pSecHdr[2].SizeOfRawData; SetItemStatus(iItem, hwndDlg, "Scanning..."); // scan data section for "Unknown chat type" for(DWORD dwDataIndex = 0; dwDataIndex < dwDataSize - (sizeof("Unknown chat type") - 1); dwDataIndex++) { if(MemoryCompare(&pbData[dwDataIndex], (PBYTE)"Unknown chat type", sizeof("Unknown chat type") - 1)) { // calculate va of found string DWORD dwStringVA = OffsetToRva(pbFile, PtrToUlong(pbData) + dwDataIndex - PtrToUlong(pbFile)); if(dwStringVA) { dwStringVA += pNtHdr->OptionalHeader.ImageBase; // scan code section for 'push dwStringVA' for(DWORD dwCodeIndex = 0; dwCodeIndex < dwCodeSize - 8; dwCodeIndex++) { if(pbCode[dwCodeIndex] == 0x68 && *((PDWORD)&pbCode[dwCodeIndex + 1]) == dwStringVA) { // find beginning of procedure for(DWORD dwCodeIndex2 = dwCodeIndex & 0xFFFFFFF0; dwCodeIndex2; dwCodeIndex2 -= 0x10) { if(pbCode[dwCodeIndex2 - 1] == 0x90 || pbCode[dwCodeIndex2 - 1] == 0xC3 || pbCode[dwCodeIndex2 - 3] == 0xC2) { DWORD dwProcRva = OffsetToRva(pbFile, PtrToUlong(pbCode) + dwCodeIndex2 - PtrToUlong(pbFile)); if(dwProcRva) { GetPPD(iItem, hwndDlg)->dwValue = dwProcRva + pNtHdr->OptionalHeader.ImageBase; SetItemStatus(iItem, hwndDlg, "Success"); return; } } } } } } } } GetPPD(iItem, hwndDlg)->dwValue = 0; SetItemStatus(iItem, hwndDlg, "Fail"); }
BOOL CRemoteLoader::ProcessTlsEntries( PVOID BaseAddress, PVOID RemoteAddress ) { IMAGE_NT_HEADERS* ImageNtHeaders = ToNts( BaseAddress ); if( ImageNtHeaders == NULL ) return FALSE; if( ImageNtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_TLS ].Size == 0 ) return TRUE; // Success when there is no Tls Entries DebugShout( "[ProcessTlsEntries] Tls Data detected!" ); IMAGE_TLS_DIRECTORY* TlsDirectory = ( IMAGE_TLS_DIRECTORY* ) RvaToPointer( ImageNtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_TLS ].VirtualAddress, BaseAddress ); if( TlsDirectory == NULL ) return TRUE; // Success when there is no Tls entries / broken data? DebugShout( "[ProcessTlsEntries] TlsDirectory (0x%X)", TlsDirectory ); if( TlsDirectory->AddressOfCallBacks == NULL ) return TRUE; // Success when there is no Tls entries / broken data? DebugShout( "[ProcessTlsEntries] TlsDirectory->AddressOfCallBacks (0x%X)", TlsDirectory->AddressOfCallBacks ); PIMAGE_TLS_CALLBACK TLSCallbacks[ 0xFF ]; if( ReadProcessMemory( GetProcess(), ( LPCVOID ) TlsDirectory->AddressOfCallBacks, TLSCallbacks, sizeof( TLSCallbacks ), NULL ) == FALSE ) { DebugShout( "[ProcessTlsEntries] Failed ReadProcessMemory" ); return FALSE; } BOOL SuccessValue = TRUE; for( int i = 0; TLSCallbacks[i]; i++ ) { DebugShout( "[ProcessTlsEntries] TLSCallbacks[%i] = 0x%X (0x%X)", i, TLSCallbacks[i], RemoteAddress ); // As a consequence of the relocation stuff mentioned above, pCallbacks[i] is already fixed if( CallEntryPoint( RemoteAddress, ( FARPROC ) TLSCallbacks[i] ) == false ) { DebugShout( "[ProcessTlsEntries] Failed to execute Tls Entry [%i]", i ); } else { DebugShout( "[ProcessTlsEntries] Called Tls Callback (0x%X)", TLSCallbacks[i] ); } } return SuccessValue; }
VOID scanZeroGravity_ScanProc(INT iItem, HWND hwndDlg, PBYTE pbFile) { PIMAGE_NT_HEADERS pNtHdr = PIMAGE_NT_HEADERS(pbFile + PIMAGE_DOS_HEADER(pbFile)->e_lfanew); PIMAGE_SECTION_HEADER pSecHdr = PIMAGE_SECTION_HEADER(pNtHdr + 1); PBYTE pbCode = RvaToPointer(pbFile, pSecHdr[0].VirtualAddress); DWORD dwCodeSize = pSecHdr[0].SizeOfRawData; PBYTE pbRData = RvaToPointer(pbFile, pSecHdr[1].VirtualAddress); DWORD dwRDataSize = pSecHdr[1].SizeOfRawData; PBYTE pbData = RvaToPointer(pbFile, pSecHdr[2].VirtualAddress); DWORD dwDataSize = pSecHdr[2].SizeOfRawData; SetItemStatus(iItem, hwndDlg, "Scanning..."); // scan for 'and reg, 75BFEDFF' for(DWORD dwCodeIndex = 0; dwCodeIndex < dwCodeSize - 6; dwCodeIndex++) { if(*((PDWORD)&pbCode[dwCodeIndex]) == 0x75BFEDFF && (pbCode[dwCodeIndex - 1] == 0x25 || ((pbCode[dwCodeIndex - 1] & 0xF8) == 0xE0 && pbCode[dwCodeIndex - 2] == 0x81))) { // search for long jump or call following and instruction for(DWORD dwCodeIndex2 = dwCodeIndex + 4; dwCodeIndex2 - dwCodeIndex < 20; dwCodeIndex2++) { if(pbCode[dwCodeIndex2] == 0xE9 || pbCode[dwCodeIndex2] == 0xE8) { // get offset of jump location DWORD dwJumpOffset = (dwCodeIndex2 + 5) + *((PDWORD)&pbCode[dwCodeIndex2 + 1]); // scan for 'test [reg+disp], 4000000h' for(DWORD dwCodeIndex3 = dwJumpOffset; dwCodeIndex3 - dwJumpOffset < 500; dwCodeIndex3++) { if(*((PDWORD)&pbCode[dwCodeIndex3]) == 0x04000000) { if(pbCode[dwCodeIndex3 - 3] == 0xF7) // short displacement { // find a je to this instruction for(DWORD dwCodeIndex4 = dwCodeIndex3 - 5; dwCodeIndex4 >= dwJumpOffset; dwCodeIndex4--) { if(pbCode[dwCodeIndex4] == 0x74 && pbCode[dwCodeIndex4+1] == ((dwCodeIndex3 - 3) - (dwCodeIndex4 + 2))) { // search for 'mov [reg+disp], reg' above the jump for(DWORD dwCodeIndex5 = dwCodeIndex4; dwCodeIndex5 >= dwJumpOffset; dwCodeIndex5--) { if(pbCode[dwCodeIndex5] == 0x89) { // search for 'mov reg, [reg+disp] for(DWORD dwCodeIndex6 = dwCodeIndex5; dwCodeIndex6 >= dwJumpOffset; dwCodeIndex6--) { if(pbCode[dwCodeIndex6] == 0x8B && (pbCode[dwCodeIndex6+1] & 0x38) == (pbCode[dwCodeIndex5+1] & 0x38)) { GetPPD(iItem, hwndDlg)->dwValue = OffsetToRva(pbFile, PtrToUlong(pbCode) + dwCodeIndex - PtrToUlong(pbFile)) + pNtHdr->OptionalHeader.ImageBase; SetItemStatus(iItem, hwndDlg, "Success"); return; } } } } } } } else if(pbCode[dwCodeIndex3 - 6] == 0xF7) // long displacement { // find a je to this instruction for(DWORD dwCodeIndex4 = dwCodeIndex3 - 8; dwCodeIndex4 >= dwJumpOffset; dwCodeIndex4--) { if(pbCode[dwCodeIndex4] == 0x74 && pbCode[dwCodeIndex4+1] == ((dwCodeIndex3 - 6) - (dwCodeIndex4 + 2))) { // search for mov '[reg+disp], reg' above the jump for(DWORD dwCodeIndex5 = dwCodeIndex4; dwCodeIndex5 >= dwJumpOffset; dwCodeIndex5--) { if(pbCode[dwCodeIndex5] == 0x89) { // search for 'mov reg, [reg+disp] for(DWORD dwCodeIndex6 = dwCodeIndex5; dwCodeIndex6 >= dwJumpOffset; dwCodeIndex6--) { if(pbCode[dwCodeIndex6] == 0x8B && (pbCode[dwCodeIndex6+1] & 0x38) == (pbCode[dwCodeIndex5+1] & 0x38)) { GetPPD(iItem, hwndDlg)->dwValue = OffsetToRva(pbFile, PtrToUlong(pbCode) + dwCodeIndex - PtrToUlong(pbFile)) + pNtHdr->OptionalHeader.ImageBase; SetItemStatus(iItem, hwndDlg, "Success"); return; } } } } } } } } } } } } } GetPPD(iItem, hwndDlg)->dwValue = 0; SetItemStatus(iItem, hwndDlg, "Fail"); }
BOOL CRemoteLoader::ProcessRelocations( PVOID BaseAddress, PVOID RemoteAddress ) { IMAGE_NT_HEADERS* ImageNtHeaders = ToNts( BaseAddress ); if( ImageNtHeaders == NULL ) return FALSE; if( ImageNtHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED ) { DebugShout( "[ProcessRelocations] Relocations have been stripped from this executable, continuing.." ); return TRUE; } else { DWORD ImageBaseDelta = MakeDelta( DWORD, RemoteAddress, ImageNtHeaders->OptionalHeader.ImageBase ); DebugShout( "[ProcessRelocations] VirtualAddress (0x%X)", ImageNtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BASERELOC ].VirtualAddress ); DWORD RelocationSize = ImageNtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BASERELOC ].Size; DebugShout( "[ProcessRelocations] Relocation Size [0x%X]", RelocationSize ); if( RelocationSize ) { IMAGE_BASE_RELOCATION* RelocationDirectory = ( IMAGE_BASE_RELOCATION* ) RvaToPointer( ImageNtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BASERELOC ].VirtualAddress, BaseAddress ); if( RelocationDirectory ) { DebugShout( "[ProcessRelocations] RelocationDirectory (0x%X)", RelocationDirectory ); PVOID RelocationEnd = reinterpret_cast< PBYTE >( RelocationDirectory ) + RelocationSize; while( RelocationDirectory < RelocationEnd ) { PBYTE RelocBase = static_cast< PBYTE >( RvaToPointer( RelocationDirectory->VirtualAddress, BaseAddress ) ); DWORD NumRelocs = ( RelocationDirectory->SizeOfBlock - sizeof( IMAGE_BASE_RELOCATION ) ) / sizeof( WORD ); PWORD RelocationData = reinterpret_cast< PWORD >( RelocationDirectory + 1 ); DebugShout( "[ProcessRelocations] RelocationDirectory (0x%X)", RelocationDirectory ); DebugShout( "[ProcessRelocations] RelocationData (0x%X)", RelocationData ); for( DWORD i = 0; i < NumRelocs; ++i, ++RelocationData ) { if( ProcessRelocation( ImageBaseDelta, *RelocationData, RelocBase ) == FALSE ) { DebugShout( "[ProcessRelocations] Unable to process relocation (%i)", i ); } } RelocationDirectory = reinterpret_cast< PIMAGE_BASE_RELOCATION >( RelocationData ); } } else { DebugShout( "[ProcessRelocations] Relocations have a size, but the pointer is invalid" ); return FALSE; } } else { DebugShout( "[ProcessRelocations] Relocations have have not been found in this executable, continuing.." ); return TRUE; } } return TRUE; }
BOOL CRemoteLoader::ProcessImportTable( PVOID BaseAddress, PVOID RemoteAddress, PCHAR OptionalPath ) { IMAGE_NT_HEADERS* ImageNtHeaders = ToNts( BaseAddress ); if( ImageNtHeaders == NULL ) return FALSE; if( ImageNtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ].Size ) { IMAGE_IMPORT_DESCRIPTOR* ImageImportDescriptor = ( IMAGE_IMPORT_DESCRIPTOR* ) RvaToPointer( ImageNtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ].VirtualAddress, BaseAddress ); if( ImageImportDescriptor ) { for( ; ImageImportDescriptor->Name; ImageImportDescriptor++ ) { PCHAR ModuleName = ( PCHAR ) RvaToPointer( ImageImportDescriptor->Name, BaseAddress ); if( ModuleName == NULL ) { DebugShout( "[ProcessImportTable] Module name for entry NULL" ); continue; } DebugShout( "[ProcessImportTable] Module Name [%s]", ModuleName ); HMODULE ModuleBase = GetRemoteModuleHandleA( ModuleName ); if( ModuleBase == NULL ) { ModuleBase = LoadLibraryByPathA( ModuleName ); } if( ModuleBase == NULL ) { DebugShout( "[ProcessImportTable] Failed to obtain module handle [%s]", ModuleName ); continue; } IMAGE_THUNK_DATA *ImageThunkData = NULL; IMAGE_THUNK_DATA *ImageFuncData = NULL; if( ImageImportDescriptor->OriginalFirstThunk ) { ImageThunkData = ( IMAGE_THUNK_DATA* ) RvaToPointer( ImageImportDescriptor->OriginalFirstThunk, BaseAddress ); ImageFuncData = ( IMAGE_THUNK_DATA* ) RvaToPointer( ImageImportDescriptor->FirstThunk, BaseAddress ); } else { ImageThunkData = ( IMAGE_THUNK_DATA* ) RvaToPointer( ImageImportDescriptor->FirstThunk, BaseAddress ); ImageFuncData = ( IMAGE_THUNK_DATA* ) RvaToPointer( ImageImportDescriptor->FirstThunk, BaseAddress ); } if( ImageThunkData == NULL ) { DebugShout( "[ProcessImportTable] Image Thunk Data is NULL" ); } if( ImageFuncData == NULL ) { DebugShout( "[ProcessImportTable] Image Func Data is NULL" ); } for( ; ImageThunkData->u1.AddressOfData; ImageThunkData++, ImageFuncData++ ) { FARPROC FunctionAddress = NULL; if( IMAGE_SNAP_BY_ORDINAL( ImageThunkData->u1.Ordinal ) ) { SHORT Ordinal = ( SHORT ) IMAGE_ORDINAL( ImageThunkData->u1.Ordinal ); FunctionAddress = ( FARPROC ) GetRemoteProcAddress( ModuleName, Ordinal ); DebugShout( "[ProcessImportTable] Processed (%s -> %i) -> (0x%X)", ModuleName, Ordinal, FunctionAddress ); if( this->GetProcess() == INVALID_HANDLE_VALUE ) { DebugShout( "[ProcessImportTable] Normal Value (0x%X)", GetProcAddress( GetModuleHandleA( ModuleName ), ( LPCSTR ) Ordinal ) ); } } else { IMAGE_IMPORT_BY_NAME* ImageImportByName = ( IMAGE_IMPORT_BY_NAME* ) RvaToPointer( *( DWORD* ) ImageThunkData, BaseAddress ); PCHAR NameOfImport = ( PCHAR ) ImageImportByName->Name; FunctionAddress = ( FARPROC ) GetRemoteProcAddress( ModuleName, NameOfImport ); DebugShout( "[ProcessImportTable] Processed (%s -> %s) -> (0x%X)", ModuleName, NameOfImport, FunctionAddress ); if( this->GetProcess() == INVALID_HANDLE_VALUE ) { DebugShout( "[ProcessImportTable] Normal Value (0x%X)", GetProcAddress( GetModuleHandleA( ModuleName ), NameOfImport ) ); } } ImageFuncData->u1.Function = ( DWORD ) FunctionAddress; } } return TRUE; } else { DebugShout( "[ProcessImportTable] Size of table confirmed but pointer to data invalid!" ); return FALSE; } } else { DebugShout( "[ProcessImportTable] No Imports" ); return TRUE; } return FALSE; }
VOID scanGetCharacterGuid_ScanProc(INT iItem, HWND hwndDlg, PBYTE pbFile) { PIMAGE_NT_HEADERS pNtHdr = PIMAGE_NT_HEADERS(pbFile + PIMAGE_DOS_HEADER(pbFile)->e_lfanew); PIMAGE_SECTION_HEADER pSecHdr = PIMAGE_SECTION_HEADER(pNtHdr + 1); PBYTE pbCode = RvaToPointer(pbFile, pSecHdr[0].VirtualAddress); DWORD dwCodeSize = pSecHdr[0].SizeOfRawData; PBYTE pbRData = RvaToPointer(pbFile, pSecHdr[1].VirtualAddress); DWORD dwRDataSize = pSecHdr[1].SizeOfRawData; PBYTE pbData = RvaToPointer(pbFile, pSecHdr[2].VirtualAddress); DWORD dwDataSize = pSecHdr[2].SizeOfRawData; SetItemStatus(iItem, hwndDlg, "Scanning..."); // scan data section for "Player_C.h" for(DWORD dwDataIndex = 0; dwDataIndex < dwDataSize - (sizeof("Player_C.h") - 1); dwDataIndex++) { if(MemoryCompare(&pbData[dwDataIndex], (PBYTE)"Player_C.h", sizeof("Player_C.h") - 1)) { // found "Player_C.h", now scan for beginning of the string DWORD dwStringIndex; for(dwStringIndex = dwDataIndex - 1; dwStringIndex && pbData[dwStringIndex] >= 0x20 && pbData[dwStringIndex] <= 0x7E; dwStringIndex--); dwStringIndex++; // calculate va of found string DWORD dwStringVA = OffsetToRva(pbFile, PtrToUlong(pbData) + dwStringIndex - PtrToUlong(pbFile)); if(dwStringVA) { dwStringVA += pNtHdr->OptionalHeader.ImageBase; // scan code section for 'mov edx, dwStringVA' BYTE bMoveIns[5]; bMoveIns[0] = 0xBA; *((PDWORD)&bMoveIns[1]) = dwStringVA; for(DWORD dwCodeIndex = 0; dwCodeIndex < dwCodeSize - sizeof(bMoveIns); dwCodeIndex++) { if(MemoryCompare(&pbCode[dwCodeIndex], bMoveIns, sizeof(bMoveIns))) { // found mov instruction, make sure next instruction is 'mov ecx, constant' if(pbCode[dwCodeIndex + 5] == 0xB9) { // make sure instruction following 'mov ecx, constant' is a call relative if(pbCode[dwCodeIndex + 10] == 0xE8) { // somewhere before the 'mov edx, dwStringVA' instruction there must be this code: // call relative // push edx // push eax for(DWORD dwCodeIndex2 = dwCodeIndex - 2; dwCodeIndex - dwCodeIndex2 < 20; dwCodeIndex2--) { if(*((PWORD)&pbCode[dwCodeIndex2]) == 0x5052 && pbCode[dwCodeIndex2 - 5] == 0xE8) { // lastly check for a 'push constant' instruction before those two register pushes instruction for(DWORD dwCodeIndex3 = dwCodeIndex2 - 5; dwCodeIndex2 - dwCodeIndex3 < 20; dwCodeIndex3--) { if(pbCode[dwCodeIndex3] == 0x68) { // we need to decode the call relative preceeding the two register pushes // calculate va of next instruction following call DWORD dwFollowingVA = OffsetToRva(pbFile, PtrToUlong(pbCode) + dwCodeIndex2 - PtrToUlong(pbFile)) + pNtHdr->OptionalHeader.ImageBase; if(dwFollowingVA) { GetPPD(iItem, hwndDlg)->dwValue = dwFollowingVA + *((PDWORD)&pbCode[dwCodeIndex2 - 4]); SetItemStatus(iItem, hwndDlg, "Success"); return; } } } } } } } } } } } } GetPPD(iItem, hwndDlg)->dwValue = 0; SetItemStatus(iItem, hwndDlg, "Fail"); }