Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi Inline Assembler (https://www.delphipraxis.net/155516-inline-assembler.html)

WorstNightmare 26. Okt 2010 20:56

Inline Assembler
 
Hallo,

ich habe eine DLL die als AntiCheat-Schutz in einem Spiel dienen soll. Für dieses Spiel gibt es sehr viele Packet Editors (oder eher gesagt Packet Senders), die eine bestimmte Adresse aufrufen. Um zu verhinden dass die Cheater nun ihre PEs injizieren möchte ich bei dieser Adresse gerne prüfen, ob der Aufruf aus der Haupt-EXE oder aus einer geladenen DLL kommt.

Delphi-Quellcode:
function GetModuleFromAddress(Address: Pointer): string;
var
  Res: HMODULE;
  Name: array[0..100] of AnsiChar;
begin
  GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, Address, Res);
  GetModuleBaseName(GetCurrentProcess, Res, Name, 100);
  Result := string(AnsiString(Name));
end;

procedure OnSendPacket(Ret: Pointer); stdcall;
var
  F: TextFile;
begin
  AssignFile(F, 'C:\test.txt');
  Append(F);
  Writeln(F, GetModuleFromAddress(Ret));
  CloseFile(F);
end;

procedure SendPacket; stdcall;
asm
  mov eax, [ebp]
  mov eax, [eax+$04]
  push eax
  call OnSendPacket
  mov eax,$00BF0044
  jmp dword ptr [SendPacketRet]
end;

[...] hier wird noch der Speicher modifiziert und ein JMP zu SendPacket() erstellt.
Mein eigentliches Ziel habe ich erreicht - der Name steht in der Textdatei. Leider geht dabei irgendwas kaputt und die Pakete werden vom Spiel nicht mehr weiterverarbeitet :?
Ich habs leider mit Assembler nicht so, ich vermute das geschieht durch den Aufruf der Delphi-Funktion OnSendPacket, welche dann irgendwelche Register verändert?
Zur Info, das Paket was der Client dann verarbeiten soll wird in ecx gespeichert.

rollstuhlfahrer 26. Okt 2010 21:13

AW: Inline Assembler
 
Delphi-Quellcode:
asm lea ecx, Quelle end;
Bernhard

Assarbad 26. Okt 2010 21:14

AW: Inline Assembler
 
Ohne jetzt auf die Assemblerfrage weiter einzugehen, möchte ich nur kurz deine gesamte Vorgehensweise infrage stellen.

Es gibt auch sog. "cavity injection". Da du an einer AC-Engine arbeitest, setze ich mal voraus, daß du Grundkenntnisse über den Aufbau von PE-Dateien besitzt. Du weißt also, daß eine PE-Datei auf Platte und im Speicher (meist) anders aussehen. Im Speicher haben sie oft - zumeist am Ende von Sektionen - ein "Loch", nämlich die Bytes welche bis zur Ausrichtung im Speicher noch fehlen um die Seite/Sektion (o.ä.) vollzumachen. Entsprechend kann ein cleverer "Angreifer" (i.e. Cheater) mal eben ein Trampolin oder komplexeren Shellcode da einbauen. Dann kommt der Aufruf also ggf. "aus deinem PE-Abbild" im Speicher, obwohl nur stimmt, daß der Aufruf aus dem Bereich zwischen Basisadresse und Basisadresse+Größe stammt.

Dein Ansatz geht also am Problem leicht vorbei ;)

Diese Methode wird schon seit Jahren bei Malware eingesetzt, so auch bei KM-Rootkits, wo die Antimalware-Lösung bspw. versucht auch anhand der Adresse festzustellen ob die SSDT gehookt wurde ;)

BUG 26. Okt 2010 22:07

AW: Inline Assembler
 
Mal als naiven Vorschlag:
Da man ja nicht wie einem Anti-Malware-Programm viele Prozesse überwachen muss, könnte man doch zusätzlich regelmäßig die Codesektionen mit denen aus der PE-Datei (+Anti-Cheat-Tool-Hooks) vergleichen und Lücken mit Schrott/NOPs ausfüllen. Eventuelle von der Anwendung "legal" änderbare Sektionen könnte man ja davon ausnehmen.

Assarbad 26. Okt 2010 22:13

AW: Inline Assembler
 
