lu51268 发表于 2024-3-13 18:17

python实现大富翁4如意骰子

我是一个初学者,搞的不对的地方请各位大神批评。
此次学习使用python实现大富翁4如意骰子。
先上最终效果

第一步肯定是找地址,我就一次性把所有地址列出来:

1、两个参数是调用撒骰子call时使用的两个参数。
2、存储几颗骰子是存储骰子颗数的地址,类型为字节,改成几是存储几颗,最多有3颗。
3、撒到多少是存储计算后最终撒到几的地址,一个存储结果,一个用来控制向前走。
4、最后骰子地址就是存储骰子撒到几的初始计算值。只有这个地址有偏移,地址为+0c。
通过骰子存储的地址追踪到撒骰子这个动作的调用call,地址为0040D7C4。用OD更好追踪一点,如下图。

分析call的返回处以及调用前的push都没有发现有参数传入。但是直接调用的话程序就崩溃。
使用od下断点,进入call的内部执行发现了两个跳转。
0040D7DA | 0F84 37050000            | je rich4.40DD17                         |
0040D7F6 | 0F87 92000000            | ja rich4.40D88E                         |
查找两个跳转的条件,多次通过单步执行的方式发现直接调用call,需要向498ea2和46cafb两个地址赋值call才能正常执行下去。

多次执行发现两个地址都是固定的值,0和01010100。
之后尝试赋值调用call。成功撒骰子。

汇编代码如下:
mov ,01000101
mov ,2
call 40D7C4
ret
然后存储几颗骰子的地址,改成几就会投几颗骰子。
通过这个地址就找到了计算骰子投到多少的call,地址为00419572。
分析这个call发现骰子的值就是通过这段代码计算,最终把值存在edx后存入,地址是固定的。

分析这个计算方法,后得出如果是2颗或是3颗骰子就是把第一颗计算的第二步的值作为后面的初始值计算。
然后写代码计算出撒1~18每个数值的初始值。
rice_pieces=3
for 初始值 in range(1000):
    count=0
    第一次初始值=初始值
    for i in range(rice_pieces):
      edx=0x41C64E6D*第一次初始值
      edx=edx+0x3039
      if len(str(hex(edx)))<=11:
            下一次初始值=edx
      else:
            下一次初始值=(int(str(hex(edx))[-8:],16))
      print("下一次初始值",hex(下一次初始值))
      第一次初始值=下一次初始值
      eax=edx>>0x10
      eax=eax&0x7FFF
      edx=eax%6
      edx=edx+1
      print("第"+str(i+1)+"次"+"骰子",edx)
      count=count+edx

    print(count)
    if count==18:
      print("初始值",hex(初始值))
      break

"dice_dict={1:,2:,3:,4:,5:,6:,"
"7:,8:,9:,10:,11:,12:," \
"13:,14:,15:,16:,17:,18:}"
经过测试正确后就可以开始写代码了(完整代码如下):
from ctypes import *
from keystone import *
from tkinter import *
from pymem import Pymem
import win32gui
dice_dict={1:,2:,3:,4:,5:,6:,7:,8:,9:,10:,11:,12:,13:,14:,15:,16:,17:,18:}
def dice(dice):
    race_database_code="""
    mov eax,
    add eax,0x0c
    """
    dice_code="mov ebx,"+str(dice_dict)
    code1="""
    mov ,ebx
    """
    dice_number="mov eax,0x0100090"+str(dice_dict)
    code2="""
    mov ,eax
    """
    code3 = """
    mov eax,0x01000101
    mov ,eax
    mov eax,0x2
    mov ,eax
    mov eax,0x40D7C4
    call eax
    ret
    """
    code=(race_database_code+dice_code+code1+dice_number+code2+code3)
    #####获取句柄
    Rich4_process = Pymem('Rich4.exe')
    Rich4_handle=Rich4_process.process_handle
    ######生成注入代码
    ks = Ks(KS_ARCH_X86, KS_MODE_32)
    Original_code=ks.asm(code)
    shellcode=''
    for i in Original_code:
      alone_code=hex(i).zfill(2)
      shellcode=shellcode+alone_code
    shellcode=bytes.fromhex(shellcode)

    kernel32=windll.kernel32
    code_size = len(shellcode)
    PAGE_EXECUTE_READWRITE=0x00000040
    VIRTUAL_MEM=( 0x1000 | 0x2000 )# 为我们的shellcode申请内存
    #########获取注入的地址
    arg_address = kernel32.VirtualAllocEx( Rich4_handle,0, code_size, VIRTUAL_MEM, PAGE_EXECUTE_READWRITE)
    # 在内存中写入shellcode
    written = c_int(0)
    kernel32.WriteProcessMemory(Rich4_handle, arg_address, shellcode, code_size, byref(written))
    # 创建远程线程,指定入口为我们的shellcode头部
    thread_id = c_ulong(0) kernel32.CreateRemoteThread(Rich4_handle,None,0,arg_address,None,0,byref(thread_id))
    Rich4_process.close_process()
    handle = win32gui.FindWindow(None, "Rich4")
    win32gui.SetForegroundWindow(handle)
