DWORD HDTools::GetFunctionLength(LPVOID begin) { size_t end = GetFunctionEnd((size_t)begin); DWORD delta = (DWORD)((DWORD_PTR)end - (DWORD_PTR)begin); delta += hde_disasm((void*)end); return delta; }
//Creates stub function. And jump to target+5 bytes void* GetSafeFuncStartOrig(void *addr){ //malloc for code void *p = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 32); if(!p) return 0; //Damn antivirals trick PFN_VirtualProtectEx pVirtualProtectEx = (PFN_VirtualProtectEx)(GetProcAddress( g_hKernel32, "VirtualProtectEx" ) ); DWORD dwTemp; pVirtualProtectEx((HANDLE)(-1), (LPVOID)p, 32, PAGE_EXECUTE_READWRITE, &dwTemp); BYTE *pcode=(BYTE*)addr; DWORD code_len=0; while(code_len<5){ HDE_STRUCT hdestr={0}; DWORD instr_len=hde_disasm(pcode, &hdestr); code_len+=instr_len; pcode+=instr_len; //FIX: opcode tests here } memcpy((void*)p, addr, code_len); pcode=(BYTE*)p+code_len; *pcode=0xE9; *(DWORD*)(pcode+1)=(DWORD)((DWORD)((BYTE*)addr+code_len)-(DWORD)pcode-5); return p; }
size_t GetBranchListFromBlock(size_t block, size_t* branchList, DWORD& branchIdx) { unsigned char* ptr = (unsigned char* )block; // If we reach an end-point, then this block is complete while(!IsEndPoint(ptr, block)) { // Record all branching instructions that we encounter size_t address = GetBranchAddress(ptr); if(address) branchList[branchIdx++] = address; // Next instruction ptr += hde_disasm(ptr); } return (size_t)(ptr); }
int IsShortFunc(LPVOID addr){ int res=0; DWORD code_len=0; BYTE* pcode = (BYTE*)addr; while(code_len<5){ HDE_STRUCT hdestr={0}; DWORD instr_len=hde_disasm(pcode, &hdestr); BYTE Opcode = *pcode; code_len += instr_len; pcode += instr_len; if(Opcode==0xC3 || Opcode==0xC2){//retn , retn NN res=1; break; } } if( res == 0 ){//Long function return 0; } if( code_len >= 5 ){//5 bytes len function return 0; } DWORD CheckLen = 5 - code_len; DWORD FilledWithCC = 1; for( DWORD i = 0; i < CheckLen; i++ ){ if( (pcode[i] != 0xCC) && (pcode[i] != 0x90) ){//Check for 0xCC or 0x90 after RETN -> compiler code alignment FilledWithCC = 0; } } if( FilledWithCC ){ res = 0; } return res; }
//Creates stub function. And jump to target+5 bytes void* GetSafeFuncStart(void *addr){ //malloc for code void *p=MemAlloc(32); if(!p) return 0; DWORD dwTemp; safe_VirtualProtectEx((HANDLE)(-1), (LPVOID)p, 32, PAGE_EXECUTE_READWRITE, &dwTemp); BYTE *pcode=(BYTE*)addr; DWORD code_len=0; while(code_len<5){ HDE_STRUCT hdestr={0}; DWORD instr_len=hde_disasm(pcode, &hdestr); code_len+=instr_len; pcode+=instr_len; //FIX: opcode tests here } memcpy((void*)p, addr, code_len); pcode=(BYTE*)p+code_len; *pcode=0xE9; *(DWORD*)(pcode+1)=(DWORD)((DWORD)((BYTE*)addr+code_len)-(DWORD)pcode-5); return p; }
bool CreateTrampolineFunction(CREATE_TREMPOLINE_T& ct) { assert(("CreateTrampolineFunction", ct.pTarget != NULL)); #if defined _M_X64 CALL_ABS call = { 0x15FF, 0x00000000 }; JMP_ABS jmp = { 0x25FF, 0x00000000 }; JCC_ABS jcc = { 0x70, 0x02, 0xEB, 0x06, 0x25FF, 0x00000000 }; #elif defined _M_IX86 CALL_REL call = { 0xE8, 0x00000000 }; JMP_REL jmp = { 0xE9, 0x00000000 }; JCC_REL jcc = { 0x800F, 0x00000000 }; #endif size_t oldPos = 0; size_t newPos = 0; uintptr_t jmpDest = 0; // 関数内ジャンプの飛び先アドレス(分岐中判定に使用) bool finished = false; // 関数終了フラグ while (!finished) { uint8_t *pInst = reinterpret_cast<uint8_t*>(ct.pTarget) + oldPos; hde_t hs; hde_disasm(pInst, &hs); if ((hs.flags & F_ERROR) == F_ERROR) { return false; } void* pCopySrc = pInst; size_t copySize = hs.len; if (pInst - reinterpret_cast<uint8_t*>(ct.pTarget) >= sizeof(JMP_REL)) { // ターゲット関数へのジャンプを書き込み、関数を終了 AppendTempAddress(reinterpret_cast<uintptr_t>(pInst), newPos, jmp, ct); pCopySrc = &jmp; copySize = sizeof(jmp); finished = true; } #if defined _M_X64 // RIP相対アドレッシングを使用している命令 (ModR/M = 00???101B) else if ((hs.modrm & 0xC7) == 0x05) { // RIP相対アドレスのみ書き換え AppendRipRelativeAddress(pInst, newPos, hs, ct); // JMP (FF /4)なら関数を終了 if (hs.opcode == 0xFF && hs.modrm_reg == 4) { finished = true; } } #endif // 相対直接CALL else if (hs.opcode == 0xE8) { AppendTempAddress(GetRelativeBranchDestination(pInst, hs, false), newPos, call, ct); pCopySrc = &call; copySize = sizeof(call); } // 相対直接JMP (EB or E9) else if ((hs.opcode & 0xFD) == 0xE9) { uintptr_t dest = GetRelativeBranchDestination(pInst, hs, hs.opcode == 0xEB); // 関数内へのジャンプはそのままコピー(ジャンプ中は命令長が変わるような操作は不可) if (IsInternalJump(ct.pTarget, dest)) { jmpDest = std::max<uintptr_t>(jmpDest, dest); } else { AppendTempAddress(dest, newPos, jmp, ct); pCopySrc = &jmp; copySize = sizeof(jmp); // 分岐中でなければ関数を終了 finished = (reinterpret_cast<uintptr_t>(pInst) >= jmpDest); } } // 相対直接Jcc else if ((hs.opcode & 0xF0) == 0x70 || (hs.opcode & 0xFC) == 0xE0 || (hs.opcode2 & 0xF0) == 0x80) { uintptr_t dest = GetRelativeBranchDestination(pInst, hs, (hs.opcode & 0xF0) == 0x70 || (hs.opcode & 0xFC) == 0xE0); // 関数内へのジャンプはそのままコピー(分岐中は命令長が変わるような操作は不可) if (IsInternalJump(ct.pTarget, dest)) { jmpDest = std::max<uintptr_t>(jmpDest, dest); } else if ((hs.opcode & 0xFC) == 0xE0) // 関数外へのJCXZ, JECXZ には対応しない { return false; } else { AppendTempAddress(dest, newPos, jcc, ct); SetJccOpcode(hs, jcc); pCopySrc = &jcc; copySize = sizeof(jcc); } } // RET (C2 or C3) else if ((hs.opcode & 0xFE) == 0xC2) { // 分岐中でなければトランポリン関数を終了 finished = (reinterpret_cast<uintptr_t>(pInst) >= jmpDest); } // 分岐中は命令長が変わるような操作は不可 if (reinterpret_cast<uintptr_t>(pInst) < jmpDest && copySize != hs.len) { return false; } ct.trampoline.resize(newPos + copySize); memcpy(&ct.trampoline[ newPos ], pCopySrc, copySize); ct.oldIPs.push_back(oldPos); oldPos += hs.len; ct.newIPs.push_back(newPos); newPos += copySize; } // Is there enough place for a long jump? if (oldPos < sizeof(JMP_REL) && !IsCodePadding(reinterpret_cast<uint8_t*>(ct.pTarget) + oldPos, sizeof(JMP_REL) - oldPos)) { // Is there enough place for a short jump? if (oldPos < sizeof(JMP_REL_SHORT) && !IsCodePadding(reinterpret_cast<uint8_t*>(ct.pTarget) + oldPos, sizeof(JMP_REL_SHORT) - oldPos)) { return false; } // Can we place the long jump above the function? if (!IsExecutableAddress(reinterpret_cast<uint8_t*>(ct.pTarget) - sizeof(JMP_REL))) { return false; } if (!IsCodePadding(reinterpret_cast<uint8_t*>(ct.pTarget) - sizeof(JMP_REL), sizeof(JMP_REL))) { return false; } ct.patchAbove = true; } return true; }
void* KHOOK::operator new(size_t size, LPCVOID addr, LPCVOID stub, int *pError, DWORD PushID){ if(IsShortFunc((LPVOID)addr)){ *pError=LESS_5_BYTE; return 0; } DWORD dwTemp=0; if(!safe_VirtualProtectEx((HANDLE)(-1), (LPVOID)addr, 32, PAGE_EXECUTE_READWRITE, &dwTemp)){ *pError=KHOOK::PAGE_PROT_ERR; return 0; } KHOOK *pHook=(KHOOK*)MemAlloc(sizeof(KHOOK)); if(!pHook){ *pError=MEMALLOC_ERR; return 0; } pHook->addr=addr; pHook->stub=stub; pHook->code_len=0; pHook->ReassembledCodeLen = 0; BYTE* pDst = (BYTE*)pHook->exec_buf;//dst BYTE *pcode = (BYTE*)addr; //src while(pHook->code_len < 5){ HDE_STRUCT hdestr = {0}; DWORD instr_len = hde_disasm(pcode, &hdestr); //reassemble copy DWORD NewInstrLen = pHook->ReAssembleInstr((BYTE*)addr, pcode, pDst, instr_len); pHook->code_len += instr_len; pHook->ReassembledCodeLen += NewInstrLen; pcode += instr_len; pDst += NewInstrLen; } //Save original bytes for restore hook memcpy((void*)pHook->orig_bytes, addr, pHook->code_len); //push id //jmp Stub pHook->push_id[0] = 0x68; //PUSH opcode *(DWORD*)&pHook->push_id[1] = PushID; pHook->push_id[5] = 0xE9; //JMP opcode *(DWORD*)&pHook->push_id[6] = (DWORD)((BYTE*)stub - ((BYTE*)&pHook->push_id[5] + 5)); //EXEC_BUFFER...JMP FUNC_ADDR+LEN BYTE *dst=pHook->exec_buf + pHook->ReassembledCodeLen; *(BYTE*)dst = 0xE9;//JMP opcode *(DWORD*)(dst+1) = (DWORD)((DWORD)((BYTE*)addr + pHook->code_len) - (DWORD)dst - 5); //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //Set hook //Write jmp stub to function begin address *(BYTE*)addr=0xE9; if(PushID==0xFFFFFFFF){//jmp to exec_buf *(DWORD*)((BYTE*)addr + 1)=(DWORD)((BYTE*)stub - ((BYTE*)addr + 5)); } else{// jmp to pushid *(DWORD*)((BYTE*)addr + 1)=(DWORD)((BYTE*)(BYTE*)pHook->push_id - ((BYTE*)addr + 5)); } if(!safe_VirtualProtectEx((HANDLE)(-1), (LPVOID)pHook->exec_buf, 32, PAGE_EXECUTE_READWRITE, &dwTemp)){ *pError=KHOOK::PAGE_PROT_ERR; return 0; } if(!safe_VirtualProtectEx((HANDLE)(-1), (LPVOID)pHook->push_id, 16, PAGE_EXECUTE_READWRITE, &dwTemp)){ *pError=KHOOK::PAGE_PROT_ERR; return 0; } //safe_FlushInstructionCache((HANDLE)-1, 0, 0); return pHook; }