DWORD_PTR IATSearch::findNextFunctionAddress() { #ifdef DEBUG_COMMENTS _DecodedInst inst; #endif for (unsigned int i = 0; i < decomposerInstructionsCount; i++) { if (decomposerResult[i].flags != FLAG_NOT_DECODABLE) { if (META_GET_FC(decomposerResult[i].meta) == FC_CALL || META_GET_FC(decomposerResult[i].meta) == FC_UNC_BRANCH) { if (decomposerResult[i].size >= 5) { if (decomposerResult[i].ops[0].type == O_PC) { #ifdef DEBUG_COMMENTS distorm_format(&decomposerCi, &decomposerResult[i], &inst); Scylla::debugLog.log(L"%S %S %d %d - target address: " PRINTF_DWORD_PTR_FULL, inst.mnemonic.p, inst.operands.p, decomposerResult[i].ops[0].type, decomposerResult[i].size, INSTRUCTION_GET_TARGET(&decomposerResult[i])); #endif return (DWORD_PTR)INSTRUCTION_GET_TARGET(&decomposerResult[i]); } } } } } return 0; }
// - 'call dword ptr [0xC0DEC0DE]' (6 bytes) // - 'call dword ptr <reg + 32bit_displacement>' (6 bytes) // - 'call 0xC0DEC0DE' (5 bytes) // - 'call dword ptr <reg>' (2 bytes) // - 'call dword ptr <reg + 8bit_displacement>' (3 bytes) // - 'call dword ptr <reg1 + reg2 + 8bit_displacement>' (4 bytes) // - 'call dword ptr <reg1 + reg2 + 32bit_displacement>' (7 bytes) // // bExactCheck decides whether we checks target of the call instruction // matches critical function. BOOL CheckCaller( IN ULONG_PTR lpReturningAddress, IN BOOL bExactCheck, IN ROP_CALLEE RopCallee, IN ULONG *pGeneralRegisters) { CONST DWORD CallInstructionLength[] = {6, 5, 2, 3, 4, 7}; CONST DWORD dwMaxInstructions = 7; _DInst DecodedInstructions[dwMaxInstructions]; /* There might be 7 instructions in all */ DWORD dwDecodedInstructionsCount = 0; _CodeInfo ci; for(DWORD i = 0; i < sizeof(CallInstructionLength) / sizeof(DWORD); ++i) { ci.code = (BYTE*)(lpReturningAddress - CallInstructionLength[i]); ci.codeLen = CallInstructionLength[i]; ci.codeOffset = 0; ci.dt = Decode32Bits; ci.features = DF_NONE; distorm_decompose(&ci, DecodedInstructions, dwMaxInstructions, (unsigned int*)&dwDecodedInstructionsCount); if(dwDecodedInstructionsCount != 1 || DecodedInstructions[0].flags == FLAG_NOT_DECODABLE) { continue; } ULONG_PTR lpCallingTarget = 0; if(DecodedInstructions[0].opcode == I_CALL) { if(!bExactCheck) { return TRUE; } else { _DInst* pInstr = &DecodedInstructions[0]; /* Single operand only for call instructions */ switch(pInstr->ops[0].type) { case O_REG: lpCallingTarget = GENERAL_REGISTER(pInstr->ops[0].index); break; case O_SMEM: lpCallingTarget = *(ULONG_PTR*)(GENERAL_REGISTER(pInstr->ops[0].index) + pInstr->disp); break; case O_MEM: lpCallingTarget = *(ULONG_PTR*) ( GENERAL_REGISTER(pInstr->base) /* base */ + GENERAL_REGISTER(pInstr->ops[0].index) * pInstr->scale /* index and scale */ + pInstr->disp /* displacement */ ); break; case O_PC: lpCallingTarget = (ULONG_PTR)INSTRUCTION_GET_TARGET(pInstr); break; case O_DISP: lpCallingTarget = *(ULONG_PTR*)(pInstr->disp); break; default: DEBUG_PRINTF(LDBG, NULL, "Error occurs in CALL_VALIDATION. Operand type = %x.\n", pInstr->ops[0].type); break; } } if(lpCallingTarget == (ULONG_PTR)GetCriticalFunctionAddress(RopCallee)) { return TRUE; } } /* TODO: Handle those more complicated cases, like jmp and so on */ } return FALSE; }