Beispiel #1
0
void DumpBoundImports(hadesmem::Process const& process,
                      hadesmem::PeFile const& pe_file,
                      bool has_new_bound_imports_any)
{
  std::wostream& out = GetOutputStreamW();

  if (!HasBoundImportDir(process, pe_file))
  {
    // Sample: dllmaxvals.dll (Corkami PE Corpus)
    if (has_new_bound_imports_any)
    {
      WriteNewline(out);
      WriteNormal(
        out,
        L"WARNING! No bound import directory on file with an import dir "
        L"indicating the presence of a bound import dir.",
        1);
      WarnForCurrentFile(WarningType::kSuspicious);
    }

    return;
  }

  if (!has_new_bound_imports_any)
  {
    WriteNewline(out);
    WriteNormal(
      out,
      L"WARNING! Seemingly valid bound import directory on file with an "
      L"import dir indicating no new bound import dir.",
      1);
    WarnForCurrentFile(WarningType::kSuspicious);
    return;
  }

  hadesmem::BoundImportDescriptorList const bound_import_descs(process,
                                                               pe_file);

  if (std::begin(bound_import_descs) == std::end(bound_import_descs))
  {
    WriteNewline(out);
    WriteNormal(out, L"WARNING! Empty or invalid bound import directory.", 1);
    WarnForCurrentFile(WarningType::kSuspicious);
    return;
  }

  WriteNewline(out);
  WriteNormal(out, L"Bound Import Descriptors:", 1);

  std::uint32_t num_descs = 0U;
  for (auto const& desc : bound_import_descs)
  {
    WriteNewline(out);

    if (num_descs++ == 1000)
    {
      WriteNormal(out,
                  L"WARNING! Processed 1000 bound import descriptors. Stopping "
                  L"early to avoid resource exhaustion attacks.",
                  2);
      WarnForCurrentFile(WarningType::kUnsupported);
      break;
    }

    DWORD const time_date_stamp = desc.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"OffsetModuleName", desc.GetOffsetModuleName(), 2);
    WriteNamedNormal(out, L"ModuleName", desc.GetModuleName().c_str(), 2);
    WriteNamedHex(out,
                  L"NumberOfModuleForwarderRefs",
                  desc.GetNumberOfModuleForwarderRefs(),
                  2);
    hadesmem::BoundImportForwarderRefList const forwarder_refs(
      process, pe_file, desc);
    if (std::begin(forwarder_refs) != std::end(forwarder_refs))
    {
      WriteNewline(out);
      WriteNormal(out, L"Module Forwarder Refs:", 2);
    }
    for (auto const& forwarder : forwarder_refs)
    {
      WriteNewline(out);

      DWORD const fwd_time_date_stamp = forwarder.GetTimeDateStamp();
      std::wstring fwd_time_date_stamp_str;
      if (!ConvertTimeStamp(fwd_time_date_stamp, fwd_time_date_stamp_str))
      {
        WriteNormal(out, L"WARNING! Invalid timestamp.", 3);
        WarnForCurrentFile(WarningType::kSuspicious);
      }
      WriteNamedHexSuffix(
        out, L"TimeDateStamp", fwd_time_date_stamp, fwd_time_date_stamp_str, 3);
      WriteNamedHex(
        out, L"OffsetModuleName", forwarder.GetOffsetModuleName(), 3);
      WriteNamedNormal(
        out, L"ModuleName", forwarder.GetModuleName().c_str(), 3);
      WriteNamedHex(out, L"Reserved", forwarder.GetReserved(), 3);
    }
  }
}
Beispiel #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);
      }
    }
  }
}