summaryrefslogtreecommitdiffstats
path: root/src/loader.c
diff options
context:
space:
mode:
authorladevieq <ladevie.quentin@gmail.com>2026-07-12 00:47:54 +0200
committerladevieq <ladevie.quentin@gmail.com>2026-07-12 00:47:54 +0200
commit7b6964eb1bcf30a0ae7ed3391adce30565b262b4 (patch)
tree3bbf89d582a1466a2319ccaaf6d4cbb734bdd66b /src/loader.c
parentce51256c91e566d339c6a670af11bab519f98349 (diff)
Load functions by hand
Diffstat (limited to 'src/loader.c')
-rw-r--r--src/loader.c235
1 files changed, 235 insertions, 0 deletions
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
+
+}