/* $Id$ * reactos ldr/ (loader) emulation of libcaptive * Copyright (C) 2002 Jan Kratochvil * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; exactly version 2 of June 1991 is required * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #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/rtl-file.h" #include #include #include #include "reactos/napi/types.h" #include "reactos/internal/kd.h" /* for KDB_LOADDRIVER_HOOK */ #include #include /* for PROT_READ, MAP_SHARED */ #include "captive/macros.h" #include #include "reactos/ntos/rtl.h" /* for InsertTailList() */ #include "reactos/internal/debug.h" /* for assert() */ #include /* for g_path_get_basename() */ #include #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; } /** * captive_LdrLoadModule: * @options_module: #captive_options_module structure describing the module to load. * Loading of already loaded module is forbidden. * @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 captive_LdrLoadModule(struct captive_options_module *options_module,PMODULE_OBJECT *ModuleObjectp) { PMODULE_OBJECT Module; NTSTATUS err; gchar *Filename_utf8=options_module->pathname_utf8; gchar *Filename_bslash_utf8,*s; UNICODE_STRING *Filename_bslash; *ModuleObjectp=NULL; /* 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 */ *ModuleObjectp=Module; /* Hook for KDB on loading a driver. */ KDB_LOADDRIVER_HOOK(Filename_bslash,Module); return STATUS_SUCCESS; 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. * @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. * @DriverEntry_RegistryPath: argument #RegistryPath of #PDRIVER_INITIALIZE call. * * Corresponds to reactos LdrpLoadAndCallImage() but it also provides arguments * to pass to #PDRIVER_INITIALIZE call of module driver initialization. * * 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,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=captive_LdrLoadModule(options_module,ModuleObjectp); g_return_val_if_fail(NT_SUCCESS(err),err); /* initialize the module */ DriverEntry=(PDRIVER_INITIALIZE)(*ModuleObjectp)->EntryPoint; err=(NTSTATUS)captive_stdcall_call_8((CaptiveStdCallFunc8)DriverEntry, DriverEntry_DriverObject, DriverEntry_RegistryPath); if (!NT_SUCCESS(err)) goto err_LdrUnloadModule; /* assumed STATUS_SUCCESS */ return err; err_LdrUnloadModule: /* errors ignored */ LdrUnloadModule(*ModuleObjectp); *ModuleObjectp=NULL; /* err: */ g_return_val_if_reached(err); } /** * captive_ModuleList_add_builtin: * @FullName_utf8: String to fill in #PMODULE_OBJECT->FullName. * @...: (const gchar *sym_name,void *sym_val) symbol list terminated by %NULL. * * Adds simulated built-in module to #ModuleListHead module list. * It can be used for the functionality of reactos/ntoskrnl/ldr/loader.c/LdrInitModuleManagement(). * libcaptive does not support Ordinals - we just pretend liner (%0-based) * Ordinal numbers of the functions in given @... stdargs order. * * Returns: %TRUE if the module was successfuly added. */ gboolean captive_ModuleList_add_builtin(const gchar *FullName_utf8,...) { MODULE_OBJECT *ModuleObject; BOOLEAN errbool; va_list ap; const gchar *sym_name; const void *sym_val; gchar *basename_utf8; IMAGE_DOS_HEADER *DosHeader; 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_MINUS()ed */ WORD *OrdinalList; /* linear list - libcaptive doesn't support Ordinals */ 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_MINUS(addr) ((ptrdiff_t)((char *)addr-(char *)ModuleObject->Base)) ModuleObject->Flags = MODULE_FLAG_PE; /* fill ModuleObject->FullName * ModuleObject->FullName should be probably "\\SYSTEM32\\..." style but * we put there '/'-based UNIX filenames in libcaptive. */ errbool=RtlCreateUnicodeString(&ModuleObject->FullName,captive_utf8_to_UnicodeString_alloca(FullName_utf8)->Buffer); if (!errbool) { g_error("captive_ModuleList_add_builtin: RtlCreateUnicodeString()==FALSE"); goto err_g_free_ModuleObject; } /* fill ModuleObject->BaseName * reactos/ntoskrnl/ldr/loader.c/LdrpBuildModuleBaseName() does this one * but it is 'static' for that file and also it is stricly backslash based. * ModuleObject->FullName should be probably "\\SYSTEM32\\..." style but * we put there '/'-based UNIX filenames in libcaptive. */ basename_utf8=g_path_get_basename(FullName_utf8); errbool=RtlCreateUnicodeString(&ModuleObject->BaseName,captive_utf8_to_UnicodeString_alloca(basename_utf8)->Buffer); g_free(basename_utf8); if (!errbool) { g_error("captive_ModuleList_add_builtin: RtlCreateUnicodeString()==FALSE"); goto err_g_free_ModuleObject; } /* We must satisfy reactos/ntoskrnl/ldr/rtl.c/RtlImageDirectoryEntryToData(,,IMAGE_DIRECTORY_ENTRY_EXPORT) * prepare module headers */ captive_new0(DosHeader); ModuleObject->Base=DosHeader; /* link DosHeader to ModuleObject */ DosHeader->e_magic=IMAGE_DOS_MAGIC; captive_new0(NTHeaders); 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_MINUS(ExportDir); /* link ExportDir to NTHeaders */ ExportDir->Base=0; /* base Ordinal number; Ordinals are not supported by libcaptive */ /* count the number of symbols */ va_start(ap,FullName_utf8); for (symN=0;captive_va_arg(sym_name,ap);symN++) captive_va_arg(sym_val,ap); va_end(ap); ExportDir->NumberOfNames=symN; ExportDir->NumberOfFunctions=symN; /* allocate and link the symbol tables */ captive_newn(NameList,symN); ExportDir->AddressOfNames=(PDWORD *)MODULEOBJECT_BASE_OFFSET_MINUS(NameList); /* link NameList to ExportDir */ captive_newn(OrdinalList,symN); ExportDir->AddressOfNameOrdinals=(PWORD *)MODULEOBJECT_BASE_OFFSET_MINUS(OrdinalList); /* link OrdinalList to ExportDir */ captive_newn(FunctionList,symN); ExportDir->AddressOfFunctions=(PDWORD *)MODULEOBJECT_BASE_OFFSET_MINUS(FunctionList); /* link FunctionList to ExportDir */ /* fill in symbol tables */ va_start(ap,FullName_utf8); for (symi=0;symiListEntry); return TRUE; err_g_free_ModuleObject: 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;IdxNumberOfNames;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; }