status_t DisassemblerX8664::GetNextInstructionInfo(InstructionInfo& _info, CpuState* state) { unsigned int size = ud_disassemble(fUdisData); if (size < 1) return B_ENTRY_NOT_FOUND; target_addr_t address = ud_insn_off(fUdisData); instruction_type type = INSTRUCTION_TYPE_OTHER; target_addr_t targetAddress = 0; ud_mnemonic_code mnemonic = ud_insn_mnemonic(fUdisData); if (mnemonic == UD_Icall) type = INSTRUCTION_TYPE_SUBROUTINE_CALL; else if (mnemonic == UD_Ijmp) type = INSTRUCTION_TYPE_JUMP; if (state != NULL) targetAddress = GetInstructionTargetAddress(state); char buffer[256]; snprintf(buffer, sizeof(buffer), "0x%016" B_PRIx64 ": %16.16s %s", address, ud_insn_hex(fUdisData), ud_insn_asm(fUdisData)); // TODO: Resolve symbols! if (!_info.SetTo(address, targetAddress, size, type, true, buffer)) return B_NO_MEMORY; return B_OK; }
int main(void) { ud_t ud_obj; char x[4]; unsigned char buff[256]; int i, j; printf("Content-Type: text/html\r\n"); printf("\r\n"); char *qs = getenv("QUERY_STRING"); if(qs == NULL) return 1; for(i=0, j=0; qs[i] == '%'; i+=3, j++){ if(j >= sizeof(buff)) break; x[0] = *(qs+i+1); x[1] = *(qs+i+2); x[2] = '\0'; buff[j] = (unsigned char)strtoul(x, NULL, 16); } ud_init(&ud_obj); ud_set_input_buffer(&ud_obj, buff, j); ud_set_mode(&ud_obj, 32); ud_set_syntax(&ud_obj, UD_SYN_INTEL); while(ud_disassemble(&ud_obj)){ //printf("%d:%s", ud_insn_len(&ud_obj), ud_insn_asm(&ud_obj)); printf("%10s: %s\n", ud_insn_hex(&ud_obj), ud_insn_asm(&ud_obj)); } return 0; }
void DisassembleEp(hadesmem::Process const& process, hadesmem::PeFile const& pe_file, std::uintptr_t ep_rva, void* ep_va, std::size_t tabs) { if (!ep_va) { return; } std::wostream& out = GetOutputStreamW(); // Get the number of bytes from the EP to the end of the file. std::size_t max_buffer_size = GetBytesToEndOfFile(pe_file, ep_va); // Clamp the amount of data read to the theoretical maximum. std::size_t const kMaxInstructions = 10U; std::size_t const kMaxInstructionLen = 15U; std::size_t const kMaxInstructionsBytes = kMaxInstructions * kMaxInstructionLen; max_buffer_size = (std::min)(max_buffer_size, kMaxInstructionsBytes); auto const disasm_buf = hadesmem::ReadVector<std::uint8_t>(process, ep_va, max_buffer_size); std::uint64_t const ip = hadesmem::GetRuntimeBase(process, pe_file) + ep_rva; ud_t ud_obj; ud_init(&ud_obj); ud_set_input_buffer(&ud_obj, disasm_buf.data(), max_buffer_size); ud_set_syntax(&ud_obj, UD_SYN_INTEL); ud_set_pc(&ud_obj, ip); ud_set_mode(&ud_obj, pe_file.Is64() ? 64 : 32); // Be pessimistic. Use the minimum theoretical amount of instrutions we could // fit in our buffer. std::size_t const instruction_count = max_buffer_size / kMaxInstructionLen; for (std::size_t i = 0U; i < instruction_count; ++i) { std::uint32_t const len = ud_disassemble(&ud_obj); if (len == 0) { WriteNormal(out, L"WARNING! Disassembly failed.", tabs); // If we can't disassemble at least 5 instructions there's probably // something strange about the function. Even in the case of a nullsub // there is typically some INT3 or NOP padding after it... WarnForCurrentFile(i < 5U ? WarningType::kUnsupported : WarningType::kSuspicious); break; } char const* const asm_str = ud_insn_asm(&ud_obj); HADESMEM_DETAIL_ASSERT(asm_str); char const* const asm_bytes_str = ud_insn_hex(&ud_obj); HADESMEM_DETAIL_ASSERT(asm_bytes_str); auto const diasm_line = hadesmem::detail::MultiByteToWideChar(asm_str) + L" (" + hadesmem::detail::MultiByteToWideChar(asm_bytes_str) + L")"; WriteNormal(out, diasm_line, tabs); } }
int MDBCodeRegion::disassemble(char *buffer, size_t bufferSize) { void *localBuffer = malloc(size); code->debugger->read(localBuffer, address, size); ud_t ud_obj; ud_init(&ud_obj); ud_set_input_buffer(&ud_obj, (uint8_t*)localBuffer, size); ud_set_mode(&ud_obj, 32); ud_set_syntax(&ud_obj, UD_SYN_INTEL); uint32_t remainingBytes = size; do { int pc = ud_obj.pc; size_t insnSize = ud_disassemble(&ud_obj); remainingBytes -= insnSize; appendString(buffer, "0x%llx: %-16s %s\n", address + pc, ud_insn_hex(&ud_obj), ud_insn_asm(&ud_obj)); } while (remainingBytes > 0); free(localBuffer); return 0; }
// Function to read and disassemble one instrution after ptrace stopped on singlestep // written by Xiao Lin static void handle_singelstep() { struct user_regs_struct regfile; ptrace(PTRACE_GETREGS, tr_pid, NULL, ®file); unsigned long addr = regfile.eip; fprintf(stdout, "Address = 0x%08lx\n", addr); unsigned long data = 0; data = ptrace(PTRACE_PEEKTEXT, tr_pid, addr, NULL); fprintf(stdout, "Data = 0x%08lx\n", data); ud_t ud_obj; unsigned char buff[15]; memcpy(buff, (char*)&data, sizeof(long)); // setup udis86 ud_init(&ud_obj); ud_set_mode(&ud_obj, 32); ud_set_syntax(&ud_obj, UD_SYN_INTEL); ud_set_input_buffer(&ud_obj, buff, 15); // disassemble and have udis86 guess instruction length ud_disassemble(&ud_obj); unsigned int instr_len = ud_insn_len(&ud_obj); fprintf(stdout, "Instruction length = %d Bytes\n", instr_len); // get more byte via ptrace if intruction length > 4bytes int i = 4; while (i < instr_len) { data = ptrace(PTRACE_PEEKTEXT, tr_pid, addr+i, NULL); memcpy(buff+i, (char*)&data, sizeof(long)); i = i + 4; } // disassemble second time and print ud_init(&ud_obj); ud_set_mode(&ud_obj, 32); ud_set_syntax(&ud_obj, UD_SYN_INTEL); ud_set_input_buffer(&ud_obj, buff, 15); if (ud_disassemble(&ud_obj) != 0) { printf("Disassemble: %s %s\n", ud_insn_hex(&ud_obj), ud_insn_asm(&ud_obj)); } return; }
status_t DisassemblerX8664::GetNextInstruction(BString& line, target_addr_t& _address, target_size_t& _size, bool& _breakpointAllowed) { unsigned int size = ud_disassemble(fUdisData); if (size < 1) return B_ENTRY_NOT_FOUND; target_addr_t address = ud_insn_off(fUdisData); char buffer[256]; snprintf(buffer, sizeof(buffer), "0x%016" B_PRIx64 ": %16.16s %s", address, ud_insn_hex(fUdisData), ud_insn_asm(fUdisData)); // TODO: Resolve symbols! line = buffer; _address = address; _size = size; _breakpointAllowed = true; // TODO: Implement (rep!)! return B_OK; }
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; }
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 }