Esempio n. 1
0
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;
}
Esempio n. 2
0
  void LLVMState::show_machine_code(void* buffer, size_t size) {
    ud_t ud;

    ud_init(&ud);
#ifdef IS_X8664
    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));

      std::cout << std::setw(10) << std::right
                << address
                << "  ";

      std::cout << std::setw(24) << std::left << 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);
        std::cout << " ; " << addr;
        if(ud.mnemonic == UD_Icall) {
          Dl_info info;
          if(dladdr(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;
              std::cout << " " << cpp_name;
              free(cpp_name);
            } else {
              std::cout << " " << 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)) {
            std::cout << " ; " << info.dli_sname;
            break; // only do one
          }
        }
      }

      std::cout << "\n";
    }
  }
Esempio n. 3
0
int ludis86_ud_insn_hex (lua_State * L)
{
    ud_t * ud_obj;
    
    ud_obj = ludis86_check_ud_t(L, 1);
    
    lua_pop(L, 1);
    
    lua_pushinteger(L, ud_insn_off(ud_obj));
    
    return 1;
}
Esempio n. 4
0
static int check_dynamic_opr(ud_t *udptr)
{
	//obtain the operand of current instruction
	const ud_operand_t *opr = ud_insn_opr(udptr, 0);	
	if (opr == NULL) {
		fprintf(stderr, "Bad jmp instruction at address %p.\n", (void *)ud_insn_off(udptr));
		exit(1);
	}
	
	//if it is a dynamic operand
	if (opr->type == UD_OP_MEM || opr->type == UD_OP_PTR || opr->type == UD_OP_REG)
		return 1;
		
	return 0;
}
Esempio n. 5
0
status_t
DisassemblerX8664::GetPreviousInstruction(target_addr_t nextAddress,
	target_addr_t& _address, target_size_t& _size)
{
	if (nextAddress < fAddress || nextAddress > fAddress + fCodeSize)
		return B_BAD_VALUE;

	// loop until hitting the last instruction
	while (true) {
		target_size_t size = ud_disassemble(fUdisData);
		if (size < 1)
			return B_ENTRY_NOT_FOUND;

		target_addr_t address = ud_insn_off(fUdisData);
		if (address + size == nextAddress) {
			_address = address;
			_size = size;
			return B_OK;
		}
	}
}
Esempio n. 6
0
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;
}
Esempio n. 7
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

  }
Esempio n. 8
0
  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;
  }
Esempio n. 9
0
target_addr_t
DisassemblerX8664::GetInstructionTargetAddress(CpuState* state) const
{
	ud_mnemonic_code mnemonic = ud_insn_mnemonic(fUdisData);
	if (mnemonic != UD_Icall && mnemonic != UD_Ijmp)
		return 0;

	CpuStateX8664* x64State = dynamic_cast<CpuStateX8664*>(state);
	if (x64State == NULL)
		return 0;

	target_addr_t targetAddress = 0;
	const struct ud_operand* op = ud_insn_opr(fUdisData, 0);
	switch (op->type) {
		case UD_OP_REG:
		{
			targetAddress = x64State->IntRegisterValue(
				RegisterNumberFromUdisIndex(op->base));
			targetAddress += op->offset;
		}
		break;
		case UD_OP_MEM:
		{
			targetAddress = x64State->IntRegisterValue(
				RegisterNumberFromUdisIndex(op->base));
			targetAddress += x64State->IntRegisterValue(
				RegisterNumberFromUdisIndex(op->index))
				* op->scale;
			off_t offset = 0;
			switch (op->offset) {
				case 8:
					offset = op->lval.sbyte;
					break;
				case 16:
					offset = op->lval.sword;
					break;
				case 32:
					offset = op->lval.sdword;
					break;
				case 64:
					offset = op->lval.sqword;
					break;
			}
			targetAddress += offset;
		}
		break;
		case UD_OP_JIMM:
		{
			targetAddress = ud_insn_off(fUdisData) + ud_insn_len(fUdisData);
			if (op->size == 32)
				targetAddress += op->lval.sdword;
			else
				targetAddress += op->lval.sqword;
		}
		break;

		case UD_OP_IMM:
		case UD_OP_CONST:
		{
			if (op->size == 32)
				targetAddress = op->lval.udword;
			else if (op->size == 64)
				targetAddress = op->lval.uqword;
		}
		break;

		default:
		break;
	}

	return targetAddress;
}
Esempio n. 10
0
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
}