• 标 题:回朔找内存地址 (17千字)
  • 作 者:*咖啡豆*  
  • 时 间:2003-12-12 00:23:21
  • 链 接:http://bbs.pediy.com

双休日,干什么呢?闲着还不如恶搞一下(心理变态)。
把中国游戏中心的象棋拿来看看,决定破之而后快。
目的,找出表示象棋棋子的内存地址.
象棋棋子的表示和其他游戏里的经验值生命值不同,经验值和生命值是用数值表示的,在内存中用值查找就OK了,但是棋子呢,车用什么表示?没人知道。
首先,对软件进行资源分析,发现棋子的在资源位图中的顺序是车马炮帅士象兵,大概猜测知道(红或黑)车~兵是用0~6表示。但是内存中是0~6的单元多如牛毛,而且还不确定值的存放长度和确切值,想在内存中找这些数简直是大海捞针。
要怎么办呢,有一点WINDOWS图象编程的人都知道,要最终画出图象,多半要用到BITBLT这个API,如果知道贴棋子时的BITBLT参数就可以用回朔法找到棋子信息内存的指针。什么?在BITBLT上下断点就行了?那是不可能的,因为,BITBLT这个API的应用率太高,你的SOFTICE会一直中断....
于是在W32DASM中找BITBLT函数,找到两个:
:0041A630 55                      push ebp
:0041A631 8BEC                    mov ebpesp
:0041A633 51                      push ecx
:0041A634 894DFC                  mov dword ptr [ebp-04], ecx
:0041A637 8B4524                  mov eaxdword ptr [ebp+24]
:0041A63A 50                      push eax
:0041A63B 8B4D20                  mov ecxdword ptr [ebp+20]
:0041A63E 51                      push ecx
:0041A63F 8B551C                  mov edxdword ptr [ebp+1C]
:0041A642 52                      push edx
:0041A643 8B4D18                  mov ecxdword ptr [ebp+18]
:0041A646 E835FFFFFF              call 0041A580
:0041A64B 50                      push eax
:0041A64C 8B4514                  mov eaxdword ptr [ebp+14]
:0041A64F 50                      push eax
:0041A650 8B4D10                  mov ecxdword ptr [ebp+10]
:0041A653 51                      push ecx
:0041A654 8B550C                  mov edxdword ptr [ebp+0C]
:0041A657 52                      push edx
:0041A658 8B4508                  mov eaxdword ptr [ebp+08]
:0041A65B 50                      push eax
:0041A65C 8B4DFC                  mov ecxdword ptr [ebp-04]
:0041A65F 8B5104                  mov edxdword ptr [ecx+04]
:0041A662 52                      push edx

* Reference To: GDI32.BitBlt, Ord:0011h
                                  |
:0041A663 FF15C4304600            Call dword ptr [004630C4]
:0041A669 8BE5                    mov espebp
:0041A66B 5D                      pop ebp
:0041A66C C22000                  ret 0020

:00448E78 2B442450                sub eaxdword ptr [esp+50]
:00448E7C 8B4C2450                mov ecxdword ptr [esp+50]
:00448E80 83E80D                  sub eax, 0000000D
:00448E83 99                      cdq
:00448E84 2BC2                    sub eaxedx
:00448E86 C1F801                  sar eax, 01
:00448E89 03C8                    add ecxeax
:00448E8B 8B44244C                mov eaxdword ptr [esp+4C]
:00448E8F 51                      push ecx

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00448D01(U)
|
:00448E90 50                      push eax
:00448E91 56                      push esi

* Reference To: GDI32.BitBlt, Ord:0011h
                                  |
:00448E92 FF15C4304600            Call dword ptr [004630C4]
:00448E98 53                      push ebx
:00448E99 57                      push edi
我们要的是初始化时绘棋子的那个,是哪个呢?
BITBLT的第8个参数是RASTER运算值,改成00000000的话就是黑的,在HIEW中把它们运算值改了,发现改第一个的时候全都黑了,于是断定是第一个。
回到第一个看:

:0041A630 55                      push ebp
:0041A631 8BEC                    mov ebpesp
:0041A633 51                      push ecx
:0041A634 894DFC                  mov dword ptr [ebp-04], ecx
:0041A637 8B4524                  mov eaxdword ptr [ebp+24]
:0041A63A 50                      push eax
:0041A63B 8B4D20                  mov ecxdword ptr [ebp+20]
:0041A63E 51                      push ecx(8)
:0041A63F 8B551C                  mov edxdword ptr [ebp+1C]
:0041A642 52                      push edx(7)
:0041A643 8B4D18                  mov ecxdword ptr [ebp+18]
:0041A646 E835FFFFFF              call 0041A580
:0041A64B 50                      push eax(6)
:0041A64C 8B4514                  mov eaxdword ptr [ebp+14]
:0041A64F 50                      push eax(5)
:0041A650 8B4D10                  mov ecxdword ptr [ebp+10]
:0041A653 51                      push ecx(4)
:0041A654 8B550C                  mov edxdword ptr [ebp+0C]
:0041A657 52                      push edx(3)
:0041A658 8B4508                  mov eaxdword ptr [ebp+08]
:0041A65B 50                      push eax(2)
:0041A65C 8B4DFC                  mov ecxdword ptr [ebp-04]
:0041A65F 8B5104                  mov edxdword ptr [ecx+04]
:0041A662 52                      push edx(第一个参数)

* Reference To: GDI32.BitBlt, Ord:0011h
                                  |
