Writes host file contents into a file in the guest. Uses injected NtCreateFile and NtWriteFile (or equivalent). Demonstrates system-call injection to write guest files from the host.
#include <boost/algorithm/string.hpp>
#include <boost/program_options.hpp>
#include <csignal>
#include <cstring>
#include <iostream>
#include <memory>
#include <string>
#include <string_view>
#include <sys/stat.h>
#include <sys/types.h>
using namespace std;
namespace po = boost::program_options;
po::variables_map& vm);
std::unique_ptr<Domain>
domain;
}
static std::string get_filename_from_path(std::string_view src) {
const size_t slashPos = src.rfind('/');
string fileName;
if (slashPos != string::npos) {
fileName = src.substr(slashPos + 1);
} else {
fileName = src;
}
return fileName;
}
public:
result_ = 1;
FILE* src_file = fopen(src_path_.c_str(), "r");
if (!src_file) {
std::cout << "Failed to open source file: " << strerror(errno) << '\n';
return;
}
struct stat src_stat;
if (fstat(fileno(src_file), &src_stat) != 0) {
std::cerr << "Failed to stat source file: " << strerror(errno) << '\n';
return;
}
retry:
auto dst_path = inject::allocate<nt::UNICODE_STRING>("\\??\\" + dst_path_);
auto object_attributes = inject::allocate<nt::OBJECT_ATTRIBUTES>();
auto io_status_block = inject::allocate<nt::IO_STATUS_BLOCK>();
object_attributes->ObjectNamePtr(dst_path);
object_attributes->Attributes(OBJECT_ATTRIBUTES::OBJ_CASE_INSENSITIVE);
uint64_t dst_file;
dst_file,
object_attributes,
io_status_block,
nullptr,
nullptr,
0
);
dst_path_ = dst_path_ + '\\' + get_filename_from_path(src_path_);
goto retry;
}
std::cout <<
"Failed to open destination file: " <<
result <<
'\n';
return;
}
size_t bytes_written = 0;
while (true) {
const int count = fread(buffer.ptr().get(), 1,
BUFFER_SIZE, src_file);
std::cout << "Failed to read from source file: " << strerror(errno) << '\n';
break;
}
if (count == 0) {
break;
}
result = inject::system_call<nt::NtWriteFile>(
dst_file, 0, nullptr, nullptr, io_status_block, buffer, count, nullptr, nullptr);
bytes_written += count;
if (progress_bar_)
progress.
draw((bytes_written * 100.0f) / src_stat.st_size);
continue;
}
std::cout <<
"Failed to write to destination file: " <<
result <<
'\n';
break;
}
result = inject::system_call<NtClose>(dst_file);
std::cout <<
"Failed to close destination file: " <<
result <<
'\n';
}
if (progress_bar_)
fclose(src_file);
}
event.
type() == EventType::EVENT_REBOOT)) {
exit(64);
}
if (event.
type() == EventType::EVENT_FAST_SYSCALL) {
if (copy_started_.test_and_set() == 0) {
event.domain().interrupt();
}
}
}
WriteFileTool(
const std::string& src_path,
const std::string& dst_path,
bool progress_bar)
: src_path_(src_path), dst_path_(dst_path), progress_bar_(progress_bar) {}
int result()
const {
return result_; }
private:
const std::string src_path_;
std::string dst_path_;
const bool progress_bar_;
int result_;
std::atomic_flag copy_started_ = false;
};
int main(
int argc,
char** argv) {
po::options_description desc("Options");
std::string domain_name;
std::string process_name;
std::string source_file;
std::string dest_file;
desc.add_options()
("domain,D", po::value<std::string>(&domain_name)->required(), "The domain name or ID attach to")
("source_file,s", po::value<std::string>(&source_file)->required(), "The path to the source file")
("dest_file,d", po::value<std::string>(&dest_file)->required(), "The destination file path to write in the guest")
("process_name,P", po::value<std::string>(&process_name)->default_value("explorer"), "The name of a process to hijack")
("progress", "Display a progress bar")
("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);
if (boost::ends_with(dest_file, "\\")) {
dest_file += get_filename_from_path(source_file);
}
WriteFileTool tool(source_file, dest_file, vm.count(
"progress"));
}
po::variables_map& vm) {
try {
po::store(po::parse_command_line(argc, argv, desc), vm);
if (vm.count("help")) {
std::cout << "ivwritefile - Write a file into 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 EventType type() const =0
Get the type of event.
Class for displaying a progress bar.
Definition ProgressBar.hh:27
void complete()
Set the progress bar to 100%.
void draw(float percentComplete)
Redraw the progress bar with the specified percent complete.
Definition FILE_SHARE_ACCESS.hh:31
Status codes returned by Windows NT system calls.
Definition NTSTATUS.hh:34
#define unlikely(x)
Definition compiler.hh:27
bool interrupted
Definition ivcallmon.cc:43
int main(int argc, char **argv)
Definition main.c:35
#define BUFFER_SIZE
Definition main.c:16
Classes related to the Windows NT kernel.
Definition APPHELPCACHESERVICECLASS.hh:23
@ STATUS_FILE_IS_A_DIRECTORY
Definition NTSTATUS_CODE.hh:398
@ GENERIC_WRITE
Generic write access.
Definition ACCESS_MASK.hh:77
@ SYNCHRONIZE
Definition ACCESS_MASK.hh:52
@ FILE_NON_DIRECTORY_FILE
Definition FileCreateOptions.hh:32
@ FILE_SYNCHRONOUS_IO_NONALERT
Definition FileCreateOptions.hh:31
@ FILE_ATTRIBUTE_NORMAL
Definition FILE_ATTRIBUTES.hh:35
@ FILE_SUPERSEDE
Definition CreateFileDisposition.hh:25
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