![]() |
DLL aus RES in Speicher laden und direkt verwenden.
Hallo DP,
in diesem ![]() Es geht darum eine DLL direkt aus einer RES in den Speicher zu laden und dort zu verwenden. Der Umweg über das Filesystem würde also entfallen. ![]() Es funktioniert fast. :-D Mit der libmysql.dll mit der ich es getestet habe, schafft er die ersten paar Funktionen aber dann scheppert's.
Code:
Ich habe folgenden Code aus obiger Quelle verwendet, der ja angeblich D2010-tauglich sein soll.
---------------------------
Zugriffsverletzung bei Adresse 776D8C19 in Modul 'ntdll.dll'. Schreiben von Adresse 00000014. ---------------------------
Delphi-Quellcode:
Zum Debugging: Die AV kommt bei mir bei mysql_real_connect, es wurden also schon einige Funktionen erfolgreich durchlaufen (mysql_get_client_version, mysql_init, mysql_ssl_set). mysql_real_connect wird aber von BTMemoryGetProcAddress auch noch gefunden. Erst beim Aufruf von mysql_real_connect passiert's.
function BTMemoryLoadLibary(fp_data: Pointer;
const f_size: int64): PBTMemoryModule; var lp_result: PBTMemoryModule; l_dos_header: TImageDosHeader; l_old_header: TImageNtHeaders; l_code, l_headers: Pointer; l_locationdelta: Cardinal; lp_DllEntry: PDllEntryProc; l_successfull: boolean; begin lp_result := nil; Result := nil; try CopyMemory(@l_dos_header, fp_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, IncF(fp_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 lp_result := PBTMemoryModule(HeapAlloc(GetProcessHeap(), 0, SizeOf(TBTMemoryModule))); lp_result^.codeBase := l_code; lp_result^.numModules := 0; lp_result^.modules := nil; lp_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, fp_data, (UInt64(l_dos_header._lfanew) + l_old_header.OptionalHeader.SizeOfHeaders)); lp_result^.headers := PImageNtHeaders (UInt64(l_headers) + l_dos_header._lfanew); // update position lp_result^.headers^.OptionalHeader.ImageBase := UInt64(l_code); // copy sections from DLL file block to new memory location CopySections(fp_data, l_old_header, lp_result); // adjust base address of imported data l_locationdelta := Cardinal (UInt64(l_code) - l_old_header.OptionalHeader.ImageBase); if l_locationdelta <> 0 then PerformBaseRelocation(lp_result, l_locationdelta); // load required dlls and adjust function table of imports if not BuildImportTable(lp_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(lp_result); // get entry point of loaded library if (lp_result^.headers^.OptionalHeader.AddressOfEntryPoint) <> 0 then begin lp_DllEntry := Pointer (UInt64(l_code) + lp_result^.headers^.OptionalHeader.AddressOfEntryPoint); if lp_DllEntry = nil then begin lastErrStr := 'BTMemoryLoadLibary: Get DLLEntyPoint failed'; Abort; end; l_successfull := TDllEntryProc(lp_DllEntry)(UInt64(l_code), DLL_PROCESS_ATTACH, nil); if not l_successfull then begin lastErrStr := 'BTMemoryLoadLibary: Can''t attach library'; Abort; end; lp_result^.initialized := true; end; except BTMemoryFreeLibrary(lp_result); exit; end; Result := lp_result; end; function BTMemoryGetProcAddress(fp_module: PBTMemoryModule; const fp_name: PChar): Pointer; var l_idx: Integer; l_i: DWORD; l_nameRef: PDWORD; l_ordinal: PWord; l_exports: PImageExportDirectory; l_directory: PImageDataDirectory; begin Result := nil; l_idx := -1; l_directory := GetHeaderDictionary(fp_module, IMAGE_DIRECTORY_ENTRY_EXPORT); if l_directory^.Size = 0 then begin lastErrStr := 'BTMemoryGetProcAddress: no export table found'; exit; end; l_exports := IncF(fp_module^.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 := IncF(fp_module^.codeBase, l_exports^.AddressOfNames); l_ordinal := IncF(fp_module^.codeBase, l_exports^.ADDressOfNameOrdinals); for l_i := 0 to l_exports^.NumberOfNames - 1 do begin if StrComp(fp_name, PAnsiCharToPChar(IncF(fp_module^.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 (UInt64(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 Result := IncF(fp_module^.codeBase, PUInt64(IncF(fp_module^.codeBase, IncF(l_exports^.AddressOfFunctions, l_idx * 4)))^); end; Hat jemand eine funktionierende Variante oder sieht einen offensichtlichen Fehler im Code? Grüße, Uwe P.S.: Hat sich erledigt. Jetzt funktioniert es. ;) |
AW: DLL aus RES in Speicher laden und direkt verwenden.
Wo lag der Fehler? Habe selbst mal versucht so eine funktion zu implementieren. Funktioniert auch wunderbar nur bei der ntdll.dll gibts ab und an auch mal ne Exception. Was mir aufgefallen ist, ist dass in deinem Code die Relocations gar nicht geparst werden.
|
AW: DLL aus RES in Speicher laden und direkt verwenden.
Hallo Zacherl,
es lag daran, dass ich nicht abgefangen hatte, dass BTMemoryLoadLibary mehrfach aufgerufen werden konnte. Wenn die DLL nur einmal im Speicher ist, funktioniert es bisher einwandfrei. :D Zitat:
Für D2010 habe ich nur einen Cast ändern müssen. Ansonsten habe ich nur noch auf die aktuellste Version umgestellt. Die gibt es ![]() Grüße, Uwe [EDIT]Habe mal die verwendete Version ins erste Posting gestellt...[/EDIT] |
AW: DLL aus RES in Speicher laden und direkt verwenden.
Kann mir jemand sagen, wie man die "Offene Frage"-Markierung weg bekommt?
Danke, schonmal. ;) |
AW: DLL aus RES in Speicher laden und direkt verwenden.
Schau mal nach, ob sich nicht da oben in den Themen-Optionen was versteckt,
ansonsten in den erweiterten Beitragseditor (oder 'nen neuen Beitrag/Post erstellen) und dann da unten das Häckchen wegmachen. |
AW: DLL aus RES in Speicher laden und direkt verwenden.
Hmm, jetzt steht oben, dass es eine offene Frage von Dir ist. :lol:
Mal sehen, was jetzt passiert... :roll: [EDIT]Ahh, hat geklappert...danke![/EDIT] |
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:53 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz