Autoassamble-Code -> C++ .dll for injection ?

02/29/2012 23:04 Paranoiaaa123#1
Hallo.
Ich habe folgenden funktionierenden CheatEngine Autoassamble-Code und will daraus eine dll schreiben. Injected wird sie dann mit Wininject.

Code:
[ENABLE]
alloc(injectLocWrite,1024)
label(isPlayer)

"abc.exe"+2CD2B6:
jmp injectLocWrite

injectLocWrite:
push eax
mov eax,["abc.exe"+01075E88]
mov eax,[eax+4]
cmp ecx,eax
pop eax
je isPlayer
movss [esi+08],xmm0
jmp "abc.exe"+2CD2BB

isPlayer:
jmp "abc.exe"+2CD2D6

[DISABLE]
dealloc(injectLocWrite)

"abc.exe"+2CD2B6:
movss [esi+08],xmm0
Die dll sieht im Moment so aus:

Code:
#include <iostream>
#include <Windows.h>
using namespace std;

typedef unsigned int uint;

enum data
{
   ncentry=0x2CD2B6,
   ncp1=0x1075E88,
   ncp2=0x2CD2BB,
   ncp3=0x2CD2D6,
};

DWORD base;
DWORD baseentry;
DWORD basepb;
DWORD basep1;
DWORD basep2;

__declspec(naked)void AsmOn()
{
    __asm
    {
        push eax
        mov eax, dword ptr basepb
        mov eax, [eax+0x4]
        cmp ecx, eax
        pop eax
        je isPlayer
        movss [esi+0x08], xmm0
        jmp dword ptr basep1

     isPlayer:
        jmp dword ptr basep2
     };
}

extern "C" __declspec(dllexport)DWORD Initialize()
{
   base=(DWORD)GetModuleHandle(NULL);

   baseentry=base+ncentry;
   basepb=base+ncp1;
   basep1=base+ncp2;
   basep2=base+ncp3;

   return 1;
}

BOOL APIENTRY DllMain( HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
   switch (ul_reason_for_call)
   {
   case DLL_PROCESS_ATTACH:
      {
         CreateThread(0, 0, &Initialize, 0, 0, 0);
      }
      break;
   case DLL_THREAD_ATTACH:
   case DLL_THREAD_DETACH:
   case DLL_PROCESS_DETACH:
      break;
   }
   return TRUE;
}
  • Stimmt "CreateThread(0, 0, &Initialize, 0, 0, 0);" überhaupt? / Kann ich nicht einfach "Initialize()" aufrufen?
  • Muß ich Speicher mittels alloc reservieren? / Macht das der Injector?
  • Wie schreibe ich einen Jump-Befehl zu meinem Code, in ""abc.exe"+2CD2B6 / baseentry"?
  • Wer kann mit helfen?

Vielen Dank bereits im Vorraus
03/01/2012 06:16 SmackJew#2
Ich sag's mal so, jemand der weiß wie eine .dll funktioniert und weitere erweiterte Fähigkeiten im Bereich der Speichermanipulation hat und dir daher dabei helfen kann wird nicht mit der CheatEngine Skriptsprache vertraut sein. Ich versuche trotzdem 'mal ein paar grundlegende Sachen zu klären:

1. Der CreateThread Call sieht soweit in Ordnung aus, grundsätzlich ist zu sagen, dass auch wenn NULL als 0 defined ist 0 für DWORDS und NULL für Zeiger zu übergeben angebracht ist.

2. Warum du Initialize exportierst ist mir nicht klar. Das passiert im Groben wenn du die DLL injezierst:

Quote:
1. Das Injectorprogramm lädt die .dll in den Adressraum des Prozesses.
Wie nun gerade dieser Injector das tut kann ich dir nicht sagen, es gibt viele Möglichkeiten eine .dll in einen Prozess zu laden, die häufigste ist wohl einen minimalen Teil an Code von Hand in den Prozess zu schreiben der Funktionen zum Laden der .dll aus dem Prozess heraus aufruft, viele weitere werden in der Praxis angewandt. Zu deiner zweiten Frage also: Nein, der Injector schummelt deine .dll in den Prozess und damit auch den Code der in der .dll kompiliert ist.

