int Hook::getCompleteInstructions(const int bytes_needed, char *out_buffer, int *out_size) { if ((bytes_needed == 0) || !source_function) return -1; _DInst *decodedInstructions = nullptr; unsigned int decodedInstructionsCount = 0; decodedInstructions = static_cast<_DInst *>(HeapAlloc(hHeap, HEAP_ZERO_MEMORY, bytes_needed*sizeof(_DInst))); if (!decodedInstructions) return -1; // Dissasamble the function ... _CodeInfo ci; ci.code = reinterpret_cast<const uint8_t *>(source_function); ci.codeLen = bytes_needed*2; ci.codeOffset = 0; #if defined(_X86_) // Defined on the command line by a linker variable. // the target architecture is x86 ci.dt = Decode32Bits; #elif defined(_AMD64_) // the target architecture is AMD x86-64 ci.dt = Decode64Bits; #endif ci.features = DF_NONE; distorm_decompose(&ci, decodedInstructions, bytes_needed, &decodedInstructionsCount); // Get the size of the fewest instructions ... bytes_needed <= instruction_size int current_size = 0; for (int i = 0; i < bytes_needed; ++i) { if (current_size < bytes_needed) current_size += (decodedInstructions+i)->size; else break; } HeapFree(hHeap, 0, decodedInstructions); if (!out_buffer || (*out_size < current_size)) { // Not enough space in output buffer *out_size = current_size; return 0; } CopyMemory(out_buffer, reinterpret_cast<void *>(source_function), current_size); return current_size; }
blockinfo get_block_stats(const uint8_t *buf, unsigned long pc, size_t size, bool use64bit){ blockinfo retval = {0,0}; #if defined(TARGET_I386) _DInst dec[256]; unsigned int dec_count = 0; _DecodeType dt = use64bit ? Decode64Bits : Decode32Bits; _CodeInfo ci; ci.code = buf; ci.codeLen = size; ci.codeOffset = pc; ci.dt = dt; ci.features = DF_NONE; distorm_decompose(&ci, dec, 256, &dec_count); for (int i = dec_count - 1; i >= 0; i--) { _DecodedInst inst; if (dec[i].flags == FLAG_NOT_DECODABLE) { printf("Instruction not decodable %lX\n", dec[i].addr); break; } switch(icls[dec[i].opcode]){ case ICLS_NORMAL: retval.total_instr++; break; case ICLS_WARN: distorm_format(&ci, &dec[i], &inst); fprintf(stderr,"Could not classify instruction %s %s\n", inst.mnemonic.p, inst.operands.p); retval.total_instr++; break; case ICLS_BITARITH: retval.arith_instr++; retval.total_instr++; break; case ICLS_MOV: break; } } #else fprintf(stderr, "Architecture not supported\n"); #endif return retval; }
bool ProcessAccessHelp::decomposeMemory(BYTE * dataBuffer, SIZE_T bufferSize, DWORD_PTR startAddress) { ZeroMemory(&decomposerCi, sizeof(_CodeInfo)); decomposerCi.code = dataBuffer; decomposerCi.codeLen = (int)bufferSize; decomposerCi.dt = dt; decomposerCi.codeOffset = startAddress; decomposerInstructionsCount = 0; if (distorm_decompose(&decomposerCi, decomposerResult, sizeof(decomposerResult)/sizeof(decomposerResult[0]), &decomposerInstructionsCount) == DECRES_INPUTERR) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"decomposeMemory :: distorm_decompose == DECRES_INPUTERR"); #endif return false; } else { return true; } }
// - '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; }