#include "config.h"
#include "captive/ldr.h" /* self */
+#include "captive/ldr_exports.h" /* self */
#include "reactos/internal/ldr.h" /* self */
#include "captive/unicode.h"
-#include "captive/file.h"
+#include "captive/rtl-file.h"
#include <glib/gtypes.h>
#include <glib/gmessages.h>
#include <glib/gmem.h>
#include <sys/mman.h> /* for PROT_READ, MAP_SHARED */
#include "captive/macros.h"
#include <stdarg.h>
-#include "reactos/ddk/rtl.h" /* for InsertTailList() */
+#include "reactos/ntos/rtl.h" /* for InsertTailList() */
#include "reactos/internal/debug.h" /* for assert() */
#include <glib/gutils.h> /* for g_path_get_basename() */
+#include <gmodule.h>
+#include "captive/options-module.h"
+
+
+/* map: ExportAddress -> (struct captive_ModuleList_patchpoint *) */
+static GHashTable *captive_ModuleList_patchpoint_hash;
+
+/* initialize 'captive_ModuleList_patchpoint_hash' */
+static void captive_ModuleList_patchpoint_hash_init(void)
+{
+ if (captive_ModuleList_patchpoint_hash)
+ return;
+ captive_ModuleList_patchpoint_hash=g_hash_table_new(g_direct_hash,g_direct_equal);
+}
+
+
+/* map: ExportAddress -> (CHAR *)funcname */
+static GHashTable *captive_ModuleList_function_disable_hash;
+
+/* initialize 'captive_ModuleList_function_disable_hash' */
+static void captive_ModuleList_function_disable_hash_init(void)
+{
+ if (captive_ModuleList_function_disable_hash)
+ return;
+ captive_ModuleList_function_disable_hash=g_hash_table_new(g_direct_hash,g_direct_equal);
+}
/* reactos/ntoskrnl/ldr/loader.c file-scope global declaration: */
NTSTATUS LdrProcessModule(PVOID ModuleLoadBase,PUNICODE_STRING ModuleName,PMODULE_OBJECT *ModuleObject);
+PVOID LdrGetExportAddress(PMODULE_OBJECT ModuleObject,char *Name,unsigned short Hint);
+
+
+/* 'ntoskrnl/ldr/loader.c' file-scoped declaration: */
+VOID LdrpBuildModuleBaseName(PUNICODE_STRING BaseName,PUNICODE_STRING FullName);
+
+
+static MODULE_OBJECT *captive_LdrLoadModule_gmodule(const gchar *Filename_utf8,const gchar *Filename_bslash_utf8)
+{
+MODULE_OBJECT *r;
+GModule *gmodule;
+MODULE_TEXT_SECTION *ModuleTextSection;
+gboolean errbool;
+
+ g_return_val_if_fail(Filename_utf8!=NULL,NULL);
+ g_return_val_if_fail(Filename_bslash_utf8!=NULL,NULL);
+ g_return_val_if_fail(TRUE==g_module_supported(),NULL);
+
+ gmodule=g_module_open(Filename_utf8,
+ 0); /* Flags; !LAZY */
+ if (!gmodule)
+ g_message(g_module_error());
+ g_assert(gmodule!=NULL);
+
+ captive_new0(r);
+
+ errbool=g_module_symbol(gmodule,"DriverEntry",&r->EntryPoint);
+ g_assert(errbool==TRUE);
+
+ r->Base=(PVOID)gmodule;
+ r->Flags=MODULE_FLAG_COFF; /* some weird value - reactos uses MODULE_FLAG_PE */
+
+ RtlCreateUnicodeString(&r->FullName,captive_utf8_to_UnicodeString_alloca(Filename_bslash_utf8)->Buffer);
+ LdrpBuildModuleBaseName(&r->BaseName,&r->FullName);
+
+ /* r->Length=0; */
+
+ /* Insert module */
+ InsertTailList(&ModuleListHead,&r->ListEntry);
+
+ captive_new0(ModuleTextSection);
+ /* ModuleTextSection->Base=0; */
+ /* ModuleTextSection->Length=0; */
+ ModuleTextSection->Name=g_memdup(r->BaseName.Buffer,
+ (captive_ucs2_strlen(r->BaseName.Buffer)+1)*sizeof(captive_ucs2));
+ /* ModuleTextSection->OptionalHeader=NULL; */
+ InsertTailList(&ModuleTextListHead,&ModuleTextSection->ListEntry);
+ r->TextSection=ModuleTextSection;
+
+ return r;
+}
/**
- * LdrLoadModule:
- * @Filename: Filename of module to load based on host OS disk.
+ * captive_LdrLoadModule:
+ * @options_module: #captive_options_module structure describing the module to load.
* Loading of already loaded module is forbidden.
- * @ModuleObject: Returns initialized module object.
+ * @ModuleObjectp: Returns initialized module object.
*
* Load and initialize module to reactos using host OS functions.
*
* Returns: STATUS_SUCCESS if the module was loaded successfuly during the call.
*/
-NTSTATUS LdrLoadModule(PUNICODE_STRING Filename,PMODULE_OBJECT *ModuleObjectp)
+NTSTATUS captive_LdrLoadModule(struct captive_options_module *options_module,PMODULE_OBJECT *ModuleObjectp)
{
-PVOID ModuleLoadBase;
PMODULE_OBJECT Module;
NTSTATUS err;
+gchar *Filename_utf8=options_module->pathname_utf8;
+gchar *Filename_bslash_utf8,*s;
+UNICODE_STRING *Filename_bslash;
*ModuleObjectp=NULL;
- /* Open the Module */
- ModuleLoadBase=captive_file_mmap(
- NULL, /* lenp */
- captive_UnicodeString_to_utf8_alloca(Filename), /* path */
- O_RDONLY, /* open_flags */
- PROT_READ, /* mmap_prot */
- MAP_SHARED); /* mmap_flags */
- /* FIXME: convert errno instead of STATUS_INSUFFICIENT_RESOURCES */
- g_return_val_if_fail(ModuleLoadBase!=NULL,STATUS_INSUFFICIENT_RESOURCES);
-
- /* examine/relocate the module */
- err=LdrProcessModule(ModuleLoadBase,Filename,&Module);
- if (!NT_SUCCESS(err)) {
- g_error("LdrLoadModule(): LdrProcessModule()=0x%08lX",err);
- goto err_captive_file_munmap;
+ /* Filename=~s#/#\\#g -> Filename_bslash to satisfy basename-derivations by reactos. */
+ Filename_bslash_utf8=(/* de-const as we do not change the length */ gchar *)captive_strdup_alloca(Filename_utf8);
+ for (s=Filename_bslash_utf8;(s=strchr(s,'/'));s++)
+ *s='\\';
+ Filename_bslash=captive_utf8_to_UnicodeString_alloca(Filename_bslash_utf8);
+
+ switch (options_module->type) {
+ case CAPTIVE_OPTIONS_MODULE_TYPE_EMPTY: g_assert_not_reached();
+
+ case CAPTIVE_OPTIONS_MODULE_TYPE_PE32:
+ g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: Loading module format: %s",G_STRLOC,"MZ/PE-32");
+ /* examine/relocate the module */
+ err=LdrProcessModule(options_module->u.pe32.base,Filename_bslash,&Module);
+ if (!NT_SUCCESS(err)) {
+ g_error("LdrLoadModule(): LdrProcessModule()=0x%08lX",(gulong)err);
+ goto err;
+ }
+ break;
+
+ case CAPTIVE_OPTIONS_MODULE_TYPE_GMODULE:
+ g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: Loading module format: %s",G_STRLOC,"native .so");
+ Module=captive_LdrLoadModule_gmodule(Filename_utf8,Filename_bslash_utf8);
+ g_assert(Module!=NULL);
}
/* we were successful */
- captive_file_munmap(ModuleLoadBase);
*ModuleObjectp=Module;
/* Hook for KDB on loading a driver. */
- KDB_LOADDRIVER_HOOK(Filename,Module);
+ KDB_LOADDRIVER_HOOK(Filename_bslash,Module);
return STATUS_SUCCESS;
- /* Error recoveries */
-err_captive_file_munmap:
- captive_file_munmap(ModuleLoadBase);
-
+err:
g_return_val_if_reached(err);
}
+NTSTATUS LdrLoadModule(PUNICODE_STRING Filename,PMODULE_OBJECT *ModuleObject)
+{
+ return STATUS_OBJECT_NAME_NOT_FOUND;
+}
+
+
/**
* captive_LdrpLoadAndCallImage:
* @ModuleObjectp: Returns PMODULE_OBJECT successfuly loaded.
- * @ModuleName: Filename of module to load based on host OS disk.
+ * @options_module: #captive_options_module structure describing the module to load.
* Loading of already loaded module is forbidden despite original
* LdrpLoadAndCallImage().
* @DriverEntry_DriverObject: argument #DriverObject of #PDRIVER_INITIALIZE call.
* Returns: STATUS_SUCCESS if the driver module was loaded and initialized
* successfuly during this call. Ignore returned @ModuleObjectp if function failed.
*/
-NTSTATUS captive_LdrpLoadAndCallImage(PMODULE_OBJECT *ModuleObjectp,PUNICODE_STRING ModuleName,
+NTSTATUS captive_LdrpLoadAndCallImage(PMODULE_OBJECT *ModuleObjectp,struct captive_options_module *options_module,
PDRIVER_OBJECT DriverEntry_DriverObject,PUNICODE_STRING DriverEntry_RegistryPath)
{
PDRIVER_INITIALIZE DriverEntry;
PMODULE_OBJECT ModuleObject_tmp;
NTSTATUS err;
+#if 0 /* TODO */
/* check for duplicity */
g_return_val_if_fail(LdrGetModuleObject(ModuleName)==NULL,STATUS_IMAGE_ALREADY_LOADED);
+#endif
/* provide our temporary storage if the caller doesn't want to know ModuleObject address */
if (!ModuleObjectp)
ModuleObjectp=&ModuleObject_tmp;
/* load the module */
- err=LdrLoadModule(ModuleName,ModuleObjectp);
+ err=captive_LdrLoadModule(options_module,ModuleObjectp);
g_return_val_if_fail(NT_SUCCESS(err),err);
/* initialize the module */
DriverEntry=(PDRIVER_INITIALIZE)(*ModuleObjectp)->EntryPoint;
- err=(*DriverEntry)(DriverEntry_DriverObject,DriverEntry_RegistryPath);
+ err=(NTSTATUS)captive_stdcall_call_8((CaptiveStdCallFunc8)DriverEntry,
+ DriverEntry_DriverObject,
+ DriverEntry_RegistryPath);
if (!NT_SUCCESS(err))
goto err_LdrUnloadModule;
IMAGE_NT_HEADERS *NTHeaders;
IMAGE_EXPORT_DIRECTORY *ExportDir;
guint symi,symN; /* index,number of passed stdarg sym_name/sym_val pairs */
-ptrdiff_t *NameList; /* filled by sym_name; MODULEOBJECT_BASE_OFFSET()ed */
+ptrdiff_t *NameList; /* filled by sym_name; MODULEOBJECT_BASE_OFFSET_MINUS()ed */
WORD *OrdinalList; /* linear list - libcaptive doesn't support Ordinals */
-ptrdiff_t *FunctionList; /* filled by sym_val; MODULEOBJECT_BASE_OFFSET()ed */
+ptrdiff_t *FunctionList; /* filled by sym_val; MODULEOBJECT_BASE_OFFSET_MINUS()ed */
g_return_val_if_fail(FullName_utf8!=NULL,FALSE);
captive_new0(ModuleObject);
/* A lot of offsets in the structures are relative to ModuleObject->Base */
-#define MODULEOBJECT_BASE_OFFSET(addr) ((ptrdiff_t)((char *)addr-(char *)ModuleObject->Base))
+#define MODULEOBJECT_BASE_OFFSET_MINUS(addr) ((ptrdiff_t)((char *)addr-(char *)ModuleObject->Base))
ModuleObject->Flags = MODULE_FLAG_PE;
ModuleObject->Base=DosHeader; /* link DosHeader to ModuleObject */
DosHeader->e_magic=IMAGE_DOS_MAGIC;
captive_new0(NTHeaders);
- DosHeader->e_lfanew=MODULEOBJECT_BASE_OFFSET(NTHeaders); /* link NTHeaders to DosHeader */
+ DosHeader->e_lfanew=MODULEOBJECT_BASE_OFFSET_MINUS(NTHeaders); /* link NTHeaders to DosHeader */
NTHeaders->Signature=IMAGE_PE_MAGIC;
NTHeaders->OptionalHeader.NumberOfRvaAndSizes=IMAGE_DIRECTORY_ENTRY_EXPORT+1;
NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size
=sizeof(*ExportDir); /* in bytes; just prevent LdrPEFixupForward() invocation */
captive_new0(ExportDir);
NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
- =MODULEOBJECT_BASE_OFFSET(ExportDir); /* link ExportDir to NTHeaders */
+ =MODULEOBJECT_BASE_OFFSET_MINUS(ExportDir); /* link ExportDir to NTHeaders */
ExportDir->Base=0; /* base Ordinal number; Ordinals are not supported by libcaptive */
/* count the number of symbols */
/* allocate and link the symbol tables */
captive_newn(NameList,symN);
- ExportDir->AddressOfNames=(PDWORD *)MODULEOBJECT_BASE_OFFSET(NameList); /* link NameList to ExportDir */
+ ExportDir->AddressOfNames=(PDWORD *)MODULEOBJECT_BASE_OFFSET_MINUS(NameList); /* link NameList to ExportDir */
captive_newn(OrdinalList,symN);
- ExportDir->AddressOfNameOrdinals=(PWORD *)MODULEOBJECT_BASE_OFFSET(OrdinalList); /* link OrdinalList to ExportDir */
+ ExportDir->AddressOfNameOrdinals=(PWORD *)MODULEOBJECT_BASE_OFFSET_MINUS(OrdinalList); /* link OrdinalList to ExportDir */
captive_newn(FunctionList,symN);
- ExportDir->AddressOfFunctions=(PDWORD *)MODULEOBJECT_BASE_OFFSET(FunctionList); /* link FunctionList to ExportDir */
+ ExportDir->AddressOfFunctions=(PDWORD *)MODULEOBJECT_BASE_OFFSET_MINUS(FunctionList); /* link FunctionList to ExportDir */
/* fill in symbol tables */
va_start(ap,FullName_utf8);
for (symi=0;symi<symN;symi++) {
captive_va_arg(sym_name,ap);
captive_va_arg(sym_val ,ap);
- NameList[symi]=MODULEOBJECT_BASE_OFFSET(sym_name);
+ NameList[symi]=MODULEOBJECT_BASE_OFFSET_MINUS(sym_name);
OrdinalList[symi]=symi; /* Ordinals are not supported by libcaptive */
- FunctionList[symi]=MODULEOBJECT_BASE_OFFSET(sym_val);
+ FunctionList[symi]=MODULEOBJECT_BASE_OFFSET_MINUS(sym_val);
}
va_end(ap);
/* successful module info build */
InsertTailList(&ModuleListHead,&ModuleObject->ListEntry);
-#undef MODULEOBJECT_BASE_OFFSET /* no longer valid */
return TRUE;
err_g_free_ModuleObject:
/* err */
g_return_val_if_reached(FALSE);
}
+
+
+static gsize instruction_length(const guint8 *instr)
+{
+ if ((instr[0] & 0xF8)==0x50) /* push %regular-register */
+ return 1;
+ if ((instr[0] & 0xF8)==0x58) /* pop %regular-register */
+ return 1;
+ if ((instr[0] & 0xE7)==0x06) /* push %segment-register */
+ return 1;
+ if ((instr[0] & 0xE7)==0x07 && instr[0]!=0x0F) /* pop %segment-register */
+ return 1;
+ switch (instr[0]) {
+ case 0x33: /* xor GB,Ev */
+ return 1+1;
+ case 0x64: /* prefix %fs */
+ return instruction_length(instr+1);
+ case 0x68: /* push $quad-byte */
+ return 1+4;
+ case 0x6A: /* push $single-byte */
+ return 1+1;
+ case 0x80:
+ switch (instr[1]) {
+ case 0x3D: /* cmpb $byte,immediate-quad-indirect */
+ return 1+1+4+1; /* 80 3D immediate-quad-indirect byte */
+ case 0x7C: /* cmpb $byte,#immediate(%reg,1) */
+ return 1+1+1+1+1; /* 80 7C address-mode immediate byte */
+ default: g_assert_not_reached();
+ }
+ case 0x83:
+ switch (instr[1]) {
+ case 0x01: /* addl $byte,(%ecx) */
+ return 1+1+1;
+ case 0x3D: /* cmpl $byte,immediate-quad-indirect */
+ return 1+1+4+1; /* 83 3D immediate-quad-indirect byte */
+ case 0x7C: /* cmpl $byte,#immediate(%reg,1) */
+ return 1+1+1+1+1; /* 80 7C address-mode immediate byte */
+ default: g_assert_not_reached();
+ }
+ case 0x8A: /* mov ??,?? */
+ case 0x8B: /* mov Gb,Eb */
+ switch (instr[1]) {
+ case 0x0D: /* mov immediate-quad-indirect,%ecx */
+ return 1+1+4;
+ case 0x15: /* mov immediate-quad-indirect,%edx */
+ return 1+1+4;
+ case 0x44: /* mov #offset(%reg,%reg,#mult),%reg */
+ case 0x4C: /* mov #offset(%reg,#mult),%reg */
+ case 0x54: /* mov #offset(%reg,#mult),%reg */
+ return 1+1+1+1; /* 8B 44 address-mode offset */
+ default: g_assert_not_reached();
+ }
+ case 0x8D: /* lea Gb,M */
+ switch (instr[1]) {
+ case 0x44: /* mov #offset(%reg,%reg,#mult),%reg */
+ return 4; /* 8B 44 address-mode offset */
+ default: g_assert_not_reached();
+ }
+ case 0x8F: /* lea Gb,M */
+ switch (instr[1]) {
+ case 0x04:
+ switch (instr[2]) {
+ case 0x24: /* popl (%esp,1) */
+ return 3;
+ default: g_assert_not_reached();
+ }
+ default: g_assert_not_reached();
+ }
+ case 0x9C: /* pushf */
+ return 1;
+ case 0x9D: /* popf */
+ return 1;
+ case 0xA1: /* mov immediate-quad-indirect,%eax */
+ return 1+4;
+ case 0xB8: /* mov $immediate-quad,%eax */
+ return 1+4;
+ case 0xC2: /* ret $immediate-double */
+ return 1+2;
+ case 0xCC: /* int $0x3 */
+ return 1;
+ case 0xF0: /* lock prefix */
+ return 1+instruction_length(instr+1);
+ case 0xFA: /* cli */
+ return 1;
+ case 0xFB: /* sti */
+ return 1;
+ case 0xFF: /* inc/dec Ev */
+ return 2;
+ default: g_assert_not_reached();
+ }
+ g_assert_not_reached(); /* TODO:fill the table */
+ /* NOTREACHED */
+ return 0;
+}
+
+
+ /* A lot of offsets in the structures are relative to ModuleObject->Base */
+#define MODULEOBJECT_BASE_OFFSET_PLUS(addr) ((gpointer)((char *)addr+(ptrdiff_t)ModuleObject->Base))
+
+static void captive_ModuleList_patch_function_disable
+ (CHAR *funcname,PVOID *ExportAddressp,MODULE_OBJECT *ModuleObject /* user_data */)
+{
+PVOID ExportAddress;
+
+ g_return_if_fail(funcname!=NULL);
+ g_return_if_fail(ExportAddressp!=NULL);
+ g_return_if_fail(ModuleObject!=NULL);
+
+ ExportAddress=(PVOID)MODULEOBJECT_BASE_OFFSET_PLUS(*ExportAddressp);
+ g_return_if_fail(ExportAddress!=NULL);
+
+ /* Some alised name; safe to ignore as we checked for possible W32 binary 0xF4
+ * hits during our initialization in captive_ModuleList_patch().
+ */
+ if (0xF4 /* hlt */ ==*(guint8 *)ExportAddress)
+ return;
+
+ captive_ModuleList_function_disable_hash_init();
+
+ *(guint8 *)ExportAddress=0xF4; /* hlt */
+ /* We may get aliased here; already existing entry is therefore allowed. */
+ g_hash_table_insert(captive_ModuleList_function_disable_hash,
+ ExportAddress, /* key */
+ funcname); /* value */
+}
+
+
+/**
+ * captive_ModuleList_patch:
+ * @FullName_utf8: String to find #PMODULE_OBJECT by #FullName.
+ * @...: (const gchar *sym_name,void (*sym_val)(void),struct captive_ModuleList_patchpoint *patchpoint) symbol list terminated by %NULL.
+ *
+ * Patches existing @FullName_utf8 module to use for function named #sym_name
+ * pointer to the handler #sym_val. If #patchpoint is not %NULL it gets assigned the original
+ * pointer value (used for %pass keyword in #exports.captivesym).
+ *
+ * Put here 0xF4 'hlt' instead of 0xCC 'int $0x3; breakpoint'
+ * as 'hlt' will generate handled SIGSEGV instead of SIGTRAP which
+ * is used by gdb(1) during debugging.
+ * See also libcaptive/ps/signal.c/ sigaction_SIGSEGV().
+ *
+ * Returns: %TRUE if the module was successfuly added.
+ */
+gboolean captive_ModuleList_patch(const gchar *FullName_utf8,...)
+{
+MODULE_OBJECT *ModuleObject;
+va_list ap;
+IMAGE_EXPORT_DIRECTORY *ExportDir;
+ptrdiff_t *NameList; /* filled by sym_name; MODULEOBJECT_BASE_OFFSET_PLUS()ed */
+WORD *OrdinalList; /* linear list - libcaptive doesn't support Ordinals */
+ptrdiff_t *FunctionList; /* filled by sym_val; MODULEOBJECT_BASE_OFFSET_PLUS()ed */
+ULONG ExportDirSize;
+USHORT Idx;
+PVOID ExportAddress,*ExportAddressp;
+const gchar *sym_name;
+void (*sym_val)(void);
+struct captive_ModuleList_patchpoint *patchpoint,*patchpointpatch;
+GHashTable *exportdir_hash;
+gboolean errbool;
+
+ g_return_val_if_fail(FullName_utf8!=NULL,FALSE);
+
+ captive_ModuleList_patchpoint_hash_init();
+
+ ModuleObject=LdrGetModuleObject(captive_utf8_to_UnicodeString_alloca(g_path_get_basename(FullName_utf8)));
+ g_return_val_if_fail(ModuleObject!=NULL,FALSE);
+
+ ExportDir=(PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData(ModuleObject->Base,
+ TRUE,IMAGE_DIRECTORY_ENTRY_EXPORT,&ExportDirSize);
+ g_return_val_if_fail(ExportDir!=NULL,FALSE);
+
+ NameList =MODULEOBJECT_BASE_OFFSET_PLUS(ExportDir->AddressOfNames);
+ OrdinalList =MODULEOBJECT_BASE_OFFSET_PLUS(ExportDir->AddressOfNameOrdinals);
+ FunctionList=MODULEOBJECT_BASE_OFFSET_PLUS(ExportDir->AddressOfFunctions);
+
+ /* map (CHAR *)funcname->(PVOID *)ExportAddressp */
+ exportdir_hash=g_hash_table_new(g_str_hash,g_str_equal);
+
+ /* Initialize 'exportdir_hash' by all W32 exported functions. */
+ for (Idx=0;Idx<ExportDir->NumberOfNames;Idx++) {
+CHAR *funcname=MODULEOBJECT_BASE_OFFSET_PLUS(NameList[Idx]);
+
+ ExportAddressp=(PVOID *)(FunctionList+OrdinalList[Idx]);
+ ExportAddress=(PVOID)MODULEOBJECT_BASE_OFFSET_PLUS(*ExportAddressp);
+ if (0xF4 /* hlt */ ==*(guint8 *)ExportAddress) {
+ /* FIXME: 'data' type symbols should be permitted to have 0xF4 byte */
+ g_error("%s: Function already patched although we did not touch it yet: %s",G_STRLOC,funcname);
+ g_assert_not_reached();
+ }
+ g_assert(NULL==g_hash_table_lookup(exportdir_hash,funcname));
+ g_hash_table_insert(exportdir_hash,
+ funcname, /* key */
+ ExportAddressp); /* value */
+ }
+
+ /* Patch wished functions and remove them from 'exportdir_hash'. */
+ va_start(ap,FullName_utf8);
+ while (captive_va_arg(sym_name,ap)) {
+ captive_va_arg(sym_val ,ap);
+ /* 'sym_val' may be NULL if 'data' type && "pass"ed */
+ captive_va_arg(patchpoint,ap); /* 'data' type if ==NULL */
+ captive_va_arg(patchpointpatch,ap); /* 'data' type or 'pass' in non-debug mode if ==NULL */
+ ExportAddressp=g_hash_table_lookup(exportdir_hash,sym_name);
+ if (ExportAddressp==NULL) {
+ g_message("%s: Function not found for patchpoint (ignoring): %s",G_STRLOC,sym_name);
+ continue;
+ }
+ errbool=g_hash_table_remove(exportdir_hash,sym_name);
+ g_assert(errbool==TRUE);
+ if (!sym_val) { /* 'data' type && "pass"ed => do not corrupt it by 0xF4 */
+ g_assert(!patchpoint);
+ continue;
+ }
+ ExportAddress=(PVOID)MODULEOBJECT_BASE_OFFSET_PLUS(*ExportAddressp);
+ *ExportAddressp=(PVOID)MODULEOBJECT_BASE_OFFSET_MINUS(sym_val);
+ if (((ULONG)ExportAddress >= (ULONG)ExportDir) &&
+ ((ULONG)ExportAddress < (ULONG)ExportDir + ExportDirSize))
+ g_assert_not_reached(); /* LdrPEFixupForward() needed */
+ if (!patchpoint) /* 'data' type && !"pass"ed => do not corrupt it by 0xF4 */
+ continue;
+ patchpoint->orig_w32_func=ExportAddress;
+ if (!patchpointpatch) /* 'pass' in non-debug mode */
+ continue;
+ if (0xF4 /* hlt */ ==*patchpointpatch->orig_w32_func) /* Already patched by name-aliased function? */
+ continue;
+ g_assert(0xF4 /* hlt */ !=*patchpointpatch->orig_w32_func);
+ patchpointpatch->orig_w32_2ndinstr=patchpointpatch->orig_w32_func
+ +instruction_length((guint8 *)patchpointpatch->orig_w32_func);
+ g_assert(0xF4 /* hlt */ !=*patchpointpatch->orig_w32_2ndinstr);
+ patchpointpatch->wrap_wrap_func=sym_val;
+ patchpointpatch->orig_w32_func_byte=*patchpointpatch->orig_w32_func;
+ patchpointpatch->orig_w32_2ndinstr_byte=*patchpointpatch->orig_w32_2ndinstr;
+ patchpointpatch->through_w32_func=FALSE;
+ g_assert(NULL==g_hash_table_lookup(captive_ModuleList_patchpoint_hash,patchpointpatch->orig_w32_func));
+ g_hash_table_insert(captive_ModuleList_patchpoint_hash,
+ patchpointpatch->orig_w32_func, /* key */
+ patchpointpatch); /* value */
+ g_assert(NULL==g_hash_table_lookup(captive_ModuleList_patchpoint_hash,patchpointpatch->orig_w32_2ndinstr));
+ g_hash_table_insert(captive_ModuleList_patchpoint_hash,
+ patchpointpatch->orig_w32_2ndinstr, /* key */
+ patchpointpatch); /* value */
+ *(guint8 *)ExportAddress=0xF4; /* hlt */
+ }
+ va_end(ap);
+
+ /* The remaining entries of 'exportdir_hash' are W32 native functions
+ * unspecified by .captivesym file; we patch them as not-implemented ones.
+ */
+ g_hash_table_foreach(exportdir_hash,
+ (GHFunc)captive_ModuleList_patch_function_disable, /* func */
+ ModuleObject); /* used_data; unused */
+
+ g_hash_table_destroy(exportdir_hash);
+
+#undef MODULEOBJECT_BASE_OFFSET_PLUS /* no longer valid */
+#undef MODULEOBJECT_BASE_OFFSET_MINUS /* no longer valid */
+ return TRUE;
+}
+
+
+struct captive_ModuleList_patchpoint *captive_ModuleList_patchpoint_find(gconstpointer ExportAddress)
+{
+struct captive_ModuleList_patchpoint *r;
+
+ g_return_val_if_fail(ExportAddress!=NULL,NULL);
+
+ captive_ModuleList_patchpoint_hash_init();
+
+ r=g_hash_table_lookup(captive_ModuleList_patchpoint_hash,ExportAddress);
+ g_return_val_if_fail(r!=NULL,NULL);
+ g_assert(r->orig_w32_func==ExportAddress || r->orig_w32_2ndinstr==ExportAddress);
+
+ return r;
+}
+
+
+G_CONST_RETURN gchar *captive_ModuleList_function_disable_find(gconstpointer ExportAddress)
+{
+ g_return_val_if_fail(ExportAddress!=NULL,NULL);
+
+ return g_hash_table_lookup(captive_ModuleList_function_disable_hash,ExportAddress); /* funcname */
+}
+
+
+void *captive_Module_GetExportAddress(const gchar *ModuleName_utf8,const gchar *FunctionName)
+{
+MODULE_OBJECT *ModuleObject;
+void *r;
+
+ g_return_val_if_fail(ModuleName_utf8!=NULL,NULL);
+ g_return_val_if_fail(FunctionName!=NULL,NULL);
+
+ ModuleObject=LdrGetModuleObject(captive_utf8_to_UnicodeString_alloca(g_path_get_basename(ModuleName_utf8)));
+ g_return_val_if_fail(ModuleObject!=NULL,NULL);
+
+ r=LdrGetExportAddress(
+ ModuleObject, /* ModuleObject */
+ (/* de-const */char *)FunctionName, /* Name */
+ -1); /*Hint*/
+ g_return_val_if_fail(r!=NULL,NULL);
+
+ return r;
+}