From 7b6964eb1bcf30a0ae7ed3391adce30565b262b4 Mon Sep 17 00:00:00 2001 From: ladevieq Date: Sun, 12 Jul 2026 00:47:54 +0200 Subject: Load functions by hand --- src/loader.c | 235 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 src/loader.c (limited to 'src/loader.c') diff --git a/src/loader.c b/src/loader.c new file mode 100644 index 0000000..da98364 --- /dev/null +++ b/src/loader.c @@ -0,0 +1,235 @@ +#include "win_funcs.h" +#include "module.h" +#include "utils.h" + +// ======================= +// ====== windows.h ====== +// ======================= + +extern uint64_t __readgsqword(unsigned long offset); + +typedef struct _LIST_ENTRY { + struct _LIST_ENTRY *Flink; + struct _LIST_ENTRY *Blink; +} LIST_ENTRY, *PLIST_ENTRY, *PRLIST_ENTRY; + +typedef struct _UNICODE_STRING { + u16 Length; + u16 MaximumLength; + u16* Buffer; +} UNICODE_STRING, *PUNICODE_STRING; + +typedef struct _LDR_DATA_TABLE_ENTRY { + void* Reserved1[2]; + LIST_ENTRY InMemoryOrderLinks; + void* Reserved2[2]; + void* DllBase; + void* Reserved3[2]; + UNICODE_STRING FullDllName; + UNICODE_STRING BaseDllName; + void* Reserved5[2]; + union + { + u32 CheckSum; + void* Reserved6; + }; + u32 TimeDateStamp; +} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; + +typedef struct _PEB_LDR_DATA { + u8 Reserved1[8]; + void* Reserved2[3]; + LIST_ENTRY InMemoryOrderModuleList; +} PEB_LDR_DATA, *PPEB_LDR_DATA; + +typedef struct _RTL_USER_PROCESS_PARAMETERS { + u8 Reserved1[16]; + void* Reserved2[10]; + UNICODE_STRING ImagePathName; + UNICODE_STRING CommandLine; +} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS; + +typedef void(*PS_POST_PROCESS_INIT_ROUTINE)(void); +typedef PS_POST_PROCESS_INIT_ROUTINE* PPS_POST_PROCESS_INIT_ROUTINE; + +typedef struct _PEB { + u8 Reserved1[2]; + u8 BeingDebugged; + u8 Reserved2[21]; + PPEB_LDR_DATA LoaderData; + PRTL_USER_PROCESS_PARAMETERS ProcessParameters; + u8 Reserved3[520]; + PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine; + u8 Reserved4[136]; + u32 SessionId; +} PEB, *PPEB; + +typedef struct _TEB { + void* Reserved1[12]; + PPEB ProcessEnvironmentBlock; + void* Reserved2[399]; + u8 Reserved3[1952]; + void* TlsSlots[64]; + u8 Reserved4[8]; + void* Reserved5[26]; + void* ReservedForOle; + void* Reserved6[4]; + void* TlsExpansionSlots; +} TEB, *PTEB; + +typedef struct _IMAGE_EXPORT_DIRECTORY { + u32 Characteristics; + u32 TimeDateStamp; + u16 MajorVersion; + u16 MinorVersion; + u32 Name; + u32 Base; + u32 NumberOfFunctions; + u32 NumberOfNames; + u32 AddressOfFunctions; // RVA from base of image + u32 AddressOfNames; // RVA from base of image + u32 AddressOfNameOrdinals; // RVA from base of image +} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; + +// +// Code Page Default Values. +// Please Use Unicode, either UTF-16 (as in WCHAR) or UTF-8 (code page CP_ACP) +// +#define CP_ACP 0 // default to ANSI code page +#define CP_OEMCP 1 // default to OEM code page +#define CP_MACCP 2 // default to MAC code page +#define CP_THREAD_ACP 3 // current thread's ANSI code page +#define CP_SYMBOL 42 // SYMBOL translations + +#define CP_UTF7 65000 // UTF-7 translation +#define CP_UTF8 65001 // UTF-8 translation + +// ======================== +// ====== !windows.h ====== +// ======================== + +#define KERNEL32(name) \ + PFN_##name name = NULL; + +#define KERNEL_BASE(name) \ + PFN_##name name = NULL; + +#include "funcs.h" + +#undef KERNEL_BASE +#undef KERNEL32 + +i32 str_cmp(const i8* str1, size_t str1_len, const i8* str2, size_t str2_len) { + u32 min_len = str1_len < str2_len ? str1_len : str2_len; + + for (u32 index = 0U; index < min_len; index++) { + if (str1[index] < str2[index]) { + return -1; + } else if (str1[index] > str2[index]) { + return 1; + } + } + + return 0; +} + +i32 wstr_cmp(const u16* str1, size_t str1_len, const u16* str2, size_t str2_len) { + u32 min_len = str1_len < str2_len ? str1_len : str2_len; + + for (u32 index = 0U; index < min_len; index++) { + if (str1[index] < str2[index]) { + return -1; + } else if (str1[index] > str2[index]) { + return 1; + } + } + + return 0; +} + +PEB* get_PEB(void) { + return (PEB*)__readgsqword(__builtin_offsetof(TEB, ProcessEnvironmentBlock)); +} + +void* get_kernel32(void) { + const u16 kernel32_str[] = L"KERNEL32.DLL"; + PEB* PEB = get_PEB(); + LIST_ENTRY* last_entry = PEB->LoaderData->InMemoryOrderModuleList.Blink; + LIST_ENTRY* cur_entry = PEB->LoaderData->InMemoryOrderModuleList.Flink; + + while(cur_entry != last_entry) { + LDR_DATA_TABLE_ENTRY* table_entry = (LDR_DATA_TABLE_ENTRY*)((u8*)cur_entry - 0x10); + UNICODE_STRING* BaseDllName = &table_entry->BaseDllName; + + if (BaseDllName->Buffer) { + if (wstr_cmp(kernel32_str, sizeof(kernel32_str) / sizeof(u16), BaseDllName->Buffer, BaseDllName->Length / sizeof(u16)) == 0) { + return table_entry->DllBase; + } + } + + cur_entry = cur_entry->Flink; + } + + return NULL; +} + +void* get_kernel_base(void) { + const u16 kernel32_str[] = L"KERNELBASE.dll"; + PEB* PEB = get_PEB(); + LIST_ENTRY* last_entry = PEB->LoaderData->InMemoryOrderModuleList.Blink; + LIST_ENTRY* cur_entry = PEB->LoaderData->InMemoryOrderModuleList.Flink; + + while(cur_entry != last_entry) { + LDR_DATA_TABLE_ENTRY* table_entry = (LDR_DATA_TABLE_ENTRY*)((u8*)cur_entry - 0x10); + UNICODE_STRING* BaseDllName = &table_entry->BaseDllName; + + if (BaseDllName->Buffer) { + if (wstr_cmp(kernel32_str, sizeof(kernel32_str) / sizeof(u16), BaseDllName->Buffer, BaseDllName->Length / sizeof(u16)) == 0) { + return table_entry->DllBase; + } + } + + cur_entry = cur_entry->Flink; + } + + return NULL; +} + +void* load_func(u64 base_addr, const char* func_name, u32 func_name_len) { + IMAGE_DOS_HEADER* dos_header = (IMAGE_DOS_HEADER*)base_addr; + IMAGE_NT_HEADERS64* nt_header = (IMAGE_NT_HEADERS64*)(base_addr + dos_header->e_lfanew); + IMAGE_DATA_DIRECTORY export_table = nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; + const IMAGE_EXPORT_DIRECTORY* export_dir = (const IMAGE_EXPORT_DIRECTORY*)(base_addr + export_table.VirtualAddress); + + u16* ordinals = (u16*)(base_addr + export_dir->AddressOfNameOrdinals); + u32* names_address = (u32*)(base_addr + export_dir->AddressOfNames); + u32* addresses = (u32*)(base_addr + export_dir->AddressOfFunctions); + + for (u32 name_index = 0U; name_index < export_dir->NumberOfNames; name_index++) { + const char* name = (const char*)(base_addr + names_address[name_index]); + u32 length = str_len(name, 256U); + + if (str_cmp((i8*)name, length, (i8*)func_name, func_name_len) == 0) { + return (void*)(base_addr + addresses[ordinals[name_index]]); + } + } + + return NULL; +} + +void load_funcs(void) { + void* kernel32 = get_kernel32(); + void* kernel_base = get_kernel_base(); + +#define KERNEL32(name) \ + name = (PFN_##name)load_func((u64)kernel32, #name, sizeof(#name)); + +#define KERNEL_BASE(name) \ + name = (PFN_##name)load_func((u64)kernel_base, #name, sizeof(#name)); + +#include "funcs.h" + +#undef KERNEL_BASE +#undef KERNEL32 + +} -- cgit v1.3