AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Projekte [Lib] Shellcode Forger für einfache Codeausführung in Fremdprozessen

[Lib] Shellcode Forger für einfache Codeausführung in Fremdprozessen

Ein Thema von Zacherl · begonnen am 15. Dez 2013
Antwort Antwort
Benutzerbild von Zacherl
Zacherl
Registriert seit: 3. Sep 2004
Hallo zusammen,

bei meinem letzten Projekt kam ich in die Verlegenheit Code in einem anderen Prozess ausführen zu müssen. Eine komplette DLL Injection wollte ich vermeiden, da die Codemenge in diesem Fall nur sehr gering war. Nun kann man natürlich einfach den Assembler Code einer kompletten Delphi Funktion injizieren und ausführen. Dies bringt allerdings einige Schwierigkeiten mit sich:
  1. Man kann keine APIs verwenden, da der Aufruf in Delphi immer über die IAT (welche im Zielprozess anders aussieht) erfolgt
  2. Man kann keine Unterfunktionen aufrufen (ohne diese ebenfalls zu injizieren und die relativen Calls per Disassembler zu patchen)
  3. Man kann keine Strings verwenden (ohne diese ebenfalls zu injizieren und die entsprechenden PAnsi/PWideChar Referenzen zu patchen)
  4. Man kann nur umständlich mit globalen Feldern arbeiten

Um diesen Problemen entgegenzuwirken, habe ich eine Klasse geschrieben, welche Code erzeugen kann, der direkt in einem anderen Prozess ausführbar ist.

Für den maximalen Komfort wird der Shellcode in einer Klasse gekapselt, die ihr von TBasicShellcode ableiten müsst. Alle Felder der Klasse werden zur Laufzeit im Fremdprozess verfügbar sein. Ebenfalls könnt ihr alle Klassenfunktionen für die Verwendung im Shellcode registrieren (nur VIRTUAL Methods) und so Unterfunktionen ganz intuitiv verwenden. Wenn der Shellcode externe API Imports benötigt, so reicht es einfach die jeweilige Funktion an ein beliebiges Feld der Klasse zu binden.

Beispiel:
Delphi-Quellcode:
const
  ID_WSTRING_INFO = $00000001;
  ID_WSTRING_INFO_TEXT = $00000002;
  ID_WSTRING_QUESTION = $00000003;
  ID_WSTRING_QUESTION_TEXT = $00000004;

type
  TMyShellcode = class(TBasicShellcode)
  private
    FMessageTitle: PWideChar;
    FMessageText: PWideChar;
    FMessageFlags: DWord;
  private
    APIBeep: function(dwFreq, dwDuration: DWORD): BOOL; stdcall;
    APIMessageBoxW: function(hWnd: HWND; lpText, lpCaption: LPCWSTR; uType: UINT): Integer; stdcall;
  private
    function ShowQuestion(Text, Title: PWideChar): Integer; virtual;
    procedure DoShowMessage; virtual;
  protected
    procedure RegisterImports(Forger: TBasicShellcodeForger); override;
    procedure RegisterMethods(Forger: TBasicShellcodeForger); override;
    procedure RegisterStrings(Forger: TBasicShellcodeForger); override;
  protected
    function Initialize({Param: Pointer}): DWord; override;
    function Finalize: DWord; override;
  end;

{ TMyShellcode }

function TMyShellcode.ShowQuestion(Text, Title: PWideChar): Integer;
begin
  Result := APIMessageBoxW(0, Text, Title, MB_ICONQUESTION or MB_YESNO);
end;
procedure EndOfTMyShellcodeShowQuestion; begin end;

function TMyShellcode.Initialize({Param: Pointer}): DWord;
begin
  APIBeep(1000, 200);
  FMessageText := FindWideString(ID_WSTRING_INFO_TEXT);
  FMessageTitle := FindWideString(ID_WSTRING_INFO);
  FMessageFlags := MB_ICONINFORMATION;
  DoShowMessage;
  Result := 0;
end;
procedure EndOfTMyShellcodeInitialize; begin end;

procedure TMyShellcode.DoShowMessage;
begin
  APIMessageBoxW(0, FMessageText, FMessageTitle, FMessageFlags);
end;
procedure EndOfTMyShellcodeDoShowMessage; begin end;

function TMyShellcode.Finalize: DWord;
begin
  APIBeep(500, 200);
  Result :=
    ShowQuestion(FindWideString(ID_WSTRING_QUESTION_TEXT), FindWideString(ID_WSTRING_QUESTION));
end;
procedure EndOfTMyShellcodeFinalize; begin end;

procedure TMyShellcode.RegisterImports(Forger: TBasicShellcodeForger);
begin
  inherited;
  RegisterImport(Forger, @@APIBeep, 'kernel32.dll', 'Beep');
  RegisterImport(Forger, @@APIMessageBoxW, 'user32.dll', 'MessageBoxW');
