Fragen zu DMA und ASM

06/27/2008 19:48 Term!nX#1
Hi,

habe bis jetzt mit statischen Adressen so ein paar Trainer geschrieben, wollte mich jetzt mal an DMA wagen (Testspiel Guild Wars).

Habe einen WriteBP auf die Adresse gesetzt und es breakt hier:

0078D143 897E 10 MOV DWORD PTR DS:[ESI+10],EDI

Dann muss ich schauen, wo ESI aufgefüllt wird, müsste daher nach einer MOV ESI... Instruktion suchen denke ich.

40 Zeilen später oder so:

0078D0DE 8BF1 MOV ESI,ECX

ESI wird durch ECX gefüllt. Also nach einer MOV ECX Instruktion suchen.

100 Zeilen später:

0078CF4F 8B0D E466D300 MOV ECX,DWORD PTR DS:[D366E4]

Eigentlich ein Treffer würde ich sagen.

Darüber steht:
0078CF45 B9 5067D300 MOV ECX,Gw.00D36750

Das versteh ich leider nicht, weiss daher auch nicht obs es überhaupt von belang ist.

Und noch was: Bevor ECX statisch gefüllt wird:

0078CF77 8911 MOV DWORD PTR DS:[ECX],EDX

Aber soweit ich mich mit ASM auskenne (limes 0) wird hier nur ein neues Datenwort gefüllt. Allerdings heist das ja, Quelle rechts in Ziel links. Also EDX in ECX. Müsste ich dann nochmal EDX suchen? Eigentlich ja nicht, sonst müsste das ja MOV ECX, EDX heissen. Hab ich das richtig verstanden so?


Für den Fall, dass ich mich richtig zur statischen Füllung vorgearbeitet habe, müsste ich theoretisch den Wert an D366E4 auslesen. Dann käme MOV ESI,ECX. Dann ist ESI doch == ECX und somit läuft der ganze Zauber auf [Wert von D366E4(==ESI)+0x10] hinaus.

Soweit korrekt oder alles Käse :>

Grüße
06/27/2008 20:24 Bot_interesierter#2
MOV DWORD PTR DS:[ECX],EDX
DWORD PTR DS:[ECX] ist ein Pointer ins Daten Segment wenn ich jetzt nicht toal blöd bin, also wird der Wert von ECX als DWORD an die Adresse geschrieben auf die dieser Ausdruck zeigt ^^
06/27/2008 20:45 Term!nX#3
Ahso danke.
Also wäre dann bei:
0078CF77 8911 MOV DWORD PTR DS:[ECX],EDX

0x78CF77 hätte den Wert von ECX. ECX selbst wird dann aber nicht verändert. Was ist dann EDX?
06/27/2008 21:21 Bosin#4
Quote:
Originally Posted by Bot_interesierter View Post
MOV DWORD PTR DS:[ECX],EDX
DWORD PTR DS:[ECX] ist ein Pointer ins Daten Segment wenn ich jetzt nicht toal blöd bin, also wird der Wert von ECX als DWORD an die Adresse geschrieben auf die dieser Ausdruck zeigt ^^
Das ist falsch.

PHP Code:
MOV DWORD PTR DS:[ECX],EDX 
Hier wird der Wert von EDX in die nächten 4 Bytes der Addresse geschrieben, auf die ECX zeigt.

Wenn du nun auf die Struktur / Klasse zugreifen willst, auf die EDI zeigt, dann kannst du
PHP Code:
0078CF4F 8B0D E466D300 MOV ECX,DWORD PTR DS:[D366E4
benutzen, da diese Instruktion nach deinen Angaben die letzte war, die den Wert von EDI beeinflusste.
06/27/2008 22:25 Term!nX#5
Jetzt bin ich etwas überfordert.

Es pausiert bei:
Code:
0078D143 897E 10 MOV DWORD PTR DS:[ESI+10],EDI
Der Wert von EDI wird auf die nächsten 4 Byte auf die ESI+0x10 zeigt, geschrieben. Dann müsste EDI den Wert der Lebenspunkte haben. ESI+0x10 bildet die Adresse, wo die Lebenspunkte gespeichert werden.
EDI müsste dann eigentlich uninteressant für mich sein, da ich ja nur die Adresse brauche, um von dort auszulesen.
Und inwiefern wird EDI durch meine Codezeilen beeinflusst? Es ist doch eher so, dass EDI in diesem Fall ESI und im Endeffekt ECX beeinflusst.

Wie kann ich eigentlich in ollydbg nach einem command der diesen fraglichen wert 0xD366E4 benutzt suchen? Damit ich prüfen kann, ob der Wert überhaupt statisch ist.
06/27/2008 22:36 Bosin#6
Quote:
Originally Posted by Term!nX View Post
Und inwiefern wird EDI durch meine Codezeilen beeinflusst? Es ist doch eher so, dass EDI in diesem Fall ESI und im Endeffekt ECX beeinflusst.
Ich hab im oberen Post EDI mit ESI verwechselt, ESI ist gemeint.

Quote:
Originally Posted by Term!nX View Post
Wie kann ich eigentlich in ollydbg nach einem command der diesen fraglichen wert 0xD366E4 benutzt suchen? Damit ich prüfen kann, ob der Wert überhaupt statisch ist.
Die Addresse ist statisch und wird nicht vom Programm selbst geändert.
In fact ist das eine globale Variable des Programms, welche vom Compiler immer so aufgerufen werden.
Um herauszufinden, wo auf diese globale Variable zugegriffen wird, machst du einen Rechtsklick auf die "MOV DWORD PTR DS:[ESI+10],EDI" Instruktion und klickst auf "Find references to" -> "Immediate value".

Hier, so könnte es dann aussehen:
PHP Code:
// leichter verständlich
DWORD __declspecnaked GetHealth()
{
    
_asm
    
{
        
MOV EAX,DWORD PTR DS:[D366E4]
        
MOV EAXDWORD PTR DS:[EAX+10]
        
RETN
    
}
}

// später leichter zu handhaben
struct SPlayer
{
    
BYTE bUnknown0x10 ]; // 0x00 - 0x10
    
DWORD dwHealth// 0x10 - 0x14
};

DWORD GetHealth()
{
     
SPlayer pLocal = (SPlayer*)0xD366E4;
     return 
pLocal->dwHealth;
  
    
// oder du schreibst es so
    // return ((SPlayer*)0xD366E4)->dwHealth;

06/27/2008 22:59 wadimwadim#7
Das Leben in Guild Wars ist ein Float type, .... wie möchtest du es denn dir immer wieder holen?
vllt kann das dir helfen
[Only registered and activated users can see links. Click Here To Register...]

Gruß
wadimwadim
06/28/2008 00:22 Adroxxx#8
Hatten wir nicht schon einen großen Thread über das Leben in GW? ^^
06/28/2008 10:54 Term!nX#9
Quote:
Originally Posted by wadimwadim View Post
Das Leben in Guild Wars ist ein Float type, .... wie möchtest du es denn dir immer wieder holen?
vllt kann das dir helfen
[Only registered and activated users can see links. Click Here To Register...]

Gruß
wadimwadim
Wenn das so ist, was finde ich den unter den 2 Adressen, die ich über 4byte int finde?
Denn du hast recht, unter Float finde ich auch 2 Adresse, die liegen aber 4byte auseinander.
Habe den ganzen Quatsch jetzt mal auf ner anderen Maschine gemacht und oh Wunder, ich komme zum selben Ergebnis.
Ich schreib jetzt einfach mal ein Programm drauf los.

Danke für die Hilfe


So:
Code:
  unsigned lpBaseAdress = 0xD366E4;
  int buffer;
  DWORD rw;
  bool read;
  
  unsigned lifeAdress;
  int lifeBuffer;
  DWORD lifeRw;
  bool readLife;

  read = ReadProcessMemory(proc, (LPCVOID)lpBaseAdress, &buffer, sizeof(int), &rw);
  
  if (!read)
  {
      DWORD error = GetLastError();
      cerr << "Read Baseadress fails: " << error;
      Sleep(2000);
      exit(1);
  }
  
  cout << "n" << buffer;
  
  Sleep(3000);
  
  lifeAdress = buffer + 0x10; 
  
  cout << "n" << lifeAdress;

  while (true)
  {
      readLife = ReadProcessMemory(proc, (LPCVOID)lifeAdress, &lifeBuffer, sizeof(int), &lifeRw);
      if (!readLife)
      {
          DWORD error = GetLastError();
          cerr << "Lesen fehlschlag. " << error;
          Sleep(2000);
          exit(1);
      }
      else
      {
          cout << "n" << lifeBuffer;
      }
      Sleep(2000);       
  }
Der Wert der ausgelesen wird ist immer 0. Schade :)

Ich lese also den Wert auf der Basisadresse (0xD366E4) aus. Der wird in buffer gespeichert. Dann errechne ich die Lebensadresse durch buffer + 0x10.
buffer hat übrigens den Wert 78756116. Demnach müsste lifeAfress == 78756132 sein, wie es angezeigt wird.
Dann mache ich auf 78756132 einen read und lass mir den lifeBuffer anzeigen. Leider immer 0.
Muss ich bei der Adressenrechnung alles vorher in Hex umwandeln, oder wird das automatisch gemacht?

grüße

Habe jetzt auch mal mit dem float-type gearbeitet: Breakt aber bei:
Code:
008880D2   D911             FST DWORD PTR DS:[ECX]
Keine Ahnung was das zu bedeuten hat, müsste aber falsch sein, dass es doch eigentlich bei einer MOV anweisung pausieren müsste.
Und die Adressen werden nach ner Minute oder so nutzlos und der Wert wird woander gespeichert.
06/28/2008 19:49 Bot_interesierter#10
@Bosin
Ich meinte genau das was du gesagt hast ^^, eventuell etwas unglücklich formuliert aber darüber kann man hoffentlich hinweg sehen :>
@Term!nX
ein float type ist normal auch 4byte groß, der Unterschied ergibt sich daraus wie man die bytes liest.
FST DWORD PTR DS:[ECX]
Ich denke das pusht die 4 bytes die an der Adresse die in ECX steht stehen auf den float stack, zumindest hab ich die bezeichnung mal so gelesen, das ist son Lifo Ding spezielle für floats mit fstp kann man den ersten wert von diesem Stapel holen.
Edit: du brauchst debug rechte um ReadProcessMemory() zu usen, unterumständen ^^
06/28/2008 23:18 Term!nX#11
Quote:
Originally Posted by Bot_interesierter View Post
@Bosin
Ich meinte genau das was du gesagt hast ^^, eventuell etwas unglücklich formuliert aber darüber kann man hoffentlich hinweg sehen :>
@Term!nX
ein float type ist normal auch 4byte groß, der Unterschied ergibt sich daraus wie man die bytes liest.
FST DWORD PTR DS:[ECX]
Ich denke das pusht die 4 bytes die an der Adresse die in ECX steht stehen auf den float stack, zumindest hab ich die bezeichnung mal so gelesen, das ist son Lifo Ding spezielle für floats mit fstp kann man den ersten wert von diesem Stapel holen.
Edit: du brauchst debug rechte um ReadProcessMemory() zu usen, unterumständen ^^
Also lohnt es sich, nach dem Ursprung vno ECX zu suchen?

debug rechte weiss ich nicht, bei der Basisadresse bekomme ich ja nen Wert. Und der read schlägt nicht fehl.
06/28/2008 23:25 wadimwadim#12
Was willst du denn genau rausfinden?
06/28/2008 23:48 Term!nX#13
Die Frage habe ich jetzt nicht erwartet :) In meiner Anleitung steht, dass man den Ursprung finden soll.
Also wenns bei MOV DWORD PTR DS:[ESI+10] breakt, dann muss ich solange ESI zurückverfolgen, bis ich zu einer statischen Füllung (zB MOV EAX,[3BF2C3]) gelange.


Wo ich jetzt mal bei:
008880D2 D911 FST DWORD PTR DS:[ECX]

ECX-Ursprung zu finden versuche, der geht leider ins Nirvana. Weit über 300 Zeilen jedenfalls.
06/29/2008 11:22 Term!nX#14
Von hinten aufrollen triffts ganz gut.
DMA heisst Dynamic Memory Allocation.

Andere Methoden als dieses von hinten aufrollen kenn ich jetzt nicht, das tut habe ich auf ner anderen Maschine, lad ich später hoch.
06/29/2008 11:47 Azunai#15
hi Term!nX altes haus ^^
kannst du des ganze auch bei gw anwenden? ^^
weil wadim und ich es nach x methoden probiert haben aber keine erfolgreich war -.-