#include "cPatchUtils.h" #define MakePtr( cast, ptr, addValue )( cast )( ( DWORD )( ptr ) + ( DWORD )( addValue ) ) #pragma warning( disable : 4311 ) #pragma warning( disable : 4312 ) #pragma intrinsic(_ReturnAddress) extern DWORD ade32_table[512]; DWORD cPatchUtils::dwFindPattern ( DWORD dwAddress, DWORD dwSize, BYTE* pbMask, char* szMask ) { for( DWORD i = NULL; i < dwSize; i++ ) if( bDataCompare( (BYTE*) ( dwAddress + i ), pbMask, szMask ) ) return (DWORD)( dwAddress + i ); return 0; } DWORD cPatchUtils::dwFindPattern ( DWORD dwAddress, DWORD dwSize, BYTE* pbMask, int iLen ) { for( DWORD i = NULL; i < dwSize; i++ ) if( bDataCompare ( (BYTE*) ( dwAddress + i ), pbMask, iLen ) ) return (DWORD)( dwAddress + i ); return 0; } bool cPatchUtils::bDataCompare(const BYTE* pData, const BYTE* bMask, int iLen ) { for( int i = 0; i < iLen; i++ ) { if (pData[i] == bMask[i]) { continue; } else { if (bMask[i] == 0x00 && bMask[i + 1] == 0x00 && bMask[i + 2] == 0x00 && bMask[i + 3] == 0x00 ) { i += 3; continue; } else { return false; } } } return (i >= iLen); } DWORD cPatchUtils::dwFindPattern ( HMODULE hModule, BYTE* pbMask, char* szMask ) { if ( hModule == NULL || hModule == INVALID_HANDLE_VALUE ) return NULL; PIMAGE_DOS_HEADER pDosHeader = reinterpret_cast< PIMAGE_DOS_HEADER >( hModule ); if( pDosHeader->e_magic != IMAGE_DOS_SIGNATURE ) return NULL; PIMAGE_NT_HEADERS pNTHeader = MakePtr( PIMAGE_NT_HEADERS, pDosHeader,pDosHeader->e_lfanew ); if (pNTHeader->Signature != IMAGE_NT_SIGNATURE) return NULL; DWORD dwAddress = (DWORD) hModule + pNTHeader->OptionalHeader.BaseOfCode; DWORD dwSize = pNTHeader->OptionalHeader.SizeOfCode; return dwFindPattern ( dwAddress, dwSize, pbMask, szMask ); } DWORD cPatchUtils::dwFindPattern ( HMODULE hModule, DWORD dwAddress, DWORD dwSize, BYTE* pbMask, char* szMask ) { if ( hModule == NULL || hModule == INVALID_HANDLE_VALUE ) return NULL; PIMAGE_DOS_HEADER pDosHeader = reinterpret_cast< PIMAGE_DOS_HEADER >( hModule ); if( pDosHeader->e_magic != IMAGE_DOS_SIGNATURE ) return NULL; PIMAGE_NT_HEADERS pNTHeader = MakePtr( PIMAGE_NT_HEADERS, pDosHeader,pDosHeader->e_lfanew ); if (pNTHeader->Signature != IMAGE_NT_SIGNATURE) return NULL; DWORD dwAddressOfCode = (DWORD) hModule + dwAddress; DWORD dwSizeOfCode = pNTHeader->OptionalHeader.SizeOfCode - dwAddress; return dwFindPattern ( dwAddressOfCode, dwSizeOfCode, pbMask, szMask ); } bool cPatchUtils::bDataCompare(const BYTE* pData, const BYTE* bMask, const char* szMask) { for( ; *szMask; ++szMask, ++pData, ++bMask ) if(*szMask == 'x' && *pData != *bMask ) return false; return (*szMask) == NULL; } DWORD cPatchUtils::dwDetour ( DWORD dwOldAddress, DWORD dwNewAddress ) { disasm_struct diza; memset(&diza,0,sizeof(diza)); DWORD dwLen = NULL; while( true ) { disasm( (PBYTE)(dwOldAddress + dwLen), &diza ); if(diza.disasm_flag == C_ERROR || diza.disasm_flag & (C_STOP|C_REL|C_BAD) || !diza.disasm_len ) return dwOldAddress; dwLen += diza.disasm_len; if (dwLen >= SIZE_OF_JUMP) break; } return dwDetour( dwOldAddress, dwNewAddress, dwLen); } DWORD cPatchUtils::dwDetour ( DWORD dwOldAddress, DWORD dwNewAddress, DWORD dwLen ) { BYTE* pbSource = (BYTE*) dwOldAddress; BYTE* pbDestination = (BYTE*) dwNewAddress; BYTE* pbTrampoline = (BYTE*) malloc(dwLen + SIZE_OF_JUMP); DWORD dwOldProtect = NULL; if(!VirtualProtect(pbSource, dwLen, PAGE_READWRITE, &dwOldProtect)) return NULL; memcpy(pbTrampoline, pbSource, dwLen); pbTrampoline += dwLen; pbTrampoline[0] = OPCODE_OF_JUMP; *(DWORD*)(pbTrampoline+1) = (DWORD)(pbSource + dwLen - pbTrampoline) - SIZE_OF_JUMP; pbSource[0] = OPCODE_OF_JUMP; *(DWORD*)(pbSource+1) = (DWORD)(pbDestination - pbSource) - SIZE_OF_JUMP; if(!VirtualProtect(pbSource, dwLen, dwOldProtect, &dwOldProtect)) return NULL; return (((DWORD) pbTrampoline) - dwLen ); } DWORD cPatchUtils::dwOPCodeLength ( DWORD dwAddress ) { disasm_struct diza; memset(&diza,0,sizeof(diza)); disasm((BYTE*)dwAddress,&diza); if ( ( diza.disasm_flag == C_ERROR ) || (diza.disasm_flag & C_BAD) ) return 1;//most opcodes are just 1 byte return diza.disasm_len; } bool cPatchUtils::bCreateJump ( DWORD dwAddress,DWORD dwDestination ) { DWORD dwOldProtect = NULL; if(!VirtualProtect((DWORD*)dwAddress,SIZE_OF_JUMP,PAGE_READWRITE,&dwOldProtect)) return false; *(BYTE*) (dwAddress) = OPCODE_OF_JUMP; *(DWORD*)(dwAddress+1) = dwDestination - (dwAddress + SIZE_OF_JUMP); return (VirtualProtect((DWORD*)dwAddress,SIZE_OF_JUMP,dwOldProtect,&dwOldProtect) == TRUE); } DWORD cPatchUtils::dwGetJumpAddress ( PDWORD pdwAddress ) { DWORD dwAddress; // create the return buffer PBYTE pbAddress = (PBYTE)pdwAddress; // reinterpret to PBYTE pbAddress = &pbAddress[1]; // skip the opcode memcpy((void*)&dwAddress,pbAddress,sizeof(DWORD)); // copy the relative address return (dwAddress + (DWORD) pdwAddress + SIZE_OF_JUMP); // calculate the final address } DWORD cPatchUtils::dwReplaceJump ( DWORD dwAddress,DWORD dwDestination ) { DWORD dwRet = dwGetJumpAddress( (PDWORD) dwAddress ); if ( !bCreateJump( dwAddress, dwDestination ) ) return NULL; return dwRet; } bool cPatchUtils::bCreateCall ( DWORD dwAddress,DWORD dwDestination ) { DWORD dwOldProtect = NULL; if(!VirtualProtect((DWORD*)dwAddress,SIZE_OF_CALL,PAGE_READWRITE,&dwOldProtect)) return false; *(BYTE*) (dwAddress) = OPCODE_OF_CALL; *(DWORD*)(dwAddress+1) = dwDestination - (dwAddress + SIZE_OF_CALL); return (VirtualProtect((DWORD*)dwAddress,SIZE_OF_JUMP,dwOldProtect,&dwOldProtect) == TRUE); } DWORD cPatchUtils::dwReplaceCall ( DWORD dwAddress, DWORD dwDestination ) { DWORD dwRet = dwGetJumpAddress( (PDWORD) dwAddress ); if ( !bCreateCall( dwAddress, dwDestination ) ) return NULL; return dwRet; } // Credits: Flautz! DWORD cPatchUtils::dwHookIATEntry ( HMODULE hModule, DWORD dwNewAddress, DWORD dwOldAddress ) { if ( hModule == NULL || hModule == INVALID_HANDLE_VALUE ) return NULL; PIMAGE_DOS_HEADER pDosHeader = reinterpret_cast< PIMAGE_DOS_HEADER >( hModule ); if( pDosHeader->e_magic != IMAGE_DOS_SIGNATURE ) return NULL; PIMAGE_NT_HEADERS pNTHeader = MakePtr( PIMAGE_NT_HEADERS, pDosHeader,pDosHeader->e_lfanew ); if (pNTHeader->Signature != IMAGE_NT_SIGNATURE) return NULL; DWORD dwIATStart = pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress; DWORD dwIATEnd = dwIATStart + pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size; DWORD dwCurrentContent = NULL; DWORD dwOldProtect = NULL; for (DWORD dwCurrentAddr = dwIATStart; dwCurrentAddr < dwIATEnd; dwCurrentAddr += sizeof ( DWORD ) ) { memcpy(&dwCurrentContent,(void *)dwCurrentAddr, sizeof ( DWORD )); if( dwCurrentContent == dwOldAddress) { if(!VirtualProtect((void *)dwCurrentAddr,sizeof(DWORD), PAGE_EXECUTE_READWRITE, &dwOldProtect)) return NULL; memcpy((void *)dwCurrentAddr,&dwNewAddress,sizeof(DWORD)); if(!VirtualProtect((void *)dwCurrentAddr,sizeof(DWORD), dwOldProtect, &dwOldProtect)) return NULL; return dwOldAddress; } } return NULL; } bool cPatchUtils::bDecodeVMString ( LPWSTR pszEncoded, LPWSTR pszDecoded , int iLen ) { if ( pszEncoded == NULL || pszDecoded == NULL || iLen == NULL ) return false; for ( int i = 0; i < iLen; i++ ) { WORD wTemp = pszEncoded[i]; __asm { mov ax,wTemp; xor al,33; mov wTemp,ax; } pszDecoded[i] = wTemp; } return true; } bool cPatchUtils::bDecrypt ( PBYTE pbAddress, int iLen,BYTE bStartValue,BYTE bXorVal ) { BYTE bXor = bXorVal; for (int i = bStartValue; i < iLen; i++) { byte newdata = pbAddress[i] ^ bXor; pbAddress[i] = newdata; bXor += newdata + bXorVal; } return true; } bool cPatchUtils::bEncrypt ( PBYTE pbAddress, int iLen,BYTE bStartValue,BYTE bXorVal ) { BYTE bXor = bXorVal; BYTE bDecoded = 0x00; for( int i = bStartValue; i < iLen; i++ ) { bDecoded = pbAddress[i] ^ bXor; bXor += pbAddress[i] + bXorVal; pbAddress[i] = bDecoded; } return true; } bool cPatchUtils::bDisAsmCMCode ( PBYTE pbOpcode, disasm_struct* diza ) { BYTE* pbOPcode = pbOpcode; memset(diza, 0x00, sizeof(disasm_struct)); diza->disasm_defdata = 4; diza->disasm_defaddr = 4; if (*(WORD*)pbOPcode == 0x0000) return false; if (*(WORD*)pbOPcode == 0xFFFF) return false; DWORD dwFlag = NULL; repeat_prefix: BYTE c = *pbOPcode++; DWORD t = ade32_table[ c ]; if (t & C_ANYPREFIX) { if (dwFlag & t) return false; // twice LOCK,SEG,REP,66,67 dwFlag |= t; if (t & C_67 || t & C_66) diza->disasm_defaddr ^= 2^4; else if (t & C_SEG) diza->disasm_seg = c; else if (t & C_REP) diza->disasm_rep = c; // LOCK goto repeat_prefix; } // C_ANYPREFIX dwFlag |= t; diza->disasm_opcode = c; switch( c ) { case 0x06: // PUSH case 0x07: // POP case 0x0E: // PUSH case 0x16: // PUSH case 0x17: // POP case 0x18: // SBB /r case 0x19: // SBB /r case 0x1A: // SBB /r case 0x1B: // SBB /r case 0x1C: // SBB ib case 0x1D: // SBB id case 0x1E: // PUSH case 0x26: // ES prefix case 0x27: // DAA case 0x40: // INC case 0x41: // INC case 0x42: // INC case 0x43: // INC case 0x44: // INC case 0x45: // INC case 0x46: // INC case 0x47: // INC case 0x48: // DEC case 0x49: // DEC case 0x4A: // DEC case 0x4B: // DEC case 0x4C: // DEC case 0x4D: // DEC case 0x4E: // DEC case 0x4F: // DEC case 0x50: // PUSH case 0x51: // PUSH case 0x52: // PUSH case 0x53: // PUSH case 0x54: // PUSH case 0x55: // PUSH case 0x56: // PUSH case 0x57: // PUSH case 0x58: // POP case 0x59: // POP case 0x5A: // POP case 0x5B: // POP case 0x5C: // POP case 0x5D: // POP case 0x5E: // POP case 0x5F: // POP case 0x60: // PUSHAD case 0x61: // POPAD case 0x68: // PUSH case 0x69: // case 0x6A: // PUSH case 0x70: // JO case 0x71: // JNO case 0x72: // JB/JC/JNAE case 0x73: // JAE/JNB/JNC case 0x74: // JE/JZ case 0x75: // JNE/JNZ case 0x76: // JBE/JNA case 0x77: // JA/JNBE case 0x78: // JS case 0x79: // JNS case 0x7A: // JP/JPE case 0x7B: // JNP/JPO case 0x7C: // JL/JNGE case 0x7D: // JGE/JNL case 0x7E: // JLE/JNG case 0x7F: // JG/JNLE case 0x90: // NOP case 0x9A: // CALL cp case 0x9B: // WAIT/FWAIT case 0x9C: // PUSHFD case 0x9D: // POPFD case 0xC2: // RET case 0xC3: // RET case 0xCA: // RET case 0xCB: // RET case 0xCC: // INT 3 case 0xCD: // INT ib case 0xCE: // INTO case 0xCF: // IRET case 0xE0: // LOOPNE cb case 0xE1: // LOOPE cb case 0xE2: // LOOP cb case 0xE3: // JCXZ/JECXZ case 0xE4: // IN ib case 0xE5: // IN id case 0xE6: // OUT ib case 0xE7: // OUT ib case 0xE8: // CALL cd case 0xE9: // JMP cd case 0xEA: // JMP cp case 0xEB: // JMP cb return (disasm(pbOpcode,diza) != 0); default: PDWORD pdwBase = new DWORD[2]; PBYTE pbBase = (PBYTE) pdwBase; pbBase[0] = pbOpcode[0];//opcode pbBase[1] = pbOpcode[5];//register pbBase[2] = pbOpcode[1];//address byte 1 pbBase[3] = pbOpcode[2];//address byte 2 pbBase[4] = pbOpcode[3];//address byte 3 pbBase[5] = pbOpcode[4];//address byte 4 pbBase[6] = 0x90; // NOP pbBase[7] = 0x90; // NOP bool bRet = ( disasm(pbBase,diza) != 0); delete [] pdwBase; return bRet; } } bool cPatchUtils::bRelocate( PBYTE pbOldBase, PBYTE pbNewBase, DWORD* dwTable, int iNumEntries ) { DWORD dwDelta = (DWORD) (pbNewBase - (PBYTE) pbOldBase); DWORD dwOldPotection = NULL; if(!VirtualProtect((LPVOID)dwTable,iNumEntries * sizeof ( DWORD ),PAGE_EXECUTE_READWRITE,&dwOldPotection)) return false; for ( int i = 0; i < iNumEntries ;i++) dwTable[i] += dwDelta; if(!VirtualProtect((LPVOID)dwTable,iNumEntries * sizeof ( DWORD ),dwOldPotection,&dwOldPotection)) return false; return true; } DWORD cPatchUtils::dwPerformThisCall ( DWORD dwAddress,DWORD dwBase ) { DWORD dwRet; __asm { pushad; mov ecx,dwBase; mov eax,dwAddress; call eax; mov dwRet,eax; popad; } return dwRet; } bool cPatchUtils::bIsValidCodePointer ( HMODULE hModule,DWORD dwAddress) { PIMAGE_DOS_HEADER pDosHeader = reinterpret_cast< PIMAGE_DOS_HEADER >( hModule ); if( pDosHeader->e_magic != IMAGE_DOS_SIGNATURE ) return NULL; PIMAGE_NT_HEADERS pNTHeader = MakePtr( PIMAGE_NT_HEADERS, pDosHeader,pDosHeader->e_lfanew ); if (pNTHeader->Signature != IMAGE_NT_SIGNATURE) return NULL; DWORD dwCodeBase = pNTHeader->OptionalHeader.BaseOfCode + (DWORD)hModule; DWORD dwSize = pNTHeader->OptionalHeader.SizeOfCode; return ( dwAddress > dwCodeBase && dwAddress < dwCodeBase + dwSize ); } bool cPatchUtils::bIsValidDataPointer ( HMODULE hModule,DWORD dwAddress) { PIMAGE_DOS_HEADER pDosHeader = reinterpret_cast< PIMAGE_DOS_HEADER >( hModule ); if( pDosHeader->e_magic != IMAGE_DOS_SIGNATURE ) return NULL; PIMAGE_NT_HEADERS pNTHeader = MakePtr( PIMAGE_NT_HEADERS, pDosHeader,pDosHeader->e_lfanew ); if (pNTHeader->Signature != IMAGE_NT_SIGNATURE) return NULL; DWORD dwCodeBase = pNTHeader->OptionalHeader.BaseOfData + (DWORD)hModule; DWORD dwSize = pNTHeader->OptionalHeader.SizeOfInitializedData; // heap + static return ( dwAddress > dwCodeBase && dwAddress < dwCodeBase + dwSize ); } bool cPatchUtils::bRelocate( PBYTE pbOldBase, PBYTE pbNewBase ) { PIMAGE_DOS_HEADER pDosHeader = reinterpret_cast< PIMAGE_DOS_HEADER >( pbOldBase ); if( pDosHeader->e_magic != IMAGE_DOS_SIGNATURE ) return NULL; PIMAGE_NT_HEADERS pNTHeader = MakePtr( PIMAGE_NT_HEADERS, pDosHeader,pDosHeader->e_lfanew ); if (pNTHeader->Signature != IMAGE_NT_SIGNATURE) return NULL; DWORD dwDelta = (DWORD) (pbNewBase - (BYTE*)pNTHeader->OptionalHeader.ImageBase); PIMAGE_BASE_RELOCATION pReloc = (PIMAGE_BASE_RELOCATION)( pbOldBase + pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress); for (;pReloc->VirtualAddress; pReloc = (PIMAGE_BASE_RELOCATION)((BYTE*)pReloc+pReloc->SizeOfBlock)) { DWORD dwSize = (DWORD)sizeof(IMAGE_BASE_RELOCATION); DWORD dwBlocks = (pReloc->SizeOfBlock-dwSize)/2; BYTE * pFinalBase = (BYTE*)(pbOldBase + pReloc->VirtualAddress); WORD * wFixUp = (WORD*)(((BYTE*) pReloc)+dwSize); for ( DWORD i = 0; i < dwBlocks; i++ ) { DWORD dwOffset = (DWORD)(wFixUp[i] & 0x0FFF); if( wFixUp[i] >> 12 == IMAGE_REL_BASED_HIGH ) *((WORD*)(pFinalBase+dwOffset)) += ( WORD )( dwDelta >> 16 ); if( wFixUp[i] >> 12 == IMAGE_REL_BASED_LOW ) *((WORD*)(pFinalBase+dwOffset)) += ( WORD )( dwDelta ); if( wFixUp[i] >> 12 == IMAGE_REL_BASED_HIGHLOW ) *((DWORD*)(pFinalBase + dwOffset)) += dwDelta; } } return true; }