end;

procedure TMyShellcode.RegisterMethods(Forger: TBasicShellcodeForger);
begin
  inherited;
  RegisterMethod(Forger, @TMyShellcode.Initialize,
    NativeUInt(@EndOfTMyShellcodeInitialize) - NativeUInt(@TMyShellcode.Initialize));
  RegisterMethod(Forger, @TMyShellcode.Finalize,
    NativeUInt(@EndOfTMyShellcodeFinalize) - NativeUInt(@TMyShellcode.Finalize));
  RegisterMethod(Forger, @TMyShellcode.ShowQuestion,
    NativeUInt(@EndOfTMyShellcodeShowQuestion) - NativeUInt(@TMyShellcode.ShowQuestion));
  RegisterMethod(Forger, @TMyShellcode.DoShowMessage,
    NativeUInt(@EndOfTMyShellcodeDoShowMessage) - NativeUInt(@TMyShellcode.DoShowMessage));
end;

procedure TMyShellcode.RegisterStrings(Forger: TBasicShellcodeForger);
begin
  inherited;
  RegisterWideString(Forger, ID_WSTRING_INFO, 'Info');
  RegisterWideString(Forger, ID_WSTRING_INFO_TEXT, 'Hello hello boys and girls!');
  RegisterWideString(Forger, ID_WSTRING_QUESTION, 'Question');
  RegisterWideString(Forger, ID_WSTRING_QUESTION_TEXT, 'Bye bye. What do you want me to return?');
end;
Delphi-Quellcode:
var
  Forger: TBasicShellcodeForger;
  ProcessHandle,
  ThreadHandleA,
  ThreadHandleB: THandle;
  Shellcode: TMemoryStream;
  ShellcodeSize: DWord;
  BaseAddress,
  ProcEntryPoint,
  ProcDestructor: Pointer;
  BytesWritten: SIZE_T;
  TID,
  ExitCode: DWord;
begin
  Forger := TBasicShellcodeForger.Create(TMyShellcode);
  try
    ProcessHandle := OpenProcess(PROCESS_ALL_ACCESS, false, {Process ID});
    if (ProcessHandle <> 0) and (ProcessHandle <> INVALID_HANDLE_VALUE) then
    try
      ShellcodeSize := Forger.GetShellcodeSize;
      BaseAddress := VirtualAllocEx(ProcessHandle, nil, ShellcodeSize, MEM_COMMIT or MEM_RESERVE,
        PAGE_EXECUTE_READWRITE);
      if Assigned(BaseAddress) then
      try
        Shellcode := TMemoryStream.Create;
        try
          Forger.GenerateShellcode(BaseAddress, Shellcode, ProcEntryPoint, ProcDestructor);
          if (WriteProcessMemory(ProcessHandle, BaseAddress, Shellcode.Memory, Shellcode.Size,
            BytesWritten)) and (BytesWritten = Shellcode.Size) then
          begin
            ThreadHandleA :=
              CreateRemoteThread(ProcessHandle, nil, 0, ProcEntryPoint, BaseAddress, 0, TID);
            if (ThreadHandleA <> 0) and (ThreadHandleA <> INVALID_HANDLE_VALUE) then
            try
              WaitForSingleObject(ThreadHandleA, INFINITE);
              if GetExitCodeThread(ThreadHandleA, ExitCode) then
              begin
                MessageBox(0, PChar(Format('Shellcode initialize returned: %.8x.', [ExitCode])),
                  'Info', MB_ICONINFORMATION);
              end;
            finally
              CloseHandle(ThreadHandleA);
            end;
            ThreadHandleB :=
              CreateRemoteThread(ProcessHandle, nil, 0, ProcDestructor, BaseAddress, 0, TID);
            if (ThreadHandleB <> 0) and (ThreadHandleB <> INVALID_HANDLE_VALUE) then
            try
              WaitForSingleObject(ThreadHandleB, INFINITE);
              if GetExitCodeThread(ThreadHandleB, ExitCode) then
              begin
                MessageBox(0, PChar(Format('Shellcode finalize returned: %.8x.', [ExitCode])),
                  'Info', MB_ICONINFORMATION);
              end;
            finally
              CloseHandle(ThreadHandleB);
            end;
          end;
        finally
          Shellcode.Free;
        end;
      finally
        VirtualFreeEx(ProcessHandle, BaseAddress, ShellcodeSize, MEM_RELEASE or MEM_FREE);
      end;
    finally
      CloseHandle(ProcessHandle);
    end;
  finally
    Forger.Free;
  end;
end;
Feedback und Verbesserungsvorschläge erwünscht!

Viele Grüße
Zacherl
Angehängte Dateien
Dateityp: pas libShellcode.pas (23,5 KB, 47x aufgerufen)
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)
 
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:38 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz