Add binary loader
This commit is contained in:
parent
22bd1aad3f
commit
dfc1037bd2
18
premake5.lua
18
premake5.lua
@ -17,6 +17,15 @@ workspace "open-mw3"
|
||||
staticruntime "On"
|
||||
warnings "Extra"
|
||||
|
||||
flags {
|
||||
"StaticRuntime",
|
||||
"NoIncrementalLink",
|
||||
"NoEditAndContinue",
|
||||
"NoMinimalRebuild",
|
||||
"MultiProcessorCompile",
|
||||
"No64BitChecks"
|
||||
}
|
||||
|
||||
configuration "windows"
|
||||
defines {
|
||||
"_WINDOWS",
|
||||
@ -31,7 +40,6 @@ workspace "open-mw3"
|
||||
}
|
||||
|
||||
flags {
|
||||
"MultiProcessorCompile",
|
||||
"LinkTimeOptimization",
|
||||
"FatalCompileWarnings",
|
||||
}
|
||||
@ -44,10 +52,6 @@ workspace "open-mw3"
|
||||
"_DEBUG",
|
||||
}
|
||||
|
||||
flags {
|
||||
"MultiProcessorCompile",
|
||||
}
|
||||
|
||||
configuration {}
|
||||
|
||||
project "open-mw3"
|
||||
@ -56,6 +60,10 @@ workspace "open-mw3"
|
||||
|
||||
pchheader "std_include.hpp"
|
||||
pchsource "src/std_include.cpp"
|
||||
|
||||
linkoptions "/IGNORE:4254 /DYNAMICBASE:NO /SAFESEH:NO /LARGEADDRESSAWARE"
|
||||
linkoptions "/LAST:.zdata"
|
||||
|
||||
|
||||
files {
|
||||
"./src/**.rc",
|
||||
|
@ -111,7 +111,7 @@ void launcher::paint() const
|
||||
EndPaint(this->window_, &ps);
|
||||
}
|
||||
|
||||
void launcher::mouse_move(LPARAM l_param)
|
||||
void launcher::mouse_move(const LPARAM l_param)
|
||||
{
|
||||
this->mouse_.x = GET_X_LPARAM(l_param);
|
||||
this->mouse_.y = GET_Y_LPARAM(l_param);
|
||||
|
@ -17,7 +17,7 @@ window::window(const std::string& title, const int width, const int height)
|
||||
this->wc_.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
||||
this->wc_.hIcon = LoadIcon(handle, MAKEINTRESOURCE(102));
|
||||
this->wc_.hIconSm = this->wc_.hIcon;
|
||||
this->wc_.hbrBackground = CreateSolidBrush(RGB(35, 35, 35)); //HBRUSH(COLOR_WINDOW);
|
||||
this->wc_.hbrBackground = CreateSolidBrush(RGB(35, 35, 35));
|
||||
this->wc_.lpszClassName = L"omw3_window";
|
||||
RegisterClassEx(&this->wc_);
|
||||
|
||||
|
187
src/loader/loader.cpp
Normal file
187
src/loader/loader.cpp
Normal file
@ -0,0 +1,187 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader.hpp"
|
||||
|
||||
loader::loader(const launcher::mode mode) : mode_(mode)
|
||||
{
|
||||
}
|
||||
|
||||
void loader::patch()
|
||||
{
|
||||
}
|
||||
|
||||
FARPROC loader::load(const utils::nt::module& module) const
|
||||
{
|
||||
const auto buffer = this->load_binary();
|
||||
if (buffer.empty()) return nullptr;
|
||||
|
||||
utils::nt::module source(HMODULE(buffer.data()));
|
||||
if (!source) return nullptr;
|
||||
|
||||
this->load_sections(module, source);
|
||||
this->load_imports(module, source);
|
||||
|
||||
if (source.get_optional_header()->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size)
|
||||
{
|
||||
const IMAGE_TLS_DIRECTORY* target_tls = reinterpret_cast<PIMAGE_TLS_DIRECTORY>(module.get_ptr() + module
|
||||
.get_optional_header()
|
||||
->DataDirectory
|
||||
[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress);
|
||||
const IMAGE_TLS_DIRECTORY* source_tls = reinterpret_cast<PIMAGE_TLS_DIRECTORY>(module.get_ptr() + source
|
||||
.get_optional_header()
|
||||
->DataDirectory
|
||||
[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress);
|
||||
|
||||
*reinterpret_cast<DWORD*>(source_tls->AddressOfIndex) = 0;
|
||||
|
||||
DWORD old_protect;
|
||||
VirtualProtect(PVOID(target_tls->StartAddressOfRawData),
|
||||
source_tls->EndAddressOfRawData - source_tls->StartAddressOfRawData, PAGE_READWRITE, &old_protect);
|
||||
|
||||
const LPVOID tls_base = *reinterpret_cast<LPVOID*>(__readfsdword(0x2C));
|
||||
std::memmove(tls_base, PVOID(source_tls->StartAddressOfRawData),
|
||||
source_tls->EndAddressOfRawData - source_tls->StartAddressOfRawData);
|
||||
std::memmove(PVOID(target_tls->StartAddressOfRawData), PVOID(source_tls->StartAddressOfRawData),
|
||||
source_tls->EndAddressOfRawData - source_tls->StartAddressOfRawData);
|
||||
}
|
||||
|
||||
DWORD oldProtect;
|
||||
VirtualProtect(module.get_nt_headers(), 0x1000, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
|
||||
module.get_optional_header()->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] = source
|
||||
.get_optional_header()->DataDirectory[
|
||||
IMAGE_DIRECTORY_ENTRY_IMPORT];
|
||||
std::memmove(module.get_nt_headers(), source.get_nt_headers(),
|
||||
sizeof(IMAGE_NT_HEADERS) + (source.get_nt_headers()->FileHeader.NumberOfSections * (sizeof(
|
||||
IMAGE_SECTION_HEADER))));
|
||||
|
||||
return FARPROC(module.get_ptr() + source.get_relative_entry_point());
|
||||
}
|
||||
|
||||
void loader::set_import_resolver(const std::function<FARPROC(const std::string&, const std::string&)>& resolver)
|
||||
{
|
||||
this->import_resolver_ = resolver;
|
||||
}
|
||||
|
||||
std::string loader::load_binary() const
|
||||
{
|
||||
if (this->mode_ == launcher::mode::SINGLEPLAYER)
|
||||
{
|
||||
return loader::load_resource(BINARY_SP);
|
||||
}
|
||||
|
||||
if (this->mode_ == launcher::mode::MULTIPLAYER)
|
||||
{
|
||||
return loader::load_resource(BINARY_MP);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string loader::load_resource(const int id)
|
||||
{
|
||||
const auto res = FindResource(::utils::nt::module(), MAKEINTRESOURCE(id), RT_RCDATA);
|
||||
if (!res) return {};
|
||||
|
||||
const auto handle = LoadResource(nullptr, res);
|
||||
if (!handle) return {};
|
||||
|
||||
return std::string(LPSTR(LockResource(handle)), SizeofResource(nullptr, res));
|
||||
}
|
||||
|
||||
void loader::load_section(const utils::nt::module& target, const utils::nt::module& source,
|
||||
IMAGE_SECTION_HEADER* section)
|
||||
{
|
||||
void* target_ptr = target.get_ptr() + section->VirtualAddress;
|
||||
const void* source_ptr = source.get_ptr() + section->PointerToRawData;
|
||||
|
||||
if (PBYTE(target_ptr) >= (target.get_ptr() + BINARY_PAYLOAD_SIZE))
|
||||
{
|
||||
MessageBoxA(nullptr, "Section exceeds the binary payload size, please increase it!", nullptr, MB_ICONERROR);
|
||||
TerminateProcess(GetCurrentProcess(), 1);
|
||||
}
|
||||
|
||||
if (section->SizeOfRawData > 0)
|
||||
{
|
||||
const auto size_of_data = min(section->SizeOfRawData, section->Misc.VirtualSize);
|
||||
std::memmove(target_ptr, source_ptr, size_of_data);
|
||||
|
||||
DWORD old_protect;
|
||||
VirtualProtect(target_ptr, size_of_data, PAGE_EXECUTE_READWRITE, &old_protect);
|
||||
}
|
||||
}
|
||||
|
||||
void loader::load_sections(const utils::nt::module& target, const utils::nt::module& source) const
|
||||
{
|
||||
for (auto& section : source.get_section_headers())
|
||||
{
|
||||
this->load_section(target, source, section);
|
||||
}
|
||||
}
|
||||
|
||||
void loader::load_imports(const utils::nt::module& target, const utils::nt::module& source) const
|
||||
{
|
||||
IMAGE_DATA_DIRECTORY* import_directory = &source.get_optional_header()->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
|
||||
|
||||
auto descriptor = PIMAGE_IMPORT_DESCRIPTOR(target.get_ptr() + import_directory->VirtualAddress);
|
||||
|
||||
while (descriptor->Name)
|
||||
{
|
||||
std::string name = LPSTR(target.get_ptr() + descriptor->Name);
|
||||
|
||||
auto name_table_entry = reinterpret_cast<uintptr_t*>(target.get_ptr() + descriptor->OriginalFirstThunk);
|
||||
auto address_table_entry = reinterpret_cast<uintptr_t*>(target.get_ptr() + descriptor->FirstThunk);
|
||||
|
||||
if (!descriptor->OriginalFirstThunk)
|
||||
{
|
||||
name_table_entry = reinterpret_cast<uintptr_t*>(target.get_ptr() + descriptor->FirstThunk);
|
||||
}
|
||||
|
||||
while (*name_table_entry)
|
||||
{
|
||||
FARPROC function = nullptr;
|
||||
std::string function_name;
|
||||
|
||||
// is this an ordinal-only import?
|
||||
if (IMAGE_SNAP_BY_ORDINAL(*name_table_entry))
|
||||
{
|
||||
auto module = utils::nt::module::load(name);
|
||||
if (module)
|
||||
{
|
||||
function = GetProcAddress(module, MAKEINTRESOURCEA(IMAGE_ORDINAL(*name_table_entry)));
|
||||
}
|
||||
|
||||
function_name = "#" + std::to_string(IMAGE_ORDINAL(*name_table_entry));
|
||||
}
|
||||
else
|
||||
{
|
||||
auto import = PIMAGE_IMPORT_BY_NAME(target.get_ptr() + *name_table_entry);
|
||||
function_name = import->Name;
|
||||
|
||||
if (this->import_resolver_) function = this->import_resolver_(name, function_name);
|
||||
if (!function)
|
||||
{
|
||||
auto module = utils::nt::module::load(name);
|
||||
if (module)
|
||||
{
|
||||
function = GetProcAddress(module, function_name.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function)
|
||||
{
|
||||
auto error = "Unable to load import '"s + function_name + "' from module '"s + name + "'"s;
|
||||
|
||||
MessageBoxA(nullptr, error.data(), nullptr, MB_ICONERROR);
|
||||
TerminateProcess(GetCurrentProcess(), 1);
|
||||
}
|
||||
|
||||
*address_table_entry = reinterpret_cast<uintptr_t>(function);
|
||||
|
||||
name_table_entry++;
|
||||
address_table_entry++;
|
||||
}
|
||||
|
||||
descriptor++;
|
||||
}
|
||||
}
|
26
src/loader/loader.hpp
Normal file
26
src/loader/loader.hpp
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
#include "utils/nt.hpp"
|
||||
#include "launcher/launcher.hpp"
|
||||
|
||||
class loader final
|
||||
{
|
||||
public:
|
||||
explicit loader(launcher::mode mode);
|
||||
|
||||
void patch();
|
||||
FARPROC load(const utils::nt::module& module) const;
|
||||
|
||||
void set_import_resolver(const std::function<FARPROC(const std::string&, const std::string&)>& resolver);
|
||||
|
||||
private:
|
||||
launcher::mode mode_;
|
||||
std::function<FARPROC(const std::string&, const std::string&)> import_resolver_;
|
||||
|
||||
std::string load_binary() const;
|
||||
static std::string load_resource(const int id);
|
||||
|
||||
static void load_section(const utils::nt::module& target, const utils::nt::module& source, IMAGE_SECTION_HEADER* section);
|
||||
void load_sections(const utils::nt::module& target, const utils::nt::module& source) const;
|
||||
void load_imports(const utils::nt::module& target, const utils::nt::module& source) const;
|
||||
|
||||
};
|
10
src/loader/module.hpp
Normal file
10
src/loader/module.hpp
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
class module
|
||||
{
|
||||
public:
|
||||
virtual ~module() {};
|
||||
virtual void pre_load() {}
|
||||
virtual void post_load() {}
|
||||
virtual void pre_destroy() {}
|
||||
};
|
40
src/main.cpp
40
src/main.cpp
@ -1,23 +1,37 @@
|
||||
#include <std_include.hpp>
|
||||
#include "launcher/launcher.hpp"
|
||||
#include "loader/loader.hpp"
|
||||
|
||||
int CALLBACK WinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int /*nCmdShow*/)
|
||||
{
|
||||
launcher launcher;
|
||||
const auto mode = launcher.run();
|
||||
FARPROC entry_point = nullptr;
|
||||
|
||||
if(mode == launcher::mode::NONE)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if(mode == launcher::mode::SINGLEPLAYER)
|
||||
{
|
||||
OutputDebugStringA("\n\nSINGLEPLAYER\n\n");
|
||||
}
|
||||
else if(mode == launcher::mode::MULTIPLAYER)
|
||||
{
|
||||
MessageBoxA(nullptr, "Multiplayer not supported yet!", "ERROR", MB_ICONEXCLAMATION);
|
||||
launcher launcher;
|
||||
const auto mode = launcher.run();
|
||||
|
||||
if (mode == launcher::mode::NONE) return 0;
|
||||
|
||||
loader loader(mode);
|
||||
loader.set_import_resolver([](const std::string& module, const std::string& function) -> FARPROC
|
||||
{
|
||||
if (module == "steam_api.dll")
|
||||
{
|
||||
return utils::nt::module().get_proc<FARPROC>(function);
|
||||
}
|
||||
else if (function == "ExitProcess")
|
||||
{
|
||||
return FARPROC(exit);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
});
|
||||
|
||||
entry_point = loader.load({});
|
||||
if (!entry_point) return 1;
|
||||
|
||||
loader.patch();
|
||||
}
|
||||
|
||||
return 0;
|
||||
return entry_point();
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#define IMAGE_SP 300
|
||||
#define IMAGE_MP 301
|
||||
#define IMAGE_SP 300
|
||||
#define IMAGE_MP 301
|
||||
#define BINARY_SP 302
|
||||
#define BINARY_MP 303
|
||||
|
@ -86,9 +86,11 @@ END
|
||||
// Binary Data
|
||||
//
|
||||
|
||||
102 ICON "resources/icon.ico"
|
||||
IMAGE_SP BITMAP "resources/singleplayer.bmp"
|
||||
IMAGE_MP BITMAP "resources/multiplayer.bmp"
|
||||
102 ICON "resources/icon.ico"
|
||||
IMAGE_SP BITMAP "resources/singleplayer.bmp"
|
||||
IMAGE_MP BITMAP "resources/multiplayer.bmp"
|
||||
BINARY_SP RCDATA "resources/iw5sp.exe"
|
||||
BINARY_MP RCDATA "resources/iw5mp.exe"
|
||||
|
||||
|
||||
#endif // English (United States) resources
|
||||
|
@ -1 +1,18 @@
|
||||
#include <std_include.hpp>
|
||||
|
||||
#pragma comment(linker, "/merge:.data=.cld")
|
||||
#pragma comment(linker, "/merge:.rdata=.clr")
|
||||
#pragma comment(linker, "/merge:.cl=.zdata")
|
||||
#pragma comment(linker, "/merge:.text=.zdata")
|
||||
#pragma comment(linker, "/section:.zdata,re")
|
||||
#pragma comment(linker, "/base:0x400000")
|
||||
|
||||
__declspec(thread) char tls_data[0x2000];
|
||||
|
||||
#pragma bss_seg(".cdummy")
|
||||
char dummy_seg[BINARY_PAYLOAD_SIZE];
|
||||
|
||||
char stub_seg[0x100000];
|
||||
|
||||
#pragma data_seg(".zdata")
|
||||
char zdata[200] = { 1 };
|
||||
|
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#define BINARY_PAYLOAD_SIZE 0x0A000000
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4458)
|
||||
|
||||
@ -14,6 +16,8 @@
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
|
||||
#pragma warning(pop)
|
||||
|
||||
|
202
src/utils/nt.cpp
Normal file
202
src/utils/nt.cpp
Normal file
@ -0,0 +1,202 @@
|
||||
#include <std_include.hpp>
|
||||
#include "nt.hpp"
|
||||
|
||||
namespace utils
|
||||
{
|
||||
namespace nt
|
||||
{
|
||||
module module::load(const std::string& name)
|
||||
{
|
||||
return module(LoadLibraryA(name.data()));
|
||||
}
|
||||
|
||||
module module::get_by_address(void* address)
|
||||
{
|
||||
HMODULE handle = nullptr;
|
||||
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast<LPCSTR>(address), &handle);
|
||||
return module(handle);
|
||||
}
|
||||
|
||||
module::module()
|
||||
{
|
||||
this->module_ = GetModuleHandleA(nullptr);
|
||||
}
|
||||
|
||||
module::module(const std::string& name)
|
||||
{
|
||||
this->module_ = GetModuleHandleA(name.data());
|
||||
}
|
||||
|
||||
module::module(const HMODULE handle)
|
||||
{
|
||||
this->module_ = handle;
|
||||
}
|
||||
|
||||
bool module::operator==(const module &obj) const
|
||||
{
|
||||
return this->module_ == obj.module_;
|
||||
}
|
||||
|
||||
module::operator bool() const
|
||||
{
|
||||
return this->is_valid();
|
||||
}
|
||||
|
||||
module::operator HMODULE() const
|
||||
{
|
||||
return this->get_handle();
|
||||
}
|
||||
|
||||
PIMAGE_NT_HEADERS module::get_nt_headers() const
|
||||
{
|
||||
if (!this->is_valid()) return nullptr;
|
||||
return reinterpret_cast<PIMAGE_NT_HEADERS>(this->get_ptr() + this->get_dos_header()->e_lfanew);
|
||||
}
|
||||
|
||||
PIMAGE_DOS_HEADER module::get_dos_header() const
|
||||
{
|
||||
return reinterpret_cast<PIMAGE_DOS_HEADER>(this->get_ptr());
|
||||
}
|
||||
|
||||
PIMAGE_OPTIONAL_HEADER module::get_optional_header() const
|
||||
{
|
||||
if (!this->is_valid()) return nullptr;
|
||||
return &this->get_nt_headers()->OptionalHeader;
|
||||
}
|
||||
|
||||
std::vector<PIMAGE_SECTION_HEADER> module::get_section_headers() const
|
||||
{
|
||||
std::vector<PIMAGE_SECTION_HEADER> headers;
|
||||
|
||||
auto nt_headers = this->get_nt_headers();
|
||||
auto section = IMAGE_FIRST_SECTION(nt_headers);
|
||||
|
||||
for (uint16_t i = 0; i < nt_headers->FileHeader.NumberOfSections; ++i, ++section)
|
||||
{
|
||||
if (section) headers.push_back(section);
|
||||
else OutputDebugStringA("There was an invalid section :O");
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
std::uint8_t* module::get_ptr() const
|
||||
{
|
||||
return reinterpret_cast<std::uint8_t*>(this->module_);
|
||||
}
|
||||
|
||||
void module::unprotect() const
|
||||
{
|
||||
if (!this->is_valid()) return;
|
||||
|
||||
DWORD protection;
|
||||
VirtualProtect(this->get_ptr(), this->get_optional_header()->SizeOfImage, PAGE_EXECUTE_READWRITE, &protection);
|
||||
}
|
||||
|
||||
size_t module::get_relative_entry_point() const
|
||||
{
|
||||
if (!this->is_valid()) return 0;
|
||||
return this->get_nt_headers()->OptionalHeader.AddressOfEntryPoint;
|
||||
}
|
||||
|
||||
void* module::get_entry_point() const
|
||||
{
|
||||
if (!this->is_valid()) return nullptr;
|
||||
return this->get_ptr() + this->get_relative_entry_point();
|
||||
}
|
||||
|
||||
bool module::is_valid() const
|
||||
{
|
||||
return this->module_ != nullptr && this->get_dos_header()->e_magic == IMAGE_DOS_SIGNATURE;
|
||||
}
|
||||
|
||||
std::string module::get_name() const
|
||||
{
|
||||
if (!this->is_valid()) return "";
|
||||
|
||||
auto path = this->get_path();
|
||||
const auto pos = path.find_last_of("/\\");
|
||||
if (pos == std::string::npos) return path;
|
||||
|
||||
return path.substr(pos + 1);
|
||||
}
|
||||
|
||||
std::string module::get_path() const
|
||||
{
|
||||
if (!this->is_valid()) return "";
|
||||
|
||||
char name[MAX_PATH] = { 0 };
|
||||
GetModuleFileNameA(this->module_, name, sizeof name);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
void module::free()
|
||||
{
|
||||
if (this->is_valid())
|
||||
{
|
||||
FreeLibrary(this->module_);
|
||||
this->module_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
HMODULE module::get_handle() const
|
||||
{
|
||||
return this->module_;
|
||||
}
|
||||
|
||||
void** module::get_iat_entry(const std::string& module_name, const std::string& proc_name) const
|
||||
{
|
||||
if (!this->is_valid()) return nullptr;
|
||||
|
||||
module other_module(module_name);
|
||||
if (!other_module.is_valid()) return nullptr;
|
||||
|
||||
const auto target_function = other_module.get_proc<void*>(proc_name);
|
||||
if (!target_function) return nullptr;
|
||||
|
||||
auto* header = this->get_optional_header();
|
||||
if (!header) return nullptr;
|
||||
|
||||
auto* import_descriptor = reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(this->get_ptr() + header->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
|
||||
|
||||
while (import_descriptor->Name)
|
||||
{
|
||||
if (!_stricmp(reinterpret_cast<char*>(this->get_ptr() + import_descriptor->Name), module_name.data()))
|
||||
{
|
||||
auto* original_thunk_data = reinterpret_cast<PIMAGE_THUNK_DATA>(import_descriptor->OriginalFirstThunk + this->get_ptr());
|
||||
auto* thunk_data = reinterpret_cast<PIMAGE_THUNK_DATA>(import_descriptor->FirstThunk + this->get_ptr());
|
||||
|
||||
while(original_thunk_data->u1.AddressOfData)
|
||||
{
|
||||
const size_t ordinal_number = original_thunk_data->u1.AddressOfData & 0xFFFFFFF;
|
||||
|
||||
if (ordinal_number > 0xFFFF) continue;
|
||||
|
||||
if (GetProcAddress(other_module.module_, reinterpret_cast<char*>(ordinal_number)) == target_function)
|
||||
{
|
||||
return reinterpret_cast<void**>(&thunk_data->u1.Function);
|
||||
}
|
||||
|
||||
++original_thunk_data;
|
||||
++thunk_data;
|
||||
}
|
||||
|
||||
//break;
|
||||
}
|
||||
|
||||
++import_descriptor;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void raise_hard_exception()
|
||||
{
|
||||
int data = false;
|
||||
utils::nt::module ntdll("ntdll.dll");
|
||||
ntdll.invoke_pascal<void>("RtlAdjustPrivilege", 19, true, false, &data);
|
||||
ntdll.invoke_pascal<void>("NtRaiseHardError", 0xC000007B, 0, nullptr, nullptr, 6, &data);
|
||||
}
|
||||
}
|
||||
}
|
89
src/utils/nt.hpp
Normal file
89
src/utils/nt.hpp
Normal file
@ -0,0 +1,89 @@
|
||||
#pragma once
|
||||
|
||||
namespace utils
|
||||
{
|
||||
namespace nt
|
||||
{
|
||||
class module final
|
||||
{
|
||||
public:
|
||||
static module load(const std::string& name);
|
||||
static module get_by_address(void* address);
|
||||
|
||||
module();
|
||||
explicit module(const std::string& name);
|
||||
explicit module(HMODULE handle);
|
||||
|
||||
module(const module& a) : module_(a.module_) {}
|
||||
|
||||
bool operator!=(const module &obj) const { return !(*this == obj); };
|
||||
bool operator==(const module &obj) const;
|
||||
|
||||
operator bool() const;
|
||||
operator HMODULE() const;
|
||||
|
||||
void unprotect() const;
|
||||
void* get_entry_point() const;
|
||||
size_t get_relative_entry_point() const;
|
||||
|
||||
bool is_valid() const;
|
||||
std::string get_name() const;
|
||||
std::string get_path() const;
|
||||
std::uint8_t* get_ptr() const;
|
||||
void free();
|
||||
|
||||
HMODULE get_handle() const;
|
||||
|
||||
template <typename T>
|
||||
T get_proc(const std::string& process)
|
||||
{
|
||||
if (!this->is_valid()) T{};
|
||||
return reinterpret_cast<T>(GetProcAddress(this->module_, process.data()));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::function<T> get(const std::string& process)
|
||||
{
|
||||
if (!this->is_valid()) std::function<T>();
|
||||
return reinterpret_cast<T*>(this->get_proc<void*>(process));
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
T invoke(const std::string& process, Args... args)
|
||||
{
|
||||
auto method = this->get<T(__cdecl)(Args...)>(process);
|
||||
if (method) return method(args...);
|
||||
return T();
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
T invoke_pascal(const std::string& process, Args... args)
|
||||
{
|
||||
auto method = this->get<T(__stdcall)(Args...)>(process);
|
||||
if (method) return method(args...);
|
||||
return T();
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
T invoke_this(const std::string& process, void* thisPtr, Args... args)
|
||||
{
|
||||
auto method = this->get<T(__thiscall)(void*,Args...)>(thisPtr, process);
|
||||
if (method) return method(args...);
|
||||
return T();
|
||||
}
|
||||
|
||||
std::vector<PIMAGE_SECTION_HEADER> get_section_headers() const;
|
||||
|
||||
PIMAGE_NT_HEADERS get_nt_headers() const;
|
||||
PIMAGE_DOS_HEADER get_dos_header() const;
|
||||
PIMAGE_OPTIONAL_HEADER get_optional_header() const;
|
||||
|
||||
void** get_iat_entry(const std::string& module_name, const std::string& proc_name) const;
|
||||
|
||||
private:
|
||||
HMODULE module_;
|
||||
};
|
||||
|
||||
void raise_hard_exception();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user