void DumpStrings(hadesmem::Process const& process, hadesmem::PeFile const& pe_file) { std::wostream& out = GetOutputStreamW(); std::uint8_t* const file_beg = static_cast<std::uint8_t*>(pe_file.GetBase()); void* const file_end = file_beg + pe_file.GetSize(); // TODO: Fix to not require multiple passes. WriteNewline(out); WriteNormal(out, L"Narrow Strings:", 1); WriteNewline(out); DumpStringsImpl(process, pe_file, file_beg, file_end, false); WriteNewline(out); WriteNormal(out, L"Wide Strings (Pass 1):", 1); WriteNewline(out); DumpStringsImpl(process, pe_file, file_beg, file_end, true); WriteNewline(out); WriteNormal(out, L"Wide Strings (Pass 2):", 1); WriteNewline(out); DumpStringsImpl(process, pe_file, file_beg + 1, file_end, true); }
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); }
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); } }
void DumpPeFile(hadesmem::Process const& process, hadesmem::PeFile const& pe_file, std::wstring const& path) { std::wostream& out = std::wcout; ClearWarnForCurrentFile(); 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. WriteNewline(out); WriteNormal(out, L"WARNING! File is over 100MB.", 0); WarnForCurrentFile(WarningType::kUnsupported); } DumpHeaders(process, pe_file); DumpSections(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); DumpStrings(process, pe_file); HandleWarnings(path); }
void TestDosHeader() { hadesmem::Process const process(::GetCurrentProcessId()); hadesmem::PeFile pe_file_1( process, ::GetModuleHandleW(nullptr), hadesmem::PeFileType::Image, 0); hadesmem::DosHeader dos_header_1(process, pe_file_1); hadesmem::DosHeader dos_header_2(dos_header_1); BOOST_TEST_EQ(dos_header_1, dos_header_2); dos_header_1 = dos_header_2; BOOST_TEST_EQ(dos_header_1, dos_header_2); hadesmem::DosHeader dos_header_3(std::move(dos_header_2)); BOOST_TEST_EQ(dos_header_3, dos_header_1); dos_header_2 = std::move(dos_header_3); BOOST_TEST_EQ(dos_header_1, dos_header_2); hadesmem::ModuleList modules(process); for (auto const& mod : modules) { hadesmem::PeFile const cur_pe_file( process, mod.GetHandle(), hadesmem::PeFileType::Image, 0); hadesmem::DosHeader cur_dos_header(process, cur_pe_file); auto const dos_header_raw = hadesmem::Read<IMAGE_DOS_HEADER>(process, cur_dos_header.GetBase()); BOOST_TEST_EQ(cur_dos_header.IsValid(), true); cur_dos_header.EnsureValid(); cur_dos_header.SetMagic(cur_dos_header.GetMagic()); cur_dos_header.SetBytesOnLastPage(cur_dos_header.GetBytesOnLastPage()); cur_dos_header.SetPagesInFile(cur_dos_header.GetPagesInFile()); cur_dos_header.SetRelocations(cur_dos_header.GetRelocations()); cur_dos_header.SetSizeOfHeaderInParagraphs( cur_dos_header.GetSizeOfHeaderInParagraphs()); cur_dos_header.SetMinExtraParagraphs( cur_dos_header.GetMinExtraParagraphs()); cur_dos_header.SetMaxExtraParagraphs( cur_dos_header.GetMaxExtraParagraphs()); cur_dos_header.SetInitialSS(cur_dos_header.GetInitialSS()); cur_dos_header.SetInitialSP(cur_dos_header.GetInitialSP()); cur_dos_header.SetChecksum(cur_dos_header.GetChecksum()); cur_dos_header.SetInitialIP(cur_dos_header.GetInitialIP()); cur_dos_header.SetInitialCS(cur_dos_header.GetInitialCS()); cur_dos_header.SetRelocTableFileAddr( cur_dos_header.GetRelocTableFileAddr()); cur_dos_header.SetOverlayNum(cur_dos_header.GetOverlayNum()); cur_dos_header.SetReservedWords1(cur_dos_header.GetReservedWords1()); cur_dos_header.SetOEMID(cur_dos_header.GetOEMID()); cur_dos_header.SetOEMInfo(cur_dos_header.GetOEMInfo()); cur_dos_header.SetReservedWords2(cur_dos_header.GetReservedWords2()); cur_dos_header.SetNewHeaderOffset(cur_dos_header.GetNewHeaderOffset()); cur_dos_header.UpdateWrite(); cur_dos_header.UpdateRead(); auto const dos_header_raw_new = hadesmem::Read<IMAGE_DOS_HEADER>(process, cur_pe_file.GetBase()); BOOST_TEST_EQ( std::memcmp(&dos_header_raw, &dos_header_raw_new, sizeof(dos_header_raw)), 0); std::stringstream test_str_1; test_str_1.imbue(std::locale::classic()); test_str_1 << cur_dos_header; std::stringstream test_str_2; test_str_2.imbue(std::locale::classic()); test_str_2 << cur_dos_header.GetBase(); BOOST_TEST_EQ(test_str_1.str(), test_str_2.str()); if (mod.GetHandle() != ::GetModuleHandleW(L"ntdll")) { hadesmem::PeFile const pe_file_ntdll( process, ::GetModuleHandleW(L"ntdll"), hadesmem::PeFileType::Image, 0); hadesmem::DosHeader const dos_header_ntdll(process, pe_file_ntdll); std::stringstream test_str_3; test_str_3.imbue(std::locale::classic()); test_str_3 << dos_header_ntdll.GetBase(); BOOST_TEST_NE(test_str_1.str(), test_str_3.str()); } } }