2 * reactos ldr/ (loader) emulation of libcaptive
3 * Copyright (C) 2002 Jan Kratochvil <project-captive@jankratochvil.net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; exactly version 2 of June 1991 is required
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "captive/ldr.h" /* self */
23 #include "captive/ldr_exports.h" /* self */
24 #include "reactos/internal/ldr.h" /* self */
25 #include "captive/unicode.h"
26 #include "captive/rtl-file.h"
27 #include <glib/gtypes.h>
28 #include <glib/gmessages.h>
29 #include <glib/gmem.h>
30 #include "reactos/napi/types.h"
31 #include "reactos/internal/kd.h" /* for KDB_LOADDRIVER_HOOK */
33 #include <sys/mman.h> /* for PROT_READ, MAP_SHARED */
34 #include "captive/macros.h"
36 #include "reactos/ntos/rtl.h" /* for InsertTailList() */
37 #include "reactos/internal/debug.h" /* for assert() */
38 #include <glib/gutils.h> /* for g_path_get_basename() */
40 #include "captive/options-module.h"
43 /* map: ExportAddress -> (struct captive_ModuleList_patchpoint *) */
44 static GHashTable *captive_ModuleList_patchpoint_hash;
46 /* initialize 'captive_ModuleList_patchpoint_hash' */
47 static void captive_ModuleList_patchpoint_hash_init(void)
49 if (captive_ModuleList_patchpoint_hash)
51 captive_ModuleList_patchpoint_hash=g_hash_table_new(g_direct_hash,g_direct_equal);
55 /* map: ExportAddress -> (CHAR *)funcname */
56 static GHashTable *captive_ModuleList_function_disable_hash;
58 /* initialize 'captive_ModuleList_function_disable_hash' */
59 static void captive_ModuleList_function_disable_hash_init(void)
61 if (captive_ModuleList_function_disable_hash)
63 captive_ModuleList_function_disable_hash=g_hash_table_new(g_direct_hash,g_direct_equal);
67 /* reactos/ntoskrnl/ldr/loader.c file-scope global declaration: */
68 NTSTATUS LdrProcessModule(PVOID ModuleLoadBase,PUNICODE_STRING ModuleName,PMODULE_OBJECT *ModuleObject);
69 PVOID LdrGetExportAddress(PMODULE_OBJECT ModuleObject,char *Name,unsigned short Hint);
72 /* 'ntoskrnl/ldr/loader.c' file-scoped declaration: */
73 VOID LdrpBuildModuleBaseName(PUNICODE_STRING BaseName,PUNICODE_STRING FullName);
76 static MODULE_OBJECT *captive_LdrLoadModule_gmodule(const gchar *Filename_utf8,const gchar *Filename_bslash_utf8)
80 MODULE_TEXT_SECTION *ModuleTextSection;
83 g_return_val_if_fail(Filename_utf8!=NULL,NULL);
84 g_return_val_if_fail(Filename_bslash_utf8!=NULL,NULL);
85 g_return_val_if_fail(TRUE==g_module_supported(),NULL);
87 gmodule=g_module_open(Filename_utf8,
88 0); /* Flags; !LAZY */
90 g_message(g_module_error());
91 g_assert(gmodule!=NULL);
95 errbool=g_module_symbol(gmodule,"DriverEntry",&r->EntryPoint);
96 g_assert(errbool==TRUE);
98 r->Base=(PVOID)gmodule;
99 r->Flags=MODULE_FLAG_COFF; /* some weird value - reactos uses MODULE_FLAG_PE */
101 RtlCreateUnicodeString(&r->FullName,captive_utf8_to_UnicodeString_alloca(Filename_bslash_utf8)->Buffer);
102 LdrpBuildModuleBaseName(&r->BaseName,&r->FullName);
107 InsertTailList(&ModuleListHead,&r->ListEntry);
109 captive_new0(ModuleTextSection);
110 /* ModuleTextSection->Base=0; */
111 /* ModuleTextSection->Length=0; */
112 ModuleTextSection->Name=g_memdup(r->BaseName.Buffer,
113 (captive_ucs2_strlen(r->BaseName.Buffer)+1)*sizeof(captive_ucs2));
114 /* ModuleTextSection->OptionalHeader=NULL; */
115 InsertTailList(&ModuleTextListHead,&ModuleTextSection->ListEntry);
116 r->TextSection=ModuleTextSection;
123 * captive_LdrLoadModule:
124 * @options_module: #captive_options_module structure describing the module to load.
125 * Loading of already loaded module is forbidden.
126 * @ModuleObjectp: Returns initialized module object.
128 * Load and initialize module to reactos using host OS functions.
130 * Returns: STATUS_SUCCESS if the module was loaded successfuly during the call.
132 NTSTATUS captive_LdrLoadModule(struct captive_options_module *options_module,PMODULE_OBJECT *ModuleObjectp)
134 PMODULE_OBJECT Module;
136 gchar *Filename_utf8=options_module->pathname_utf8;
137 gchar *Filename_bslash_utf8,*s;
138 UNICODE_STRING *Filename_bslash;
142 /* Filename=~s#/#\\#g -> Filename_bslash to satisfy basename-derivations by reactos. */
143 Filename_bslash_utf8=(/* de-const as we do not change the length */ gchar *)captive_strdup_alloca(Filename_utf8);
144 for (s=Filename_bslash_utf8;(s=strchr(s,'/'));s++)
146 Filename_bslash=captive_utf8_to_UnicodeString_alloca(Filename_bslash_utf8);
148 switch (options_module->type) {
149 case CAPTIVE_OPTIONS_MODULE_TYPE_EMPTY: g_assert_not_reached();
151 case CAPTIVE_OPTIONS_MODULE_TYPE_PE32:
152 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: Loading module format: %s",G_STRLOC,"MZ/PE-32");
153 /* examine/relocate the module */
154 err=LdrProcessModule(options_module->u.pe32.base,Filename_bslash,&Module);
155 if (!NT_SUCCESS(err)) {
156 g_error("LdrLoadModule(): LdrProcessModule()=0x%08lX",(gulong)err);
161 case CAPTIVE_OPTIONS_MODULE_TYPE_GMODULE:
162 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: Loading module format: %s",G_STRLOC,"native .so");
163 Module=captive_LdrLoadModule_gmodule(Filename_utf8,Filename_bslash_utf8);
164 g_assert(Module!=NULL);
167 /* we were successful */
168 *ModuleObjectp=Module;
170 /* Hook for KDB on loading a driver. */
171 KDB_LOADDRIVER_HOOK(Filename_bslash,Module);
173 return STATUS_SUCCESS;
176 g_return_val_if_reached(err);
180 NTSTATUS LdrLoadModule(PUNICODE_STRING Filename,PMODULE_OBJECT *ModuleObject)
182 return STATUS_OBJECT_NAME_NOT_FOUND;
187 * captive_LdrpLoadAndCallImage:
188 * @ModuleObjectp: Returns PMODULE_OBJECT successfuly loaded.
189 * @options_module: #captive_options_module structure describing the module to load.
190 * Loading of already loaded module is forbidden despite original
191 * LdrpLoadAndCallImage().
192 * @DriverEntry_DriverObject: argument #DriverObject of #PDRIVER_INITIALIZE call.
193 * @DriverEntry_RegistryPath: argument #RegistryPath of #PDRIVER_INITIALIZE call.
195 * Corresponds to reactos LdrpLoadAndCallImage() but it also provides arguments
196 * to pass to #PDRIVER_INITIALIZE call of module driver initialization.
198 * Returns: STATUS_SUCCESS if the driver module was loaded and initialized
199 * successfuly during this call. Ignore returned @ModuleObjectp if function failed.
201 NTSTATUS captive_LdrpLoadAndCallImage(PMODULE_OBJECT *ModuleObjectp,struct captive_options_module *options_module,
202 PDRIVER_OBJECT DriverEntry_DriverObject,PUNICODE_STRING DriverEntry_RegistryPath)
204 PDRIVER_INITIALIZE DriverEntry;
205 PMODULE_OBJECT ModuleObject_tmp;
209 /* check for duplicity */
210 g_return_val_if_fail(LdrGetModuleObject(ModuleName)==NULL,STATUS_IMAGE_ALREADY_LOADED);
213 /* provide our temporary storage if the caller doesn't want to know ModuleObject address */
215 ModuleObjectp=&ModuleObject_tmp;
217 /* load the module */
218 err=captive_LdrLoadModule(options_module,ModuleObjectp);
219 g_return_val_if_fail(NT_SUCCESS(err),err);
221 /* initialize the module */
222 DriverEntry=(PDRIVER_INITIALIZE)(*ModuleObjectp)->EntryPoint;
223 err=(NTSTATUS)captive_stdcall_call_8((CaptiveStdCallFunc8)DriverEntry,
224 DriverEntry_DriverObject,
225 DriverEntry_RegistryPath);
226 if (!NT_SUCCESS(err))
227 goto err_LdrUnloadModule;
229 /* assumed STATUS_SUCCESS */
234 LdrUnloadModule(*ModuleObjectp);
237 g_return_val_if_reached(err);
242 * captive_ModuleList_add_builtin:
243 * @FullName_utf8: String to fill in #PMODULE_OBJECT->FullName.
244 * @...: (const gchar *sym_name,void *sym_val) symbol list terminated by %NULL.
246 * Adds simulated built-in module to #ModuleListHead module list.
247 * It can be used for the functionality of reactos/ntoskrnl/ldr/loader.c/LdrInitModuleManagement().
248 * libcaptive does not support Ordinals - we just pretend liner (%0-based)
249 * Ordinal numbers of the functions in given @... stdargs order.
251 * Returns: %TRUE if the module was successfuly added.
253 gboolean captive_ModuleList_add_builtin(const gchar *FullName_utf8,...)
255 MODULE_OBJECT *ModuleObject;
258 const gchar *sym_name;
260 gchar *basename_utf8;
261 IMAGE_DOS_HEADER *DosHeader;
262 IMAGE_NT_HEADERS *NTHeaders;
263 IMAGE_EXPORT_DIRECTORY *ExportDir;
264 guint symi,symN; /* index,number of passed stdarg sym_name/sym_val pairs */
265 ptrdiff_t *NameList; /* filled by sym_name; MODULEOBJECT_BASE_OFFSET_MINUS()ed */
266 WORD *OrdinalList; /* linear list - libcaptive doesn't support Ordinals */
267 ptrdiff_t *FunctionList; /* filled by sym_val; MODULEOBJECT_BASE_OFFSET_MINUS()ed */
269 g_return_val_if_fail(FullName_utf8!=NULL,FALSE);
271 captive_new0(ModuleObject);
272 /* A lot of offsets in the structures are relative to ModuleObject->Base */
273 #define MODULEOBJECT_BASE_OFFSET_MINUS(addr) ((ptrdiff_t)((char *)addr-(char *)ModuleObject->Base))
275 ModuleObject->Flags = MODULE_FLAG_PE;
277 /* fill ModuleObject->FullName
278 * ModuleObject->FullName should be probably "\\SYSTEM32\\..." style but
279 * we put there '/'-based UNIX filenames in libcaptive.
281 errbool=RtlCreateUnicodeString(&ModuleObject->FullName,captive_utf8_to_UnicodeString_alloca(FullName_utf8)->Buffer);
283 g_error("captive_ModuleList_add_builtin: RtlCreateUnicodeString()==FALSE");
284 goto err_g_free_ModuleObject;
287 /* fill ModuleObject->BaseName
288 * reactos/ntoskrnl/ldr/loader.c/LdrpBuildModuleBaseName() does this one
289 * but it is 'static' for that file and also it is stricly backslash based.
290 * ModuleObject->FullName should be probably "\\SYSTEM32\\..." style but
291 * we put there '/'-based UNIX filenames in libcaptive.
293 basename_utf8=g_path_get_basename(FullName_utf8);
294 errbool=RtlCreateUnicodeString(&ModuleObject->BaseName,captive_utf8_to_UnicodeString_alloca(basename_utf8)->Buffer);
295 g_free(basename_utf8);
297 g_error("captive_ModuleList_add_builtin: RtlCreateUnicodeString()==FALSE");
298 goto err_g_free_ModuleObject;
301 /* We must satisfy reactos/ntoskrnl/ldr/rtl.c/RtlImageDirectoryEntryToData(,,IMAGE_DIRECTORY_ENTRY_EXPORT)
302 * prepare module headers
304 captive_new0(DosHeader);
305 ModuleObject->Base=DosHeader; /* link DosHeader to ModuleObject */
306 DosHeader->e_magic=IMAGE_DOS_MAGIC;
307 captive_new0(NTHeaders);
308 DosHeader->e_lfanew=MODULEOBJECT_BASE_OFFSET_MINUS(NTHeaders); /* link NTHeaders to DosHeader */
309 NTHeaders->Signature=IMAGE_PE_MAGIC;
310 NTHeaders->OptionalHeader.NumberOfRvaAndSizes=IMAGE_DIRECTORY_ENTRY_EXPORT+1;
311 NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size
312 =sizeof(*ExportDir); /* in bytes; just prevent LdrPEFixupForward() invocation */
313 captive_new0(ExportDir);
314 NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
315 =MODULEOBJECT_BASE_OFFSET_MINUS(ExportDir); /* link ExportDir to NTHeaders */
316 ExportDir->Base=0; /* base Ordinal number; Ordinals are not supported by libcaptive */
318 /* count the number of symbols */
319 va_start(ap,FullName_utf8);
320 for (symN=0;captive_va_arg(sym_name,ap);symN++)
321 captive_va_arg(sym_val,ap);
323 ExportDir->NumberOfNames=symN;
324 ExportDir->NumberOfFunctions=symN;
326 /* allocate and link the symbol tables */
327 captive_newn(NameList,symN);
328 ExportDir->AddressOfNames=(PDWORD *)MODULEOBJECT_BASE_OFFSET_MINUS(NameList); /* link NameList to ExportDir */
329 captive_newn(OrdinalList,symN);
330 ExportDir->AddressOfNameOrdinals=(PWORD *)MODULEOBJECT_BASE_OFFSET_MINUS(OrdinalList); /* link OrdinalList to ExportDir */
331 captive_newn(FunctionList,symN);
332 ExportDir->AddressOfFunctions=(PDWORD *)MODULEOBJECT_BASE_OFFSET_MINUS(FunctionList); /* link FunctionList to ExportDir */
334 /* fill in symbol tables */
335 va_start(ap,FullName_utf8);
336 for (symi=0;symi<symN;symi++) {
337 captive_va_arg(sym_name,ap);
338 captive_va_arg(sym_val ,ap);
339 NameList[symi]=MODULEOBJECT_BASE_OFFSET_MINUS(sym_name);
340 OrdinalList[symi]=symi; /* Ordinals are not supported by libcaptive */
341 FunctionList[symi]=MODULEOBJECT_BASE_OFFSET_MINUS(sym_val);
345 /* successful module info build */
346 InsertTailList(&ModuleListHead,&ModuleObject->ListEntry);
349 err_g_free_ModuleObject:
350 g_free(ModuleObject);
352 g_return_val_if_reached(FALSE);
355 static void instruction_fail(const guint8 *instr_base,gint offset_last,const gchar *location)
357 char instr_buf[4*3+1],*s;
359 g_return_if_fail(offset_last<=(gint)((sizeof(instr_buf)-1)/3));
362 while (offset_last-->=0)
363 s+=sprintf(s," %02X",*instr_base++);
364 g_error("instruction_length(): Unhandled at %s:%s",location,instr_buf);
368 static gsize instruction_length(const guint8 *instr)
370 #define INSTRUCTION_FAIL(offset_last) instruction_fail(instr,(offset_last),G_STRLOC)
372 if ((instr[0] & 0xF8)==0x50) /* push %regular-register */
374 if ((instr[0] & 0xF8)==0x58) /* pop %regular-register */
376 if ((instr[0] & 0xE7)==0x06) /* push %segment-register */
378 if ((instr[0] & 0xE7)==0x07 && instr[0]!=0x0F) /* pop %segment-register */
381 case 0x33: /* xor GB,Ev */
383 case 0x64: /* prefix %fs */
384 return instruction_length(instr+1);
385 case 0x68: /* push $quad-byte */
387 case 0x6A: /* push $single-byte */
391 case 0x3D: /* cmpb $byte,immediate-quad-indirect */
392 return 1+1+4+1; /* 80 3D immediate-quad-indirect byte */
393 case 0x7C: /* cmpb $byte,#immediate(%reg,1) */
394 return 1+1+1+1+1; /* 80 7C address-mode immediate byte */
395 default: INSTRUCTION_FAIL(1);
399 case 0x01: /* addl $byte,(%ecx) */
401 case 0x3D: /* cmpl $byte,immediate-quad-indirect */
402 return 1+1+4+1; /* 83 3D immediate-quad-indirect byte */
403 case 0x7C: /* cmpl $byte,#immediate(%reg,1) */
404 return 1+1+1+1+1; /* 80 7C address-mode immediate byte */
405 default: INSTRUCTION_FAIL(1);
407 case 0x8A: /* mov ??,?? */
408 case 0x8B: /* mov Gb,Eb */
410 case 0x0D: /* mov immediate-quad-indirect,%ecx */
412 case 0x15: /* mov immediate-quad-indirect,%edx */
414 case 0x44: /* mov #offset(%reg,%reg,#mult),%reg */
415 case 0x4C: /* mov #offset(%reg,#mult),%reg */
416 case 0x54: /* mov #offset(%reg,#mult),%reg */
417 return 1+1+1+1; /* 8B 44 address-mode offset */
418 case 0xC0: /* mov %eax,%eax */
420 case 0xFF: /* mov %edi,%edi */
422 default: INSTRUCTION_FAIL(1);
424 case 0x8D: /* lea Gb,M */
426 case 0x44: /* mov #offset(%reg,%reg,#mult),%reg */
427 return 4; /* 8B 44 address-mode offset */
428 default: INSTRUCTION_FAIL(1);
430 case 0x8F: /* lea Gb,M */
434 case 0x24: /* popl (%esp,1) */
436 default: INSTRUCTION_FAIL(2);
438 default: INSTRUCTION_FAIL(1);
440 case 0x9C: /* pushf */
442 case 0x9D: /* popf */
444 case 0xA1: /* mov immediate-quad-indirect,%eax */
446 case 0xB8: /* mov $immediate-quad,%eax */
448 case 0xC2: /* ret $immediate-double */
450 case 0xCC: /* int $0x3 */
452 case 0xF0: /* lock prefix */
453 return 1+instruction_length(instr+1);
458 case 0xFF: /* inc/dec Ev */
460 default: INSTRUCTION_FAIL(0);
462 g_assert_not_reached(); /* TODO:fill the table */
466 #undef INSTRUCTION_FAIL
470 /* A lot of offsets in the structures are relative to ModuleObject->Base */
471 #define MODULEOBJECT_BASE_OFFSET_PLUS(addr) ((gpointer)((char *)addr+(ptrdiff_t)ModuleObject->Base))
473 static void captive_ModuleList_patch_function_disable
474 (CHAR *funcname,PVOID *ExportAddressp,MODULE_OBJECT *ModuleObject /* user_data */)
478 g_return_if_fail(funcname!=NULL);
479 g_return_if_fail(ExportAddressp!=NULL);
480 g_return_if_fail(ModuleObject!=NULL);
482 ExportAddress=(PVOID)MODULEOBJECT_BASE_OFFSET_PLUS(*ExportAddressp);
483 g_return_if_fail(ExportAddress!=NULL);
485 /* Some alised name; safe to ignore as we checked for possible W32 binary 0xF4
486 * hits during our initialization in captive_ModuleList_patch().
488 if (0xF4 /* hlt */ ==*(guint8 *)ExportAddress)
491 captive_ModuleList_function_disable_hash_init();
493 *(guint8 *)ExportAddress=0xF4; /* hlt */
494 /* We may get aliased here; already existing entry is therefore allowed. */
495 g_hash_table_insert(captive_ModuleList_function_disable_hash,
496 ExportAddress, /* key */
497 funcname); /* value */
502 * captive_ModuleList_patch:
503 * @FullName_utf8: String to find #PMODULE_OBJECT by #FullName.
504 * @...: (const gchar *sym_name,void (*sym_val)(void),struct captive_ModuleList_patchpoint *patchpoint) symbol list terminated by %NULL.
506 * Patches existing @FullName_utf8 module to use for function named #sym_name
507 * pointer to the handler #sym_val. If #patchpoint is not %NULL it gets assigned the original
508 * pointer value (used for %pass keyword in #exports.captivesym).
510 * Put here 0xF4 'hlt' instead of 0xCC 'int $0x3; breakpoint'
511 * as 'hlt' will generate handled SIGSEGV instead of SIGTRAP which
512 * is used by gdb(1) during debugging.
513 * See also libcaptive/ps/signal.c/ sigaction_SIGSEGV().
515 * Returns: %TRUE if the module was successfuly added.
517 gboolean captive_ModuleList_patch(const gchar *FullName_utf8,...)
519 MODULE_OBJECT *ModuleObject;
521 IMAGE_EXPORT_DIRECTORY *ExportDir;
522 ptrdiff_t *NameList; /* filled by sym_name; MODULEOBJECT_BASE_OFFSET_PLUS()ed */
523 WORD *OrdinalList; /* linear list - libcaptive doesn't support Ordinals */
524 ptrdiff_t *FunctionList; /* filled by sym_val; MODULEOBJECT_BASE_OFFSET_PLUS()ed */
527 PVOID ExportAddress,*ExportAddressp;
528 const gchar *sym_name;
529 void (*sym_val)(void);
530 struct captive_ModuleList_patchpoint *patchpoint,*patchpointpatch;
531 GHashTable *exportdir_hash;
534 g_return_val_if_fail(FullName_utf8!=NULL,FALSE);
536 captive_ModuleList_patchpoint_hash_init();
538 ModuleObject=LdrGetModuleObject(captive_utf8_to_UnicodeString_alloca(g_path_get_basename(FullName_utf8)));
539 g_return_val_if_fail(ModuleObject!=NULL,FALSE);
541 ExportDir=(PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData(ModuleObject->Base,
542 TRUE,IMAGE_DIRECTORY_ENTRY_EXPORT,&ExportDirSize);
543 g_return_val_if_fail(ExportDir!=NULL,FALSE);
545 NameList =MODULEOBJECT_BASE_OFFSET_PLUS(ExportDir->AddressOfNames);
546 OrdinalList =MODULEOBJECT_BASE_OFFSET_PLUS(ExportDir->AddressOfNameOrdinals);
547 FunctionList=MODULEOBJECT_BASE_OFFSET_PLUS(ExportDir->AddressOfFunctions);
549 /* map (CHAR *)funcname->(PVOID *)ExportAddressp */
550 exportdir_hash=g_hash_table_new(g_str_hash,g_str_equal);
552 /* Initialize 'exportdir_hash' by all W32 exported functions. */
553 for (Idx=0;Idx<ExportDir->NumberOfNames;Idx++) {
554 CHAR *funcname=MODULEOBJECT_BASE_OFFSET_PLUS(NameList[Idx]);
556 ExportAddressp=(PVOID *)(FunctionList+OrdinalList[Idx]);
557 ExportAddress=(PVOID)MODULEOBJECT_BASE_OFFSET_PLUS(*ExportAddressp);
558 if (0xF4 /* hlt */ ==*(guint8 *)ExportAddress) {
559 /* FIXME: 'data' type symbols should be permitted to have 0xF4 byte */
560 g_error("%s: Function already patched although we did not touch it yet: %s",G_STRLOC,funcname);
561 g_assert_not_reached();
563 g_assert(NULL==g_hash_table_lookup(exportdir_hash,funcname));
564 g_hash_table_insert(exportdir_hash,
566 ExportAddressp); /* value */
569 /* Patch wished functions and remove them from 'exportdir_hash'. */
570 va_start(ap,FullName_utf8);
571 while (captive_va_arg(sym_name,ap)) {
572 captive_va_arg(sym_val ,ap);
573 /* 'sym_val' may be NULL if 'data' type && "pass"ed */
574 captive_va_arg(patchpoint,ap); /* 'data' type if ==NULL */
575 captive_va_arg(patchpointpatch,ap); /* 'data' type or 'pass' in non-debug mode if ==NULL */
576 ExportAddressp=g_hash_table_lookup(exportdir_hash,sym_name);
577 if (ExportAddressp==NULL) {
578 g_message("%s: Function not found for patchpoint (ignoring): %s",G_STRLOC,sym_name);
581 errbool=g_hash_table_remove(exportdir_hash,sym_name);
582 g_assert(errbool==TRUE);
583 if (!sym_val) { /* 'data' type && "pass"ed => do not corrupt it by 0xF4 */
584 g_assert(!patchpoint);
587 ExportAddress=(PVOID)MODULEOBJECT_BASE_OFFSET_PLUS(*ExportAddressp);
588 *ExportAddressp=(PVOID)MODULEOBJECT_BASE_OFFSET_MINUS(sym_val);
589 if (((ULONG)ExportAddress >= (ULONG)ExportDir) &&
590 ((ULONG)ExportAddress < (ULONG)ExportDir + ExportDirSize))
591 g_assert_not_reached(); /* LdrPEFixupForward() needed */
592 if (!patchpoint) /* 'data' type && !"pass"ed => do not corrupt it by 0xF4 */
594 patchpoint->orig_w32_func=ExportAddress;
595 if (!patchpointpatch) /* 'pass' in non-debug mode */
597 if (0xF4 /* hlt */ ==*patchpointpatch->orig_w32_func) /* Already patched by name-aliased function? */
599 g_assert(0xF4 /* hlt */ !=*patchpointpatch->orig_w32_func);
600 patchpointpatch->orig_w32_2ndinstr=patchpointpatch->orig_w32_func
601 +instruction_length((guint8 *)patchpointpatch->orig_w32_func);
602 g_assert(0xF4 /* hlt */ !=*patchpointpatch->orig_w32_2ndinstr);
603 patchpointpatch->wrap_wrap_func=sym_val;
604 patchpointpatch->orig_w32_func_byte=*patchpointpatch->orig_w32_func;
605 patchpointpatch->orig_w32_2ndinstr_byte=*patchpointpatch->orig_w32_2ndinstr;
606 patchpointpatch->through_w32_func=FALSE;
607 g_assert(NULL==g_hash_table_lookup(captive_ModuleList_patchpoint_hash,patchpointpatch->orig_w32_func));
608 g_hash_table_insert(captive_ModuleList_patchpoint_hash,
609 patchpointpatch->orig_w32_func, /* key */
610 patchpointpatch); /* value */
611 g_assert(NULL==g_hash_table_lookup(captive_ModuleList_patchpoint_hash,patchpointpatch->orig_w32_2ndinstr));
612 g_hash_table_insert(captive_ModuleList_patchpoint_hash,
613 patchpointpatch->orig_w32_2ndinstr, /* key */
614 patchpointpatch); /* value */
615 *(guint8 *)ExportAddress=0xF4; /* hlt */
619 /* The remaining entries of 'exportdir_hash' are W32 native functions
620 * unspecified by .captivesym file; we patch them as not-implemented ones.
622 g_hash_table_foreach(exportdir_hash,
623 (GHFunc)captive_ModuleList_patch_function_disable, /* func */
624 ModuleObject); /* used_data; unused */
626 g_hash_table_destroy(exportdir_hash);
628 #undef MODULEOBJECT_BASE_OFFSET_PLUS /* no longer valid */
629 #undef MODULEOBJECT_BASE_OFFSET_MINUS /* no longer valid */
634 struct captive_ModuleList_patchpoint *captive_ModuleList_patchpoint_find(gconstpointer ExportAddress)
636 struct captive_ModuleList_patchpoint *r;
638 g_return_val_if_fail(ExportAddress!=NULL,NULL);
640 captive_ModuleList_patchpoint_hash_init();
642 r=g_hash_table_lookup(captive_ModuleList_patchpoint_hash,ExportAddress);
643 g_return_val_if_fail(r!=NULL,NULL);
644 g_assert(r->orig_w32_func==ExportAddress || r->orig_w32_2ndinstr==ExportAddress);
650 G_CONST_RETURN gchar *captive_ModuleList_function_disable_find(gconstpointer ExportAddress)
652 g_return_val_if_fail(ExportAddress!=NULL,NULL);
654 return g_hash_table_lookup(captive_ModuleList_function_disable_hash,ExportAddress); /* funcname */
658 void *captive_Module_GetExportAddress(const gchar *ModuleName_utf8,const gchar *FunctionName)
660 MODULE_OBJECT *ModuleObject;
663 g_return_val_if_fail(ModuleName_utf8!=NULL,NULL);
664 g_return_val_if_fail(FunctionName!=NULL,NULL);
666 ModuleObject=LdrGetModuleObject(captive_utf8_to_UnicodeString_alloca(g_path_get_basename(ModuleName_utf8)));
667 g_return_val_if_fail(ModuleObject!=NULL,NULL);
669 r=LdrGetExportAddress(
670 ModuleObject, /* ModuleObject */
671 (/* de-const */char *)FunctionName, /* Name */
673 g_return_val_if_fail(r!=NULL,NULL);