Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi DLL-Injection mit Freelibrary (https://www.delphipraxis.net/104122-dll-injection-mit-freelibrary.html)

Wotan89 27. Nov 2007 19:23


DLL-Injection mit Freelibrary
 
Ich möchte, dass nach dem Ausführen meines Quelltextes der DLL, sie wieder "entladen wird". Aber dies klappt nicht. Mein Quelltext des Programmes:
Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Button1: TButton;
    Label1: TLabel;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

function InjectIntoProcess(lpProcessID: Cardinal; lpDllname: String):Boolean;
var
  hProc: Cardinal;
  t:file of cardinal;
  func:pointer;
  hRemThread:cardinal;
  addr:pointer;
  cWPM: Cardinal;
  hdll:cardinal;
begin
  result := false;
  SetLastError(ERROR_SUCCESS);
  hProc := OpenProcess(PROCESS_ALL_ACCESS, false, lpProcessID);
  addr:=VirtualAllocEx(hProc, 0, length(lpDllname), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  WriteProcessMemory(hProc, addr, PChar(lpDllName), length(lpDllName), cWPM);
  CreateRemoteThread(hProc, nil, 0,GetProcaddress(getmodulehandle('kernel32.dll'),'LoadLibraryA') , addr, 0, hRemThread);
  if GetLastError = ERROR_SUCCESS then
   result := true;
   sleep(1000);
   assignfile(t,'e:\windows\HALLO.txt');  //{in der Datei HALLO.txt speichert meine DLL das Handle der DLL (hmod)}
   reset(t);
   read(t,hdll);
   closefile(t);

   addr:=Virtualallocex(hproc,0,sizeof(hdll),MEM_COMMIT,PAGE_EXECUTE_READWRITE);
   writeprocessmemory(hproc,addr,pointer(hdll),sizeof(hdll),cWPM);
   createremotethread(hproc,nil,0,getprocaddress(getmodulehandle('kernel32.dll'),'FreeLibrary'),addr,0,hremthread);
  CloseHandle(hProc);
end;

procedure TForm1.Button1Click(Sender: TObject);
var pid,h:cardinal;

begin
h:=findwindow(nil,pchar(edit1.Text));
getwindowthreadprocessid(h,@pid);
label1.Caption:=booltostr(InjectIntoProcess(pid,'E:\Dokumente und Einstellungen\Stefan_Admin\Eigene Dateien\Programmierung\code-injection\project1.dll'),true);
end;

end.
und hier meine DLL:
Delphi-Quellcode:
library Project1;

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, mmsystem;


{$R *.res}

procedure Timecallback(TimerId,Msg:Cardinal;dwuser,dw1,dw2:longword); pascal;
var t:file of cardinal; g:cardinal;
begin
g:=integer(getmodulehandle('project1.dll'));
assignfile(t,'e:\windows\HALLO.txt');
rewrite(t);
write(t,g);
closefile(t);
end;

procedure timeevent; stdcall;
begin
TimeSetEvent(1,0,@Timecallback,0,TIME_ONESHOT);
end;


begin
showmessage('hallo');
timeevent;
end.
Ich hoffe ihr könnt mir helfen oder etwas optimieren...

R4id 27. Nov 2007 20:06

Re: DLL-Injection mit Freelibrary
 
Ich kenn mich zwar nicht so aus, aber ich glaube du musst die Proceduren in Export einsetzten.

Zacherl 27. Nov 2007 20:21

Re: DLL-Injection mit Freelibrary
 
Naja erstmal ist der Code unsauber, weil du nicht sicher sein kannst, dass das Handle auch wirklich schon geschrieben wurde. Da nützt auch das Sleep(1000) nichts.

Delphi-Quellcode:
addr:=Virtualallocex(hproc,0,sizeof(hdll),MEM_COMMIT,PAGE_EXECUTE_READWRITE);
   writeprocessmemory(hproc,addr,pointer(hdll),sizeof(hdll),cWPM);
   createremotethread(hproc,nil,0,getprocaddress(getmodulehandle('kernel32.dll'),'FreeLibrary'),addr,0,hremthread);
  CloseHandle(hProc);
Willst du einen Zeiger auf die Speicherstelle von HDLL oder einen Zeiger auf den Speicherinhalt? Denke ja mal eher an den Inhalt, von daher mal statt Pointer(HDLL), @HDLL versuchen.

sirius 27. Nov 2007 20:23

Re: DLL-Injection mit Freelibrary
 
Bist du dir sicher, dass in der Datei überhaupt etwas steht? Warum benutzt du einen Timer dafür (und wahrscheinlich sind dessen Argumente falsch; TIME_CALLBACK_FUNCTION muss noch in den letzten Parameter)?
Und warum nimmst du zum übertragen keine Messages?

Wotan89 27. Nov 2007 20:39

Re: DLL-Injection mit Freelibrary
 
Die Timerfunktion funktioniert, denn in meine Datei wird auch der Inhalt hineingeschrieben. Ich habe ersteinmal die Timerfunktion genommen, da die DLL beim Laden kein Handle mit Getmodulehandle "ausgespuckt" hat. Ich wusste nicht, wie ich es mit einer Messagefunktion machen sollte, deswegen habe ich übergangsweise alles einfach in eine Datei geschrieben. Ich habe statt Pointer(HDLL) @HDLL genommen. Funktioniert zwar dann noch immer nicht, aber ich denke meine Variante war trotzdem falsch :-D .

Zacherl 27. Nov 2007 21:08

Re: DLL-Injection mit Freelibrary
 
Finde das hier sieht nett aus. Ist zwar auf Spanisch oder sowas, aber den Code kann man gut verstehen:
http://pasotech.altervista.org/delphi/articolo62.htm

Wotan89 28. Nov 2007 14:41

Re: DLL-Injection mit Freelibrary
 
Danke für den Link, der hat mir wirklich weitergeholfen :-D .Ich habe jetzt Teile des spanischen Quelltextes übernommen.

Hier mein Quelltext:
Delphi-Quellcode:
 unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, TLHelp32;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Button1: TButton;
    Label1: TLabel;
    Button2: TButton;
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure Button2Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }

   function BaseAddrDllProcess(PID: Cardinal; DLLName: string): Cardinal;

  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;
     hProc: Cardinal;
     hthread:cardinal;
  TID:cardinal;
  addr:pointer;
  cWPM: Cardinal;
  hdll:cardinal;  processid:cardinal;
implementation

{$R *.dfm}



function InjectIntoProcess(lpProcessID: Cardinal; lpDllname: PChar):Boolean;
begin
  result := false;
  SetLastError(ERROR_SUCCESS);
  processid:=lpProcessID;
 hProc := OpenProcess(PROCESS_ALL_ACCESS, false, lpProcessID); //{prozesshandle besorgen}
   //{freien Speicher im Prozess reservieren und dem Zeiger auf den Speicherblock} 
   //{den DLL-Namen in den Prozess schreiben}
  addr:=VirtualAllocEx(hProc, nil, length(lpDllname), MEM_COMMIT, PAGE_READWRITE);
  WriteProcessMemory(hProc, addr, Pointer(lpDllName), length(lpDllName),cWPM);

   hthread:=CreateRemoteThread(hproc, nil, 0,GetProcaddress(getmodulehandle('kernel32.dll'),'LoadLibraryA') , addr, 0, TID);
  WaitforSingleObject(hThread,INFINITE);
   Virtualfreeex(hproc,addr,0,MEM_Release);
 
  if GetLastError = ERROR_SUCCESS then
   result := true;
end;



procedure TForm1.Button1Click(Sender: TObject);
var pid,h:cardinal;

begin
h:=findwindow(nil,pchar(edit1.Text));
getwindowthreadprocessid(h,@pid);
label1.Caption:=booltostr(Injectintoprocess(pid,'E:\Dokumente und Einstellungen\Stefan_Admin\Eigene Dateien\Programmierung\code-injection\project1.dll'));
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
hdll:=BaseAddrDllProcess(ProcessID,'project1.dll');
 if hdll=0 then
 begin
 showmessage('keine entsprechende DLL gefunden');
 exit;
 end;
   addr:=Virtualallocex(hproc,0,sizeof(hdll),MEM_COMMIT,PAGE_READWRITE);
   writeprocessmemory(hproc,addr,pointer(hdll),sizeof(hdll),cWPM);
   hthread:=createremotethread(hproc,nil,0,getprocaddress(getmodulehandle('kernel32.dll'),'FreeLibrary'),addr,0,TID);
   WaitforSingleObject(hthread,INFINITE);
   VirtualFreeex(hproc,addr,0,MEM_Release);

end;


function TForm1.BaseAddrDllProcess(PID: Cardinal; DLLName: string): Cardinal;
var
  me: TModuleEntry32;
  hSnap: THandle;
begin
  Result := 0;
  hSnap := CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid);
  me.dwSize := sizeof(TModuleEntry32);
  Module32First(hSnap, me);
  repeat
    if LowerCase(me.szModule) = LowerCase(DLLName) then
      begin
        result := Cardinal(me.modBaseAddr);
        break;
      end;
  until (not (Module32Next(hSnap, me)));
  CloseHandle(hSnap);
