AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren

x64 main-thread hook mittels dll

Ein Thema von Clowdy · begonnen am 1. Mai 2016 · letzter Beitrag vom 13. Mai 2016
Antwort Antwort
Clowdy

Registriert seit: 1. Mai 2016
4 Beiträge
 
#1

x64 main-thread hook mittels dll

  Alt 1. Mai 2016, 18:49
Hallo,

ich versuche zur Zeit den main-thread einer Anwendung zu hooken.
Hierfür injecte ich die Dll ganz normal über CreateRemoteThread und rufe eine exportierte Funktion meiner Dll als Einstieg auf.

Die Dll versucht dann in den main-thread zu gelangen. Das funktioniert soweit auch, aber ab und an friert die Anwendung einfach ein, obwohl an der dll selber nichts verändert wurde.

Ich vermute das es Probleme mit dem Stack gibt.

Um in den main-thread zu gelangen verwende ich zunächst folgende 2 Funktionen, letztere ist sicher nicht perfekt vermute hier aber nicht den Fehler:

Code:
function GetMainThreadId: Cardinal;
var
  ThreadEntry: THREADENTRY32;
  hThreadSnapShot: THandle;
  dwProcessId: Cardinal;
begin
  result := 0;

  dwProcessId := GetCurrentProcessId();

  ThreadEntry.dwSize := SizeOf(THREADENTRY32);
  hThreadSnapShot := CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, dwProcessID);

  if (Thread32First(hThreadSnapShot, ThreadEntry)) then
  begin
    repeat
      if (ThreadEntry.th32OwnerProcessID = dwProcessID) then
      begin
        CloseHandle(hThreadSnapShot);
        result := ThreadEntry.th32ThreadID;
        exit;
      end;
    until Thread32Next(hThreadSnapshot, ThreadEntry) = false;
    CloseHandle(hThreadSnapShot);
  end;
end;

function HookThread(pFunction: Pointer; var OldEIP: NativeUInt): Boolean;
var
  hThread: THandle;
  dwMainThreadId: Cardinal;
  ctx: TContext;
const
  THREAD_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED or SYNCHRONIZE or $3FF;
begin
  dwMainThreadId := GetMainThreadId();

  if (dwMainThreadId = 0) then
    exit(false);

  hThread := OpenThread(THREAD_ALL_ACCESS, false, dwMainThreadId);

  if (hThread = 0) then
    exit(false);

  if (SuspendThread(hThread) = Cardinal(-1)) then
  begin
    CloseHandle(hThread);
    exit(false);
  end;

  ctx.ContextFlags := CONTEXT_CONTROL;

  if not (GetThreadContext(hThread, ctx)) then
  begin
    ResumeThread(hThread);
    CloseHandle(hThread);
    exit(false);
  end;

  OldEIP := ctx.Rip;
  ctx.Rip := NativeUInt(pFunction);

  if (SetThreadContext(hThread, ctx)) then
  begin
    ResumeThread(hThread);
    CloseHandle(hThread);
    result := true;
  end else
    result := false;
end;
Direkt nach dem injizieren wird mittels der beiden Funktionen dann folgender Assembler Code aufgerufen:

Delphi-Quellcode:
procedure AsmLoader; assembler;
asm
  sub RSP, 8h
  push RAX
  push RBX
  push RCX
  push RDX
  push RDI
  push RSI
  push RSP
  push RBP
  push R8
  push R9
  push R10
  push R11
  push R12
  push R13
  push R14
  push R15
  mov RAX, _rip
  mov [RSP+128], RAX
  call _Load
  pop R15
  pop R14
  pop R13
  pop R12
  pop R11
  pop R10
  pop R9
  pop R8
  pop RBP
  pop RSP
  pop RSI
  pop RDI
  pop RDX
  pop RCX
  pop RBX
  pop RAX
end;
Load Funktion:

Delphi-Quellcode:
procedure _Load;
begin
  // sobald hier etwas aufgerufen wird kann es krachen
  GetCurrentThreadId();
end;

// Exported function
procedure Load(pArgs: Pointer);
begin
  if not (HookThread(@AsmLoader, _rip)) then
    ExitProcessMessage('Basic init failed');
end;
_rip ist ein NativeUint.

Den Assembler Code um die Register zu sichern und anschließend meine Funktion aufzurufen habe ich aus einem C++ Forum, der andere Part stammt von mir.

Ich bin bei x64 komplett neu, wäre nett wenn da mal jemand nachschauen könnte ob das alles so korrekt ist, und mir ggf. noch mitteilen kann wieso weshalb warum

Es frieren übrigens alle Anwendungen ab und zu ein welche ich als Ziel benutze, kann auch das Notepad sein.

Grüße
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#2

AW: x64 main-thread hook mittels dll

  Alt 1. Mai 2016, 23:48
Darf man fragen, was du genau vor hast?

Unter x64 werden alleine schon von der calling-convention her nicht nur die GP-Register verwendet, sondern auch XMM, etc. Diese musst du ebenfalls saven und wieder restoren. Und das (R)/(E)FLAGS Register würde ich mir ebenfalls sichern, sofern du nicht 100%-ig garantieren kannst, dass deine aufgerufene Funktion die Flags nicht affektiert.
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)
  Mit Zitat antworten Zitat
Benutzerbild von BUG
BUG

Registriert seit: 4. Dez 2003
Ort: Cottbus
2.094 Beiträge
 
#3

AW: x64 main-thread hook mittels dll

  Alt 2. Mai 2016, 08:30
Die Register und Flags sind zwar ein Problem, aber ein lösbares ... besonders wenn man sich mal anguckt was getThreadContext sichert

Das kompliziertere Problem ist, dass du das Programm irgendwo unterbrichst. Wenn der gerade an einer Datenstruktur rummanipuliert und deine injizierte Funktion diese auch benutzt, kann es krachen. Ähnliches Problem wie mit Unix-Signal-Handlern.

Geändert von BUG ( 2. Mai 2016 um 08:34 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Neutral General
Neutral General

Registriert seit: 16. Jan 2004
Ort: Bendorf
5.219 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#4

AW: x64 main-thread hook mittels dll

  Alt 2. Mai 2016, 08:35
Bist du dir denn sicher, dass GetMainThreadId dir auch immer den Mainthread zurückgibt?
Du gehst ja davon aus, dass der erste Thread der für den Prozess gefunden wird der Mainthread ist. Ist das irgendwo dokumentiert?
Kann mir vorstellen, dass du manchmal einfach im falschen Thread landest.
Michael
"Programmers talk about software development on weekends, vacations, and over meals not because they lack imagination,
but because their imagination reveals worlds that others cannot see."
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#5

AW: x64 main-thread hook mittels dll

  Alt 2. Mai 2016, 15:37
Bist du dir denn sicher, dass GetMainThreadId dir auch immer den Mainthread zurückgibt?
Du gehst ja davon aus, dass der erste Thread der für den Prozess gefunden wird der Mainthread ist. Ist das irgendwo dokumentiert?
Kann mir vorstellen, dass du manchmal einfach im falschen Thread landest.
Da es offiziell nichtmal sowas wie einen "Mainthread" gibt, ist deine Frage durchaus berechtigt Ich gehe aber mal davon aus, dass er den Prozess suspendet erstellt und dann direkt seine Dll injected. In diesem Falle existiert eh nur ein einziger Thread. Allerdings kann er sich dann einiges an Arbeit ersparen, indem er einfach ein wenig anders vorgeht .. deshalb auch meine Frage, was er denn eigentlich vorhat.

@Clowdy:
Mit MSDN-Library durchsuchenQueueUserAPC kannst du einen APC registrieren, der netterweise direkt nach dem Resumen ausgeführt wird (natürlich nur in dem Falle, dass du den Prozess tatsächlich wie von mir vermutet im suspended State erstellst). Dieser APC würde dann auch im Kontext des angegebenen Threads ausgeführt (das scheint dir ja scheinbar wichtig zu sein).
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)
  Mit Zitat antworten Zitat
Clowdy

Registriert seit: 1. Mai 2016
4 Beiträge
 
#6

AW: x64 main-thread hook mittels dll

  Alt 2. Mai 2016, 20:48
Hallo hallo! Danke für die doch zahlreichen Antworten.

Bist du dir denn sicher, dass GetMainThreadId dir auch immer den Mainthread zurückgibt?
Du gehst ja davon aus, dass der erste Thread der für den Prozess gefunden wird der Mainthread ist. Ist das irgendwo dokumentiert?
Kann mir vorstellen, dass du manchmal einfach im falschen Thread landest.
Ich bin mir relativ sicher mit der Funktion zumindest im richtigen zu landen.
Rufe ich in der _Load Funktion SetTimer() auf - was nicht mein Ziel ist, führen meine Aufrufe in der Callback Funktion in keinen Fall mehr zu einem Freeze. Rufe ich ich die gleichen Funktionen direkt in _Load auf, stürzt mir die Anwendung ab. Ich gehe also davon aus das nur der Assembler Code mit der Stack-Sicherung das Problem ist. Die ThreadId habe ich mit Breakpoints ohne das meine Dll injiziert ist noch einmal verifiziert. Der Aufruf erfolgt ausnahmslos vom ersten erstellten Thread.

Ich bin aber wahrlich noch kein Meister mit WinDbg.

Die Funktionen, oder eher ein Teil davon meiner Ziel-Anwendung sind nicht Thread sicher, daher der Umweg.

Da es offiziell nichtmal sowas wie einen "Mainthread" gibt, ist deine Frage durchaus berechtigt Ich gehe aber mal davon aus, dass er den Prozess suspendet erstellt und dann direkt seine Dll injected. In diesem Falle existiert eh nur ein einziger Thread. Allerdings kann er sich dann einiges an Arbeit ersparen, indem er einfach ein wenig anders vorgeht .. deshalb auch meine Frage, was er denn eigentlich vorhat.