Quote:
2. Nach dem Laden der DLL wird die DllMain Funktion aufgerufen, bei diesem Aufruf werden dann natürlich auch die Parameter gefüllt, für dich wichtig ist ul_reason_for_call, der bestimmt warum die DllMain aufgerufen wurde. Wurde die .dll von einem Prozess geladen ist dies DLL_PROCESS_ATTACH. Deine .dll erzeugt nun den Thread der wiederrum Initialize ausführt.

Initialize tut bei dir nichts als einige Berechnungen durchzuführen. Willst du deinen ASM Code ausführen musst du natürlich auch deine AsmOn Funktion aufrufen. Die dritte Frage verstehe ich nicht, entweder interpretiere ich die CheatEngine Skriptsprache falsch (sehr gut möglich, ich habe sie noch nie gesehen) oder meine inline ASM Abstinenz macht sich langsam bemerkt. Der "jmp dword ptr basep2" sieht soweit in Ordnung aus, bis auf fehlende []. Funktioniert etwas konkret nicht? Im Zweifelsfall die .dll disassemblen oder live debuggen und einfach mal über den JMP steppen und schauen wo du landest.
03/01/2012 15:28 Paranoiaaa123#3
Vielen Dank, für deine Bemühungen! :handsdown: - Frage 1 und 2 sind damit beantwortet.

Ich versuche mein eigentliches Problem / Frage 3 noch mal zu konkretisieren:
Original steht bei "abc.exe"+2CD2B6 der Asm-Code: movss [esi+08],xmm0.
Ich will jetzt mit der dll meinen Asm-Code (AsmOn), in den Adressraum des Prozesses "injecten" und leihenhaft gesagt, auf "abc.exe"+2CD2B6 einen Jmp-Befehl auf meinen Asm-Code schreiben.
Dann sollte sozusagen statt "movss [esi+08],xmm0" meine Funktion "AsmOn" ausgeführt werden.

"baseentry" sollte die Adresse "abc.exe"+0x2CD2B6 sein.
Wie kann ich in "baseentry" einen Jump auf AsmOn() schreiben?

Mit Besten Dank im Voraus!
03/01/2012 15:35 Dr. Coxxy#4
mit nem detour:

Code:
void* DetourFunc(PBYTE src, const PBYTE dst, const int len)
{
	DWORD dwback;
	BYTE* jmp = (BYTE*)malloc(len+5);
	VirtualProtect(jmp, len+5, PAGE_EXECUTE_READWRITE, &dwback);
	VirtualProtect(src, len, PAGE_READWRITE, &dwback);
	memcpy(jmp, src, len);
	jmp += len;
	jmp[0] = 0xE9;
	*(DWORD*)(jmp+1) = (DWORD)(src + len - jmp) - 5;
	src[0] = 0xE9;
	*(DWORD*)(src+1) = (DWORD)(dst - src) - 5;
	for (int i = 5; i < len; i++)
	{
		src[i] = 0x90;
	}
	VirtualProtect(src, len, dwback, &dwback);
	return (jmp - len);
}
der sichert sogar den code, überschreibt die unnötigen bytes mit nops etc., sollte kein großes problem sein, das abzuspecken, wobei dus natürlich auch so lassen kannst.

falls du den code nicht verstehst, ist hier nen tut in dem der aufbau von nem detour relativ detailliert erklärt ist:
[Only registered and activated users can see links. Click Here To Register...]
03/01/2012 22:32 Paranoiaaa123#5
Danke! Der Detour funktioniert nun richtig, allerdings scheint die ptr-Berechnung falsch zu sein. Mal ein Beispiel:

Original im Debugger:
Code:
[U]0043D7C6[/U] - F3 0F11 46 08     - movss [esi+08],xmm0      [B]//Hier will ich den jmp in meine Funkt.[/B]
[U]0043D7CB[/U] - F3 0F11 56 0C     - movss [esi+0C],xmm2     [B]//Entweder hier retour[/B]
0043D7D0 - F3 0F11 4E 10     - movss [esi+10],xmm1
0043D7D5 - 74 0F                 - je 0043D7E6
0043D7D7 - F3 0F11 46 5C     - movss [esi+5C],xmm0
0043D7DC - F3 0F11 56 60     - movss [esi+60],xmm2
0043D7E1 - F3 0F11 4E 64     - movss [esi+64],xmm1
[U]0043D7E6[/U] - 8B 4E 04            - mov ecx,[esi+04]     [B]//Sonst hier retour[/B]
Nach Inject und Jmp sollte die Asm-Funktion so aussehen:

Code:
- push eax
- mov eax,[[U]011E5E88[/U]]
- mov eax,[eax+04]
- cmp ecx,eax
- pop eax
- je 0330001C
- movss [esi+08],xmm0
- jmp [U]0043D7CB[/U]
(0330001C) - jmp [U]0043D7E6[/U]
Im Debugger sieht sie allerdings so aus:

Code:
- push eax
- mov eax,[[U]5AEC3348[/U]]
- mov eax,[eax+04]
- cmp ecx,eax
- pop eax
- je 5AEC1019
- movss [esi+08],xmm0
- jmp dword ptr [[U]5AEC334C[/U]]
(5AEC1019) - jmp dword ptr [[U]5AEC3354[/U]]
Wie kommt der auf die Adressen?
Warum steht "dword ptr" dabei?

So sieht die Asm und Berechnungsfunktion aus:

Code:
enum data
{
	ncentry=0x2CD7C6,
	ncp1=0x1075E88,
	ncp2=0x2CD7CB,
	ncp3=0x2CD7E6,
};

DWORD base;
DWORD baseentry;
DWORD basepb;
DWORD basep1;
DWORD basep2;

__declspec(naked)void AsmOn()
{
	__asm
	{
	push eax 
        mov eax, dword ptr basepb
        mov eax, [eax+0x04]
        cmp ecx, eax 
        pop eax 
        je isPlayer 
        movss [esi+0x08], xmm0 
        Jmp dword ptr basep1

isPlayer: 
        Jmp dword ptr basep2
	};
}

__declspec(naked)void Initialize()
{
	base=(DWORD)GetModuleHandle(NULL);

	baseentry = base + ncentry;
	basepb = base + ncp1;
	basep1 = base + ncp2;
	basep2 = base + ncp3;

	DetourFunc((PBYTE) baseentry, (PBYTE) AsmOn);
}
Wieso sind die Adressen falsch?
Zuerst dachte ich im GetModuleHandle(NULL) liegt der Fehler. Aber dann würde ja der Detour auch nicht funktionieren. Der jmp wird aber richtig gesetzt....
Bitte nochmals um Hilfe :handsdown:
03/01/2012 23:22 Dr. Coxxy#6
die adressen sind deine basep1 und basep2?
die sind ja an bestimmten adressen im speicher und die löst er dann mit dword ptr[adresse] auf und springt dahin?
d.h. z.b. in dem fall
Code:
jmp dword ptr [5AEC334C]
steht an der adresse 5AEC334C dein basep1, also in c praktisch &basep1.
durchs dword ptr [] wirds aufgelöst und es wird zum inhalt von basep1 gesprungen, der "base + ncp2;" sein sollte.
03/01/2012 23:38 MrSm!th#7
Quote:
Originally Posted by Dr. Coxxy View Post
mit nem detour:

Code:
void* DetourFunc(PBYTE src, const PBYTE dst, const int len)
{
	DWORD dwback;
	BYTE* jmp = (BYTE*)malloc(len+5);
	VirtualProtect(jmp, len+5, PAGE_EXECUTE_READWRITE, &dwback);
	VirtualProtect(src, len, PAGE_READWRITE, &dwback);
	memcpy(jmp, src, len);
	jmp += len;
	jmp[0] = 0xE9;
	*(DWORD*)(jmp+1) = (DWORD)(src + len - jmp) - 5;
	src[0] = 0xE9;
	*(DWORD*)(src+1) = (DWORD)(dst - src) - 5;
	for (int i = 5; i < len; i++)
	{
		src[i] = 0x90;
	}
	VirtualProtect(src, len, dwback, &dwback);
	return (jmp - len);
}
der sichert sogar den code, überschreibt die unnötigen bytes mit nops etc., sollte kein großes problem sein, das abzuspecken, wobei dus natürlich auch so lassen kannst.

falls du den code nicht verstehst, ist hier nen tut in dem der aufbau von nem detour relativ detailliert erklärt ist:
[Only registered and activated users can see links. Click Here To Register...]
Dann lieber MS Detours als diese schreckliche Funktion, die schon seit Ewigkeiten im Netz kursiert.

Quote:
Code:
DetourFunc((PBYTE) baseentry, (PBYTE) AsmOn);
Das dürfte so gar nicht funktionieren, du hast den 3. Parameter vergessen.
03/01/2012 23:56 link#8
Ersetz das dword ptr mal mit eckigen Klammern. Das ist nämlich die eigentliche Schreibweise und Funktion.

Eckige Klammern bedeuten einen Speicherzugriff, damit holt man also Werte aus Variablen bzw. Werte, die an den angegebenen Adressen stehen.

Code:
mov eax,[basepb] ; Wert der Variable basepb wird in EAX kopiert | eax = 011E5E88
mov eax,[eax]    ; ist gleich [I]mov eax,[011E5E88][/I]
mov eax,[eax+04]
; ...
03/01/2012 23:58 Dr. Coxxy#9
Quote:
Dann lieber MS Detours als diese schreckliche Funktion, die schon seit Ewigkeiten im Netz kursiert.
was ist an dieser funktion auszusetzen, wenn man was gegen ms-detours hat?
und warum die ganze ms-detours lib, wenn man eigtl nur einen jmp reinschreiben will?

Quote:
Das dürfte so gar nicht funktionieren, du hast den 3. Parameter vergessen.
nehme mal an, er wird meinen oben erwähnten tipp beherzigt haben und hat die funktion auf seine bedürfnisse abgespeckt.

Quote:
Ersetz das dword ptr mal mit eckigen Klammern. Das ist nämlich die eigentliche Schreibweise und Funktion.

Eckige Klammern bedeuten einen Speicherzugriff, damit holt man also Werte aus Variablen bzw. Werte, die an den angegebenen Adressen stehen.
das dürfte keinen unterschied machen, die eckigen klammern sind optional.
03/02/2012 14:52 Nightblizard#10
Quote:
Originally Posted by Dr. Coxxy View Post
was ist an dieser funktion auszusetzen, wenn man was gegen ms-detours hat?
Folgendes:
Nehmen wir mal an die ersten fünf Bytes der Funktion sind eine jump Anweisung (z.B. weil die Funktion bereits gehooked wurde):