end;

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
closehandle(hproc);
end;

end.
meine DLL wird aber nicht entladen. Zumindest kann ich sie nicht löschen und ich kann keine erneute Injection mehr machen. Den Quelltext meiner DLL habe ich auf eine Showmessage-Function beschränkt um zu sehen, ob die Injection klappt.

Zacherl 28. Nov 2007 15:38

Re: DLL-Injection mit Freelibrary
 
Was ist hiermit?

Delphi-Quellcode:
function UnloadDll(PID: dword; DLL: string; synch: Boolean; var success: Boolean): Boolean;
var
  BytesWritten, hProcess, hThread, TID: Cardinal;
  Parameters: pointer;
  BaseAddr: Cardinal;
  pThreadStartRoutine: Pointer;
  lpExitCode: Cardinal;
begin

  Result := False;
  if PID = 0 then
    Exit;
  BaseAddr := BaseAddrDllProcesso(PID, DLL);
  if BaseAddr = 0 then
    Exit;
  hProcess := 0;
  hThread := 0;
  pThreadStartRoutine := nil;

  try
    hProcess := OpenProcess(PROCESS_CREATE_THREAD +
                            PROCESS_QUERY_INFORMATION +
                            PROCESS_VM_OPERATION +
                            PROCESS_VM_WRITE +
                            PROCESS_VM_READ,
                            False,
                            PID
                            );
    if hProcess = 0 then
      begin
        ErrStr('OpenProcess');
        Exit;
      end;

    pThreadStartRoutine := GetProcAddress(GetModuleHandle('KERNEL32.DLL'), 'FreeLibrary');
    if pThreadStartRoutine = nil then
      begin
        ErrStr('GetProcAddress');
        Exit;
      end;

    hThread := CreateRemoteThread(hProcess,
                                  nil,
                                  0,
                                  pThreadStartRoutine,
                                  Pointer(BaseAddr),
                                  0,
                                  TID);

    if hThread = 0 then
      begin
        ErrStr('CreateRemoteThread');
        Exit;
      end;

    //mi metto in attesa della terminazione del thread
    if synch then
      begin
        case WaitForSingleObject(hThread, INFINITE) of
          WAIT_FAILED:
            begin
              ErrStr('WaitForSingleObject');
              Exit;
            end;
        end;
        if not GetExitCodeThread(hThread, lpExitCode) then
          begin
            ErrStr('GetExitCodeThread');
            Exit;
          end;
        success := (lpExitCode > 0);
      end;

    Result := True;

  finally

    if hThread <> 0 then
      begin
        if not CloseHandle(hThread) then
          begin
            ErrStr('CloseHandle');
          end;
      end;

    if hProcess <> 0 then
      begin
        if not CloseHandle(hProcess) then
          begin
            ErrStr('CloseHandle');
          end;
      end;

  end;