tk=Tk()
tk.title("大富翁4如意骰子")
tk.iconbitmap("Rich4.ico")
Button(tk,text='1',command=lambda:dice(1),width=5,height=2).grid(row=0,column=0)
Button(tk,text='2',command=lambda:dice(2),width=5,height=2).grid(row=0,column=1)
Button(tk,text='3',command=lambda:dice(3),width=5,height=2).grid(row=0,column=2)
Button(tk,text='4',command=lambda:dice(4),width=5,height=2).grid(row=0,column=3)
Button(tk,text='5',command=lambda:dice(5),width=5,height=2).grid(row=0,column=4)
Button(tk,text='6',command=lambda:dice(6),width=5,height=2).grid(row=0,column=5)
Button(tk,text='7',command=lambda:dice(7),width=5,height=2).grid(row=1,column=0)
Button(tk,text='8',command=lambda:dice(8),width=5,height=2).grid(row=1,column=1)
Button(tk,text='9',command=lambda:dice(9),width=5,height=2).grid(row=1,column=2)
Button(tk,text='10',command=lambda:dice(10),width=5,height=2).grid(row=1,column=3)
Button(tk,text='11',command=lambda:dice(11),width=5,height=2).grid(row=1,column=4)
Button(tk,text='12',command=lambda:dice(12),width=5,height=2).grid(row=1,column=5)
Button(tk,text='13',command=lambda:dice(13),width=5,height=2).grid(row=2,column=0)
Button(tk,text='14',command=lambda:dice(14),width=5,height=2).grid(row=2,column=1)
Button(tk,text='15',command=lambda:dice(15),width=5,height=2).grid(row=2,column=2)
Button(tk,text='16',command=lambda:dice(16),width=5,height=2).grid(row=2,column=3)
Button(tk,text='17',command=lambda:dice(17),width=5,height=2).grid(row=2,column=4)
Button(tk,text='18',command=lambda:dice(18),width=5,height=2).grid(row=2,column=5)
tk.mainloop()
第一次发帖希望各位大哥大家多多见谅!
附上游戏包及程序,想体验的可以下载:
链接:https://pan.baidu.com/s/1pKKZReQIyVyyQWmjlmPJmg?pwd=z6v6
提取码:z6v6

eeeetif 发表于 2024-3-14 09:32

算是经典中的经典了,后续版本都没有这个版本好玩,可惜没有出适配如今高分屏的重制版,楼主详细记录了OD过程,谢谢了

smqltzx 发表于 2024-3-13 20:59

支持,下载游戏玩玩

skingnemo 发表于 2024-3-18 15:18

试了一下 楼主发的版本 我win10会闪退~ 不知原因
发个我自用的版本 楼主的如意骰子正常使用。。。

链接:https://pan.baidu.com/s/14F0jDh0iSqkvItQaAKSwsA?pwd=8888
提取码:8888
--来自百度网盘超级会员V8的分享

落痕 发表于 2024-3-13 21:04

学习下感谢

19sl 发表于 2024-3-13 21:33

学习一下

sanzhu 发表于 2024-3-13 21:48

支持支持,楼主加油{:1_921:}

探玄珠 发表于 2024-3-13 21:48

学习一下学习一下

fa22 发表于 2024-3-13 22:06

感觉不错玩玩,感谢!

StevenWang 发表于 2024-3-14 00:12

感谢大佬分享

ztl456110 发表于 2024-3-14 00:18

好经典的游戏
以前无修改通关....

SakuraiFang 发表于 2024-3-14 01:01

童年的记忆了,感觉新版也没有4好玩。还能从自己喜欢的游戏里学到调试的知识,感谢LZ的技术分享
页: [1] 2 3 4 5 6 7 8 9 10
查看完整版本: python实现大富翁4如意骰子