summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorauth12 <[email protected]>2021-07-04 01:15:09 +0100
committerauth12 <[email protected]>2021-07-04 01:15:09 +0100
commit661b73df47caae2cc62a9a2f7b85eb925ff1f80b (patch)
tree79ab09cc3b9877b52fe32186ba3c0c354d0120bd
downloadsysmap-661b73df47caae2cc62a9a2f7b85eb925ff1f80b.tar.xz
sysmap-661b73df47caae2cc62a9a2f7b85eb925ff1f80b.zip
initial commit
-rw-r--r--.gitignore45
-rw-r--r--.gitmodules9
m---------modules/linuxpe0
m---------modules/phnt0
m---------modules/spdlog0
-rw-r--r--sysmap.sln31
-rw-r--r--sysmap/src/context.h8
-rw-r--r--sysmap/src/include.h28
-rw-r--r--sysmap/src/io.h41
-rw-r--r--sysmap/src/main.cpp59
-rw-r--r--sysmap/src/mapper/apiset.h41
-rw-r--r--sysmap/src/mapper/pe.h118
-rw-r--r--sysmap/src/mapper/process.h458
-rw-r--r--sysmap/src/mapper/syscalls.h116
-rw-r--r--sysmap/src/mapper/util.h52
-rw-r--r--sysmap/sysmap.vcxproj163
-rw-r--r--sysmap/sysmap.vcxproj.filters48
-rw-r--r--sysmap/sysmap.vcxproj.user6
18 files changed, 1223 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3bb30db
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,45 @@
+#Auto generated files
+.vs/*
+sysmap/obj/*
+
+#Visual studio files
+*.tlog
+
+# Prerequisites
+*.d
+
+# Compiled Object files
+*.slo
+*.lo
+*.o
+*.obj
+*.ipch
+*.suo
+*.db
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Compiled Dynamic libraries
+*.so
+*.dylib
+*.dll
+
+# Fortran module files
+*.mod
+*.smod
+
+# Compiled Static libraries
+*.lai
+*.la
+*.a
+*.lib
+
+# Executables
+*.exe
+*.out
+*.app
+.DS_Store
+*.sqlite
+*.pdb
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..5f79fb2
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,9 @@
+[submodule "modules/spdlog"]
+ path = modules/spdlog
+ url = https://github.com/gabime/spdlog.git
+[submodule "modules/linuxpe"]
+ path = modules/linuxpe
+ url = https://github.com/can1357/linux-pe.git
+[submodule "modules/phnt"]
+ path = modules/phnt
+ url = https://github.com/processhacker/phnt.git
diff --git a/modules/linuxpe b/modules/linuxpe
new file mode 160000
+Subproject db2b7af6e6beae1bc391ff8f8e5c97b963dc325
diff --git a/modules/phnt b/modules/phnt
new file mode 160000
+Subproject 190fbb00f1d3f541441ee0bc6f220ee9eff5e64
diff --git a/modules/spdlog b/modules/spdlog
new file mode 160000
+Subproject 21413e599a8bae53bb8e49360849bfae32334a7
diff --git a/sysmap.sln b/sysmap.sln
new file mode 100644
index 0000000..e6074a1
--- /dev/null
+++ b/sysmap.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31402.337
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sysmap", "sysmap\sysmap.vcxproj", "{BF998D5B-57F5-42EB-B644-2B38EC4CC048}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {BF998D5B-57F5-42EB-B644-2B38EC4CC048}.Debug|x64.ActiveCfg = Debug|x64
+ {BF998D5B-57F5-42EB-B644-2B38EC4CC048}.Debug|x64.Build.0 = Debug|x64
+ {BF998D5B-57F5-42EB-B644-2B38EC4CC048}.Debug|x86.ActiveCfg = Debug|Win32
+ {BF998D5B-57F5-42EB-B644-2B38EC4CC048}.Debug|x86.Build.0 = Debug|Win32
+ {BF998D5B-57F5-42EB-B644-2B38EC4CC048}.Release|x64.ActiveCfg = Release|x64
+ {BF998D5B-57F5-42EB-B644-2B38EC4CC048}.Release|x64.Build.0 = Release|x64
+ {BF998D5B-57F5-42EB-B644-2B38EC4CC048}.Release|x86.ActiveCfg = Release|Win32
+ {BF998D5B-57F5-42EB-B644-2B38EC4CC048}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {699B3DD4-B2CD-4599-8072-353A0DFED075}
+ EndGlobalSection
+EndGlobal
diff --git a/sysmap/src/context.h b/sysmap/src/context.h
new file mode 100644
index 0000000..cb604eb
--- /dev/null
+++ b/sysmap/src/context.h
@@ -0,0 +1,8 @@
+#pragma once
+
+struct mapper_context_t {
+ std::vector<util::module_data_t> local_modules;
+ std::string win_path;
+};
+
+extern mapper_context_t g_ctx; \ No newline at end of file
diff --git a/sysmap/src/include.h b/sysmap/src/include.h
new file mode 100644
index 0000000..ebd4953
--- /dev/null
+++ b/sysmap/src/include.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include <algorithm>
+#include <array>
+#include <chrono>
+#include <cstring>
+#include <fstream>
+#include <functional>
+#include <iostream>
+#include <memory>
+#include <sstream>
+#include <string>
+#include <thread>
+#include <vector>
+#include <unordered_map>
+#include <map>
+#include <utility>
+#include <filesystem>
+
+#include <phnt_windows.h>
+#include <phnt.h>
+
+using namespace std::chrono_literals;
+
+using u8 = uint8_t;
+using u16 = uint16_t;
+using u32 = uint32_t;
+using u64 = uint64_t; \ No newline at end of file
diff --git a/sysmap/src/io.h b/sysmap/src/io.h
new file mode 100644
index 0000000..b498065
--- /dev/null
+++ b/sysmap/src/io.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#include <spdlog/fmt/fmt.h>
+#include <spdlog/spdlog.h>
+#include <spdlog/sinks/basic_file_sink.h>
+#include <spdlog/sinks/stdout_color_sinks.h>
+
+enum log_lvl {
+ trace = 0,
+ debug,
+ info,
+ warn,
+ error,
+ critical
+};
+
+namespace io {
+ template<log_lvl T, typename... Args>
+ void log(std::string_view msg, Args... params) {
+ spdlog::log(static_cast<spdlog::level::level_enum>(T), msg.data(), std::forward<Args>(params)...);
+ }
+
+ static std::vector<u8> read_file(std::string_view name) {
+ std::ifstream file(name.data(), std::ios::binary);
+ if (!file.good()) {
+ return {};
+ }
+
+ std::vector<u8> out;
+
+ file.seekg(0, std::ios::end);
+ std::streampos length = file.tellg();
+ file.seekg(0, std::ios::beg);
+
+ out.resize(length);
+
+ file.read((char*)out.data(), length);
+
+ return out;
+ }
+}; \ No newline at end of file
diff --git a/sysmap/src/main.cpp b/sysmap/src/main.cpp
new file mode 100644
index 0000000..871be35
--- /dev/null
+++ b/sysmap/src/main.cpp
@@ -0,0 +1,59 @@
+#include "include.h"
+#include "io.h"
+#include "mapper/util.h"
+#include "mapper/pe.h"
+
+#include "context.h"
+
+#include "mapper/syscalls.h"
+#include "mapper/apiset.h"
+
+#include "mapper/process.h"
+
+mapper_context_t g_ctx;
+syscalls_t g_syscalls;
+apiset_t g_apiset;
+
+
+int main(int argc, char* argv[]) {
+ std::vector<std::string> args;
+
+ for (int i = 1; i < argc; ++i) {
+ args.emplace_back(argv[i]);
+ }
+
+ if (args.size() < 2) {
+ io::log<critical>("Invalid arguments specified.");
+ return 0;
+ }
+
+ spdlog::set_pattern("[%^%l%$] %v");
+
+ for (auto& arg : args) {
+ if (arg == "--debug") {
+ spdlog::set_level(spdlog::level::debug);
+ }
+ }
+
+ g_ctx.local_modules = std::move(util::get_modules());
+
+ auto ntdll = g_ctx.local_modules[1];
+
+ g_ctx.win_path = ntdll.full_path.substr(0, ntdll.full_path.size() - ntdll.name.size());
+
+ g_syscalls.init();
+
+ process::process_x64_t proc;
+ if (NT_SUCCESS(proc.attach(args[0]))) {
+ io::log<info>("attached!");
+
+ proc.modules = proc.get_modules();
+
+ proc.map(io::read_file(args[1]));
+
+ proc.close(proc.handle);
+ }
+
+ std::cin.get();
+ return 0;
+} \ No newline at end of file
diff --git a/sysmap/src/mapper/apiset.h b/sysmap/src/mapper/apiset.h
new file mode 100644
index 0000000..2797f8f
--- /dev/null
+++ b/sysmap/src/mapper/apiset.h
@@ -0,0 +1,41 @@
+#pragma once
+
+struct apiset_t {
+ std::unordered_map<std::string, std::vector<std::string>> apiset_map;
+
+ apiset_t() {
+ auto map = util::get_teb()->ProcessEnvironmentBlock->ApiSetMap;
+ auto map_ptr = uintptr_t(map);
+
+ for (size_t i = 0; i < map->Count; i++) {
+ auto hash_entry = reinterpret_cast<API_SET_HASH_ENTRY*>(map_ptr + map->HashOffset + (i * sizeof(API_SET_HASH_ENTRY)));
+
+ auto namespace_entry = reinterpret_cast<API_SET_NAMESPACE_ENTRY*>(map_ptr + map->EntryOffset + (hash_entry->Index * sizeof(API_SET_NAMESPACE_ENTRY)));
+
+ std::wstring name(reinterpret_cast<wchar_t*>(map_ptr + namespace_entry->NameOffset), namespace_entry->NameLength / sizeof(wchar_t));
+
+ auto val_entry = reinterpret_cast<API_SET_VALUE_ENTRY*>(map_ptr + namespace_entry->ValueOffset);
+
+ for (size_t j = 0; j < namespace_entry->ValueCount; j++, val_entry++) {
+ std::wstring val(reinterpret_cast<wchar_t*>(map_ptr + val_entry->ValueOffset), val_entry->ValueLength / sizeof(wchar_t));
+ if (val.empty()) {
+ continue;
+ }
+
+ apiset_map[util::to_multibyte(name)].emplace_back(util::to_multibyte(val));
+ }
+ }
+ }
+
+ std::string resolve(std::string_view mod) {
+ for (auto& [api, host] : apiset_map) {
+ if (mod.find(api) != std::string::npos) {
+ return host.front().compare(mod.data()) != 0 ? host.front() : host.back();
+ }
+ }
+
+ return mod.data();
+ }
+};
+
+extern apiset_t g_apiset; \ No newline at end of file
diff --git a/sysmap/src/mapper/pe.h b/sysmap/src/mapper/pe.h
new file mode 100644
index 0000000..9841cb2
--- /dev/null
+++ b/sysmap/src/mapper/pe.h
@@ -0,0 +1,118 @@
+#pragma once
+
+#include <linuxpe>
+
+namespace pe {
+ struct export_data_t {
+ uintptr_t func_rva;
+ std::string f_mod;
+ std::string f_func;
+ };
+
+ struct image_t {
+ uintptr_t base;
+ std::unordered_map<std::string, export_data_t> exports;
+ std::vector<win::section_header_t> sections;
+
+ image_t() : base{ 0 } { }
+ image_t(uintptr_t b) : base{ b } {
+ auto image = reinterpret_cast<win::image_x64_t*>(b);
+
+ auto nt = image->get_nt_headers();
+
+ for (auto &sec : nt->sections()) {
+ sections.emplace_back(sec);
+ }
+
+ auto export_dir = b + nt->optional_header.data_directories.export_directory.rva;
+ auto export_size = nt->optional_header.data_directories.export_directory.size;
+
+ auto exp = reinterpret_cast<win::export_directory_t*>(export_dir);
+
+ if (exp->num_functions == 0) return;
+
+ auto names = reinterpret_cast<uint32_t*>(b + exp->rva_names);
+ auto funcs = reinterpret_cast<uint32_t*>(b + exp->rva_functions);
+ auto ords = reinterpret_cast<uint16_t*>(b + exp->rva_name_ordinals);
+
+ if (!names || !funcs || !ords) return;
+
+ for (size_t i{}; i < exp->num_names; i++) {
+ std::string name = reinterpret_cast<const char*>(b + names[i]);
+
+ export_data_t ret;
+
+ ret.func_rva = funcs[ords[i]];
+
+ uintptr_t proc_addr = b + funcs[ords[i]];
+ if (proc_addr > export_dir && proc_addr < export_dir + export_size) {
+ std::string forwarded_name = reinterpret_cast<char*>(proc_addr);
+
+ size_t delim = forwarded_name.find('.');
+ if (delim == std::string::npos) continue;
+
+ ret.f_mod = forwarded_name.substr(0, delim + 1);
+ ret.f_mod.append("dll");
+
+ std::transform(ret.f_mod.begin(), ret.f_mod.end(), ret.f_mod.begin(), ::tolower);
+
+ ret.f_func = forwarded_name.substr(delim + 1);
+ }
+
+
+ exports[name] = ret;
+ }
+ }
+ };
+
+ struct import_data_t {
+ std::string name;
+ uintptr_t rva;
+ };
+
+ struct raw_image_t {
+ win::nt_headers_x64_t* nt;
+
+ std::unordered_map<std::string, std::vector<import_data_t>> imports;
+ std::unordered_map<uintptr_t, std::vector<win::reloc_entry_t>> relocs;
+ std::vector<win::section_header_t> sections;
+
+ raw_image_t(std::vector<u8>& buffer) {
+ auto image = reinterpret_cast<win::image_x64_t*>(buffer.data());
+
+ nt = image->get_nt_headers();
+
+ for (auto& sec : nt->sections()) {
+ sections.emplace_back(sec);
+ }
+
+ auto import_rva = nt->optional_header.data_directories.import_directory.rva;
+
+ auto desc = image->rva_to_ptr<win::import_directory_t>(import_rva);
+
+ for (uint32_t i = 0; i < desc->rva_name; i = desc->rva_name, ++desc) {
+ std::string mod = image->rva_to_ptr<char>(desc->rva_name);
+
+ auto thunk = image->rva_to_ptr<win::image_thunk_data_x64_t>(desc->rva_original_first_thunk);
+
+ for (uint32_t index = 0; thunk->address; index += sizeof(u64), ++thunk) {
+ auto named_import = image->rva_to_ptr<win::image_named_import_t>(thunk->address);
+
+ if (!thunk->is_ordinal) {
+ std::transform(mod.begin(), mod.end(), mod.begin(), ::tolower);
+
+ imports[mod].emplace_back(import_data_t{ reinterpret_cast<const char*>(named_import->name), desc->rva_first_thunk + index });
+ }
+ }
+ }
+
+ auto reloc_dir = image->rva_to_ptr<win::reloc_directory_t>(nt->optional_header.data_directories.basereloc_directory.rva);
+
+ for (auto* block = &reloc_dir->first_block; block->base_rva; block = block->next()) {
+ for (auto& entry : *block) {
+ relocs[block->base_rva].emplace_back(entry);
+ }
+ }
+ }
+ };
+}; \ No newline at end of file
diff --git a/sysmap/src/mapper/process.h b/sysmap/src/mapper/process.h
new file mode 100644
index 0000000..77f7185
--- /dev/null
+++ b/sysmap/src/mapper/process.h
@@ -0,0 +1,458 @@
+#pragma once
+
+
+namespace process {
+ struct process_info_t {
+ std::string name;
+ u16 pid;
+ };
+
+ struct process_iterator {
+ void* buf = nullptr;
+
+ void* get_next() {
+ static ptrdiff_t offset = offsetof(SYSTEM_PROCESS_INFORMATION, NextEntryOffset);
+
+ auto next_entry = *reinterpret_cast<uint32_t*>(uintptr_t(buf) + offset);
+
+ if (next_entry == 0) {
+ return nullptr;
+ }
+
+ buf = reinterpret_cast<void*>(uintptr_t(buf) + next_entry);
+
+ return buf;
+ }
+ };
+
+ std::vector<process_info_t> get_processes() {
+ std::vector<uint8_t> buf;
+ std::vector<process_info_t> out;
+
+ static auto nt_query = g_syscalls.get<decltype(&NtQuerySystemInformation)>("NtQuerySystemInformation");
+
+ ULONG size;
+ while (nt_query(SystemProcessInformation, &buf[0], static_cast<ULONG>(buf.size()), &size) == STATUS_INFO_LENGTH_MISMATCH) {
+ buf.resize(size);
+ };
+
+ process_iterator iter{ buf.data() };
+
+ void* ptr = iter.buf;
+ while (ptr) {
+ auto pi = reinterpret_cast<SYSTEM_PROCESS_INFORMATION*>(ptr);
+
+ std::wstring s{ pi->ImageName.Buffer, pi->ImageName.Length / sizeof(wchar_t) };
+ if (s.empty()) {
+ ptr = iter.get_next();
+
+ continue;
+ }
+
+ out.emplace_back(process_info_t{ util::to_multibyte(s), reinterpret_cast<u16>(pi->UniqueProcessId) });
+
+ ptr = iter.get_next();
+ }
+
+ return out;
+ }
+
+ struct process_x64_t {
+ process_info_t info;
+ HANDLE handle;
+
+ std::vector<util::module_data_t> modules;
+
+ NTSTATUS open_handle() {
+ static auto nt_open = g_syscalls.get<decltype(&NtOpenProcess)>("NtOpenProcess");
+ CLIENT_ID cid = { HANDLE(info.pid), 0 };
+ OBJECT_ATTRIBUTES oa;
+ oa.Length = sizeof(oa);
+ oa.Attributes = 0;
+ oa.RootDirectory = 0;
+ oa.SecurityDescriptor = 0;
+ oa.ObjectName = 0;
+ oa.SecurityQualityOfService = 0;
+
+ auto ret = nt_open(&handle, PROCESS_ALL_ACCESS, &oa, &cid);
+
+ io::log<debug>("NtOpenProcess on {}, returned {:x}.", info.pid, ret & 0xFFFFFFFF);
+
+ return ret;
+ }
+
+ NTSTATUS attach(std::string_view process_name) {
+ auto processes = get_processes();
+ auto it = std::find_if(processes.begin(), processes.end(), [&](process_info_t& info) {
+ return process_name.compare(info.name) == 0;
+ });
+
+ while (it == processes.end()) {
+ std::this_thread::sleep_for(3s);
+
+ processes = get_processes();
+
+ it = std::find_if(processes.begin(), processes.end(), [&](process_info_t& info) {
+ return process_name.compare(info.name) == 0;
+ });
+ }
+
+ info = *it;
+
+ return open_handle();
+ }
+
+ NTSTATUS read(uintptr_t addr, void* buf, size_t size) {
+ static auto nt_read = g_syscalls.get<decltype(&NtReadVirtualMemory)>("NtReadVirtualMemory");
+
+ auto ret = nt_read(handle, reinterpret_cast<void*>(addr), buf, size, nullptr);
+
+ //io::log<debug>("NtReadVirtualMemory at {:x}, buf {:x}, size {:x}, returned {:x}.", addr, uintptr_t(buf), size, ret & 0xFFFFFFFF);
+
+ return ret;
+ }
+
+ NTSTATUS write(uintptr_t addr, void* buf, size_t size) {
+ static auto nt_write = g_syscalls.get<decltype(&NtWriteVirtualMemory)>("NtWriteVirtualMemory");
+
+ auto ret = nt_write(handle, reinterpret_cast<void*>(addr), buf, size, nullptr);
+ io::log<debug>("NtWriteVirtualMemory at {:x}, buf {:x}, size {:x}, returned {:x}.", addr, uintptr_t(buf), size, ret & 0xFFFFFFFF);
+
+ return ret;
+ }
+
+ NTSTATUS protect(uintptr_t addr, size_t size, uint32_t new_protection, uint32_t* old_protection) {
+ static auto nt_protect = g_syscalls.get<decltype(&NtProtectVirtualMemory)>("NtProtectVirtualMemory");
+
+ void* addr_cast = reinterpret_cast<void*>(addr);
+ auto ret = nt_protect(handle, &addr_cast, &size, new_protection, (PULONG)old_protection);
+
+ io::log<debug>("NtProtectVirtualMemory at {:x}, size {:x}, new_protection {:x}, old_protection {:x}, returned {:x}.", addr, size, new_protection, *old_protection, ret & 0xFFFFFFFF);
+
+ return ret;
+ }
+
+ NTSTATUS query_info(PROCESSINFOCLASS inf, void* dat, size_t size) {
+ static auto nt_info = g_syscalls.get<decltype(&NtQueryInformationProcess)>("NtQueryInformationProcess");
+
+ auto ret = nt_info(handle, inf, dat, static_cast<ULONG>(size), nullptr);
+
+ io::log<debug>("NtQueryInformationProcess with {:x}, dat {:x}, size {:x}, returned {:x}.", (int)inf, uintptr_t(dat), size, ret & 0xFFFFFFFF);
+
+ return ret;
+ }
+
+ NTSTATUS alloc(uintptr_t* out, size_t size, uint32_t type, uint32_t protection) {
+ static auto nt_alloc = g_syscalls.get<decltype(&NtAllocateVirtualMemory)>("NtAllocateVirtualMemory");
+
+ void* base = nullptr;
+ auto ret = nt_alloc(handle, &base, 0, &size, type, protection);
+ *out = uintptr_t(base);
+
+ io::log<debug>("NtAllocateVirtualMemory allocated at {:x}, size {:x}, type {:x}, protection {:x}, returned {:x}.", *out, size, type, protection, ret & 0xFFFFFFFF);
+
+ return ret;
+ }
+
+ NTSTATUS close(HANDLE handle) {
+ static auto nt_close = g_syscalls.get<decltype(&NtClose)>("NtClose");
+
+ auto ret = nt_close(handle);
+ io::log<debug>("NtClose on {:x}, returned {:x}.", uintptr_t(handle), ret & 0xFFFFFFFF);
+
+ return ret;
+ }
+
+ NTSTATUS get_peb(uintptr_t* out) {
+ PROCESS_BASIC_INFORMATION info;
+ auto status = query_info(ProcessBasicInformation, &info, sizeof(info));
+
+ *out = uintptr_t(info.PebBaseAddress);
+
+ return status;
+ }
+
+ std::vector<util::module_data_t> get_modules() {
+ uintptr_t peb_ptr{ 0 };
+ get_peb(&peb_ptr);
+
+ PEB peb;
+ read(peb_ptr, &peb, sizeof(peb));
+
+ uintptr_t head = uintptr_t(peb.Ldr) + offsetof(PEB_LDR_DATA, InLoadOrderModuleList);
+
+ LIST_ENTRY64 entry;
+ read(head, &entry, sizeof(entry));
+
+ LDR_DATA_TABLE_ENTRY ldr_entry;
+ std::vector<util::module_data_t> ret;
+
+ for (auto i = entry.Flink; i != head;) {
+ read(i, &ldr_entry, sizeof(ldr_entry));
+
+ i = uintptr_t(ldr_entry.InLoadOrderLinks.Flink);
+
+ std::wstring ws;
+ ws.resize(ldr_entry.BaseDllName.Length);
+
+ read(uintptr_t(ldr_entry.BaseDllName.Buffer), &ws[0], ws.size());
+
+ auto name = util::to_multibyte(ws);
+
+ std::transform(name.begin(), name.end(), name.begin(), ::tolower);
+
+ ret.emplace_back(util::module_data_t{ name, uintptr_t(ldr_entry.DllBase), ldr_entry.SizeOfImage });
+ }
+
+ return ret;
+ }
+
+ uintptr_t get_module_export(util::module_data_t* module_info, std::string_view func) {
+ std::vector<u8> mapped_module(module_info->size);
+
+ auto status = read(module_info->base, mapped_module.data(), mapped_module.size());
+ if (!NT_SUCCESS(status)) {
+ return {};
+ }
+
+ pe::image_t img(uintptr_t(mapped_module.data()));
+
+ return img.exports[func.data()].func_rva;
+ }
+
+ auto get_module_exports(util::module_data_t* module_info) -> std::unordered_map<std::string, pe::export_data_t> {
+ if (!module_info->base) {
+ return {};
+ }
+
+ std::vector<u8> mapped_module(module_info->size);
+
+ auto status = read(module_info->base, mapped_module.data(), mapped_module.size());
+ if (!NT_SUCCESS(status)) {
+ return {};
+ }
+
+ pe::image_t img(uintptr_t(mapped_module.data()));
+
+ return img.exports;
+ }
+
+ util::module_data_t map_module(std::string_view name) {
+ auto resolved_name = g_apiset.resolve(name);
+ auto it = std::find_if(modules.begin(), modules.end(), [&](util::module_data_t& data) {
+ return data.name == resolved_name;
+ });
+
+ if (it != modules.end()) {
+ return *it;
+ }
+
+ auto file = io::read_file(g_ctx.win_path.append(resolved_name));
+ if (file.empty()) {
+ io::log<critical>("failed to read {}", resolved_name);
+ return {};
+ }
+
+ pe::raw_image_t image(file);
+ auto nt = image.nt;
+
+ std::vector<u8> mapped_image(nt->optional_header.size_image);
+
+ std::memcpy(&mapped_image[0], &file[0], nt->optional_header.size_headers);
+ for (auto& sec : image.sections) {
+ std::memcpy(&mapped_image[sec.virtual_address], &file[sec.ptr_raw_data], sec.size_raw_data);
+ }
+
+ uintptr_t allocation_base{ 0 };
+ auto status = alloc(&allocation_base, mapped_image.size(), MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+
+ if (!NT_SUCCESS(status)) {
+ io::log<critical>("failed to allocate memory for {}", resolved_name);
+ return {};
+ }
+
+ io::log<log_lvl::info>("mapping {} to {:x}", resolved_name, allocation_base);
+
+ io::log<log_lvl::info>("fixing {} relocations...", resolved_name);
+
+ auto delta = allocation_base - nt->optional_header.image_base;
+ if (delta > 0) {
+ for (auto& [block_rva, entries] : image.relocs) {
+ for (auto& e : entries) {
+ if (e.type == win::rel_based_high_low || e.type == win::rel_based_dir64) {
+ *reinterpret_cast<u64*>(&mapped_image[block_rva + e.offset]) += delta;
+ }
+ }
+ }
+ }
+
+ io::log<log_lvl::info>("resolving {} imports...", resolved_name);
+ for (auto& [mod, funcs] : image.imports) {
+ auto mod_data = map_module(mod);
+ auto exports = get_module_exports(&mod_data);
+
+ for (auto& f : funcs) {
+ auto exp_data = exports[f.name];
+
+ uintptr_t proc_addr{ 0 };
+ if (!exp_data.f_mod.empty()) {
+ auto f_mod_data = map_module(exp_data.f_mod);
+
+ proc_addr = f_mod_data.base + get_module_export(&f_mod_data, exp_data.f_func);
+
+ io::log<debug>("{}!{}->{}!{}->{:x}", mod, f.name, exp_data.f_mod, exp_data.f_func, proc_addr);
+
+ *reinterpret_cast<u64*>(&mapped_image[f.rva]) = proc_addr;
+
+ continue;
+ }
+
+ proc_addr = mod_data.base + exports[f.name].func_rva;
+
+ io::log<debug>("{}!{}->{:x}", mod, f.name, proc_addr);
+
+ *reinterpret_cast<u64*>(&mapped_image[f.rva]) = proc_addr;
+ }
+ }
+
+
+ io::log<log_lvl::info>("writing {} image...", resolved_name);
+ status = write(allocation_base, mapped_image.data(), mapped_image.size());
+ if (!NT_SUCCESS(status)) {
+ io::log<critical>("failed to write mapped image for {}", resolved_name);
+ return {};
+ }
+
+ io::log<log_lvl::info>("fixing {} section permissions...", resolved_name);
+ for (auto& sec : image.sections) {
+ uintptr_t addr = allocation_base + sec.virtual_address;
+ uint32_t prot;
+ if (sec.characteristics.mem_execute) {
+ prot = PAGE_EXECUTE;
+
+ if (sec.characteristics.mem_read) {
+ prot = PAGE_EXECUTE_READ;
+ }
+
+ if (sec.characteristics.mem_write) {
+ prot = PAGE_EXECUTE_READWRITE;
+ }
+ }
+ else {
+ prot = PAGE_NOACCESS;
+ if (sec.characteristics.mem_read) {
+ prot = PAGE_READONLY;
+ }
+
+ if (sec.characteristics.mem_write) {
+ prot = PAGE_READWRITE;
+ }
+ }
+
+ uint32_t old_protection;
+ status = protect(addr, sec.size_raw_data, prot, &old_protection);
+ if (!NT_SUCCESS(status)) {
+ io::log<critical>("failed to set section permissions on {} for {}", sec.name.to_string(), resolved_name);
+ continue;
+ }
+ }
+
+ io::log<log_lvl::info>("successfully mapped {}", resolved_name);
+
+ return util::module_data_t{ resolved_name, allocation_base, mapped_image.size() };
+ }
+
+ util::module_data_t map(std::vector<u8> file) {
+ pe::raw_image_t image(file);
+ auto nt = image.nt;
+
+ std::vector<u8> mapped_image(nt->optional_header.size_image);
+
+ for (auto& sec : image.sections) {
+ std::memcpy(&mapped_image[sec.virtual_address], &file[sec.ptr_raw_data], sec.size_raw_data);
+ }
+
+ uintptr_t allocation_base{ 0 };
+ auto status = alloc(&allocation_base, mapped_image.size(), MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+
+ if (!NT_SUCCESS(status)) {
+ io::log<critical>("failed to allocate memory for target image");
+ return {};
+ }
+
+ io::log<log_lvl::info>("mapping target image to {:x}", allocation_base);
+
+ const u16 headers_size = 4096;
+
+ io::log<log_lvl::info>("fixing target image relocations...");
+
+ auto delta = allocation_base - nt->optional_header.image_base;
+ if (delta > 0) {
+ for (auto& [block_rva, entries] : image.relocs) {
+ for (auto& e : entries) {
+ if (e.type == win::rel_based_high_low || e.type == win::rel_based_dir64) {
+ *reinterpret_cast<u64*>(&mapped_image[block_rva + e.offset]) += delta - headers_size;
+ }
+ }
+ }
+ }
+
+ io::log<log_lvl::info>("resolving target image imports...");
+ for (auto& [mod, funcs] : image.imports) {
+ auto mod_data = map_module(mod);
+ auto exports = get_module_exports(&mod_data);
+
+ for (auto& f : funcs) {
+ auto exp_data = exports[f.name];
+
+ uintptr_t proc_addr{ 0 };
+ if (!exp_data.f_mod.empty()) {
+ auto f_mod_data = map_module(exp_data.f_mod);
+
+ proc_addr = f_mod_data.base + get_module_export(&f_mod_data, exp_data.f_func);
+
+ io::log<debug>("{}!{}->{}!{}->{:x}", mod, f.name, exp_data.f_mod, exp_data.f_func, proc_addr);
+
+ *reinterpret_cast<u64*>(&mapped_image[f.rva]) = proc_addr;
+
+ continue;
+ }
+
+ proc_addr = mod_data.base + exports[f.name].func_rva;
+
+ io::log<debug>("{}!{}->{:x}", mod, f.name, proc_addr);
+
+ *reinterpret_cast<u64*>(&mapped_image[f.rva]) = proc_addr;
+ }
+ }
+
+
+ io::log<log_lvl::info>("writing target image...");
+ status = write(allocation_base, mapped_image.data() + headers_size, mapped_image.size() - headers_size);
+ if (!NT_SUCCESS(status)) {
+ io::log<critical>("failed to write mapped image");
+ return {};
+ }
+
+ static std::vector<u8> shellcode = { 0x48, 0x83, 0xEC, 0x28, 0x48, 0xB9, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x48, 0xC7, 0xC2,0x01, 0x00, 0x00, 0x00, 0x4D, 0x31, 0xC0,
+ 0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xD0, 0x48, 0x83, 0xC4, 0x28, 0xC3 };
+
+ *reinterpret_cast<u64*>(&shellcode[6]) = allocation_base;
+ *reinterpret_cast<u64*>(&shellcode[26]) = allocation_base + nt->optional_header.entry_point - headers_size;
+
+ uintptr_t shellcode_base;
+ alloc(&shellcode_base, shellcode.size(), MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+
+ io::log<log_lvl::info>("writing shellcode at {:x}...", shellcode_base);
+
+ write(shellcode_base, shellcode.data(), shellcode.size());
+
+ CreateRemoteThread(handle, 0, 0, (LPTHREAD_START_ROUTINE)shellcode_base, 0, 0, 0);
+
+ io::log<log_lvl::info>("mapped target image");
+
+ return util::module_data_t{ "", allocation_base, mapped_image.size() };
+ }
+ };
+} \ No newline at end of file
diff --git a/sysmap/src/mapper/syscalls.h b/sysmap/src/mapper/syscalls.h
new file mode 100644
index 0000000..d7b917d
--- /dev/null
+++ b/sysmap/src/mapper/syscalls.h
@@ -0,0 +1,116 @@
+#pragma once
+
+struct syscalls_t {
+ void* call_table;
+ std::vector<uint8_t> stub;
+
+ std::unordered_map<std::string, u16> syscalls;
+
+ syscalls_t() : call_table{nullptr} {}
+
+ void init() {
+ auto ntdll_base = g_ctx.local_modules[1].base;
+ auto ntdll = pe::image_t(ntdll_base);
+
+ u32 max_index = 0;
+ for (auto& [name, exp_data] : ntdll.exports) {
+ auto fn = reinterpret_cast<uint8_t*>(ntdll_base + exp_data.func_rva);
+ auto size = get_size(fn);
+
+ if (!is_valid(fn, size)) {
+ continue;
+ }
+
+ if (stub.empty()) {
+ for (size_t i = 0; i < size; i++) {
+ if (fn[i] == x64::test_imm8) { // skip <test byte ptr ds:[7FFE0308],1> and <jne ntdll.7FFF70550395>
+ i += 9;
+ continue;
+ }
+
+ stub.emplace_back(fn[i]);
+ }
+ }
+
+ u32 idx = get_idx(fn, size);
+
+ if (idx > max_index)
+ max_index = idx;
+
+ syscalls[name] = idx;
+ }
+
+ size_t table_size = stub.size() * (max_index + 1);
+
+ call_table = VirtualAlloc(0, table_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
+
+ if (!call_table) {
+ io::log<critical>("failed to allocated syscall call table.");
+ return;
+ }
+
+ io::log<debug>("syscall call table allocated at {:x}.", uintptr_t(call_table));
+
+ std::memset(call_table, x64::nop, table_size);
+
+ for (auto& [hash, index] : syscalls) {
+ uintptr_t func_dest = uintptr_t(call_table) + (index * stub.size());
+ std::memcpy(reinterpret_cast<void*>(func_dest), stub.data(), stub.size());
+
+ *reinterpret_cast<u32*>(func_dest + 4) = index;
+ }
+
+ DWORD old;
+ VirtualProtect(call_table, table_size, PAGE_EXECUTE, &old);
+ }
+
+ template< typename T = void* >
+ __forceinline T get(std::string_view fn) {
+ return reinterpret_cast<T>(uintptr_t(call_table) + (syscalls[fn.data()] * stub.size()));
+ }
+
+
+ uint16_t get_idx(u8 *fn, size_t size) {
+ for (size_t i = 0; i < size; i++) {
+ auto op = fn[i];
+ if (op == x64::mov_imm16) {
+ return *reinterpret_cast<u32*>(&fn[i + 1]);
+ }
+ }
+
+ return 0;
+ }
+
+ size_t get_size(const u8* func) {
+ for (size_t i = 0; i < 64; i++) {
+ auto op = func[i];
+ if (op == x64::retn) {
+ return i + 1;
+ }
+ }
+
+ return 0;
+ }
+
+ bool is_valid(u8* func, size_t size) {
+ // mov r10, rcx
+ u32 a = func[0] + func[1] + func[2];
+ if (a != 0x1a8) {
+ return false;
+ }
+
+ for (size_t i = 0; i < size; i++) {
+ auto cur = func[i];
+ auto next = func[i + 1];
+
+ // syscall
+ if (cur == 0x0f && next == 0x05) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+};
+
+extern syscalls_t g_syscalls; \ No newline at end of file
diff --git a/sysmap/src/mapper/util.h b/sysmap/src/mapper/util.h
new file mode 100644
index 0000000..f50192b
--- /dev/null
+++ b/sysmap/src/mapper/util.h
@@ -0,0 +1,52 @@
+#pragma once
+
+namespace util {
+ struct module_data_t {
+ std::string name;
+ uintptr_t base;
+ size_t size;
+ std::string full_path;
+ };
+
+ std::string to_multibyte(std::wstring_view str) {
+ return std::filesystem::path(str.data()).string();
+ }
+
+ std::wstring to_wide(std::string_view str) {
+ return std::filesystem::path(str.data()).wstring();
+ }
+
+ TEB* get_teb() {
+ return reinterpret_cast<TEB*>(__readgsqword(0x30));
+ }
+
+ std::vector<module_data_t> get_modules() {
+ std::vector<module_data_t> ret{};
+
+ auto* list = &get_teb()->ProcessEnvironmentBlock->Ldr->InMemoryOrderModuleList;
+
+ for (auto i = list->Flink; i != list; i = i->Flink) {
+ auto entry = CONTAINING_RECORD(i, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
+ if (!entry)
+ continue;
+
+ auto name = util::to_multibyte(entry->BaseDllName.Buffer);
+ std::transform(name.begin(), name.end(), name.begin(), tolower);
+
+ auto full_path = util::to_multibyte(entry->FullDllName.Buffer);
+
+ ret.emplace_back(module_data_t{name, uintptr_t(entry->DllBase), entry->SizeOfImage, full_path});
+ }
+
+ return ret;
+ }
+};
+
+namespace x64 {
+ enum inst : uint8_t {
+ retn = 0xC3,
+ mov_imm16 = 0xB8,
+ nop = 0x90,
+ test_imm8 = 0xF6
+ };
+}; \ No newline at end of file
diff --git a/sysmap/sysmap.vcxproj b/sysmap/sysmap.vcxproj
new file mode 100644
index 0000000..a42f5d0
--- /dev/null
+++ b/sysmap/sysmap.vcxproj
@@ -0,0 +1,163 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <VCProjectVersion>16.0</VCProjectVersion>
+ <Keyword>Win32Proj</Keyword>
+ <ProjectGuid>{bf998d5b-57f5-42eb-b644-2b38ec4cc048}</ProjectGuid>
+ <RootNamespace>sysmap</RootNamespace>
+ <WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v142</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v142</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="Shared">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(SolutionDir)bin\$(Platform)\$(Configuration)\</OutDir>
+ <IntDir>obj\$(Platform)\$(Configuration)\</IntDir>
+ <IncludePath>$(SolutionDir)modules\phnt\;$(SolutionDir)modules\linuxpe\includes\;$(SolutionDir)modules\spdlog\include\;$(IncludePath)</IncludePath>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ <LanguageStandard>stdcpplatest</LanguageStandard>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <UACExecutionLevel>RequireAdministrator</UACExecutionLevel>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="src\main.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="src\context.h" />
+ <ClInclude Include="src\io.h" />
+ <ClInclude Include="src\mapper\apiset.h" />
+ <ClInclude Include="src\mapper\pe.h" />
+ <ClInclude Include="src\mapper\process.h" />
+ <ClInclude Include="src\mapper\syscalls.h" />
+ <ClInclude Include="src\include.h" />
+ <ClInclude Include="src\mapper\util.h" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/sysmap/sysmap.vcxproj.filters b/sysmap/sysmap.vcxproj.filters
new file mode 100644
index 0000000..0d19da0
--- /dev/null
+++ b/sysmap/sysmap.vcxproj.filters
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="src\main.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="src\include.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\mapper\util.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\mapper\syscalls.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\mapper\pe.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\io.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\context.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\mapper\process.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\mapper\apiset.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/sysmap/sysmap.vcxproj.user b/sysmap/sysmap.vcxproj.user
new file mode 100644
index 0000000..966b4ff
--- /dev/null
+++ b/sysmap/sysmap.vcxproj.user
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <ShowAllFiles>true</ShowAllFiles>
+ </PropertyGroup>
+</Project> \ No newline at end of file