@Clowdy:
Mit MSDN-Library durchsuchenQueueUserAPC kannst du einen APC registrieren, der netterweise direkt nach dem Resumen ausgeführt wird (natürlich nur in dem Falle, dass du den Prozess tatsächlich wie von mir vermutet im suspended State erstellst). Dieser APC würde dann auch im Kontext des angegebenen Threads ausgeführt (das scheint dir ja scheinbar wichtig zu sein).
Nein ich kann auch zur Laufzeit injizieren, das Resultat bleibt aber das gleiche. Dennoch sieht die Funktion interessant aus, danke.
Darf man fragen, was du genau vor hast?

Unter x64 werden alleine schon von der calling-convention her nicht nur die GP-Register verwendet, sondern auch XMM, etc. Diese musst du ebenfalls saven und wieder restoren. Und das (R)/(E)FLAGS Register würde ich mir ebenfalls sichern, sofern du nicht 100%-ig garantieren kannst, dass deine aufgerufene Funktion die Flags nicht affektiert.
Die Register und Flags sind zwar ein Problem, aber ein lösbares ... besonders wenn man sich mal anguckt was getThreadContext sichert

Das kompliziertere Problem ist, dass du das Programm irgendwo unterbrichst. Wenn der gerade an einer Datenstruktur rummanipuliert und deine injizierte Funktion diese auch benutzt, kann es krachen. Ähnliches Problem wie mit Unix-Signal-Handlern.
Danke für die Hinweise euch beiden, auch da werde ich mich noch einmal schlau machen.
Habt mir schon mal sehr weitergeholfen.
  Mit Zitat antworten Zitat
Clowdy

Registriert seit: 1. Mai 2016
4 Beiträge
 
#7

AW: x64 main-thread hook mittels dll

  Alt 13. Mai 2016, 15:34
Hallo nochmal,

da durchaus der ein oder andere durch Google auf den Beitrag hier stoßen dürfte und die Resultate zu Thread Hijacking unter x64 ziemlich dürftig sind, möchte ich hier noch einmal den korrigierten Code posten. Ich habe den Code jetzt seit einer Woche ohne Probleme bei mir im Einsatz, möglich das er noch immer Fehler enthält, dafür übernehme ich keine Gewähr. :p

Hinzu kamen einige Probleme bei den Parametern einiger Funktionen bei der Anwendung für die ich meine DLL nutze, aber das dürfte eher uninteressant sein.

edit: Mit QueueUserAPC habe ich mich ebenfalls intensiv beschäftigt, scheidet hier aber leider aus da der Thread sich in einer Schleife befindet und nie in einem alertable state ist, das wäre also nur eine Lösung gewesen wenn ich direkt beim Start der Anwendung injiziere.

Delphi-Quellcode:
procedure AsmLoader; assembler;
asm
  push [_rip]
  pushfq
  push RAX
  push RBX
  push RCX
  push RDX
  push RDI
  push RSI
  push RSP
  push RBP
  push R8
  push R9
  push R10
  push R11
  push R12
  push R13
  push R14
  push R15
  call _Load
  pop R15
  pop R14
  pop R13
  pop R12
  pop R11
  pop R10
  pop R9
  pop R8
  pop RBP
  pop RSP
  pop RSI
  pop RDI
  pop RDX
  pop RCX
  pop RBX
  pop RAX
  popfq
end;

Geändert von Clowdy (13. Mai 2016 um 15:45 Uhr) Grund: Delphi Code Tags
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#8

AW: x64 main-thread hook mittels dll

  Alt 13. Mai 2016, 16:43
Der Vollsrändigkeit halber solltest du aber auf jeden Fall noch den State der XMM Register XMM0-XMM15 sichern. YMM, ZMM und die AVX512 Erweiterung mit X/Y/ZMM16-31 kann man denke ich außer Acht lassen, aber einige XMM Register werden für die Standard 64-Bit CallingConvention verwendet. Die würde ich deshalb auf jeden Fall noch sichern.
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)
  Mit Zitat antworten Zitat
Clowdy

Registriert seit: 1. Mai 2016
4 Beiträge
 
#9

AW: x64 main-thread hook mittels dll

  Alt 13. Mai 2016, 17:38
Da muss ich mich tatsächlich selber noch einmal schlau machen, pushen geht ja nicht einfach so.
Ist bisher auch in keines der Beispiele die ich gefunden habe behandelt worden, allgemein unterscheiden sich die Lösungsansätze hier und da.

Ist aber ein guter Einwand.

Meinen aktuellen Lösungseinsatz habe ich übrigens von hier: http://shellblade.net/code-cave-windows.html
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#10

AW: x64 main-thread hook mittels dll

  Alt 13. Mai 2016, 18:10
Die AVX Register kannst du so pushen:
http://stackoverflow.com/a/10162065

Um ganz generisch zu sein, könntest du auch noch den FPU State sichern.
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)
  Mit Zitat antworten Zitat
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 10:19 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