[c++] class methoden callen

04/28/2012 04:21 Tyrar#1
da bei vielen hacks klassen methoden gecalled werden müssen und das meistens so in die richtung aussieht:
Code:
mov ecx, 0x13371337
mov eax, 0x13371337
call eax
und das meiner meinung nach doch recht unübersichtlicht ist arbeite ich lieber auf folgende weise:

Code:
#define CLASSCALL(addr) \ // macro definieren
__asm { mov esp, ebp } \ // stack wieder herstellen
__asm { pop ebp } \ // base pointer wieder herstellen
__asm { mov eax, addr } \ // die adresse in eax schieben
__asm { jmp eax } // an die adresse springen
an sich recht simpel:
stack pointer und base pointer zurücksetzen, zur eigentlichen funktion springen :)

kleines anwendungs beispiel
Code:
class CItem
{
public:
    CItem() { CLASSCALL(0x13371337); }; // 0x13371337 ist hier die adresse zum echten constructor im game!
    ~CItem() { CLASSCALL(0x13371337); }; // das gleiche wie oben, nur dass es hier um den destructor geht!

    void SetPosition(float x, float y, float z) { CLASSCALL(0x13371337); }; // hier wird die SetPosition methode gecalled :)
};
so würden in etwa die klassen aussehen, wie man sie ingame verwenden kann!

die richtige verwendung sieht etwa so aus:
Code:
void Hack(uint32_t itemptr)
{
    CItem* item=(CItem*)itemptr; // class pointer, kommt mir nich mit c++ casts! :p
    // wenn ihr die player position habt, könnte man items zum player bewegen
    // in dem fall wird nur das item an 0,0,0 bewegt :)
    item->SetPosition(0.0f,0.0f,0.0f);
}
wie schon gesagt, meiner meinung nach schöner und übersichtlicher :)

da es sich hier nicht um ein anfänger tutorial handelt, gibts nicht mehr zu sagen :)
das verständnis für klassen und asm sollte einfach da sein!

edit: natürlich ist es bei diesem macro wichtig, ihn NUR in class wrappern zu verwenden!
da wie im unteren post schon erwähnt, jmp direkt an die adresse springt!
04/28/2012 13:53 MrSm!th#2
Funktionspointer ftw. :rolleyes:
So geschieht es auch meistens, weiß ja nicht, wo du verkehrst, wo inline asm dafür genutzt wird und das auch noch auf diese Weise.
Parameter kannst du ja auch nur per asm ändern, na viel Spaß.

Weiß nicht, wie man sowas schön finden kann :x

Nur als Hinweis, dein inline asm neigt leider (wie fast jede inline asm Sequenz), dass sie sehr abhängig und unflexibel ist. Was machst du, wenn die Funktion keine __stdcall Funktion ist?

Außerdem wäre ein bisschen mehr Beschreibung eben schon schön, sonst könntest du einige in die Irre leiten.
Du vergleichst unterschiedlichen Code miteinander. Dein erstes Beispiel ist ein Function Call, d.h. er könnte so an jeder Stelle im Code vorkommen.
Dein Code enthält einen Jump, es ist also zwingend notwendig, dass man dafür eine Wrapper Funktion schreibt, die die Parameter entgegennimmt, damit dann dein Zurücksetzen vom Stackptr klappt (und auch nur, wenn es __stdcall ist) und du zur richtigen Funktion springen kannst.
Außerhalb dieser Wrapper Funktion könnte das Makro so nicht verwendet werden.
Das ist so ein unnötiger Schritt, da sollte man lieber gleich Funktionspointer nutzen oO

Ach ja: C++-Casts
Ne aber mal ernsthaft, wieso in dem Beispiel überhaupt casten? oO Du machst doch nichts anderes als ihn in einen Pointer einer bekannten Klasse zu casten: Warum nicht gleich CItem* als Parametertyp?
04/28/2012 15:53 Tyrar#3
Quote:
Originally Posted by MrSm!th View Post
Funktionspointer ftw. :rolleyes:
So geschieht es auch meistens, weiß ja nicht, wo du verkehrst, wo inline asm dafür genutzt wird und das auch noch auf diese Weise.
Parameter kannst du ja auch nur per asm ändern, na viel Spaß.

Weiß nicht, wie man sowas schön finden kann :x

Nur als Hinweis, dein inline asm neigt leider (wie fast jede inline asm Sequenz), dass sie sehr abhängig und unflexibel ist. Was machst du, wenn die Funktion keine __stdcall Funktion ist?

Außerdem wäre ein bisschen mehr Beschreibung eben schon schön, sonst könntest du einige in die Irre leiten.
Du vergleichst unterschiedlichen Code miteinander. Dein erstes Beispiel ist ein Function Call, d.h. er könnte so an jeder Stelle im Code vorkommen.
Dein Code enthält einen Jump, es ist also zwingend notwendig, dass man dafür eine Wrapper Funktion schreibt, die die Parameter entgegennimmt, damit dann dein Zurücksetzen vom Stackptr klappt (und auch nur, wenn es __stdcall ist) und du zur richtigen Funktion springen kannst.
Außerhalb dieser Wrapper Funktion könnte das Makro so nicht verwendet werden.
Das ist so ein unnötiger Schritt, da sollte man lieber gleich Funktionspointer nutzen oO

Ach ja: C++-Casts
Ne aber mal ernsthaft, wieso in dem Beispiel überhaupt casten? oO Du machst doch nichts anderes als ihn in einen Pointer einer bekannten Klasse zu casten: Warum nicht gleich CItem* als Parametertyp?
in der metin2 section wird oft auf diese weise gearbeitet, was ich einfach unschön finde :)

ich habe bisher bei __stdcall und __cdecl den einzigen unterschied in der ret instruction gesehen, da esp genau so nach ebp geschoben wird!
Code:
cdeclfunc:
push ebp
mov ebp, esp
xor eax, eax
pop ebp
ret

stdcallfunc:
push ebp
mov ebp, esp
xor eax, eax
pop ebp
ret 12
ich verwende das ganze schon etwas länger und hatte NIE probleme mit __cdecl!

der cast in CItem is in dem beispiel natürlich so nicht nötig, mein erster gedanke war auch
Code:
CItem* item=(CItem*)0x13371337;
zu schreiben ;)
04/29/2012 21:22 MrSm!th#4
Quote:
ich habe bisher bei __stdcall und __cdecl den einzigen unterschied in der ret instruction gesehen, da esp genau so nach ebp geschoben wird!
Ist aber nicht der Fall und wie du es schon sagst, ret wird ohne Parameter verwendet.
Der Caller ist für das Aufräumen des Stacks verantwortlich.
Parameter werden über das ESP Register angesprochen.

Desweiteren gehst du nicht auf die anderen genannten Nachteile ein.
04/30/2012 07:31 Tyrar#5
Quote:
Originally Posted by MrSm!th View Post
Ist aber nicht der Fall und wie du es schon sagst, ret wird ohne Parameter verwendet.
Der Caller ist für das Aufräumen des Stacks verantwortlich.
Parameter werden über das ESP Register angesprochen.

Desweiteren gehst du nicht auf die anderen genannten Nachteile ein.
ich kann keine nachteile finden. dass man eine wrapper klasse/funktion braucht ist meiner meinung nach kein nachteil, da man so viel mehr übersicht hat! (das gilt in dem fall für klassen, bei normalen funktionen eignen sich wie du schon sagst eher funktions pointer... aber im titel steht auch 'class methoden' :))

wenn in der executable steht:
Code:
push 1
push 2
push 3
mov ecx, 0x13371337
call cdeclmemberfunc
add esp, 0x0C
; ...

cdeclmemberfunc:
push ebp
mov ebp, esp
mov eax, [esp+8]
xor eax, [esp+12]
xor eax, [esp+16]
pop ebp
retn
man die func allerdings mit der wrapper klasse called, sieht das so aus:
Code:
push 1
push 2
push 3
mov ecx, 0x13371337
call wrapperfunc
add esp, 0x0C
; ...

wrapperfunc:
push ebp
mov ebp, esp
mov esp, ebp
pop ebp
mov eax, cdeclmemberfunc
jmp eax

cdeclmemberfunc:
push ebp
mov ebp, esp
mov eax, [esp+8]
xor eax, [esp+12]
xor eax, [esp+16]
pop ebp
retn
bei __stdcall würde das fast genau so aussehen!


wo es probleme geben würde, wäre __fastcall!
__stdcall und __cdecl funktionieren!
04/30/2012 21:07 MrSm!th#6
Bei stdcall wird kein ebp am Anfang gepusht, versteh es oO

Quote:
ich kann keine nachteile finden. dass man eine wrapper klasse/funktion braucht ist meiner meinung nach kein nachteil, da man so viel mehr übersicht hat!
Wenn ich eine Funktion callen will,will ich nicht extra eine Klasse dafür schreiben müssen.
Wenn man die Übersicht haben will, macht man sie sich, das sollte einem nicht aufgezwungen werden.