We don't display ads so we rely on your Bitcoin donations to 1KWEk9QaiJb2NwP5YFmR24LyUBa4JyuKqZ
Post date: Sep 5, 2010 5:01:19 AM
BTMemoryModule allows you to load a dll file directly from memory (ie. without dropping it to disk).
The archive contains two units (one original, the other unicode compatible) as well as an example of how to use the unit (pictured).
unit BTMemoryModule; {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Memory DLL loading code * * ------------------------ * * * * MemoryModule "Conversion to Delphi" * * Copyright (c) 2005 - 2006 by Martin Offenwanger / coder@dsplayer.de * * http://www.dsplayer.de * * * * Original C++ Code "MemoryModule Version 0.0.1" * * Copyright (c) 2004- 2006 by Joachim Bauch / mail@joachim-bauch.de * * http://www.joachim-bauch.de * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2.1 of the License, or (at your option) any later version. * * * * This library 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 * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}{@author(Martin Offenwanger: coder@dsplayer.de)@created(Mar 20, 2005)@lastmod(Sep 27, 2005)}interfaceuses // Borland Run-time Library Windows; {++++++++++++++++++++++++++++++++++++++ *** MemoryModule Type Definition *** --------------------------------------}type PBTMemoryModule = ^TBTMemoryModule; _BT_MEMORY_MODULE = packed record headers: PImageNtHeaders; codeBase: Pointer; modules: Pointer; numModules: integer; initialized: boolean; end;{$EXTERNALSYM _BT_MEMORY_MODULE} TBTMemoryModule = _BT_MEMORY_MODULE; BT_MEMORY_MODULE = _BT_MEMORY_MODULE;{$EXTERNALSYM BT_MEMORY_MODULE} {++++++++++++++++++++++++++++++++++++++++++++++++++ *** Memory DLL loading functions Declaration *** --------------------------------------------------}// return value is nil if function failsfunction BTMemoryLoadLibary(var f_data: Pointer; const f_size: int64): PBTMemoryModule; stdcall;// return value is nil if function failsfunction BTMemoryGetProcAddress(var f_module: PBTMemoryModule; const f_name: PChar): Pointer; stdcall;// free moduleprocedure BTMemoryFreeLibrary(var f_module: PBTMemoryModule); stdcall;// returns last errorfunction BTMemoryGetLastError: string; stdcall;implementationuses // Borland Run-time Library SysUtils; {+++++++++++++++++++++++++++++++++++ *** Dll EntryPoint Definition *** -----------------------------------}type TDllEntryProc = function(hinstdll: THandle; fdwReason: DWORD; lpReserved: Pointer): BOOL; stdcall; {++++++++++++++++++++++++++++++++++++++++ *** Missing Windows API Definitions *** ----------------------------------------} PImageBaseRelocation = ^TImageBaseRelocation; _IMAGE_BASE_RELOCATION = packed record VirtualAddress: DWORD; SizeOfBlock: DWORD; end;{$EXTERNALSYM _IMAGE_BASE_RELOCATION} TImageBaseRelocation = _IMAGE_BASE_RELOCATION; IMAGE_BASE_RELOCATION = _IMAGE_BASE_RELOCATION;{$EXTERNALSYM IMAGE_BASE_RELOCATION} PImageImportDescriptor = ^TImageImportDescriptor; _IMAGE_IMPORT_DESCRIPTOR = packed record OriginalFirstThunk: DWORD; TimeDateStamp: DWORD; ForwarderChain: DWORD; Name: DWORD; FirstThunk: DWORD; end;{$EXTERNALSYM _IMAGE_IMPORT_DESCRIPTOR} TImageImportDescriptor = _IMAGE_IMPORT_DESCRIPTOR; IMAGE_IMPORT_DESCRIPTOR = _IMAGE_IMPORT_DESCRIPTOR;{$EXTERNALSYM IMAGE_IMPORT_DESCRIPTOR} PImageImportByName = ^TImageImportByName; _IMAGE_IMPORT_BY_NAME = packed record Hint: Word; Name: array[0..255] of Byte; // original: "Name: array [0..0] of Byte;" end;{$EXTERNALSYM _IMAGE_IMPORT_BY_NAME} TImageImportByName = _IMAGE_IMPORT_BY_NAME; IMAGE_IMPORT_BY_NAME = _IMAGE_IMPORT_BY_NAME;{$EXTERNALSYM IMAGE_IMPORT_BY_NAME}const IMAGE_SIZEOF_BASE_RELOCATION = 8;{$EXTERNALSYM IMAGE_SIZEOF_BASE_RELOCATION} IMAGE_REL_BASED_HIGHLOW = 3;{$EXTERNALSYM IMAGE_REL_BASED_HIGHLOW} IMAGE_ORDINAL_FLAG32 = DWORD($80000000);{$EXTERNALSYM IMAGE_ORDINAL_FLAG32}var lastErrStr: string; {+++++++++++++++++++++++++++++++++++++++++++++++++++++ *** Memory DLL loading functions Implementation *** -----------------------------------------------------}function BTMemoryGetLastError: string; stdcall;begin Result := lastErrStr;end;function GetFieldOffset(const Struc; const Field): Cardinal; stdcall;begin Result := Cardinal(@Field) - Cardinal(@Struc);end;function GetImageFirstSection(NtHeader: PImageNtHeaders): PImageSectionHeader; stdcall;begin Result := PImageSectionHeader(Cardinal(NtHeader) + GetFieldOffset(NtHeader^, NtHeader^.OptionalHeader) + NtHeader^.FileHeader.SizeOfOptionalHeader);end;function GetHeaderDictionary(f_module: PBTMemoryModule; f_idx: integer): PImageDataDirectory; stdcall;begin Result := PImageDataDirectory(@(f_module.headers.OptionalHeader.DataDirectory[f_idx]));end;function GetImageOrdinal(Ordinal: DWORD): Word; stdcall;begin Result := Ordinal and $FFFF;end;function GetImageSnapByOrdinal(Ordinal: DWORD): Boolean; stdcall;begin Result := ((Ordinal and IMAGE_ORDINAL_FLAG32) <> 0);end;procedure CopySections(const f_data: Pointer; const f_old_headers: TImageNtHeaders; f_module: PBTMemoryModule); stdcall;var l_size, i: integer; l_codebase: Pointer; l_dest: Pointer; l_section: PImageSectionHeader;begin l_codebase := f_module.codeBase; l_section := GetImageFirstSection(f_module.headers); for i := 0 to f_module.headers.FileHeader.NumberOfSections - 1 do begin // section doesn't contain data in the dll itself, but may define // uninitialized data if (l_section.SizeOfRawData = 0) then begin l_size := f_old_headers.OptionalHeader.SectionAlignment; if l_size > 0 then begin l_dest := VirtualAlloc(Pointer(Cardinal(l_codebase) + l_section.VirtualAddress), l_size, MEM_COMMIT, PAGE_READWRITE); l_section.Misc.PhysicalAddress := cardinal(l_dest); ZeroMemory(l_dest, l_size); end; inc(longword(l_section), sizeof(TImageSectionHeader)); // Continue with the nex loop Continue; end; // commit memory block and copy data from dll l_dest := VirtualAlloc(Pointer(Cardinal(l_codebase) + l_section.VirtualAddress), l_section.SizeOfRawData, MEM_COMMIT, PAGE_READWRITE); CopyMemory(l_dest, Pointer(longword(f_data) + l_section.PointerToRawData), l_section.SizeOfRawData); l_section.Misc.PhysicalAddress := cardinal(l_dest); // IMAGE_SIZEOF_SECTION_HEADER inc(longword(l_section), sizeof(TImageSectionHeader)); end;end;procedure PerformBaseRelocation(f_module: PBTMemoryModule; f_delta: Cardinal); stdcall;var l_i: Cardinal; l_codebase: Pointer; l_directory: PImageDataDirectory; l_relocation: PImageBaseRelocation; l_dest: Pointer; l_relInfo: ^Word; l_patchAddrHL: ^DWord; l_type, l_offset: integer;begin l_codebase := f_module.codeBase; l_directory := GetHeaderDictionary(f_module, IMAGE_DIRECTORY_ENTRY_BASERELOC); if l_directory.Size > 0 then begin l_relocation := PImageBaseRelocation(Cardinal(l_codebase) + l_directory.VirtualAddress); while l_relocation.VirtualAddress > 0 do begin l_dest := Pointer((Cardinal(l_codebase) + l_relocation.VirtualAddress)); l_relInfo := Pointer(Cardinal(l_relocation) + IMAGE_SIZEOF_BASE_RELOCATION); for l_i := 0 to (trunc(((l_relocation.SizeOfBlock - IMAGE_SIZEOF_BASE_RELOCATION) / 2)) - 1) do begin // the upper 4 bits define the type of relocation l_type := (l_relInfo^ shr 12); // the lower 12 bits define the offset l_offset := l_relInfo^ and $FFF; //showmessage(inttostr(l_relInfo^)); if l_type = IMAGE_REL_BASED_HIGHLOW then begin // change complete 32 bit address l_patchAddrHL := Pointer(Cardinal(l_dest) + Cardinal(l_offset)); l_patchAddrHL^ := l_patchAddrHL^ + f_delta; end; inc(l_relInfo); end; l_relocation := Pointer(cardinal(l_relocation) + l_relocation.SizeOfBlock); end; end;end;function BuildImportTable(f_module: PBTMemoryModule): boolean; stdcall;var l_codeBase: Pointer; l_directory: PImageDataDirectory; l_importDesc: PImageImportDescriptor; l_thunkRef, l_funcRef: ^DWORD; l_handle: HMODULE; l_temp: integer; l_thunkData: TImageImportByName;begin Result := true; l_codeBase := f_module.codeBase; l_directory := GetHeaderDictionary(f_module, IMAGE_DIRECTORY_ENTRY_IMPORT); if (l_directory.Size > 0) then begin l_importDesc := PImageImportDescriptor(Cardinal(l_codeBase) + l_directory.VirtualAddress); while (not IsBadReadPtr(l_importDesc, sizeof(TImageImportDescriptor))) and (l_importDesc.Name <> 0) do begin l_handle := LoadLibrary(PChar(Cardinal(l_codeBase) + l_importDesc.Name)); if (l_handle = INVALID_HANDLE_VALUE) then begin lastErrStr := 'BuildImportTable: can''t load library: ' + PChar(Cardinal(l_codeBase) + l_importDesc.Name); Result := false; exit; end; // ReallocMemory crashes if "f_module.modules = nil" if f_module.modules = nil then f_module.modules := AllocMem(1); f_module.modules := ReallocMemory(f_module.modules, ((f_module.numModules + 1) * (sizeof(HMODULE)))); if f_module.modules = nil then begin lastErrStr := 'BuildImportTable: ReallocMemory failed'; result := false; exit; end; // module->modules[module->numModules++] = handle; l_temp := (sizeof(cardinal) * (f_module.numModules)); inc(Cardinal(f_module.modules), l_temp); cardinal(f_module.modules^) := l_handle; dec(Cardinal(f_module.modules), l_temp); f_module.numModules := f_module.numModules + 1; if l_importDesc.OriginalFirstThunk <> 0 then begin l_thunkRef := Pointer(Cardinal(l_codeBase) + l_importDesc.OriginalFirstThunk); l_funcRef := Pointer(Cardinal(l_codeBase) + l_importDesc.FirstThunk); end else begin // no hint table l_thunkRef := Pointer(Cardinal(l_codeBase) + l_importDesc.FirstThunk); l_funcRef := Pointer(Cardinal(l_codeBase) + l_importDesc.FirstThunk); end; while l_thunkRef^ <> 0 do begin if GetImageSnapByOrdinal(l_thunkRef^) then l_funcRef^ := Cardinal(GetProcAddress(l_handle, PChar(GetImageOrdinal(l_thunkRef^)))) else begin CopyMemory(@l_thunkData, Pointer(Cardinal(l_codeBase) + l_thunkRef^), sizeof(TImageImportByName)); l_funcRef^ := Cardinal(GetProcAddress(l_handle, PChar(@(l_thunkData.Name)))); end; if l_funcRef^ = 0 then begin lastErrStr := 'BuildImportTable: GetProcAddress failed'; result := false; break; end; inc(l_funcRef); inc(l_thunkRef); end; inc(longword(l_importDesc), sizeof(TImageImportDescriptor)); end; end;end;function GetSectionProtection(SC: cardinal): cardinal; stdcall;//SC – ImageSectionHeader.Characteristicsbegin result := 0; if (SC and IMAGE_SCN_MEM_NOT_CACHED) <> 0 then result := result or PAGE_NOCACHE; // E - Execute, R – Read , W – Write if (SC and IMAGE_SCN_MEM_EXECUTE) <> 0 //E ? then if (SC and IMAGE_SCN_MEM_READ) <> 0 //ER ? then if (SC and IMAGE_SCN_MEM_WRITE) <> 0 //ERW ? then result := result or PAGE_EXECUTE_READWRITE else result := result or PAGE_EXECUTE_READ else if (SC and IMAGE_SCN_MEM_WRITE) <> 0 //EW? then result := result or PAGE_EXECUTE_WRITECOPY else result := result or PAGE_EXECUTE else if (SC and IMAGE_SCN_MEM_READ) <> 0 // R? then if (SC and IMAGE_SCN_MEM_WRITE) <> 0 //RW? then result := result or PAGE_READWRITE else result := result or PAGE_READONLY else if (SC and IMAGE_SCN_MEM_WRITE) <> 0 //W? then result := result or PAGE_WRITECOPY else result := result or PAGE_NOACCESS;end;procedure FinalizeSections(f_module: PBTMemoryModule); stdcall;var l_i: integer; l_section: PImageSectionHeader; l_protect, l_oldProtect, l_size: Cardinal;begin l_section := GetImageFirstSection(f_module.headers); for l_i := 0 to f_module.headers.FileHeader.NumberOfSections - 1 do begin if (l_section.Characteristics and IMAGE_SCN_MEM_DISCARDABLE) <> 0 then begin // section is not needed any more and can safely be freed VirtualFree(Pointer(l_section.Misc.PhysicalAddress), l_section.SizeOfRawData, MEM_DECOMMIT); inc(longword(l_section), sizeof(TImageSectionHeader)); continue; end; l_protect := GetSectionProtection(l_section.Characteristics); if (l_section.Characteristics and IMAGE_SCN_MEM_NOT_CACHED) <> 0 then l_protect := (l_protect or PAGE_NOCACHE); // determine size of region l_size := l_section.SizeOfRawData; if l_size = 0 then begin if (l_section.Characteristics and IMAGE_SCN_CNT_INITIALIZED_DATA) <> 0 then begin l_size := f_module.headers.OptionalHeader.SizeOfInitializedData; end else begin if (l_section.Characteristics and IMAGE_SCN_CNT_UNINITIALIZED_DATA) <> 0 then l_size := f_module.headers.OptionalHeader.SizeOfUninitializedData; end; if l_size > 0 then begin if not VirtualProtect(Pointer(l_section.Misc.PhysicalAddress), l_section.SizeOfRawData, l_protect, @l_oldProtect) then begin lastErrStr := 'FinalizeSections: VirtualProtect failed'; exit; end; end; end; inc(longword(l_section), sizeof(TImageSectionHeader)); end;end;function BTMemoryLoadLibary(var f_data: Pointer; const f_size: int64): PBTMemoryModule; stdcall;var l_result: PBTMemoryModule; l_dos_header: TImageDosHeader; l_old_header: TImageNtHeaders; l_code, l_headers: Pointer; l_locationdelta: Cardinal; l_DllEntry: TDllEntryProc; l_successfull: boolean;begin l_result := nil; Result := nil; try CopyMemory(@l_dos_header, f_data, sizeof(_IMAGE_DOS_HEADER)); if (l_dos_header.e_magic <> IMAGE_DOS_SIGNATURE) then begin lastErrStr := 'BTMemoryLoadLibary: dll dos header is not valid'; exit; end; CopyMemory(@l_old_header, pointer(longint(f_data) + l_dos_header._lfanew), sizeof(_IMAGE_NT_HEADERS)); if l_old_header.Signature <> IMAGE_NT_SIGNATURE then begin lastErrStr := 'BTMemoryLoadLibary: IMAGE_NT_SIGNATURE is not valid'; exit; end; // reserve memory for image of library l_code := VirtualAlloc(Pointer(l_old_header.OptionalHeader.ImageBase), l_old_header.OptionalHeader.SizeOfImage, MEM_RESERVE, PAGE_READWRITE); if l_code = nil then // try to allocate memory at arbitrary position l_code := VirtualAlloc(nil, l_old_header.OptionalHeader.SizeOfImage, MEM_RESERVE, PAGE_READWRITE); if l_code = nil then begin lastErrStr := 'BTMemoryLoadLibary: VirtualAlloc failed'; exit; end; // alloc space for the result record l_result := PBTMemoryModule(HeapAlloc(GetProcessHeap(), 0, sizeof(TBTMemoryModule))); l_result.codeBase := l_code; l_result.numModules := 0; l_result.modules := nil; l_result.initialized := false; // xy: is it correct to commit the complete memory region at once? // calling DllEntry raises an exception if we don't... VirtualAlloc(l_code, l_old_header.OptionalHeader.SizeOfImage, MEM_COMMIT, PAGE_READWRITE); // commit memory for headers l_headers := VirtualAlloc(l_code, l_old_header.OptionalHeader.SizeOfHeaders, MEM_COMMIT, PAGE_READWRITE); // copy PE header to code CopyMemory(l_headers, f_data, (Cardinal(l_dos_header._lfanew) + l_old_header.OptionalHeader.SizeOfHeaders)); l_result.headers := PImageNtHeaders(longint(l_headers) + l_dos_header._lfanew); // update position l_result.headers.OptionalHeader.ImageBase := cardinal(l_code); // copy sections from DLL file block to new memory location CopySections(f_data, l_old_header, l_result); // adjust base address of imported data l_locationdelta := Cardinal(Cardinal(l_code) - l_old_header.OptionalHeader.ImageBase); if l_locationdelta <> 0 then PerformBaseRelocation(l_result, l_locationdelta); // load required dlls and adjust function table of imports if not BuildImportTable(l_result) then begin lastErrStr := lastErrStr + ' BTMemoryLoadLibary: BuildImportTable failed'; Abort; end; // mark memory pages depending on section headers and release // sections that are marked as "discardable" FinalizeSections(l_result); // get entry point of loaded library if (l_result.headers.OptionalHeader.AddressOfEntryPoint) <> 0 then begin @l_DllEntry := Pointer(Cardinal(l_code) + l_result.headers.OptionalHeader.AddressOfEntryPoint); if @l_DllEntry = nil then begin lastErrStr := 'BTMemoryLoadLibary: Get DLLEntyPoint failed'; Abort; end; l_successfull := l_DllEntry(Cardinal(l_code), DLL_PROCESS_ATTACH, nil); if not l_successfull then begin lastErrStr := 'BTMemoryLoadLibary: Can''t attach library'; Abort; end; l_result.initialized := true; end; except BTMemoryFreeLibrary(l_result); exit; end; Result := l_result;end;function BTMemoryGetProcAddress(var f_module: PBTMemoryModule; const f_name: PChar): Pointer; stdcall;var l_codeBase: Pointer; l_idx: integer; l_i: DWORD; l_nameRef: ^DWORD; l_ordinal: ^WORD; l_exports: PImageExportDirectory; l_directory: PImageDataDirectory; l_temp: ^DWORD;begin Result := nil; l_codeBase := f_module.codeBase; l_idx := -1; l_directory := GetHeaderDictionary(f_module, IMAGE_DIRECTORY_ENTRY_EXPORT); if l_directory.Size = 0 then begin lastErrStr := 'BTMemoryGetProcAddress: no export table found'; exit; end; l_exports := PImageExportDirectory(Cardinal(l_codeBase) + l_directory.VirtualAddress); if ((l_exports.NumberOfNames = 0) or (l_exports.NumberOfFunctions = 0)) then begin lastErrStr := 'BTMemoryGetProcAddress: DLL doesn''t export anything'; exit; end; // search function name in list of exported names l_nameRef := Pointer(Cardinal(l_codeBase) + Cardinal(l_exports.AddressOfNames)); l_ordinal := Pointer(Cardinal(l_codeBase) + Cardinal(l_exports.AddressOfNameOrdinals)); for l_i := 0 to l_exports.NumberOfNames - 1 do begin if StrComp(f_name, PChar(Cardinal(l_codeBase) + l_nameRef^)) = 0 then begin l_idx := l_ordinal^; break; end; inc(l_nameRef); inc(l_ordinal); end; if (l_idx = -1) then begin lastErrStr := 'BTMemoryGetProcAddress: exported symbol not found'; exit; end; if (Cardinal(l_idx) > l_exports.NumberOfFunctions - 1) then begin lastErrStr := 'BTMemoryGetProcAddress: name <-> ordinal number don''t match'; exit; end; // AddressOfFunctions contains the RVAs to the "real" functions l_temp := Pointer(Cardinal(l_codeBase) + Cardinal(l_exports.AddressOfFunctions) + Cardinal((l_idx * 4))); Result := Pointer(Cardinal(l_codeBase) + l_temp^);end;procedure BTMemoryFreeLibrary(var f_module: PBTMemoryModule); stdcall;var l_module: PBTMemoryModule; l_i: integer; l_temp: integer; l_DllEntry: TDllEntryProc;begin l_module := f_module; if l_module <> nil then begin if l_module.initialized then begin @l_DllEntry := Pointer(Cardinal(l_module.codeBase) + l_module.headers.OptionalHeader.AddressOfEntryPoint); l_DllEntry(Cardinal(l_module.codeBase), DLL_PROCESS_DETACH, nil); l_module.initialized := false; // free previously opened libraries for l_i := 0 to l_module.numModules - 1 do begin l_temp := (sizeof(cardinal) * (l_i)); inc(Cardinal(l_module.modules), l_temp); if Cardinal(f_module.modules^) <> INVALID_HANDLE_VALUE then FreeLibrary(Cardinal(f_module.modules^)); dec(Cardinal(l_module.modules), l_temp); end; FreeMemory(l_module.modules); if l_module.codeBase <> nil then // release memory of library VirtualFree(l_module.codeBase, 0, MEM_RELEASE); HeapFree(GetProcessHeap(), 0, f_module); Pointer(f_module) := nil; end; end;end;end.Only Delphi source code is included in the archive.