Leute ich bin´s mal wieder mit einem API-Problem!

Windowsspezifisches Forum , API ,..
Beiträge, die plattformübergreifend sind, gehören ins 'Allgemein'-Forum.
whitelion
Beiträge: 46
Registriert: 05.05.2008 18:16
Wohnort: Celle
Kontaktdaten:

Leute ich bin´s mal wieder mit einem API-Problem!

Beitrag von whitelion »

hiho,
ich weiss dass ich eure nerven schon ganz gut strapaziert habe, aber ich denke, dass ich jetzt schon ein ganzes stück weiter bin. - zumindest aus meiner sicht! vielen dank an dieser stelle schonmal für eure geduld und hilfe! Leider ist mein vorhaben offensichtlich nicht gerade das, mit dem man anfangen sollte, aber ich bin hoffnungsfroh das ganze bald abgeschlossen zu haben.

Also, mein ziel ist es ja einen laufenden prozess an verschiedenen stellen zu patchen, welcher nicht erst durch PB aufgerufen wird. Das menü bzw die oberfläche drumherumzulegen sehe ich anhand der tutorials nicht als große schwierigkeit an. für den kern fehlt mir allerdings noch etwas... quasi die kernkompetenz :-P

ok, jetzt zur sache: wie ihr seht ist das beispiel recht simpel bzw beim lesen der remarks verständlich. leider fehlen mir noch einige dinge:

1. ich bekomme es einfach nicht hin per WriteProcessMemory überhaupt irgendwas an die gewünschte stelle zu schreiben!

2. die geschriebenen werte würde ich gerne in hexa angeben, was aber nicht funktioniert, der wert "NeuerHexwert1" wird immer in eine dezimalzahl umgwandelt. (vermutlich gibt´s eine einfache lösung)?

