uint disasmnext(unsigned char* data, uint base, uint size, uint ip, int n) { int i; uint cmdsize; unsigned char* pdata; // Reset Disasm Structure Capstone cp; if(data == NULL) return 0; if(ip >= size) ip = size - 1; if(n <= 0) return ip; pdata = data + ip; size -= ip; for(i = 0; i < n && size > 0; i++) { if(!cp.Disassemble(0, pdata, (int)size)) cmdsize = 1; else cmdsize = cp.Size(); pdata += cmdsize; ip += cmdsize; size -= cmdsize; } return ip; }
int disasmgetsize(uint addr, unsigned char* data) { Capstone cp; if(!cp.Disassemble(addr, data, MAX_DISASM_BUFFER)) return 1; return cp.Size(); }
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]); }
uint disasmback(unsigned char* data, uint base, uint size, uint ip, int n) { int i; uint abuf[131], addr, back, cmdsize; unsigned char* pdata; // Reset Disasm Structure Capstone cp; // Check if the pointer is not null if(data == NULL) return 0; // Round the number of back instructions to 127 if(n < 0) n = 0; else if(n > 127) n = 127; // Check if the instruction pointer ip is not outside the memory range if(ip >= size) ip = size - 1; // Obvious answer if(n == 0) return ip; if(ip < (uint)n) return ip; back = MAX_DISASM_BUFFER * (n + 3); // Instruction length limited to 16 if(ip < back) back = ip; addr = ip - back; pdata = data + addr; for(i = 0; addr < ip; i++) { abuf[i % 128] = addr; if(!cp.Disassemble(0, pdata, (int)size)) cmdsize = 1; else cmdsize = cp.Size(); pdata += cmdsize; addr += cmdsize; back -= cmdsize; size -= cmdsize; } if(i < n) return abuf[0]; else return abuf[(i - n + 128) % 128]; }
int RefFindInRange(duint scanStart, duint scanSize, CBREF Callback, void* UserData, bool Silent, REFINFO & refInfo, Capstone & cp, bool initCallBack, CBPROGRESS cbUpdateProgress) { // Allocate and read a buffer from the remote process Memory<unsigned char*> data(scanSize, "reffind:data"); if(!MemRead(scanStart, data(), scanSize)) { if(!Silent) dprintf("Error reading memory in reference search\n"); return 0; } if(initCallBack) Callback(0, 0, &refInfo); //concurrency::parallel_for(duint (0), scanSize, [&](duint i) for(duint i = 0; i < scanSize;) { // Print the progress every 4096 bytes if((i % 0x1000) == 0) { // Percent = (current / total) * 100 // Integer = floor(percent) int percent = (int)floor(((float)i / (float)scanSize) * 100.0f); cbUpdateProgress(percent); } // Disassemble the instruction int disasmMaxSize = min(MAX_DISASM_BUFFER, (int)(scanSize - i)); // Prevent going past the boundary int disasmLen = 1; if(cp.Disassemble(scanStart, data() + i, disasmMaxSize)) { BASIC_INSTRUCTION_INFO basicinfo; fillbasicinfo(&cp, &basicinfo); if(Callback(&cp, &basicinfo, &refInfo)) refInfo.refcount++; disasmLen = cp.Size(); } else { // Invalid instruction detected, so just skip the byte } scanStart += disasmLen; i += disasmLen; } cbUpdateProgress(100); return refInfo.refcount; }
const char* disasmtext(uint addr) { unsigned char buffer[MAX_DISASM_BUFFER] = ""; DbgMemRead(addr, buffer, sizeof(buffer)); Capstone cp; static char instruction[64] = ""; if(!cp.Disassemble(addr, buffer)) strcpy_s(instruction, "???"); else sprintf_s(instruction, "%s %s", cp.GetInstr()->mnemonic, cp.GetInstr()->op_str); return instruction; }
bool disasmfast(const unsigned char* data, duint addr, BASIC_INSTRUCTION_INFO* basicinfo) { if(!data || !basicinfo) return false; Capstone cp; if(!cp.Disassemble(addr, data, MAX_DISASM_BUFFER)) { strcpy_s(basicinfo->instruction, "???"); basicinfo->size = 1; return false; } fillbasicinfo(&cp, basicinfo); return true; }
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; } } }