/** --------------------------------------------------------------------------- \brief calculate instruction length of Addr \param \return \code \endcode -----------------------------------------------------------------------------*/ int GetInstructionLength(BYTE* Addr) { #ifdef _USE_LIBDASM_LIB INSTRUCTION instr = {0}; int Len = get_instruction(&instr, Addr, MODE_32); // check illegal opcode if (0 == Len) { _ASSERTE(!"get_instruction"); return -1; } #ifdef _DEBUG char string[256] = {0}; get_instruction_string(&instr, FORMAT_INTEL, 0, string, sizeof(string)); _tprintf(TEXT("%s\n"), string); #endif return Len; #else DISASSEMBLER Disassembler; INSTRUCTION * Instruction = NULL; if (TRUE != InitDisassembler(&Disassembler, ARCH_X86)) { _ASSERTE(!"InitDisassembler"); return -1; } ULONG Flags = DISASM_DISASSEMBLE | DISASM_DECODE | DISASM_STOPONERROR | DISASM_STOPONANOMALY | DISASM_STOPONRETURN; Instruction = GetInstruction(&Disassembler, (ULONG)Addr, (PBYTE)Addr, Flags); if (!Instruction) { _ASSERTE(!"GetInstruction"); CloseDisassembler(&Disassembler); return -1; } #ifdef _DEBUG DumpInstruction(Instruction, TRUE, TRUE); #endif int Len = Instruction->Length; CloseDisassembler(&Disassembler); return Len; #endif//_USE_LIBDASM_LIB }
static size_t dpCopyInstructions(void *dst, void *src, size_t minlen) { #ifdef dpWithTDisasm size_t len = 0; #ifdef _M_X64 ARCHITECTURE_TYPE arch = ARCH_X64; #elif defined _M_IX86 ARCHITECTURE_TYPE arch = ARCH_X86; #endif DISASSEMBLER dis; if(InitDisassembler(&dis, arch)) { INSTRUCTION* pins = NULL; U8* pLoc = (U8*)src; U8* pDst = (U8*)dst; DWORD dwFlags = DISASM_SUPPRESSERRORS; while( len<minlen ) { pins = GetInstruction(&dis, (ULONG_PTR)pLoc, pLoc, dwFlags); if(!pins) { break; } if(pins->Type == ITYPE_RET ) { break; } //// todo: call or jmp //if(pins->Type == ITYPE_BRANCH ) break; //if(pins->Type == ITYPE_BRANCHCC) break; //if(pins->Type == ITYPE_CALL ) break; //if(pins->Type == ITYPE_CALLCC ) break; switch(pLoc[0]) { // call & jmp case 0xE8: case 0xE9: { int rva = *(int*)(pLoc+1); pDst[0] = pLoc[0]; *(DWORD*)(pDst+1) = (DWORD)((ptrdiff_t)(pLoc+rva)-(ptrdiff_t)(pDst)); } break; default: memcpy(pDst, pLoc, pins->Length); break; } len += pins->Length; pLoc += pins->Length; pDst += pins->Length; } CloseDisassembler(&dis); } return len; #else // dpWithTDisasm memcpy(dst, src, minlen); return minlen; #endif // dpWithTDisasm }
//========================================================================= // Examine the machine code at the target function's entry point, and // skip bytes in a way that we'll always end on an instruction boundary. // We also detect branches and subroutine calls (as well as returns) // at which point disassembly must stop. // Finally, detect and collect information on IP-relative instructions // that we can patch. static DWORD DisassembleAndSkip(PVOID pFunction, DWORD dwMinLen, MHOOKS_PATCHDATA* pdata) { DWORD dwRet = 0; pdata->nLimitDown = 0; pdata->nLimitUp = 0; pdata->nRipCnt = 0; #ifdef _M_IX86 ARCHITECTURE_TYPE arch = ARCH_X86; #elif defined _M_X64 ARCHITECTURE_TYPE arch = ARCH_X64; #else #error unsupported platform #endif DISASSEMBLER dis; if (InitDisassembler(&dis, arch)) { INSTRUCTION* pins = NULL; U8* pLoc = (U8*)pFunction; DWORD dwFlags = DISASM_DECODE | DISASM_DISASSEMBLE | DISASM_ALIGNOUTPUT; ODPRINTF((L"mhooks: DisassembleAndSkip: Disassembling %p", pLoc)); while ( (dwRet < dwMinLen) && (pins = GetInstruction(&dis, (ULONG_PTR)pLoc, pLoc, dwFlags)) ) { ODPRINTF(("mhooks: DisassembleAndSkip: %p:(0x%2.2x) %s", pLoc, pins->Length, pins->String)); if (pins->Type == ITYPE_RET ) break; if (pins->Type == ITYPE_BRANCH ) break; if (pins->Type == ITYPE_BRANCHCC) break; if (pins->Type == ITYPE_CALL ) break; if (pins->Type == ITYPE_CALLCC ) break; #if defined _M_X64 BOOL bProcessRip = FALSE; // mov or lea to register from rip+imm32 if ((pins->Type == ITYPE_MOV || pins->Type == ITYPE_LEA) && (pins->X86.Relative) && (pins->X86.OperandSize == 8) && (pins->OperandCount == 2) && (pins->Operands[1].Flags & OP_IPREL) && (pins->Operands[1].Register == AMD64_REG_RIP)) { // rip-addressing "mov reg, [rip+imm32]" ODPRINTF((L"mhooks: DisassembleAndSkip: found OP_IPREL on operand %d with displacement 0x%x (in memory: 0x%x)", 1, pins->X86.Displacement, *(PDWORD)(pLoc+3))); bProcessRip = TRUE; } // mov or lea to rip+imm32 from register else if ((pins->Type == ITYPE_MOV || pins->Type == ITYPE_LEA) && (pins->X86.Relative) && (pins->X86.OperandSize == 8) && (pins->OperandCount == 2) && (pins->Operands[0].Flags & OP_IPREL) && (pins->Operands[0].Register == AMD64_REG_RIP)) { // rip-addressing "mov [rip+imm32], reg" ODPRINTF((L"mhooks: DisassembleAndSkip: found OP_IPREL on operand %d with displacement 0x%x (in memory: 0x%x)", 0, pins->X86.Displacement, *(PDWORD)(pLoc+3))); bProcessRip = TRUE; } else if ( (pins->OperandCount >= 1) && (pins->Operands[0].Flags & OP_IPREL) ) { // unsupported rip-addressing ODPRINTF((L"mhooks: DisassembleAndSkip: found unsupported OP_IPREL on operand %d", 0)); // dump instruction bytes to the debug output for (DWORD i=0; i<pins->Length; i++) { ODPRINTF((L"mhooks: DisassembleAndSkip: instr byte %2.2d: 0x%2.2x", i, pLoc[i])); } break; } else if ( (pins->OperandCount >= 2) && (pins->Operands[1].Flags & OP_IPREL) ) { // unsupported rip-addressing ODPRINTF((L"mhooks: DisassembleAndSkip: found unsupported OP_IPREL on operand %d", 1)); // dump instruction bytes to the debug output for (DWORD i=0; i<pins->Length; i++) { ODPRINTF((L"mhooks: DisassembleAndSkip: instr byte %2.2d: 0x%2.2x", i, pLoc[i])); } break; } else if ( (pins->OperandCount >= 3) && (pins->Operands[2].Flags & OP_IPREL) ) { // unsupported rip-addressing ODPRINTF((L"mhooks: DisassembleAndSkip: found unsupported OP_IPREL on operand %d", 2)); // dump instruction bytes to the debug output for (DWORD i=0; i<pins->Length; i++) { ODPRINTF((L"mhooks: DisassembleAndSkip: instr byte %2.2d: 0x%2.2x", i, pLoc[i])); } break; } // follow through with RIP-processing if needed if (bProcessRip) { // calculate displacement relative to function start S64 nAdjustedDisplacement = pins->X86.Displacement + (pLoc - (U8*)pFunction); // store displacement values furthest from zero (both positive and negative) if (nAdjustedDisplacement < pdata->nLimitDown) pdata->nLimitDown = nAdjustedDisplacement; if (nAdjustedDisplacement > pdata->nLimitUp) pdata->nLimitUp = nAdjustedDisplacement; // store patch info if (pdata->nRipCnt < MHOOKS_MAX_RIPS) { pdata->rips[pdata->nRipCnt].dwOffset = dwRet + 3; pdata->rips[pdata->nRipCnt].nDisplacement = pins->X86.Displacement; pdata->nRipCnt++; } else { // no room for patch info, stop disassembly break; } } #endif dwRet += pins->Length; pLoc += pins->Length; } CloseDisassembler(&dis); } return dwRet; }