欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  网络运营

逆向一个老的双升扑克游戏,并完成外挂

程序员文章站 2022-04-30 19:31:18
逆向一个老的双升扑克游戏,并完成外挂【文章作者】: cdanlover【软件名称】: 古今大战80分【加壳方式】: 无【保护方式】: Name/Serial【编写语言】: Delphi【使用工...



逆向一个老的双升扑克游戏,并完成外挂
【文章作者】: cdanlover
【软件名称】: 古今大战80分
【加壳方式】: 无
【保护方式】: Name/Serial
【编写语言】: Delphi
【使用工具】: peid、DeDeDark、RadASM、MASM32、OD、WINDOWS计算器
【操作平台】: WINXP
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】

    好久没有逆向过程序了,手都有点生了,今天有空就找了一个简单的来练练手,原来写过这个游戏的注册机,算法挺简单,估计软件设计也不会太复杂,于是就有了这篇笔记。
    这个游戏是用Delphi编程的,于是找来DeDeDark对其反了一下,很容易找到菜单的调用过程地址:

        Caption = 开局(K)
        OnClick = MIShuffleClick    00464A58  

        Caption = 摸牌(M)
        OnClick = MISettleClick     00464A60  

        Caption = 扣牌(D)
        OnClick = MIDiscardClick      00464A70 

        Caption = 出牌(C)        
        OnClick = MIShowClick        00464A78   


        Caption = 作弊模式
        OnClick = MIShowCardClick     004649FC

      Caption = 察看
        Caption = 底牌
        OnClick = N14Click           00466CAC
首先是对“开局”进行跟踪的,发现在发牌的过程中,在寄存器中反复出现同一个地址,我就想到有可能是程序申请到的一块内存的开始地址,用来存放牌面信息,在我的办公电
脑上是00B53250,后来在另一台电脑上跟踪时发现这个地址变了,于是就想找出是什么时间开始取的这块内存,发现在程序一开始就进行了申请:
004678E4 > $  55            push ebp
004678E5   .  8BEC          mov ebp,esp
004678E7   .  83C4 F4       add esp,-0C
004678EA   .  B8 1C774600   mov eax,0046771C
004678EF   .  E8 B8DEF9FF   call 004057AC                            ;  申请内存
004678F4   .  A1 408E4600   mov eax,dword ptr ds:[468E40]
004678F9   .  8B00          mov eax,dword ptr ds:[eax]
004678FB   .  E8 746AFCFF   call 0042E374
00467900   .  8B0D 348D4600 mov ecx,dword ptr ds:[468D34]            ;  古今大战.00469980
00467906   .  A1 408E4600   mov eax,dword ptr ds:[468E40]
0046790B   .  8B00          mov eax,dword ptr ds:[eax]
0046790D   .  8B15 74614500 mov edx,dword ptr ds:[456174]            ;  古今大战.004561B4
00467913   .  E8 746AFCFF   call 0042E38C                            ;  在call之前,内存已申请好,在call过后,地址指针等已经分配好了,开始出界面
00467918 > .  A1 408E4600   mov eax,dword ptr ds:[468E40]
0046791D   .  8B00          mov eax,dword ptr ds:[eax]
0046791F   .  E8 F46AFCFF   call 0042E418                            ;  已完全运行
就开始找这个00B53250,最早出现的地方,是在
mov ecx,dword ptr ds:[468D34]
[468D34] 保存一个地址:00469980,程序正常运行后,在[00469980]保存了基址:------>00B53250
在00467918处下条件记录断点,可直接定位到分配的内存基址。

逆向一个老的双升扑克游戏,并完成外挂

 

在后来的分析中,发现以这个基址有很多可能关注的地方:
+F34  [00B54184]  代表本局中出的第几张牌。
+4E4  [00B53734]  比较是否为庄家,4为庄家,1为最后出牌(分析结果:1代表左边的,2代表对家,3代表右边的,4代表玩家自己)

一开始没有找到存放牌信息的地方,后来就对“扣牌”过程进行分析,其中有段:
004641E8  |.  B8 14000000   mov eax,14                               ;  20个元素
004641ED  |.  8D55 B0       lea edx,[local.20]                       ;  初始化一个数组,用于保存出的牌是手中的第几张牌
004641F0  |>  33C9          /xor ecx,ecx
004641F2  |.  890A          |mov dword ptr ds:[edx],ecx
004641F4  |.  83C2 04       |add edx,4
004641F7  |.  48            |dec eax
004641F8  |.^ 75 F6         jnz short 004641F0
004641FA  |.  B8 01000000   mov eax,1
004641FF  |>  8B9483 4C0400>/mov edx,dword ptr ds:[ebx+eax*4+44C]
00464206  |.  8B52 34       |mov edx,dword ptr ds:[edx+34]
00464209  |.  8B8B 18030000 |mov ecx,dword ptr ds:[ebx+318]
0046420F  |.  83E9 0A       |sub ecx,0A
00464212  |.  3BD1          |cmp edx,ecx
00464214  |.  75 05         |jnz short 0046421B
00464216  |.  46            |inc esi
00464217  |.  8944B5 AC     |mov dword ptr ss:[ebp+esi*4-54],eax     ;  一个数组,记录出的第几张牌
0046421B  |>  40            |inc eax
0046421C  |.  83F8 1A       |cmp eax,1A                              ;  与26比较,每个玩家手中25张牌
0046421F  |.^ 75 DE         jnz short 004641FF

发现在mov edx,dword ptr ds:[ebx+eax*4+44C]这个地方计算是哪张牌,查看这块内存发现挺有规律的,有很多4SD开始的,继续向上翻,找到第一个4SD的单元,重新跟踪,对其

下内存写入断点,就找到了这块保存牌面信息的地方,当eax=1时,即可以算出玩家手中第一张牌保存的地方了,每个双字保存一个地址指针,指向每一张牌:

左手边玩家的:
00B53574  94 99 B5 00 70 BA B5 00 50 BC B5 00 48 BE B5