Dumps memory of a guest process to a file. Demonstrates attaching to a domain, resolving a process by name, and reading guest virtual memory (e.g. via NtReadVirtualMemory or guest memory mapping).
#include <boost/algorithm/string.hpp>
#include <boost/program_options.hpp>
#include <cerrno>
#include <csignal>
#include <cstring>
#include <iostream>
#include <memory>
#include <thread>
namespace po = boost::program_options;
po::variables_map& vm);
std::unique_ptr<Domain>
domain;
std::cerr << "Interrupted by signal, exiting...\n";
}
}
public:
MemDumpTool(
const std::string& output_file) : output_file_(output_file) {}
auto& vcpu = event.vcpu();
auto object_attributes = inject::allocate<nt::OBJECT_ATTRIBUTES>();
auto client_id = inject::allocate<nt::CLIENT_ID>(pid, 0);
const uint32_t access_mask =
uint64_t process_handle;
auto result = inject::system_call<nt::NtOpenProcess>(process_handle, access_mask,
object_attributes, client_id);
std::cerr <<
"Failed to open PID " << pid <<
": " <<
result <<
'\n';
return;
}
auto ObjectTable = current_process.ObjectTable();
auto process = ObjectTable->ProcessObject(process_handle);
std::cout << "Opened process " << process->ImageFileName() << std::endl;
auto mmvad = process->VadRoot();
if (!mmvad) {
std::cerr << "MMVAD was null\n";
return;
}
auto mbi = inject::allocate<MEMORY_BASIC_INFORMATION>();
for (const auto& entry : mmvad->VadTreeInOrder()) {
if ((entry->Protection().value() & PAGE_PROTECTION::PAGE_NOACCESS))
continue;
if (pid == current_process.UniqueProcessId()) {
if (object_attributes.ptr().page_number() == entry->StartingVpn())
continue;
if (client_id.ptr().page_number() == entry->StartingVpn())
continue;
if (mbi.ptr().page_number() == entry->StartingVpn())
continue;
}
uint64_t addr;
for (addr = entry->StartingAddress(); addr < entry->EndingAddress();) {
auto result = inject::system_call<nt::NtQueryVirtualMemory>(
mbi->buffer_size(), nullptr);
std::cerr <<
"NtQueryVirtualMemory failed for " << addr <<
": " <<
result
<< '\n';
addr += x86::PageDirectory::PAGE_SIZE;
continue;
}
if (mbi->State().MEM_COMMIT() == false ||
(mbi->Protect() &
(PAGE_PROTECTION::PAGE_GUARD | PAGE_PROTECTION::PAGE_NOACCESS)) != 0 ||
addr += mbi->RegionSize();
continue;
}
dump_regions.push_back(std::make_pair(gva, gva + mbi->RegionSize()));
addr += mbi->RegionSize();
}
}
int count = 0;
constexpr int BufferSize = x86::PageDirectory::PAGE_SIZE * 4;
auto buffer = inject::allocate<char[]>(BufferSize);
FILE* output = fopen64(output_file_.c_str(), "wb");
if (!output) {
std::cerr << "Failed to open output file\n";
goto bad_fopen;
}
for (const auto& region : dump_regions) {
for (auto addr = region.first; addr < region.second;) {
const uint32_t copy_size =
std::min<uint64_t>(region.second.address() - addr.address(), BufferSize);
uint32_t ResultLength = 0;
auto result = inject::system_call<nt::NtReadVirtualMemory>(
process_handle, addr, buffer, x86::PageDirectory::PAGE_SIZE, &ResultLength);
if (!
result.NT_SUCCESS() || ResultLength != x86::PageDirectory::PAGE_SIZE) {
std::cerr <<
"Failed to copy " << addr <<
": " <<
result <<
'\n';
addr += x86::PageDirectory::PAGE_SIZE;
continue;
}
off64_t offset = addr.address();
if (fseeko64(output, offset, SEEK_SET) < 0) {
}
fwrite(buffer.ptr().get(), 1, copy_size, output);
count += (copy_size / x86::PageDirectory::PAGE_SIZE);
addr += copy_size;
}
}
fclose(output);
std::cerr << "Done!\n";
std::cerr << "Copied " << count << " pages\n";
result_ = 0;
bad_fopen:
result = inject::system_call<nt::NtClose>(process_handle);
std::cerr <<
"Failed to close target process: " <<
result <<
'\n';
}
event.
type() == EventType::EVENT_REBOOT)) {
result_ = 64;
return;
}
if (started_.test_and_set() == true)
return;
event.domain().intercept_system_calls(false);
event.domain().interrupt();
}
int result()
const {
return result_; }
private:
const std::string output_file_;
std::atomic_flag started_ = false;
uint8_t result_ = 1;
};
int main(
int argc,
char** argv) {
po::options_description desc("Options");
std::string domain_name;
std::string process_name;
std::string output;
desc.add_options()
("domain,D", po::value<std::string>(&domain_name)->required(), "The domain name or ID attach to")
("procname,P", po::value<std::string>(&process_name)->required(), "The name of a process to hijack")
("output,o", po::value<std::string>(&output)->required(), "A path to an output file")
("help", "Display program help");
std::cout.sync_with_stdio(false);
po::variables_map vm;
auto hypervisor = Hypervisor::instance();
domain = hypervisor->attach_domain(domain_name);
if (!
domain->detect_guest()) {
std::cerr << "Failed to detect guest OS\n";
return 1;
}
if (
domain->guest()->os() != OS::Windows) {
std::cerr <<
"Unsupported OS: " <<
domain->guest()->os() <<
'\n';
return 1;
}
domain->task_filter().add_name(process_name);
domain->intercept_system_calls(
true);
return tool.result();
}
po::variables_map& vm) {
try {
po::store(po::parse_command_line(argc, argv, desc), vm);
if (vm.count("help")) {
std::cout << "ivexec - Execute a file in the guest" << '\n';
std::cout << desc << '\n';
exit(0);
}
po::notify(vm);
} catch (po::error& e) {
std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
std::cerr << desc << std::endl;
exit(1);
}
}
Interface for an event poller callback.
Definition EventCallback.hh:29
Interface class for hypervisor events.
Definition Event.hh:43
virtual Domain & domain()=0
Get the Domain that the event is for.
virtual EventType type() const =0
Get the type of event.
Definition guest_ptr.hh:88
Definition WindowsEvent.hh:26
virtual WindowsEventTaskInformation & task()=0
Get the task information.
virtual THREAD & CurrentThread()=0
Get the currently active thread.
virtual uint64_t UniqueProcessId() const =0
virtual const PROCESS & Process() const =0
#define unlikely(x)
Definition compiler.hh:27
bool interrupted
Definition ivcallmon.cc:43
int main(int argc, char **argv)
Definition main.c:35
Code for handling ioctls to condrv.sys.
Definition ConsoleCallServerGenericRequestCode.hh:23
Definition CreationFlags.hh:20
Classes related to the Windows NT kernel.
Definition APPHELPCACHESERVICECLASS.hh:23
@ MemoryBasicInformation
Definition MEMORY_INFORMATION_CLASS.hh:30
@ MEM_MAPPED
Definition MEMORY_ALLOCATION_TYPE.hh:41
@ MEM_PRIVATE
Definition MEMORY_ALLOCATION_TYPE.hh:40
@ MEM_IMAGE
Definition MEMORY_ALLOCATION_TYPE.hh:45
@ PROCESS_VM_OPERATION
Required to perform an operation on the address space of a process.
Definition PROCESS_ACCESS_MASK.hh:39
@ PROCESS_VM_READ
Required to read memory in a process using ReadProcessMemory.
Definition PROCESS_ACCESS_MASK.hh:41
@ PROCESS_QUERY_INFORMATION
Definition PROCESS_ACCESS_MASK.hh:54
Classes related to Microsoft Windows guests.
Definition LanguageId.hh:21
Core IntroVirt classes.
Definition Cr0.hh:20
void sig_handler(int signum)
Definition vmcall_interface.cc:571
void parse_program_options(int argc, char **argv, po::options_description &desc, po::variables_map &vm)
Definition vmcall_interface.cc:581
unique_ptr< Domain > domain
Definition vmcall_interface.cc:48