Ejemplo n.º 1
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);
  }
}
Ejemplo n.º 2
0
void DumpPeFile(hadesmem::Process const& process,
                hadesmem::PeFile const& pe_file,
                std::wstring const& path)
{
  std::wostream& out = GetOutputStreamW();

  ClearWarnForCurrentFile();

  WriteNewline(out);
  std::wstring const architecture_str{pe_file.Is64() ? L"64-Bit File: Yes"
                                                     : L"64-Bit File: No"};
  WriteNormal(out, architecture_str, 1);

  std::uint32_t const k1MB = (1U << 20);
  std::uint32_t const k100MB = k1MB * 100;
  if (pe_file.GetSize() > k100MB)
  {
    // Not actually unsupported, just want to flag large files for use in perf
    // testing.
    WriteNewline(out);
    WriteNormal(out, L"WARNING! File is over 100MB.", 0);
    // WarnForCurrentFile(WarningType::kUnsupported);
  }

  DumpHeaders(process, pe_file);

  DumpSections(process, pe_file);

  DumpOverlay(process, pe_file);

  DumpTls(process, pe_file);

  DumpExports(process, pe_file);

  bool has_new_bound_imports_any = false;
  DumpImports(process, pe_file, has_new_bound_imports_any);

  DumpBoundImports(process, pe_file, has_new_bound_imports_any);

  DumpRelocations(process, pe_file);

  if (!g_quiet && g_strings)
  {
    DumpStrings(process, pe_file);
  }

  HandleWarnings(path);
}