static const char *disassemble(unsigned char *insn, int len, uint64_t rip, int cr0_pe, int eflags_vm, int cs_d, int cs_l) { int mode; if (!cr0_pe) mode = 16; else if (eflags_vm) mode = 16; else if (cs_l) mode = 64; else if (cs_d) mode = 32; else mode = 16; ud_set_pc(&ud, rip); ud_set_mode(&ud, mode); ud_set_input_buffer(&ud, insn, len); ud_disassemble(&ud); return ud_insn_asm(&ud); }
struct _ins * redis_x86_create_ins (struct _redis_x86 * redis_x86) { ud_t ud_obj; ud_init(&ud_obj); ud_set_mode(&ud_obj, 32); ud_set_syntax(&ud_obj, UD_SYN_INTEL); ud_set_input_buffer(&ud_obj, redis_x86->ins_bytes, redis_x86->ins_size); if (ud_disassemble(&ud_obj) == 0) { fprintf(stderr, "disassembly error %p %d\n", redis_x86->ins_bytes, (int) redis_x86->ins_size); return NULL; } struct _ins * ins = ins_create(redis_x86->ins_addr, ud_insn_ptr(&ud_obj), ud_insn_len(&ud_obj), ud_insn_asm(&ud_obj), NULL); return ins; }
/* * 如果是纯数据区域直接返回TRUE,反之返回FALSE */ __INLINE__ __bool __INTERNAL_FUNC__ DeepAnalyzeBlock(__memory pMem, __address ImageBase, __memory pCurr, __integer iSize, PANALYZE_CONFIGURE pAnalyzeConfigure) { __bool bBlock = FALSE; ud_t ud_obj; ud_init(&ud_obj); ud_set_mode(&ud_obj, 32); ud_set_syntax(&ud_obj, UD_SYN_INTEL); ud_set_input_buffer(&ud_obj, pCurr, iSize); while (ud_disassemble(&ud_obj)) { enum ud_mnemonic_code mnemonic = ud_obj.mnemonic; if ((mnemonic == UD_Iinvalid) && (!(pAnalyzeConfigure->bDisInvalidOpcodeIsData))) { bBlock = TRUE; return bBlock; } } /* * 进行深度分析 */ bBlock = AbyssAnalyze(pMem, ImageBase, pCurr, iSize); return bBlock; }
bool tryToDisassemble(const MacroAssemblerCodePtr& codePtr, size_t size, const char* prefix, PrintStream& out) { ud_t disassembler; ud_init(&disassembler); ud_set_input_buffer(&disassembler, static_cast<unsigned char*>(codePtr.executableAddress()), size); #if CPU(X86_64) ud_set_mode(&disassembler, 64); #else ud_set_mode(&disassembler, 32); #endif ud_set_pc(&disassembler, bitwise_cast<uintptr_t>(codePtr.executableAddress())); ud_set_syntax(&disassembler, UD_SYN_ATT); uint64_t currentPC = disassembler.pc; while (ud_disassemble(&disassembler)) { char pcString[20]; print(pcString, sizeof(pcString), currentPC); out.printf("%s%16s: %s\n", prefix, pcString, ud_insn_asm(&disassembler)); currentPC = disassembler.pc; } return true; }
MDBCodeRegion * MDBCodeRegion::fromProcedure(MDBDebugger *debugger, uintptr_t address) { size_t bufferSize = 128; char buffer[bufferSize]; if (debugger->read(buffer, address, sizeof(buffer)) != (int) sizeof(buffer)) { log.traceLn("Cannot read procedure memory."); } ud_t ud_obj; ud_init(&ud_obj); ud_set_input_buffer(&ud_obj, (uint8_t*)buffer, bufferSize); ud_set_mode(&ud_obj, 32); ud_set_syntax(&ud_obj, UD_SYN_INTEL); size_t remaining = bufferSize; do { int pc = ud_obj.pc; size_t instructionSize = ud_disassemble(&ud_obj); remaining -= instructionSize; log.traceLn("decoded: 0x%llx %s", pc, ud_insn_asm(&ud_obj)); } while (remaining > 0); return NULL; }
//-------------------------------------------------------------------------------------- PVOID Hook(PVOID Function, PVOID Handler, PULONG pBytesPatched) { #ifdef _X86_ #define SIZEOFJUMP 6 #elif _AMD64_ #define SIZEOFJUMP 14 #endif ULONG Size = 0, CollectedSpace = 0; PUCHAR pInst = (PUCHAR)Function; if (pBytesPatched) { *pBytesPatched = NULL; } // initialize disassembler engine ud_t ud_obj; ud_init(&ud_obj); // set mode, syntax and vendor ud_set_mode(&ud_obj, UD_MODE); ud_set_syntax(&ud_obj, UD_SYN_INTEL); ud_set_vendor(&ud_obj, UD_VENDOR_INTEL); while (CollectedSpace < SIZEOFJUMP) { ud_set_input_buffer(&ud_obj, pInst, MAX_INST_LEN); // get length of instruction ULONG dwInstLen = ud_disassemble(&ud_obj); if (dwInstLen == 0) { // error while disassembling instruction DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Can't disassemble instruction at "IFMT"\n", pInst); return NULL; } if (ud_obj.mnemonic == UD_Ijmp || ud_obj.mnemonic == UD_Icall) { // call/jmp with relative address DbgMsg(__FILE__, __LINE__, __FUNCTION__"() call/jmp/jxx instruction at "IFMT"\n", pInst); return NULL; } for (int i = 0; i < 3; i++) { if (ud_obj.operand[i].type == UD_OP_JIMM) { // jxx with relative address DbgMsg(__FILE__, __LINE__, __FUNCTION__"() jxx instruction at "IFMT"\n", pInst); return NULL; } } pInst += dwInstLen; CollectedSpace += dwInstLen; if (ud_obj.mnemonic == UD_Iret || ud_obj.mnemonic == UD_Iretf || ud_obj.mnemonic == UD_Iiretw || ud_obj.mnemonic == UD_Iiretq || ud_obj.mnemonic == UD_Iiretd) { // end of the function thunk? DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ret/retn/iret instruction at "IFMT"\n", pInst); break; } } if (SIZEOFJUMP > CollectedSpace) { DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: not enough memory for jump\n"); return NULL; } ULONG CallGateSize = CollectedSpace + SIZEOFJUMP; // allocate memory for callgate PVOID CallGate = M_ALLOC(CallGateSize); if (CallGate) { // generate callgate memset(CallGate, 0x90, CallGateSize); // save begining of the function memcpy(CallGate, Function, CollectedSpace); #ifdef _X86_ // jump from callgate to function body // push imm32 *(PUCHAR)((PUCHAR)CallGate + CollectedSpace) = 0x68; *(PUCHAR *)((PUCHAR)CallGate + CollectedSpace + 1) = (PUCHAR)Function + SIZEOFJUMP; // ret *(PUCHAR)((PUCHAR)CallGate + CollectedSpace + 5) = 0xC3; #elif _AMD64_ // jmp qword [addr] *(PUSHORT)((PUCHAR)CallGate + CollectedSpace) = 0x25FF; *(PULONG)((PUCHAR)CallGate + CollectedSpace + 2) = 0; // addr dq XXXh *(PULONGLONG)((PUCHAR)CallGate + CollectedSpace + 6) = (ULONGLONG)Function + SIZEOFJUMP; #endif // jump from the function to callgate memset(Function, 0x90, CollectedSpace); #ifdef _X86_ // push imm32 *(PUCHAR)Function = 0x68; *(PUCHAR *)((PUCHAR)Function + 1) = (PUCHAR)Handler; // ret *(PUCHAR)((PUCHAR)Function + 5) = 0xC3; #elif _AMD64_ // jmp qword [addr] *(PUSHORT)Function = 0x25FF; *(PULONG)((PUCHAR)Function + 2) = 0; // addr dq XXXh *(PULONGLONG)((PUCHAR)Function + 6) = (ULONGLONG)Handler; #endif *pBytesPatched = CollectedSpace; return CallGate; } else { DbgMsg(__FILE__, __LINE__, "M_ALLOC() fails\n"); } return NULL; }
/* * 进行分区处理 * 以NOP,INT3,0,无效指令编码字符进行分区标志 * 遇到NOP或者INT3,0,无效指令编码则将扫描过的区域 * 作为一个区块摘出,继续查询,如果其后的数据有很长 * 一段为连续的 NOP,INT3,0字节则将此视做绝对无效区域, * 在扫描过程中,如果遇到无效指令直接忽略当作这个区域 * 的一部分如果遇到有效指令,则进入预分析阶段,尝试向前 * 分析如果分析的指令长度小于最小代码长度则直接忽略.如果 * 大于则将此区域继续分析,往返以上流程.直到完毕 */ __INLINE__ PPROCEDURE __INTERNAL_FUNC__ FormatBlock(__memory pMem, __address ImageBase, __memory pStart, __integer iSize, PANALYZE_CONFIGURE pAnalyzeConfigure) { __integer iBlockEndSignCount = 0; __offset ofOffset = 0; PPROCEDURE pBlock = NULL; PPROCEDURE *pCurrBlockPoint = &pBlock; ud_t ud_obj; ud_init(&ud_obj); ud_set_mode(&ud_obj, 32); ud_set_syntax(&ud_obj, UD_SYN_INTEL); ud_set_input_buffer(&ud_obj, pStart, iSize); while (ud_disassemble(&ud_obj)) { enum ud_mnemonic_code mnemonic = ud_obj.mnemonic; if ((mnemonic == UD_Inop) || \ (mnemonic == UD_Iint3) || \ ((mnemonic == UD_Iadd) && (ud_obj.inp_ctr == 2) && (*(__word *)&(ud_obj.inp_sess) == 0))) iBlockEndSignCount += (__integer)ud_insn_len(&ud_obj); else { /* * 遇到有效指令了 * 现在该进入预读分析阶段,这里还有一个判断 * 标志是剩余长度,如果其后的长度小于最小代码 * 长度直接将这段代码视作为数据 */ __integer iRemainSize = iSize - (__integer)ofOffset; __memory pCurr = pStart + (__integer)ofOffset; if (iRemainSize >= pAnalyzeConfigure->bCodeMixSize) { /* * 进入预读分析阶段 * 在这里开始判断,如果预读处理分析的结果为单纯的数据块则 * 与先前分析的区域进行合并 * 否则单独为前面分析的块分配内存 */ __integer iOutSize = 0; if (PredictBlockEnd(pMem, ImageBase, pCurr, iRemainSize, &iOutSize, pAnalyzeConfigure)) iBlockEndSignCount += iOutSize;//进行合并 else { /* * 判断上一组区块标记是否为0如果不为则分配空间存储它 */ if (iBlockEndSignCount) { (*pCurrBlockPoint) = __logic_new__(PROCEDURE, 1); __logic_memset__((*pCurrBlockPoint), 0, sizeof(PROCEDURE)); (*pCurrBlockPoint)->bBlock = TRUE;//数据区域 (*pCurrBlockPoint)->pFileStartAddress = pCurr - iBlockEndSignCount; (*pCurrBlockPoint)->addrMemoryStartAddress = ImageBase + AnalyzerRaw2Rva(pMem, (__integer)((*pCurrBlockPoint)->pFileStartAddress - pMem)); (*pCurrBlockPoint)->iSize = iBlockEndSignCount; pCurrBlockPoint = &((*pCurrBlockPoint)->pNext); iBlockEndSignCount = 0;//清空标志记录计数 } // 设定此段为代码区域 (*pCurrBlockPoint) = __logic_new__(PROCEDURE, 1); __logic_memset__((*pCurrBlockPoint), 0, sizeof(PROCEDURE)); (*pCurrBlockPoint)->bBlock = FALSE;//代码区域 (*pCurrBlockPoint)->pFileStartAddress = pCurr; (*pCurrBlockPoint)->addrMemoryStartAddress = ImageBase + AnalyzerRaw2Rva(pMem, (__integer)(pCurr - pMem)); (*pCurrBlockPoint)->iSize = iOutSize; pCurrBlockPoint = &((*pCurrBlockPoint)->pNext); } // 重新设定反汇编指针 pCurr += iOutSize; (__integer)ofOffset += iOutSize; iRemainSize -= iOutSize;//剩余长度 ud_set_input_buffer(&ud_obj, pCurr, iRemainSize); continue; } else { // 进入到这里就是进入到分析的末尾 (*pCurrBlockPoint) = __logic_new__(PROCEDURE, 1); __logic_memset__((*pCurrBlockPoint), 0, sizeof(PROCEDURE)); (*pCurrBlockPoint)->bBlock = TRUE;//表示有可能是数据 iBlockEndSignCount += iRemainSize; (*pCurrBlockPoint)->iSize = iBlockEndSignCount; (*pCurrBlockPoint)->pFileStartAddress = pCurr; (*pCurrBlockPoint)->addrMemoryStartAddress = ImageBase + AnalyzerRaw2Rva(pMem, (__integer)(pCurr - pMem)); pCurrBlockPoint = &((*pCurrBlockPoint)->pNext); iBlockEndSignCount = 0;//清空标志记录计数 } } (__integer)ofOffset += ud_insn_len(&ud_obj); } /* * 处理组后一个纯区域块 * 两种情况造成这种现象 * 1) 整个分析的数据都是纯数据区 * 2) 被分析的数据最后一个区域是纯数据区 */ if (iBlockEndSignCount) { __memory pBlockZoon = NULL; // 第一种情况 if (iBlockEndSignCount == iSize) pBlockZoon = pStart; else pBlockZoon = pStart + iSize - iBlockEndSignCount; (*pCurrBlockPoint) = __logic_new__(PROCEDURE, 1); __logic_memset__((*pCurrBlockPoint), 0, sizeof(PROCEDURE)); (*pCurrBlockPoint)->bBlock = TRUE;//表示有可能是数据 (*pCurrBlockPoint)->iSize = iBlockEndSignCount; (*pCurrBlockPoint)->pFileStartAddress = pBlockZoon; (*pCurrBlockPoint)->addrMemoryStartAddress = ImageBase + AnalyzerRaw2Rva(pMem, (__integer)(pBlockZoon - pMem)); pCurrBlockPoint = &((*pCurrBlockPoint)->pNext); iBlockEndSignCount = 0;//清空标志记录计数 } return pBlock; }
AddressArray Analysis::analysis_code_piece_address(pCodeBufferInfo pinfo) { ud_t ud_obj; ud_init(&ud_obj); #ifndef PROTECT_X64 ud_set_mode(&ud_obj,32); #else ud_set_mode(&ud_obj,64); #endif ud_set_pc(&ud_obj,pinfo->addr); ud_set_input_buffer(&ud_obj, (uint8_t*)pinfo->buf, pinfo->size); ud_set_syntax(&ud_obj,UD_SYN_INTEL); base = pinfo->addr; size = pinfo->size; std::vector <long> address_array; //pAssemblerTree root = new AssemblerTree; // pAssemblerTree nowtree = root; address_array.push_back(pinfo->addr); address_array.push_back(pinfo->addr + pinfo->size); while (ud_disassemble(&ud_obj) != 0) { //if (ud_obj.operand[0].type == UD_OP_JIMM || ud_obj.mnemonic == UD_Icall )//&& ud_obj.mnemonic != UD_Icall) if (ud_obj.pfx_rep != 0 || ud_obj.pfx_repe != 0 || ud_obj.pfx_repne != 0) //有前缀 { address_array.push_back(ud_obj.pc); address_array.push_back(ud_obj.insn_offset); } if (ud_obj.operand[0].type == UD_OP_JIMM ) { long addr = ud_obj.operand[0].size == 8 ? ((signed char)ud_obj.operand[0].lval.sbyte + ud_obj.pc) : (ud_obj.operand[0].lval.sdword + ud_obj.pc); if (addr >= pinfo->addr && addr <= pinfo->addr + pinfo->size) { address_array.push_back(addr); address_array.push_back(ud_obj.pc); } else { //address_array.push_back(ud_obj.pc); if (ud_obj.mnemonic != UD_Icall && ud_obj.mnemonic != UD_Ijmp) { printf("%x:跳转的地址无法找到:",ud_obj.insn_offset); printf("%x\n",addr); // __asm("int3"); //表示跳转地址是一个jcc指令 } else { address_array.push_back(ud_obj.pc); } } } if (ud_obj.mnemonic == UD_Iret || ud_obj.mnemonic == UD_Icall || ud_obj.mnemonic == UD_Ijmp) { address_array.push_back(ud_obj.pc); } /*if (ud_obj.mnemonic == UD_Icall || ud_obj.mnemonic == UD_Iret) { address_array.push_back(ud_obj.pc); }*/ } long count = 0; size_t address_size = address_array.size(); AddressArray a_array(address_size); for (std::vector <long>::iterator iter = address_array.begin() ; iter != address_array.end() ; ++iter) { bool fk = true; for (int i = 0; i < count; ++i) { if (*iter == a_array[i]) { fk = false; } } if (fk) a_array[count++] = *iter; } for (int i = 0; i < count; ++i) { for (int j = i; j < count ; ++j) { if (a_array[i] > a_array[j]) { long t = a_array[i]; a_array[i] = a_array[j]; a_array[j] = t; } } } a_array.set_size(count); #ifdef DEBUG //printf("a_array size:%08x",a_array.get_size()); for (int i = 0; i < count - 1; ++i) { printf("标签%x,分支地址:%08x - %08x\n",i,a_array[i],a_array[i+1]-1); } //__asm ("int3"); #endif return a_array; }
/* * 获取单个函数帧 * 使用IsProcEnd函数鉴别末尾,不处理中间遇到的CALL指令 */ __INLINE__ PPROCEDURE __INTERNAL_FUNC__ GetProcFrame(__memory pMem, __memory pStart, __integer iBlockMaxSize, PPROGRAM pParents) { PPROCEDURE pProcedure = InitProcedure(pParents); PX86INSTRUCTION pInstructionPrev = NULL, *pInstructionPoint = &(pProcedure->pInstruction); __address ImageBase = pParents->ImageBase; __offset ofOffset = 0; __integer iContinueSize = 0, iInstCount = 0; __bool bPredictProcEnd = FALSE;//是否启用预测函数结尾 ud_t ud_obj; ud_init(&ud_obj); ud_set_mode(&ud_obj, 32); ud_set_input_buffer(&ud_obj, pStart, iBlockMaxSize); ud_set_syntax(&ud_obj, UD_SYN_INTEL); /* * 预测结尾分析 * 可以在为遍历完指令流时,预先知道函数的末尾 */ // 获取整个函数框架 while (ud_disassemble(&ud_obj)) { __memory pCurrent = pStart + ofOffset; // 如果是未知指令,则记录它的数量 if (ud_obj.mnemonic == UD_Iinvalid) (pProcedure->iInvalidOpcodeCount)++; *pInstructionPoint = InitInstruction(pProcedure, pInstructionPrev); AnalyzeInstructionPass1(&ud_obj, pMem, ImageBase, pCurrent, ofOffset, *pInstructionPoint); pInstructionPrev = *pInstructionPoint; // 判断是否到达函数末尾,常规分析 if (IsProcEnd(&ud_obj, pProcedure->pInstruction, *pInstructionPoint, &bPredictProcEnd, &iContinueSize)) { ofOffset += ud_obj.inp_ctr; iInstCount++; goto _end_while; } /* * 如果进入这里则说明当前指令必定是ret指令 */ if (bPredictProcEnd) { // 将反汇编的缓冲区长度设置为 // 从当前指令到预测出的函数结尾 __memory pRetNextInstruction = (*pInstructionPoint)->pCurrFileAddress + ud_obj.inp_ctr;//得到ret指令下一条指令的位置 ofOffset += ud_obj.inp_ctr;//将当前指令的长度加入偏移值内 ud_set_input_buffer(&ud_obj, pRetNextInstruction, (size_t)iContinueSize);//ud_obj会重新初始化 pInstructionPoint = &((*pInstructionPoint)->pNext); iInstCount++; bPredictProcEnd = FALSE; continue;//直接进入下一轮 } // 移动指针 pInstructionPoint = &((*pInstructionPoint)->pNext); ofOffset += ud_obj.inp_ctr; iInstCount++; }/* end while */ _end_while: // 填充函数基本信息 pProcedure->addrMemoryStartAddress = pParents->ImageBase + AnalyzerRaw2Rva(pMem, (__integer)(pStart - pMem)); pProcedure->pFileStartAddress = pStart; pProcedure->iSize = (__integer)ofOffset; pProcedure->iInstCount = iInstCount; pProcedure->pInstructionJmp = GetInstructionJmpListHeader(pProcedure); return pProcedure; }
void Analysis::disasm(pCodeBufferInfo pinfo,std::vector<CodePiece> & code) { ud_t ud_obj; ud_init(&ud_obj); #ifndef PROTECT_X64 ud_set_mode(&ud_obj,32); #else ud_set_mode(&ud_obj,64); #endif ud_set_pc(&ud_obj,pinfo->addr); ud_set_input_buffer(&ud_obj, (uint8_t*)pinfo->buf, pinfo->size); ud_set_syntax(&ud_obj,UD_SYN_INTEL); base = pinfo->addr; size = pinfo->size; AddressArray a_array = analysis_code_piece_address(pinfo); int point = 0; const bool begin = true; const bool end = false; bool status = end; std::map<long,int> addr_id; set_label_address(pinfo,a_array,addr_id); CodePiece *piece = NULL; while (ud_disassemble(&ud_obj) != 0) { if (ud_obj.insn_offset == a_array[point] && status == end) { piece = new CodePiece; piece->set_label(point); point++; status = begin; } if (a_array.get_size() > point) { if (ud_obj.pc == a_array[point]) { if (addr_id.find(ud_obj.pc) == addr_id.end()) //下条指令没有找到 { #ifdef DEBUG printf("没有查找到数据,地址%08x\n",ud_obj.pc) ; #endif //piece->set_jmplabel(PC_NONE); if (ud_obj.mnemonic == UD_Iret) { //piece->set_jmplabel(PC_NONE); piece->set_opcode_attribute(OPCODE_ATTRIBUTE_RET); } else if (ud_insn_mnemonic(&ud_obj) == UD_Ijmp) { long addr = ud_obj.operand[0].size == 8 ? ((signed char)ud_obj.operand[0].lval.sbyte + ud_obj.pc) : (ud_obj.operand[0].lval.sdword + ud_obj.pc); if (addr >= pinfo->addr && addr <= pinfo->addr + pinfo->size && ud_obj.operand[0].type == UD_OP_JIMM) { piece->set_opcode_attribute(OPCODE_ATTRIBUTE_JMP); piece->set_jmplabel(addr_id[addr]); } else { piece->set_opcode_attribute(OPCODE_ATTRIBUTE_EXTERNAL_JMP); if (ud_obj.operand[0].type == UD_OP_JIMM) piece->set_jmplabel(addr); else piece->set_jmplabel(PC_NONE); } } else if (ud_insn_mnemonic(&ud_obj) == UD_Icall) { long addr = ud_obj.operand[0].size == 8 ? ((signed char)ud_obj.operand[0].lval.sbyte + ud_obj.pc) : (ud_obj.operand[0].lval.sdword + ud_obj.pc); //if (addr >= pinfo->addr && addr <= pinfo->addr + pinfo->size && if (addr >= pinfo->addr && addr < pinfo->addr + pinfo->size && ud_obj.operand[0].type == UD_OP_JIMM) { piece->set_opcode_attribute(OPCODE_ATTRIBUTE_CALL); piece->set_jmplabel(addr_id[addr]); } else { piece->set_opcode_attribute(OPCODE_ATTRIBUTE_EXTERNAL_CALL); if (ud_obj.operand[0].type == UD_OP_JIMM) piece->set_jmplabel(addr); else piece->set_jmplabel(PC_NONE); } } else { piece->set_opcode_attribute(OPCODE_ATTRIBUTE_EXIT); piece->set_jmplabel(ud_obj.pc); } } else { if (ud_obj.operand[0].type == UD_OP_JIMM || ud_obj.mnemonic == UD_Icall || ud_obj.mnemonic == UD_Ijmp)//&& ud_obj.mnemonic != UD_Icall) { piece->set_is_jcc(ud_obj.mnemonic != UD_Icall && ud_obj.mnemonic != UD_Iret && ud_obj.mnemonic != UD_Ijmp); if (ud_obj.operand[0].type == UD_OP_MEM || ud_obj.operand[0].type == UD_OP_REG) { if (ud_insn_mnemonic(&ud_obj) == UD_Ijmp) { piece->set_opcode_attribute(OPCODE_ATTRIBUTE_EXTERNAL_JMP); } else if (ud_insn_mnemonic(&ud_obj) == UD_Icall) { piece->set_opcode_attribute(OPCODE_ATTRIBUTE_EXTERNAL_CALL); } else { //piece->set_opcode_attribute(OPCODE_ATTRIBUTE_JCC); } piece->set_jmplabel(PC_NONE); } else { long addr = ud_obj.operand[0].size == 8 ? ((signed char)ud_obj.operand[0].lval.sbyte + ud_obj.pc) : (ud_obj.operand[0].lval.sdword + ud_obj.pc); if (addr >= pinfo->addr && addr < pinfo->addr + pinfo->size) //<=pinfo->addr + pinfo->size将导致跳转到最后一条指令的下一条还是在范围之内 { if (addr_id.find(addr) == addr_id.end()) { printf("没有找到跳转地址:%08x\n",addr ); } if (ud_insn_mnemonic(&ud_obj) == UD_Ijmp) { piece->set_opcode_attribute(OPCODE_ATTRIBUTE_JMP); piece->set_jmplabel(addr_id[addr]); } else if (ud_insn_mnemonic(&ud_obj) == UD_Icall) { piece->set_opcode_attribute(OPCODE_ATTRIBUTE_CALL); piece->set_jmplabel(addr); } else { piece->set_opcode_attribute(OPCODE_ATTRIBUTE_JCC); piece->set_jmplabel( addr_id[addr] ); } } else { if (ud_insn_mnemonic(&ud_obj) == UD_Ijmp) { piece->set_opcode_attribute(OPCODE_ATTRIBUTE_EXTERNAL_JMP); //piece->set_jmplabel(addr_id[addr]); } else if (ud_insn_mnemonic(&ud_obj) == UD_Icall) { piece->set_opcode_attribute(OPCODE_ATTRIBUTE_EXTERNAL_CALL); //piece->set_jmplabel(addr); } else { //piece->set_opcode_attribute(OPCODE_ATTRIBUTE_JCC); printf("jcc不能跳转到虚拟机外部\n"); //piece->set_jmplabel( addr_id[addr] ); } piece->set_jmplabel(addr); } } } else { piece->set_jmplabel( addr_id[ud_obj.pc] ); piece->set_opcode_attribute(OPCODE_ATTRIBUTE_NORMAL); } } if (ud_obj.mnemonic == UD_Iret) { piece->set_jmplabel(PC_NONE); piece->set_opcode_attribute(OPCODE_ATTRIBUTE_RET); //piece->set_jmplabel(PC_RET); } piece->add_assemble(ud_obj); code.push_back(*piece); delete piece; piece = NULL; status = end; } } if (status == begin) { if (piece == NULL) { printf("没有为piece分配空间"); } piece->add_assemble(ud_obj); } } }
pAssemblerTree Analysis::disasm(pCodeBufferInfo pinfo) { std::vector<CodePiece> piece_test; disasm(pinfo,piece_test) ; for (std::vector<CodePiece>::iterator iter = piece_test.begin(); iter != piece_test.end();iter++) { printf("\033[31m标签:%08x,\033[34m跳转到:%08x\033[0m,条件跳转:%d\n",iter->get_label(),iter->get_jmplabel(),iter->get_is_jcc()); for (std::list<ud_t>::iterator xiter = iter->get_piece().begin(); xiter != iter->get_piece().end();xiter++) { printf("%s\n",xiter->insn_buffer); } } //__asm("int3"); ud_t ud_obj; ud_init(&ud_obj); #ifndef PROTECT_X64 ud_set_mode(&ud_obj,32); #else ud_set_mode(&ud_obj,64); #endif ud_set_pc(&ud_obj,pinfo->addr); ud_set_input_buffer(&ud_obj, (uint8_t*)pinfo->buf, pinfo->size); ud_set_syntax(&ud_obj,UD_SYN_INTEL); base = pinfo->addr; size = pinfo->size; std::vector <long> address_array; //pAssemblerTree root = new AssemblerTree; // pAssemblerTree nowtree = root; std::vector <ud_t> ud_obj_array; address_array.push_back(pinfo->addr); address_array.push_back(pinfo->addr + pinfo->size); while (ud_disassemble(&ud_obj) != 0) { ud_obj_array.push_back(ud_obj); // nowtree.asmpiect.push_back(ud_obj); if (ud_obj.operand[0].type == UD_OP_JIMM || ud_obj.mnemonic == UD_Icall )//&& ud_obj.mnemonic != UD_Icall) { long addr = ud_obj.operand[0].size == 8 ? ((signed char)ud_obj.operand[0].lval.sbyte + ud_obj.pc) : (ud_obj.operand[0].lval.sdword + ud_obj.pc); if (addr >= pinfo->addr && addr <= pinfo->addr + pinfo->size) { address_array.push_back(addr); address_array.push_back(ud_obj.pc); } } } long count = 0; long *a_array; size_t address_size = address_array.size(); a_array = new long[address_size]; for (std::vector <long>::iterator iter = address_array.begin() ; iter != address_array.end() ; ++iter) { bool fk = true; for (int i = 0; i < count; ++i) { if (*iter == a_array[i]) { fk = false; } } if (fk) a_array[count++] = *iter; } for (int i = 0; i < count; ++i) { for (int j = i; j < count ; ++j) { if (a_array[i] > a_array[j]) { long t = a_array[i]; a_array[i] = a_array[j]; a_array[j] = t; } } } for (int i = 0; i < count; ++i) { printf("%08x\r\n",a_array[i]); } int point = 0; pAssemblerTree nowtree = NULL; pAssemblerTree parent = NULL; const bool begin = true; const bool end = false; bool status = end; for (std::vector <ud_t>::iterator iter = ud_obj_array.begin(); iter != ud_obj_array.end(); ++iter) { //typedef true begin; //typedef false end; // ud_t *p = iter; ud_t ud = *iter; if (ud.insn_offset == a_array[point] && status == end) { point++; status = begin; nowtree = new AssemblerTree; root ? NULL : root = nowtree; nowtree->LeftChild = NULL; nowtree->RightChild = NULL; nowtree->id = point - 1; // nowtree.asmpiect.push_back(ud); } if (nowtree) { nowtree->asmpiece.push_back(ud); } if (ud.pc == a_array[point] && status == begin) { nowtree->base = a_array[point-1]; //point++; nowtree->size = ud.pc - a_array[point-1]; //代码块大小 status = end; parent = add_tree(parent,nowtree,L); //nowtree = new AssemblerTree; //nowtree->LeftChild = NULL; //nowtree->RightChild = NULL; } nowtree->reloc_address = -1; nowtree->next_instruction = ud.pc; } block_count = point; link_tree(); #ifdef DEBUG show_tree(root,"false:"); #endif delete [] a_array; // show_tree(root); /*for (std::vector <long>::iterator iter = address_array.begin() ; iter != address_array.end() ; ++iter) { int addr = *iter; printf("%08x\r\n",addr); }*/ return NULL; }
int check_status(int pid) { static int eip_range_size = 1024 - 1; static unsigned long eip_range = 0; ud_t ud_obj; unsigned char buff[16]; struct user_regs_struct regs; int i, len; ptrace(PTRACE_GETREGS, pid, 0, ®s); if(eip_range == 0) eip_range = regs.eip - 1; read_data(pid, regs.eip, buff, 16); ud_init(&ud_obj); ud_set_input_buffer(&ud_obj, buff, sizeof(buff)); ud_set_mode(&ud_obj, 32); ud_set_syntax(&ud_obj, UD_SYN_INTEL); if(!ud_disassemble(&ud_obj)) return -1; len = ud_insn_len(&ud_obj); printf("eax=%08lx, ecx=%08lx, edx=%08lx, ebx=%08lx\n", regs.eax, regs.ecx, regs.edx, regs.ebx); printf("esi=%08lx, edi=%08lx, esp=%08lx, ebp=%08lx\n", regs.esi, regs.edi, regs.esp, regs.ebp); printf("eip=%08lx, eflags=%08lx\n", regs.eip, regs.eflags); printf("\n"); printf("eip: "); for(i=0; i < len; i++) printf("%02x ", buff[i]); printf("( %s )\n", ud_insn_asm(&ud_obj)); printf("\n"); // check system call if(check_int80h(buff) || check_sysenter(buff)){ char str[64]; if(check_sys_write(pid, ®s, str, sizeof(str))){ printf("output:\n"); printf("%s", str); if(strcmp(str, "HelloASM") == 0){ printf("\nPassword: MagicaMadoca\n"); } } return -1; } // found int3 if(check_int3(buff)) return -1; // out of mem range if(regs.eip < eip_range || (eip_range + eip_range_size) < regs.eip) return -1; // found 0x00 if(check_00(buff, len)) return -1; return 0; }
int x86_udis86_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *data, int len) { int oplen; struct ud u; ud_init (&u); ud_set_pc (&u, addr); ud_set_mode (&u, anal->bits); ud_set_syntax (&u, NULL); ud_set_input_buffer (&u, data, len); ud_disassemble (&u); memset (op, '\0', sizeof (RAnalOp)); op->addr = addr; op->jump = op->fail = -1; op->ref = op->value = -1; oplen = op->length = ud_insn_len (&u); switch (u.mnemonic) { case UD_Ijmp: if (u.operand[0].type == UD_OP_REG) { op->type = R_ANAL_OP_TYPE_UJMP; } else { op->type = R_ANAL_OP_TYPE_JMP; op->jump = addr + oplen + getval (&u.operand[0]); } break; case UD_Ijz: case UD_Ijnz: case UD_Ijb: case UD_Ijbe: case UD_Ija: case UD_Ijs: case UD_Ijns: case UD_Ijo: case UD_Ijno: case UD_Ijp: case UD_Ijnp: case UD_Ijl: case UD_Ijge: case UD_Ijle: case UD_Ijg: case UD_Ijcxz: op->type = R_ANAL_OP_TYPE_CJMP; op->jump = addr + oplen + getval (&u.operand[0]); op->fail = addr+oplen; break; case UD_Icall: op->type = R_ANAL_OP_TYPE_CALL; op->jump = oplen + getval (&u.operand[0]); op->fail = addr+oplen; break; case UD_Iret: case UD_Iretf: case UD_Isysret: op->type = R_ANAL_OP_TYPE_RET; break; case UD_Isyscall: op->type = R_ANAL_OP_TYPE_SWI; break; case UD_Inop: op->type = R_ANAL_OP_TYPE_NOP; break; default: break; } return oplen; }
/** * Recursively generate code regions by statically analyzing machine code. */ bool MDBCode::scanProcedure(uintptr_t address) { if (getRegion(address)) { log.traceLn("a region already exists"); // A region already exists for this address. return true; } log.traceLn("scanning address %llx", address); size_t bufferSize = 1024 * 8; char buffer[bufferSize]; if (debugger->read(buffer, address, sizeof(buffer)) != (int) sizeof(buffer)) { log.traceLn("Cannot read procedure memory."); } MBList<uintptr_t> callTargets; ud_t insn; ud_init(&insn); ud_set_input_buffer(&insn, (uint8_t*)buffer, bufferSize); ud_set_mode(&insn, 32); ud_set_syntax(&insn, UD_SYN_INTEL); size_t remainingBytes = bufferSize; while (remainingBytes > 0) { int offset = insn.pc; size_t insnSize = ud_disassemble(&insn); remainingBytes -= insnSize; if (insnSize == 0) { error("cannot disassemble"); break; } log.traceLn("decoded: 0x%-8llx 0x%-8llx %s", address + offset, offset, ud_insn_asm(&insn)); switch (insn.mnemonic) { case UD_Icall: { uintptr_t target = 0; if (insn.operand[0].type == UD_OP_JIMM) { if (insn.operand[0].size == 32) { target = address + insn.pc + insn.operand[0].lval.sdword; } } if (target) { if (callTargets.contains(target) == false) { log.traceLn("discovered new call target 0x%llx", target); callTargets.append(target); } } break; } case UD_Iret: { MDBCodeRegion *region = new MDBCodeRegion(this, address, findSymbolByNameOrAddress(NULL, address), insn.pc); regions.append(region); remainingBytes = 0; break; } default: break; } } for (uint32_t i = 0; i < callTargets.length(); i++) { scanProcedure(callTargets[i]); } return true; }
int x86_udis86_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *data, int len) { const char *pc = anal->bits==64? "rip": anal->bits==32? "eip": "ip"; const char *sp = anal->bits==64? "rsp": anal->bits==32? "esp": "sp"; const char *bp = anal->bits==64? "rbp": anal->bits==32? "ebp": "bp"; int oplen, regsz = 4; char str[64], src[32], dst[32]; struct ud u; switch (anal->bits) { case 64: regsz = 8; break; case 16: regsz = 2; break; default: case 32: regsz = 4; break; } UDis86Esil *handler; UDis86OPInfo info = {0, anal->bits, (1LL << anal->bits) - 1, regsz, 0, pc, sp, bp}; memset (op, '\0', sizeof (RAnalOp)); r_strbuf_init (&op->esil); op->addr = addr; op->jump = op->fail = -1; op->ptr = op->val = -1; ud_init (&u); ud_set_pc (&u, addr); ud_set_mode (&u, anal->bits); ud_set_syntax (&u, NULL); ud_set_input_buffer (&u, data, len); ud_disassemble (&u); oplen = op->size = ud_insn_len (&u); if (anal->decode && (handler = udis86_esil_get_handler (u.mnemonic))) { info.oplen = oplen; if (handler->argc > 0) { info.n = getval (u.operand); getarg (dst, &u, info.bitmask, 0); if (handler->argc > 1) { getarg (src, &u, info.bitmask, 1); if (handler->argc > 2) getarg (str, &u, info.bitmask, 2); } } handler->callback (&info, op, dst, src, str); } switch (u.mnemonic) { case UD_Iinvalid: oplen = op->size = -1; return -1; break; case UD_Itest: case UD_Icmp: op->type = R_ANAL_OP_TYPE_CMP; break; case UD_Isalc: // ?? // al = cf break; case UD_Ixor: op->type = R_ANAL_OP_TYPE_XOR; break; case UD_Ior: op->type = R_ANAL_OP_TYPE_OR; break; case UD_Iand: op->type = R_ANAL_OP_TYPE_AND; break; case UD_Isar: op->type = R_ANAL_OP_TYPE_SAR; break; // XXX: sal ?!? case UD_Ishl: op->type = R_ANAL_OP_TYPE_SHL; break; case UD_Ishr: op->type = R_ANAL_OP_TYPE_SHR; break; case UD_Irol: op->type = R_ANAL_OP_TYPE_ROL; break; case UD_Iror: op->type = R_ANAL_OP_TYPE_ROR; break; case UD_Iint3: op->type = R_ANAL_OP_TYPE_TRAP; break; case UD_Iint: op->type = R_ANAL_OP_TYPE_SWI; op->val = u.operand[0].lval.uword; break; case UD_Ilea: case UD_Imov: op->type = R_ANAL_OP_TYPE_MOV; switch (u.operand[1].type) { case UD_OP_MEM: op->type = R_ANAL_OP_TYPE_MOV; if (u.operand[1].base == UD_R_RIP) { int delta = u.operand[1].lval.uword; op->ptr = addr + oplen + delta; } break; default: op->type = R_ANAL_OP_TYPE_MOV; op->ptr = getval (&u.operand[1]); // XX break; } op->stackop = R_ANAL_STACK_INC; op->stackptr = regsz; break; case UD_Ipush: case UD_Ipusha: case UD_Ipushad: case UD_Ipushfq: case UD_Ipushfd: case UD_Ipushfw: switch (u.operand[0].type) { case UD_OP_CONST: case UD_OP_JIMM: case UD_OP_IMM: op->type = R_ANAL_OP_TYPE_PUSH; op->ptr = getval (&u.operand[0]); break; case UD_OP_REG: case UD_OP_PTR: case UD_OP_MEM: default: op->type = R_ANAL_OP_TYPE_UPUSH; op->ptr = 0; break; } op->stackop = R_ANAL_STACK_INC; op->stackptr = regsz; break; case UD_Ipop: case UD_Ipopa: case UD_Ipopad: case UD_Ipopfw: case UD_Ipopfd: case UD_Ipopfq: op->type = R_ANAL_OP_TYPE_POP; op->stackop = R_ANAL_STACK_INC; op->stackptr = -regsz; break; case UD_Ileave: op->type = R_ANAL_OP_TYPE_MOV; op->stackop = R_ANAL_STACK_INC; op->stackptr = -regsz; break; case UD_Iadd: case UD_Isub: op->type = (u.mnemonic==UD_Iadd)? R_ANAL_OP_TYPE_ADD: R_ANAL_OP_TYPE_SUB; op->ptr = 0; op->stackptr = 0; if (u.operand[0].type == UD_OP_REG) { if (u.operand[0].base == UD_R_RSP) { int o = (int)getval (&u.operand[1]); op->stackop = R_ANAL_STACK_INC; if (u.mnemonic ==UD_Iadd) { op->stackptr = -o; } else { op->stackptr = o; } } if (u.operand[1].type != UD_OP_REG) op->val = getval (&u.operand[1]); } op->stackptr = 4; break; case UD_Iadc: case UD_Iinc: op->type = R_ANAL_OP_TYPE_ADD; break; case UD_Isbb: case UD_Idec: op->type = R_ANAL_OP_TYPE_SUB; break; case UD_Ijmp: switch (u.operand[0].type) { case UD_OP_MEM: case UD_OP_REG: op->type = R_ANAL_OP_TYPE_UJMP; break; default: op->type = R_ANAL_OP_TYPE_JMP; #if 0 { ut16 a = (op->lval.ptr.seg & 0xFFFF); ut16 b = (op->lval.ptr.off); switch (op->size) { case 32: sprintf (src, "%04x:%04x", a, b & 0xFFFF); break; case 48: sprintf (src, "%04x:%04x", a, b); break; default: eprintf ("F**K YOU\n"); } } #endif if (u.operand[0].type==UD_OP_PTR) { op->jump = getval (&u.operand[0]); } else { if (anal->bits==16) { // honor segment op->jump = (addr&0xf0000) + oplen + \ (((addr&0xffff)+getval (&u.operand[0])&0xffff)); } else { op->jump = addr + oplen + (int)getval (&u.operand[0]); } } } break; case UD_Ije: case UD_Ijne: case UD_Ijb: case UD_Ijbe: case UD_Ija: case UD_Ijae: case UD_Ijs: case UD_Ijns: case UD_Ijo: case UD_Ijno: case UD_Ijp: case UD_Ijnp: case UD_Ijl: case UD_Ijge: case UD_Ijle: case UD_Ijg: case UD_Ijcxz: case UD_Iloop: op->type = R_ANAL_OP_TYPE_CJMP; op->jump = addr + oplen + (int)getval (&u.operand[0]); op->fail = addr+oplen; break; case UD_Icall: op->type = R_ANAL_OP_TYPE_CALL; switch (u.operand[0].type) { case UD_OP_REG: op->jump = 0; // EAX, EBX, ... use anal->reg break; case UD_OP_IMM: case UD_OP_MEM: case UD_OP_PTR: default: op->jump = addr + oplen + (int)getval (&u.operand[0]); } op->fail = addr + oplen; break; case UD_Ihlt: //op->type = R_ANAL_OP_TYPE_HALT; break; case UD_Iret: case UD_Iretf: case UD_Isysret: op->type = R_ANAL_OP_TYPE_RET; op->stackop = R_ANAL_STACK_INC; op->stackptr = -regsz; break; case UD_Isyscall: op->type = R_ANAL_OP_TYPE_SWI; break; case UD_Inop: op->type = R_ANAL_OP_TYPE_NOP; break; default: break; } return oplen; }
struct _map * elf32_functions (struct _elf32 * elf32, struct _map * memory) { struct _list * entries = list_create(); // add the entry point struct _function * function = function_create(elf32_entry(elf32)); list_append(entries, function); object_delete(function); // check for __libc_start_main loader uint64_t target_offset = elf32_entry(elf32) - elf32_base_address(elf32) + 0x17; if (target_offset + 0x10 < elf32->data_size) { uint8_t * data = &(elf32->data[target_offset]); size_t size = elf32->data_size - target_offset; ud_t ud_obj; ud_init (&ud_obj); ud_set_mode (&ud_obj, 32); ud_set_syntax(&ud_obj, UD_SYN_INTEL); ud_set_input_buffer(&ud_obj, data, size); ud_disassemble(&ud_obj); if (ud_obj.mnemonic == UD_Ipush) { printf("found __libc_start_main loader, main at %llx\n", (unsigned long long) udis86_sign_extend_lval(&(ud_obj.operand[0]))); // add main to function tree struct _function * function; function = function_create(udis86_sign_extend_lval(&(ud_obj.operand[0]))); list_append(entries, function); object_delete(function); } else printf("disassembled: %s\n disassembled at %llx\n", ud_insn_asm(&ud_obj), (unsigned long long) target_offset); } struct _map * functions = elf32_functions_wqueue(elf32, memory, entries); // these are the reachable functions struct _map_it * mit; for (mit = map_iterator(functions); mit != NULL; mit = map_it_next(mit)) { struct _function * function = map_it_data(mit); function->flags |= FUNCTION_REACHABLE; } // reset entries object_delete(entries); entries = list_create(); // symbols are easy int sec_i; for (sec_i = 0; sec_i < elf32->ehdr->e_shnum; sec_i++) { Elf32_Shdr * shdr = elf32_shdr(elf32, sec_i); if (shdr == NULL) break; if ((shdr->sh_type != SHT_SYMTAB) && (shdr->sh_type != SHT_DYNSYM)) continue; int sym_i; for (sym_i = 0; sym_i < shdr->sh_size / shdr->sh_entsize; sym_i++) { Elf32_Sym * sym = elf32_section_element(elf32, sec_i, sym_i); if (sym == NULL) break; if (ELF32_ST_TYPE(sym->st_info) != STT_FUNC) continue; if (sym->st_value == 0) continue; struct _function * function = function_create(sym->st_value); list_append(entries, function); object_delete(function); } } struct _map * sym_functions = elf32_functions_wqueue(elf32, memory, entries); for (mit = map_iterator(sym_functions); mit != NULL; mit = map_it_next(mit)) { struct _function * function = map_it_data(mit); if (map_fetch(functions, function->address) == NULL) map_insert(functions, function->address, function); } object_delete(sym_functions); object_delete(entries); return functions; }
virtual void Apply() override { if (applied_) { return; } if (detached_) { HADESMEM_DETAIL_ASSERT(false); return; } // Reset the trampolines here because we don't do it in remove, otherwise // there's a potential race condition where we want to unhook and unload // safely, so we unhook the function, then try waiting on our ref count to // become zero, but we haven't actually called the trampoline yet, so we end // up jumping to the memory we just free'd! trampoline_ = nullptr; trampolines_.clear(); stub_gate_ = nullptr; SuspendedProcess const suspended_process{process_->GetId()}; std::uint32_t const kMaxInstructionLen = 15; std::uint32_t const kTrampSize = kMaxInstructionLen * 3; trampoline_ = std::make_unique<Allocator>(*process_, kTrampSize); auto tramp_cur = static_cast<std::uint8_t*>(trampoline_->GetBase()); auto const detour_raw = detour_.target<DetourFuncRawT>(); if (detour_raw || detour_) { HADESMEM_DETAIL_TRACE_FORMAT_A( "Target = %p, Detour = %p, Trampoline = %p.", target_, detour_raw, trampoline_->GetBase()); } else { HADESMEM_DETAIL_TRACE_FORMAT_A( "Target = %p, Detour = INVALID, Trampoline = %p.", target_, trampoline_->GetBase()); } auto const buffer = ReadVector<std::uint8_t>(*process_, target_, kTrampSize); ud_t ud_obj; ud_init(&ud_obj); ud_set_input_buffer(&ud_obj, buffer.data(), buffer.size()); ud_set_syntax(&ud_obj, UD_SYN_INTEL); ud_set_pc(&ud_obj, reinterpret_cast<std::uint64_t>(target_)); #if defined(HADESMEM_DETAIL_ARCH_X64) ud_set_mode(&ud_obj, 64); #elif defined(HADESMEM_DETAIL_ARCH_X86) ud_set_mode(&ud_obj, 32); #else #error "[HadesMem] Unsupported architecture." #endif stub_gate_ = detail::AllocatePageNear(*process_, target_); std::size_t const patch_size = GetPatchSize(); std::uint32_t instr_size = 0; do { std::uint32_t const len = ud_disassemble(&ud_obj); if (len == 0) { HADESMEM_DETAIL_THROW_EXCEPTION(Error{} << ErrorString{"Disassembly failed."}); } #if !defined(HADESMEM_NO_TRACE) char const* const asm_str = ud_insn_asm(&ud_obj); char const* const asm_bytes_str = ud_insn_hex(&ud_obj); HADESMEM_DETAIL_TRACE_FORMAT_A( "%s. [%s].", (asm_str ? asm_str : "Invalid."), (asm_bytes_str ? asm_bytes_str : "Invalid.")); #endif ud_operand_t const* const op = ud_insn_opr(&ud_obj, 0); bool is_jimm = op && op->type == UD_OP_JIMM; // Handle JMP QWORD PTR [RIP+Rel32]. Necessary for hook chain support. bool is_jmem = op && op->type == UD_OP_MEM && op->base == UD_R_RIP && op->index == UD_NONE && op->scale == 0 && op->size == 0x40; if ((ud_obj.mnemonic == UD_Ijmp || ud_obj.mnemonic == UD_Icall) && op && (is_jimm || is_jmem)) { std::uint16_t const size = is_jimm ? op->size : op->offset; HADESMEM_DETAIL_TRACE_FORMAT_A("Operand/offset size is %hu.", size); std::int64_t const insn_target = [&]() -> std::int64_t { switch (size) { case sizeof(std::int8_t) * CHAR_BIT: return op->lval.sbyte; case sizeof(std::int16_t) * CHAR_BIT: return op->lval.sword; case sizeof(std::int32_t) * CHAR_BIT: return op->lval.sdword; case sizeof(std::int64_t) * CHAR_BIT: return op->lval.sqword; default: HADESMEM_DETAIL_ASSERT(false); HADESMEM_DETAIL_THROW_EXCEPTION( Error{} << ErrorString{"Unknown instruction size."}); } }(); auto const resolve_rel = [](std::uint64_t base, std::int64_t target, std::uint32_t insn_len) { return reinterpret_cast<std::uint8_t*>( static_cast<std::uintptr_t>(base)) + target + insn_len; }; std::uint64_t const insn_base = ud_insn_off(&ud_obj); std::uint32_t const insn_len = ud_insn_len(&ud_obj); auto const resolved_target = resolve_rel(insn_base, insn_target, insn_len); void* const jump_target = is_jimm ? resolved_target : Read<void*>(*process_, resolved_target); HADESMEM_DETAIL_TRACE_FORMAT_A("Jump/call target = %p.", jump_target); if (ud_obj.mnemonic == UD_Ijmp) { HADESMEM_DETAIL_TRACE_A("Writing resolved jump."); tramp_cur += detail::WriteJump( *process_, tramp_cur, jump_target, true, &trampolines_); } else { HADESMEM_DETAIL_ASSERT(ud_obj.mnemonic == UD_Icall); HADESMEM_DETAIL_TRACE_A("Writing resolved call."); tramp_cur += detail::WriteCall(*process_, tramp_cur, jump_target, trampolines_); } } else { std::uint8_t const* const raw = ud_insn_ptr(&ud_obj); Write(*process_, tramp_cur, raw, raw + len); tramp_cur += len; } instr_size += len; } while (instr_size < patch_size); HADESMEM_DETAIL_TRACE_A("Writing jump back to original code."); tramp_cur += detail::WriteJump(*process_, tramp_cur, reinterpret_cast<std::uint8_t*>(target_) + instr_size, true, &trampolines_); FlushInstructionCache( *process_, trampoline_->GetBase(), trampoline_->GetSize()); detail::WriteStubGate<TargetFuncT>(*process_, stub_gate_->GetBase(), &*stub_, &GetOriginalArbitraryUserPtrPtr); orig_ = ReadVector<std::uint8_t>(*process_, target_, patch_size); detail::VerifyPatchThreads(process_->GetId(), target_, orig_.size()); WritePatch(); FlushInstructionCache(*process_, target_, instr_size); applied_ = true; }
telf_status binary_to_asm(char *bin, size_t bin_len, char **bufp, size_t *buf_lenp) { telf_status ret; char *buf = NULL; size_t buf_len = 0; ud_t ud_obj; char *tmpbuf = NULL; ud_init(&ud_obj); ud_set_input_buffer(&ud_obj, bin, bin_len); ud_set_mode(&ud_obj, 64); ud_set_syntax(&ud_obj, UD_SYN_INTEL); if (! bin_len || ! bin) { ret = ELF_SUCCESS; goto end; } while (ud_disassemble(&ud_obj)) { char line[64] = ""; size_t len; len = sprintf(line, "%s\n", ud_insn_asm(&ud_obj)); tmpbuf = realloc(buf, buf_len + len); if (! tmpbuf) { ERR("realloc: %s", strerror(errno)); free(buf); buf = NULL; ret = ELF_ENOMEM; goto end; } buf = tmpbuf; memmove(buf + buf_len, line, len); buf_len += len; } /* we didn't reserve any room for the nul-terminaison char */ if (buf) { tmpbuf = realloc(buf, buf_len + 1); if (! tmpbuf) { ERR("realloc: %s", strerror(errno)); free(buf); buf = NULL; ret = ELF_ENOMEM; goto end; } tmpbuf[buf_len] = 0; buf_len++; buf = tmpbuf; } ret = ELF_SUCCESS; end: if (bufp) *bufp = buf; else free(buf); if (buf_lenp) *buf_lenp = buf_len; return ret; }
/* * This is the initial phase, used to populate the graph with all reachable * nodes. We will worry about fixing edges from jmp-like mnemonics later. */ void x8664_graph_0 (struct _graph * graph, uint64_t address, struct _map * memory) { ud_t ud_obj; int continue_disassembling = 1; uint64_t last_address = -1; int edge_type = INS_EDGE_NORMAL; struct _buffer * buffer = map_fetch_max(memory, address); if (buffer == NULL) return; uint64_t base_address = map_fetch_max_key(memory, address); if (base_address + buffer->size < address) return; uint64_t offset = address - base_address; ud_init (&ud_obj); ud_set_mode (&ud_obj, 64); ud_set_syntax(&ud_obj, UD_SYN_INTEL); ud_set_input_buffer(&ud_obj, &(buffer->bytes[offset]), buffer->size - offset); while (continue_disassembling == 1) { size_t bytes_disassembled = ud_disassemble(&ud_obj); if (bytes_disassembled == 0) { break; } // even if we have already added this node, make sure we add the edge // from the preceeding node, in case this node was added from a jump // previously. otherwise we won't have an edge from its preceeding // instruction if (graph_fetch_node(graph, address) != NULL) { if (last_address != -1) { // not concerned if this call fails struct _ins_edge * ins_edge = ins_edge_create(edge_type); graph_add_edge(graph, last_address, address, ins_edge); object_delete(ins_edge); } break; } // create graph node for this instruction struct _ins * ins = x8664_ins(address, &ud_obj); struct _list * ins_list = list_create(); list_append(ins_list, ins); graph_add_node(graph, address, ins_list); object_delete(ins_list); object_delete(ins); // add edge from previous instruction to this instruction if (last_address != -1) { struct _ins_edge * ins_edge = ins_edge_create(edge_type); graph_add_edge(graph, last_address, address, ins_edge); object_delete(ins_edge); } // these mnemonics cause us to continue disassembly somewhere else struct ud_operand * operand; switch (ud_obj.mnemonic) { case UD_Ijo : case UD_Ijno : case UD_Ijb : case UD_Ijae : case UD_Ijz : case UD_Ijnz : case UD_Ijbe : case UD_Ija : case UD_Ijs : case UD_Ijns : case UD_Ijp : case UD_Ijnp : case UD_Ijl : case UD_Ijge : case UD_Ijle : case UD_Ijg : case UD_Ijmp : case UD_Iloop : //case UD_Icall : operand = &(ud_obj.operand[0]); if (operand->type != UD_OP_JIMM) break; if (ud_obj.mnemonic == UD_Icall) edge_type = INS_EDGE_NORMAL; else if (ud_obj.mnemonic == UD_Ijmp) edge_type = INS_EDGE_NORMAL; // not important, will terminate else edge_type = INS_EDGE_JCC_FALSE; if (operand->type == UD_OP_JIMM) { x8664_graph_0(graph, address + ud_insn_len(&ud_obj) + udis86_sign_extend_lval(operand), memory); } break; default : edge_type = INS_EDGE_NORMAL; break; } // these mnemonics cause disassembly to stop switch (ud_obj.mnemonic) { case UD_Iret : case UD_Ihlt : case UD_Ijmp : continue_disassembling = 0; break; default : break; } last_address = address; address += bytes_disassembled; } }
struct _ins * x86_disassemble_ins_ (const struct _map * mem_map, const uint64_t address, uint8_t mode) { struct _buffer * buf = map_fetch_max(mem_map, address); uint64_t buf_addr = map_fetch_max_key(mem_map, address); if (buf == NULL) return NULL; size_t offset = address - buf_addr; ud_t ud_obj; ud_init(&ud_obj); ud_set_mode(&ud_obj, mode); ud_set_syntax(&ud_obj, UD_SYN_INTEL); ud_set_input_buffer(&ud_obj, &(buf->bytes[offset]), buf->size - offset); if (ud_disassemble(&ud_obj) == 0) return NULL; struct _ins * ins = ins_create(address, ud_insn_ptr(&ud_obj), ud_insn_len(&ud_obj), ud_insn_asm(&ud_obj), NULL); switch (ud_obj.mnemonic) { case UD_Ijo : case UD_Ijno : case UD_Ijb : case UD_Ijae : case UD_Ijz : case UD_Ijnz : case UD_Ijbe : case UD_Ija : case UD_Ijs : case UD_Ijns : case UD_Ijp : case UD_Ijnp : case UD_Ijl : case UD_Ijge : case UD_Ijle : case UD_Ijg : case UD_Iloop : ins_add_successor(ins, address + ud_insn_len(&ud_obj), INS_SUC_JCC_FALSE); if (ud_obj.operand[0].type == UD_OP_JIMM) { ins_add_successor(ins, address + ud_insn_len(&ud_obj) + x86_sign_extend_lval(&(ud_obj.operand[0])), INS_SUC_JCC_TRUE); } break; case UD_Ijmp : if (ud_obj.operand[0].type == UD_OP_JIMM) { ins_add_successor(ins, address + ud_insn_len(&ud_obj) + x86_sign_extend_lval(&(ud_obj.operand[0])), INS_SUC_JUMP); } break; case UD_Icall : ins_add_successor(ins, address + ud_insn_len(&ud_obj), INS_SUC_NORMAL); if (ud_obj.operand[0].type == UD_OP_JIMM) { ins_add_successor(ins, address + ud_insn_len(&ud_obj) + x86_sign_extend_lval(&(ud_obj.operand[0])), INS_SUC_CALL); } break; case UD_Iret : case UD_Ihlt : break; default : ins_add_successor(ins, address + ud_insn_len(&ud_obj), INS_SUC_NORMAL); } return ins; }
void x8664_functions_r (struct _map * functions, struct _tree * disassembled, uint64_t address, struct _map * memory) { ud_t ud_obj; int continue_disassembling = 1; struct _buffer * buffer = map_fetch_max(memory, address); if (buffer == NULL) return; uint64_t base_address = map_fetch_max_key(memory, address); if (base_address + buffer->size < address) return; uint64_t offset = address - base_address; ud_init (&ud_obj); ud_set_mode (&ud_obj, 64); ud_set_syntax(&ud_obj, UD_SYN_INTEL); ud_set_input_buffer(&ud_obj, &(buffer->bytes[offset]), buffer->size - offset); while (continue_disassembling == 1) { size_t bytes_disassembled = ud_disassemble(&ud_obj); if (bytes_disassembled == 0) { break; } if ( (ud_obj.mnemonic == UD_Icall) && (ud_obj.operand[0].type == UD_OP_JIMM)) { uint64_t target_addr = address + ud_insn_len(&ud_obj) + udis86_sign_extend_lval(&(ud_obj.operand[0])); if (map_fetch(functions, target_addr) == NULL) { struct _function * function = function_create(target_addr); map_insert(functions, target_addr, function); object_delete(function); } } struct _index * index = index_create(address); if (tree_fetch(disassembled, index) != NULL) { object_delete(index); return; } tree_insert(disassembled, index); object_delete(index); // these mnemonics cause us to continue disassembly somewhere else struct ud_operand * operand; switch (ud_obj.mnemonic) { case UD_Ijo : case UD_Ijno : case UD_Ijb : case UD_Ijae : case UD_Ijz : case UD_Ijnz : case UD_Ijbe : case UD_Ija : case UD_Ijs : case UD_Ijns : case UD_Ijp : case UD_Ijnp : case UD_Ijl : case UD_Ijge : case UD_Ijle : case UD_Ijg : case UD_Ijmp : case UD_Iloop : case UD_Icall : operand = &(ud_obj.operand[0]); if (operand->type == UD_OP_JIMM) { x8664_functions_r(functions, disassembled, address + ud_insn_len(&ud_obj) + udis86_sign_extend_lval(operand), memory); } break; default : break; } // these mnemonics cause disassembly to stop switch (ud_obj.mnemonic) { case UD_Iret : case UD_Ihlt : case UD_Ijmp : continue_disassembling = 0; break; default : break; } address += bytes_disassembled; } }
void debugger_proc(pid_t child_proc, struct execute_context *ctx) { /* about child process */ int child_stat; kern_return_t kret; mach_port_t task; int wait_cnt = 0; char **args = ctx->passing_args; /* related analysys of target process binary. */ int i; int nsym; int text_section; uint64_t text_section_offset; uint64_t text_section_size; uint64_t text_section_vmaddr; struct symbol_info *psymbol_table; int init = 0; struct breakpoint_entry top; int stack_depth = 0; /* error check */ if (child_proc == 0 || child_proc == -1) return; /* initialize */ memset(&top, 0x00, sizeof(top)); /* open the port (do as an administrator) */ kret = task_for_pid(mach_task_self(), child_proc, &task); if (kret != KERN_SUCCESS) { fprintf(stderr, "task_for_pid() failed\n"); fprintf(stderr, "%s\n", mach_error_string(kret)); exit(0); } fprintf(stderr, "[Tracer] child_proc: %d\n", child_proc); /* main loop */ while(waitpid(child_proc, &child_stat, WUNTRACED)) { /* {{{ */ char buffer[128]; char w_buf[128]; w_buf[0] = 0x90; /* nop */ if (WIFEXITED(child_stat)) { /* Child Process Terminated */ fprintf(stderr, "[Tracer] Process :%d Terminated\n", child_proc); return; } memset(buffer, 0x00, 128); if(wait_cnt == 0) { /* The First time trapped {{{ */ /* -- The debugee program has not been expanded.-- */ /* -- lookup named symbol -- */ struct file_info bininfo; ud_t ud_obj; uint64_t previous_eip; uint64_t func_start_addr; uint64_t func_end_addr; nsym = get_func_table(args[0], &psymbol_table, &text_section, &text_section_offset, &text_section_size, &text_section_vmaddr); debug_printf("nsym: %d\n", nsym); debug_printf("text section = %d\n", text_section); debug_printf("text section offset: 0x%llx\n", text_section_offset); debug_printf("text section size: 0x%llx\n", text_section_size); debug_printf("text section vmaddr: 0x%llx\n", text_section_vmaddr); qsort(psymbol_table, nsym, sizeof(struct symbol_info), symbolinfo_comp); /* XXX for debugging */ /*display_symbol_table(psymbol_table, nsym); */ /* code analysys */ map_binary(args[0], &bininfo); ud_init(&ud_obj); ud_set_input_buffer(&ud_obj, bininfo.top + text_section_offset, text_section_size); ud_set_mode(&ud_obj, 64); previous_eip = text_section_vmaddr; /* set breakpoint at the entry and exit points of functions */ for(i = 0; i < nsym; i++) { /* Set breakpoints {{{ */ if (is_exclude_func(psymbol_table + i) == 1) { continue; } /* 1, specifying the region of the function */ func_start_addr = psymbol_table[i].nlist64.n_value; if (i != nsym - 1) { /* next section's entry point - 1 */ func_end_addr = psymbol_table[i + 1].nlist64.n_value; } else { func_end_addr = text_section_vmaddr + text_section_size + 1; } printf("%s: 0x%llx --> 0x%llx\n", psymbol_table[i].name, func_start_addr, func_end_addr); /* if (strstr(psymbol_table[i].name, "main") != NULL) { __asm__("int3"); } */ psymbol_table[i].ret_address_num = 0; previous_eip = ud_obj.pc + text_section_vmaddr; while(ud_disassemble(&ud_obj) && previous_eip < func_start_addr) { previous_eip = ud_obj.pc + text_section_vmaddr; } while(ud_disassemble(&ud_obj) && previous_eip < func_end_addr) { if (func_start_addr <= previous_eip && ud_obj.mnemonic == UD_Iret) { set_breakpoint(task, previous_eip, &top); psymbol_table[i].ret_inst_address[ psymbol_table[i].ret_address_num ] = previous_eip; psymbol_table[i].ret_address_num++; } previous_eip = ud_obj.pc + text_section_vmaddr; } /* if (0 < psymbol_table[i].ret_address_num) { set_breakpoint(task, psymbol_table[i].nlist64.n_value, &top); } */ set_breakpoint(task, psymbol_table[i].nlist64.n_value, &top); /* }}} */ } debug_printf("break point insert\n"); unmap_binary(&bininfo); /* }}} */ } else { /* {{{ */ /* break point */ /* 1, Get current address from RIP value. * 2, Find current function name by EIP, and Logging. * 3, Substitute original instruction code for current break point code(0x90). * 4, Decrement EIP value. * 5, Execute only one op-code. * 6, Substitute 0x90 for oroginal code (located in entrance of function). * */ uint64_t rip; read_process_register_64(task, RIP, &rip); if (is_breakpoint(rip - 1, &top) == 1) { stack_depth = breakpoint_handler(task, rip - 1, psymbol_table, nsym, stack_depth); write_process_register_64(task, RIP, RELATIVE_VAL, -1); disable_breakpoint(task, rip - 1, &top); ptrace(PT_STEP, child_proc, (caddr_t)1, 0); set_breakpoint(task, rip - 1, &top); } /* }}} */ } wait_cnt++; ptrace(PT_CONTINUE, child_proc, (caddr_t)1, 0); } /* }}} */ }
void LLVMState::show_machine_code(void* buffer, size_t size) { #if defined(IS_X86) || defined(IS_X8664) #ifndef RBX_WINDOWS ud_t ud; ud_init(&ud); #ifdef IS_64BIT_ARCH ud_set_mode(&ud, 64); #else ud_set_mode(&ud, 32); #endif ud_set_syntax(&ud, UD_SYN_ATT); ud_set_input_buffer(&ud, reinterpret_cast<uint8_t*>(buffer), size); while(ud_disassemble(&ud)) { void* address = reinterpret_cast<void*>( reinterpret_cast<uintptr_t>(buffer) + ud_insn_off(&ud)); llvm::outs() << format("%10p", address) << " "; llvm::outs() << format("%-24s", ud_insn_asm(&ud)); if(ud.operand[0].type == UD_OP_JIMM) { const void* addr = (const void*)((uintptr_t)buffer + ud.pc + (int)ud.operand[0].lval.udword); llvm::outs() << " ; " << addr; if(ud.mnemonic == UD_Icall) { Dl_info info; if(dladdr((void*)addr, &info)) { int status = 0; char* cpp_name = abi::__cxa_demangle(info.dli_sname, 0, 0, &status); if(status >= 0) { // Chop off the arg info from the signature output char *paren = strstr(cpp_name, "("); *paren = 0; llvm::outs() << " " << cpp_name; free(cpp_name); } else { llvm::outs() << " " << info.dli_sname; } } } } for(uint8_t i = 0; i < 2; i++) { if(ud.operand[i].type == UD_OP_IMM) { Dl_info info; if(dladdr((void*)ud.operand[i].lval.uqword, &info)) { llvm::outs() << " ; " << info.dli_sname; break; // only do one } } } llvm::outs() << "\n"; } #endif // !RBX_WINDOWS #else JITDisassembler disassembler(buffer, size); std::string output = disassembler.print_machine_code(); std::cout << output; #endif // !IS_X86 }
void lp_disassemble(const void* func) { #ifdef HAVE_UDIS86 ud_t ud_obj; uint64_t max_jmp_pc; uint inst_no; boolean emit_addrs = TRUE, emit_line_nos = FALSE; ud_init(&ud_obj); ud_set_input_buffer(&ud_obj, (void*)func, 0xffff); max_jmp_pc = (uint64_t) (uintptr_t) func; ud_set_pc(&ud_obj, max_jmp_pc); #ifdef PIPE_ARCH_X86 ud_set_mode(&ud_obj, 32); #endif #ifdef PIPE_ARCH_X86_64 ud_set_mode(&ud_obj, 64); #endif ud_set_syntax(&ud_obj, UD_SYN_ATT); while (ud_disassemble(&ud_obj)) { if (emit_addrs) { #ifdef PIPE_ARCH_X86 debug_printf("0x%08lx:\t", (unsigned long)ud_insn_off(&ud_obj)); #endif #ifdef PIPE_ARCH_X86_64 debug_printf("0x%016llx:\t", (unsigned long long)ud_insn_off(&ud_obj)); #endif } else if (emit_line_nos) { debug_printf("%6d:\t", inst_no); inst_no++; } #if 0 debug_printf("%-16s ", ud_insn_hex(&ud_obj)); #endif debug_printf("%s\n", ud_insn_asm(&ud_obj)); if(ud_obj.mnemonic != UD_Icall) { unsigned i; for(i = 0; i < 3; ++i) { const struct ud_operand *op = &ud_obj.operand[i]; if (op->type == UD_OP_JIMM){ uint64_t pc = ud_obj.pc; switch (op->size) { case 8: pc += op->lval.sbyte; break; case 16: pc += op->lval.sword; break; case 32: pc += op->lval.sdword; break; default: break; } if(pc > max_jmp_pc) max_jmp_pc = pc; } } } if (ud_obj.mnemonic == UD_Iinvalid || (ud_insn_off(&ud_obj) >= max_jmp_pc && (ud_obj.mnemonic == UD_Iret || ud_obj.mnemonic == UD_Ijmp))) break; } #if 0 /* Print GDB command, useful to verify udis86 output */ debug_printf("disassemble %p %p\n", func, (void*)(uintptr_t)ud_obj.pc); #endif debug_printf("\n"); #else (void)func; #endif }