aboutsummaryrefslogtreecommitdiff
path: root/source/tools/old/loadlib.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/tools/old/loadlib.c')
-rw-r--r--source/tools/old/loadlib.c397
1 files changed, 397 insertions, 0 deletions
diff --git a/source/tools/old/loadlib.c b/source/tools/old/loadlib.c
new file mode 100644
index 0000000..b2689ee
--- /dev/null
+++ b/source/tools/old/loadlib.c
@@ -0,0 +1,397 @@
+#include <windows.h>
+#include <string.h>
+
+#include "compat.h"
+
+#define MAKE_ORDINAL(val) (val & 0xffff)
+#define ROUND(n, r) (((n + (r - 1)) / r) * r)
+
+#define GET_NT_HEADERS(module) ((IMAGE_NT_HEADERS *)((char *)module + ((IMAGE_DOS_HEADER *)module)->e_lfanew))
+
+typedef BOOL (WINAPI *DllMainFunc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved);
+
+static void free_imp_by_range(void *module,
+ IMAGE_IMPORT_DESCRIPTOR *begining,
+ IMAGE_IMPORT_DESCRIPTOR *end);
+void *get_proc_address(HMODULE module, const char *proc_name);
+
+
+DWORD rva_to_raw(DWORD rva, IMAGE_NT_HEADERS *nt_headers)
+{
+ WORD nsections;
+ IMAGE_SECTION_HEADER *sec_hdr = (IMAGE_SECTION_HEADER *)((char *)nt_headers + sizeof(IMAGE_NT_HEADERS));
+
+ for (nsections = 0; nsections < nt_headers->FileHeader.NumberOfSections; nsections++)
+ {
+ if (rva >= sec_hdr->VirtualAddress &&
+ rva < (sec_hdr->VirtualAddress + sec_hdr->Misc.VirtualSize))
+ return sec_hdr->PointerToRawData + (rva - sec_hdr->VirtualAddress);
+ sec_hdr++;
+ }
+ return 0;
+}
+
+static int is_pe(void *map)
+{
+ IMAGE_DOS_HEADER *dos_hdr;
+ IMAGE_NT_HEADERS *nt_hdrs;
+
+ dos_hdr = (IMAGE_DOS_HEADER *)map;
+ if (dos_hdr->e_magic != IMAGE_DOS_SIGNATURE)
+ return 0;
+ nt_hdrs = (IMAGE_NT_HEADERS *)((char *)map + dos_hdr->e_lfanew);
+ return nt_hdrs->Signature == IMAGE_NT_SIGNATURE;
+}
+
+static IMAGE_IMPORT_DESCRIPTOR *get_imp_desc(void *module)
+{
+ IMAGE_NT_HEADERS *nt_hdrs;
+ DWORD imp_desc_rva;
+ nt_hdrs = GET_NT_HEADERS(module);
+ if (!(imp_desc_rva = nt_hdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress))
+ return NULL;
+ return (IMAGE_IMPORT_DESCRIPTOR *)((char *)module + imp_desc_rva);
+}
+
+static int load_imports(void *module)
+{
+ IMAGE_IMPORT_DESCRIPTOR *first_imp_desc, *imp_desc;
+ first_imp_desc = imp_desc = get_imp_desc(module);
+ /* FIX ME: is checking Name and Stamp enough? */
+ for (; imp_desc->Name || imp_desc->TimeDateStamp; ++imp_desc)
+ {
+ IMAGE_THUNK_DATA *name_table, *address_table, *thunk;
+ char *dll_name;
+ HMODULE lib_module;
+
+ dll_name = (char *)module + imp_desc->Name;
+ /* the reference count side effect is desired */
+ if (!(lib_module = LoadLibraryA(dll_name)))
+ goto fail;
+
+ name_table = (IMAGE_THUNK_DATA *)((char *)module + imp_desc->OriginalFirstThunk);
+ address_table = (IMAGE_THUNK_DATA *)((char *)module + imp_desc->FirstThunk);
+
+ /* if there is no name table, use address table */
+ thunk = imp_desc->OriginalFirstThunk ? name_table : address_table;
+ while (thunk->u1.AddressOfData)
+ {
+ unsigned char *func_name;
+ /* is ordinal? */
+ if (thunk->u1.Ordinal & IMAGE_ORDINAL_FLAG)
+ func_name = (unsigned char *)MAKE_ORDINAL(thunk->u1.Ordinal);
+ else
+ func_name = ((IMAGE_IMPORT_BY_NAME *)((char *)module + thunk->u1.AddressOfData))->Name;
+
+ address_table->u1.Function = (DWORD)get_proc_address(lib_module, (char *)func_name);
+
+ thunk++;
+ address_table++;
+ }
+ }
+ return 1;
+
+fail:
+ /* free the modules we loaded till now */
+ free_imp_by_range(module, first_imp_desc, imp_desc);
+ return 0;
+}
+
+/* if end is NULL, then it will continue till there are no more modules to free */
+static void free_imp_by_range(void *module,
+ IMAGE_IMPORT_DESCRIPTOR *begining,
+ IMAGE_IMPORT_DESCRIPTOR *end)
+{
+ IMAGE_IMPORT_DESCRIPTOR *imp_desc;
+ imp_desc = begining;
+ for ( ;
+ (imp_desc->Name || imp_desc->TimeDateStamp) && (!end || imp_desc != end);
+ ++imp_desc)
+ {
+ char *dll_name;
+ HMODULE loaded_module;
+
+ dll_name = (char *)module + imp_desc->Name;
+ if ((loaded_module = GetModuleHandleA(dll_name)))
+ FreeLibrary(loaded_module);
+ }
+}
+
+static void free_imports(void *module)
+{
+ free_imp_by_range(module, get_imp_desc(module), NULL);
+}
+
+static void fix_relocations(IMAGE_BASE_RELOCATION *base_reloc, DWORD dir_size,
+ void *new_imgbase, void *old_imgbase)
+{
+ IMAGE_BASE_RELOCATION *cur_reloc = base_reloc, *reloc_end;
+ DWORD delta = (char *)new_imgbase - (char *)old_imgbase;
+
+ reloc_end = (IMAGE_BASE_RELOCATION *)((char *)base_reloc + dir_size);
+ /* FIX-ME: is checking virtualaddress for cur_reloc necessary? */
+ while (cur_reloc < reloc_end && cur_reloc->VirtualAddress)
+ {
+ int count = (cur_reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
+ WORD *cur_entry = (WORD *)(cur_reloc + 1);
+ void *page_va = (void *)((char *)new_imgbase + cur_reloc->VirtualAddress);
+
+ while (count--)
+ {
+ /* is valid x86 relocation? */
+ if (*cur_entry >> 12 == IMAGE_REL_BASED_HIGHLOW)
+ *(DWORD *)((char *)page_va + (*cur_entry & 0x0fff)) += delta;
+ cur_entry++;
+ }
+ /* advance to the next reloc entry */
+ cur_reloc = (IMAGE_BASE_RELOCATION *)((char *)cur_reloc + cur_reloc->SizeOfBlock);
+ }
+}
+
+static void copy_headers(void *dest_pe, void *src_pe)
+{
+ IMAGE_NT_HEADERS *nt_hdrs;
+ nt_hdrs = GET_NT_HEADERS(src_pe);
+ memcpy(dest_pe, src_pe, nt_hdrs->OptionalHeader.SizeOfHeaders);
+}
+
+static void copy_sections(void *dest_pe, void *src_pe)
+{
+ WORD i;
+ IMAGE_NT_HEADERS *nt_hdrs;
+ IMAGE_SECTION_HEADER *sec_hdr;
+
+ nt_hdrs = GET_NT_HEADERS(src_pe);
+ sec_hdr = IMAGE_FIRST_SECTION(nt_hdrs);
+ for (i = 0; i < nt_hdrs->FileHeader.NumberOfSections; ++i, ++sec_hdr)
+ {
+ void *sec_dest;
+ size_t padding_size;
+
+ sec_dest = (void *)((char *)dest_pe + sec_hdr->VirtualAddress);
+ /* copy the raw data from the mapped module */
+ memcpy(sec_dest,
+ (void *)((char *)src_pe + sec_hdr->PointerToRawData),
+ sec_hdr->SizeOfRawData);
+ /* set the remaining part of the section with zeros */
+ padding_size = ROUND(sec_hdr->Misc.VirtualSize, nt_hdrs->OptionalHeader.SectionAlignment) - sec_hdr->SizeOfRawData;
+ memset((void *)((char *)sec_dest + sec_hdr->SizeOfRawData), 0, padding_size);
+ }
+}
+
+/* executable, readable, writable */
+static DWORD secp2vmemp[2][2][2] =
+{
+ {
+ /* not executable */
+ {PAGE_NOACCESS, PAGE_WRITECOPY},
+ {PAGE_READONLY, PAGE_READWRITE}
+ },
+ {
+ /* executable */
+ {PAGE_EXECUTE, PAGE_EXECUTE_WRITECOPY},
+ {PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE}
+ }
+};
+
+static DWORD secp_to_vmemp(DWORD secp)
+{
+ DWORD vmemp;
+ int executable, readable, writable;
+
+ executable = (secp & IMAGE_SCN_MEM_EXECUTE) != 0;
+ readable = (secp & IMAGE_SCN_MEM_READ) != 0;
+ writable = (secp & IMAGE_SCN_MEM_WRITE) != 0;
+ vmemp = secp2vmemp[executable][readable][writable];
+ if (secp & IMAGE_SCN_MEM_NOT_CACHED)
+ vmemp |= PAGE_NOCACHE;
+ return vmemp;
+}
+
+static void protect_module_pages(void *module)
+{
+ IMAGE_NT_HEADERS *nt_hdrs;
+ IMAGE_SECTION_HEADER *sec_hdr;
+ DWORD old_prot, new_prot;
+ WORD i;
+
+ nt_hdrs = GET_NT_HEADERS(module);
+ /* protect the PE headers */
+ VirtualProtect(module, nt_hdrs->OptionalHeader.SizeOfHeaders, PAGE_READONLY, &old_prot);
+
+ /* protect the image sections */
+ sec_hdr = IMAGE_FIRST_SECTION(nt_hdrs);
+ for (i = 0; i < nt_hdrs->FileHeader.NumberOfSections; ++i, ++sec_hdr)
+ {
+ void *section;
+ section = (void *)((char *)module + sec_hdr->VirtualAddress);
+ /* free the section if it's marked as discardable */
+ if (sec_hdr->Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
+ {
+ VirtualFree(section, sec_hdr->Misc.VirtualSize, MEM_DECOMMIT);
+ continue;
+ }
+ new_prot = secp_to_vmemp(sec_hdr->Characteristics);
+ VirtualProtect(section,
+ sec_hdr->Misc.VirtualSize, /* pages affected in the range are changed */
+ new_prot,
+ &old_prot);
+ }
+}
+
+/* loads dlls from memory
+* returns the address of the loaded dll on successs, NULL on failure
+*/
+HMODULE mem_load_library(void *module_map)
+{
+ IMAGE_NT_HEADERS *nt_hdrs;
+ HMODULE module;
+ DWORD image_base, ep_rva;
+ IMAGE_DATA_DIRECTORY *reloc_dir_entry;
+ int relocate, apis_loaded;
+
+ relocate = apis_loaded = 0;
+ if (!is_pe(module_map))
+ return NULL;
+
+ nt_hdrs = (IMAGE_NT_HEADERS *)((char *)module_map + ((IMAGE_DOS_HEADER *)module_map)->e_lfanew);
+ reloc_dir_entry = &nt_hdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
+
+ /* reserve memory for the module at image base if possible */
+ image_base = nt_hdrs->OptionalHeader.ImageBase;
+ module = VirtualAlloc((void *)(image_base), nt_hdrs->OptionalHeader.SizeOfImage,
+ MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+ /* image base taken ? */
+ if (!module)
+ {
+ relocate = 1;
+ /* is module relocatable? */
+ if (!reloc_dir_entry->VirtualAddress)
+ return NULL;
+ /* try to allocate it at an arbitrary address */
+ module = VirtualAlloc(NULL, nt_hdrs->OptionalHeader.SizeOfImage,
+ MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+ if (!module)
+ return NULL;
+ }
+
+ copy_headers(module, module_map);
+ copy_sections(module, module_map);
+ if (!load_imports(module))
+ goto fail;
+ apis_loaded = 1;
+ /* relocate the module if it isn't loaded at it's prefered address */
+ if (relocate)
+ {
+ IMAGE_BASE_RELOCATION *base_reloc;
+ base_reloc = (IMAGE_BASE_RELOCATION *)((char *)module_map + rva_to_raw(reloc_dir_entry->VirtualAddress, nt_hdrs));
+ fix_relocations(base_reloc, reloc_dir_entry->Size, module, (void *)image_base);
+ }
+ /* change the protection flags of the module pages */
+ protect_module_pages(module);
+ /* call DLLMain if it has one */
+ if ((ep_rva = nt_hdrs->OptionalHeader.AddressOfEntryPoint))
+ {
+ DllMainFunc dll_main;
+ dll_main = (DllMainFunc)((char *)module + ep_rva);
+ if (!dll_main((HINSTANCE)module, DLL_PROCESS_ATTACH, NULL))
+ goto fail;
+ }
+
+ return module;
+
+fail:
+ if (apis_loaded)
+ free_imports(module);
+ VirtualFree(module, 0, MEM_RELEASE);
+ return NULL;
+}
+
+void mem_free_library(HMODULE *module)
+{
+ IMAGE_NT_HEADERS *nt_hdrs;
+
+ nt_hdrs = (IMAGE_NT_HEADERS *)((char *)module + ((IMAGE_DOS_HEADER *)module)->e_lfanew);
+ /* tell the module it's getting detached */
+ if (nt_hdrs->OptionalHeader.AddressOfEntryPoint)
+ {
+ DllMainFunc dll_main;
+
+ dll_main = (DllMainFunc)((char *)module + nt_hdrs->OptionalHeader.AddressOfEntryPoint);
+ dll_main((HINSTANCE)module, DLL_PROCESS_DETACH, NULL);
+ }
+ free_imports(module);
+ VirtualFree(module, 0, MEM_RELEASE);
+}
+
+void *get_proc_address(HMODULE module, const char *proc_name)
+{
+ IMAGE_NT_HEADERS *nt_hdrs;
+ IMAGE_DATA_DIRECTORY *exp_entry;
+ IMAGE_EXPORT_DIRECTORY *exp_dir;
+ void **func_table;
+ WORD *ord_table;
+ char **name_table;
+ void *address;
+
+
+ nt_hdrs = GET_NT_HEADERS(module);
+ exp_entry = (IMAGE_DATA_DIRECTORY *)(&nt_hdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]);
+ exp_dir = (IMAGE_EXPORT_DIRECTORY *)((char *)module + exp_entry->VirtualAddress);
+
+ func_table = (void **)((char *)module + exp_dir->AddressOfFunctions);
+ ord_table = (WORD *)((char *)module + exp_dir->AddressOfNameOrdinals);
+ name_table = (char **)((char *)module + exp_dir->AddressOfNames);
+
+ /* NULL is returned if nothing is found */
+ address = NULL;
+
+
+ /* is ordinal? */
+ if (((DWORD)proc_name >> 16) == 0)
+ {
+ WORD ordinal = LOWORD(proc_name);
+ DWORD ord_base = exp_dir->Base;
+ /* is valid ordinal? */
+ if (ordinal < ord_base || ordinal > ord_base + exp_dir->NumberOfFunctions)
+ return NULL;
+
+ /* taking ordinal base into consideration */
+ address = (void *)((char *)module + (DWORD)func_table[ordinal - ord_base]);
+ }
+ else
+ {
+ DWORD i;
+
+ /* import by name */
+ for (i = 0; i < exp_dir->NumberOfNames; i++)
+ {
+ /* name table pointers are rvas */
+ if (strcmp(proc_name, (char *)module + (DWORD)name_table[i]) == 0)
+ address = (void *)((char *)module + (DWORD)func_table[ord_table[i]]);
+ }
+ }
+
+ /* is forwarded? */
+ if ((char *)address >= (char *)exp_dir &&
+ (char *)address < (char *)exp_dir + exp_entry->Size)
+ {
+ char *dll_name, *func_name;
+ HMODULE frwd_module;
+
+ dll_name = strdup((char *)address);
+ if (!dll_name)
+ return NULL;
+ func_name = strchr(dll_name, '.');
+ *func_name++ = 0;
+
+ if ((frwd_module = GetModuleHandleA(dll_name)))
+ address = get_proc_address(frwd_module, func_name);
+ else
+ address = NULL;
+
+ free(dll_name);
+ }
+
+ return address;
+}