44#include < Windows.h>
55#include < TlHelp32.h>
66#include < winternl.h>
7+ #include < algorithm>
78#include < array>
89#include < format>
910#include < fstream>
@@ -24,6 +25,41 @@ namespace
2425 }
2526 return p;
2627 }
28+ [[nodiscard]]
29+ std::size_t shellcode_section_size (const std::uint8_t * shell_code_start)
30+ {
31+ MEMORY_BASIC_INFORMATION memory_info{};
32+ if (!VirtualQuery (shell_code_start, &memory_info, sizeof (memory_info)))
33+ return 0 ;
34+
35+ const auto * image_base = static_cast <const std::uint8_t *>(memory_info.AllocationBase );
36+ const auto * dos_headers = reinterpret_cast <const IMAGE_DOS_HEADER *>(image_base);
37+ if (dos_headers->e_magic != IMAGE_DOS_SIGNATURE )
38+ return 0 ;
39+
40+ const auto * nt_headers = reinterpret_cast <const IMAGE_NT_HEADERS *>(image_base + dos_headers->e_lfanew );
41+ if (nt_headers->Signature != IMAGE_NT_SIGNATURE )
42+ return 0 ;
43+
44+ constexpr std::array<std::uint8_t , IMAGE_SIZEOF_SHORT_NAME > expected_name{' .' , ' y' , ' a' , ' i' , ' l' };
45+ const auto shell_code_rva =
46+ reinterpret_cast <std::uintptr_t >(shell_code_start) - reinterpret_cast <std::uintptr_t >(image_base);
47+ const auto * section = IMAGE_FIRST_SECTION (nt_headers);
48+ for (std::uint16_t i = 0 ; i < nt_headers->FileHeader .NumberOfSections ; i++, section++)
49+ {
50+ if (!std::equal (expected_name.begin (), expected_name.end (), section->Name ))
51+ continue ;
52+
53+ const auto section_start = static_cast <std::size_t >(section->VirtualAddress );
54+ const auto section_size = static_cast <std::size_t >(section->Misc .VirtualSize );
55+ if (shell_code_rva < section_start || shell_code_rva - section_start >= section_size)
56+ return 0 ;
57+
58+ return section_size - (shell_code_rva - section_start);
59+ }
60+
61+ return 0 ;
62+ }
2763 struct LdrDataTableEntryFull final
2864 {
2965 LIST_ENTRY in_load_order_links;
@@ -117,8 +153,8 @@ namespace
117153#pragma optimize("ts", on)
118154#pragma strict_gs_check(push, off)
119155#endif
120- // Ordered COFF subsections keep the end marker adjacent after linking .
121- __declspec (safebuffers) __declspec(noinline) __declspec(code_seg(" .text$yail_shellcode $a" )) DWORD WINAPI
156+ // A dedicated PE section keeps sizing independent from consumer linker ordering .
157+ __declspec (safebuffers) __declspec(noinline) __declspec(code_seg(" .yail $a" )) DWORD WINAPI
122158 remote_shellcode (const RemoteLoaderData* data)
123159 {
124160 auto * base = data->image_base ;
@@ -340,8 +376,9 @@ namespace
340376
341377 return 0 ;
342378 }
343- __declspec (noinline) __declspec(code_seg(" .text$yail_shellcode$ z" )) void remote_shellcode_end ()
379+ __declspec (noinline) __declspec(code_seg(" .yail$ z" )) std:: uint64_t remote_shellcode_end ()
344380 {
381+ return 0x5941494C5348454Cull ;
345382 }
346383
347384#ifdef _MSC_VER
@@ -497,16 +534,27 @@ namespace yail
497534
498535 // Prepare shellcode page: [RemoteLoaderData | padding | shellcode bytes]
499536 const auto * shell_code_start = resolve_ilt (reinterpret_cast <void *>(&remote_shellcode));
537+ const auto * shell_code_end = resolve_ilt (reinterpret_cast <void *>(&remote_shellcode_end));
500538 const auto shell_code_start_address = reinterpret_cast <std::uintptr_t >(shell_code_start);
501- const auto shell_code_end_address =
502- reinterpret_cast <std::uintptr_t >(resolve_ilt (reinterpret_cast <void *>(&remote_shellcode_end)));
503- if (shell_code_end_address <= shell_code_start_address)
539+ const auto shell_code_end_address = reinterpret_cast <std::uintptr_t >(shell_code_end);
540+ const auto section_size = shellcode_section_size (shell_code_start);
541+
542+ std::size_t size_of_shell_code = 0 ;
543+ if (shell_code_end_address > shell_code_start_address)
544+ {
545+ const auto marker_size = shell_code_end_address - shell_code_start_address;
546+ if (!section_size || marker_size <= section_size)
547+ size_of_shell_code = marker_size;
548+ }
549+ if (!size_of_shell_code)
550+ size_of_shell_code = section_size;
551+
552+ if (!size_of_shell_code)
504553 {
505554 VirtualFreeEx (process_handle, remote_image, 0 , MEM_RELEASE );
506555 CloseHandle (process_handle);
507- return std::unexpected (" Invalid shellcode section layout " );
556+ return std::unexpected (" Failed to determine shellcode size " );
508557 }
509- const auto size_of_shell_code = shell_code_end_address - shell_code_start_address;
510558
511559 constexpr std::size_t data_aligned = (sizeof (RemoteLoaderData) + 0xF ) & ~0xF ;
512560 const std::size_t total_shellcode = data_aligned + size_of_shell_code;
0 commit comments