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