mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-11 16:46:16 +00:00
26
.clang-format
Normal file
26
.clang-format
Normal file
@@ -0,0 +1,26 @@
|
||||
# Format Style Options - Created with Clang Power Tools
|
||||
---
|
||||
BasedOnStyle: Microsoft
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
DerivePointerAlignment: false
|
||||
FixNamespaceComments: false
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
Language: Cpp
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: All
|
||||
PointerAlignment: Left
|
||||
SortIncludes: false
|
||||
AlignEscapedNewlines: Left
|
||||
PackConstructorInitializers: Never
|
||||
IndentPPDirectives: None
|
||||
AlignConsecutiveMacros:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: true
|
||||
AcrossComments: true
|
||||
AlignCompound: true
|
||||
PadOperators: true
|
||||
BraceWrapping:
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
...
|
||||
13
.github/workflows/build.yml
vendored
13
.github/workflows/build.yml
vendored
@@ -15,6 +15,19 @@ on:
|
||||
# cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
verify-formatting:
|
||||
name: Verify Formatting
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout Source
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Verify Formatting
|
||||
uses: jidicula/clang-format-action@v4.14.0
|
||||
with:
|
||||
clang-format-version: '19'
|
||||
check-path: 'src'
|
||||
|
||||
dump-registry:
|
||||
name: Dump Registry
|
||||
runs-on: windows-latest
|
||||
|
||||
@@ -25,17 +25,14 @@ namespace
|
||||
|
||||
auto* params_hook = watch_object(win_emu, win_emu.process().process_params, cache_logging);
|
||||
|
||||
win_emu.emu().hook_memory_write(win_emu.process().peb.value() + offsetof(PEB64, ProcessParameters), 0x8,
|
||||
[&, cache_logging](const uint64_t address, size_t, const uint64_t value)
|
||||
{
|
||||
const auto target_address = win_emu.process().peb.value() + offsetof(
|
||||
PEB64, ProcessParameters);
|
||||
win_emu.emu().hook_memory_write(
|
||||
win_emu.process().peb.value() + offsetof(PEB64, ProcessParameters), 0x8,
|
||||
[&, cache_logging](const uint64_t address, size_t, const uint64_t value) {
|
||||
const auto target_address = win_emu.process().peb.value() + offsetof(PEB64, ProcessParameters);
|
||||
|
||||
if (address == target_address)
|
||||
{
|
||||
const emulator_object<RTL_USER_PROCESS_PARAMETERS64> obj{
|
||||
win_emu.emu(), value
|
||||
};
|
||||
const emulator_object<RTL_USER_PROCESS_PARAMETERS64> obj{win_emu.emu(), value};
|
||||
|
||||
win_emu.emu().delete_hook(params_hook);
|
||||
params_hook = watch_object(win_emu, obj, cache_logging);
|
||||
@@ -117,7 +114,7 @@ namespace
|
||||
(void)&watch_system_objects;
|
||||
watch_system_objects(win_emu, options.concise_logging);
|
||||
win_emu.buffer_stdout = true;
|
||||
//win_emu.verbose_calls = true;
|
||||
// win_emu.verbose_calls = true;
|
||||
|
||||
const auto& exe = *win_emu.process().executable;
|
||||
|
||||
@@ -130,8 +127,7 @@ namespace
|
||||
continue;
|
||||
}
|
||||
|
||||
auto read_handler = [&, section, concise_logging](const uint64_t address, size_t, uint64_t)
|
||||
{
|
||||
auto read_handler = [&, section, concise_logging](const uint64_t address, size_t, uint64_t) {
|
||||
const auto rip = win_emu.emu().read_instruction_pointer();
|
||||
if (win_emu.process().mod_manager.find_by_address(rip) != win_emu.process().executable)
|
||||
{
|
||||
@@ -142,17 +138,16 @@ namespace
|
||||
{
|
||||
static uint64_t count{0};
|
||||
++count;
|
||||
if (count > 100 && count % 10000 != 0) return;
|
||||
if (count > 100 && count % 10000 != 0)
|
||||
return;
|
||||
}
|
||||
|
||||
win_emu.log.print(
|
||||
color::green,
|
||||
win_emu.log.print(color::green,
|
||||
"Reading from executable section %s at 0x%" PRIx64 " via 0x%" PRIx64 "\n",
|
||||
section.name.c_str(), address, rip);
|
||||
};
|
||||
|
||||
const auto write_handler = [&, section, concise_logging](const uint64_t address, size_t, uint64_t)
|
||||
{
|
||||
const auto write_handler = [&, section, concise_logging](const uint64_t address, size_t, uint64_t) {
|
||||
const auto rip = win_emu.emu().read_instruction_pointer();
|
||||
if (win_emu.process().mod_manager.find_by_address(rip) != win_emu.process().executable)
|
||||
{
|
||||
@@ -163,12 +158,11 @@ namespace
|
||||
{
|
||||
static uint64_t count{0};
|
||||
++count;
|
||||
if (count > 100 && count % 10000 != 0) return;
|
||||
if (count > 100 && count % 10000 != 0)
|
||||
return;
|
||||
}
|
||||
|
||||
win_emu.log.print(
|
||||
color::blue,
|
||||
"Writing to executable section %s at 0x%" PRIx64 " via 0x%" PRIx64 "\n",
|
||||
win_emu.log.print(color::blue, "Writing to executable section %s at 0x%" PRIx64 " via 0x%" PRIx64 "\n",
|
||||
section.name.c_str(), address, rip);
|
||||
};
|
||||
|
||||
@@ -235,8 +229,7 @@ int main(const int argc, char** argv)
|
||||
do
|
||||
{
|
||||
run(options, args);
|
||||
}
|
||||
while (options.use_gdb);
|
||||
} while (options.use_gdb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -7,10 +7,9 @@ emulator_hook* watch_object(windows_emulator& emu, emulator_object<T> object, co
|
||||
{
|
||||
const reflect_type_info<T> info{};
|
||||
|
||||
return emu.emu().hook_memory_read(object.value(), object.size(),
|
||||
[i = std::move(info), object, &emu, cache_logging](
|
||||
const uint64_t address, size_t, uint64_t)
|
||||
{
|
||||
return emu.emu().hook_memory_read(
|
||||
object.value(), object.size(),
|
||||
[i = std::move(info), object, &emu, cache_logging](const uint64_t address, size_t, uint64_t) {
|
||||
const auto rip = emu.emu().read_instruction_pointer();
|
||||
const auto* mod = emu.process().mod_manager.find_by_address(rip);
|
||||
const auto is_main_access = mod == emu.process().executable;
|
||||
@@ -31,10 +30,7 @@ emulator_hook* watch_object(windows_emulator& emu, emulator_object<T> object, co
|
||||
|
||||
const auto offset = address - object.value();
|
||||
emu.log.print(is_main_access ? color::green : color::dark_gray,
|
||||
"Object access: %s - 0x%llX (%s) at 0x%llX (%s)\n",
|
||||
i.get_type_name().c_str(),
|
||||
offset,
|
||||
i.get_member_name(offset).c_str(), rip,
|
||||
mod ? mod->name.c_str() : "<N/A>");
|
||||
"Object access: %s - 0x%llX (%s) at 0x%llX (%s)\n", i.get_type_name().c_str(), offset,
|
||||
i.get_member_name(offset).c_str(), rip, mod ? mod->name.c_str() : "<N/A>");
|
||||
});
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,13 +15,12 @@
|
||||
template <typename T>
|
||||
class reflect_type_info
|
||||
{
|
||||
public:
|
||||
public:
|
||||
reflect_type_info()
|
||||
{
|
||||
this->type_name_ = reflect::type_name<T>();
|
||||
|
||||
reflect::for_each<T>([this](auto I)
|
||||
{
|
||||
reflect::for_each<T>([this](auto I) {
|
||||
const auto member_name = reflect::member_name<I, T>();
|
||||
const auto member_offset = reflect::offset_of<I, T>();
|
||||
|
||||
@@ -59,7 +58,7 @@ public:
|
||||
return this->type_name_;
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
std::string type_name_{};
|
||||
std::map<size_t, std::string> members_{};
|
||||
};
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
|
||||
#define THE_SIZE 30
|
||||
|
||||
extern "C" NO_INLINE EXPORT_SYMBOL
|
||||
void vulnerable(const uint8_t* data, const size_t size)
|
||||
extern "C" NO_INLINE EXPORT_SYMBOL void vulnerable(const uint8_t* data, const size_t size)
|
||||
{
|
||||
if (size < 10)
|
||||
{
|
||||
@@ -48,7 +47,6 @@ void vulnerable(const uint8_t* data, const size_t size)
|
||||
|
||||
uint8_t buffer[THE_SIZE] = {};
|
||||
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
const void* input = buffer;
|
||||
|
||||
@@ -13,7 +13,6 @@ namespace network
|
||||
#ifdef _WIN32
|
||||
static struct wsa_initializer
|
||||
{
|
||||
public:
|
||||
wsa_initializer()
|
||||
{
|
||||
WSADATA wsa_data;
|
||||
@@ -197,16 +196,13 @@ namespace network
|
||||
}
|
||||
|
||||
// 192.168.X.X
|
||||
if (bytes[0] == 192
|
||||
&& bytes[1] == 168)
|
||||
if (bytes[0] == 192 && bytes[1] == 168)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// 172.16.X.X - 172.31.X.X
|
||||
if (bytes[0] == 172
|
||||
&& bytes[1] >= 16
|
||||
&& bytes[1] < 32)
|
||||
if (bytes[0] == 172 && bytes[1] >= 16 && bytes[1] < 32)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -313,10 +309,7 @@ namespace network
|
||||
void address::resolve(const std::string& hostname, const std::optional<int>& family)
|
||||
{
|
||||
const auto port = this->get_port();
|
||||
auto port_reset_action = utils::finally([this, port]()
|
||||
{
|
||||
this->set_port(port);
|
||||
});
|
||||
auto port_reset_action = utils::finally([this, port]() { this->set_port(port); });
|
||||
|
||||
const auto result = resolve_multiple(hostname);
|
||||
for (const auto& addr : result)
|
||||
@@ -339,10 +332,7 @@ namespace network
|
||||
addrinfo* result = nullptr;
|
||||
if (!getaddrinfo(hostname.data(), nullptr, nullptr, &result))
|
||||
{
|
||||
const auto _2 = utils::finally([&result]
|
||||
{
|
||||
freeaddrinfo(result);
|
||||
});
|
||||
const auto _2 = utils::finally([&result] { freeaddrinfo(result); });
|
||||
|
||||
for (auto* i = result; i; i = i->ai_next)
|
||||
{
|
||||
@@ -372,10 +362,9 @@ std::size_t std::hash<network::address>::operator()(const network::address& a) c
|
||||
hash ^= std::hash<decltype(a.get_in_addr().sin_addr.s_addr)>{}(a.get_in_addr().sin_addr.s_addr);
|
||||
break;
|
||||
case AF_INET6:
|
||||
hash ^= std::hash<std::string_view>{}(std::string_view{
|
||||
reinterpret_cast<const char*>(a.get_in6_addr().sin6_addr.s6_addr),
|
||||
sizeof(a.get_in6_addr().sin6_addr.s6_addr)
|
||||
});
|
||||
hash ^= std::hash<std::string_view>{}(
|
||||
std::string_view{reinterpret_cast<const char*>(a.get_in6_addr().sin6_addr.s6_addr),
|
||||
sizeof(a.get_in6_addr().sin6_addr.s6_addr)});
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -69,8 +69,7 @@ namespace network
|
||||
bool socket::send(const address& target, const void* data, const size_t size) const
|
||||
{
|
||||
const auto res = sendto(this->socket_, static_cast<const char*>(data), static_cast<send_size>(size), 0,
|
||||
&target.get_addr(),
|
||||
target.get_size());
|
||||
&target.get_addr(), target.get_size());
|
||||
return static_cast<size_t>(res) == size;
|
||||
}
|
||||
|
||||
@@ -84,8 +83,8 @@ namespace network
|
||||
char buffer[0x2000];
|
||||
auto len = source.get_max_size();
|
||||
|
||||
const auto result = recvfrom(this->socket_, buffer, static_cast<int>(sizeof(buffer)), 0, &source.get_addr(),
|
||||
&len);
|
||||
const auto result =
|
||||
recvfrom(this->socket_, buffer, static_cast<int>(sizeof(buffer)), 0, &source.get_addr(), &len);
|
||||
if (result == SOCKET_ERROR)
|
||||
{
|
||||
return false;
|
||||
@@ -107,7 +106,8 @@ namespace network
|
||||
return ioctlsocket(s, FIONBIO, &mode) == 0;
|
||||
#else
|
||||
int flags = fcntl(s, F_GETFL, 0);
|
||||
if (flags == -1) return false;
|
||||
if (flags == -1)
|
||||
return false;
|
||||
flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
|
||||
return fcntl(s, F_SETFL, flags) == 0;
|
||||
#endif
|
||||
@@ -181,8 +181,7 @@ namespace network
|
||||
pfd.revents = 0;
|
||||
}
|
||||
|
||||
const auto retval = poll(pfds.data(), static_cast<uint32_t>(pfds.size()),
|
||||
static_cast<int>(timeout.count()));
|
||||
const auto retval = poll(pfds.data(), static_cast<uint32_t>(pfds.size()), static_cast<int>(timeout.count()));
|
||||
|
||||
if (retval == SOCKET_ERROR)
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#define OS_WINDOWS
|
||||
#elif defined(__APPLE__) || defined(__MACH__)
|
||||
#define OS_MAC
|
||||
#define OS_MAC
|
||||
#elif defined(__linux__)
|
||||
#define OS_LINUX
|
||||
#else
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
#define FILE_DELETE_CHILD 0x0040 /* directory */
|
||||
#define FILE_READ_ATTRIBUTES 0x0080 /* all */
|
||||
#define FILE_WRITE_ATTRIBUTES 0x0100 /* all */
|
||||
#define FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x1ff)
|
||||
#define FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1ff)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -84,7 +84,8 @@ typedef enum _FSINFOCLASS
|
||||
FileFsObjectIdInformation, // q; s: FILE_FS_OBJECTID_INFORMATION (s: requires FILE_WRITE_DATA to volume)
|
||||
FileFsDriverPathInformation, // q: FILE_FS_DRIVER_PATH_INFORMATION
|
||||
FileFsVolumeFlagsInformation,
|
||||
// q; s: FILE_FS_VOLUME_FLAGS_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES to volume) // 10
|
||||
// q; s: FILE_FS_VOLUME_FLAGS_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES to
|
||||
// volume) // 10
|
||||
FileFsSectorSizeInformation, // q: FILE_FS_SECTOR_SIZE_INFORMATION // since WIN8
|
||||
FileFsDataCopyInformation, // q: FILE_FS_DATA_COPY_INFORMATION
|
||||
FileFsMetadataSizeInformation, // q: FILE_FS_METADATA_SIZE_INFORMATION // since THRESHOLD
|
||||
@@ -159,7 +160,8 @@ typedef enum _FILE_INFORMATION_CLASS
|
||||
FileNormalizedNameInformation, // q: FILE_NAME_INFORMATION
|
||||
FileNetworkPhysicalNameInformation, // q: FILE_NETWORK_PHYSICAL_NAME_INFORMATION
|
||||
FileIdGlobalTxDirectoryInformation,
|
||||
// q: FILE_ID_GLOBAL_TX_DIR_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) // since WIN7 // 50
|
||||
// q: FILE_ID_GLOBAL_TX_DIR_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) // since WIN7 //
|
||||
// 50
|
||||
FileIsRemoteDeviceInformation, // q: FILE_IS_REMOTE_DEVICE_INFORMATION (requires FILE_READ_ATTRIBUTES)
|
||||
FileUnusedInformation,
|
||||
FileNumaNodeInformation, // q: FILE_NUMA_NODE_INFORMATION
|
||||
@@ -179,7 +181,8 @@ typedef enum _FILE_INFORMATION_CLASS
|
||||
FileRenameInformationEx, // s: FILE_RENAME_INFORMATION_EX
|
||||
FileRenameInformationExBypassAccessCheck, // (kernel-mode only); s: FILE_RENAME_INFORMATION_EX
|
||||
FileDesiredStorageClassInformation,
|
||||
// q; s: FILE_DESIRED_STORAGE_CLASS_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES) // since REDSTONE2
|
||||
// q; s: FILE_DESIRED_STORAGE_CLASS_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires
|
||||
// FILE_WRITE_ATTRIBUTES) // since REDSTONE2
|
||||
FileStatInformation, // q: FILE_STAT_INFORMATION (requires FILE_READ_ATTRIBUTES)
|
||||
FileMemoryPartitionInformation, // s: FILE_MEMORY_PARTITION_INFORMATION // since REDSTONE3
|
||||
FileStatLxInformation,
|
||||
@@ -192,7 +195,8 @@ typedef enum _FILE_INFORMATION_CLASS
|
||||
// q; s: FILE_STORAGE_RESERVE_ID_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES)
|
||||
FileCaseSensitiveInformationForceAccessCheck, // q; s: FILE_CASE_SENSITIVE_INFORMATION
|
||||
FileKnownFolderInformation,
|
||||
// q; s: FILE_KNOWN_FOLDER_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES) // since WIN11
|
||||
// q; s: FILE_KNOWN_FOLDER_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES) //
|
||||
// since WIN11
|
||||
FileStatBasicInformation, // since 23H2
|
||||
FileId64ExtdDirectoryInformation, // FILE_ID_64_EXTD_DIR_INFORMATION
|
||||
FileId64ExtdBothDirectoryInformation, // FILE_ID_64_EXTD_BOTH_DIR_INFORMATION
|
||||
@@ -353,8 +357,7 @@ typedef struct _FILE_BOTH_DIR_INFORMATION
|
||||
} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION;
|
||||
|
||||
#ifndef OS_WINDOWS
|
||||
typedef BOOLEAN SECURITY_CONTEXT_TRACKING_MODE,
|
||||
* PSECURITY_CONTEXT_TRACKING_MODE;
|
||||
typedef BOOLEAN SECURITY_CONTEXT_TRACKING_MODE, *PSECURITY_CONTEXT_TRACKING_MODE;
|
||||
typedef struct _SECURITY_QUALITY_OF_SERVICE
|
||||
{
|
||||
DWORD Length;
|
||||
|
||||
@@ -49,8 +49,8 @@ union PEB_BITFIELD_UNION
|
||||
|
||||
typedef struct _LIST_ENTRY64
|
||||
{
|
||||
struct _LIST_ENTRY *Flink;
|
||||
struct _LIST_ENTRY *Blink;
|
||||
struct _LIST_ENTRY* Flink;
|
||||
struct _LIST_ENTRY* Blink;
|
||||
} LIST_ENTRY64, *PLIST_ENTRY64, *RESTRICTED_POINTER PRLIST_ENTRY64;
|
||||
|
||||
#endif
|
||||
@@ -391,7 +391,6 @@ union TEB_CURRENT_IDEAL_PROCESSOR_UNION
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
union TEB_CROSS_TEB_FLAGS_UNION
|
||||
{
|
||||
USHORT CrossTebFlags;
|
||||
@@ -557,9 +556,9 @@ typedef struct _TEB64
|
||||
} TEB64, *PTEB64;
|
||||
|
||||
#ifdef OS_WINDOWS
|
||||
inline TEB64* NtCurrentTeb64(VOID)
|
||||
inline TEB64* NtCurrentTeb64()
|
||||
{
|
||||
return (TEB64*)__readgsqword(FIELD_OFFSET(EMU_NT_TIB64, Self));
|
||||
return reinterpret_cast<TEB64*>(__readgsqword(FIELD_OFFSET(EMU_NT_TIB64, Self)));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -658,18 +657,22 @@ union KUSD_QPC_DATA_UNION
|
||||
#ifndef OS_WINDOWS
|
||||
#define MAXIMUM_XSTATE_FEATURES 64
|
||||
|
||||
typedef struct _XSTATE_FEATURE {
|
||||
typedef struct _XSTATE_FEATURE
|
||||
{
|
||||
ULONG Offset;
|
||||
ULONG Size;
|
||||
} XSTATE_FEATURE;
|
||||
|
||||
typedef struct _XSTATE_CONFIGURATION {
|
||||
typedef struct _XSTATE_CONFIGURATION
|
||||
{
|
||||
std::uint64_t EnabledFeatures;
|
||||
std::uint64_t EnabledVolatileFeatures;
|
||||
ULONG Size;
|
||||
union {
|
||||
union
|
||||
{
|
||||
ULONG ControlFlags;
|
||||
struct {
|
||||
struct
|
||||
{
|
||||
ULONG OptimizedSave : 1;
|
||||
ULONG CompactionEnabled : 1;
|
||||
ULONG Reserved1 : 30;
|
||||
|
||||
@@ -62,7 +62,6 @@ typedef enum _SECTION_INHERIT
|
||||
ViewUnmap = 2
|
||||
} SECTION_INHERIT;
|
||||
|
||||
|
||||
typedef struct DECLSPEC_ALIGN(16) _EMU_MEMORY_BASIC_INFORMATION64
|
||||
{
|
||||
void* BaseAddress;
|
||||
@@ -75,7 +74,6 @@ typedef struct DECLSPEC_ALIGN(16) _EMU_MEMORY_BASIC_INFORMATION64
|
||||
DWORD Type;
|
||||
} EMU_MEMORY_BASIC_INFORMATION64, *PEMU_MEMORY_BASIC_INFORMATION64;
|
||||
|
||||
|
||||
typedef struct _MEMORY_IMAGE_INFORMATION64
|
||||
{
|
||||
void* ImageBase;
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4201) // nameless struct/union
|
||||
#pragma warning(disable: 4702) // unreachable code
|
||||
#pragma warning(disable : 4201) // nameless struct/union
|
||||
#pragma warning(disable : 4702) // unreachable code
|
||||
#else
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpedantic"
|
||||
@@ -27,18 +27,12 @@
|
||||
#ifdef OS_WINDOWS
|
||||
#pragma comment(lib, "ntdll")
|
||||
|
||||
extern "C" {
|
||||
NTSYSCALLAPI
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtQuerySystemInformationEx(
|
||||
_In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,
|
||||
_In_reads_bytes_(InputBufferLength) PVOID InputBuffer,
|
||||
_In_ ULONG InputBufferLength,
|
||||
_Out_writes_bytes_opt_(SystemInformationLength) PVOID SystemInformation,
|
||||
_In_ ULONG SystemInformationLength,
|
||||
_Out_opt_ PULONG ReturnLength
|
||||
);
|
||||
extern "C"
|
||||
{
|
||||
NTSYSCALLAPI NTSTATUS NTAPI NtQuerySystemInformationEx(
|
||||
_In_ SYSTEM_INFORMATION_CLASS SystemInformationClass, _In_reads_bytes_(InputBufferLength) PVOID InputBuffer,
|
||||
_In_ ULONG InputBufferLength, _Out_writes_bytes_opt_(SystemInformationLength) PVOID SystemInformation,
|
||||
_In_ ULONG SystemInformationLength, _Out_opt_ PULONG ReturnLength);
|
||||
}
|
||||
#pragma warning(pop)
|
||||
#else
|
||||
|
||||
@@ -44,7 +44,6 @@ using BYTE = std::uint8_t;
|
||||
#define CHAR BYTE
|
||||
#endif
|
||||
|
||||
|
||||
using WORD = std::uint16_t;
|
||||
|
||||
#define UCHAR unsigned char
|
||||
@@ -53,7 +52,6 @@ using WORD = std::uint16_t;
|
||||
using CSHORT = short;
|
||||
using USHORT = WORD;
|
||||
|
||||
|
||||
#define DUMMYSTRUCTNAME
|
||||
|
||||
#ifndef TRUE
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
#define CONTEXT_XSTATE_32 (CONTEXT_X86_MAIN | 0x20L)
|
||||
#define CONTEXT_XSTATE_64 (CONTEXT_AMD64_MAIN | 0x20L)
|
||||
|
||||
#define CONTEXT64_ALL (CONTEXT_CONTROL_64 | CONTEXT_INTEGER_64 | CONTEXT_SEGMENTS_64 | \
|
||||
CONTEXT_FLOATING_POINT_64 | CONTEXT_DEBUG_REGISTERS_64)
|
||||
|
||||
#define CONTEXT64_ALL \
|
||||
(CONTEXT_CONTROL_64 | CONTEXT_INTEGER_64 | CONTEXT_SEGMENTS_64 | CONTEXT_FLOATING_POINT_64 | \
|
||||
CONTEXT_DEBUG_REGISTERS_64)
|
||||
|
||||
typedef enum _SYSTEM_INFORMATION_CLASS
|
||||
{
|
||||
@@ -119,7 +119,8 @@ typedef enum _SYSTEM_INFORMATION_CLASS
|
||||
SystemProcessorPowerInformationEx, // not implemented
|
||||
SystemRefTraceInformation, // q; s: SYSTEM_REF_TRACE_INFORMATION // ObQueryRefTraceInformation
|
||||
SystemSpecialPoolInformation,
|
||||
// q; s: SYSTEM_SPECIAL_POOL_INFORMATION (requires SeDebugPrivilege) // MmSpecialPoolTag, then MmSpecialPoolCatchOverruns != 0
|
||||
// q; s: SYSTEM_SPECIAL_POOL_INFORMATION (requires SeDebugPrivilege) // MmSpecialPoolTag, then
|
||||
// MmSpecialPoolCatchOverruns != 0
|
||||
SystemProcessIdInformation, // q: SYSTEM_PROCESS_ID_INFORMATION
|
||||
SystemErrorPortInformation, // s (requires SeTcbPrivilege)
|
||||
SystemBootEnvironmentInformation, // q: SYSTEM_BOOT_ENVIRONMENT_INFORMATION // 90
|
||||
@@ -142,9 +143,11 @@ typedef enum _SYSTEM_INFORMATION_CLASS
|
||||
SystemProcessorMicrocodeUpdateInformation, // s: SYSTEM_PROCESSOR_MICROCODE_UPDATE_INFORMATION
|
||||
SystemProcessorBrandString, // q: CHAR[] // HaliQuerySystemInformation -> HalpGetProcessorBrandString, info class 23
|
||||
SystemVirtualAddressInformation,
|
||||
// q: SYSTEM_VA_LIST_INFORMATION[]; s: SYSTEM_VA_LIST_INFORMATION[] (requires SeIncreaseQuotaPrivilege) // MmQuerySystemVaInformation
|
||||
// q: SYSTEM_VA_LIST_INFORMATION[]; s: SYSTEM_VA_LIST_INFORMATION[] (requires SeIncreaseQuotaPrivilege) //
|
||||
// MmQuerySystemVaInformation
|
||||
SystemLogicalProcessorAndGroupInformation,
|
||||
// q: SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX (EX in: LOGICAL_PROCESSOR_RELATIONSHIP RelationshipType) // since WIN7 // KeQueryLogicalProcessorRelationship
|
||||
// q: SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX (EX in: LOGICAL_PROCESSOR_RELATIONSHIP RelationshipType) // since WIN7
|
||||
// // KeQueryLogicalProcessorRelationship
|
||||
SystemProcessorCycleTimeInformation, // q: SYSTEM_PROCESSOR_CYCLE_TIME_INFORMATION[] (EX in: USHORT ProcessorGroup)
|
||||
SystemStoreInformation,
|
||||
// q; s: SYSTEM_STORE_INFORMATION (requires SeProfileSingleProcessPrivilege) // SmQueryStoreInformation
|
||||
@@ -165,7 +168,8 @@ typedef enum _SYSTEM_INFORMATION_CLASS
|
||||
SystemAcpiAuditInformation,
|
||||
// q: SYSTEM_ACPI_AUDIT_INFORMATION // HaliQuerySystemInformation -> HalpAuditQueryResults, info class 26
|
||||
SystemBasicPerformanceInformation,
|
||||
// q: SYSTEM_BASIC_PERFORMANCE_INFORMATION // name:wow64:whNtQuerySystemInformation_SystemBasicPerformanceInformation
|
||||
// q: SYSTEM_BASIC_PERFORMANCE_INFORMATION //
|
||||
// name:wow64:whNtQuerySystemInformation_SystemBasicPerformanceInformation
|
||||
SystemQueryPerformanceCounterInformation, // q: SYSTEM_QUERY_PERFORMANCE_COUNTER_INFORMATION // since WIN7 SP1
|
||||
SystemSessionBigPoolInformation, // q: SYSTEM_SESSION_POOLTAG_INFORMATION // since WIN8
|
||||
SystemBootGraphicsInformation, // q; s: SYSTEM_BOOT_GRAPHICS_INFORMATION (kernel-mode only)
|
||||
@@ -228,7 +232,8 @@ typedef enum _SYSTEM_INFORMATION_CLASS
|
||||
SystemCodeIntegrityPlatformManifestInformation,
|
||||
// q: SYSTEM_SECUREBOOT_PLATFORM_MANIFEST_INFORMATION // since REDSTONE
|
||||
SystemInterruptSteeringInformation,
|
||||
// q: in: SYSTEM_INTERRUPT_STEERING_INFORMATION_INPUT, out: SYSTEM_INTERRUPT_STEERING_INFORMATION_OUTPUT // NtQuerySystemInformationEx // 180
|
||||
// q: in: SYSTEM_INTERRUPT_STEERING_INFORMATION_INPUT, out: SYSTEM_INTERRUPT_STEERING_INFORMATION_OUTPUT //
|
||||
// NtQuerySystemInformationEx // 180
|
||||
SystemSupportedProcessorArchitectures,
|
||||
// p: in opt: HANDLE, out: SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES_INFORMATION[] // NtQuerySystemInformationEx
|
||||
SystemMemoryUsageInformation, // q: SYSTEM_MEMORY_USAGE_INFORMATION
|
||||
@@ -261,9 +266,11 @@ typedef enum _SYSTEM_INFORMATION_CLASS
|
||||
SystemSecurityModelInformation, // SYSTEM_SECURITY_MODEL_INFORMATION // since 19H1
|
||||
SystemCodeIntegritySyntheticCacheInformation,
|
||||
SystemFeatureConfigurationInformation,
|
||||
// q: in: SYSTEM_FEATURE_CONFIGURATION_QUERY, out: SYSTEM_FEATURE_CONFIGURATION_INFORMATION; s: SYSTEM_FEATURE_CONFIGURATION_UPDATE // NtQuerySystemInformationEx // since 20H1 // 210
|
||||
// q: in: SYSTEM_FEATURE_CONFIGURATION_QUERY, out: SYSTEM_FEATURE_CONFIGURATION_INFORMATION; s:
|
||||
// SYSTEM_FEATURE_CONFIGURATION_UPDATE // NtQuerySystemInformationEx // since 20H1 // 210
|
||||
SystemFeatureConfigurationSectionInformation,
|
||||
// q: in: SYSTEM_FEATURE_CONFIGURATION_SECTIONS_REQUEST, out: SYSTEM_FEATURE_CONFIGURATION_SECTIONS_INFORMATION // NtQuerySystemInformationEx
|
||||
// q: in: SYSTEM_FEATURE_CONFIGURATION_SECTIONS_REQUEST, out: SYSTEM_FEATURE_CONFIGURATION_SECTIONS_INFORMATION //
|
||||
// NtQuerySystemInformationEx
|
||||
SystemFeatureUsageSubscriptionInformation,
|
||||
// q: SYSTEM_FEATURE_USAGE_SUBSCRIPTION_DETAILS; s: SYSTEM_FEATURE_USAGE_SUBSCRIPTION_UPDATE
|
||||
SystemSecureSpeculationControlInformation, // SECURE_SPECULATION_CONTROL_INFORMATION
|
||||
@@ -285,7 +292,8 @@ typedef enum _SYSTEM_INFORMATION_CLASS
|
||||
SystemDpcWatchdogInformation, // q; s: SYSTEM_DPC_WATCHDOG_CONFIGURATION_INFORMATION
|
||||
SystemDpcWatchdogInformation2, // q; s: SYSTEM_DPC_WATCHDOG_CONFIGURATION_INFORMATION_V2
|
||||
SystemSupportedProcessorArchitectures2,
|
||||
// q: in opt: HANDLE, out: SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES_INFORMATION[] // NtQuerySystemInformationEx // 230
|
||||
// q: in opt: HANDLE, out: SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES_INFORMATION[] // NtQuerySystemInformationEx //
|
||||
// 230
|
||||
SystemSingleProcessorRelationshipInformation,
|
||||
// q: SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX // (EX in: PROCESSOR_NUMBER Processor)
|
||||
SystemXfgCheckFailureInformation, // q: SYSTEM_XFG_FAILURE_INFORMATION
|
||||
@@ -295,10 +303,12 @@ typedef enum _SYSTEM_INFORMATION_CLASS
|
||||
SystemPointerAuthInformation, // SYSTEM_POINTER_AUTH_INFORMATION
|
||||
SystemSecureKernelDebuggerInformation,
|
||||
SystemOriginalImageFeatureInformation,
|
||||
// q: in: SYSTEM_ORIGINAL_IMAGE_FEATURE_INFORMATION_INPUT, out: SYSTEM_ORIGINAL_IMAGE_FEATURE_INFORMATION_OUTPUT // NtQuerySystemInformationEx
|
||||
// q: in: SYSTEM_ORIGINAL_IMAGE_FEATURE_INFORMATION_INPUT, out: SYSTEM_ORIGINAL_IMAGE_FEATURE_INFORMATION_OUTPUT //
|
||||
// NtQuerySystemInformationEx
|
||||
SystemMemoryNumaInformation, // SYSTEM_MEMORY_NUMA_INFORMATION_INPUT, SYSTEM_MEMORY_NUMA_INFORMATION_OUTPUT
|
||||
SystemMemoryNumaPerformanceInformation,
|
||||
// SYSTEM_MEMORY_NUMA_PERFORMANCE_INFORMATION_INPUTSYSTEM_MEMORY_NUMA_PERFORMANCE_INFORMATION_INPUT, SYSTEM_MEMORY_NUMA_PERFORMANCE_INFORMATION_OUTPUT // since 24H2 // 240
|
||||
// SYSTEM_MEMORY_NUMA_PERFORMANCE_INFORMATION_INPUTSYSTEM_MEMORY_NUMA_PERFORMANCE_INFORMATION_INPUT,
|
||||
// SYSTEM_MEMORY_NUMA_PERFORMANCE_INFORMATION_OUTPUT // since 24H2 // 240
|
||||
SystemCodeIntegritySignedPoliciesFullInformation,
|
||||
SystemSecureSecretsInformation,
|
||||
SystemTrustedAppsRuntimeInformation, // SYSTEM_TRUSTEDAPPS_RUNTIME_INFORMATION
|
||||
@@ -359,7 +369,8 @@ typedef enum _TOKEN_INFORMATION_CLASS
|
||||
TokenChildProcessFlags, // s: ULONG (requires SeTcbPrivilege) // since REDSTONE3
|
||||
TokenIsLessPrivilegedAppContainer, // q: ULONG // since REDSTONE5
|
||||
TokenIsSandboxed, // q: ULONG // since 19H1
|
||||
TokenIsAppSilo, // q: ULONG // since WIN11 22H2 // previously TokenOriginatingProcessTrustLevel // q: TOKEN_PROCESS_TRUST_LEVEL
|
||||
TokenIsAppSilo, // q: ULONG // since WIN11 22H2 // previously TokenOriginatingProcessTrustLevel // q:
|
||||
// TOKEN_PROCESS_TRUST_LEVEL
|
||||
TokenLoggingInformation, // TOKEN_LOGGING_INFORMATION // since 24H2
|
||||
MaxTokenInfoClass
|
||||
} TOKEN_INFORMATION_CLASS, *PTOKEN_INFORMATION_CLASS;
|
||||
@@ -538,12 +549,14 @@ struct SYSTEM_PROCESSOR_INFORMATION64
|
||||
|
||||
#ifndef OS_WINDOWS
|
||||
|
||||
typedef struct _M128A {
|
||||
typedef struct _M128A
|
||||
{
|
||||
ULONGLONG Low;
|
||||
LONGLONG High;
|
||||
} M128A, *PM128A;
|
||||
|
||||
typedef struct _XMM_SAVE_AREA32 {
|
||||
typedef struct _XMM_SAVE_AREA32
|
||||
{
|
||||
WORD ControlWord;
|
||||
WORD StatusWord;
|
||||
BYTE TagWord;
|
||||
@@ -656,7 +669,7 @@ struct EMU_EXCEPTION_RECORD
|
||||
{
|
||||
DWORD ExceptionCode;
|
||||
DWORD ExceptionFlags;
|
||||
EMULATOR_CAST(typename Traits::PVOID, struct EMU_EXCEPTION_RECORD *) ExceptionRecord;
|
||||
EMULATOR_CAST(typename Traits::PVOID, struct EMU_EXCEPTION_RECORD*) ExceptionRecord;
|
||||
typename Traits::PVOID ExceptionAddress;
|
||||
DWORD NumberParameters;
|
||||
typename Traits::ULONG_PTR ExceptionInformation[15];
|
||||
@@ -742,30 +755,34 @@ struct TOKEN_MANDATORY_LABEL64
|
||||
|
||||
#ifndef OS_WINDOWS
|
||||
|
||||
typedef enum _TOKEN_TYPE {
|
||||
typedef enum _TOKEN_TYPE
|
||||
{
|
||||
TokenPrimary = 1,
|
||||
TokenImpersonation
|
||||
} TOKEN_TYPE;
|
||||
typedef TOKEN_TYPE* PTOKEN_TYPE;
|
||||
|
||||
typedef struct _TOKEN_ELEVATION {
|
||||
typedef struct _TOKEN_ELEVATION
|
||||
{
|
||||
DWORD TokenIsElevated;
|
||||
} TOKEN_ELEVATION, * PTOKEN_ELEVATION;
|
||||
} TOKEN_ELEVATION, *PTOKEN_ELEVATION;
|
||||
|
||||
typedef enum _SECURITY_IMPERSONATION_LEVEL {
|
||||
typedef enum _SECURITY_IMPERSONATION_LEVEL
|
||||
{
|
||||
SecurityAnonymous,
|
||||
SecurityIdentification,
|
||||
SecurityImpersonation,
|
||||
SecurityDelegation
|
||||
} SECURITY_IMPERSONATION_LEVEL, *PSECURITY_IMPERSONATION_LEVEL;
|
||||
|
||||
|
||||
typedef struct _LUID {
|
||||
typedef struct _LUID
|
||||
{
|
||||
DWORD LowPart;
|
||||
LONG HighPart;
|
||||
} LUID, *PLUID;
|
||||
|
||||
typedef struct _TOKEN_STATISTICS {
|
||||
typedef struct _TOKEN_STATISTICS
|
||||
{
|
||||
LUID TokenId;
|
||||
LUID AuthenticationId;
|
||||
LARGE_INTEGER ExpirationTime;
|
||||
|
||||
@@ -11,8 +11,9 @@ using NTSTATUS = std::uint32_t;
|
||||
#define STATUS_ACCESS_VIOLATION ((NTSTATUS)0xC0000005L)
|
||||
#define STATUS_INVALID_HANDLE ((NTSTATUS)0xC0000008L)
|
||||
#define STATUS_INVALID_PARAMETER ((NTSTATUS)0xC000000DL)
|
||||
#define STATUS_ILLEGAL_INSTRUCTION ((NTSTATUS)0xC000001DL)
|
||||
|
||||
#define STATUS_PENDING ((DWORD)0x00000103L)
|
||||
#define STATUS_PENDING ((NTSTATUS)0x00000103L)
|
||||
#endif
|
||||
|
||||
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
|
||||
@@ -25,7 +26,6 @@ using NTSTATUS = std::uint32_t;
|
||||
|
||||
#define STATUS_NO_MORE_FILES ((NTSTATUS)0x80000006L)
|
||||
|
||||
#define STATUS_ILLEGAL_INSTRUCTION ((DWORD )0xC000001DL)
|
||||
#define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L)
|
||||
#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L)
|
||||
#define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS)0xC0000034L)
|
||||
@@ -41,6 +41,5 @@ using NTSTATUS = std::uint32_t;
|
||||
|
||||
#define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L)
|
||||
|
||||
|
||||
#define FILE_DEVICE_NETWORK 0x00000012
|
||||
#define FSCTL_AFD_BASE FILE_DEVICE_NETWORK
|
||||
|
||||
@@ -65,7 +65,6 @@ typedef enum _THREADINFOCLASS
|
||||
MaxThreadInfoClass
|
||||
} THREADINFOCLASS;
|
||||
|
||||
|
||||
template <typename Traits>
|
||||
struct THREAD_NAME_INFORMATION
|
||||
{
|
||||
|
||||
@@ -91,7 +91,6 @@ enum class PEMachineType : std::uint16_t
|
||||
CEE = 0xC0EE,
|
||||
};
|
||||
|
||||
|
||||
#pragma pack(push, 4)
|
||||
|
||||
template <typename T>
|
||||
@@ -130,7 +129,6 @@ struct PEOptionalHeaderBasePart1_t
|
||||
uint32_t BaseOfCode;
|
||||
};
|
||||
|
||||
|
||||
struct PEDirectory_t2
|
||||
{
|
||||
std::uint32_t VirtualAddress;
|
||||
@@ -246,8 +244,9 @@ struct PEDosHeader_t
|
||||
typedef struct _IMAGE_SECTION_HEADER
|
||||
{
|
||||
std::uint8_t Name[IMAGE_SIZEOF_SHORT_NAME];
|
||||
union {
|
||||
std:: uint32_t PhysicalAddress;
|
||||
union
|
||||
{
|
||||
std::uint32_t PhysicalAddress;
|
||||
std::uint32_t VirtualSize;
|
||||
} Misc;
|
||||
std::uint32_t VirtualAddress;
|
||||
@@ -260,7 +259,8 @@ typedef struct _IMAGE_SECTION_HEADER
|
||||
std::uint32_t Characteristics;
|
||||
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
|
||||
|
||||
typedef struct _IMAGE_EXPORT_DIRECTORY {
|
||||
typedef struct _IMAGE_EXPORT_DIRECTORY
|
||||
{
|
||||
DWORD Characteristics;
|
||||
DWORD TimeDateStamp;
|
||||
WORD MajorVersion;
|
||||
@@ -274,7 +274,8 @@ typedef struct _IMAGE_EXPORT_DIRECTORY {
|
||||
DWORD AddressOfNameOrdinals;
|
||||
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
|
||||
|
||||
typedef struct _IMAGE_BASE_RELOCATION {
|
||||
typedef struct _IMAGE_BASE_RELOCATION
|
||||
{
|
||||
DWORD VirtualAddress;
|
||||
DWORD SizeOfBlock;
|
||||
WORD TypeOffset[1];
|
||||
|
||||
@@ -11,8 +11,8 @@ namespace utils
|
||||
{
|
||||
public:
|
||||
safe_object_accessor(const std::span<S> buffer, const size_t offset)
|
||||
: buffer_(buffer)
|
||||
, offset_(offset)
|
||||
: buffer_(buffer),
|
||||
offset_(offset)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -36,8 +36,14 @@ namespace utils::concurrency
|
||||
return accessor(object_, lock);
|
||||
}
|
||||
|
||||
T& get_raw() { return object_; }
|
||||
const T& get_raw() const { return object_; }
|
||||
T& get_raw()
|
||||
{
|
||||
return object_;
|
||||
}
|
||||
const T& get_raw() const
|
||||
{
|
||||
return object_;
|
||||
}
|
||||
|
||||
T copy() const
|
||||
{
|
||||
|
||||
@@ -5,23 +5,25 @@
|
||||
namespace utils
|
||||
{
|
||||
/*
|
||||
* Copied from here: https://github.com/microsoft/GSL/blob/e0880931ae5885eb988d1a8a57acf8bc2b8dacda/include/gsl/util#L57
|
||||
* Copied from here:
|
||||
* https://github.com/microsoft/GSL/blob/e0880931ae5885eb988d1a8a57acf8bc2b8dacda/include/gsl/util#L57
|
||||
*/
|
||||
|
||||
template <class F>
|
||||
class final_action
|
||||
{
|
||||
public:
|
||||
static_assert(!std::is_reference<F>::value && !std::is_const<F>::value &&
|
||||
!std::is_volatile<F>::value,
|
||||
static_assert(!std::is_reference<F>::value && !std::is_const<F>::value && !std::is_volatile<F>::value,
|
||||
"Final_action should store its callable by value");
|
||||
|
||||
explicit final_action(F f) noexcept : f_(std::move(f))
|
||||
explicit final_action(F f) noexcept
|
||||
: f_(std::move(f))
|
||||
{
|
||||
}
|
||||
|
||||
final_action(final_action&& other) noexcept
|
||||
: f_(std::move(other.f_)), invoke_(std::exchange(other.invoke_, false))
|
||||
: f_(std::move(other.f_)),
|
||||
invoke_(std::exchange(other.invoke_, false))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -31,7 +33,8 @@ namespace utils
|
||||
|
||||
~final_action() noexcept
|
||||
{
|
||||
if (invoke_) f_();
|
||||
if (invoke_)
|
||||
f_();
|
||||
}
|
||||
|
||||
// Added by momo5502
|
||||
@@ -46,10 +49,8 @@ namespace utils
|
||||
};
|
||||
|
||||
template <class F>
|
||||
final_action<typename std::remove_cv<typename std::remove_reference<F>::type>::type>
|
||||
finally(F&& f) noexcept
|
||||
final_action<typename std::remove_cv<typename std::remove_reference<F>::type>::type> finally(F&& f) noexcept
|
||||
{
|
||||
return final_action<typename std::remove_cv<typename std::remove_reference<F>::type>::type>(
|
||||
std::forward<F>(f));
|
||||
return final_action<typename std::remove_cv<typename std::remove_reference<F>::type>::type>(std::forward<F>(f));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,8 +28,8 @@ namespace utils::io
|
||||
io::create_directory(file.parent_path());
|
||||
}
|
||||
|
||||
std::ofstream stream(
|
||||
file, std::ios::binary | std::ofstream::out | (append ? std::ofstream::app : std::ofstream::out));
|
||||
std::ofstream stream(file, std::ios::binary | std::ofstream::out |
|
||||
(append ? std::ofstream::app : std::ofstream::out));
|
||||
|
||||
if (stream.is_open())
|
||||
{
|
||||
@@ -50,11 +50,13 @@ namespace utils::io
|
||||
|
||||
bool read_file(const std::filesystem::path& file, std::vector<uint8_t>* data)
|
||||
{
|
||||
if (!data) return false;
|
||||
if (!data)
|
||||
return false;
|
||||
data->clear();
|
||||
|
||||
std::ifstream stream(file, std::ios::binary);
|
||||
if (!stream) return false;
|
||||
if (!stream)
|
||||
return false;
|
||||
|
||||
*data = std::vector<uint8_t>{(std::istreambuf_iterator<char>(stream)), std::istreambuf_iterator<char>()};
|
||||
return true;
|
||||
@@ -94,9 +96,9 @@ namespace utils::io
|
||||
void copy_folder(const std::filesystem::path& src, const std::filesystem::path& target)
|
||||
{
|
||||
std::error_code ec{};
|
||||
std::filesystem::copy(src, target,
|
||||
std::filesystem::copy_options::overwrite_existing |
|
||||
std::filesystem::copy_options::recursive, ec);
|
||||
std::filesystem::copy(
|
||||
src, target, std::filesystem::copy_options::overwrite_existing | std::filesystem::copy_options::recursive,
|
||||
ec);
|
||||
}
|
||||
|
||||
std::vector<std::filesystem::path> list_files(const std::filesystem::path& directory, const bool recursive)
|
||||
|
||||
@@ -29,10 +29,7 @@ namespace utils::string
|
||||
template <class Elem, class Traits, class Alloc>
|
||||
void to_lower_inplace(std::basic_string<Elem, Traits, Alloc>& str)
|
||||
{
|
||||
std::ranges::transform(str, str.begin(), [](const Elem e)
|
||||
{
|
||||
return char_to_lower(e);
|
||||
});
|
||||
std::ranges::transform(str, str.begin(), [](const Elem e) { return char_to_lower(e); });
|
||||
}
|
||||
|
||||
template <class Elem, class Traits, class Alloc>
|
||||
|
||||
@@ -34,23 +34,22 @@ struct basic_block
|
||||
size_t size;
|
||||
};
|
||||
|
||||
using edge_generation_hook_callback = std::function<void(const basic_block& current_block,
|
||||
const basic_block& previous_block)>;
|
||||
using edge_generation_hook_callback =
|
||||
std::function<void(const basic_block& current_block, const basic_block& previous_block)>;
|
||||
using basic_block_hook_callback = std::function<void(const basic_block& block)>;
|
||||
|
||||
using instruction_hook_callback = std::function<instruction_hook_continuation()>;
|
||||
|
||||
using interrupt_hook_callback = std::function<void(int interrupt)>;
|
||||
using simple_memory_hook_callback = std::function<void(uint64_t address, size_t size, uint64_t value)>;
|
||||
using complex_memory_hook_callback = std::function<void(uint64_t address, size_t size, uint64_t value,
|
||||
memory_operation operation)>;
|
||||
using complex_memory_hook_callback =
|
||||
std::function<void(uint64_t address, size_t size, uint64_t value, memory_operation operation)>;
|
||||
using memory_violation_hook_callback = std::function<memory_violation_continuation(
|
||||
uint64_t address, size_t size, memory_operation operation,
|
||||
memory_violation_type type)>;
|
||||
uint64_t address, size_t size, memory_operation operation, memory_violation_type type)>;
|
||||
|
||||
class emulator : public memory_manager
|
||||
{
|
||||
public:
|
||||
public:
|
||||
emulator() = default;
|
||||
|
||||
emulator(const emulator&) = delete;
|
||||
@@ -133,7 +132,7 @@ public:
|
||||
|
||||
virtual bool has_violation() const = 0;
|
||||
|
||||
private:
|
||||
private:
|
||||
std::vector<std::byte> last_snapshot_data_{};
|
||||
|
||||
emulator_hook* hook_simple_memory_access(const uint64_t address, const size_t size,
|
||||
@@ -143,10 +142,7 @@ private:
|
||||
return this->hook_memory_access(address, size, operation,
|
||||
[c = std::move(callback)](const uint64_t a, const size_t s,
|
||||
const uint64_t value,
|
||||
memory_operation)
|
||||
{
|
||||
c(a, s, value);
|
||||
});
|
||||
memory_operation) { c(a, s, value); });
|
||||
}
|
||||
|
||||
void perform_serialization(utils::buffer_serializer& buffer, const bool is_snapshot) const
|
||||
|
||||
@@ -227,11 +227,13 @@ bool memory_manager::allocate_mmio(const uint64_t address, const size_t size, mm
|
||||
|
||||
this->map_mmio(address, size, std::move(read_cb), std::move(write_cb));
|
||||
|
||||
const auto entry = this->reserved_regions_.try_emplace(address,
|
||||
const auto entry = this->reserved_regions_
|
||||
.try_emplace(address,
|
||||
reserved_region{
|
||||
.length = size,
|
||||
.is_mmio = true,
|
||||
}).first;
|
||||
})
|
||||
.first;
|
||||
|
||||
entry->second.committed_regions[address] = committed_region{size, memory_permission::read_write};
|
||||
|
||||
@@ -246,7 +248,12 @@ bool memory_manager::allocate_memory(const uint64_t address, const size_t size,
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto entry = this->reserved_regions_.try_emplace(address, reserved_region{.length = size,}).first;
|
||||
const auto entry = this->reserved_regions_
|
||||
.try_emplace(address,
|
||||
reserved_region{
|
||||
.length = size,
|
||||
})
|
||||
.first;
|
||||
|
||||
if (!reserve_only)
|
||||
{
|
||||
@@ -416,8 +423,7 @@ bool memory_manager::release_memory(const uint64_t address, size_t size)
|
||||
|
||||
uint64_t memory_manager::find_free_allocation_base(const size_t size, const uint64_t start) const
|
||||
{
|
||||
uint64_t start_address =
|
||||
std::max(MIN_ALLOCATION_ADDRESS, start ? start : 0x100000000ULL);
|
||||
uint64_t start_address = std::max(MIN_ALLOCATION_ADDRESS, start ? start : 0x100000000ULL);
|
||||
|
||||
for (const auto& region : this->reserved_regions_)
|
||||
{
|
||||
|
||||
@@ -18,7 +18,7 @@ using mmio_write_callback = std::function<void(uint64_t addr, size_t size, uint6
|
||||
|
||||
class memory_manager
|
||||
{
|
||||
public:
|
||||
public:
|
||||
struct committed_region
|
||||
{
|
||||
size_t length{};
|
||||
@@ -90,8 +90,7 @@ public:
|
||||
memory_permission* old_permissions = nullptr);
|
||||
|
||||
bool allocate_mmio(uint64_t address, size_t size, mmio_read_callback read_cb, mmio_write_callback write_cb);
|
||||
bool allocate_memory(uint64_t address, size_t size, memory_permission permissions,
|
||||
bool reserve_only = false);
|
||||
bool allocate_memory(uint64_t address, size_t size, memory_permission permissions, bool reserve_only = false);
|
||||
|
||||
bool commit_memory(uint64_t address, size_t size, memory_permission permissions);
|
||||
bool decommit_memory(uint64_t address, size_t size);
|
||||
@@ -113,7 +112,7 @@ public:
|
||||
return allocation_base;
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
using reserved_region_map = std::map<uint64_t, reserved_region>;
|
||||
reserved_region_map reserved_regions_{};
|
||||
|
||||
@@ -126,7 +125,7 @@ private:
|
||||
|
||||
virtual void apply_memory_protection(uint64_t address, size_t size, memory_permission permissions) = 0;
|
||||
|
||||
protected:
|
||||
protected:
|
||||
void serialize_memory_state(utils::buffer_serializer& buffer, bool is_snapshot) const;
|
||||
void deserialize_memory_state(utils::buffer_deserializer& buffer, bool is_snapshot);
|
||||
};
|
||||
|
||||
@@ -15,49 +15,39 @@ enum class memory_permission : uint8_t
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
inline constexpr memory_permission
|
||||
operator&(const memory_permission x, const memory_permission y)
|
||||
inline constexpr memory_permission operator&(const memory_permission x, const memory_permission y)
|
||||
{
|
||||
return static_cast<memory_permission>
|
||||
(static_cast<uint8_t>(x) & static_cast<uint8_t>(y));
|
||||
return static_cast<memory_permission>(static_cast<uint8_t>(x) & static_cast<uint8_t>(y));
|
||||
}
|
||||
|
||||
inline constexpr memory_permission
|
||||
operator|(const memory_permission x, const memory_permission y)
|
||||
inline constexpr memory_permission operator|(const memory_permission x, const memory_permission y)
|
||||
{
|
||||
return static_cast<memory_permission>
|
||||
(static_cast<uint8_t>(x) | static_cast<uint8_t>(y));
|
||||
return static_cast<memory_permission>(static_cast<uint8_t>(x) | static_cast<uint8_t>(y));
|
||||
}
|
||||
|
||||
inline constexpr memory_permission
|
||||
operator^(const memory_permission x, const memory_permission y)
|
||||
inline constexpr memory_permission operator^(const memory_permission x, const memory_permission y)
|
||||
{
|
||||
return static_cast<memory_permission>
|
||||
(static_cast<uint8_t>(x) ^ static_cast<uint8_t>(y));
|
||||
return static_cast<memory_permission>(static_cast<uint8_t>(x) ^ static_cast<uint8_t>(y));
|
||||
}
|
||||
|
||||
inline constexpr memory_permission
|
||||
operator~(memory_permission x)
|
||||
inline constexpr memory_permission operator~(memory_permission x)
|
||||
{
|
||||
return static_cast<memory_permission>(~static_cast<uint8_t>(x));
|
||||
}
|
||||
|
||||
inline memory_permission&
|
||||
operator&=(memory_permission& x, const memory_permission y)
|
||||
inline memory_permission& operator&=(memory_permission& x, const memory_permission y)
|
||||
{
|
||||
x = x & y;
|
||||
return x;
|
||||
}
|
||||
|
||||
inline memory_permission&
|
||||
operator|=(memory_permission& x, const memory_permission y)
|
||||
inline memory_permission& operator|=(memory_permission& x, const memory_permission y)
|
||||
{
|
||||
x = x | y;
|
||||
return x;
|
||||
}
|
||||
|
||||
inline memory_permission&
|
||||
operator^=(memory_permission& x, const memory_permission y)
|
||||
inline memory_permission& operator^=(memory_permission& x, const memory_permission y)
|
||||
{
|
||||
x = x ^ y;
|
||||
return x;
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
|
||||
class scoped_hook
|
||||
{
|
||||
public:
|
||||
public:
|
||||
scoped_hook() = default;
|
||||
|
||||
scoped_hook(emulator& emu, emulator_hook* hook)
|
||||
: emu_(&emu)
|
||||
, hook_(hook)
|
||||
: emu_(&emu),
|
||||
hook_(hook)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
emulator* emu_{};
|
||||
emulator_hook* hook_{};
|
||||
};
|
||||
|
||||
@@ -15,8 +15,7 @@ namespace utils
|
||||
class buffer_deserializer;
|
||||
|
||||
template <typename T>
|
||||
concept Serializable = requires(T a, const T ac, buffer_serializer& serializer, buffer_deserializer& deserializer)
|
||||
{
|
||||
concept Serializable = requires(T a, const T ac, buffer_serializer& serializer, buffer_deserializer& deserializer) {
|
||||
{ ac.serialize(serializer) } -> std::same_as<void>;
|
||||
{ a.deserialize(deserializer) } -> std::same_as<void>;
|
||||
};
|
||||
@@ -38,9 +37,9 @@ namespace utils
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct has_serialize_function<T, std::void_t<decltype(serialize(std::declval<buffer_serializer&>(),
|
||||
std::declval<const std::remove_cvref_t<T>&>())
|
||||
)>>
|
||||
struct has_serialize_function<T,
|
||||
std::void_t<decltype(serialize(std::declval<buffer_serializer&>(),
|
||||
std::declval<const std::remove_cvref_t<T>&>()))>>
|
||||
: std::true_type
|
||||
{
|
||||
};
|
||||
@@ -51,16 +50,14 @@ namespace utils
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct has_deserialize_function<T, std::void_t<decltype(deserialize(
|
||||
std::declval<buffer_deserializer&>(),
|
||||
struct has_deserialize_function<T, std::void_t<decltype(deserialize(std::declval<buffer_deserializer&>(),
|
||||
std::declval<std::remove_cvref_t<T>&>()))>>
|
||||
: std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct has_deserializer_constructor
|
||||
: std::bool_constant<std::is_constructible_v<T, buffer_deserializer&>>
|
||||
struct has_deserializer_constructor : std::bool_constant<std::is_constructible_v<T, buffer_deserializer&>>
|
||||
{
|
||||
};
|
||||
}
|
||||
@@ -70,8 +67,8 @@ namespace utils
|
||||
public:
|
||||
template <typename T>
|
||||
buffer_deserializer(const std::span<T> buffer, bool no_debugging = false)
|
||||
: no_debugging_(no_debugging)
|
||||
, buffer_(reinterpret_cast<const std::byte*>(buffer.data()), buffer.size() * sizeof(T))
|
||||
: no_debugging_(no_debugging),
|
||||
buffer_(reinterpret_cast<const std::byte*>(buffer.data()), buffer.size() * sizeof(T))
|
||||
{
|
||||
static_assert(std::is_trivially_copyable_v<T>, "Type must be trivially copyable");
|
||||
}
|
||||
@@ -257,7 +254,7 @@ namespace utils
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T= char>
|
||||
template <typename T = char>
|
||||
std::basic_string<T> read_string()
|
||||
{
|
||||
std::basic_string<T> result{};
|
||||
@@ -284,9 +281,7 @@ namespace utils
|
||||
requires(std::is_invocable_r_v<T, F>)
|
||||
void register_factory(F factory)
|
||||
{
|
||||
this->factories_[std::type_index(typeid(T))] = [f = std::move(factory)]() -> T* {
|
||||
return new T(f());
|
||||
};
|
||||
this->factories_[std::type_index(typeid(T))] = [f = std::move(factory)]() -> T* { return new T(f()); };
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -311,8 +306,8 @@ namespace utils
|
||||
const auto factory = this->factories_.find(std::type_index(typeid(T)));
|
||||
if (factory == this->factories_.end())
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"Object construction failed. Missing factory for type: " + std::string(typeid(T).name()));
|
||||
throw std::runtime_error("Object construction failed. Missing factory for type: " +
|
||||
std::string(typeid(T).name()));
|
||||
}
|
||||
|
||||
auto* object = static_cast<T*>(factory->second());
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
#include "emulator.hpp"
|
||||
|
||||
template <typename PointerType, typename Register, Register InstructionPointer, Register
|
||||
StackPointer, typename HookableInstructions>
|
||||
template <typename PointerType, typename Register, Register InstructionPointer, Register StackPointer,
|
||||
typename HookableInstructions>
|
||||
class typed_emulator : public emulator
|
||||
{
|
||||
public:
|
||||
public:
|
||||
using registers = Register;
|
||||
using pointer_type = PointerType;
|
||||
using hookable_instructions = HookableInstructions;
|
||||
@@ -87,7 +87,7 @@ public:
|
||||
return this->hook_instruction(static_cast<int>(instruction_type), std::move(callback));
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
emulator_hook* hook_instruction(int instruction_type, instruction_hook_callback callback) override = 0;
|
||||
|
||||
void read_raw_register(int reg, void* value, size_t size) override = 0;
|
||||
|
||||
@@ -11,5 +11,5 @@ enum class x64_hookable_instructions
|
||||
rdtscp,
|
||||
};
|
||||
|
||||
using x64_emulator = typed_emulator<uint64_t, x64_register, x64_register::rip,
|
||||
x64_register::rsp, x64_hookable_instructions>;
|
||||
using x64_emulator =
|
||||
typed_emulator<uint64_t, x64_register, x64_register::rip, x64_register::rsp, x64_hookable_instructions>;
|
||||
|
||||
@@ -35,10 +35,7 @@ namespace
|
||||
void forward_emulator(windows_emulator& win_emu)
|
||||
{
|
||||
const auto target = win_emu.process().executable->find_export("vulnerable");
|
||||
win_emu.emu().hook_memory_execution(target, 1, [&](uint64_t, size_t, uint64_t)
|
||||
{
|
||||
win_emu.emu().stop();
|
||||
});
|
||||
win_emu.emu().hook_memory_execution(target, 1, [&](uint64_t, size_t, uint64_t) { win_emu.emu().stop(); });
|
||||
|
||||
run_emulation(win_emu);
|
||||
}
|
||||
@@ -50,13 +47,11 @@ namespace
|
||||
std::unordered_set<uint64_t> visited_blocks{};
|
||||
const std::function<fuzzer::coverage_functor>* handler{nullptr};
|
||||
|
||||
|
||||
fuzzer_executer(std::span<const std::byte> data)
|
||||
: emulator_data(data)
|
||||
{
|
||||
emu.fuzzing = true;
|
||||
emu.emu().hook_basic_block([&](const basic_block& block)
|
||||
{
|
||||
emu.emu().hook_basic_block([&](const basic_block& block) {
|
||||
if (this->handler && visited_blocks.emplace(block.address).second)
|
||||
{
|
||||
(*this->handler)(block.address);
|
||||
@@ -69,10 +64,7 @@ namespace
|
||||
|
||||
const auto ret = emu.emu().read_stack(0);
|
||||
|
||||
emu.emu().hook_memory_execution(ret, 1, [&](uint64_t, size_t, uint64_t)
|
||||
{
|
||||
emu.emu().stop();
|
||||
});
|
||||
emu.emu().hook_memory_execution(ret, 1, [&](uint64_t, size_t, uint64_t) { emu.emu().stop(); });
|
||||
}
|
||||
|
||||
void restore_emulator()
|
||||
@@ -85,7 +77,7 @@ namespace
|
||||
fuzzer::execution_result execute(std::span<const uint8_t> data,
|
||||
const std::function<fuzzer::coverage_functor>& coverage_handler) override
|
||||
{
|
||||
//printf("Input size: %zd\n", data.size());
|
||||
// printf("Input size: %zd\n", data.size());
|
||||
this->handler = &coverage_handler;
|
||||
this->visited_blocks.clear();
|
||||
|
||||
@@ -164,7 +156,7 @@ int main(const int argc, char** argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
//setvbuf(stdout, nullptr, _IOFBF, 0x10000);
|
||||
// setvbuf(stdout, nullptr, _IOFBF, 0x10000);
|
||||
if (argc > 2 && argv[1] == "-d"s)
|
||||
{
|
||||
use_gdb = true;
|
||||
@@ -175,8 +167,7 @@ int main(const int argc, char** argv)
|
||||
do
|
||||
{
|
||||
run(argv[use_gdb ? 2 : 1]);
|
||||
}
|
||||
while (use_gdb);
|
||||
} while (use_gdb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@ namespace fuzzer
|
||||
{
|
||||
public:
|
||||
fuzzing_context(input_generator& generator, fuzzing_handler& handler)
|
||||
: generator(generator)
|
||||
, handler(handler)
|
||||
: generator(generator),
|
||||
handler(handler)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -48,13 +48,9 @@ namespace fuzzer
|
||||
void perform_fuzzing_iteration(fuzzing_context& context, executer& executer)
|
||||
{
|
||||
++context.executions;
|
||||
context.generator.access_input([&](const std::span<const uint8_t> input)
|
||||
{
|
||||
context.generator.access_input([&](const std::span<const uint8_t> input) {
|
||||
uint64_t score{0};
|
||||
const auto result = executer.execute(input, [&](uint64_t)
|
||||
{
|
||||
++score;
|
||||
});
|
||||
const auto result = executer.execute(input, [&](uint64_t) { ++score; });
|
||||
|
||||
if (result == execution_result::error)
|
||||
{
|
||||
@@ -88,10 +84,7 @@ namespace fuzzer
|
||||
|
||||
for (size_t i = 0; i < concurrency; ++i)
|
||||
{
|
||||
this->workers_.emplace_back([&context]
|
||||
{
|
||||
worker(context);
|
||||
});
|
||||
this->workers_.emplace_back([&context] { worker(context); });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ namespace fuzzer
|
||||
|
||||
const auto mutations = (rng.get_geometric<size_t>() + 1) % input.size();
|
||||
|
||||
|
||||
for (size_t i = 0; i < mutations; ++i)
|
||||
{
|
||||
const auto index = rng.get<size_t>(input.size());
|
||||
@@ -102,9 +101,8 @@ namespace fuzzer
|
||||
}
|
||||
|
||||
const auto insert_at_random = this->rng.get(10) == 0;
|
||||
const auto index = insert_at_random
|
||||
? (this->rng.get<size_t>() % this->top_scorer_.size())
|
||||
: this->lowest_scorer;
|
||||
const auto index =
|
||||
insert_at_random ? (this->rng.get<size_t>() % this->top_scorer_.size()) : this->lowest_scorer;
|
||||
|
||||
this->top_scorer_[index] = std::move(entry);
|
||||
|
||||
|
||||
@@ -52,13 +52,12 @@ bool test_threads()
|
||||
|
||||
for (auto i = 0ULL; i < thread_count; ++i)
|
||||
{
|
||||
threads.emplace_back([&counter]
|
||||
{
|
||||
threads.emplace_back([&counter] {
|
||||
++counter;
|
||||
std::this_thread::yield();
|
||||
++counter;
|
||||
// Host scheduling/cpu performance can have impact on emulator scheduling
|
||||
//std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
// std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
++counter;
|
||||
});
|
||||
}
|
||||
@@ -82,8 +81,7 @@ bool test_tls()
|
||||
|
||||
for (size_t i = 0; i < thread_count; ++i)
|
||||
{
|
||||
ts.emplace_back([&]
|
||||
{
|
||||
ts.emplace_back([&] {
|
||||
while (!kill)
|
||||
{
|
||||
std::this_thread::yield();
|
||||
@@ -173,8 +171,7 @@ bool test_dir_io()
|
||||
std::optional<std::string> read_registry_string(const HKEY root, const char* path, const char* value)
|
||||
{
|
||||
HKEY key{};
|
||||
if (RegOpenKeyExA(root, path, 0, KEY_READ, &key) !=
|
||||
ERROR_SUCCESS)
|
||||
if (RegOpenKeyExA(root, path, 0, KEY_READ, &key) != ERROR_SUCCESS)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -203,8 +200,8 @@ std::optional<std::string> read_registry_string(const HKEY root, const char* pat
|
||||
|
||||
bool test_registry()
|
||||
{
|
||||
const auto val = read_registry_string(HKEY_LOCAL_MACHINE, R"(SOFTWARE\Microsoft\Windows\CurrentVersion)",
|
||||
"ProgramFilesDir");
|
||||
const auto val =
|
||||
read_registry_string(HKEY_LOCAL_MACHINE, R"(SOFTWARE\Microsoft\Windows\CurrentVersion)", "ProgramFilesDir");
|
||||
if (!val)
|
||||
{
|
||||
return false;
|
||||
@@ -259,7 +256,7 @@ bool test_ud2_exception(void* address)
|
||||
{
|
||||
__try
|
||||
{
|
||||
static_cast<void(*)()>(address)();
|
||||
static_cast<void (*)()>(address)();
|
||||
return false;
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
@@ -287,8 +284,7 @@ bool test_illegal_instruction_exception()
|
||||
|
||||
bool test_native_exceptions()
|
||||
{
|
||||
return test_access_violation_exception()
|
||||
&& test_illegal_instruction_exception();
|
||||
return test_access_violation_exception() && test_illegal_instruction_exception();
|
||||
}
|
||||
|
||||
void print_time()
|
||||
@@ -298,12 +294,12 @@ void print_time()
|
||||
}
|
||||
|
||||
#define RUN_TEST(func, name) \
|
||||
{ \
|
||||
{ \
|
||||
printf("Running test '" name "': "); \
|
||||
const auto res = func(); \
|
||||
valid &= res; \
|
||||
puts(res ? "Success" : "Fail"); \
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
template <typename ReturnType, typename... Args>
|
||||
class function_wrapper : public object
|
||||
{
|
||||
public:
|
||||
public:
|
||||
using user_data_pointer = void*;
|
||||
using c_function_type = ReturnType(Args..., user_data_pointer);
|
||||
using functor_type = std::function<ReturnType(Args...)>;
|
||||
@@ -22,8 +22,7 @@ public:
|
||||
|
||||
c_function_type* get_c_function() const
|
||||
{
|
||||
return +[](Args... args, user_data_pointer user_data) -> ReturnType
|
||||
{
|
||||
return +[](Args... args, user_data_pointer user_data) -> ReturnType {
|
||||
return (*static_cast<functor_type*>(user_data))(std::forward<Args>(args)...);
|
||||
};
|
||||
}
|
||||
@@ -38,6 +37,6 @@ public:
|
||||
return this->functor_.get();
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
std::unique_ptr<functor_type> functor_{};
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4505)
|
||||
#pragma warning(disable : 4505)
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
@@ -28,8 +28,8 @@ namespace unicorn
|
||||
struct unicorn_error : std::runtime_error
|
||||
{
|
||||
unicorn_error(const uc_err error_code)
|
||||
: std::runtime_error(uc_strerror(error_code))
|
||||
, code(error_code)
|
||||
: std::runtime_error(uc_strerror(error_code)),
|
||||
code(error_code)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ namespace unicorn
|
||||
}
|
||||
|
||||
unicorn_hook(uc_engine* uc, const uc_hook hook)
|
||||
: uc_(uc)
|
||||
, hook_(hook)
|
||||
: uc_(uc),
|
||||
hook_(hook)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ namespace unicorn
|
||||
unicorn_hook(const unicorn_hook&) = delete;
|
||||
unicorn_hook& operator=(const unicorn_hook&) = delete;
|
||||
|
||||
|
||||
unicorn_hook(unicorn_hook&& obj) noexcept
|
||||
{
|
||||
this->operator=(std::move(obj));
|
||||
|
||||
@@ -14,7 +14,6 @@ namespace unicorn
|
||||
uce(uc_mem_regions(uc, &this->regions_, &this->count_));
|
||||
}
|
||||
|
||||
|
||||
~unicorn_memory_regions()
|
||||
{
|
||||
this->release();
|
||||
|
||||
@@ -85,8 +85,7 @@ namespace unicorn
|
||||
{
|
||||
public:
|
||||
template <typename T>
|
||||
requires(std::is_base_of_v<object, T>
|
||||
&& std::is_move_constructible_v<T>)
|
||||
requires(std::is_base_of_v<object, T> && std::is_move_constructible_v<T>)
|
||||
void add(T data, unicorn_hook hook)
|
||||
{
|
||||
hook_entry entry{};
|
||||
@@ -178,9 +177,7 @@ namespace unicorn
|
||||
const std::shared_ptr<complex_memory_hook_callback>& callback)
|
||||
{
|
||||
function_wrapper<void, uc_engine*, uc_mem_type, uint64_t, int, int64_t> wrapper(
|
||||
[callback](uc_engine*, const uc_mem_type type, const uint64_t address, const int size,
|
||||
const int64_t)
|
||||
{
|
||||
[callback](uc_engine*, const uc_mem_type type, const uint64_t address, const int size, const int64_t) {
|
||||
const auto operation = map_memory_operation(type);
|
||||
if (operation != memory_permission::none)
|
||||
{
|
||||
@@ -201,8 +198,7 @@ namespace unicorn
|
||||
{
|
||||
function_wrapper<void, uc_engine*, uc_mem_type, uint64_t, int, int64_t> wrapper(
|
||||
[callback](uc_engine*, const uc_mem_type type, const uint64_t address, const int size,
|
||||
const uint64_t value)
|
||||
{
|
||||
const uint64_t value) {
|
||||
const auto operation = map_memory_operation(type);
|
||||
if (operation != memory_permission::none)
|
||||
{
|
||||
@@ -222,15 +218,14 @@ namespace unicorn
|
||||
const std::shared_ptr<complex_memory_hook_callback>& callback)
|
||||
{
|
||||
function_wrapper<void, uc_engine*, uint64_t, uint32_t> wrapper(
|
||||
[callback](uc_engine*, const uint64_t address, const uint32_t size)
|
||||
{
|
||||
[callback](uc_engine*, const uint64_t address, const uint32_t size) {
|
||||
(*callback)(address, size, 0, memory_permission::exec);
|
||||
});
|
||||
|
||||
unicorn_hook hook{uc};
|
||||
|
||||
uce(uc_hook_add(uc, hook.make_reference(), UC_HOOK_CODE, wrapper.get_function(),
|
||||
wrapper.get_user_data(), address, address + size));
|
||||
uce(uc_hook_add(uc, hook.make_reference(), UC_HOOK_CODE, wrapper.get_function(), wrapper.get_user_data(),
|
||||
address, address + size));
|
||||
|
||||
container.add(std::move(wrapper), std::move(hook));
|
||||
}
|
||||
@@ -281,8 +276,7 @@ namespace unicorn
|
||||
|
||||
this->has_violation_ = false;
|
||||
const auto timeoutYs = std::chrono::duration_cast<std::chrono::microseconds>(timeout);
|
||||
const auto res = uc_emu_start(*this, start, end, static_cast<uint64_t>(timeoutYs.count()),
|
||||
count);
|
||||
const auto res = uc_emu_start(*this, start, end, static_cast<uint64_t>(timeoutYs.count()), count);
|
||||
if (res == UC_ERR_OK)
|
||||
{
|
||||
return;
|
||||
@@ -314,8 +308,8 @@ namespace unicorn
|
||||
|
||||
if (size < result_size)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"Register size mismatch: " + std::to_string(size) + " != " + std::to_string(result_size));
|
||||
throw std::runtime_error("Register size mismatch: " + std::to_string(size) +
|
||||
" != " + std::to_string(result_size));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,27 +321,21 @@ namespace unicorn
|
||||
|
||||
if (size < result_size)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"Register size mismatch: " + std::to_string(size) + " != " + std::to_string(result_size));
|
||||
throw std::runtime_error("Register size mismatch: " + std::to_string(size) +
|
||||
" != " + std::to_string(result_size));
|
||||
}
|
||||
}
|
||||
|
||||
void map_mmio(const uint64_t address, const size_t size, mmio_read_callback read_cb,
|
||||
mmio_write_callback write_cb) override
|
||||
{
|
||||
mmio_callbacks cb{
|
||||
.read = mmio_callbacks::read_wrapper(
|
||||
[c = std::move(read_cb)](uc_engine*, const uint64_t addr, const uint32_t s)
|
||||
{
|
||||
mmio_callbacks cb{.read = mmio_callbacks::read_wrapper(
|
||||
[c = std::move(read_cb)](uc_engine*, const uint64_t addr, const uint32_t s) {
|
||||
return c(addr, s);
|
||||
}),
|
||||
.write = mmio_callbacks::write_wrapper(
|
||||
[c = std::move(write_cb)](uc_engine*, const uint64_t addr, const uint32_t s,
|
||||
const uint64_t value)
|
||||
{
|
||||
c(addr, s, value);
|
||||
})
|
||||
};
|
||||
const uint64_t value) { c(addr, s, value); })};
|
||||
|
||||
uce(uc_mmio_map(*this, address, size, cb.read.get_c_function(), cb.read.get_user_data(),
|
||||
cb.write.get_c_function(), cb.write.get_user_data()));
|
||||
@@ -392,14 +380,10 @@ namespace unicorn
|
||||
uce(uc_mem_protect(*this, address, size, static_cast<uint32_t>(permissions)));
|
||||
}
|
||||
|
||||
emulator_hook* hook_instruction(int instruction_type,
|
||||
instruction_hook_callback callback) override
|
||||
emulator_hook* hook_instruction(int instruction_type, instruction_hook_callback callback) override
|
||||
{
|
||||
function_wrapper<int, uc_engine*> wrapper([c = std::move(callback)](uc_engine*)
|
||||
{
|
||||
return (c() == instruction_hook_continuation::skip_instruction)
|
||||
? 1
|
||||
: 0;
|
||||
function_wrapper<int, uc_engine*> wrapper([c = std::move(callback)](uc_engine*) {
|
||||
return (c() == instruction_hook_continuation::skip_instruction) ? 1 : 0;
|
||||
});
|
||||
|
||||
unicorn_hook hook{*this};
|
||||
@@ -432,8 +416,7 @@ namespace unicorn
|
||||
emulator_hook* hook_basic_block(basic_block_hook_callback callback) override
|
||||
{
|
||||
function_wrapper<void, uc_engine*, uint64_t, size_t> wrapper(
|
||||
[c = std::move(callback)](uc_engine*, const uint64_t address, const size_t size)
|
||||
{
|
||||
[c = std::move(callback)](uc_engine*, const uint64_t address, const size_t size) {
|
||||
basic_block block{};
|
||||
block.address = address;
|
||||
block.size = size;
|
||||
@@ -445,8 +428,7 @@ namespace unicorn
|
||||
auto container = std::make_unique<hook_container>();
|
||||
|
||||
uce(uc_hook_add(*this, hook.make_reference(), UC_HOOK_BLOCK, wrapper.get_function(),
|
||||
wrapper.get_user_data(), 0, std::numeric_limits<pointer_type>::max())
|
||||
);
|
||||
wrapper.get_user_data(), 0, std::numeric_limits<pointer_type>::max()));
|
||||
|
||||
container->add(std::move(wrapper), std::move(hook));
|
||||
|
||||
@@ -458,8 +440,7 @@ namespace unicorn
|
||||
emulator_hook* hook_edge_generation(edge_generation_hook_callback callback) override
|
||||
{
|
||||
function_wrapper<void, uc_engine*, uc_tb*, uc_tb*> wrapper(
|
||||
[c = std::move(callback)](uc_engine*, const uc_tb* cur_tb, const uc_tb* prev_tb)
|
||||
{
|
||||
[c = std::move(callback)](uc_engine*, const uc_tb* cur_tb, const uc_tb* prev_tb) {
|
||||
const auto current_block = map_block(*cur_tb);
|
||||
const auto previous_block = map_block(*prev_tb);
|
||||
|
||||
@@ -470,8 +451,7 @@ namespace unicorn
|
||||
auto container = std::make_unique<hook_container>();
|
||||
|
||||
uce(uc_hook_add(*this, hook.make_reference(), UC_HOOK_EDGE_GENERATED, wrapper.get_function(),
|
||||
wrapper.get_user_data(), 0, std::numeric_limits<pointer_type>::max())
|
||||
);
|
||||
wrapper.get_user_data(), 0, std::numeric_limits<pointer_type>::max()));
|
||||
|
||||
container->add(std::move(wrapper), std::move(hook));
|
||||
|
||||
@@ -483,17 +463,13 @@ namespace unicorn
|
||||
emulator_hook* hook_interrupt(interrupt_hook_callback callback) override
|
||||
{
|
||||
function_wrapper<void, uc_engine*, int> wrapper(
|
||||
[c = std::move(callback)](uc_engine*, const int interrupt_type)
|
||||
{
|
||||
c(interrupt_type);
|
||||
});
|
||||
[c = std::move(callback)](uc_engine*, const int interrupt_type) { c(interrupt_type); });
|
||||
|
||||
unicorn_hook hook{*this};
|
||||
auto container = std::make_unique<hook_container>();
|
||||
|
||||
uce(uc_hook_add(*this, hook.make_reference(), UC_HOOK_INTR, wrapper.get_function(),
|
||||
wrapper.get_user_data(), 0, std::numeric_limits<pointer_type>::max())
|
||||
);
|
||||
wrapper.get_user_data(), 0, std::numeric_limits<pointer_type>::max()));
|
||||
|
||||
container->add(std::move(wrapper), std::move(hook));
|
||||
|
||||
@@ -506,9 +482,8 @@ namespace unicorn
|
||||
memory_violation_hook_callback callback) override
|
||||
{
|
||||
function_wrapper<bool, uc_engine*, uc_mem_type, uint64_t, int, int64_t> wrapper(
|
||||
[c = std::move(callback), this](uc_engine*, const uc_mem_type type,
|
||||
const uint64_t address, const int size, const int64_t)
|
||||
{
|
||||
[c = std::move(callback), this](uc_engine*, const uc_mem_type type, const uint64_t address,
|
||||
const int size, const int64_t) {
|
||||
const auto ip = this->read_instruction_pointer();
|
||||
|
||||
assert(size >= 0);
|
||||
@@ -584,8 +559,8 @@ namespace unicorn
|
||||
|
||||
void delete_hook(emulator_hook* hook) override
|
||||
{
|
||||
const auto entry = std::ranges::find_if(this->hooks_, [&](const std::unique_ptr<hook_object>& hook_ptr)
|
||||
{
|
||||
const auto entry =
|
||||
std::ranges::find_if(this->hooks_, [&](const std::unique_ptr<hook_object>& hook_ptr) {
|
||||
return hook_ptr->as_opaque_hook() == hook;
|
||||
});
|
||||
|
||||
|
||||
@@ -4,19 +4,19 @@
|
||||
#include <windows_emulator.hpp>
|
||||
|
||||
#define ASSERT_NOT_TERMINATED(win_emu) \
|
||||
do { \
|
||||
do \
|
||||
{ \
|
||||
ASSERT_FALSE((win_emu).process().exit_status.has_value()); \
|
||||
} while(false)
|
||||
|
||||
} while (false)
|
||||
|
||||
#define ASSERT_TERMINATED_WITH_STATUS(win_emu, status) \
|
||||
do { \
|
||||
do \
|
||||
{ \
|
||||
ASSERT_TRUE((win_emu).process().exit_status.has_value()); \
|
||||
ASSERT_EQ(*(win_emu).process().exit_status, status); \
|
||||
} while(false)
|
||||
} while (false)
|
||||
|
||||
#define ASSERT_TERMINATED_SUCCESSFULLY(win_emu) \
|
||||
ASSERT_TERMINATED_WITH_STATUS(win_emu, STATUS_SUCCESS)
|
||||
#define ASSERT_TERMINATED_SUCCESSFULLY(win_emu) ASSERT_TERMINATED_WITH_STATUS(win_emu, STATUS_SUCCESS)
|
||||
|
||||
namespace test
|
||||
{
|
||||
@@ -28,8 +28,7 @@ namespace test
|
||||
|
||||
inline windows_emulator create_sample_emulator()
|
||||
{
|
||||
emulator_settings settings
|
||||
{
|
||||
emulator_settings settings{
|
||||
.disable_logging = true,
|
||||
.use_relative_time = true,
|
||||
};
|
||||
|
||||
@@ -8,10 +8,7 @@ namespace test
|
||||
|
||||
const emulator_settings settings{
|
||||
.arguments = {u"-time"},
|
||||
.stdout_callback = [&output_buffer](const std::string_view data)
|
||||
{
|
||||
output_buffer.append(data);
|
||||
},
|
||||
.stdout_callback = [&output_buffer](const std::string_view data) { output_buffer.append(data); },
|
||||
.disable_logging = true,
|
||||
.use_relative_time = false,
|
||||
};
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
|
||||
#include <utils/finally.hpp>
|
||||
|
||||
extern "C" {
|
||||
extern "C"
|
||||
{
|
||||
#include <gdbstub.h>
|
||||
}
|
||||
|
||||
@@ -114,8 +115,7 @@ namespace
|
||||
bool run_gdb_stub(gdb_stub_handler& handler, std::string target_description, const size_t register_count,
|
||||
std::string bind_address)
|
||||
{
|
||||
const arch_info_t info
|
||||
{
|
||||
const arch_info_t info{
|
||||
target_description.data(),
|
||||
static_cast<int>(register_count),
|
||||
sizeof(uint64_t),
|
||||
@@ -130,10 +130,7 @@ bool run_gdb_stub(gdb_stub_handler& handler, std::string target_description, con
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto _ = utils::finally([&]
|
||||
{
|
||||
gdbstub_close(&stub);
|
||||
});
|
||||
const auto _ = utils::finally([&] { gdbstub_close(&stub); });
|
||||
|
||||
return gdbstub_run(&stub, &handler);
|
||||
}
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
|
||||
class win_x64_gdb_stub_handler : public x64_gdb_stub_handler
|
||||
{
|
||||
public:
|
||||
public:
|
||||
win_x64_gdb_stub_handler(windows_emulator& win_emu)
|
||||
: x64_gdb_stub_handler(win_emu.emu())
|
||||
, win_emu_(&win_emu)
|
||||
: x64_gdb_stub_handler(win_emu.emu()),
|
||||
win_emu_(&win_emu)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -40,6 +40,6 @@ public:
|
||||
return gdb_action::resume;
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
windows_emulator* win_emu_{};
|
||||
};
|
||||
|
||||
@@ -4,24 +4,9 @@
|
||||
#include "scoped_hook.hpp"
|
||||
|
||||
inline std::vector gdb_registers{
|
||||
x64_register::rax,
|
||||
x64_register::rbx,
|
||||
x64_register::rcx,
|
||||
x64_register::rdx,
|
||||
x64_register::rsi,
|
||||
x64_register::rdi,
|
||||
x64_register::rbp,
|
||||
x64_register::rsp,
|
||||
x64_register::r8,
|
||||
x64_register::r9,
|
||||
x64_register::r10,
|
||||
x64_register::r11,
|
||||
x64_register::r12,
|
||||
x64_register::r13,
|
||||
x64_register::r14,
|
||||
x64_register::r15,
|
||||
x64_register::rip,
|
||||
x64_register::rflags,
|
||||
x64_register::rax, x64_register::rbx, x64_register::rcx, x64_register::rdx, x64_register::rsi, x64_register::rdi,
|
||||
x64_register::rbp, x64_register::rsp, x64_register::r8, x64_register::r9, x64_register::r10, x64_register::r11,
|
||||
x64_register::r12, x64_register::r13, x64_register::r14, x64_register::r15, x64_register::rip, x64_register::rflags,
|
||||
/*x64_register::cs,
|
||||
x64_register::ss,
|
||||
x64_register::ds,
|
||||
@@ -65,15 +50,14 @@ struct std::hash<breakpoint_key>
|
||||
{
|
||||
std::size_t operator()(const breakpoint_key& k) const noexcept
|
||||
{
|
||||
return ((std::hash<size_t>()(k.addr)
|
||||
^ (std::hash<size_t>()(k.size) << 1)) >> 1)
|
||||
^ (std::hash<size_t>()(static_cast<size_t>(k.type)) << 1);
|
||||
return ((std::hash<size_t>()(k.addr) ^ (std::hash<size_t>()(k.size) << 1)) >> 1) ^
|
||||
(std::hash<size_t>()(static_cast<size_t>(k.type)) << 1);
|
||||
}
|
||||
};
|
||||
|
||||
class x64_gdb_stub_handler : public gdb_stub_handler
|
||||
{
|
||||
public:
|
||||
public:
|
||||
x64_gdb_stub_handler(x64_emulator& emu)
|
||||
: emu_(&emu)
|
||||
{
|
||||
@@ -169,12 +153,10 @@ public:
|
||||
{
|
||||
try
|
||||
{
|
||||
this->hooks_[{addr, size, type}] = scoped_hook(*this->emu_, this->emu_->hook_memory_access(
|
||||
this->hooks_[{addr, size, type}] = scoped_hook(
|
||||
*this->emu_, this->emu_->hook_memory_access(
|
||||
addr, size, map_breakpoint_type(type),
|
||||
[this](uint64_t, size_t, uint64_t, memory_operation)
|
||||
{
|
||||
this->on_interrupt();
|
||||
}));
|
||||
[this](uint64_t, size_t, uint64_t, memory_operation) { this->on_interrupt(); }));
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -209,7 +191,7 @@ public:
|
||||
this->emu_->stop();
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
x64_emulator* emu_{};
|
||||
std::unordered_map<breakpoint_key, scoped_hook> hooks_{};
|
||||
};
|
||||
|
||||
@@ -32,8 +32,8 @@ namespace
|
||||
return win_emu.emu().read_memory<afd_creation_data>(data.buffer);
|
||||
}
|
||||
|
||||
std::pair<AFD_POLL_INFO64, std::vector<AFD_POLL_HANDLE_INFO64>> get_poll_info(
|
||||
windows_emulator& win_emu, const io_device_context& c)
|
||||
std::pair<AFD_POLL_INFO64, std::vector<AFD_POLL_HANDLE_INFO64>> get_poll_info(windows_emulator& win_emu,
|
||||
const io_device_context& c)
|
||||
{
|
||||
constexpr auto info_size = offsetof(AFD_POLL_INFO64, Handles);
|
||||
if (!c.input_buffer || c.input_buffer_length < info_size)
|
||||
@@ -170,10 +170,8 @@ namespace
|
||||
|
||||
assert(current_index == static_cast<size_t>(count));
|
||||
|
||||
emulator_object<AFD_POLL_INFO64>{win_emu.emu(), c.input_buffer}.access([&](AFD_POLL_INFO64& info)
|
||||
{
|
||||
info.NumberOfHandles = static_cast<ULONG>(current_index);
|
||||
});
|
||||
emulator_object<AFD_POLL_INFO64>{win_emu.emu(), c.input_buffer}.access(
|
||||
[&](AFD_POLL_INFO64& info) { info.NumberOfHandles = static_cast<ULONG>(current_index); });
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
@@ -259,10 +257,7 @@ namespace
|
||||
}
|
||||
|
||||
this->executing_delayed_ioctl_ = true;
|
||||
const auto _ = utils::finally([&]
|
||||
{
|
||||
this->executing_delayed_ioctl_ = false;
|
||||
});
|
||||
const auto _ = utils::finally([&] { this->executing_delayed_ioctl_ = false; });
|
||||
|
||||
if (this->require_poll_.has_value())
|
||||
{
|
||||
@@ -510,9 +505,9 @@ namespace
|
||||
|
||||
const auto data = emu.read_memory(buffer.buf, buffer.len);
|
||||
|
||||
const auto sent_data = sendto(*this->s_, reinterpret_cast<const char*>(data.data()),
|
||||
static_cast<send_size>(data.size()), 0 /* ? */, &target.get_addr(),
|
||||
target.get_size());
|
||||
const auto sent_data =
|
||||
sendto(*this->s_, reinterpret_cast<const char*>(data.data()), static_cast<send_size>(data.size()),
|
||||
0 /* ? */, &target.get_addr(), target.get_size());
|
||||
|
||||
if (sent_data < 0)
|
||||
{
|
||||
|
||||
@@ -117,10 +117,8 @@ struct AFD_POLL_INFO64
|
||||
#define AFD_NUM_POLL_EVENTS 11
|
||||
#define AFD_POLL_ALL ((1 << AFD_NUM_POLL_EVENTS) - 1)
|
||||
|
||||
#define _AFD_REQUEST(ioctl) \
|
||||
((((ULONG)(ioctl)) >> 2) & 0x03FF)
|
||||
#define _AFD_BASE(ioctl) \
|
||||
((((ULONG)(ioctl)) >> 12) & 0xFFFFF)
|
||||
#define _AFD_REQUEST(ioctl) ((((ULONG)(ioctl)) >> 2) & 0x03FF)
|
||||
#define _AFD_BASE(ioctl) ((((ULONG)(ioctl)) >> 12) & 0xFFFFF)
|
||||
|
||||
#define FSCTL_AFD_BASE FILE_DEVICE_NETWORK
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ class object_wrapper
|
||||
{
|
||||
T* obj_;
|
||||
|
||||
public:
|
||||
public:
|
||||
object_wrapper(T& obj)
|
||||
: obj_(&obj)
|
||||
{
|
||||
@@ -45,7 +45,7 @@ using windows_emulator_wrapper = object_wrapper<windows_emulator>;
|
||||
template <typename T>
|
||||
class emulator_object
|
||||
{
|
||||
public:
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
emulator_object(const x64_emulator_wrapper& wrapper, const uint64_t address = 0)
|
||||
@@ -54,8 +54,8 @@ public:
|
||||
}
|
||||
|
||||
emulator_object(emulator& emu, const uint64_t address = 0)
|
||||
: emu_(&emu)
|
||||
, address_(address)
|
||||
: emu_(&emu),
|
||||
address_(address)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -135,26 +135,25 @@ public:
|
||||
this->address_ = address;
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
emulator* emu_{};
|
||||
uint64_t address_{};
|
||||
};
|
||||
|
||||
|
||||
// TODO: warning emulator_utils is hardcoded for 64bit unicode_string usage
|
||||
class emulator_allocator
|
||||
{
|
||||
public:
|
||||
public:
|
||||
emulator_allocator(emulator& emu)
|
||||
: emu_(&emu)
|
||||
{
|
||||
}
|
||||
|
||||
emulator_allocator(emulator& emu, const uint64_t address, const uint64_t size)
|
||||
: emu_(&emu)
|
||||
, address_(address)
|
||||
, size_(size)
|
||||
, active_address_(address)
|
||||
: emu_(&emu),
|
||||
address_(address),
|
||||
size_(size),
|
||||
active_address_(address)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -181,7 +180,6 @@ public:
|
||||
return emulator_object<T>(*this->emu_, potential_start);
|
||||
}
|
||||
|
||||
|
||||
char16_t* copy_string(const std::u16string_view str)
|
||||
{
|
||||
UNICODE_STRING<EmulatorTraits<Emu64>> uc_str{};
|
||||
@@ -211,10 +209,8 @@ public:
|
||||
{
|
||||
const auto unicode_string = this->reserve<UNICODE_STRING<EmulatorTraits<Emu64>>>();
|
||||
|
||||
unicode_string.access([&](UNICODE_STRING<EmulatorTraits<Emu64>>& unicode_str)
|
||||
{
|
||||
this->make_unicode_string(unicode_str, str);
|
||||
});
|
||||
unicode_string.access(
|
||||
[&](UNICODE_STRING<EmulatorTraits<Emu64>>& unicode_str) { this->make_unicode_string(unicode_str, str); });
|
||||
|
||||
return unicode_string;
|
||||
}
|
||||
@@ -263,14 +259,13 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
emulator* emu_{};
|
||||
uint64_t address_{};
|
||||
uint64_t size_{};
|
||||
uint64_t active_address_{0};
|
||||
};
|
||||
|
||||
|
||||
inline std::u16string read_unicode_string(const emulator& emu, const UNICODE_STRING<EmulatorTraits<Emu64>> ucs)
|
||||
{
|
||||
static_assert(offsetof(UNICODE_STRING<EmulatorTraits<Emu64>>, Length) == 0);
|
||||
@@ -286,7 +281,6 @@ inline std::u16string read_unicode_string(const emulator& emu, const UNICODE_STR
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
inline std::u16string read_unicode_string(const emulator& emu,
|
||||
const emulator_object<UNICODE_STRING<EmulatorTraits<Emu64>>> uc_string)
|
||||
{
|
||||
|
||||
@@ -121,7 +121,7 @@ template <handle_types::type Type, typename T, uint32_t IndexShift = 0>
|
||||
requires(utils::Serializable<T>)
|
||||
class handle_store : public generic_handle_store
|
||||
{
|
||||
public:
|
||||
public:
|
||||
using index_type = uint32_t;
|
||||
using value_map = std::map<index_type, T>;
|
||||
|
||||
@@ -319,7 +319,7 @@ public:
|
||||
return this->store_.end();
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
typename value_map::iterator get_iterator(const handle_value h)
|
||||
{
|
||||
if (h.type != Type || h.is_pseudo)
|
||||
|
||||
@@ -14,11 +14,8 @@ namespace
|
||||
|
||||
std::unique_ptr<io_device> create_device(const std::u16string_view device)
|
||||
{
|
||||
if (device == u"CNG"
|
||||
|| device == u"KsecDD"
|
||||
|| device == u"PcwDrv"
|
||||
|| device == u"DeviceApi\\CMApi"
|
||||
|| device == u"ConDrv\\Server")
|
||||
if (device == u"CNG" || device == u"KsecDD" || device == u"PcwDrv" || device == u"DeviceApi\\CMApi" ||
|
||||
device == u"ConDrv\\Server")
|
||||
{
|
||||
return std::make_unique<dummy_device>();
|
||||
}
|
||||
|
||||
@@ -70,10 +70,8 @@ inline void write_io_status(const emulator_object<IO_STATUS_BLOCK<EmulatorTraits
|
||||
{
|
||||
if (io_status_block)
|
||||
{
|
||||
io_status_block.access([&](IO_STATUS_BLOCK<EmulatorTraits<Emu64>>& status_block)
|
||||
{
|
||||
status_block.Status = status;
|
||||
});
|
||||
io_status_block.access(
|
||||
[&](IO_STATUS_BLOCK<EmulatorTraits<Emu64>>& status_block) { status_block.Status = status; });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +134,7 @@ std::unique_ptr<io_device> create_device(std::u16string_view device);
|
||||
|
||||
class io_device_container : public io_device
|
||||
{
|
||||
public:
|
||||
public:
|
||||
io_device_container() = default;
|
||||
|
||||
io_device_container(std::u16string device, windows_emulator& win_emu, const io_device_creation_data& data)
|
||||
@@ -182,7 +180,7 @@ public:
|
||||
return dynamic_cast<T*>(value);
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
std::u16string device_name_{};
|
||||
std::unique_ptr<io_device> device_{};
|
||||
|
||||
|
||||
@@ -103,8 +103,8 @@ namespace utils
|
||||
}
|
||||
|
||||
kusd_mmio::kusd_mmio(x64_emulator& emu, process_context& process)
|
||||
: emu_(&emu)
|
||||
, process_(&process)
|
||||
: emu_(&emu),
|
||||
process_(&process)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -205,12 +205,10 @@ void kusd_mmio::register_mmio()
|
||||
|
||||
this->registered_ = true;
|
||||
|
||||
this->emu_->allocate_mmio(KUSD_ADDRESS, KUSD_BUFFER_SIZE,
|
||||
[this](const uint64_t addr, const size_t size)
|
||||
{
|
||||
return this->read(addr, size);
|
||||
}, [](const uint64_t, const size_t, const uint64_t)
|
||||
{
|
||||
this->emu_->allocate_mmio(
|
||||
KUSD_ADDRESS, KUSD_BUFFER_SIZE,
|
||||
[this](const uint64_t addr, const size_t size) { return this->read(addr, size); },
|
||||
[](const uint64_t, const size_t, const uint64_t) {
|
||||
// Writing not supported!
|
||||
});
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ class windows_emulator;
|
||||
|
||||
class kusd_mmio
|
||||
{
|
||||
public:
|
||||
public:
|
||||
kusd_mmio(x64_emulator& emu, process_context& process);
|
||||
~kusd_mmio();
|
||||
|
||||
@@ -38,7 +38,7 @@ public:
|
||||
|
||||
void setup(bool use_relative_time);
|
||||
|
||||
private:
|
||||
private:
|
||||
x64_emulator* emu_{};
|
||||
process_context* process_{};
|
||||
|
||||
|
||||
@@ -24,17 +24,27 @@ namespace
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case black: return COLOR(0x8, "\033[0;90m");
|
||||
case red: return COLOR(0xC, "\033[0;91m");
|
||||
case green: return COLOR(0xA, "\033[0;92m");
|
||||
case yellow: return COLOR(0xE, "\033[0;93m");
|
||||
case blue: return COLOR(0x9, "\033[0;94m");
|
||||
case cyan: return COLOR(0xB, "\033[0;96m");
|
||||
case pink: return COLOR(0xD, "\033[0;95m");
|
||||
case white: return COLOR(0xF, "\033[0;97m");
|
||||
case dark_gray: return COLOR(0x8, "\033[0;97m");
|
||||
case black:
|
||||
return COLOR(0x8, "\033[0;90m");
|
||||
case red:
|
||||
return COLOR(0xC, "\033[0;91m");
|
||||
case green:
|
||||
return COLOR(0xA, "\033[0;92m");
|
||||
case yellow:
|
||||
return COLOR(0xE, "\033[0;93m");
|
||||
case blue:
|
||||
return COLOR(0x9, "\033[0;94m");
|
||||
case cyan:
|
||||
return COLOR(0xB, "\033[0;96m");
|
||||
case pink:
|
||||
return COLOR(0xD, "\033[0;95m");
|
||||
case white:
|
||||
return COLOR(0xF, "\033[0;97m");
|
||||
case dark_gray:
|
||||
return COLOR(0x8, "\033[0;97m");
|
||||
case gray:
|
||||
default: return get_reset_color();
|
||||
default:
|
||||
return get_reset_color();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,14 +81,15 @@ namespace
|
||||
const int count = vsnprintf(buffer, sizeof(buffer), message, *ap);
|
||||
#endif
|
||||
|
||||
if (count < 0) return {};
|
||||
if (count < 0)
|
||||
return {};
|
||||
return {buffer, static_cast<size_t>(count)};
|
||||
}
|
||||
|
||||
#define format_to_string(msg, str)\
|
||||
va_list ap;\
|
||||
va_start(ap, msg);\
|
||||
const auto str = format(&ap, msg);\
|
||||
#define format_to_string(msg, str) \
|
||||
va_list ap; \
|
||||
va_start(ap, msg); \
|
||||
const auto str = format(&ap, msg); \
|
||||
va_end(ap);
|
||||
|
||||
void print_colored(const std::string_view& line, const color_type base_color)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#ifdef OS_WINDOWS
|
||||
#define FORMAT_ATTRIBUTE(fmt_pos, var_pos)
|
||||
#else
|
||||
#define FORMAT_ATTRIBUTE(fmt_pos, var_pos) __attribute__((format( printf, fmt_pos, var_pos)))
|
||||
#define FORMAT_ATTRIBUTE(fmt_pos, var_pos) __attribute__((format(printf, fmt_pos, var_pos)))
|
||||
#endif
|
||||
|
||||
enum class color
|
||||
@@ -22,7 +22,7 @@ enum class color
|
||||
|
||||
class logger
|
||||
{
|
||||
public:
|
||||
public:
|
||||
void print(color c, std::string_view message) const;
|
||||
void print(color c, const char* message, ...) const FORMAT_ATTRIBUTE(3, 4);
|
||||
void info(const char* message, ...) const FORMAT_ATTRIBUTE(2, 3);
|
||||
@@ -41,6 +41,6 @@ public:
|
||||
return this->disable_output_;
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
bool disable_output_{false};
|
||||
};
|
||||
|
||||
@@ -6,7 +6,7 @@ class logger;
|
||||
|
||||
class module_manager
|
||||
{
|
||||
public:
|
||||
public:
|
||||
module_manager(emulator& emu);
|
||||
|
||||
mapped_module* map_module(const std::filesystem::path& file, logger& logger);
|
||||
@@ -38,7 +38,7 @@ public:
|
||||
|
||||
bool unmap(const uint64_t address);
|
||||
|
||||
private:
|
||||
private:
|
||||
emulator* emu_{};
|
||||
|
||||
using module_map = std::map<uint64_t, mapped_module>;
|
||||
|
||||
@@ -10,8 +10,8 @@ namespace
|
||||
uint64_t get_first_section_offset(const PENTHeaders_t<std::uint64_t>& nt_headers, const uint64_t nt_headers_offset)
|
||||
{
|
||||
const uint8_t* nt_headers_addr = reinterpret_cast<const uint8_t*>(&nt_headers);
|
||||
size_t optional_header_offset = reinterpret_cast<uintptr_t>(&(nt_headers.OptionalHeader)) - reinterpret_cast<
|
||||
uintptr_t>(&nt_headers);
|
||||
size_t optional_header_offset =
|
||||
reinterpret_cast<uintptr_t>(&(nt_headers.OptionalHeader)) - reinterpret_cast<uintptr_t>(&nt_headers);
|
||||
size_t optional_header_size = nt_headers.FileHeader.SizeOfOptionalHeader;
|
||||
const uint8_t* first_section_addr = nt_headers_addr + optional_header_offset + optional_header_size;
|
||||
|
||||
@@ -38,11 +38,10 @@ namespace
|
||||
return;
|
||||
}
|
||||
|
||||
const auto export_directory = buffer.as<IMAGE_EXPORT_DIRECTORY>(export_directory_entry.
|
||||
VirtualAddress).get();
|
||||
const auto export_directory = buffer.as<IMAGE_EXPORT_DIRECTORY>(export_directory_entry.VirtualAddress).get();
|
||||
|
||||
const auto names_count = export_directory.NumberOfNames;
|
||||
//const auto function_count = export_directory.NumberOfFunctions;
|
||||
// const auto function_count = export_directory.NumberOfFunctions;
|
||||
|
||||
const auto names = buffer.as<DWORD>(export_directory.AddressOfNames);
|
||||
const auto ordinals = buffer.as<WORD>(export_directory.AddressOfNameOrdinals);
|
||||
@@ -142,8 +141,7 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
void map_sections(emulator& emu, mapped_module& binary,
|
||||
const utils::safe_buffer_accessor<const uint8_t> buffer,
|
||||
void map_sections(emulator& emu, mapped_module& binary, const utils::safe_buffer_accessor<const uint8_t> buffer,
|
||||
const PENTHeaders_t<std::uint64_t>& nt_headers, const uint64_t nt_headers_offset)
|
||||
{
|
||||
const auto first_section_offset = get_first_section_offset(nt_headers, nt_headers_offset);
|
||||
@@ -197,8 +195,7 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
mapped_module map_module_from_data(emulator& emu, const std::span<const uint8_t> data,
|
||||
std::filesystem::path file)
|
||||
mapped_module map_module_from_data(emulator& emu, const std::span<const uint8_t> data, std::filesystem::path file)
|
||||
{
|
||||
mapped_module binary{};
|
||||
binary.path = std::move(file);
|
||||
@@ -224,12 +221,10 @@ mapped_module map_module_from_data(emulator& emu, const std::span<const uint8_t>
|
||||
{
|
||||
binary.image_base = emu.find_free_allocation_base(binary.size_of_image);
|
||||
const auto is_dll = nt_headers.FileHeader.Characteristics & IMAGE_FILE_DLL;
|
||||
const auto has_dynamic_base =
|
||||
optional_header.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
|
||||
const auto has_dynamic_base = optional_header.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
|
||||
const auto is_relocatable = is_dll || has_dynamic_base;
|
||||
|
||||
if (!is_relocatable || !emu.allocate_memory(binary.image_base, binary.size_of_image,
|
||||
memory_permission::read))
|
||||
if (!is_relocatable || !emu.allocate_memory(binary.image_base, binary.size_of_image, memory_permission::read))
|
||||
{
|
||||
throw std::runtime_error("Memory range not allocatable");
|
||||
}
|
||||
@@ -238,8 +233,7 @@ mapped_module map_module_from_data(emulator& emu, const std::span<const uint8_t>
|
||||
binary.entry_point = binary.image_base + optional_header.AddressOfEntryPoint;
|
||||
|
||||
const auto* header_buffer = buffer.get_pointer_for_range(0, optional_header.SizeOfHeaders);
|
||||
emu.write_memory(binary.image_base, header_buffer,
|
||||
optional_header.SizeOfHeaders);
|
||||
emu.write_memory(binary.image_base, header_buffer, optional_header.SizeOfHeaders);
|
||||
|
||||
map_sections(emu, binary, buffer, nt_headers, nt_headers_offset);
|
||||
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
#include <x64_emulator.hpp>
|
||||
#include "mapped_module.hpp"
|
||||
|
||||
mapped_module map_module_from_data(emulator& emu, std::span<const uint8_t> data,
|
||||
std::filesystem::path file);
|
||||
mapped_module map_module_from_data(emulator& emu, std::span<const uint8_t> data, std::filesystem::path file);
|
||||
mapped_module map_module_from_file(emulator& emu, std::filesystem::path file);
|
||||
|
||||
bool unmap_module(emulator& emu, const mapped_module& mod);
|
||||
|
||||
@@ -283,7 +283,7 @@ struct process_context;
|
||||
|
||||
class moved_marker
|
||||
{
|
||||
public:
|
||||
public:
|
||||
moved_marker() = default;
|
||||
|
||||
moved_marker(const moved_marker& copy) = default;
|
||||
@@ -313,13 +313,13 @@ public:
|
||||
return this->was_moved_;
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
bool was_moved_{false};
|
||||
};
|
||||
|
||||
class emulator_thread : ref_counted_object
|
||||
{
|
||||
public:
|
||||
public:
|
||||
emulator_thread(x64_emulator& emu)
|
||||
: emu_ptr(&emu)
|
||||
{
|
||||
@@ -471,7 +471,7 @@ public:
|
||||
buffer.read_vector(this->last_registers);
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
void setup_registers(x64_emulator& emu, const process_context& context) const;
|
||||
|
||||
void release()
|
||||
@@ -503,11 +503,11 @@ private:
|
||||
struct process_context
|
||||
{
|
||||
process_context(x64_emulator& emu)
|
||||
: base_allocator(emu)
|
||||
, peb(emu)
|
||||
, process_params(emu)
|
||||
, kusd(emu, *this)
|
||||
, mod_manager(emu)
|
||||
: base_allocator(emu),
|
||||
peb(emu),
|
||||
process_params(emu),
|
||||
kusd(emu, *this),
|
||||
mod_manager(emu)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -214,7 +214,7 @@ void hive_key::parse(std::ifstream& file)
|
||||
}
|
||||
|
||||
hive_parser::hive_parser(const std::filesystem::path& file_path)
|
||||
: file_(file_path, std::ios::binary)
|
||||
, root_key_(parse_root_block(file_, file_path))
|
||||
: file_(file_path, std::ios::binary),
|
||||
root_key_(parse_root_block(file_, file_path))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -15,11 +15,11 @@ struct hive_value
|
||||
|
||||
class hive_key
|
||||
{
|
||||
public:
|
||||
public:
|
||||
hive_key(const int subkey_block_offset, const int value_count, const int value_offsets)
|
||||
: subkey_block_offset_(subkey_block_offset)
|
||||
, value_count_(value_count)
|
||||
, value_offsets_(value_offsets)
|
||||
: subkey_block_offset_(subkey_block_offset),
|
||||
value_count_(value_count),
|
||||
value_offsets_(value_offsets)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ public:
|
||||
|
||||
const hive_value* get_value(std::ifstream& file, const std::string_view name);
|
||||
|
||||
private:
|
||||
private:
|
||||
struct raw_hive_value : hive_value
|
||||
{
|
||||
bool parsed{false};
|
||||
@@ -65,7 +65,7 @@ private:
|
||||
|
||||
class hive_parser
|
||||
{
|
||||
public:
|
||||
public:
|
||||
explicit hive_parser(const std::filesystem::path& file_path);
|
||||
|
||||
[[nodiscard]] hive_key* get_sub_key(const std::filesystem::path& key)
|
||||
@@ -96,7 +96,7 @@ public:
|
||||
return sub_key->get_value(this->file_, name);
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
std::ifstream file_{};
|
||||
hive_key root_key_;
|
||||
};
|
||||
|
||||
@@ -29,8 +29,8 @@ namespace
|
||||
return true;
|
||||
}
|
||||
|
||||
void register_hive(registry_manager::hive_map& hives,
|
||||
const std::filesystem::path& key, const std::filesystem::path& file)
|
||||
void register_hive(registry_manager::hive_map& hives, const std::filesystem::path& key,
|
||||
const std::filesystem::path& file)
|
||||
{
|
||||
hives[canonicalize_path(key)] = std::make_unique<hive_parser>(file);
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ struct registry_value
|
||||
|
||||
class registry_manager
|
||||
{
|
||||
public:
|
||||
public:
|
||||
using hive_ptr = std::unique_ptr<hive_parser>;
|
||||
using hive_map = std::unordered_map<std::filesystem::path, hive_ptr>;
|
||||
|
||||
@@ -45,14 +45,13 @@ public:
|
||||
registry_manager(const registry_manager&) = delete;
|
||||
registry_manager& operator=(const registry_manager&) = delete;
|
||||
|
||||
|
||||
void serialize(utils::buffer_serializer& buffer) const;
|
||||
void deserialize(utils::buffer_deserializer& buffer);
|
||||
|
||||
std::optional<registry_key> get_key(const std::filesystem::path& key);
|
||||
std::optional<registry_value> get_value(const registry_key& key, std::string name);
|
||||
|
||||
private:
|
||||
private:
|
||||
std::filesystem::path hive_path_{};
|
||||
hive_map hives_{};
|
||||
std::unordered_map<std::filesystem::path, std::filesystem::path> path_mapping_{};
|
||||
|
||||
@@ -2,32 +2,32 @@
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4005)
|
||||
#pragma warning(disable: 4127)
|
||||
#pragma warning(disable: 4201)
|
||||
#pragma warning(disable: 4244)
|
||||
#pragma warning(disable: 4245)
|
||||
#pragma warning(disable: 4324)
|
||||
#pragma warning(disable: 4458)
|
||||
#pragma warning(disable: 4471)
|
||||
#pragma warning(disable: 4505)
|
||||
#pragma warning(disable: 4702)
|
||||
#pragma warning(disable: 4996)
|
||||
#pragma warning(disable: 5054)
|
||||
#pragma warning(disable: 6011)
|
||||
#pragma warning(disable: 6297)
|
||||
#pragma warning(disable: 6385)
|
||||
#pragma warning(disable: 6386)
|
||||
#pragma warning(disable: 6387)
|
||||
#pragma warning(disable: 26110)
|
||||
#pragma warning(disable: 26451)
|
||||
#pragma warning(disable: 26444)
|
||||
#pragma warning(disable: 26451)
|
||||
#pragma warning(disable: 26489)
|
||||
#pragma warning(disable: 26495)
|
||||
#pragma warning(disable: 26498)
|
||||
#pragma warning(disable: 26812)
|
||||
#pragma warning(disable: 28020)
|
||||
#pragma warning(disable : 4005)
|
||||
#pragma warning(disable : 4127)
|
||||
#pragma warning(disable : 4201)
|
||||
#pragma warning(disable : 4244)
|
||||
#pragma warning(disable : 4245)
|
||||
#pragma warning(disable : 4324)
|
||||
#pragma warning(disable : 4458)
|
||||
#pragma warning(disable : 4471)
|
||||
#pragma warning(disable : 4505)
|
||||
#pragma warning(disable : 4702)
|
||||
#pragma warning(disable : 4996)
|
||||
#pragma warning(disable : 5054)
|
||||
#pragma warning(disable : 6011)
|
||||
#pragma warning(disable : 6297)
|
||||
#pragma warning(disable : 6385)
|
||||
#pragma warning(disable : 6386)
|
||||
#pragma warning(disable : 6387)
|
||||
#pragma warning(disable : 26110)
|
||||
#pragma warning(disable : 26451)
|
||||
#pragma warning(disable : 26444)
|
||||
#pragma warning(disable : 26451)
|
||||
#pragma warning(disable : 26489)
|
||||
#pragma warning(disable : 26495)
|
||||
#pragma warning(disable : 26498)
|
||||
#pragma warning(disable : 26812)
|
||||
#pragma warning(disable : 28020)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ void syscall_dispatcher::deserialize(utils::buffer_deserializer& buffer)
|
||||
this->add_handlers();
|
||||
}
|
||||
|
||||
|
||||
void syscall_dispatcher::setup(const exported_symbols& ntdll_exports, std::span<const std::byte> ntdll_data,
|
||||
const exported_symbols& win32u_exports, std::span<const std::byte> win32u_data)
|
||||
{
|
||||
@@ -68,7 +67,6 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu)
|
||||
const auto address = emu.read_instruction_pointer();
|
||||
const auto syscall_id = emu.reg<uint32_t>(x64_register::eax);
|
||||
|
||||
|
||||
const syscall_context c{win_emu, emu, context, true};
|
||||
|
||||
try
|
||||
@@ -94,9 +92,7 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu)
|
||||
if (mod != context.ntdll && mod != context.win32u)
|
||||
{
|
||||
win_emu.log.print(color::blue, "Executing inline syscall: %s (0x%X) at 0x%" PRIx64 " (%s)\n",
|
||||
entry->second.name.c_str(),
|
||||
syscall_id,
|
||||
address, mod ? mod->name.c_str() : "<N/A>");
|
||||
entry->second.name.c_str(), syscall_id, address, mod ? mod->name.c_str() : "<N/A>");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -108,8 +104,7 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu)
|
||||
|
||||
win_emu.log.print(color::dark_gray,
|
||||
"Executing syscall: %s (0x%X) at 0x%" PRIx64 " via 0x%" PRIx64 " (%s)\n",
|
||||
entry->second.name.c_str(),
|
||||
syscall_id, address, return_address, mod_name);
|
||||
entry->second.name.c_str(), syscall_id, address, return_address, mod_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -117,10 +112,8 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu)
|
||||
win_emu.log.print(color::blue,
|
||||
"Crafted out-of-line syscall: %s (0x%X) at 0x%" PRIx64 " (%s) via 0x%" PRIx64
|
||||
" (%s)\n",
|
||||
entry->second.name.c_str(),
|
||||
syscall_id,
|
||||
address, mod ? mod->name.c_str() : "<N/A>", context.previous_ip,
|
||||
previous_mod ? previous_mod->name.c_str() : "<N/A>");
|
||||
entry->second.name.c_str(), syscall_id, address, mod ? mod->name.c_str() : "<N/A>",
|
||||
context.previous_ip, previous_mod ? previous_mod->name.c_str() : "<N/A>");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "process_context.hpp"
|
||||
|
||||
struct syscall_context;
|
||||
using syscall_handler = void(*)(const syscall_context& c);
|
||||
using syscall_handler = void (*)(const syscall_context& c);
|
||||
|
||||
struct syscall_handler_entry
|
||||
{
|
||||
@@ -15,7 +15,7 @@ class windows_emulator;
|
||||
|
||||
class syscall_dispatcher
|
||||
{
|
||||
public:
|
||||
public:
|
||||
syscall_dispatcher() = default;
|
||||
syscall_dispatcher(const exported_symbols& ntdll_exports, std::span<const std::byte> ntdll_data,
|
||||
const exported_symbols& win32u_exports, std::span<const std::byte> win32u_data);
|
||||
@@ -33,7 +33,7 @@ public:
|
||||
return this->handlers_.at(id).name;
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
std::map<uint64_t, syscall_handler_entry> handlers_{};
|
||||
|
||||
static void add_handlers(std::map<std::string, syscall_handler>& handler_mapping);
|
||||
|
||||
@@ -78,9 +78,8 @@ inline std::map<uint64_t, std::string> find_syscalls(const exported_symbols& exp
|
||||
|
||||
if (!entry.empty())
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"Syscall with id " + std::to_string(*id) + ", which is mapping to " + symbol.name +
|
||||
", was already mapped to " + entry);
|
||||
throw std::runtime_error("Syscall with id " + std::to_string(*id) + ", which is mapping to " +
|
||||
symbol.name + ", was already mapped to " + entry);
|
||||
}
|
||||
|
||||
entry = symbol.name;
|
||||
@@ -90,8 +89,7 @@ inline std::map<uint64_t, std::string> find_syscalls(const exported_symbols& exp
|
||||
return syscalls;
|
||||
}
|
||||
|
||||
inline void map_syscalls(std::map<uint64_t, syscall_handler_entry>& handlers,
|
||||
std::map<uint64_t, std::string> syscalls)
|
||||
inline void map_syscalls(std::map<uint64_t, syscall_handler_entry>& handlers, std::map<uint64_t, std::string> syscalls)
|
||||
{
|
||||
for (auto& [id, name] : syscalls)
|
||||
{
|
||||
@@ -99,8 +97,7 @@ inline void map_syscalls(std::map<uint64_t, syscall_handler_entry>& handlers,
|
||||
|
||||
if (!entry.name.empty())
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"Syscall with id " + std::to_string(id) + ", which is mapping to " + name +
|
||||
throw std::runtime_error("Syscall with id " + std::to_string(id) + ", which is mapping to " + name +
|
||||
", was previously mapped to " + entry.name);
|
||||
}
|
||||
|
||||
@@ -168,11 +165,8 @@ void forward_syscall(const syscall_context& c, NTSTATUS (*handler)(const syscall
|
||||
const auto ip = c.emu.read_instruction_pointer();
|
||||
|
||||
size_t index = 0;
|
||||
std::tuple<const syscall_context&, Args...> func_args
|
||||
{
|
||||
c,
|
||||
resolve_indexed_argument<std::remove_cv_t<std::remove_reference_t<Args>>>(c.emu, index)...
|
||||
};
|
||||
std::tuple<const syscall_context&, Args...> func_args{
|
||||
c, resolve_indexed_argument<std::remove_cv_t<std::remove_reference_t<Args>>>(c.emu, index)...};
|
||||
|
||||
(void)index;
|
||||
|
||||
@@ -183,10 +177,7 @@ void forward_syscall(const syscall_context& c, NTSTATUS (*handler)(const syscall
|
||||
template <auto Handler>
|
||||
syscall_handler make_syscall_handler()
|
||||
{
|
||||
return +[](const syscall_context& c)
|
||||
{
|
||||
forward_syscall(c, Handler);
|
||||
};
|
||||
return +[](const syscall_context& c) { forward_syscall(c, Handler); };
|
||||
}
|
||||
|
||||
template <typename T, typename Traits>
|
||||
@@ -214,8 +205,8 @@ inline std::chrono::steady_clock::time_point convert_delay_interval_to_time_poin
|
||||
const auto relative_time = -delay_interval.QuadPart;
|
||||
const auto relative_ticks_in_ms = relative_time / 10;
|
||||
const auto relative_fraction_ns = (relative_time % 10) * 100;
|
||||
const auto relative_duration = std::chrono::microseconds(relative_ticks_in_ms) +
|
||||
std::chrono::nanoseconds(relative_fraction_ns);
|
||||
const auto relative_duration =
|
||||
std::chrono::microseconds(relative_ticks_in_ms) + std::chrono::nanoseconds(relative_fraction_ns);
|
||||
|
||||
return std::chrono::steady_clock::now() + relative_duration;
|
||||
}
|
||||
@@ -226,13 +217,11 @@ inline std::chrono::steady_clock::time_point convert_delay_interval_to_time_poin
|
||||
const auto delay_seconds_since_1970 = delay_seconds_since_1601 - EPOCH_DIFFERENCE_1601_TO_1970_SECONDS;
|
||||
|
||||
const auto target_time =
|
||||
std::chrono::system_clock::from_time_t(delay_seconds_since_1970) +
|
||||
std::chrono::nanoseconds(delay_fraction_ns);
|
||||
std::chrono::system_clock::from_time_t(delay_seconds_since_1970) + std::chrono::nanoseconds(delay_fraction_ns);
|
||||
|
||||
const auto now_system = std::chrono::system_clock::now();
|
||||
|
||||
const auto duration_until_target = std::chrono::duration_cast<
|
||||
std::chrono::microseconds>(target_time - now_system);
|
||||
const auto duration_until_target = std::chrono::duration_cast<std::chrono::microseconds>(target_time - now_system);
|
||||
|
||||
return std::chrono::steady_clock::now() + duration_until_target;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,8 +14,8 @@ namespace
|
||||
emulator_object<T> allocate_object_on_stack(x64_emulator& emu)
|
||||
{
|
||||
const auto old_sp = emu.reg(x64_register::rsp);
|
||||
const auto new_sp = align_down(old_sp - sizeof(CONTEXT64),
|
||||
std::max(alignof(CONTEXT64), alignof(x64_emulator::pointer_type)));
|
||||
const auto new_sp =
|
||||
align_down(old_sp - sizeof(CONTEXT64), std::max(alignof(CONTEXT64), alignof(x64_emulator::pointer_type)));
|
||||
emu.reg(x64_register::rsp, new_sp);
|
||||
|
||||
return {emu, new_sp};
|
||||
@@ -42,10 +42,7 @@ namespace
|
||||
uint64_t value;
|
||||
};
|
||||
|
||||
const msr_value value{
|
||||
IA32_GS_BASE_MSR,
|
||||
allocator.get_base()
|
||||
};
|
||||
const msr_value value{IA32_GS_BASE_MSR, allocator.get_base()};
|
||||
|
||||
emu.write_register(x64_register::msr, &value, sizeof(value));
|
||||
}
|
||||
@@ -66,8 +63,7 @@ namespace
|
||||
}
|
||||
|
||||
ULONG copy_string_as_relative(x64_emulator& emu, emulator_allocator& allocator, const uint64_t result_base,
|
||||
const void* base_ptr, const uint64_t offset,
|
||||
const size_t length)
|
||||
const void* base_ptr, const uint64_t offset, const size_t length)
|
||||
{
|
||||
const auto address = copy_string(emu, allocator, base_ptr, offset, length);
|
||||
if (!address)
|
||||
@@ -86,17 +82,16 @@ namespace
|
||||
const auto ns_entries_obj = allocator.reserve<API_SET_NAMESPACE_ENTRY>(orig_api_set_map.Count);
|
||||
const auto hash_entries_obj = allocator.reserve<API_SET_HASH_ENTRY>(orig_api_set_map.Count);
|
||||
|
||||
api_set_map_obj.access([&](API_SET_NAMESPACE& api_set)
|
||||
{
|
||||
api_set_map_obj.access([&](API_SET_NAMESPACE& api_set) {
|
||||
api_set = orig_api_set_map;
|
||||
api_set.EntryOffset = static_cast<ULONG>(ns_entries_obj.value() - api_set_map_obj.value());
|
||||
api_set.HashOffset = static_cast<ULONG>(hash_entries_obj.value() - api_set_map_obj.value());
|
||||
});
|
||||
|
||||
const auto orig_ns_entries = offset_pointer<API_SET_NAMESPACE_ENTRY>(&orig_api_set_map,
|
||||
orig_api_set_map.EntryOffset);
|
||||
const auto orig_hash_entries = offset_pointer<API_SET_HASH_ENTRY>(&orig_api_set_map,
|
||||
orig_api_set_map.HashOffset);
|
||||
const auto orig_ns_entries =
|
||||
offset_pointer<API_SET_NAMESPACE_ENTRY>(&orig_api_set_map, orig_api_set_map.EntryOffset);
|
||||
const auto orig_hash_entries =
|
||||
offset_pointer<API_SET_HASH_ENTRY>(&orig_api_set_map, orig_api_set_map.HashOffset);
|
||||
|
||||
for (ULONG i = 0; i < orig_api_set_map.Count; ++i)
|
||||
{
|
||||
@@ -112,8 +107,7 @@ namespace
|
||||
}
|
||||
|
||||
const auto values_obj = allocator.reserve<API_SET_VALUE_ENTRY>(ns_entry.ValueCount);
|
||||
const auto orig_values = offset_pointer<API_SET_VALUE_ENTRY>(&orig_api_set_map,
|
||||
ns_entry.ValueOffset);
|
||||
const auto orig_values = offset_pointer<API_SET_VALUE_ENTRY>(&orig_api_set_map, ns_entry.ValueOffset);
|
||||
|
||||
ns_entry.ValueOffset = static_cast<ULONG>(values_obj.value() - api_set_map_obj.value());
|
||||
|
||||
@@ -127,8 +121,7 @@ namespace
|
||||
if (value.NameLength)
|
||||
{
|
||||
value.NameOffset = copy_string_as_relative(emu, allocator, api_set_map_obj.value(),
|
||||
&orig_api_set_map,
|
||||
value.NameOffset, value.NameLength);
|
||||
&orig_api_set_map, value.NameOffset, value.NameLength);
|
||||
}
|
||||
|
||||
values_obj.write(value, j);
|
||||
@@ -211,8 +204,7 @@ namespace
|
||||
|
||||
context.process_params = allocator.reserve<RTL_USER_PROCESS_PARAMETERS64>();
|
||||
|
||||
context.process_params.access([&](RTL_USER_PROCESS_PARAMETERS64& proc_params)
|
||||
{
|
||||
context.process_params.access([&](RTL_USER_PROCESS_PARAMETERS64& proc_params) {
|
||||
proc_params.Flags = 0x6001; //| 0x80000000; // Prevent CsrClientConnectToServer
|
||||
|
||||
proc_params.ConsoleHandle = CONSOLE_HANDLE.h;
|
||||
@@ -251,13 +243,12 @@ namespace
|
||||
|
||||
const auto total_length = allocator.get_next_address() - context.process_params.value();
|
||||
|
||||
proc_params.Length = static_cast<uint32_t>(std::max(static_cast<uint64_t>(sizeof(proc_params)),
|
||||
total_length));
|
||||
proc_params.Length =
|
||||
static_cast<uint32_t>(std::max(static_cast<uint64_t>(sizeof(proc_params)), total_length));
|
||||
proc_params.MaximumLength = proc_params.Length;
|
||||
});
|
||||
|
||||
context.peb.access([&](PEB64& peb)
|
||||
{
|
||||
context.peb.access([&](PEB64& peb) {
|
||||
peb.ImageBaseAddress = nullptr;
|
||||
peb.ProcessParameters = context.process_params.ptr();
|
||||
peb.ApiSetMap = build_api_set_map(emu, allocator).ptr();
|
||||
@@ -277,12 +268,11 @@ namespace
|
||||
});
|
||||
}
|
||||
|
||||
using exception_record_map = std::unordered_map<
|
||||
const EMU_EXCEPTION_RECORD<EmulatorTraits<Emu64>>*, emulator_object<EMU_EXCEPTION_RECORD<EmulatorTraits<
|
||||
Emu64>>>>;
|
||||
using exception_record_map = std::unordered_map<const EMU_EXCEPTION_RECORD<EmulatorTraits<Emu64>>*,
|
||||
emulator_object<EMU_EXCEPTION_RECORD<EmulatorTraits<Emu64>>>>;
|
||||
|
||||
emulator_object<EMU_EXCEPTION_RECORD<EmulatorTraits<Emu64>>> save_exception_record(emulator_allocator& allocator,
|
||||
const EMU_EXCEPTION_RECORD<EmulatorTraits<Emu64>>& record,
|
||||
emulator_object<EMU_EXCEPTION_RECORD<EmulatorTraits<Emu64>>> save_exception_record(
|
||||
emulator_allocator& allocator, const EMU_EXCEPTION_RECORD<EmulatorTraits<Emu64>>& record,
|
||||
exception_record_map& record_mapping)
|
||||
{
|
||||
const auto record_obj = allocator.reserve<EMU_EXCEPTION_RECORD<EmulatorTraits<Emu64>>>();
|
||||
@@ -307,8 +297,7 @@ namespace
|
||||
record_mapping);
|
||||
}
|
||||
|
||||
record_obj.access([&](EMU_EXCEPTION_RECORD<EmulatorTraits<Emu64>>& r)
|
||||
{
|
||||
record_obj.access([&](EMU_EXCEPTION_RECORD<EmulatorTraits<Emu64>>& r) {
|
||||
r.ExceptionRecord = reinterpret_cast<EmulatorTraits<Emu64>::PVOID>(nested_record_obj.ptr());
|
||||
});
|
||||
}
|
||||
@@ -316,8 +305,8 @@ namespace
|
||||
return record_obj;
|
||||
}
|
||||
|
||||
emulator_object<EMU_EXCEPTION_RECORD<EmulatorTraits<Emu64>>> save_exception_record(emulator_allocator& allocator,
|
||||
const EMU_EXCEPTION_RECORD<EmulatorTraits<Emu64>>& record)
|
||||
emulator_object<EMU_EXCEPTION_RECORD<EmulatorTraits<Emu64>>> save_exception_record(
|
||||
emulator_allocator& allocator, const EMU_EXCEPTION_RECORD<EmulatorTraits<Emu64>>& record)
|
||||
{
|
||||
exception_record_map record_mapping{};
|
||||
return save_exception_record(allocator, record, record_mapping);
|
||||
@@ -405,8 +394,7 @@ namespace
|
||||
}
|
||||
|
||||
const emulator_object<machine_frame> machine_frame_obj{emu, new_sp + combined_size};
|
||||
machine_frame_obj.access([&](machine_frame& frame)
|
||||
{
|
||||
machine_frame_obj.access([&](machine_frame& frame) {
|
||||
const auto& record = *reinterpret_cast<CONTEXT64*>(pointers.ContextRecord);
|
||||
frame.rip = record.Rip;
|
||||
frame.rsp = record.Rsp;
|
||||
@@ -467,10 +455,7 @@ namespace
|
||||
|
||||
// Crappy mechanism to prevent mutation while iterating.
|
||||
const auto was_blocked = devices.block_mutation(true);
|
||||
const auto _ = utils::finally([&]
|
||||
{
|
||||
devices.block_mutation(was_blocked);
|
||||
});
|
||||
const auto _ = utils::finally([&] { devices.block_mutation(was_blocked); });
|
||||
|
||||
for (auto& device : devices)
|
||||
{
|
||||
@@ -504,7 +489,6 @@ namespace
|
||||
|
||||
context.active_thread = &thread;
|
||||
|
||||
|
||||
thread.restore(emu);
|
||||
thread.setup_if_necessary(emu, context);
|
||||
|
||||
@@ -568,8 +552,7 @@ namespace
|
||||
default:
|
||||
break;
|
||||
|
||||
case handle_types::event:
|
||||
{
|
||||
case handle_types::event: {
|
||||
auto* e = c.events.get(h);
|
||||
if (e)
|
||||
{
|
||||
@@ -579,8 +562,7 @@ namespace
|
||||
break;
|
||||
}
|
||||
|
||||
case handle_types::mutant:
|
||||
{
|
||||
case handle_types::mutant: {
|
||||
auto* e = c.mutants.get(h);
|
||||
if (e)
|
||||
{
|
||||
@@ -590,8 +572,7 @@ namespace
|
||||
break;
|
||||
}
|
||||
|
||||
case handle_types::thread:
|
||||
{
|
||||
case handle_types::thread: {
|
||||
const auto* t = c.threads.get(h);
|
||||
if (t)
|
||||
{
|
||||
@@ -606,16 +587,14 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
emulator_thread::emulator_thread(x64_emulator& emu, const process_context& context,
|
||||
const uint64_t start_address,
|
||||
const uint64_t argument,
|
||||
const uint64_t stack_size, const uint32_t id)
|
||||
: emu_ptr(&emu)
|
||||
, stack_size(page_align_up(std::max(stack_size, static_cast<uint64_t>(STACK_SIZE))))
|
||||
, start_address(start_address)
|
||||
, argument(argument)
|
||||
, id(id)
|
||||
, last_registers(context.default_register_set)
|
||||
emulator_thread::emulator_thread(x64_emulator& emu, const process_context& context, const uint64_t start_address,
|
||||
const uint64_t argument, const uint64_t stack_size, const uint32_t id)
|
||||
: emu_ptr(&emu),
|
||||
stack_size(page_align_up(std::max(stack_size, static_cast<uint64_t>(STACK_SIZE)))),
|
||||
start_address(start_address),
|
||||
argument(argument),
|
||||
id(id),
|
||||
last_registers(context.default_register_set)
|
||||
{
|
||||
this->stack_base = emu.allocate_memory(this->stack_size, memory_permission::read_write);
|
||||
|
||||
@@ -627,8 +606,7 @@ emulator_thread::emulator_thread(x64_emulator& emu, const process_context& conte
|
||||
|
||||
this->teb = this->gs_segment->reserve<TEB64>();
|
||||
|
||||
this->teb->access([&](TEB64& teb_obj)
|
||||
{
|
||||
this->teb->access([&](TEB64& teb_obj) {
|
||||
teb_obj.ClientId.UniqueProcess = 1ul;
|
||||
teb_obj.ClientId.UniqueThread = static_cast<uint64_t>(this->id);
|
||||
teb_obj.NtTib.StackLimit = reinterpret_cast<std::uint64_t*>(this->stack_base);
|
||||
@@ -752,8 +730,7 @@ std::unique_ptr<x64_emulator> create_default_x64_emulator()
|
||||
return unicorn::create_x64_emulator();
|
||||
}
|
||||
|
||||
windows_emulator::windows_emulator(emulator_settings settings,
|
||||
std::unique_ptr<x64_emulator> emu)
|
||||
windows_emulator::windows_emulator(emulator_settings settings, std::unique_ptr<x64_emulator> emu)
|
||||
: windows_emulator(std::move(emu))
|
||||
{
|
||||
this->silent_until_main_ = settings.silent_until_main && !settings.disable_logging;
|
||||
@@ -764,8 +741,8 @@ windows_emulator::windows_emulator(emulator_settings settings,
|
||||
}
|
||||
|
||||
windows_emulator::windows_emulator(std::unique_ptr<x64_emulator> emu)
|
||||
: emu_(std::move(emu))
|
||||
, process_(*emu_)
|
||||
: emu_(std::move(emu)),
|
||||
process_(*emu_)
|
||||
{
|
||||
this->setup_hooks();
|
||||
}
|
||||
@@ -781,10 +758,8 @@ void windows_emulator::setup_process(const emulator_settings& settings)
|
||||
|
||||
context.executable = context.mod_manager.map_module(settings.application, this->log);
|
||||
|
||||
context.peb.access([&](PEB64& peb)
|
||||
{
|
||||
peb.ImageBaseAddress = reinterpret_cast<std::uint64_t*>(context.executable->image_base);
|
||||
});
|
||||
context.peb.access(
|
||||
[&](PEB64& peb) { peb.ImageBaseAddress = reinterpret_cast<std::uint64_t*>(context.executable->image_base); });
|
||||
|
||||
context.ntdll = context.mod_manager.map_module(R"(C:\Windows\System32\ntdll.dll)", this->log);
|
||||
context.win32u = context.mod_manager.map_module(R"(C:\Windows\System32\win32u.dll)", this->log);
|
||||
@@ -858,16 +833,13 @@ void windows_emulator::on_instruction_execution(uint64_t address)
|
||||
if (export_entry != binary->address_names.end())
|
||||
{
|
||||
log.print(is_interesting_call ? color::yellow : color::dark_gray,
|
||||
"Executing function: %s - %s (0x%" PRIx64 ")\n",
|
||||
binary->name.c_str(),
|
||||
"Executing function: %s - %s (0x%" PRIx64 ")\n", binary->name.c_str(),
|
||||
export_entry->second.c_str(), address);
|
||||
}
|
||||
else if (address == binary->entry_point)
|
||||
{
|
||||
log.print(is_interesting_call ? color::yellow : color::gray,
|
||||
"Executing entry point: %s (0x%" PRIx64 ")\n",
|
||||
binary->name.c_str(),
|
||||
address);
|
||||
log.print(is_interesting_call ? color::yellow : color::gray, "Executing entry point: %s (0x%" PRIx64 ")\n",
|
||||
binary->name.c_str(), address);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -878,22 +850,16 @@ void windows_emulator::on_instruction_execution(uint64_t address)
|
||||
|
||||
auto& emu = this->emu();
|
||||
|
||||
printf(
|
||||
"Inst: %16" PRIx64 " - RAX: %16" PRIx64 " - RBX: %16" PRIx64 " - RCX: %16" PRIx64 " - RDX: %16" PRIx64
|
||||
printf("Inst: %16" PRIx64 " - RAX: %16" PRIx64 " - RBX: %16" PRIx64 " - RCX: %16" PRIx64 " - RDX: %16" PRIx64
|
||||
" - R8: %16" PRIx64 " - R9: %16" PRIx64 " - RDI: %16" PRIx64 " - RSI: %16" PRIx64 " - %s\n",
|
||||
address,
|
||||
emu.reg(x64_register::rax), emu.reg(x64_register::rbx),
|
||||
emu.reg(x64_register::rcx),
|
||||
emu.reg(x64_register::rdx), emu.reg(x64_register::r8),
|
||||
emu.reg(x64_register::r9),
|
||||
emu.reg(x64_register::rdi), emu.reg(x64_register::rsi),
|
||||
binary ? binary->name.c_str() : "<N/A>");
|
||||
address, emu.reg(x64_register::rax), emu.reg(x64_register::rbx), emu.reg(x64_register::rcx),
|
||||
emu.reg(x64_register::rdx), emu.reg(x64_register::r8), emu.reg(x64_register::r9), emu.reg(x64_register::rdi),
|
||||
emu.reg(x64_register::rsi), binary ? binary->name.c_str() : "<N/A>");
|
||||
}
|
||||
|
||||
void windows_emulator::setup_hooks()
|
||||
{
|
||||
this->emu().hook_instruction(x64_hookable_instructions::syscall, [&]
|
||||
{
|
||||
this->emu().hook_instruction(x64_hookable_instructions::syscall, [&] {
|
||||
for (const auto& hook : this->syscall_hooks_)
|
||||
{
|
||||
if (hook() == instruction_hook_continuation::skip_instruction)
|
||||
@@ -906,16 +872,14 @@ void windows_emulator::setup_hooks()
|
||||
return instruction_hook_continuation::skip_instruction;
|
||||
});
|
||||
|
||||
this->emu().hook_instruction(x64_hookable_instructions::rdtsc, [&]
|
||||
{
|
||||
this->emu().hook_instruction(x64_hookable_instructions::rdtsc, [&] {
|
||||
const auto instructions = this->process().executed_instructions;
|
||||
this->emu().reg(x64_register::rax, instructions & 0xFFFFFFFF);
|
||||
this->emu().reg(x64_register::rdx, (instructions >> 32) & 0xFFFFFFFF);
|
||||
return instruction_hook_continuation::skip_instruction;
|
||||
});
|
||||
|
||||
this->emu().hook_instruction(x64_hookable_instructions::invalid, [&]
|
||||
{
|
||||
this->emu().hook_instruction(x64_hookable_instructions::invalid, [&] {
|
||||
const auto ip = this->emu().read_instruction_pointer();
|
||||
|
||||
this->log.print(color::gray, "Invalid instruction at: 0x%" PRIx64 "\n", ip);
|
||||
@@ -923,8 +887,7 @@ void windows_emulator::setup_hooks()
|
||||
return instruction_hook_continuation::skip_instruction;
|
||||
});
|
||||
|
||||
this->emu().hook_interrupt([&](const int interrupt)
|
||||
{
|
||||
this->emu().hook_interrupt([&](const int interrupt) {
|
||||
if (interrupt == 6)
|
||||
{
|
||||
dispatch_illegal_instruction_violation(this->emu(), this->process().ki_user_exception_dispatcher);
|
||||
@@ -942,8 +905,7 @@ void windows_emulator::setup_hooks()
|
||||
});
|
||||
|
||||
this->emu().hook_memory_violation([&](const uint64_t address, const size_t size, const memory_operation operation,
|
||||
const memory_violation_type type)
|
||||
{
|
||||
const memory_violation_type type) {
|
||||
const auto permission = get_permission_string(operation);
|
||||
const auto ip = this->emu().read_instruction_pointer();
|
||||
const char* name = this->process().mod_manager.find_name(ip);
|
||||
@@ -951,16 +913,12 @@ void windows_emulator::setup_hooks()
|
||||
if (type == memory_violation_type::protection)
|
||||
{
|
||||
this->log.print(color::gray, "Protection violation: 0x%" PRIx64 " (%zX) - %s at 0x%" PRIx64 " (%s)\n",
|
||||
address, size,
|
||||
permission.c_str(), ip,
|
||||
name);
|
||||
address, size, permission.c_str(), ip, name);
|
||||
}
|
||||
else if (type == memory_violation_type::unmapped)
|
||||
{
|
||||
this->log.print(color::gray, "Mapping violation: 0x%" PRIx64 " (%zX) - %s at 0x%" PRIx64 " (%s)\n", address,
|
||||
size,
|
||||
permission.c_str(), ip,
|
||||
name);
|
||||
size, permission.c_str(), ip, name);
|
||||
}
|
||||
|
||||
if (this->fuzzing)
|
||||
@@ -976,10 +934,7 @@ void windows_emulator::setup_hooks()
|
||||
|
||||
this->emu().hook_memory_execution(
|
||||
0, std::numeric_limits<size_t>::max(),
|
||||
[&](const uint64_t address, const size_t, const uint64_t)
|
||||
{
|
||||
this->on_instruction_execution(address);
|
||||
});
|
||||
[&](const uint64_t address, const size_t, const uint64_t) { this->on_instruction_execution(address); });
|
||||
}
|
||||
|
||||
void windows_emulator::start(std::chrono::nanoseconds timeout, size_t count)
|
||||
@@ -1043,15 +998,9 @@ void windows_emulator::serialize(utils::buffer_serializer& buffer) const
|
||||
|
||||
void windows_emulator::deserialize(utils::buffer_deserializer& buffer)
|
||||
{
|
||||
buffer.register_factory<x64_emulator_wrapper>([this]
|
||||
{
|
||||
return x64_emulator_wrapper{this->emu()};
|
||||
});
|
||||
buffer.register_factory<x64_emulator_wrapper>([this] { return x64_emulator_wrapper{this->emu()}; });
|
||||
|
||||
buffer.register_factory<windows_emulator_wrapper>([this]
|
||||
{
|
||||
return windows_emulator_wrapper{*this};
|
||||
});
|
||||
buffer.register_factory<windows_emulator_wrapper>([this] { return windows_emulator_wrapper{*this}; });
|
||||
|
||||
buffer.read(this->use_relative_time_);
|
||||
|
||||
@@ -1070,7 +1019,7 @@ void windows_emulator::save_snapshot()
|
||||
this->process_snapshot_ = serializer.move_buffer();
|
||||
|
||||
// TODO: Make process copyable
|
||||
//this->process_snapshot_ = this->process();
|
||||
// this->process_snapshot_ = this->process();
|
||||
}
|
||||
|
||||
void windows_emulator::restore_snapshot()
|
||||
@@ -1085,5 +1034,5 @@ void windows_emulator::restore_snapshot()
|
||||
|
||||
utils::buffer_deserializer deserializer{this->process_snapshot_};
|
||||
this->process_.deserialize(deserializer);
|
||||
//this->process_ = *this->process_snapshot_;
|
||||
// this->process_ = *this->process_snapshot_;
|
||||
}
|
||||
|
||||
@@ -24,10 +24,9 @@ struct emulator_settings
|
||||
|
||||
class windows_emulator
|
||||
{
|
||||
public:
|
||||
public:
|
||||
windows_emulator(std::unique_ptr<x64_emulator> emu = create_default_x64_emulator());
|
||||
windows_emulator(emulator_settings settings,
|
||||
std::unique_ptr<x64_emulator> emu = create_default_x64_emulator());
|
||||
windows_emulator(emulator_settings settings, std::unique_ptr<x64_emulator> emu = create_default_x64_emulator());
|
||||
|
||||
windows_emulator(windows_emulator&&) = delete;
|
||||
windows_emulator(const windows_emulator&) = delete;
|
||||
@@ -112,7 +111,7 @@ public:
|
||||
return this->use_relative_time_;
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
bool use_relative_time_{false};
|
||||
bool silent_until_main_{false};
|
||||
std::unique_ptr<x64_emulator> emu_{};
|
||||
@@ -123,7 +122,7 @@ private:
|
||||
syscall_dispatcher dispatcher_;
|
||||
|
||||
std::vector<std::byte> process_snapshot_{};
|
||||
//std::optional<process_context> process_snapshot_{};
|
||||
// std::optional<process_context> process_snapshot_{};
|
||||
|
||||
void setup_hooks();
|
||||
void setup_process(const emulator_settings& settings);
|
||||
|
||||
Reference in New Issue
Block a user