Skip to content

Commit e4ac0ff

Browse files
committed
improved
1 parent 8440178 commit e4ac0ff

File tree

2 files changed

+60
-48
lines changed

2 files changed

+60
-48
lines changed

include/yail/yail.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,18 @@
1111
namespace yail
1212
{
1313
[[nodiscard]]
14-
std::expected<uintptr_t, std::string> manual_map_injection_from_raw(
14+
std::expected<std::uintptr_t, std::string> manual_map_injection_from_raw(
1515
const std::span<std::uint8_t>& raw_dll, std::uintptr_t process_id);
1616

1717
[[nodiscard]]
18-
std::expected<uintptr_t, std::string> manual_map_injection_from_raw(
18+
std::expected<std::uintptr_t, std::string> manual_map_injection_from_raw(
1919
const std::span<std::uint8_t>& raw_dll, const std::string_view& process_name);
2020

2121
[[nodiscard]]
22-
std::expected<uintptr_t, std::string> manual_map_injection_from_file(
22+
std::expected<std::uintptr_t, std::string> manual_map_injection_from_file(
2323
const std::string_view& dll_path, std::uintptr_t process_id);
2424

2525
[[nodiscard]]
26-
std::expected<uintptr_t, std::string> manual_map_injection_from_file(
26+
std::expected<std::uintptr_t, std::string> manual_map_injection_from_file(
2727
const std::string_view& dll_path, const std::string_view& process_name);
2828
}

source/yail.cpp

Lines changed: 56 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <TlHelp32.h>
66
#include <winternl.h>
77
#include <array>
8+
#include <format>
89
#include <fstream>
910
#include <omath/utility/pe_pattern_scan.hpp>
1011
#include <yail/yail.hpp>
@@ -13,12 +14,12 @@ namespace
1314
// Resolve MSVC incremental-link jump stubs (ILT): E9 xx xx xx xx → target
1415

1516
[[nodiscard]]
16-
uint8_t* resolve_ilt(void* fn)
17+
std::uint8_t* resolve_ilt(void* fn)
1718
{
18-
auto* p = static_cast<uint8_t*>(fn);
19+
auto* p = static_cast<std::uint8_t*>(fn);
1920
if (p[0] == 0xE9)
2021
{
21-
const auto rel = *reinterpret_cast<int32_t*>(p + 1);
22+
const auto rel = *reinterpret_cast<std::int32_t*>(p + 1);
2223
return p + 5 + rel;
2324
}
2425
return p;
@@ -43,7 +44,7 @@ namespace
4344
using RtlInsertInvertedFunctionTableFn = void(NTAPI*)(PVOID image_base, ULONG size_of_image);
4445

4546
[[nodiscard]]
46-
LdrpHandleTlsDataFn find_ldrp_handle_tls_data()
47+
std::expected<LdrpHandleTlsDataFn, std::string> find_ldrp_handle_tls_data()
4748
{
4849
constexpr std::array signatures = {
4950
"4C 8B DC 49 89 5B ? 49 89 73 ? 57 41 54 41 55 41 56 41 57 48 81 EC ? ? ? ? 48 8B 05 ? ? ? ? 48 33 C4 48 89 84 24 ? ? ? ? 48 8B F9", // Windows 11 24H2
@@ -53,17 +54,14 @@ namespace
5354

5455
const auto* ntdll = GetModuleHandleA("ntdll.dll");
5556
for (const auto* sig : signatures)
56-
{
57-
const auto result = omath::PePatternScanner::scan_for_pattern_in_loaded_module(ntdll, sig);
58-
if (result)
57+
if (const auto result = omath::PePatternScanner::scan_for_pattern_in_loaded_module(ntdll, sig))
5958
return reinterpret_cast<LdrpHandleTlsDataFn>(result.value());
60-
}
6159

62-
throw std::runtime_error{"Failed to find LdrpHandleTlsData"};
60+
return std::unexpected("Failed to find LdrpHandleTlsData");
6361
}
6462

6563
[[nodiscard]]
66-
RtlInsertInvertedFunctionTableFn find_rtl_insert_inverted_function_table()
64+
std::expected<RtlInsertInvertedFunctionTableFn, std::string> find_rtl_insert_inverted_function_table()
6765
{
6866
constexpr std::array signatures = {
6967
"48 8B C4 48 89 58 ? 48 89 68 ? 48 89 70 ? 57 48 83 EC ? 83 60", // Windows 11 24H2
@@ -75,11 +73,11 @@ namespace
7573
if (const auto result = omath::PePatternScanner::scan_for_pattern_in_loaded_module(ntdll, sig))
7674
return reinterpret_cast<RtlInsertInvertedFunctionTableFn>(result.value());
7775

78-
throw std::runtime_error{"Failed to find RtlInsertInvertedFunctionTable"};
76+
return std::unexpected("Failed to find RtlInsertInvertedFunctionTable");
7977
}
8078
struct RemoteLoaderData final
8179
{
82-
uint8_t* image_base;
80+
std::uint8_t* image_base;
8381
DWORD nt_headers_rva;
8482

8583
decltype(&LoadLibraryA) fn_load_library_a;
@@ -129,7 +127,7 @@ namespace
129127
}
130128
if (!fn)
131129
return 2;
132-
first_trunk->u1.Function = reinterpret_cast<uintptr_t>(fn);
130+
first_trunk->u1.Function = reinterpret_cast<std::uintptr_t>(fn);
133131
original_trunk++;
134132
first_trunk++;
135133
}
@@ -185,7 +183,7 @@ namespace
185183
{
186184
data->fn_rtl_add_function_table(
187185
reinterpret_cast<IMAGE_RUNTIME_FUNCTION_ENTRY*>(base + VirtualAddress),
188-
Size / sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY), reinterpret_cast<uintptr_t>(base));
186+
Size / sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY), reinterpret_cast<std::uintptr_t>(base));
189187
}
190188
}
191189

@@ -209,7 +207,7 @@ namespace
209207
#pragma optimize("", on)
210208
#endif
211209
[[nodiscard]]
212-
bool is_portable_executable(const std::span<uint8_t>& raw_dll)
210+
bool is_portable_executable(const std::span<std::uint8_t>& raw_dll)
213211
{
214212
const auto dos_headers = reinterpret_cast<const IMAGE_DOS_HEADER*>(raw_dll.data());
215213

@@ -221,12 +219,12 @@ namespace
221219
return nt_headers->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64;
222220
}
223221

224-
void relocate_for_base(uint8_t* local_image, const uintptr_t target_base)
222+
void relocate_for_base(std::uint8_t* local_image, const std::uintptr_t target_base)
225223
{
226224
const auto* dos_headers = reinterpret_cast<IMAGE_DOS_HEADER*>(local_image);
227225
auto* nt_headers = reinterpret_cast<IMAGE_NT_HEADERS*>(local_image + dos_headers->e_lfanew);
228226

229-
const auto delta = static_cast<intptr_t>(target_base - nt_headers->OptionalHeader.ImageBase);
227+
const auto delta = static_cast<std::intptr_t>(target_base - nt_headers->OptionalHeader.ImageBase);
230228
if (delta == 0)
231229
return;
232230

@@ -238,16 +236,16 @@ namespace
238236
auto* block = reinterpret_cast<IMAGE_BASE_RELOCATION*>(local_image + relocation_directory.VirtualAddress);
239237
while (block->SizeOfBlock && block->VirtualAddress)
240238
{
241-
const size_t count = (block->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
242-
auto* info = reinterpret_cast<uint16_t*>(block + 1);
243-
for (size_t i = 0; i < count; i++, info++)
239+
const std::size_t count = (block->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
240+
auto* info = reinterpret_cast<std::uint16_t*>(block + 1);
241+
for (std::size_t i = 0; i < count; i++, info++)
244242
{
245243
if (*info >> 0x0C != IMAGE_REL_BASED_DIR64)
246244
continue;
247-
auto* patch = reinterpret_cast<uintptr_t*>(local_image + block->VirtualAddress + (*info & 0xFFF));
245+
auto* patch = reinterpret_cast<std::uintptr_t*>(local_image + block->VirtualAddress + (*info & 0xFFF));
248246
*patch += delta;
249247
}
250-
block = reinterpret_cast<IMAGE_BASE_RELOCATION*>(reinterpret_cast<uint8_t*>(block) + block->SizeOfBlock);
248+
block = reinterpret_cast<IMAGE_BASE_RELOCATION*>(reinterpret_cast<std::uint8_t*>(block) + block->SizeOfBlock);
251249
}
252250

253251
nt_headers->OptionalHeader.ImageBase = target_base;
@@ -297,24 +295,24 @@ namespace yail
297295
FALSE, static_cast<DWORD>(process_id));
298296

299297
if (!process_handle)
300-
return std::unexpected("Failed to open target process (error " + std::to_string(GetLastError()) + ")");
298+
return std::unexpected(std::format("Failed to open target process (error {})", GetLastError()));
301299

302300
const auto* dos = reinterpret_cast<const IMAGE_DOS_HEADER*>(raw_dll.data());
303301
const auto* nt = reinterpret_cast<const IMAGE_NT_HEADERS*>(raw_dll.data() + dos->e_lfanew);
304302
const std::size_t image_size = nt->OptionalHeader.SizeOfImage;
305303

306304
// Allocate image memory in target process
307-
auto* remote_image = static_cast<uint8_t*>(
305+
auto* remote_image = static_cast<std::uint8_t*>(
308306
VirtualAllocEx(process_handle, nullptr, image_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE));
309307

310308
if (!remote_image)
311309
{
312310
CloseHandle(process_handle);
313-
return std::unexpected("VirtualAllocEx failed for image (error " + std::to_string(GetLastError()) + ")");
311+
return std::unexpected(std::format("VirtualAllocEx failed for image (error {})", GetLastError()));
314312
}
315313

316314
// Prepare local copy: headers + sections
317-
std::vector<uint8_t> local_image(image_size, 0);
315+
std::vector<std::uint8_t> local_image(image_size, 0);
318316
std::copy_n(raw_dll.data(), nt->OptionalHeader.SizeOfHeaders, local_image.data());
319317

320318
auto* section_header = IMAGE_FIRST_SECTION(nt);
@@ -327,7 +325,7 @@ namespace yail
327325
}
328326

329327
// Relocate for remote base address
330-
relocate_for_base(local_image.data(), reinterpret_cast<uintptr_t>(remote_image));
328+
relocate_for_base(local_image.data(), reinterpret_cast<std::uintptr_t>(remote_image));
331329

332330
// Write image to target
333331
if (!WriteProcessMemory(process_handle, remote_image, local_image.data(), image_size, nullptr))
@@ -340,14 +338,14 @@ namespace yail
340338
// Prepare shellcode page: [RemoteLoaderData | padding | shellcode bytes]
341339
const auto* shell_code_start = resolve_ilt(reinterpret_cast<void*>(&remote_shellcode));
342340
const auto* shell_code_end = resolve_ilt(reinterpret_cast<void*>(&remote_shellcode_end));
343-
auto size_of_shell_code = static_cast<size_t>(shell_code_end - shell_code_start);
341+
auto size_of_shell_code = static_cast<std::size_t>(shell_code_end - shell_code_start);
344342
if (size_of_shell_code < 0x100)
345343
size_of_shell_code = 0x1000; // safety floor
346344

347-
constexpr size_t data_aligned = (sizeof(RemoteLoaderData) + 0xF) & ~0xF;
348-
const size_t total_shellcode = data_aligned + size_of_shell_code;
345+
constexpr std::size_t data_aligned = (sizeof(RemoteLoaderData) + 0xF) & ~0xF;
346+
const std::size_t total_shellcode = data_aligned + size_of_shell_code;
349347

350-
auto* remote_shellcode = static_cast<uint8_t*>(
348+
auto* remote_shellcode = static_cast<std::uint8_t*>(
351349
VirtualAllocEx(process_handle, nullptr, total_shellcode, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE));
352350

353351
if (!remote_shellcode)
@@ -368,14 +366,28 @@ namespace yail
368366
loader_data.fn_load_library_a = LoadLibraryA;
369367
loader_data.fn_get_proc_address = GetProcAddress;
370368
loader_data.fn_rtl_add_function_table = RtlAddFunctionTable;
371-
loader_data.fn_ldrp_handle_tls_data = reinterpret_cast<void*>(find_ldrp_handle_tls_data());
372-
loader_data.fn_rtl_insert_inverted_function_table =
373-
reinterpret_cast<void*>(find_rtl_insert_inverted_function_table());
369+
const auto tls_fn = find_ldrp_handle_tls_data();
370+
if (!tls_fn)
371+
{
372+
VirtualFreeEx(process_handle, remote_image, 0, MEM_RELEASE);
373+
CloseHandle(process_handle);
374+
return std::unexpected(tls_fn.error());
375+
}
376+
const auto inv_fn = find_rtl_insert_inverted_function_table();
377+
if (!inv_fn)
378+
{
379+
VirtualFreeEx(process_handle, remote_image, 0, MEM_RELEASE);
380+
CloseHandle(process_handle);
381+
return std::unexpected(inv_fn.error());
382+
}
383+
384+
loader_data.fn_ldrp_handle_tls_data = reinterpret_cast<void*>(tls_fn.value());
385+
loader_data.fn_rtl_insert_inverted_function_table = reinterpret_cast<void*>(inv_fn.value());
374386

375387
// Build local shellcode page
376-
std::vector<uint8_t> shell_code_page(total_shellcode, 0);
377-
std::memcpy(shell_code_page.data(), &loader_data, sizeof(loader_data));
378-
std::memcpy(shell_code_page.data() + data_aligned, shell_code_start, size_of_shell_code);
388+
std::vector<std::uint8_t> shell_code_page(total_shellcode, 0);
389+
std::copy_n(reinterpret_cast<const std::uint8_t*>(&loader_data), sizeof(loader_data), shell_code_page.data());
390+
std::copy_n(shell_code_start, size_of_shell_code, shell_code_page.data() + data_aligned);
379391

380392
// Write shellcode page to target
381393
if (!WriteProcessMemory(process_handle, remote_shellcode, shell_code_page.data(), total_shellcode, nullptr))
@@ -398,7 +410,7 @@ namespace yail
398410
VirtualFreeEx(process_handle, remote_shellcode, 0, MEM_RELEASE);
399411
VirtualFreeEx(process_handle, remote_image, 0, MEM_RELEASE);
400412
CloseHandle(process_handle);
401-
return std::unexpected("CreateRemoteThread failed (error " + std::to_string(GetLastError()) + ")");
413+
return std::unexpected(std::format("CreateRemoteThread failed (error {})", GetLastError()));
402414
}
403415

404416
WaitForSingleObject(thread_handle, INFINITE);
@@ -412,24 +424,24 @@ namespace yail
412424
CloseHandle(process_handle);
413425

414426
if (exit_code != 0)
415-
return std::unexpected("Remote shellcode failed (exit code " + std::to_string(exit_code) + ")");
427+
return std::unexpected(std::format("Remote shellcode failed (exit code {})", exit_code));
416428

417-
return reinterpret_cast<uintptr_t>(remote_image);
429+
return reinterpret_cast<std::uintptr_t>(remote_image);
418430
}
419431
std::expected<uintptr_t, std::string> manual_map_injection_from_raw(const std::span<std::uint8_t>& raw_dll,
420432
const std::string_view& process_name)
421433
{
422434
const auto pid = get_process_id_by_name(process_name);
423435

424436
if (!pid)
425-
return std::unexpected("Process \"" + std::string(process_name) + "\" not found");
437+
return std::unexpected(std::format("Process \"{}\" not found", process_name));
426438

427439
return manual_map_injection_from_raw(raw_dll, pid.value());
428440
}
429441
std::expected<uintptr_t, std::string> manual_map_injection_from_file(const std::string_view& dll_path,
430442
const std::uintptr_t process_id)
431443
{
432-
std::vector<uint8_t> data(std::filesystem::file_size(dll_path), 0);
444+
std::vector<std::uint8_t> data(std::filesystem::file_size(dll_path), 0);
433445
std::ifstream file(std::filesystem::path{dll_path}, std::ios::binary);
434446
if (!file.is_open())
435447
return std::unexpected("Failed to open DLL file");
@@ -441,7 +453,7 @@ namespace yail
441453
std::expected<uintptr_t, std::string> manual_map_injection_from_file(const std::string_view& dll_path,
442454
const std::string_view& process_name)
443455
{
444-
std::vector<uint8_t> data(std::filesystem::file_size(dll_path), 0);
456+
std::vector<std::uint8_t> data(std::filesystem::file_size(dll_path), 0);
445457
std::ifstream file(std::filesystem::path{dll_path}, std::ios::binary);
446458
if (!file.is_open())
447459
return std::unexpected("Failed to open DLL file");
@@ -450,4 +462,4 @@ namespace yail
450462

451463
return manual_map_injection_from_raw({data.data(), data.size()}, process_name);
452464
}
453-
} // namespace yail
465+
} // namespace yail

0 commit comments

Comments
 (0)