void disasmget(unsigned char* buffer, uint addr, DISASM_INSTR* instr) { if(!DbgIsDebugging()) { if(instr) instr->argcount = 0; return; } memset(instr, 0, sizeof(DISASM_INSTR)); Capstone cp; if(!cp.Disassemble(addr, buffer, MAX_DISASM_BUFFER)) { strcpy_s(instr->instruction, "???"); instr->instr_size = 1; instr->type = instr_normal; instr->argcount = 0; return; } const cs_insn* cpInstr = cp.GetInstr(); sprintf_s(instr->instruction, "%s %s", cpInstr->mnemonic, cpInstr->op_str); const cs_x86 & x86 = cpInstr->detail->x86; instr->instr_size = cpInstr->size; if(cp.InGroup(CS_GRP_JUMP) || cp.IsLoop() || cp.InGroup(CS_GRP_RET) || cp.InGroup(CS_GRP_CALL)) instr->type = instr_branch; else if(strstr(cpInstr->op_str, "sp") || strstr(cpInstr->op_str, "bp")) instr->type = instr_stack; else instr->type = instr_normal; instr->argcount = cp.x86().op_count <= 3 ? cp.x86().op_count : 3; for(int i = 0; i < instr->argcount; i++) HandleCapstoneOperand(cp, i, &instr->arg[i]); }
void LinearPass::AnalysisWorker(duint Start, duint End, BBlockArray* Blocks) { Capstone disasm; duint blockBegin = Start; // BBlock starting virtual address duint blockEnd = 0; // BBlock ending virtual address bool blockPrevPad = false; // Indicator if the last instruction was padding BasicBlock* lastBlock = nullptr; // Avoid an expensive call to std::vector::back() int insnCount = 0; // Temporary number of instructions counted for a block for(duint i = Start; i < End;) { if(!disasm.Disassemble(i, TranslateAddress(i), int(End - i))) { // Skip instructions that can't be determined i++; continue; } // Increment counters i += disasm.Size(); blockEnd = i; insnCount++; // The basic block ends here if it is a branch bool call = disasm.InGroup(CS_GRP_CALL); // CALL bool jmp = disasm.InGroup(CS_GRP_JUMP); // JUMP bool ret = disasm.InGroup(CS_GRP_RET); // RETURN bool padding = disasm.IsFilling(); // INSTRUCTION PADDING if(padding) { // PADDING is treated differently. They are all created as their // own separate block for more analysis later. duint realBlockEnd = blockEnd - disasm.Size(); if((realBlockEnd - blockBegin) > 0) { // The next line terminates the BBlock before the INT instruction. // Early termination, faked as an indirect JMP. Rare case. lastBlock = CreateBlockWorker(Blocks, blockBegin, realBlockEnd, false, false, false, false); lastBlock->SetFlag(BASIC_BLOCK_FLAG_PREPAD); blockBegin = realBlockEnd; lastBlock->InstrCount = insnCount; insnCount = 0; } } if(call || jmp || ret || padding) { // Was this a padding instruction? if(padding && blockPrevPad) { // Append it to the previous block lastBlock->VirtualEnd = blockEnd; } else { // Otherwise use the default route: create a new entry auto block = lastBlock = CreateBlockWorker(Blocks, blockBegin, blockEnd, call, jmp, ret, padding); // Counters lastBlock->InstrCount = insnCount; insnCount = 0; if(!padding) { // Check if absolute jump, regardless of operand if(disasm.GetId() == X86_INS_JMP) block->SetFlag(BASIC_BLOCK_FLAG_ABSJMP); // Figure out the operand type(s) const auto & operand = disasm.x86().operands[0]; if(operand.type == X86_OP_IMM) { // Branch target immediate block->Target = (duint)operand.imm; } else { // Indirects (no operand, register, or memory) block->SetFlag(BASIC_BLOCK_FLAG_INDIRECT); if(operand.type == X86_OP_MEM && operand.mem.base == X86_REG_RIP && operand.mem.index == X86_REG_INVALID && operand.mem.scale == 1) { /* block->SetFlag(BASIC_BLOCK_FLAG_INDIRPTR); block->Target = (duint)operand.mem.disp; */ } } } } // Reset the loop variables blockBegin = i; blockPrevPad = padding; } } }