Ejemplo n.º 1
0
int ludis86_ud_insn_ptr (lua_State * L)
{
    ud_t * ud_obj;
    
    ud_obj = ludis86_check_ud_t(L, 1);
    
    lua_pop(L, 1);
    
    lua_pushlstring(L, ud_insn_ptr(ud_obj), ud_insn_len(ud_obj));
    
    return 1;
}
Ejemplo n.º 2
0
/* =============================================================================
 * ud_insn_oct() - Returns octal form of disassembled instruction.
 * =============================================================================
 */
const char* 
ud_insn_oct(struct ud* u) 
{
  u->insn_octcode[0] = 0;
  if (!u->error) {
    unsigned int i;
    const unsigned char *src_ptr = ud_insn_ptr(u);
    char* src_oct;
    src_oct = (char*) u->insn_octcode;
    /* for each byte used to decode instruction */
    for (i = 0; i < ud_insn_len(u) && i < sizeof(u->insn_octcode) / 4;
         ++i, ++src_ptr) {
      sprintf(src_oct, (i > 0 ? " %03o" : "%03o"), *src_ptr & 0xFF);
      src_oct += (i > 0 ? 4 : 3);
    }
  }
  return u->insn_octcode;
}
Ejemplo n.º 3
0
/* =============================================================================
 * ud_insn_hex() - Returns hex form of disassembled instruction.
 * =============================================================================
 */
const char* 
ud_insn_hex(struct ud* u) 
{
  u->insn_hexcode[0] = 0;
  if (!u->error) {
    unsigned int i;
    const unsigned char *src_ptr = ud_insn_ptr(u);
    char* src_hex;
    src_hex = (char*) u->insn_hexcode;
    /* for each byte used to decode instruction */
    for (i = 0; i < ud_insn_len(u) && i < sizeof(u->insn_hexcode) / 2;
         ++i, ++src_ptr) {
      sprintf(src_hex, "%02x", *src_ptr & 0xFF);
      src_hex += 2;
    }
  }
  return u->insn_hexcode;
}
Ejemplo n.º 4
0
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;
}
Ejemplo n.º 5
0
struct _ins * x8664_ins (uint64_t address, ud_t * ud_obj)
{
    struct _ins * ins;
    ins = ins_create(address,
                     ud_insn_ptr(ud_obj),
                     ud_insn_len(ud_obj),
                     ud_insn_asm(ud_obj),
                     NULL);

    if (udis86_target(address, &(ud_obj->operand[0])) != -1) {
        char * mnemonic_str = NULL;
        switch (ud_obj->mnemonic) {
        case UD_Ijo   : mnemonic_str = "jo";   break;
        case UD_Ijno  : mnemonic_str = "jno";  break;
        case UD_Ijb   : mnemonic_str = "jb";   break;
        case UD_Ijae  : mnemonic_str = "jae";  break;
        case UD_Ijz   : mnemonic_str = "jz";   break;
        case UD_Ijnz  : mnemonic_str = "jnz";  break;
        case UD_Ijbe  : mnemonic_str = "jbe";  break;
        case UD_Ija   : mnemonic_str = "ja";   break;
        case UD_Ijs   : mnemonic_str = "js";   break;
        case UD_Ijns  : mnemonic_str = "jns";  break;
        case UD_Ijp   : mnemonic_str = "jp";   break;
        case UD_Ijnp  : mnemonic_str = "jnp";  break;
        case UD_Ijl   : mnemonic_str = "jl";   break;
        case UD_Ijge  : mnemonic_str = "jge";  break;
        case UD_Ijle  : mnemonic_str = "jle";  break;
        case UD_Ijg   : mnemonic_str = "jg";   break;
        case UD_Ijmp  : mnemonic_str = "jmp";  break;
        case UD_Iloop : mnemonic_str = "loop"; break;
        case UD_Icall : mnemonic_str = "call"; break;
        default : break;
        }

        uint64_t destination;
        destination  = ud_insn_len(ud_obj);
        destination += udis86_target(address, &(ud_obj->operand[0]));

        if (mnemonic_str != NULL) {
            char tmp[64];
            snprintf(tmp, 64, "%s %llx", mnemonic_str,
                     (unsigned long long) destination);
            ins_s_description(ins, tmp);
            ins_s_target(ins, destination);
        }
        else {
            struct _reference * reference;
            reference = reference_create(REFERENCE_STORE, address, destination);
            ins_add_reference(ins, reference);
            object_delete(reference);
        }
    }
    else if (udis86_target(address, &(ud_obj->operand[1])) != -1) {
        uint64_t destination;
        destination  = ud_insn_len(ud_obj);
        destination += udis86_target(address, &(ud_obj->operand[1]));
        struct _reference * reference;
        reference = reference_create(REFERENCE_LOAD, address, destination);
        ins_add_reference(ins, reference);
        object_delete(reference);
    }
    else if (    (ud_obj->operand[1].type == UD_OP_IMM)
              && (ud_obj->operand[1].size >= 32)) {
        int64_t tmp = udis86_sign_extend_lval(&(ud_obj->operand[1]));
        if (tmp > 0x1000) {
            struct _reference * reference;
            reference = reference_create(REFERENCE_CONSTANT,
                                         address,
                                         udis86_sign_extend_lval(&(ud_obj->operand[1])));
            ins_add_reference(ins, reference);
            object_delete(reference);
        }
    }

    if (ud_obj->mnemonic == UD_Icall)
        ins_s_call(ins);

    return ins;
}
Ejemplo n.º 6
0
Archivo: x86.c Proyecto: TDKPS/rdis2
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;
}
Ejemplo n.º 7
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;
  }