Como ya conocía bien donde andan las rutinas de tiradas de dados solo había que volver a revisarlas y localizar los registros:
CODE:00475204 ObtieneNumeroDados: ; CODE XREF: sub_475184+C3j
CODE:00475204 mov eax, 6
CODE:00475209 call XXX_Random
CODE:0047520E mov ebx, eax
CODE:00475210 inc ebx
CODE:00475211 mov eax, 6
CODE:00475216 call XXX_Random
CODE:0047521B mov esi, eax
CODE:0047521D inc esi
CODE:0047521E mov eax, 6
CODE:00475223 call XXX_Random
CODE:00475228 inc eax
CODE:00475229 mov [ebp+var_C], eax
CODE:0047522C lea eax, [esi+ebx]
CODE:0047522F cmp eax, 7
CODE:00475232 jnz short loc_475249
CODE:00475234 mov eax, ds:off_4A9C90
CODE:00475239 cmp byte ptr [eax+37h], 0
CODE:0047523D jz short loc_475249
CODE:0047523F mov eax, ds:off_4A9EE8
CODE:00475244 cmp dword ptr [eax], 3
CODE:00475247 jle short ObtieneNumeroDados
Si observamos hay tres llamadas a XXX_Random que son las tres tiradas de dados, la primera para el tipo de turno en el modo de juego de caballeros y las 2 siguientes los dos dados de juego. Los valores tras hacer unas tiradas y revisar los valores de los registros con el ollydbg se almacenan respectivamente en los registros EAX, EBX y ESI. Si lo que queremos es modificar los dados hemos de modificar los registros anteriores en la posición CODE:00475229.
Para ello preparamos un script que hará uso del PyDbg para engancharse al proceso wancatan.exe y colocar un breakpoint en lap posición 0x475229:
def modificaDados(dbg):
global dado1,dado2,dado3,modificar
if modificar:
print 'Modificando dados (%d,%d,%d)' % (dado1,dado2,dado3)
dbg.set_register('EAX', dado1)
dbg.set_register('EBX', dado2)
dbg.set_register('ESI', dado3)
return pydbg.DBG_CONTINUE
...
dbg.attach(pid)
dbg.bp_set(0x475229, handler=modificaDados)
dbg.run()
El funcionamiento como se ve es muy simple y extremadamente eficaz, le he hechado un ratillo y lo he montado sobre las wxPython para modificar a placer mediante una ventanita ;)
El código completo (requiere pydbg, ctypes y wxpython):
#C:/Python24/python.exe
# -*- coding: utf-8 -*-
import pydbg, sys, struct, wx
from threading import Thread
modificar=0
dado1,dado2,dado3=(1,1,1)
#------------------------------------------------------------------------------
# Interfaz gráfico
class selector(wx.Panel):
def __init__(self, parent, id):
wx.Panel.__init__(self, parent, id)
rango=['1','2','3','4','5','6']
self.cb = wx.CheckBox(self, -1, "Activar trucaje")
self.ch1 = wx.Choice(self, 1, choices = rango)
self.ch2 = wx.Choice(self, 2, choices = rango)
self.ch3 = wx.Choice(self, 3, choices = rango)
self.Bind(wx.EVT_CHOICE, self.EvtChoice, self.ch1)
self.Bind(wx.EVT_CHOICE, self.EvtChoice, self.ch2)
self.Bind(wx.EVT_CHOICE, self.EvtChoice, self.ch3)
self.Bind(wx.EVT_CHECKBOX, self.EvtCheckBox, self.cb)
border = wx.BoxSizer(wx.VERTICAL)
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.AddMany( [ self.ch1, self.ch2, self.ch3 ] )
border.Add(self.cb, 0, wx.ALL, 15)
border.Add(sizer, 0, wx.LEFT, 50)
self.SetSizer(border)
def EvtChoice(self, event):
global dado1,dado2,dado3
if event.GetId() == 1: dado1=int(event.GetString())
elif event.GetId() == 2: dado2=int(event.GetString())
elif event.GetId() == 3: dado3=int(event.GetString())
def EvtCheckBox(self, event):
global modificar
modificar=event.IsChecked()
class MyFrame(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, -1, title, size=(200, 100))
self.selector=selector(self,-1)
class MyApp(wx.App):
def OnInit(self):
frame = MyFrame(None, "WanCatan Dados")
self.SetTopWindow(frame)
frame.Show(True)
return True
def OnExit(self):
global dbg
dbg.detach()
class Hebra(Thread):
def run(self):
app = MyApp(0)
app.MainLoop()
#------------------------------------------------------------------------------
# Funciones del debbuger
def busca_pid(dbg, nombre):
for pid,proc in dbg.enumerate_processes():
if proc.lower() == nombre.lower(): return pid
return -1
def modificaDados(dbg):
global dado1,dado2,dado3,modificar
if modificar:
print 'Modificando dados (%d,%d,%d)' % (dado1,dado2,dado3)
dbg.set_register('EAX', dado1)
dbg.set_register('EBX', dado2)
dbg.set_register('ESI', dado3)
return pydbg.DBG_CONTINUE
#------------------------------------------------------------------------------
# Principal
if __name__ == '__main__':
global dbg
dbg=pydbg.pydbg()
proceso = "wancatan.exe"
pid = busca_pid(dbg, proceso)
if pid < 0:
print 'Proceso %s no encontrado' % proceso
sys.exit(0)
# Arrancamos el interfaz gráfico
w = Hebra()
w.start()
print "Enganchando %s(%d)" % (proceso, pid)
dbg.attach(pid)
dbg.bp_set(0x475229, handler=modificaDados)
dbg.run()
Tags: python debugger pydbg cheat
comentarios:
Publicar un comentario