https://github.com/fancycode/MemoryModu ... ryModule.c
I've had some intermittent hiccups while using this library so I wanted to see if I could piece together how it works by porting it to PureBasic. There are some parts I encountered that I wasn't sure I was converting properly.
Things to be aware of:
PerformBaseRelocation hasn't been tested because LocationDelta is false for this test. I don't know what I need to do to make it have a value so that it will call this function.
I'm fairly confident that CopySections() is fine. I went over it a couple times. The problem I've encountered is when execution hits BuildImportTable(). It's returning false because it's failing.. somewhere.
I'm stuck trying to decipher line 453 where I call "ReAllocateMemory". The original code calls "realloc". I don't understand this line at all. The first parameter should be "a memory block previously allocated with malloc, calloc or realloc to be reallocated", however, none of these functions are called elsewhere in the original library. Also, why does ReAllocateMemory succeed if I'm not using a valid MemoryID?
When VirtualAlloc is called, a desired address is always specified. Wouldn't this be a problem if, for example, two libraries want to be at the same address? How can it be assumed that this address will always be available while arbitrarily loading a library?
Any help would be appreciated.
Oh, and srod: I don't understand the math..

Here is the DLL project I'm using:
Code: Select all
ProcedureDLL Test()
MessageRequester("","Hello!")
EndProcedure
Code: Select all
XIncludeFile "LoadLibrary.pb"
DisableExplicit
; Lib=OpenLibrary(#PB_Any,"test.dll")
; Ptr=GetFunction(Lib,"Test")
;
; CallFunctionFast(Ptr)
FileID=ReadFile(#PB_Any,"test.dll")
If Not FileID
Debug "Error"
EndIf
Mem=AllocateMemory(Lof(FileID))
ReadData(FileID,Mem,Lof(FileID))
CloseFile(FileID)
MemoryLoadLibrary(Mem)
; Debug MemoryGetProcAddress(Mem,"Test")
Code: Select all
;/
;/ Memory DLL loading code
;/ Version 0.0.2
;/
;/ Copyright (c) 2004-2010 by Joachim Bauch / mail@joachim-bauch.de
;/ http://www.joachim-bauch.de
;/
;/ The contents of this file are subject to the Mozilla Public License Version
;/ 1.1 (the "License") you may not use this file except in compliance with
;/ the License. You may obtain a copy of the License at
;/ http://www.mozilla.org/MPL/
;/
;/ Software distributed under the License is distributed on an "AS IS" basis,
;/ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
;/ for the specific language governing rights and limitations under the
;/ License.
;/
;/ The Original Code is MemoryModule.c
;/
;/ The Initial Developer of the Original Code is Joachim Bauch.
;/
;/ Portions created by Joachim Bauch are Copyright (C) 2004-2010
;/ Joachim Bauch. All Rights Reserved.
;/
;/ http://github.com/fancycode/MemoryModule
;/ October 24, 2010
EnableExplicit
Global SectionData
Global BaseMemory
Global HeapMemory
Global VirtualAlloc1
Global VirtualAlloc2
Global VirtualAlloc3
Global VirtualAlloc4
Global VirtualAlloc5
Global VirtualAlloc6
Global VirtualAlloc7
; Structure IMAGE_EXPORT_DIRECTORY
; Characteristics.l
; TimeDateStamp.l
; MajorVersion.w
; MinorVersion.w
; Name.l
; Base.l
; NumberOfFunctions.l
; NumberOfNames.l
; AddressOfFunctions.l ;/ RVA from base of image
; AddressOfNames.l ;/ RVA from base of image
; AddressOfNameOrdinals.l ;/ RVA from base of image
; EndStructure
Structure IMAGE_IMPORT_BY_NAME
Hint.w
Name.b[1]
EndStructure
Structure MEMORYMODULE
*Headers.IMAGE_NT_HEADERS ;/ Is this *Headers?
*CodeBase
*Modules
NumModules.i
Initialized.i
EndStructure
Structure IMAGE_BASE_RELOCATION
VirtualAddress.l
SizeOfBlock.l
EndStructure
Structure IMAGE_IMPORT_DESCRIPTOR
;/ 0 for terminating null import descriptor RVA to original unbound IAT (#PIMAGE_THUNK_DATA)
StructureUnion
Characteristics.l
OriginalFirstThunk.l
EndStructureUnion
TimeDateStamp.l ;/ 0 if not bound, -1 if bound, and real date\time stamp in #IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND) O.W. date/time stamp of DLL bound to (Old BIND)
ForwarderChain.l ;/ -1 if no forwarders
Name.l
FirstThunk.l ;/ RVA to IAT (if bound this IAT has actual addresses)
EndStructure
#IMAGE_SIZEOF_SHORT_NAME=8
Structure IMAGE_SECTION_HEADER
Name.b[#IMAGE_SIZEOF_SHORT_NAME]
StructureUnion
PhysicalAddress.l
VirtualSize.l
EndStructureUnion
VirtualAddress.l
SizeOfRawData.l
PointerToRawData.l
PointerToRelocations.l
PointerToLinenumbers.l
NumberOfRelocations.w
NumberOfLinenumbers.w
Characteristics.l
EndStructure
; Structure IMAGE_DOS_HEADER
; e_magic.w ;/ Magic number
; e_cblp.w ;/ Bytes on last page of file
; e_cp.w ;/ Pages in file
; e_crlc.w ;/ Relocations
; e_cparhdr.w ;/ Size of header in paragraphs
; e_minalloc.w ;/ Minimum extra paragraphs needed
; e_maxalloc.w ;/ Maximum extra paragraphs needed
; e_ss.w ;/ Initial (relative) SS value
; e_sp.w ;/ Initial SP value
; e_csum.w ;/ Checksum
; e_ip.w ;/ Initial IP value
; e_cs.w ;/ Initial (relative) CS value
; e_lfarlc.w ;/ File address of relocation table
; e_ovno.w ;/ Overlay number
; e_res1.w[4] ;/ Reserved words
; e_oemid.w ;/ OEM identifier (For e_oeminfo)
; e_oeminfo.w ;/ OEM information e_oemid specific
; e_res2.w[10] ;/ Reserved words
; e_lfanew.l ;/ File address of new exe header
; EndStructure
; Structure IMAGE_DATA_DIRECTORY
; VirtualAddress.l
; Size.l
; EndStructure
Structure IMAGE_OPTIONAL_HEADER32
;/ Standard fields.
Magic.w
MajorLinkerVersion.b
MinorLinkerVersion.b
SizeOfCode.l
SizeOfInitializedData.l
SizeOfUninitializedData.l
AddressOfEntryPoint.l
BaseOfCode.l
BaseOfData.l
;/ NT additional fields.
ImageBase.l
SectionAlignment.l
FileAlignment.l
MajorOperatingSystemVersion.w
MinorOperatingSystemVersion.w
MajorImageVersion.w
MinorImageVersion.w
MajorSubsystemVersion.w
MinorSubsystemVersion.w
Win32VersionValue.l
SizeOfImage.l
SizeOfHeaders.l
CheckSum.l
Subsystem.w
DllCharacteristics.w
SizeOfStackReserve.l
SizeOfStackCommit.l
SizeOfHeapReserve.l
SizeOfHeapCommit.l
LoaderFlags.l
NumberOfRvaAndSizes.l
DataDirectory.IMAGE_DATA_DIRECTORY[#IMAGE_NUMBEROF_DIRECTORY_ENTRIES]
EndStructure
; Structure IMAGE_FILE_HEADER
; Machine.w
; NumberOfSections.w
; TimeDateStamp.l
; PointerToSymbolTable.l
; NumberOfSymbols.l
; SizeOfOptionalHeader.w
; Characteristics.w
; EndStructure
; Structure IMAGE_NT_HEADERS
; Signature.l
; FileHeader.IMAGE_FILE_HEADER
; OptionalHeader.IMAGE_OPTIONAL_HEADER32
; EndStructure
#IMAGE_SIZEOF_BASE_RELOCATION=SizeOf(IMAGE_BASE_RELOCATION)
#IMAGE_SCN_CNT_INITIALIZED_DATA=$00000040
#IMAGE_SCN_CNT_UNINITIALIZED_DATA=$00000080
#IMAGE_SCN_MEM_NOT_CACHED=$04000000
#IMAGE_SCN_MEM_DISCARDABLE=$02000000
#IMAGE_SCN_MEM_EXECUTE=$20000000
#IMAGE_SCN_MEM_READ=$40000000
#IMAGE_SCN_MEM_WRITE=$80000000
#IMAGE_REL_BASED_ABSOLUTE=0
#IMAGE_REL_BASED_HIGH=1
#IMAGE_REL_BASED_LOW=2
#IMAGE_REL_BASED_HIGHLOW=3
#IMAGE_REL_BASED_HIGHADJ=4
#IMAGE_REL_BASED_MIPS_JMPADDR=5
#IMAGE_REL_BASED_SECTION=6
#IMAGE_REL_BASED_REL32=7
#IMAGE_REL_BASED_MIPS_JMPADDR16=9
#IMAGE_REL_BASED_IA64_IMM64=9
#IMAGE_REL_BASED_DIR64=10
#IMAGE_REL_BASED_HIGH3ADJ=11
#IMAGE_NT_SIGNATURE=$00004550
#IMAGE_DOS_SIGNATURE=$5A4D
#IMAGE_ORDINAL_FLAG=$80000000
; Structure MEMORYMODULE
; headers.PIMAGE_NT_HEADERS
; *codeBase
; *modules
; numModules.i
; initialized.i
; EndStructure
;typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
;#define GET_HEADER_DICTIONARY(module, idx) &(module)->headers->OptionalHeader.DataDirectory[idx]
Declare IMAGE_FIRST_SECTION(*Header.IMAGE_NT_HEADERS)
Declare CopySections(*SectionData, *OldHeaders.IMAGE_NT_HEADERS, *Module.MEMORYMODULE)
Declare FinalizeSections(*Module.MEMORYMODULE)
Declare PerformBaseRelocation(*Module.MEMORYMODULE, Delta.i)
Declare.i BuildImportTable(*Module.MEMORYMODULE)
Declare.i MemoryLoadLibrary(*SectionData)
Declare MemoryGetProcAddress(*Module.MEMORYMODULE, ModuleName.s)
Declare MemoryFreeLibrary(*Module.MEMORYMODULE)
Procedure IMAGE_FIRST_SECTION(*Header.IMAGE_NT_HEADERS)
If Not *Header
ProcedureReturn 0
EndIf
ProcedureReturn *Header+OffsetOf(IMAGE_NT_HEADERS\OptionalHeader)+*Header\FileHeader\SizeOfOptionalHeader
EndProcedure
Procedure CopySections(*SectionData, *OldHeaders.IMAGE_NT_HEADERS, *Module.MEMORYMODULE)
Protected *CodeBase
Protected *Dest
Protected *Section.IMAGE_SECTION_HEADER
Protected Size.i
Protected i.i
*CodeBase=*Module\codeBase
*Section=IMAGE_FIRST_SECTION(*Module\headers)
For i=0 To *Module\headers\FileHeader\NumberOfSections-1
If i
*Section+SizeOf(IMAGE_SECTION_HEADER)
EndIf
If Not *Section\SizeOfRawData
;/ Section doesn't contain data in the dll itself, but may define
;/ uninitialized data
Size=*OldHeaders\OptionalHeader\SectionAlignment
If Size>0
*Dest=VirtualAlloc_(*CodeBase+*Section\VirtualAddress,Size,#MEM_COMMIT,#PAGE_READWRITE)
*Section\PhysicalAddress=*Dest
EndIf
;/ Section is empty
Continue
EndIf
;/ Commit memory block and copy data from dll
*Dest=VirtualAlloc_(*CodeBase+*Section\VirtualAddress,*Section\SizeOfRawData,#MEM_COMMIT,#PAGE_READWRITE)
CopyMemory(*SectionData+*Section\PointerToRawData,*Dest,*Section\SizeOfRawData)
*Section\PhysicalAddress=*Dest
Next i
EndProcedure
; ;/ Protection flags for memory pages (Executable, Readable, Writeable)
; Static int ProtectionFlags[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},
; },
; }
Procedure FinalizeSections(*Module.MEMORYMODULE)
Protected *Section.IMAGE_SECTION_HEADER
Protected ImageOffset.i
Protected Executable
Protected Readable
Protected Writeable
Protected Protect
Protected OldProtect
Protected Size
Protected i.i
Dim ProtectionFlags.b(2,2,2)
ProtectionFlags(0,0,0)=$01
ProtectionFlags(0,0,1)=$08
ProtectionFlags(0,1,0)=$02
ProtectionFlags(0,1,1)=$04
ProtectionFlags(1,0,0)=$10
ProtectionFlags(1,0,1)=$80
ProtectionFlags(1,1,0)=$20
ProtectionFlags(1,1,1)=$40
*Section=IMAGE_FIRST_SECTION(*Module\headers)
CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
ImageOffset=*Module\headers\OptionalHeader\ImageBase&$ffffffff00000000
CompilerEndIf
;/ Loop through all sections and change access flags
For i=0 To *Module\headers\FileHeader\NumberOfSections-1
If i
*Section+SizeOf(IMAGE_SECTION_HEADER)
EndIf
Executable=#False
Readable=#False
Writeable=#False
If *Section\Characteristics&#IMAGE_SCN_MEM_EXECUTE
Executable=#True
EndIf
If *Section\Characteristics&#IMAGE_SCN_MEM_READ
Readable=#True
EndIf
If *Section\Characteristics&#IMAGE_SCN_MEM_WRITE
Writeable=#True
EndIf
If *Section\Characteristics &#IMAGE_SCN_MEM_DISCARDABLE
;/ Section is not needed any more and can safely be freed
VirtualFree_(*Section\PhysicalAddress|ImageOffset,*Section\SizeOfRawData,#MEM_DECOMMIT)
Continue
EndIf
;/ Determine protection flags based on characteristics
Protect=ProtectionFlags(executable,readable,writeable)
If *Section\Characteristics&#IMAGE_SCN_MEM_NOT_CACHED
Protect=Protect|#PAGE_NOCACHE
EndIf
;/ Determine size of region
Size=*Section\SizeOfRawData
If Not Size
If *Section\Characteristics&#IMAGE_SCN_CNT_INITIALIZED_DATA
Size=*Module\headers\OptionalHeader\SizeOfInitializedData
ElseIf *Section\Characteristics&#IMAGE_SCN_CNT_UNINITIALIZED_DATA
Size=*Module\headers\OptionalHeader\SizeOfUninitializedData
EndIf
EndIf
If Size>0
;/ Change memory access flags
If Not VirtualProtect_(*Section\PhysicalAddress|ImageOffset,Size,Protect,@OldProtect)
Debug "Error protecting memory page"
EndIf
EndIf
Next i
EndProcedure
Procedure PerformBaseRelocation(*Module.MEMORYMODULE, Delta.i)
Protected *CodeBase
Protected *Directory.IMAGE_DATA_DIRECTORY
Protected *Relocation.IMAGE_BASE_RELOCATION
Protected *PatchAddr
Protected Type.i
Protected Offset.i
Protected *Dest
Protected *RelInfo
Protected i.i
*CodeBase=*Module\codeBase
*Directory=*Module\headers\OptionalHeader\DataDirectory[#IMAGE_DIRECTORY_ENTRY_BASERELOC]
If *Directory\Size>0
*Relocation=*CodeBase+*Directory\VirtualAddress
;/ Matt: While loop here?
While *Relocation\VirtualAddress>0
*Dest=*CodeBase+*Relocation\VirtualAddress
*RelInfo=*Relocation+#IMAGE_SIZEOF_BASE_RELOCATION
For i=0 To *Relocation\SizeOfBlock-#IMAGE_SIZEOF_BASE_RELOCATION/2-1
If i
*RelInfo+SizeOf(Word) ;/ Will with be ok when porting to 64-bit? (was unsigned short)
EndIf
;/ the upper 4 bits define the type of relocation
Type=*RelInfo>>12
;/ the lower 12 bits define the offset
Offset=*RelInfo&$fff
Select Type
;/ Skip relocation for absolute addresses
Case #IMAGE_REL_BASED_ABSOLUTE
Case #IMAGE_REL_BASED_HIGHLOW,#IMAGE_REL_BASED_DIR64:
*PatchAddr=*Dest+Offset
*PatchAddr+Delta
Break
Default
;Debug "Unknown relocation: "+Str(Type) ;/ Some types are unhandled for x86 or unexpected?
EndSelect
Next i
;/ Advance to next relocation block
*Relocation+*Relocation\SizeOfBlock
Wend
EndIf
EndProcedure
Procedure.i BuildImportTable(*Module.MEMORYMODULE)
Protected Result=1
Protected *CodeBase
Protected *Directory.IMAGE_DATA_DIRECTORY
Protected *ImportDesc.IMAGE_IMPORT_DESCRIPTOR
Protected *ThunkRef
Protected *FuncRef
Protected Lib
Protected *ThunkData.IMAGE_IMPORT_BY_NAME
*CodeBase=*Module\codeBase
*Directory=*Module\headers\OptionalHeader\DataDirectory[#IMAGE_DIRECTORY_ENTRY_IMPORT]
If *Directory\Size>0
*ImportDesc=*CodeBase+*Directory\VirtualAddress
;/ Matt: While loop here?
;/ Matt: Is it really ok to loop IsBadReadPtr..?
While Not IsBadReadPtr_(*ImportDesc,SizeOf(IMAGE_IMPORT_DESCRIPTOR)) And *ImportDesc\Name
;/ Matt: This code originally compared the result of LoadLibrary to #INVALID_HANDLE_VALUE.. is that even a valid result?
Lib=LoadLibrary_(*CodeBase+*ImportDesc\Name)
If Not Lib
Debug "Can't load library"
Result=0
Break
EndIf
Debug "Check this code"
Protected Mem=ReAllocateMemory(*Module\modules,(*Module\numModules+1)*(SizeOf(Integer)))
Debug Mem
*Module\modules=Mem
If Not *Module\modules
Result=0
Break
EndIf
;/ Matt: PokeI here?
PokeI(*Module\modules+*Module\numModules+1,Lib)
If *ImportDesc\OriginalFirstThunk
*ThunkRef=*CodeBase+*ImportDesc\OriginalFirstThunk
*FuncRef=*CodeBase+*ImportDesc\FirstThunk
Else
;/ No hint table
*ThunkRef=*CodeBase+*ImportDesc\FirstThunk
*FuncRef=*CodeBase+*ImportDesc\FirstThunk
EndIf
Debug "May be a bug here"
;/ Matt: Pointers get a little funky here. I don't think I translated it correctly
While *ThunkRef
;/ IMAGE_SNAP_BY_ORDINAL(*ThunkRef)
;/ IMAGE_SNAP_BY_ORDINAL(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG) != 0)
If Not *ThunkRef&#IMAGE_ORDINAL_FLAG
;/ IMAGE_ORDINAL(*ThunkRef)
;/ IMAGE_ORDINAL(Ordinal) (Ordinal & 0xffff)
*FuncRef=GetProcAddress_(Lib,*ThunkRef&$ffff)
Else
*ThunkData=*CodeBase+*ThunkRef
*FuncRef=GetProcAddress_(Lib,*ThunkData\Name)
EndIf
If Not *FuncRef
Result=0
Break
EndIf
*ThunkRef+SizeOf(Integer)
*FuncRef+SizeOf(Integer)
Wend
If Not Result
Break
EndIf
*ImportDesc+SizeOf(IMAGE_IMPORT_DESCRIPTOR)
Wend
EndIf
ProcedureReturn Result
EndProcedure
Procedure.i MemoryLoadLibrary(*SectionData)
Protected *Result.MEMORYMODULE
Protected *DosHeader.IMAGE_DOS_HEADER
Protected *OldHeader.IMAGE_NT_HEADERS
Protected *Code
Protected *Headers
Protected LocationDelta.i
Protected *DllEntry
Protected Successful.b
BaseMemory=*SectionData
*DosHeader=*SectionData
If Not *DosHeader\e_magic=#IMAGE_DOS_SIGNATURE
Debug "Not a valid executable file."
ProcedureReturn #False
EndIf
;/ Matt: Conversion may be wrong here. Something might need to be dereferenced
*OldHeader=*SectionData+*DosHeader\e_lfanew
If Not *OldHeader\Signature=#IMAGE_NT_SIGNATURE
Debug "No PE header found."
ProcedureReturn #False
EndIf
;/ reserve memory for image of library
*Code=VirtualAlloc_(*OldHeader\OptionalHeader\ImageBase,*OldHeader\OptionalHeader\SizeOfImage,#MEM_RESERVE,#PAGE_READWRITE)
VirtualAlloc1=*Code
If Not *Code
;/ Try to allocate memory at arbitrary position
*Code=VirtualAlloc_(0,*OldHeader\OptionalHeader\SizeOfImage,#MEM_RESERVE,#PAGE_READWRITE)
If Not *Code
Debug "Can't reserve memory"
ProcedureReturn #False
EndIf
EndIf
*Result=HeapAlloc_(GetProcessHeap_(),0,SizeOf(MEMORYMODULE))
*Result\codeBase=*Code
*Result\numModules=0
*Result\modules=0
*Result\initialized=0
HeapMemory=*Result
;/ XXX: is it correct to commit the complete memory region at once?
;/ calling DllEntry raises an exception if we don't...
VirtualAlloc_(*Code,*OldHeader\OptionalHeader\SizeOfImage,#MEM_COMMIT,#PAGE_READWRITE)
;/ Commit memory for headers
*Headers=VirtualAlloc_(*Code,*OldHeader\OptionalHeader\SizeOfHeaders,#MEM_COMMIT,#PAGE_READWRITE)
VirtualAlloc2=*Headers
;/ Copy PE header to code
CopyMemory(*DosHeader,*Headers,*DosHeader\e_lfanew+*OldHeader\OptionalHeader\SizeOfHeaders)
;/ Matt: Conversion may be wrong here. Something might need to be dereferenced
*Result\headers=*SectionData+*DosHeader\e_lfanew
;/ Update position
*Result\headers\OptionalHeader\ImageBase=*Code
;/ Copy sections from DLL file block to new memory location
CopySections(*SectionData,*OldHeader,*Result)
;/ Adjust base address of imported data
LocationDelta=*Code-*OldHeader\OptionalHeader\ImageBase
If LocationDelta
PerformBaseRelocation(*Result,LocationDelta)
EndIf
; Debug "Result "+Str(*Result.MEMORYMODULE-HeapMemory)
; ; Debug "DosHeader "+Str(*DosHeader.IMAGE_DOS_HEADER-BaseMemory)
; ; Debug "OldHeader "+Str(*OldHeader.IMAGE_NT_HEADERS-BaseMemory)
; ; Debug "Code "+Str(*Code-VirtualAlloc1)
; ; Debug "Headers "+Str(*Headers-VirtualAlloc2)
; Debug "LocationDelta "+Str(LocationDelta.i)
; ; Debug "DllEntry "+Str(*DllEntry)
; ; Debug "Successful "+Str(Successful.b)
;
;/ Load required dlls and adjust function table of imports
If Not BuildImportTable(*Result)
Debug "Error!"
MemoryFreeLibrary(*Result)
ProcedureReturn #False
EndIf
Debug "No Error!"
End
;/ Mark memory pages depending on section headers and release
;/ sections that are marked as "discardable"
FinalizeSections(*Result)
;/ Get entry point of loaded library
If *Result\headers\OptionalHeader\AddressOfEntryPoint
*DllEntry=*Code+*Result\headers\OptionalHeader\AddressOfEntryPoint
If Not *DllEntry
Debug "Library has no entry point."
MemoryFreeLibrary(*Result)
ProcedureReturn #False
EndIf
;/ Notify library about attaching to process
Successful=CallFunctionFast(*DllEntry,*Code,#DLL_PROCESS_ATTACH,0)
If Not Successful
Debug "Can't attach library."
MemoryFreeLibrary(*Result)
ProcedureReturn #False
EndIf
*Result\initialized=1
EndIf
ProcedureReturn *Result
EndProcedure
Procedure MemoryGetProcAddress(*Module.MEMORYMODULE, ModuleName.s)
Protected *CodeBase
Protected Index.i
Protected *NameRef
Protected *Ordinal
Protected *Exports.IMAGE_EXPORT_DIRECTORY
Protected *Directory.IMAGE_DATA_DIRECTORY
Protected i
*CodeBase=*Module\codeBase
*Directory=*Module\headers\OptionalHeader\DataDirectory[#IMAGE_DIRECTORY_ENTRY_EXPORT]
Index.i=-1
If Not *Directory\Size
;/ No export table found
ProcedureReturn #False
EndIf
*Exports=*CodeBase+*Directory\VirtualAddress
If Not *Exports\NumberOfNames Or Not *Exports\NumberOfFunctions
;/ DLL doesn't export anything
ProcedureReturn #False
EndIf
;/ Search function name in list of exported names
*NameRef=*CodeBase+*Exports\AddressOfNames
*Ordinal=*CodeBase+*Exports\AddressOfNameOrdinals
For i=0 To *Exports\NumberOfNames-1
If i
*NameRef+SizeOf(Long)
*Ordinal+SizeOf(Word)
EndIf
If ModuleName.s=PeekS(*CodeBase+*NameRef)
;/ Matt: Is this right?
Index=PeekW(*Ordinal)
Break
EndIf
Next i
If Index=-1
;/ Exported symbol not found
ProcedureReturn #False
EndIf
If Index>*Exports\NumberOfFunctions
;/ Name <-> ordinal numbers don't match
ProcedureReturn #False
EndIf
;/ AddressOfFunctions contains the RVAs to the "real" functions
;/ PeekI here?
ProcedureReturn *CodeBase+PeekI(*CodeBase+*Exports\AddressOfFunctions+(Index*4))
EndProcedure
Procedure MemoryFreeLibrary(*Module.MEMORYMODULE)
Protected *DllEntry
Protected i.i
If *Module
If *Module\initialized
;/ Notify library about detaching from process
*DllEntry=*Module\codeBase+*Module\headers\OptionalHeader\AddressOfEntryPoint
CallFunctionFast(*Module\codeBase,#DLL_PROCESS_DETACH,0)
*Module\initialized=0
EndIf
If *Module\modules
;/ Free previously opened libraries
For i=0 To *Module\numModules-1
;/ Matt: Is this a valid comparison? Maybe it should compare against 0?
;/ Matt: Changed this from comparison to "#INVALID_HANDLE_VALUE"
If Not PeekI(*Module\modules+i)
FreeLibrary_(PeekI(*Module\modules+i))
EndIf
Next i
FreeMemory(*Module\modules)
EndIf
If *Module\codeBase
;/ Release memory of library
VirtualFree_(*Module\codeBase,0,#MEM_RELEASE)
EndIf
EndIf
HeapFree_(GetProcessHeap_(),0,*Module)
EndProcedure