【新兵申请转正】一个小游戏的分析和注入
经典游戏
分析:
1. 玩游戏,背后操作的API
定时器函数: SetTimer KillTimer
窗口大小变化:MoveWindow SetWindowPos
自定义设置: 弹出对话框 DialogBoxParam CreateDialog
窗口回调函数: CreateWindowEx WindowProc
随机函数: rand
API分析
工具: OD/IDA
方法:下各种断点分析
API断点 (可疑API)
条件断点 (回调函数过滤信息)
访问断点 (可疑数据)
2. 游戏中的数据(变量\数组\....)
高度,宽度,雷数, 扫雷数组
表现形式: 全局变量,局部变量, new出来的缓冲区
一般小程序为全局变量: 扫雷\俄罗斯方块\连连看
全局变量的特点,固定大小,或者是一个有穷的空间
工具: CE(Cheat Engine) OD
方法: 猜 - 查找数据,调试分析数据
猜 数据类型,数据范围
根据特定值,找到值所在的地址
例如: 扫雷数组的高度等
CE中指针寻址
指针3 = 指针2
指针2 = 指针1
指针1 = 地址
地址 = 值
Int num = 100;
Int* pNum = #
Int** ppNum = &pNum;
Int*** pppNum = &ppNum;
Step 8
i386.exe"+231390=631390
[631390] = 018C6AB8
[018C6AB8+0C] = 018912A0
[018912A0+14] = 035C3008
[035C3008] = 01827520
[01827520+18]=942
分析步骤
1. 使用CE分析扫雷程序中的数据
2. 根据在CE中查找的数据,在OD查看内存
发现了看似很像数组的一块缓冲区,通过修改宽度\高度,观察内存,最终分析出内存中标记所代表的意思
01005330 0A 00 00 00 0E 00 00 00 0E 00 00 00 00 00 00 00 ......
01005340 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 တတတတတတတတ
01005350 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F ༏༏༏༏༏༏༏༏
01005360 10 0F 0F 0F 8F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 10 ༐༏ྏ༏༏༏༏ဏ
01005370 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F ༏༏༏༏༏༏༏༏
01005380 10 0F 0F 8F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 10 ༐輏༏༏༏༏༏ဏ
01005390 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F ༏༏༏༏༏༏༏༏
010053A0 10 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 10 ༐༏༏༏༏༏༏ဏ
010053B0 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F ༏༏༏༏༏༏༏༏
010053C0 10 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 10 ༐༏༏༏༏༏༏ဏ
010053D0 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F ༏༏༏༏༏༏༏༏
010053E0 10 0F 0F 0F 0F 0F 0F 0F 0F 0F 8F 0F 0F 0F 0F 10 ༐༏༏༏༏ྏ༏ဏ
010053F0 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F ༏༏༏༏༏༏༏༏
01005400 10 0F 0F 0F 8F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 10 ༐༏ྏ༏༏༏༏ဏ
01005410 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F ༏༏༏༏༏༏༏༏
01005420 10 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 10 ༐༏༏༏༏༏༏ဏ
01005430 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F ༏༏༏༏༏༏༏༏
01005440 10 0F 0F 0F 0F 8F 0F 0F 0F 0F 0F 0F 0F 0F 0F 10 ༐༏輏༏༏༏༏ဏ
01005450 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F ༏༏༏༏༏༏༏༏
01005460 10 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 8F 0F 0F 10 ༐༏༏༏༏༏ྏဏ
01005470 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F ༏༏༏༏༏༏༏༏
01005480 10 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 10 ༐༏༏༏༏༏༏ဏ
01005490 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F ༏༏༏༏༏༏༏༏
010054A0 10 0F 0F 0F 0F 8F 0F 0F 0F 0F 8F 0F 0F 0F 0F 10 ༐༏輏༏༏ྏ༏ဏ
010054B0 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F ༏༏༏༏༏༏༏༏
010054C0 10 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 10 ༐༏༏༏༏༏༏ဏ
010054D0 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F ༏༏༏༏༏༏༏༏
010054E0 10 0F 0F 0F 0F 0F 0F 0F 8F 0F 0F 0F 0F 0F 0F 10 ༐༏༏༏ྏ༏༏ဏ
010054F0 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F ༏༏༏༏༏༏༏༏
01005500 10 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 8F 0F 10 ༐༏༏༏༏༏輏ဏ
01005510 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F ༏༏༏༏༏༏༏༏
01005520 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 တတတတတတတတ
缓冲区的值:
10 边界
0F 填充值,初始化之后的默认值
8F 雷
40-48 表示当前位置周围的雷数
3. 在扫雷数组上下写入断点,可以断到初始化数组的地方,进一步分析
4. 01002ED5 >mov eax,0x360
5. 01002EDA dec eax
6. 01002EDB mov byte ptr ds:[eax+<扫雷数组>],0xF
7. 01002EE2 jnz short winmine.01002EDA
8. 01002EE4 mov ecx,dword ptr ds:[<高度>]
9. 01002EEA mov edx,dword ptr ds:[<宽度>]
10. 01002EF0 lea eax,dword ptr ds:[ecx+0x2]
11. 01002EF3 test eax,eax
12. 01002EF5 push esi
13. 01002EF6 je short winmine.01002F11
14. 01002EF8 mov esi,edx ; 高度
15. 01002EFA shl esi,0x5
16. 01002EFD lea esi,dword ptr ds:[esi+0x1005360]
17. 01002F03 dec eax
18. 01002F04 mov byte ptr ds:[eax+<扫雷数组>],0x10 ; 填充边界
19. 01002F0B mov byte ptr ds:[esi+eax],0x10 ; 填充边界
20. 01002F0F jnz short winmine.01002F03
21. 01002F11 lea esi,dword ptr ds:[edx+0x2]
22. 01002F14 test esi,esi
23. 01002F16 je short winmine.01002F39
24. 01002F18 mov eax,esi
25. 01002F1A shl eax,0x5
26. 01002F1D lea edx,dword ptr ds:[eax+<扫雷数组>]
27. 01002F23 lea eax,dword ptr ds:[eax+ecx+0x1005341]
28. 01002F2A sub edx,0x20
29. 01002F2D sub eax,0x20
30. 01002F30 dec esi
31. 01002F31 mov byte ptr ds:[edx],0x10 ; 填充边界
32. 01002F34 mov byte ptr ds:[eax],0x10 ; 填充边界
33. 01002F37 jnz short winmine.01002F2A
34. 01002F39 pop esi
35. 01002F3A retn36.
跟踪到初始化扫雷数组函数的上一层,可以找到生成雷的地方
010036B7 mov eax,dword ptr ds:[<雷数>]
010036BC mov dword ptr ds:[0x1005160],edi
010036C2 mov dword ptr ds:[<雷数>],eax
010036C7 push dword ptr ds:[<高度>] ; 循环开始随机生成雷---------------
010036CD call <winmine.生成随机数>
010036D2 push dword ptr ds:[<宽度>]
010036D8 mov esi,eax
010036DA inc esi
010036DB call <winmine.生成随机数>
010036E0 inc eax
010036E1 mov ecx,eax
010036E3 shl ecx,0x5
010036E6 test byte ptr ds:[ecx+esi+<扫雷数组>],0x80
010036EE jnz short winmine.010036C7
010036F0 shl eax,0x5
010036F3 lea eax,dword ptr ds:[eax+esi+<扫雷数组>]
010036FA or byte ptr ds:[eax],0x80 ; 设置雷标记
010036FD dec dword ptr ds:[<雷数>]
01003703 jnz short winmine.010036C7 ; 循环结束--------------
01003705 mov ecx,dword ptr ds:[<宽度>]
0100370B imul ecx,dword ptr ds:[<高度>]
01003712 mov eax,dword ptr ds:[<雷数>]
3. 要完成在界面能判断鼠标所在的位置下方的扫雷数组数据,需要一个转换函数
经过下写入断点,找到转换坐标的代码
01002099 8B45 14 mov eax,dword ptr ss:[ebp+0x14] ; 获取lParam,低位x,高位y
0100209C C1E8 10 shr eax,0x10 ; 清除低位,获取高位,Y坐标
0100209F 83E8 27 sub eax,0x27 ; 减去界面多余的高度
010020A2 C1F8 04 sar eax,0x4 ; 转换为数组下标
010020A5 50 push eax ; y
010020A6 0FB745 14 movzx eax,word ptr ss:[ebp+0x14] ; 获取低位
010020AA 83C0 04 add eax,0x4
010020AD C1F8 04 sar eax,0x4 ; 转换为数组下标
010020B0 50 push eax ; x
010020B1 E8 1E110000 call winmine.010031D4
4. 代码编写
在DLL中编写代码
如果用MFCDLL编写代码
创建MFCDLL工程,在生成app类中的InitInstance函数中编写代码DLL注入
注入之后再游戏里面可以随便玩
评论11次
厉害啊,好想学这个~~ 师傅有基础教程吗?
有点意思。。DLL的内容为什么不写详细。
不错不错,很经典啊,扫描很经典,也是很经典的逆向基础,谢谢楼主
有逆向基础视频吗?不知道怎么学起
这很基础的吧。。 表示我的入门作。。。
这个不错,适合我等小白入门练手,跟着lz的步骤过一遍也能大概理解很多底层的概念了
逆向牛 这个注入跟我们所说的注入不是一回事吧
虽然一个简单的游xi ,隐藏很牛逼的逆向技术啊 。 学xi了
好像没人看?
思路不错
不错不错