end;

Wotan89 28. Nov 2007 15:44

Re: DLL-Injection mit Freelibrary
 
Wenn du dir meine Button2-Procedure anguckst wirst du feststellen, dass meins das selbe ist, nur ohne auffwendige Fehlerbehandlung. Der Fehler kommt bei mir doch schon bei der Injection... Da bin ich genauso weit wie vorher... :coder2:

Zacherl 28. Nov 2007 15:50

Re: DLL-Injection mit Freelibrary
 
Deshalb sollst du doch mal die Funktionen MIT Fehlerbehandlung 1 zu 1 übernehmen. Dann könntest du auch posten WELCHER Fehler WO genau auftritt. Anders ist es schwer zu helfen. Diese AccessViolation ist ziemlich allgemein und ich kann damit wenig anfangen.

R4id 28. Nov 2007 16:12

Re: DLL-Injection mit Freelibrary
 
Mit der uallCollection kannst du die DLL auch injektieren.

Wotan89 28. Nov 2007 16:58

Re: DLL-Injection mit Freelibrary
 
Ich hab das Problem selbst gelöst und zwar hatte ich statt dem Threadhandle die Threadid genommen, naja Dummheit... :P Allerdings kann ich die DLL, welche injiziert wurde, trotzdewm nicht löschen. Und das geht auch bei dem spanischen Quelltext nicht. Erst wenn ich die Anwenung, in welche die DLL injiziert wurde, beende, kann ich sie wieder löschen... Ich vermute, dass Freelibrary nicht richtig ausgeführt wird, da bei meiner Button2-Procedure immer wieder die DLL gefunden wird, ein Thread wird jedoch "erstellt".