3. ich würde gerne mehr als 4 bytes lesen und schreiben können!! leider geht´s irgenwie nicht, denn meine wenn ich mehr als 4 bytes auslesen möchte, zeigt meine fehlerkontrolle diese nicht an :-(

4. am liebesten würde ich nach hexwerten (unbegrenze anzahl) im prozess suchen lassen und diese mit neuen plazieren! - aber vorerst wäre ich zufrieden wenns überhaupt erstmal geht.

Code: Alles auswählen

Achtung! MineSweeper sollte vorher gestartet werden
;Diese Programm verweist auf den Offset des Strings bzw Fenstertitel "Benutzerdefiniertes Spiel" welcher über 
;das Menü / Spiel / Benutzerdefiniert aufgerufen werden kann! - Als Beispiel wollte ich versuchen
;den String zu ändern! Leider läufts noch nicht so!

;Variablen für die Zielapplikation
Prozessname.s = "winmine.exe"
StartLeseOffset1 = $0101E23A
NeuerHexwert1 = $1111

;Läuft alle Prozesse durch und sucht nach "Prozessname"
ExamineProcesses()
While NextProcess()
  If GetProcessName()=Prozessname
    ProgID = GetProcessPID()
  EndIf
Wend

;Öffnen der Commandline für Ausgabe
OpenConsole()

;Zeigt ProzessID
PrintN("Prozess ID:"+Str(ProgID))
Delay(5000)

;Lesen der Speicherstelle per API
ProcessHandle = OpenProcess_(#PROCESS_ALL_ACCESS, #False, ProgID)
ReadProcessMemory_(Processhandle, StartLeseOffset1, @Zeit, 4, 0)
PrintN("Zeit bzw alter Hexwert VOR schreiben:"+Str(Zeit))

;Simple Schleife zum Debuggen/Fehlersuche
x = 10
Repeat 
PrintN("Neuer Wert wird gleich geschrieben:"+Str(NeuerHexwert1))

;Schreiben der Speicherstelle
WriteProcessMemory_(Processhandle, StartLeseOffset1, NeuerHexwert1, 4, 0)
PrintN("wurde geschrieben...")
Delay(2000)
ReadProcessMemory_(Processhandle, StartLeseOffset1, @Zeit, 4, 0)
PrintN("Lese ob Zeit bzw. alter Hexwert durch neuen ersetzt ist ?:"+Str(Zeit))
Delay(5000)
x-1
Until x = 0

__________________________________________________
Thread verschoben
25.05.2008
Anfänger>APIs
RSBasic
Zuletzt geändert von whitelion am 25.05.2008 19:43, insgesamt 1-mal geändert.
...das leben ist wie ein schlechtes adventure-game, aber die grafik ist verdammt geil!
Benutzeravatar
RSBasic
Admin
Beiträge: 8047
Registriert: 05.10.2006 18:55
Wohnort: Gernsbach
Kontaktdaten:

Beitrag von RSBasic »

@whitelion
Wenn du ein API-Problem hast, wieso nicht gleich -> API-Forum?
Verschieb...
Benutzeravatar
Helle
Beiträge: 566
Registriert: 11.11.2004 16:13
Wohnort: Magdeburg

Beitrag von Helle »

So geht´s mit WinMine unter XP (das Programm wird hier mit PB gestartet; muß nicht sein):

Code: Alles auswählen

;Beispiel für WinMine (Windows XP)
;erstmal das Programm starten und dessen Programm-Handle ermitteln 
SystemDir$ = Space(255) 
FileL = GetSystemDirectory_(SystemDir$, 255) 
WinMineDir$ = Left(SystemDir$, FileL) + "\winmine.exe" 
hProgram = RunProgram(WinMineDir$, "", GetCurrentDirectory(), #PB_Program_Open) 
;damit die Programm-ID ermitteln; ist die, die auch der Task-Manager anzeigt (variabel!!!)
ProgID = ProgramID(hProgram) 
;jetzt das Ganze für Vollzugriff öffnen
ProcessHandle = OpenProcess_(#PROCESS_ALL_ACCESS, #False, ProgID) 
;Adresse festlegen 
StartLeseAdresse = $100579C  ;Spielzeit-Abspeicher-Adresse für Windows XP                                   

While ProgramRunning(hProgram)
  ReadProcessMemory_(Processhandle, StartLeseAdresse, @Zeit, 4, @Anzahl)
         ;StartLeseAdresse ist der Beginn des auszulesenden Speicherbereiches
         ;in (@)Zeit werden die ausgelesenen Bytes abgespeichert
         ;4 ist die Anzahl der zu lesenden (schreibenden) Bytes 
         ;in (@)Anzahl wird die Anzahl der tatsächlich gelesenen Bytes abgespeichert. Kann auf Null gesetzt werden, wenn uninteressant
    Debug "ProgID        =    " + Str(ProgId)
    Debug "Anzahl        =    " + Str(Anzahl) 
    Debug "Zeit          =    " + Str(Zeit)
    Debug "--------------------------------------"
    Delay(1000) 
  PokeL(@Zeit, $63)           ;Zeit zum Test auf 99dez. setzen, für Aktualisierung der Grafik selber sorgen! 
  WriteProcessMemory_(Processhandle, StartLeseAdresse, @Zeit, 4, #Null) 
Wend
Die Zeitanzeige von WinMine muß hier von Hand aktualisiert werden (mal ein Fenster drüberschieben oder mal minimieren/maximieren oder...).
Größere Bereiche eben mittels Schleife auslesen usw.

Gruß
Helle
whitelion
Beiträge: 46
Registriert: 05.05.2008 18:16
Wohnort: Celle
Kontaktdaten:

Beitrag von whitelion »

@RSBasic
sorry, ich dachte es wäre mehr Anfänger als API :-)

@Helle
danke für dein Beispiel, allerdings nützt es mir nicht wirklich viel, denn ich verstehe nicht warum bei mit das schreiben mit writeprozessmemory (Auch wenn es in deinem beispiel enthalten ist) in meinem code einfach nicht funktioniert.

weiterhin lässt es acuh die von mir gestellten fragen 2 - 4 offen.

wäre nett wenn du nochmal gucken könntest! - danke!

EDIT: ich hab nochmal intensiv nachgedacht und frage mich ob mein eingeschlagener weg über prozesswritememory überhaupt zu längeren patches ausreichend ist. schließlich sind 4 byte ja 32 bit und füllen somit ein register aus. von daher stellt sich die frage ob ich mit anderen methoden arbeiten muss um längere strings zu patchen?
aber natürlich interessiert mich weiterhin warum meine variante nicht den speicher beschreibt!
...das leben ist wie ein schlechtes adventure-game, aber die grafik ist verdammt geil!
Benutzeravatar
Helle
Beiträge: 566
Registriert: 11.11.2004 16:13
Wohnort: Magdeburg

Beitrag von Helle »

Die Parameter Zeit bzw. NeuerHexwert1 müssen Speicheradressen sein! @Variable bedeutet Speicheradresse der Variable, nicht der Wert! Der Wert wird in diesen Speicherbereich geschrieben. Die 4 als Parameter bedeutet 4 Bytes lesen oder schreiben, wenn du mehr (Strings) schreiben willst, gib die Speicheradresse des Strings an. Willst du mehrere DWords o.ä. schreiben, reserviere Speicher und fülle diesen mit den Werten (AllocateMemory gibt die Speicheradresse zurück).
Zur Anzeige von Hex-Zahlen verwende Hex() und nicht Str():

Code: Alles auswählen

;Beispiel für WinMine (Windows XP)
;erstmal das Programm starten und dessen Programm-Handle ermitteln 
SystemDir$ = Space(255) 
FileL = GetSystemDirectory_(SystemDir$, 255) 
WinMineDir$ = Left(SystemDir$, FileL) + "\winmine.exe" 
hProgram = RunProgram(WinMineDir$, "", GetCurrentDirectory(), #PB_Program_Open) 
;damit die Programm-ID ermitteln; ist die, die auch der Task-Manager anzeigt (variabel!!!)
ProgID = ProgramID(hProgram) 
;jetzt das Ganze für Vollzugriff öffnen
ProcessHandle = OpenProcess_(#PROCESS_ALL_ACCESS, #False, ProgID) 
;Adresse festlegen 
NeuerHexwert1 = $111         ;nur wegen Anzeige verkleinert  =273dez.
StartLeseOffset1 = $100579C  ;Spielzeit-Abspeicher-Adresse für Windows XP 
OpenConsole() 

;Zeigt ProzessID 
PrintN("Prozess ID:"+Str(ProgID)) 
Delay(5000) 

;Lesen der Speicherstelle per API 
ProcessHandle = OpenProcess_(#PROCESS_ALL_ACCESS, #False, ProgID) 
ReadProcessMemory_(ProcessHandle, StartLeseOffset1, @Zeit, 4, @Anzahl) 
PrintN("Zeit bzw alter Hexwert VOR schreiben:"+Str(Zeit)) 

;Simple Schleife zum Debuggen/Fehlersuche 
x = 10 
Repeat 
PrintN("Neuer Wert wird gleich geschrieben:"+Hex(NeuerHexwert1)) 

;Schreiben der Speicherstelle 
WriteProcessMemory_(Processhandle, StartLeseOffset1, @NeuerHexwert1, 4, 0) 
PrintN("wurde geschrieben...") 
Delay(2000) 
ReadProcessMemory_(Processhandle, StartLeseOffset1, @Zeit, 4, 0) 
PrintN("Lese ob Zeit bzw. alter Hexwert durch neuen ersetzt ist ?:"+Hex(Zeit)) 
Delay(5000) 
x-1 
Until x = 0
Gruß
Helle
whitelion
Beiträge: 46
Registriert: 05.05.2008 18:16
Wohnort: Celle
Kontaktdaten:

Beitrag von whitelion »

super, danke helle.... mir ist schon einiges klarer. :-)

ich habe jedoch noch 3 fragen:

- wenn ich vista verwenden würde, wäre dann die zu modifizierende speicheradresse eine andere oder warum hast du so betont für "win xp" hintergeschrieben ? - ich würde ja schon gerne haben das es kompatibel ist, wenn man z.B. eine exe oder dll modifizieren muss. kann es sein, dass vista wegen des geschützten speichermanagementes eine andere adresse zuweist ? mir ist es wichtig, wenn ich nen trainer schreibe dass das auch bei vista funktionert... dazu kann man ja die speicheradressen aus den pointern ermitteln bzw den asm programmcode modifizieren, wobei selbiger ja vermutlich auch unter vista die gleiche adresszuweisung haben wird? was ist nun zu tun ? - variablen anhand der asm pointer erörtern oder lieber programmcode modden ?

- wenn ich (wie in meinem ersten beilspiel ausprobiert) den wert: StartLeseOffset1 = $0101E23A ; das "B" also hex "42" von Benutzerdefinierte
wenn ich das patchen will gelingt es mit einfach nicht ! der wert bleibt immer der gleiche! - die rückggabe liest auch immer den alten wert aus! - warum ???? (mit Winhex im Ram gehts problemlos!)

- wenn ich nun mal einen langen hexwert schreiben möchte hab ich noch nicht ganz kappiert, dann gehe ich wie vor ? hast du da ein noch beispiel ?
(am liebsten hätte ich ja eine hex search & replacefunktion, aber dazu bin ich noch zu sehr noob))

vielen dank schonmal für die mühe mit mir !
...das leben ist wie ein schlechtes adventure-game, aber die grafik ist verdammt geil!
whitelion
Beiträge: 46
Registriert: 05.05.2008 18:16
Wohnort: Celle
Kontaktdaten:

Beitrag von whitelion »

hat denn keiner antworten ?
...das leben ist wie ein schlechtes adventure-game, aber die grafik ist verdammt geil!
Benutzeravatar
Helle
Beiträge: 566
Registriert: 11.11.2004 16:13
Wohnort: Magdeburg

Beitrag von Helle »

Hey, du kleiner Drängler :mrgreen: ! Heute war c´t-Tag; d.h. ich kaufe mir die aktuelle c´t und hocke mich in einen Biergarten zum lesen und halbe Liter schlucken (Reihenfolge beliebig austauschbar). Habe eben noch schnell was erstellt; s.u.
Welche Speicheradresse in welchem OS von welchem Prog was enthält kann ich nicht sagen (musste selbst rauskriegen).
Wenn das Rückschreiben nicht funktioniert sind es mit hoher Wahrscheinlichkeit keine Variablen, die du ändern willst (data-sections sind eigentlich immer read-write). Das lässt sich natürlich auch aushebeln, aber in diesem Forum ist dies kein Thema. Für einen Trainer sollte man sich auf die Variablen konzentrieren.

Code: Alles auswählen

;Beispiel für WinMine (Windows XP)
;Speicher zum Auslesen mehrerer Bytes reservieren, hier 50 Bytes
Buffer = AllocateMemory(50)  ;Buffer ist schon die Speicher-Adresse!
SystemDir$ = Space(255) 
FileL = GetSystemDirectory_(SystemDir$, 255) 
WinMineDir$ = Left(SystemDir$, FileL) + "\winmine.exe" 
hProgram = RunProgram(WinMineDir$, "", GetCurrentDirectory(), #PB_Program_Open) 
;damit die Programm-ID ermitteln; ist die, die auch der Task-Manager anzeigt (variabel!!!)
ProgID = ProgramID(hProgram) 
;jetzt das Ganze für Vollzugriff öffnen
ProcessHandle = OpenProcess_(#PROCESS_ALL_ACCESS, #False, ProgID) 
;Adresse festlegen 
StartLeseOffset1 = $0101E23a ;also Strings von WinMine. Dürften im Quellcode in einer Nur-Read-Section liegen 
;in den reservierten Speicher lesen wir ab der Start-Adresse 50 Bytes ein
ReadProcessMemory_(Processhandle, StartLeseOffset1, Buffer, 50, 0) 
;Anzeige des Original-Textes, Unicode!!
Debug PeekS(Buffer, 50, #PB_Unicode)
;jetzt manipulieren wir den Text im Speicher
PokeC(Buffer, 98)  ;98 oder $62 = "b". Check auf Unicode sollte vorher erfolgen. Wenn
    ;in einem Deutsch-Sprachigem Programm bei Texten jedes 2.Zeichen den (echten) Wert Null
    ;hat, kann davon ausgegangen werden, das Unicode vorliegt.   
;und schreiben ihn zurück
If WriteProcessMemory_(ProcessHandle, StartLeseOffset1, Buffer, 50, #Null) 
  ;und lesen ihn wieder aus
  ReadProcessMemory_(ProcessHandle, StartLeseOffset1, Buffer, 50, 0) 
  ;Anzeige des geänderten (?) Textes
  Debug PeekS(Buffer, 50, #PB_Unicode)
 ;oder das Rückschreiben schlug fehl
 Else 
  Debug "Mist!"
 ;jetzt (viel zu spät, testet man natürlich vorher) checken wir den Zugriffs-Status
 ; auf die gewählte Speicheradresse. Das "PROCESS_ALL_ACCESS" bei OpenProcess garantiert
 ; keinen automatischen Schreibzugriff! Priorität hat die Section-Read-Write-Zuordnung
 ; des Source-Codes!      
 ;Structure MBI definieren; siehe auch Strukturverzeichnis von PB! 
 ;PAGE_READONLY = 2     sind im Protect-Status die interessierenden Werte 
 ;PAGE_READWRITE = 4    teste mal mit Speicheradresse von Zeit!
  MBI.MEMORY_BASIC_INFORMATION
 ;Status-Informationen einholen 
  VirtualQueryEx_(ProcessHandle, StartLeseOffset1, MBI, SizeOf(MEMORY_BASIC_INFORMATION))
  Status = MBI\Protect
  Debug "Speicher-Zugriffs-Status = " + Str(Status)
  If Status = 2    ;also nur READONLY
    Debug "Vergiss es vorerst !"   
   Else 
    Debug "Hmmmm...."
  EndIf  
EndIf
Gruß
Helle
whitelion
Beiträge: 46
Registriert: 05.05.2008 18:16
Wohnort: Celle
Kontaktdaten:

Beitrag von whitelion »

hi, danke und sorry für meine ungeduld :-) ich hab das beispiel noch nciht getestet(mach ich gleich), aber da ich in der zwischenzeit etwas recherchiert habe, fand ich folgendes:
-----
Windows Vista introduces protected processes to enhance support for Digital Rights Management. The system restricts access to protected processes and the threads of protected processes.

The following standard access rights are not allowed from a process to a protected process:

DELETE
READ_CONTROL
WRITE_DAC
WRITE_OWNER

The following specific access rights are not allowed from a process to a protected process:

PROCESS_ALL_ACCESS
PROCESS_CREATE_PROCESS
PROCESS_CREATE_THREAD
PROCESS_DUP_HANDLE
PROCESS_QUERY_INFORMATION
PROCESS_SET_INFORMATION
PROCESS_SET_QUOTA
PROCESS_VM_OPERATION
PROCESS_VM_READ
PROCESS_VM_WRITE
------

das heisst ja, dass man sowieso keinen zugriffe auf geschützte prozesse unter vista hat :-( so ein mist !!!!

ich habe nämlich für ein freewaregame in der codesection die offsets ausgemacht die zu patchen wären bei unendlich leben...etc. an dieser stelle frage ich mich, warum nicht selbige patchen !???? wäre doch einfacher oder ?
außerdem ab wann ist denn überhaupt ein prozess unter vista protected ? oder trifft das eh nur ganz selten oder für sicherheitsprodukte zu wäre es ja nicht so schlimm oder ? was ist überhaupt so schlimm in der codesection zu patchen kommt man doch beim appz-reversen oft gar nicht drumherum! und es gibt auch ne menge prozesspatcher!

nerv :-)

EDIT: verdammt, ich hab mich schon durch die APIs gelesen und hatte versucht den zugriffsstatus zu ändern per:VirtualProtectEx_(ProcessHandle, @StartLeseOffset1, 4, ProgID, 0)
ging natürlich nciht :-) aber zumindest hatte ich schonmal unabhängig von dir den gleichen API befehl gefunden.

EDIT2: VirtualProtectEx_(ProcessHandle,StartLeseOffset1,4,#PAGE_EXECUTE_READWRITE ,#Null) <- ich glaube es wird wärmer :-)

EDIT3: son shit ... ich komme nicht weiter im moment

EDIT4: ich versteh deinen code an der stelle nicht:

Code: Alles auswählen

  ReadProcessMemory_(ProcessHandle, StartLeseOffset1, Buffer, 50, 0)
  ;Anzeige des geänderten (?) Textes
  Debug PeekS(Buffer, 50, #PB_Unicode) <--- enthält die geänderten daten trotz fehlgeschalgenem schreibversuch!???
 ;oder das Rückschreiben schlug fehl 
Die Rückgabe des Buffers ist die neue, also geänderte! - Ich versteh deinen remark aber so, dass wenn dort was geändert wurde, auch erfolgreich geschrieben wurde! - was aber nicht der fall ist! also der debug gibt die neue variante zurück, aber schreiben schlug fehl? - kleiner fehler im code ?
...das leben ist wie ein schlechtes adventure-game, aber die grafik ist verdammt geil!
Benutzeravatar
Helle
Beiträge: 566
Registriert: 11.11.2004 16:13
Wohnort: Magdeburg

Beitrag von Helle »

Buffer ist separater Speicher, in den ich die ausgelesenen Werte zwischenspeichere, dort verändere und dann zurückschreibe. Kann man natürlich auch direkt erledigen, wird bei Strings aber vielleicht unübersichtlich.
Da du mit VirtualProtectEx nun doch auf der richtigen Spur bist, hier die Lösung: Füge vor dem Schreiben

Code: Alles auswählen

VirtualProtectEx_(ProcessHandle, StartLeseOffset1, 50, #PAGE_EXECUTE_READWRITE , @A)
ein; A ist eine normale Long-Variable.

Gruß
Helle
Antworten