int disasmgetsize(uint addr, unsigned char* data) { Capstone cp; if(!cp.Disassemble(addr, data, MAX_DISASM_BUFFER)) return 1; return cp.Size(); }
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; }
static void HandleCapstoneOperand(Capstone & cp, int opindex, DISASM_ARG* arg) { const cs_x86 & x86 = cp.x86(); const cs_x86_op & op = x86.operands[opindex]; arg->segment = SEG_DEFAULT; strcpy_s(arg->mnemonic, cp.OperandText(opindex).c_str()); switch(op.type) { case X86_OP_REG: { const char* regname = cp.RegName((x86_reg)op.reg); arg->type = arg_normal; uint value; if(!valfromstring(regname, &value, true, true)) value = 0; arg->constant = arg->value = value; } break; case X86_OP_IMM: { arg->type = arg_normal; arg->constant = arg->value = (duint)op.imm; } break; case X86_OP_MEM: { arg->type = arg_memory; const x86_op_mem & mem = op.mem; if(mem.base == X86_REG_RIP) //rip-relative arg->constant = cp.Address() + (duint)mem.disp + cp.Size(); else arg->constant = (duint)mem.disp; uint value; if(!valfromstring(arg->mnemonic, &value, true, true)) return; arg->value = value; if(DbgMemIsValidReadPtr(value)) { switch(op.size) { case 1: DbgMemRead(value, (unsigned char*)&arg->memvalue, 1); break; case 2: DbgMemRead(value, (unsigned char*)&arg->memvalue, 2); break; case 4: DbgMemRead(value, (unsigned char*)&arg->memvalue, 4); break; case 8: DbgMemRead(value, (unsigned char*)&arg->memvalue, 8); break; } } } break; } }
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; }
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]); }
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; }
/** * @brief Return the address of the nth instruction after the instruction pointed by ip. @n * This function has been grabbed from OllyDbg ("Disassembleforward" in asmserv.c) * * @param[in] data Address of the data to disassemble * @param[in] base Original base address of the memory page (Required to disassemble destination addresses) * @param[in] size Size of the data block pointed by data * @param[in] ip RVA of the current instruction (Relative to data pointer) * @param[in] n Number of instruction next * * @return Return the RVA (Relative to the data pointer) of the nth instruction after the instruction pointed by ip */ ulong QBeaEngine::DisassembleNext(byte_t* data, duint base, duint size, duint 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(mCodeFoldingManager && mCodeFoldingManager->isFolded(ip + base)) { cmdsize = mCodeFoldingManager->getFoldEnd(ip + base) - (ip + base) + 1; } else { if(!cp.DisassembleSafe(ip + base, pdata, (int)size)) cmdsize = 1; else cmdsize = cp.Size(); cmdsize = mEncodeMap->getDataSize(base + ip, cmdsize); } pdata += cmdsize; ip += cmdsize; size -= cmdsize; } return ip; }
/** * @brief Return the address of the nth instruction before the instruction pointed by ip. @n * This function has been grabbed from OllyDbg ("Disassembleback" in asmserv.c) * * @param[in] data Address of the data to disassemble * @param[in] base Original base address of the memory page (Required to disassemble destination addresses) * @param[in] size Size of the data block pointed by data * @param[in] ip RVA of the current instruction (Relative to data pointer) * @param[in] n Number of instruction back * * @return Return the RVA (Relative to the data pointer) of the nth instruction before the instruction pointed by ip */ ulong QBeaEngine::DisassembleBack(byte_t* data, duint base, duint size, duint ip, int n) { int i; uint abuf[128], 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; //TODO: buffer overflow due to unchecked "back" value back = MAX_DISASM_BUFFER * (n + 3); // Instruction length limited to 16 if(ip < back) back = ip; addr = ip - back; if(mCodeFoldingManager && mCodeFoldingManager->isFolded(addr + base)) { duint newback = mCodeFoldingManager->getFoldBegin(addr + base); if(newback >= base && newback < size + base) addr = newback - base; } pdata = data + addr; for(i = 0; addr < ip; i++) { abuf[i % 128] = addr; if(mCodeFoldingManager && mCodeFoldingManager->isFolded(addr + base)) { duint newaddr = mCodeFoldingManager->getFoldBegin(addr + base); if(newaddr >= base) { addr = newaddr - base; } cmdsize = mCodeFoldingManager->getFoldEnd(addr + base) - (addr + base) + 1; } else { if(!cp.DisassembleSafe(addr + base, pdata, (int)size)) cmdsize = 2; //heuristic for better output (FF FE or FE FF are usually part of an instruction) else cmdsize = cp.Size(); cmdsize = mEncodeMap->getDataSize(base + addr, cmdsize); } pdata += cmdsize; addr += cmdsize; back -= cmdsize; size -= cmdsize; } if(i < n) return abuf[0]; else return abuf[(i - n + 128) % 128]; }
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; } } }