Wotan89 28. Nov 2007 19:34

Re: DLL-Injection mit Freelibrary
 
Hab noch nen kleinen Fehler bei mir entdeckt: Man darf die Adresse nicht mit WriteProcessMemory usw. in den Prozess reinschreiben, sondern dies reicht aus:
Delphi-Quellcode:
createremotethread(hproc,nil,0,getprocaddress(getmodulehandle('kernel32.dll'),'FreeLibrary'),Pointer(hdll),0,TID);
Dadurch kommt bei mir eine Frage auf! Wieso muss ich das Handle der DLL nicht in den Prozess hineinschreiben, wie den Namen der DLL beim Starten? Und warum funktioniert die Methode mit WriteProcessMemoy usw. nicht? Für mich ist dies irgendwie unlogisch...

Apollonius 28. Nov 2007 19:43

Re: DLL-Injection mit Freelibrary
 
Ganz einfach: Das Pointer-Argument von CreateRemoteThread wird direkt an FreeLibrary übergeben. Und FreeLibrary kann mit einem Zeiger auf das Handle nichts anfangen, deshalb muss das Handle direkt, zum Zeiger gecastet, übergeben werden.

Wotan89 28. Nov 2007 20:00

Re: DLL-Injection mit Freelibrary
 
Wieso kann man der LoadlibraryA-Function den Stringwert nicht direkt übergeben, sondern muss ihn über WriteProcessMemory in den anderen Prozess schreiben. Ich glaube irgendeine Funtionalität habe ich noch nicht verstanden oder falsch "interpretiert". :?: :?: :?:

Apollonius 28. Nov 2007 20:10

Re: DLL-Injection mit Freelibrary
 
LoadLibrary erwartet als Parameter einen Zeiger auf einen Null-terminierten String, FreeLibrary erwartet einen HModule-Parameter.

Dani 28. Nov 2007 23:24

Re: DLL-Injection mit Freelibrary
 
Was waren nochmal die legitimen Anwendungsgebiete für DLL-Injection? :gruebel:

Wotan89 29. Nov 2007 18:39

Re: DLL-Injection mit Freelibrary
 
LÖegitime Anwendungen wären z.B. fehlerhafte 16-Bit-Anwenungen wieder zu,m Laufen zu bringen oder der Compiler benutzt auch DLL-Injection. Ich brauch es lediglich zum Verbessern des Verständnis für Programmierung. :wink:

Zacherl 29. Nov 2007 20:20

Re: DLL-Injection mit Freelibrary
 
Zitat:

Zitat von Dani
Was waren nochmal die legitimen Anwendungsgebiete für DLL-Injection? :gruebel:

Ring3 Hooks, welche von allen möglichen Anwendungen verwendet werden. Als Beispiel nur mal Firewalls. Was wären denn die illegalen Anwendungsgebiete?

brechi 14. Jan 2008 16:56

Re: DLL-Injection mit Freelibrary
 
wenns auch schon sehr alt ist:

Delphi-Quellcode:
function InjectIntoProcess(lpProcessID: Cardinal; lpDllname: String): cardinal;
var
  hProc: Cardinal;
  hRemThread:cardinal;
  addr:pointer;
  cWPM: Cardinal;
  th: integer;
begin
  result := 0;
  SetLastError(ERROR_SUCCESS);
  hProc := OpenProcess(PROCESS_ALL_ACCESS, false, lpProcessID);
  addr:=VirtualAllocEx(hProc, nil, length(lpDllname)+1, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  WriteProcessMemory(hProc, addr, PChar(lpDllName), length(lpDllName)+1, cWPM);
  th := CreateRemoteThread(hProc, nil, 0,GetProcaddress(getmodulehandle('kernel32.dll'),'LoadLibraryA') , addr, 0, hRemThread);
  if (th > 0) then
  begin
    // warten bis thread beendet (dll im fremden prozess geladen)
    WaitForSingleObject(th,INFINITE);
    // den exitcode bekommen = EAX register von LLA = baseadresse der dll = dllhandle
    GetExitCodeThread(th,result);
    closehandle(th);
    // dll wieder entladen
    th := createremotethread(hproc,nil,0,getprocaddress(getmodulehandle('kernel32.dll'),'FreeLibrary'),Pointer(result),0,hremthread);
    if (th > 0) then
      closehandle(th);
  end;
  CloseHandle(hProc);
end;

worker 10. Mär 2009 12:59

Re: DLL-Injection mit Freelibrary
 
Hallo,

habe zu der Routine aus Beitrag #20 mal eine Frage.

Und zwar habe ich diese Routine so bei mir implementiert.
Allerdings schmiert meine Testanwendung (Notepad) beim Aufruf der folgenden Codezeile ab:

Delphi-Quellcode:
th := createremotethread(hproc, Nil, 0, getprocaddress(getmodulehandle('kernel32.dll'), 'FreeLibrary'), Pointer(result), 0, hremthread);
Die Injizierung hat vorher problemlos funktioniert.

Muss ich in der DLL noch irgendetwas implementieren?

Habe schon folgendes probiert:

Delphi-Quellcode:
Procedure DllMain(Reason: Integer);
Var
   hThread: Cardinal;
Begin
   Case Reason Of
      DLL_PROCESS_ATTACH: CreateThread(Nil, 0, TFNThreadStartRoutine(@CreateIt), Nil, 0, hThread);
      DLL_THREAD_ATTACH: ;
      DLL_THREAD_DETACH: ;
      DLL_PROCESS_DETACH: ;
   End;
End;
[...]
Begin
   DllProc := @DllMain;
   DllProc(DLL_PROCESS_ATTACH);
End.
Delphi-Quellcode:
Procedure DllMain(Reason: Integer);
Var
   hThread: Cardinal;
Begin
   Case Reason Of
      DLL_PROCESS_ATTACH: CreateThread(Nil, 0, TFNThreadStartRoutine(@CreateIt), Nil, 0, hThread);
      DLL_THREAD_ATTACH: ;
      DLL_THREAD_DETACH: ;
      DLL_PROCESS_DETACH: CreateThread(Nil, 0, TFNThreadStartRoutine(@DestroyIt), Nil, 0, hThread);
   End;
End;

Procedure DestroyIt;
Begin

   //Alte WndProc wieder zurücksetzen
   setWindowLong(xNotepad, GWL_WNDPROC, LongInt(@pWndProc));
End;
[...]
Begin
   DllProc := @DllMain;
   DllProc(DLL_PROCESS_ATTACH);
End.
Delphi-Quellcode:
Procedure DllMain(Reason: Integer);
Var
   hThread: Cardinal;
Begin
   Case Reason Of
      DLL_PROCESS_ATTACH: CreateThread(Nil, 0, TFNThreadStartRoutine(@CreateIt), Nil, 0, hThread);
      DLL_THREAD_ATTACH: ;
      DLL_THREAD_DETACH: ;
      DLL_PROCESS_DETACH: CreateThread(Nil, 0, TFNThreadStartRoutine(@DestroyIt), Nil, 0, hThread);
   End;
End;

Procedure DestroyIt;
Begin

   //Alte WndProc wieder zurücksetzen
   setWindowLong(xNotepad, GWL_WNDPROC, LongInt(@pWndProc));
FreeLibrary(HInstance);
End;
[...]
Begin
   DllProc := @DllMain;
   DllProc(DLL_PROCESS_ATTACH);
End.
Bringt aber leider alles nichts - Notepad schmiert weiterhin ab :(

worker 10. Mär 2009 14:36

Re: DLL-Injection mit Freelibrary
 
Habe ergänzend noch herausgefunden, das alles lecker ist, wenn ich darauf verzichte, die WndProc von Notepad umzubiegen:
Delphi-Quellcode:
   
//pWndProc := Pointer(GetWindowLong(oNotepad, GWL_WNDPROC));
//setWindowLong(oNotepad, GWL_WNDPROC, LongInt(@NewWndProc));
Bringt mich persönlich nicht weiter, aber vielleicht denjenigen, der mir bei diesem Problem helfen kann.

Apollonius 10. Mär 2009 14:43

Re: DLL-Injection mit Freelibrary
 
Warum erzeugst du für jeden Piep einen neuen Thread? Beim Zurücksetzen der WndProc musst du LongInt(pWndProc) angeben.

worker 10. Mär 2009 15:04

Re: DLL-Injection mit Freelibrary
 
Zitat:

Zitat von Apollonius
Beim Zurücksetzen der WndProc musst du LongInt(pWndProc) angeben.

Was so ein kleines @ doch alles vermasseln kann ;)

Zitat:

Zitat von Apollonius
Warum erzeugst du für jeden Piep einen neuen Thread?

Das ist bei meinen 5 Millionen Versuchen, das Problem in den Griff zu bekommen, dabei rausgekommen.
Dachte, es liegt vielleicht daran, dass es nur innerhalb von Threads funktioniert.

Ein Einfacher Aufruf von
Delphi-Quellcode:
DLL_PROCESS_DETACH: DestroyIt;
tut's auch.


Fazit: es funktioniert - danke Dir :thumb:


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:01 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