:0041A663 FF15C4304600            Call dword ptr [004630C4]
:0041A669 8BE5                    mov espebp
:0041A66B 5D                      pop ebp
:0041A66C C22000                  ret 0020
看CALL之前的PUSH,倒数8个,八个参数都出来了
于是看出倒数第3个正是来源位图的左上角坐标
知道了这个就可以知道是什么棋子了,因为棋子的位图
是通过在一张有所有棋子的位图上截取的。
然后开始回朔,回到上一级调用他的地方
* Referenced by a CALL at Addresses:
|:00419FBE   , :0041A13C   , :0041A1C3   , :0041A1EF   , :0041A273   
|:0041A29F   , :0041A2C8   , :0041A2F1   , :0041B1AC   , :0041F89C   
|:0041FB46   , :00420018   , :0042296B   , :00422A25   , :00422B98   
|:00422DEA   , :00422E13   , :00422E38   , :00422E61   , :004230C6   
|:00431B57   , :004320F8   , :00432121   , :00432146   , :0043216F   
这么多!!
不过看看地址可以看出很多地方是同一个函数调用的,其
实只有5~6个函数调用了它,于是回朔看看,到达这里:
:00422E3D 6846006600              push 00660046;8(Raster运算值)
:00422E42 8B5524                  mov edxdword ptr [ebp+24]
:00422E45 52                      push edx;7
:00422E46 8B4520                  mov eaxdword ptr [ebp+20]
:00422E49 50                      push eax;6
:00422E4A 8B4D1C                  mov ecxdword ptr [ebp+1C]
:00422E4D 51                      push ecx;5
:00422E4E 8B5518                  mov edxdword ptr [ebp+18]
:00422E51 52                      push edx;4
:00422E52 8B4514                  mov eaxdword ptr [ebp+14]
:00422E55 50                      push eax;3
:00422E56 8B4D10                  mov ecxdword ptr [ebp+10]
:00422E59 51                      push ecx;2
:00422E5A 8B550C                  mov edxdword ptr [ebp+0C]
:00422E5D 52                      push edx;第一个参数
:00422E5E 8B4D08                  mov ecxdword ptr [ebp+08]
:00422E61 E8CA77FFFF              call 0041A630
看到没这个就是初始化时调用贴棋子的地方!
验证一下,把Raster运算值改成0,结果,棋子全变黑了.
然后再回朔,为什么不在这里断掉找棋子的内存地址呢?
因为还没看见坐标变换的运算啊,因为从拿到棋子参数后
到贴图必须经过对棋子逻辑坐标到显示器的位置的坐标变换
才能贴图的。
于是继续回蒴,到了这里:
:00422BF9 68D6A54A00              push 004AA5D6
:00422BFE 6A00                    push 00000000
:00422C00 8B550C                  mov edxdword ptr [ebp+0C]
:00422C03 81E2FF000000            and edx, 000000FF
:00422C09 8B45C0                  mov eaxdword ptr [ebp-40]
:00422C0C 0FAF9043010000          imul edxdword ptr [eax+00000143]
:00422C13 52                      push edx
:00422C14 8D4DC8                  lea ecxdword ptr [ebp-38]
:00422C17 51                      push ecx
:00422C18 8B55C0                  mov edxdword ptr [ebp-40]
:00422C1B 8B8247010000            mov eaxdword ptr [edx+00000147]
:00422C21 50                      push eax
:00422C22 8B4DC0                  mov ecxdword ptr [ebp-40]
:00422C25 8B9143010000            mov edxdword ptr [ecx+00000143]
:00422C2B 52                      push edx
:00422C2C 8B45C0                  mov eaxdword ptr [ebp-40]
:00422C2F 8B4D14                  mov ecxdword ptr [ebp+14]
:00422C32 0FAF883F010000          imul ecxdword ptr [eax+0000013F]
:00422C39 8B55C0                  mov edxdword ptr [ebp-40]
:00422C3C 8B8237010000            mov eaxdword ptr [edx+00000137]
:00422C42 03C1                    add eaxecx
:00422C44 50                      push eax
:00422C45 8B4DC0                  mov ecxdword ptr [ebp-40]
:00422C48 8B5510                  mov edxdword ptr [ebp+10]
:00422C4B 0FAF913B010000          imul edxdword ptr [ecx+0000013B]
:00422C52 8B45C0                  mov eaxdword ptr [ebp-40]
:00422C55 8B8833010000            mov ecxdword ptr [eax+00000133]
:00422C5B 03CA                    add ecxedx
:00422C5D 51                      push ecx
:00422C5E 8B5508                  mov edxdword ptr [ebp+08]
:00422C61 52                      push edx
:00422C62 8B4DC0                  mov ecxdword ptr [ebp-40]
:00422C65 E8D5000000              call 00422D3F
看到没,坐标变换运算:
:00422C2C 8B45C0                  mov eaxdword ptr [ebp-40]
:00422C2F 8B4D14                  mov ecxdword ptr [ebp+14]
:00422C32 0FAF883F010000          imul ecxdword ptr [eax+0000013F]
:00422C39 8B55C0                  mov edxdword ptr [ebp-40]
:00422C3C 8B8237010000            mov eaxdword ptr [edx+00000137]
:00422C42 03C1                    add eaxecx
[eax+0000013F]是放棋子位图宽的地方, [[ebp-40]+00000137]又
是什么呢?是左上角的棋子到棋盘边缘的距离(y轴)。
找到最重要的BITBLT第5个的寻址:
:00422C00 8B550C                  mov edxdword ptr [ebp+0C]
:00422C03 81E2FF000000            and edx, 000000FF
:00422C09 8B45C0                  mov eaxdword ptr [ebp-40]
:00422C0C 0FAF9043010000          imul edxdword ptr [eax+00000143]
:00422C13 52                      push edx(第5个参数)
咦?怎么要先和000000FF AND呢?难道..(后面再说)
不管了,先记下寻址:
mov edxdword ptr [ebp+0C]
然后再一路反跳转回到这里:
* Referenced by a CALL at Addresses:
|:004229F4   , :00422F78   , :00423193   , :0042323B   , :00423FC4   
|:00424337   , :004246E1   , :0042483A   , :004249D6   , :004271D8   
|:004272F3   , :00427316   , :00428444   , :0042947E   , :004297A2   
|:004297E5   , :00429A6E   , :00429A92   
|
:00422A8F 55                      push ebp
:00422A90 8BEC                    mov ebpesp
:00422A92 6AFF                    push FFFFFFFF
:00422A94 685B094600              push 0046095B
:00422A99 64A100000000            mov eaxdword ptr fs:[00000000]
:00422A9F 50                      push eax
:00422AA0 64892500000000          mov dword ptr fs:[00000000], esp
:00422AA7 83EC34                  sub esp, 00000034
:00422AAA 894DC0                  mov dword ptr [ebp-40], ecx
:00422AAD 837D0800                cmp dword ptr [ebp+08], 00000000
:00422AB1 7505                    jne 00422AB8
:00422AB3 E977020000              jmp 00422D2F
还有这么多?回朔哪个?
没关系了,因为如果再回朔一次的话很可能已经可以找到读取
棋子参数的内存的指令了。(为什么?因为已经是时候了,该
做的都做了,还不是读棋子参数是什么)
于是从第一个回蒴,到达:
:004229D2 8B55B8                  mov edxdword ptr [ebp-48]
:004229D5 52                      push edx
:004229D6 8B45E8                  mov eaxdword ptr [ebp-18]
:004229D9 50                      push eax
:004229DA 8B4DE8                  mov ecxdword ptr [ebp-18]
:004229DD 6BC90A                  imul ecx, 0000000A
:004229E0 8B55B8                  mov edxdword ptr [ebp-48]
:004229E3 03D1                    add edxecx
:004229E5 8B45B4                  mov eaxdword ptr [ebp-4C]
:004229E8 8A4C1048                mov clbyte ptr [eax+edx+48]
:004229EC 51                      push ecx
:004229ED 8D55D0                  lea edxdword ptr [ebp-30]
:004229F0 52                      push edx
:004229F1 8B4DB4                  mov ecxdword ptr [ebp-4C]
:004229F4 E896000000              call 00422A8F
因为上一步已经记下了最重要的寻址:
EBP + C
于是只要回数2个PUSE就行了,由于CALL进去后还PUSH了一个EBP
:004229DA 8B4DE8                  mov ecxdword ptr [ebp-18]
:004229DD 6BC90A                  imul ecx, 0000000A
:004229E0 8B55B8                  mov edxdword ptr [ebp-48]
:004229E3 03D1                    add edxecx
:004229E5 8B45B4                  mov eaxdword ptr [ebp-4C]
:004229E8 8A4C1048                mov clbyte ptr [eax+edx+48]
:004229EC 51                      push ecx
有点复杂哦,不过CRACK就必须有耐心,耐心看完后知道:
棋子类型描述单元的寻址是:
[[ebp - 4c] + [ebp - 48] + [ebp - 18] * 11 + 48]
这么复杂是正常的,想想看,这么多棋子,肯定要分几步才能找到了 
现在怎么办呢,如果能在这里设个短点就可以知道ebp的值从而找到
棋子的单元了.
想一想,只要读不能访问的内存单元就会发生访存错误,程序会被BREAK
呵呵,只要把其中一个语句改成非法的访存语句就OK了,偶的系统是2000,读写小于0x00010000的内存是不允许的,会抛出异常:xxxx指令的xxxxx内存不能为读,于是决定虐待一下它,
用HIEW把mov ecxdword ptr [ebp-4C]改成mov ecxdword ptr [eax-4C],运行它!
点开始,生成棋盘棋子---当!WINDOWS的错误框预期出现在面前!
马上对它进行调试,看ebp的内容,代入[[ebp - 4c] + [ebp - 48] + [ebp - 18] * 11 + 48]
算出地址:0x016a4f00(这个值每台电脑可能不同)
于是一切搞顶,现在只要找到初始化棋子时的语句就可以了(可以什么?当
然是胡作非为了,想怎么改不行!)
于是在0x016a4f00上下断点,然后运行象棋...
SOFTICE弹出!
一眼就发现初始化棋子的语句了:
:004225AE 8B55FC                  mov edxdword ptr [ebp-04]
:004225B1 C6424807                mov [edx+48], 07
:004225B5 8B45FC                  mov eaxdword ptr [ebp-04]
:004225B8 C6405208                mov [eax+52], 08
:004225BC 8B4DFC                  mov ecxdword ptr [ebp-04]
:004225BF C6415C0C                mov [ecx+5C], 0C
:004225C3 8B55FC                  mov edxdword ptr [ebp-04]
:004225C6 C642660B                mov [edx+66], 0B
:004225CA 8B45FC                  mov eaxdword ptr [ebp-04]
:004225CD C640700A                mov [eax+70], 0A
:004225D1 8B4DFC                  mov ecxdword ptr [ebp-04]
:004225D4 C6417A0B                mov [ecx+7A], 0B
:004225D8 8B55FC                  mov edxdword ptr [ebp-04]
:004225DB C682840000000C          mov byte ptr [edx+00000084], 0C
:004225E2 8B45FC                  mov eaxdword ptr [ebp-04]
:004225E5 C6808E00000008          mov byte ptr [eax+0000008E], 08
:004225EC 8B4DFC                  mov ecxdword ptr [ebp-04]
:004225EF C6819800000007          mov byte ptr [ecx+00000098], 07
:004225F6 8B55FC                  mov edxdword ptr [ebp-04]
:004225F9 C6425409                mov [edx+54], 09
:004225FD 8B45FC                  mov eaxdword ptr [ebp-04]
:00422600 C6809000000009          mov byte ptr [eax+00000090], 09
:00422607 8B4DFC                  mov ecxdword ptr [ebp-04]
:0042260A C6414B0D                mov [ecx+4B], 0D
:0042260E 8B55FC                  mov edxdword ptr [ebp-04]
:00422611 C6425F0D                mov [edx+5F], 0D
:00422615 8B45FC                  mov eaxdword ptr [ebp-04]
:00422618 C640730D                mov [eax+73], 0D
:0042261C 8B4DFC                  mov ecxdword ptr [ebp-04]
:0042261F C681870000000D          mov byte ptr [ecx+00000087], 0D
:00422626 8B55FC                  mov edxdword ptr [ebp-04]
:00422629 C6829B0000000D          mov byte ptr [edx+0000009B], 0D
:00422630 8B45FC                  mov eaxdword ptr [ebp-04]
:00422633 C6404E06                mov [eax+4E], 06
:00422637 8B4DFC                  mov ecxdword ptr [ebp-04]
:0042263A C6416206                mov [ecx+62], 06
:0042263E 8B55FC                  mov edxdword ptr [ebp-04]
:00422641 C6427500                mov [edx+75], 00
:00422645 8B45FC                  mov eaxdword ptr [ebp-04]
:00422648 C6808A00000006          mov byte ptr [eax+0000008A], 06
:0042264F 8B4DFC                  mov ecxdword ptr [ebp-04]
:00422652 C6819E00000006          mov byte ptr [ecx+0000009E], 06
:00422659 8B55FC                  mov edxdword ptr [ebp-04]
:0042265C C6425902                mov [edx+59], 02
:00422660 8B45FC                  mov eaxdword ptr [ebp-04]
:00422663 C6809500000002          mov byte ptr [eax+00000095], 02
:0042266A 8B4DFC                  mov ecxdword ptr [ebp-04]
:0042266D C6415100                mov [ecx+51], 00
:00422671 8B55FC                  mov edxdword ptr [ebp-04]
:00422674 C6425B01                mov [edx+5B], 01
:00422678 8B45FC                  mov eaxdword ptr [ebp-04]
:0042267B C6406505                mov [eax+65], 05
:0042267F 8B4DFC                  mov ecxdword ptr [ebp-04]
:00422682 C6416F04                mov [ecx+6F], 04
:00422686 8B55FC                  mov edxdword ptr [ebp-04]
:00422689 C6427903                mov [edx+79], 03
:0042268D 8B45FC                  mov eaxdword ptr [ebp-04]
:00422690 C6808300000004          mov byte ptr [eax+00000083], 04
:00422697 8B4DFC                  mov ecxdword ptr [ebp-04]
:0042269A C6818D00000005          mov byte ptr [ecx+0000008D], 05
:004226A1 8B55FC                  mov edxdword ptr [ebp-04]
:004226A4 C6829700000001          mov byte ptr [edx+00000097], 01
:004226AB 8B45FC                  mov eaxdword ptr [ebp-04]
:004226AE C680A100000000          mov byte ptr [eax+000000A1], 00
呵呵,0~6是黑的车马炮将士象兵7~D是红的
现在知道上面做坐标运算的时候为什么要用FF来AND了吧,
因为每个棋子的类型只用一个byte来存放,呵呵,这样如果用值
查找找一辈子也找不到,这里还可以发现存放棋子类型不是以
棋子为对象,是以象棋盘上的交叉点来做对象,点上是FF为没有
棋子,是0~D的话就是各种棋子.
现在大功告成,把所有棋子改成帅!呵呵,爽吧.
不过最后告诉大家,由于中国游戏中心服务器只接受棋子移动的信息,
比如跑2平5,并不接受棋子类型信息,所以如果你把自己的兵改成车的话,在本地机器上是可以发送车1进3的命令的,但是到了服务器就会被认为是兵1进3了,显然兵是不能进3的,所以被认为是非法指令,马上被踢!
呵呵,如果能作弊就不敢公开了,被XX就不好了....
(众怒:TMD骗我们看了这么久..)
啊..大家有话好说嘛....还是先闪了,水平甚菜,有不当之处还请大虾们指出:)