Zitat:

Zitat von BUG (Beitrag 1057992)
Da man ja nicht wie einem Anti-Malware-Programm viele Prozesse überwachen muss, könnte man doch zusätzlich regelmäßig die Codesektionen mit denen aus der PE-Datei (+Anti-Cheat-Tool-Hooks) vergleichen und Lücken mit Schrott/NOPs ausfüllen. Eventuelle von der Anwendung "legal" änderbare Sektionen könnte man ja davon ausnehmen.

Und jetzt verknüpfen wir das ganze noch mit der primären Anforderung, daß ein Antimalware-Programm äußerst schnell sein soll und es wird nicht mehr so einfach ;)

Abgesehen davon könnte ich dann ggf. auch den Code der PE auslagern (bspw. indem ich die PE-Datei nochmal im Prozeßraum als MMF lade und selber reloziere) und einfach alle PE-Sektionen (des originalen Abbilds) dafür benutze mein eigenes Ding zu machen ...

Kommt immer drauf an welche Rechte der Angreifer schon hat. Am Ende hat der Angreifer gegen unendlich viele Möglichkeiten einen Angriff zu machen, während der Verteidiger dieses Privileg nicht genießt - u.a. wird ein Rootkit-Autor oft nicht auf Stabilität achten müssen, solange ihm das Rootkit als Teil eines Bots auf genügend anderen Rechnern etwas einbringt; der Verteidiger muß auf Stabilität achten.

BUG 26. Okt 2010 22:36

AW: Inline Assembler
 
Zitat:

Zitat von Assarbad (Beitrag 1057996)
Und jetzt verknüpfen wir das ganze noch mit der primären Anforderung, daß ein Antimalware-Programm äußerst schnell sein soll und es wird nicht mehr so einfach ;)

Deshalb schrieb ich ja: nicht Anti-Malware-Programm :tongue:

Zitat:

Zitat von Assarbad (Beitrag 1057996)
Abgesehen davon könnte ich dann ggf. auch den Code der PE auslagern (bspw. indem ich die PE-Datei nochmal im Prozeßraum als MMF lade und selber reloziere) und einfach alle PE-Sektionen (des originalen Abbilds) dafür benutze mein eigenes Ding zu machen ..

Also die Codesektionen (ungepatcht durch AntiCheats) neu aus der PE lesen und damit auf den Daten des normalen Programmes arbeiten? Oder hab ich dich da falsch verstanden?
Darauf muß man erst mal kommen :shock:

Zitat:

Zitat von Assarbad (Beitrag 1057996)
Kommt immer drauf an welche Rechte der Angreifer schon hat.

Blöderweise hat ja ein Cheat im Zweifelsfall alle Rechte. Also kommt man bei Anti-Cheat-Programmen irgendwann auf die gleiche Diskussion wie bei DRM, Anti-Cracking, usw.

Assarbad 26. Okt 2010 22:39

AW: Inline Assembler
 
Zitat:

Zitat von BUG (Beitrag 1058003)
Deshalb schrieb ich ja: nicht Anti-Malware-Programm :tongue:

Sorry, mein Fehler.

Zitat:

Zitat von BUG (Beitrag 1058003)
Also die Codesektionen (ungepatcht durch AntiCheats) neu aus der PE lesen und damit auf den Daten des normalen Programmes arbeiten? Oder hab ich dich da falsch verstanden?
Darauf muß man erst mal kommen :shock:

Jupp. Gibt es alles schon. Bspw. benutzen einige Antirootkits das um eine zweite Instanz des Kernels zu laden der sie vertrauen können (oder von der man annimmt ihr vertrauen zu können ;)).

Zitat:

Zitat von BUG (Beitrag 1058003)
Blöderweise hat ja ein Cheat im Zweifelsfall alle Rechte. Also kommt man bei Anti-Cheat-Programmen irgendwann auf die gleiche Diskussion wie bei DRM, Anti-Cracking, usw.

Exakt. Hase und Igel :lol:

WorstNightmare 27. Okt 2010 13:25

AW: Inline Assembler
 
