Example #1
0
int main(int argc, char* argv[])
{
  try
  {
    std::cout << "HadesMem Dumper [" << HADESMEM_VERSION_STRING << "]\n";

    TCLAP::CmdLine cmd("PE file format dumper", ' ', HADESMEM_VERSION_STRING);
    TCLAP::ValueArg<DWORD> pid_arg(
      "", "pid", "Target process id", false, 0, "DWORD");
    TCLAP::ValueArg<std::string> name_arg(
      "", "name", "Target process name", false, "", "string");
    TCLAP::MultiArg<std::string> path_arg(
      "", "path", "Target path (file or directory)", false, "string");
    TCLAP::SwitchArg all_arg("", "all", "No target, dump everything");
    std::vector<TCLAP::Arg*> xor_args{&pid_arg, &name_arg, &path_arg, &all_arg};
    cmd.xorAdd(xor_args);
    TCLAP::SwitchArg warned_arg(
      "", "warned", "Dump list of files which cause warnings", cmd);
    TCLAP::ValueArg<std::string> warned_file_arg(
      "",
      "warned-file",
      "Dump warned list to file instead of stdout",
      false,
      "",
      "string",
      cmd);
    TCLAP::SwitchArg warned_file_dynamic_arg(
      "",
      "warned-file-dynamic",
      "Dump warnings to file on the fly rather than at the end",
      cmd);
    TCLAP::SwitchArg quiet_arg(
      "", "quiet", "Only output status messages (no dumping)", cmd);
    TCLAP::SwitchArg memonly_arg("", "memonly", "Only do PE memory dumps", cmd);
    TCLAP::ValueArg<int> warned_type_arg("",
                                         "warned-type",
                                         "Filter warned file using warned type",
                                         false,
                                         -1,
                                         "int",
                                         cmd);
    TCLAP::ValueArg<DWORD> threads_arg(
      "", "threads", "Number of threads", false, 0, "size_t", cmd);
    TCLAP::ValueArg<DWORD> queue_factor_arg(
      "", "queue-factor", "Thread queue factor", false, 0, "size_t", cmd);
    TCLAP::SwitchArg strings_arg("", "strings", "Dump strings", cmd);
    cmd.parse(argc, argv);

    g_quiet = quiet_arg.isSet();

    g_strings = strings_arg.isSet();

    SetWarningsEnabled(warned_arg.getValue());
    SetDynamicWarningsEnabled(warned_file_dynamic_arg.getValue());
    if (warned_file_arg.isSet())
    {
      SetWarnedFilePath(
        hadesmem::detail::MultiByteToWideChar(warned_file_arg.getValue()));
    }

    if (GetDynamicWarningsEnabled() && GetWarnedFilePath().empty())
    {
      HADESMEM_DETAIL_THROW_EXCEPTION(
        hadesmem::Error() << hadesmem::ErrorString(
          "Please specify a file path for dynamic warnings."));
    }

    int const warned_type = warned_type_arg.getValue();
    switch (warned_type)
    {
    case static_cast<int>(WarningType::kSuspicious):
      SetWarnedType(WarningType::kSuspicious);
      break;
    case static_cast<int>(WarningType::kUnsupported):
      SetWarnedType(WarningType::kUnsupported);
      break;
    case static_cast<int>(WarningType::kAll):
      SetWarnedType(WarningType::kAll);
      break;
    default:
      HADESMEM_DETAIL_THROW_EXCEPTION(
        hadesmem::Error() << hadesmem::ErrorString("Unknown warned type."));
      break;
    }

    try
    {
      hadesmem::GetSeDebugPrivilege();

      std::wcout << "\nAcquired SeDebugPrivilege.\n";
    }
    catch (std::exception const& /*e*/)
    {
      std::wcout << "\nFailed to acquire SeDebugPrivilege.\n";
    }

    auto const threads = threads_arg.isSet() ? threads_arg.getValue() : 1;
    auto const queue_factor =
      queue_factor_arg.isSet() ? queue_factor_arg.getValue() : 1;
    hadesmem::detail::ThreadPool thread_pool{threads, queue_factor};

    if (pid_arg.isSet())
    {
      DWORD const pid = pid_arg.getValue();

      hadesmem::ProcessList const processes;
      auto iter =
        std::find_if(std::begin(processes),
                     std::end(processes),
                     [pid](hadesmem::ProcessEntry const& process_entry)
                     {
                       return process_entry.GetId() == pid;
                     });
      if (iter != std::end(processes))
      {
        DumpProcessEntry(*iter, memonly_arg.isSet());
      }
      else
      {
        HADESMEM_DETAIL_THROW_EXCEPTION(
          hadesmem::Error()
          << hadesmem::ErrorString("Failed to find requested process."));
      }
    }
    else if (name_arg.isSet())
    {
      auto const proc_name =
        hadesmem::detail::MultiByteToWideChar(name_arg.getValue());
      auto const proc_entry = hadesmem::GetProcessEntryByName(proc_name, false);
      DumpProcessEntry(proc_entry, memonly_arg.isSet());
    }
    else if (path_arg.isSet())
    {
      // TODO: Use backup semantics flags and try to get backup privilege in
      // order to make directory enumeration find more files.
      auto const path_args = path_arg.getValue();
      for (auto const& path : path_args)
      {
        auto const path_wide = hadesmem::detail::MultiByteToWideChar(path);
        if (hadesmem::detail::IsDirectory(path_wide))
        {
          DumpDir(path_wide, thread_pool);
        }
        else
        {
          DumpFile(path_wide);
        }
      }
    }
    else
    {
      DumpThreads(static_cast<DWORD>(-1));

      DumpProcesses(memonly_arg.isSet());

      std::wcout << "\nFiles:\n";

      // TODO: Enumerate all volumes.
      std::wstring const self_path = hadesmem::detail::GetSelfPath();
      std::wstring const root_path = hadesmem::detail::GetRootPath(self_path);
      DumpDir(root_path, thread_pool);
    }

    thread_pool.WaitForEmpty();

    if (GetWarningsEnabled())
    {
      if (!GetWarnedFilePath().empty() && !GetDynamicWarningsEnabled())
      {
        std::unique_ptr<std::wfstream> warned_file_ptr(
          hadesmem::detail::OpenFile<wchar_t>(GetWarnedFilePath(),
                                              std::ios::out));
        std::wfstream& warned_file = *warned_file_ptr;
        if (!warned_file)
        {
          HADESMEM_DETAIL_THROW_EXCEPTION(
            hadesmem::Error()
            << hadesmem::ErrorString("Failed to open warned file for output."));
        }

        DumpWarned(warned_file);
      }
      else
      {
        DumpWarned(std::wcout);
      }
    }

    return 0;
  }
  catch (...)
  {
    std::cerr << "\nError!\n"
              << boost::current_exception_diagnostic_information() << '\n';

    return 1;
  }
}
Example #2
0
int
p11_tool_main (int argc,
               char *argv[],
               const p11_tool_command *commands)
{
	const p11_tool_command *fallback = NULL;
	char *command = NULL;
	bool want_help = false;
	bool skip;
	int in, out;
	int i;

	/*
	 * Parse the global options. We rearrange the options as
	 * necessary, in order to pass relevant options through
	 * to the commands, but also have them take effect globally.
	 */

	for (in = 1, out = 1; in < argc; in++, out++) {

		/* The non-option is the command, take it out of the arguments */
		if (argv[in][0] != '-') {
			if (!command) {
				skip = true;
				command = argv[in];
			} else {
				skip = false;
			}

		/* The global long options */
		} else if (argv[in][1] == '-') {
			skip = false;

			if (strcmp (argv[in], "--") == 0) {
				if (!command) {
					p11_message ("no command specified");
					return 2;
				} else {
					break;
				}

			} else if (strcmp (argv[in], "--verbose") == 0) {
				verbose_arg ();

			} else if (strcmp (argv[in], "--quiet") == 0) {
				quiet_arg ();

			} else if (strcmp (argv[in], "--help") == 0) {
				want_help = true;

			} else if (!command) {
				p11_message ("unknown global option: %s", argv[in]);
				return 2;
			}

		/* The global short options */
		} else {
			skip = false;

			for (i = 1; argv[in][i] != '\0'; i++) {
				switch (argv[in][i]) {
				case 'h':
					want_help = true;
					break;

				/* Compatibility option */
				case 'l':
					command = "list-modules";
					break;

				case 'v':
					verbose_arg ();
					break;

				case 'q':
					quiet_arg ();
					break;

				default:
					if (!command) {
						p11_message ("unknown global option: -%c", (int)argv[in][i]);
						return 2;
					}
					break;
				}
			}
		}

		/* Skipping this argument? */
		if (skip)
			out--;
		else
			argv[out] = argv[in];
	}

	/* Initialize tool's debugging after setting env vars above */
	p11_debug_init ();

	if (command == NULL) {
		/* As a special favor if someone just typed the command, help them out */
		if (argc == 1) {
			command_usage (commands);
			return 2;
		} else if (want_help) {
			command_usage (commands);
			return 0;
		} else {
			p11_message ("no command specified");
			return 2;
		}
	}

	argc = out;

	/* Look for the command */
	for (i = 0; commands[i].name != NULL; i++) {
		if (strcmp (commands[i].name, P11_TOOL_FALLBACK) == 0) {
			fallback = commands + i;

		} else if (strcmp (commands[i].name, command) == 0) {
			argv[0] = command;
			return (commands[i].function) (argc, argv);
		}
	}

	/* Got here because no command matched */
	if (fallback != NULL) {
		argv[0] = command;
		return (fallback->function) (argc, argv);
	}

	/* At this point we have no command */
	p11_message ("'%s' is not a valid command. See '%s --help'",
	             command, getprogname ());
	return 2;
}