![]() |
Inject DLL from Memory
Hallo liebe Community,
ich suche ein Äquivalent zu der "StealthInject" Lib (C++) für Delphi. Sie bietet die Möglichkeit eine DLL (in einem Stream,Buffer,String) direkt aus dem Memory heraus in einen fremden Prozess zu injecten - ohne Umweg über die Festplatte. Alternativ würde mir auch eine Beschreibung oder ein Pseudocode, wie man so etwas selber macht, sehr helfen. Danke im Vorraus Megamorph |
Re: Inject DLL from Memory
In meiner uallCollection gibts da so eine funktion (jedenfalls ein InjectMe, und ich bin mir sicher, dass ich da auch mal so eine funktion zum injecten geschrieben habe. Wenn ich mich nicht irre kannst du LoadLibraryX oder so verwenden die lädt eine DLL in den Speicher, verwendet aber CreateFileA um die Dll zu laden und reserveirt selbst Speicher. Dieses kannst du dann ja weglassen)
Einfach googlen :) |
Re: Inject DLL from Memory
Hey,
danke für den Tipp. Die Funktion InjectMe entsprach nicht ganz meiner Vorstellung. Ich möchte schon eine DLL injecten und keine EXE. Jedoch habe ich einen Code in Anlehnung an die InjectLibrary geschrieben, welcher jedoch noch nicht ganz funktioniert. Es wäre nett, wenn ihr mal einen Blick darüber werft, danke. (-;
Delphi-Quellcode:
Anmerkung:
procedure TForm1.Timer1Timer(Sender: TObject);
var BytesWritten, Process, Thread, ThreadId: cardinal; load_lib_param, body: pointer; DLL: pchar; szDll: string; dllptr : pointer; PID: cardinal; begin if GetWindowThreadProcessID(FindWindow(nil,pchar('Unbenannt - Paint')),nil) = 0 then exit; GetWindowThreadProcessID(FindWindow(nil,pchar('Unbenannt - Paint')), PID); Timer1.Enabled:=false; tempstream.Seek(0, soFromBeginning); dllptr:=@tempstream; szdll:= ExtractFilePath(Application.ExeName) + 'test.dll'; DLL := pchar (szdll); Process := OpenProcess(PROCESS_ALL_ACCESS, False, pid); load_lib_param := xVirtualAllocEx(Process, nil, 4096, MEM_COMMIT, PAGE_READWRITE); body := xVirtualAllocEx(Process, nil, tempstream.Size, MEM_COMMIT, PAGE_READWRITE); WriteProcessMemory(Process, load_lib_param, Pointer(DLL), 4096, BytesWritten); WriteProcessMemory(Process, body, dllptr, tempstream.size, BytesWritten); Thread := CreateRemoteThread(Process, nil, 0, GetProcAddress(GetModuleHandle('KERNEL32.DLL'), 'LoadLibraryA'), load_lib_param, 0, ThreadId); tempstream.Free; if Thread <> 0 then Memo1.Lines.Add('Injected!') else Memo1.Lines.Add('Failed!'); WaitForSingleObject(Thread, 6000); CloseHandle(Thread); CloseHandle(Process); end; 1) tempstream enthält die DLL (mit SaveToFile getestet) 2) Die DLL befindet sich natürlich nicht in dem zusammengesetzten Pfad, aber man muss ja was übergeben ?! 3) kein Compiler-Error, kein Runtime-Error, die Ausgabe 'Injected!' kommt 4) Code in der DLL wird jedoch nicht ausgeführt Hat jemand eine Idee? Danke für Antworten (: Megamorph |
Re: Inject DLL from Memory
so gehts nicht, die dll muss schon dann auch von deinem programm geladen sein (da z.B. die Adressen angepasst werden müssen)
Schau dir mal die ReadLibrary Funktion aus der uallkernel an, die macht eigentlich alles was man braucht. (Sections anpassen, ImportTabelle füllen, Relocation Adressen ändern) |
Re: Inject DLL from Memory
Hallo brechi,
ich sehe, dass in ReadLibrary die DLL von der Datei in den Memory geladen wird (an dieser Stelle ist es mir auch möglich statt dessen meinen FileStream zu verwenden). Jedoch ist mir noch etwas unklar was der zweite Teil der Funktion macht bzw. was für eine Rolle die Funktion spielen soll, wenn ich die DLL in den fremden Prozess injecten möchte. :/ Kannst du mir da bitte noch einen kurzen Abriss geben? Danke, Megamorph. |
Re: Inject DLL from Memory
Zuerst musst du schauen wieviel speicher du im Zielprozess für die Dll Brauchst (ImageSize von der Dll auslesen, funktion irgendwo in uallKernel).
Dann holst du dir dort den Speicher (VirtualAllocEx). Dann musst du die Dll reinladen (ReadLibrary) und für die Adresse die du von VirtualAllocEx bekommen hast anpassen (ReloctaionSection etc. siehe ReadLibrary, eventl macht die das schon über einen Parameter). Die DLl schreibst du dann mittels WriteProcessMemory in den Fremdprozess und Startest sie mittels CreateRemoteThread. |
Re: Inject DLL from Memory
Ich überlege mittlerweile sogar, das ganze Tool in C++ zu schreiben, weil es dort schöne Lib gibt und man mit 10 Zeilen Code drin ist...
Delphi wäre mir trotzdem wegen meiner etwas besseren Kenntnisse lieber. Hier der Code in meinem Timer:
Delphi-Quellcode:
Hier die modifizierte ReadLibrary:
tempstream.Seek(0, soFromBeginning);
ImageSize:= tempstream.Size; body:= VirtualAllocEx(PID, nil, ImageSize, MEM_COMMIT, PAGE_READWRITE); dllptr:= Pointer(ReadLibrary2('',Cardinal(body))); WriteProcessMemory(PID, body, dllptr, ImageSize, BytesWritten); Thread := CreateRemoteThread(PID, nil, 0, GetProcAddress(GetModuleHandle('KERNEL32.DLL'), 'LoadLibraryA'), body, 0, ThreadId); if Thread <> 0 then Memo1.Lines.Add('Injected!') else Memo1.Lines.Add('Failed!'); (alle Überprüfungen innerhalb der Funktion sind erfolgreich)
Delphi-Quellcode:
Leider kann ich ihn nicht dazu bewegen, dass im Memofeld 'Injected!' erscheint...
function ReadLibrary2(pLibraryName: PChar; OrigBase: DWord): DWord; stdcall;
var DllMain : function (dwHandle, dwReason, dwReserved: DWord): DWord; stdcall; IDH : PImageDosHeader; INH : PImageNtHeaders; SEC : PImageSectionHeader; dwread : DWord; dwSecCount : DWord; dwFileSize : DWord; dwmemsize : DWord; i : Integer; iFileHandle: Integer; pFileMem : Pointer; pAll : Pointer; SysDirP : array [0..MAX_PATH-1] of Char; SysDir : String; begin Result := 0; (* iFileHandle := CreateFileA(pLibraryName,GENERIC_READ,FILE_SHARE_READ,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); if (iFileHandle <= 0) then begin GetSystemDirectory(SysDirP, MAX_PATH); SysDir := SysDirP; iFileHandle := CreateFileA(PChar(SysDir+'\'+pLibraryName),GENERIC_READ,FILE_SHARE_READ,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); if (iFileHandle <= 0) then iFileHandle := CreateFileA(PChar(SysDir+'\DRIVERS\'+pLibraryName),GENERIC_READ,FILE_SHARE_READ,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); if (iFileHandle <= 0) then Exit; end; *) //dwFileSize := GetFileSize(iFileHandle,nil); dwFileSize := tempstream.Size; pFileMem := VirtualAlloc(nil,dwFileSize,MEM_COMMIT or MEM_RESERVE,PAGE_EXECUTE_READWRITE); if (pFileMem = nil) then begin // CloseHandle(iFileHandle); Exit; end; //ReadFile(iFileHandle,pFileMem^,dwFileSize,dwRead,nil); tempstream.Seek(0, soFromBeginning); getmem ( pFileMem,tempstream.Size); tempstream.Read(pFileMem^,tempstream.Size-1); IDH := pFileMem; if (isBadReadPtr(IDH,SizeOf(TImageDosHeader))) or (IDH^.e_magic <> IMAGE_DOS_SIGNATURE) then begin VirtualFree(pFileMem,dwFileSize,MEM_DECOMMIT); //CloseHandle(iFileHandle); Exit; end; INH := pointer(cardinal(pFileMem)+cardinal(IDH^._lfanew)); if (isBadReadPtr(INH, SizeOf(TImageNtHeaders))) or (INH^.Signature <> IMAGE_NT_SIGNATURE) then begin VirtualFree(pFileMem,dwFileSize,MEM_DECOMMIT); //CloseHandle(iFileHandle); Exit; end; SEC := Pointer(Integer(INH)+SizeOf(TImageNtHeaders)); dwMemSize := INH^.OptionalHeader.SizeOfImage; if (dwMemSize = 0) then begin VirtualFree(pFileMem,dwFileSize,MEM_DECOMMIT); //CloseHandle(iFileHandle); Exit; end; pAll := VirtualAlloc(nil,dwMemSize,MEM_COMMIT or MEM_RESERVE,PAGE_EXECUTE_READWRITE); if (pAll = nil) then begin VirtualFree(pFileMem,dwFileSize,MEM_DECOMMIT); //CloseHandle(iFileHandle); Exit; end; dwSecCount := INH^.FileHeader.NumberOfSections; CopyMemory(pAll,IDH,DWord(SEC)-DWord(IDH)+dwSecCount*SizeOf(TImageSectionHeader)); for i := 0 to dwSecCount-1 do begin CopyMemory(Pointer(DWord(pAll)+SEC^.VirtualAddress), Pointer(DWord(pFileMem)+DWord(SEC^.PointerToRawData)), SEC^.SizeOfRawData); SEC := Pointer(Integer(SEC)+SizeOf(TImageSectionHeader)); end; if (INH^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress <> 0) then ChangeReloc(Pointer(INH^.OptionalHeader.ImageBase), pAll, Pointer(DWord(pAll)+INH^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress), Pointer(OrigBase), INH^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size); CreateImportTable(pAll, Pointer(DWord(pAll)+INH^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)); @DllMain := Pointer(INH^.OptionalHeader.AddressOfEntryPoint+DWord(pAll)); Result := DWord(pAll); //VirtualFree(pFileMem,dwFileSize,MEM_DECOMMIT); //CloseHandle(iFileHandle); Form1.Memo1.Lines.Add('bam'); end; Hat vlt. noch jemand einen Tip? Thx, Megamorph |
Re: Inject DLL from Memory
die Idee ist soweit richtig,
allersings ist imageSize <> stream.size die Imagebase steht im PE-header der dll! CreateRemoteThread muss beim EntryPoints anfangen nicht bei der dllbase (steht ebenfalls im PE header). zu beidem sollte es von mir funktionen geben um es auszulesen z.B. gibt @DllMain := Pointer(INH^.OptionalHeader.AddressOfEntryPoint+DW ord(pAll)); den Entry Point an statt AddressOfEntryPoint sollte es ein ImageSize geben, welches du brauchst um die größe zu bestimmen Scheib dafür am besten ReadLibrary um und übergib der Funktion das Prozesshandle das sollte dann hinhauen wenn du nach INH := pointer(cardinal(pFileMem)+cardinal(IDH^._lfanew)) ; mitels INH^. Size und Entry bestimmt und dann erst den Speicher aus dem Prozess holst (Size!) und bei @dllmain dann den Thread (umgerechnet auf den Zielprozess startest) Eventl!! (aber nur eventl) kann ich wenn ich zeit habe das heute abend mal umschreiben |
Re: Inject DLL from Memory
Vorläufige Version (in der Mittagspause gemacht, funktioniert aber noch nicht richtig, denke wegen den 3 Parametern bei DllMain)
Delphi-Quellcode:
jep liegt an dem RemoteThread, dies funcktioniert:
function LoadLibraryEx(const fsLibrary: TStream; dwProcessID: DWord): Boolean; stdcall;
type TRelocBlock = packed record dwAddress: DWord; dwSize: DWord; end; PRelocBlock = ^TRelocBlock; TImportBlock = packed record dwCharacteristics: DWord; dwTimeDateStamp: DWord; dwForwarderChain: DWord; dwName: DWord; pFirstThunk: Pointer; end; PImportBlock = ^TImportBlock; TImportNameBlock = packed record wHint: Word; pName: PChar; end; PImportNameBlock = ^TImportNameBlock; procedure ChangeReloc(POrigBase, PBaseTemp, PReloc, PBaseTarget: Pointer; dwRelocSize: DWord); stdcall; var pCurrentRelocBlock: PRelocBlock; RelocCount: DWord; PCurrentStart: PWord; i: Integer; pRelocAddress: PInteger; iDif: Integer; begin pCurrentRelocBlock := PReloc; iDif := Integer(PBaseTarget) - Integer(POrigBase); PCurrentStart := Pointer(Integer(PReloc) + 8); while (not isBadReadPtr(pCurrentRelocBlock, SizeOf(TRelocBlock))) and (not isBadReadPtr(pCurrentStart, SizeOf(Pointer))) and (DWord(pCurrentRelocBlock) < DWord(pReloc) + dwRelocSize) do begin RelocCount := (pCurrentRelocBlock^.dwSize - 8) div SizeOf(Word); for i := 0 to RelocCount - 1 do begin if (not isBadReadPtr(pCurrentStart, SizeOf(Pointer))) and (PCurrentStart^ xor $3000 < $1000) then begin pRelocAddress := Pointer(pCurrentRelocBlock^.dwAddress + PCurrentStart^ mod $3000 + DWord(PBaseTemp)); if (not isBadWritePtr(pRelocAddress, SizeOf(Integer))) then pRelocAddress^ := pRelocAddress^ + iDif; end; PCurrentStart := Pointer(DWord(PCurrentStart) + SizeOf(Word)); end; pCurrentRelocBlock := Pointer(PCurrentStart); pCurrentStart := Pointer(DWord(PCurrentStart) + 8); end; end; procedure CreateImportTable(pLibraryHandle, pImportTable: pointer); stdcall; var pIBlock: PImportBlock; pThunksRead: PDWord; pThunksWrite: PDWord; pDllName: PChar; dwLibraryHandle: DWord; dwOldProtect: DWord; begin pIBlock := pImportTable; while (not isBadReadPtr(pIBlock, SizeOf(TImportBlock))) and (pIBlock^.pFirstThunk <> nil) and (pIBlock^.dwName <> 0) do begin pDllName := Pointer(DWord(pLibraryHandle) + DWord(pIBlock^.dwName)); if (not isBadReadPtr(pDllName, 4)) then begin dwLibraryHandle := LoadLibrary(pDllName); pThunksRead := Pointer(DWord(pIBlock^.pFirstThunk) + DWord(pLibraryHandle)); pThunksWrite := pThunksRead; if (DWord(pIBlock^.dwTimeDateStamp) = $FFFFFFFF) then pThunksRead := Pointer(DWord(pIBlock^.dwCharacteristics) + DWord(pLibraryHandle)); while (not isBadReadPtr(pThunksRead, SizeOf(DWord))) and (not isBadReadPtr(pThunksWrite, SizeOf(Word))) and (pThunksRead^ <> 0) do begin if VirtualProtect(pThunksWrite, SizeOf(DWord), PAGE_EXECUTE_READWRITE, dwOldProtect) then begin if (DWord(pThunksRead^) and $80000000 <> 0) then pThunksWrite^ := DWord(GetProcAddress(dwLibraryHandle, PChar(pThunksRead^ and $FFFF))) else pThunksWrite^ := DWord(GetProcAddress(dwLibraryHandle, PChar(DWord(pLibraryHandle) + pThunksRead^ + SizeOf(Word)))); VirtualProtect(pThunksWrite, SizeOf(DWord), dwOldProtect, dwOldProtect); end; Inc(pThunksRead); Inc(pThunksWrite); end; end; pIBlock := Pointer(DWord(pIBlock) + SizeOf(TImportBlock)); end; end; var DllMain: function(dwHandle, dwReason, dwReserved: DWord): DWord; stdcall; IDH: PImageDosHeader; INH: PImageNtHeaders; SEC: PImageSectionHeader; dwSecCount: DWord; dwmemsize: DWord; i: Integer; pFileMem: Pointer; pMemLocal: Pointer; pMemProcess: Pointer; hProcessHandle: THandle; dwWritten: DWord; hThread: THandle; dwThreadID: DWord; begin Result := False; // ProcessHandle holen um Speicher für DLL zu allozieren und RemoteThread zu starten hProcessHandle := OpenProcess(PROCESS_ALL_ACCESS, false, dwProcessID); if hProcessHandle <> 0 then begin // für den Stream speicher holen um leichter auf die Daten zuzugreifen pFileMem := VirtualAlloc(nil, fsLibrary.Size, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (pFileMem <> nil) then begin fsLibrary.Position := 0; fsLibrary.Read(pFileMem^, fsLibrary.Size); IDH := pFileMem; // ImageDosHeader gültig? if (not isBadReadPtr(IDH, SizeOf(TImageDosHeader))) and (IDH^.e_magic = IMAGE_DOS_SIGNATURE) then begin // ImageNtHeader gültig? INH := pointer(cardinal(pFileMem) + cardinal(IDH^._lfanew)); if (not isBadReadPtr(INH, SizeOf(TImageNtHeaders))) and (INH^.Signature = IMAGE_NT_SIGNATURE) then begin SEC := Pointer(Integer(INH) + SizeOf(TImageNtHeaders)); // Virtuelle größe der Dll/Exe ermitteln dwMemSize := INH^.OptionalHeader.SizeOfImage; if (dwMemSize <> 0) then begin // Lokalen speicher für die DLL holen (wir bereiten die in userem Prozess vor) pMemLocal := VirtualAlloc(nil, dwMemSize, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (pMemLocal <> nil) then begin // Speicher aus dem Fremdprozess holen (indem wir die dll nachher kopieren und ausführen) pMemProcess := VirtualAllocEx(hProcessHandle, nil, dwMemSize, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE); if pMemProcess <> nil then begin // jede Sektion and die richtige Adresse kopieren dwSecCount := INH^.FileHeader.NumberOfSections; CopyMemory(pMemLocal, IDH, DWord(SEC) - DWord(IDH) + dwSecCount * SizeOf(TImageSectionHeader)); for i := 0 to dwSecCount - 1 do begin CopyMemory(Pointer(DWord(pMemLocal) + SEC^.VirtualAddress), Pointer(DWord(pFileMem) + DWord(SEC^.PointerToRawData)), SEC^.SizeOfRawData); SEC := Pointer(Integer(SEC) + SizeOf(TImageSectionHeader)); end; // Adressen der Dll für den Zielprozess anpassen if (INH^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress <> 0) then begin ChangeReloc(Pointer(INH^.OptionalHeader.ImageBase), pMemLocal, Pointer(DWord(pMemLocal) + INH^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress), Pointer(pMemProcess), INH^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size); end; // die Importtabelle anpassen, die Adressen holen wir lokal aus unserem Prozess // sollte die Dll nicht im Zielprozess geladen sein -> crash // theoretisch kann man diese auch aus dem Zielprozess ermitteln // und fehlende Dlls dort ebenfalls nachladen // aber jetzt nicht hier behandelt, da dll die in einen Fremdprozess injeziert werden // IMMER nur ntdll/kernel32/(user32 falls Prozess mit Fenster) Funktionen benutzen sollen CreateImportTable(pMemLocal, Pointer(DWord(pMemLocal) + INH^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)); // bei DLL-Main einen Thread starten @DllMain := Pointer(INH^.OptionalHeader.AddressOfEntryPoint + DWord(pMemProcess)); if WriteProcessMemory(hProcessHandle, pMemProcess, pMemLocal, dwMemSize, dwWritten) and (dwWritten = dwMemSize) then begin hThread := CreateRemoteThread(hProcessHandle, nil, 0, @DllMain, nil, 0, dwThreadID); if hThread <> 0 then begin Result := True; CloseHandle(hThread); end; end else begin VirtualFreeEx(hProcessHandle, pMemProcess, dwMemSize, MEM_DECOMMIT); end; end; end; VirtualFree(pMemLocal, dwMemSize, MEM_DECOMMIT); end; end; VirtualFree(pFileMem, fsLibrary.Size, MEM_DECOMMIT); end; end; CloseHandle(hProcessHandle); end; end; procedure TForm12.FormCreate(Sender: TObject); var fm: TFileStream; begin fm := TFileStream.Create(ExtractFilePath(Paramstr(0))+'test.dll', fmOpenRead); LoadLibraryEx(fm, GetCurrentProcessID); fm.Free; end; muss man noch bisl Code injezieren um DllMain richtig aufzurufen vill schaffst das selber, ansonsten meld ich mich vill heute abend
Delphi-Quellcode:
//hThread := CreateRemoteThread(hProcessHandle, nil, 0, @DllMain, nil, 0, dwThreadID);
DllMain(0, DLL_PROCESS_ATTACH, 0); |
Re: Inject DLL from Memory
Hallo brechi,
ich danke dir zuerst vielmals für deine Hilfe! (-: Ich mache mich gleich ans Testen, jedoch muss ich gleich nochmal von 17:30-20:00 Uhr weg und werde dann spätestens 22:00Uhr meine Ergenbnisse in den Post editieren. edit: bisher noch nichts - ich mache morgen weiter edit: Ich denke auch, dass es an den 3 Parametern der DLLMain liegt. Wie wäre es eine eigene Funktion zu schreiben, die Adresse dieser (zb. mit OllyDBG) rauszufinden und dann die zu starten? Bis dahin, Megamorph |
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:52 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