Nur um das klarzustellen, das soll keine aufwändige Anti-Cheat-Engine werden. Nur eine kleine Bibliothek die LoadLibrary hookt, das laden von einigen einschlägigen Trainern verhindert und eben das Senden von Paketen durch anderes injiziertes Zeugs verhindert. Das soll auch nur für diese ganzen Noobs sein, die die Cheats benutzen aber keine Ahnung haben wie das ganze funktioniert. Wenn jemand da wirklich cheaten will und auch Erfahrung darin hat ist mir klar, dass man ihn nicht davon abhalten kann. Das schaffen ja auch die professionellen Anwendungen in den meisten Fällen nicht.

Nun aber zurück zu meinem Problem. Wo soll ich dieses lea ecx benutzen und was bringt es mir, ist ecx nicht in dem Fall das Ziel? Dann müsste ich ja vorher erst was in Quelle laden.

Assarbad 27. Okt 2010 13:46

AW: Inline Assembler
 
Zitat:

Zitat von WorstNightmare (Beitrag 1058119)
Nun aber zurück zu meinem Problem. Wo soll ich dieses lea ecx benutzen und was bringt es mir, ist ecx nicht in dem Fall das Ziel? Dann müsste ich ja vorher erst was in Quelle laden.

Exzellente Frage. Dazu solltest du uns vielleicht noch ein paar Details verraten ... ;)

Zitat:

Zitat von WorstNightmare (Beitrag 1057970)
Mein eigentliches Ziel habe ich erreicht - der Name steht in der Textdatei. Leider geht dabei irgendwas kaputt und die Pakete werden vom Spiel nicht mehr weiterverarbeitet :?
Ich habs leider mit Assembler nicht so, ich vermute das geschieht durch den Aufruf der Delphi-Funktion OnSendPacket, welche dann irgendwelche Register verändert?

OnSendPacket darf laut Aufrufkonvention keine Register verändern ohne sie auch wiederherzustellen. Entsprechend würde ich eher das Problem bei SendPacketRet und allem was damit zusammenhängt sehen.

Was ist denn SendPacketRet (Funktion oder nur Zeiger?) und wo kommt es her, wo wird es gesetzt. Abgesehen davon dürfte der Spaß im Disassembler unter Umständen nicht mehr ganz so aussehen wie du es erwartest.

Außerdem scheinst du sozusagen auf dem Rasen der gehookten Funktion herumzutrampeln. Jedenfalls erschließt sich mir:

Code:
  mov eax,$00BF0044
  jmp dword ptr [SendPacketRet]
nicht, wenn man annimmt, daß die gehookte Funktion (und so sollte es ja sein) auch stdcall benutzt.

WorstNightmare 27. Okt 2010 14:00

AW: Inline Assembler
 
http://i55.tinypic.com/sdof88.png

Die 5 Bytes bei 4BC877 ersetze ich mit einem jmp zu meiner SendPacket Methode. Das mov eax,00b... ist also nur der originale Opcode und dann wird der originale Code weiter ausgeführt (SendPacketRet: Cardinal = $4BC877 + 5).
Mehr weiß ich leider auch nicht, außer dass ecx einen Pointer auf einen record mit dem Paket enthält.

Assarbad 27. Okt 2010 22:17

AW: Inline Assembler
 
Gut, der dargestellte Abschnitt ist zu klein um eine vernünftige Aussage zu erlauben.

Zitat:

Zitat von WorstNightmare (Beitrag 1058124)
Die 5 Bytes bei 4BC877 ersetze ich mit einem jmp zu meiner SendPacket Methode. Das mov eax,00b... ist also nur der originale Opcode und dann wird der originale Code weiter ausgeführt (SendPacketRet: Cardinal = $4BC877 + 5).
Mehr weiß ich leider auch nicht, außer dass ecx einen Pointer auf einen record mit dem Paket enthält.

Tja, dann empfehle ich dir erstmal keine Annahmen zu treffen, wie du es getan hast. Nehmen wir erstmal einfach das stdcall raus. Also:

Code:
procedure SendPacket;
asm
  mov eax, [ebp]
  mov eax, [eax+$04]
  push eax
  call OnSendPacket
  mov eax,$00BF0044
  jmp dword ptr [SendPacketRet]
end;
Bei OnSendPacket bleibt es!

... dann versuch mal. Ansonsten mußte vielleicht mal mehr vom Originalcode und von deinem Code rausrücken, denn sonst wird es schwer überhaupt was zu sagen (ohne zu raten).