Code:
jmp 0A00h
Die oben genannte Funktion kopiert den Teil 1 zu 1 in einen anderen Bereich des Speichers ändert jedoch nicht die Adresse des jumps (diese sind relativ zu ihrer Adresse im Speicher).
Stand der Code vorher an der Position 0xA000 so müsste das Programm an die Stelle 0xAA00 springen. Nach dem Kopieren befindet sich diese Anweisung jedoch z.B. an 0xB000, woraufhin nach 0xBA00 gesprungen wird. Im besten Fall steht da ein INT 3 und du merkst, dass das schief gelaufen ist, doch im schlimmsten Fall läuft das einfach weiter ohne dass du etwas merkst. Das zu debuggen ist kein Spaß, verlass' dich drauf!
MS Detours berechnet die Adresse neu und erspart dir somit Zeit und Nerven! Die von dir gepostete Funktion ist eine Zeitbombe.
03/02/2012 16:48 link#11
Quote:
Originally Posted by Nightblizard
Das zu debuggen ist kein Spaß, verlass' dich drauf!
Das zu debuggen ist ein Kinderspiel... wenn du merkst, dass dein Hook einen Crash verursacht, entfernst du erst einmal jeglichen Code aus deinem Hook, um zu schauen, ob wenigstens das Skeleton funktioniert.
Wird es nicht, also attachst du den Debugger und verfolgst den JMP zu deinem Code und dann einen CALL/JMP zum überschriebenen Code, der dann in's Nirvana springt. Wer hier nicht mehr weiter weiß, sollte vermutlich auch nicht mit MS Detours herumhantieren.

Außerdem hookt der TE keine Funktion, sondern speziellen Code in einer Funktion, heißt er weiß schon, welchen Code er überschreibt.

Zur Not kann man den JMP auch selber fixen:

Code:
00DBFBFE - E9 2BFDFFFF - JMP 00DBF92E
;...
00DBFC18 - E9 XXXXXXXX - hier soll der gleiche JMP hin

pSrc = (BYTE *)0x00DBFBFE;
pDest = (BYTE *)0x00DBFC18;
dwOffset = *(DWORD *)(pSrc+1);
dwOffset += pSrc;
dwOffset -= pDest;
*(DWORD *)(pDest+1) = dwOffset;
Quote:
Originally Posted by Dr. Coxxy
die eckigen klammern sind optional
In MASM schon. Es ist allerdings schlechter MASM-Stil und außerdem habe ich den Code um ein mov eax,[eax] erweitert, was wohl der Fehler sein wird, da im originalen Code 011E5E88 ein Pointer auf einen Pointer ist und er in seinem Code nicht den Wert des Pointers als zweiten Pointer nimmt, sondern den Pointer selber.
03/02/2012 17:12 MrSm!th#12
Quote:
Originally Posted by Dr. Coxxy View Post
was ist an dieser funktion auszusetzen,
Sie ist unkomfortabel, sie ist nicht threadsafe, sie beachtet die erwähnten Jumps nicht, ...
Quote:
wenn man was gegen ms-detours hat?
Das ist, als würdest du sagen "ich schreib meine eigen string Klasse, ist viel viel besser als std::string :mofo:".

Ich weiß, du als C Coder musst immer von allem dem Hintergrund kennen und kannst nicht wie dier verwöhnten C++ Coder einfach mal was hinnehmen (zum Lernen des Prinzips von Detours ist die Funktion btw. ja ok, aber nicht zur Benutzung), aber MS hat es weit besser gemacht, als es bei dieser Funktion der Fall ist.
Und auch vermutlich weit besser, als die meisten anderen Versuche von Detours Libs, darunter auch deine.

Was gibt es an MS Detours auszusetzen?
Quote:
und warum die ganze ms-detours lib, wenn man eigtl nur einen jmp reinschreiben will?
Warum nicht? Die Hilfsfunktionen kann man immer mal brauchen.
Quote:
Das zu debuggen ist ein Kinderspiel
Lieber gleich die Fehlerursache vermeiden :rolleyes:
03/03/2012 20:14 Paranoiaaa123#13
Quote:
link:
mov eax,[basepb] ; Wert der Variable basepb wird in EAX kopiert | eax = 011E5E88
mov eax,[eax] ; ist gleich mov eax,[011E5E88]
Du hattest recht, dass habe ich übersehen - Hier lag der Fehler.
Danke @ all!