Ejemplo n.º 1
0
void DumpSections(hadesmem::Process const& process,
                  hadesmem::PeFile const& pe_file)
{
  hadesmem::SectionList sections(process, pe_file);

  std::wostream& out = GetOutputStreamW();

  if (std::begin(sections) != std::end(sections))
  {
    WriteNewline(out);
    WriteNormal(out, L"Sections:", 1);
  }
  else
  {
    // Other checks on number of sections are done as part of header handling.
    hadesmem::NtHeaders const nt_hdrs(process, pe_file);
    if (nt_hdrs.GetNumberOfSections())
    {
      WriteNewline(out);
      WriteNormal(out, L"WARNING! Section list is inavlid.", 1);
      WarnForCurrentFile(WarningType::kUnsupported);
    }
  }

  for (auto const& s : sections)
  {
    WriteNewline(out);
    if (s.IsVirtual())
    {
      WriteNormal(out, L"WARNING! Section is virtual.", 2);
      WarnForCurrentFile(WarningType::kSuspicious);
    }
    HandleLongOrUnprintableString(
      L"name", L"section name", 2, WarningType::kSuspicious, s.GetName());
    WriteNamedHex(out, L"VirtualAddress", s.GetVirtualAddress(), 2);
    WriteNamedHex(out, L"VirtualSize", s.GetVirtualSize(), 2);
    WriteNamedHex(out, L"PointerToRawData", s.GetPointerToRawData(), 2);
    WriteNamedHex(out, L"SizeOfRawData", s.GetSizeOfRawData(), 2);
    WriteNamedHex(out, L"PointerToRelocations", s.GetPointerToRelocations(), 2);
    WriteNamedHex(out, L"PointerToLinenumbers", s.GetPointerToLinenumbers(), 2);
    WriteNamedHex(out, L"NumberOfRelocations", s.GetNumberOfRelocations(), 2);
    WriteNamedHex(out, L"NumberOfLinenumbers", s.GetNumberOfLinenumbers(), 2);
    WriteNamedHex(out, L"Characteristics", s.GetCharacteristics(), 2);
  }
}
Ejemplo n.º 2
0
void DumpExports(hadesmem::Process const& process,
                 hadesmem::PeFile const& pe_file)
{
  std::unique_ptr<hadesmem::ExportDir const> export_dir;
  try
  {
    export_dir = std::make_unique<hadesmem::ExportDir const>(process, pe_file);
  }
  catch (std::exception const& /*e*/)
  {
    return;
  }

  std::wostream& out = std::wcout;

  WriteNewline(out);
  WriteNormal(out, L"Export Dir:", 1);
  WriteNewline(out);

  WriteNamedHex(out, L"Characteristics", export_dir->GetCharacteristics(), 2);
  DWORD const time_date_stamp = export_dir->GetTimeDateStamp();
  std::wstring time_date_stamp_str;
  if (!ConvertTimeStamp(time_date_stamp, time_date_stamp_str))
  {
    WriteNormal(out, L"WARNING! Invalid timestamp.", 2);
    WarnForCurrentFile(WarningType::kSuspicious);
  }
  WriteNamedHexSuffix(
    out, L"TimeDateStamp", time_date_stamp, time_date_stamp_str, 2);
  WriteNamedHex(out, L"MajorVersion", export_dir->GetMajorVersion(), 2);
  WriteNamedHex(out, L"MinorVersion", export_dir->GetMinorVersion(), 2);
  WriteNamedHex(out, L"Name (Raw)", export_dir->GetNameRaw(), 2);
  // Name is not guaranteed to be valid.
  // Sample: dllord.dll (Corkami PE Corpus)
  try
  {
    auto name = export_dir->GetName();
    HandleLongOrUnprintableString(
      L"Name", L"export module name", 2, WarningType::kSuspicious, name);
  }
  catch (std::exception const& /*e*/)
  {
    WriteNormal(out, L"WARNING! Failed to read export dir name.", 2);
    WarnForCurrentFile(WarningType::kSuspicious);
  }
  WriteNamedHex(out, L"OrdinalBase", export_dir->GetOrdinalBase(), 2);
  WriteNamedHex(
    out, L"NumberOfFunctions", export_dir->GetNumberOfFunctions(), 2);
  WriteNamedHex(out, L"NumberOfNames", export_dir->GetNumberOfNames(), 2);
  WriteNamedHex(
    out, L"AddressOfFunctions", export_dir->GetAddressOfFunctions(), 2);
  WriteNamedHex(out, L"AddressOfNames", export_dir->GetAddressOfNames(), 2);
  WriteNamedHex(
    out, L"AddressOfNameOrdinals", export_dir->GetAddressOfNameOrdinals(), 2);

  std::set<std::string> export_names;

  hadesmem::ExportList const exports(process, pe_file);
  if (std::begin(exports) != std::end(exports))
  {
    WriteNewline(out);
    WriteNormal(out, L"Exports:", 2);
  }
  else
  {
    WriteNewline(out);
    WriteNormal(out, L"WARNING! Empty or invalid export list.", 2);
    WarnForCurrentFile(WarningType::kSuspicious);
  }

  std::uint32_t num_exports = 0U;
  for (auto const& e : exports)
  {
    WriteNewline(out);

    // Some legitimate DLLs have well over 1000 exports (e.g. ntdll.dll).
    if (num_exports++ == 10000)
    {
      WriteNormal(
        out,
        L"WARNING! Processed 10000 exports. Stopping early to avoid resource "
        L"exhaustion attacks.",
        2);
      WarnForCurrentFile(WarningType::kSuspicious);
      break;
    }

    if (e.ByName())
    {
      auto const name = e.GetName();
      // Sample: dllweirdexp.dll
      HandleLongOrUnprintableString(
        L"Name", L"export name", 3, WarningType::kSuspicious, name);

      // PE files can have duplicate exported function names (or even have them
      // all identical) because the import hint is used to check the name first
      // before performing a search.
      // Sample: None ("Import name hint" section of "Undocumented PECOFF"
      // whitepaper).
      if (!export_names.insert(name).second)
      {
        WriteNormal(out, L"WARNING! Detected duplicate export name.", 3);
        WarnForCurrentFile(WarningType::kSuspicious);
      }
    }

    WriteNamedHex(out, L"ProcedureNumber", e.GetProcedureNumber(), 3);
    WriteNamedHex(out, L"OrdinalNumber", e.GetOrdinalNumber(), 3);

    if (e.IsForwarded())
    {
      WriteNamedNormal(out, L"Forwarder", e.GetForwarder().c_str(), 3);
      WriteNamedNormal(
        out, L"ForwarderModule", e.GetForwarderModule().c_str(), 3);
      WriteNamedNormal(
        out, L"ForwarderFunction", e.GetForwarderFunction().c_str(), 3);
      WriteNamedNormal(
        out, L"IsForwardedByOrdinal", e.IsForwardedByOrdinal(), 3);
      if (e.IsForwardedByOrdinal())
      {
        try
        {
          WriteNamedHex(out, L"ForwarderOrdinal", e.GetForwarderOrdinal(), 3);
        }
        catch (std::exception const& /*e*/)
        {
          WriteNormal(out, L"WARNING! ForwarderOrdinal invalid.", 3);
          WarnForCurrentFile(WarningType::kSuspicious);
        }
      }
    }
    else
    {
      auto const ep_rva = e.GetRva();
      WriteNamedHex(out, L"RVA", e.GetRva(), 3);
      auto const ep_va = e.GetVa();
      WriteNamedHex(out, L"VA", reinterpret_cast<std::uintptr_t>(ep_va), 3);

      if (ep_va)
      {
        DisassembleEp(process, pe_file, ep_rva, ep_va, 4);
      }
      else
      {
        WriteNormal(out, L"WARNING! Export VA is invalid.", 3);
        WarnForCurrentFile(WarningType::kSuspicious);
      }
    }
  }
}