WorstNightmare 28. Okt 2010 18:35

AW: Inline Assembler
 
Welche Ausschnitte aus dem asm-Code brauchst du denn? Weiter nach oben oder nach unten?

Von meinem Code habe ich schon so ziemlich alles gepostet. Habe jetzt mal das stdcall weggenommen, bringt nichts.

Delphi-Quellcode:
const
  SEND_PACKET = $004BC877;

var
  SendPacketRet: Cardinal = SEND_PACKET + 5;

function JMP(iFrom, iTo: Cardinal): Cardinal;
begin
  Result := (iTo - iFrom) - 5;
end;

function GetModuleFromAddress(Address: Pointer): string;
var
  Res: HMODULE;
  Name: array[0..100] of AnsiChar;
begin
  GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, Address, Res);
  GetModuleBaseName(GetCurrentProcess, Res, Name, 100);
  Result := string(AnsiString(Name));
end;

procedure OnSendPacket(Ret: Pointer); stdcall;
var
  F: TextFile;
begin
  AssignFile(F, 'C:\test.txt');
  Append(F);
  Writeln(F, GetModuleFromAddress(Ret));
  CloseFile(F);
end;

procedure SendPacket;
asm
  mov eax, [ebp]
  mov eax, [eax+$04]
  push eax
  call OnSendPacket
  mov eax,$00BF0044
  jmp dword ptr [SendPacketRet]
end;

procedure InstallHook;
begin
  PByte(SEND_PACKET)^ := $E9;
  PCardinal(SEND_PACKET + 1)^ := JMP(SEND_PACKET, DWORD(@SendPacket));
end;
Und es liegt nicht an meinem allgemeinen Vorgehen; sobald ich das stdcall; wieder hinmache und den OnSendPacket call inklusive push eax auskommentiere geht alles, die Pakete werden gesendet.

Assarbad 28. Okt 2010 19:42

AW: Inline Assembler
 
Zitat:

Zitat von WorstNightmare (Beitrag 1058395)
Und es liegt nicht an meinem allgemeinen Vorgehen; sobald ich das stdcall; wieder hinmache und den OnSendPacket call inklusive push eax auskommentiere geht alles, die Pakete werden gesendet.

In dem Fall müßte man durch den Code durchgehen (im Debugger/Disassembler).

WorstNightmare 4. Nov 2010 13:36

AW: Inline Assembler
 
http://i52.tinypic.com/1z4llwj.png

So sieht es im Disassembler aus. Die obere ist die asm-Prozedur. Damit er die zeigte musste ich sie manuell aufrufen, damit sie überhaupt disassembliert wurde (ansonsten zeigt er an der Stelle nur db XXh an). Der untere Teil ist dementsprechend OnSendPacket.
Kann man an dem Ausschnitt was erkennen?

Edit:
Hab ich's mir gedacht, so geht es:
Delphi-Quellcode:
procedure OnSendPacket(Ret: Pointer); stdcall;
var
  F: TextFile;
begin
  AssignFile(F, 'C:\lol.txt');
  Append(F);
  Writeln(F, GetModuleFromAddress(Ret));
  CloseFile(F);
end;

procedure SendPacket; stdcall;
asm
  mov eax, [ebp]
  mov eax, [eax+$04]
  push ecx
  push eax
  call OnSendPacket
  pop ecx
  mov eax,$00BF0044
  jmp dword ptr [SendPacketRet]
end;
ecx einfach speichern. Warum ist da niemand drauf gekommen, ist das irgendwie gefährlich? o.o

Assarbad 4. Nov 2010 15:42

AW: Inline Assembler
 
Zitat:

Zitat von WorstNightmare (Beitrag 1059632)
ecx einfach speichern. Warum ist da niemand drauf gekommen, ist das irgendwie gefährlich? o.o

Gefährlich ist das nicht. Nur mit den mageren Informationen die du dargeboten hast, ließ sich über die Aufrufkonventionen nicht alles ermitteln.

Aber eigentlich sollte das absolut nichts ändern, denn bei stdcall würde es OnSendPacket obliegen den Registerwert zu speichern und wiederherzustellen. Dein Code ist also eigentlich nach den allgemeinen Regeln redundant. Der Wurm ist woanders zu finden ... nur wo?


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