Follow丶Me 发表于 2018-10-8 22:24

记一次win7下逆向扫雷到DLL(HOOK)注入

本帖最后由 Follow丶Me 于 2018-10-9 13:41 编辑

10.1国庆宅在家里,没事干就调戏了扫雷。

这是在Windows 7下的32位扫雷程序,有空在看看64位。
首先理清逆向思路:
    1.载入OD,下消息断点201 (后来发现此路不通....)
    2.后来枚举所有函数,发现了Rand这个有趣的东东,然后OD中 bp rand
    3.最后游戏结束的时候发现对话框,可以直接给 DialogBoxParamW下断

上面是我自己的开始的思路,当然有大神提供思路的,请留言,十分感谢。

第一步,当然是载入OD,bp rand


接着程序会断这里


之后OD会不停的断在这,我们在堆栈窗口找到上层CALL的调用地址,再搜索哪些地方调用了当前的CALL,每个调用的地方都F2
就会得出有8个地方调用了,把那个一直调用rand的断点的去掉,还有把bp rand那个断也去掉



去掉之后再点击格子,此时回到OD如当前图片的断点,去这个CALL的头部从上往下分析。


经过分析,得知当前CALL是一个“布雷函数”

movedi,edi                                              ;布雷函数
pushebp                           
movebp,esp                        
pushecx                           
pushecx                           
pushebx                           
pushesi                           
pushedi                           
movesi,ecx                        
callMineSweeper.0034D816                     ;全局变量到EAX
pushdword ptr ds:                  ;push 5BB9B276 == push eax
movdword ptr ss:,eax               ;mov ecx, eax
callMineSweeper.0034D821                     ;这个参数也就是eax 即为随机序列种子
push0x00000010                  
callMineSweeper.0034DCA7                     ;申请4个DWORD大小的空间(malloc)
popecx                                                    ;变相的平衡堆栈 ecx = eax = 0x5BB9B276
testeax,eax                                 
jeMineSweeper.003400F1            
push0x00000010                                    ;初始化函数第一个参数0x10
movecx,eax                                              ;ecx = 01FD6948即为第一次申请的空间首地址
callMineSweeper.0033F959                        ;上面四个参数初始化为:0x0 0x0 0x10 0x0
movdword ptr ss:,eax                ;ecx = eax 即为01FD6948
jmpMineSweeper.003400F5         
anddword ptr ss:,0x00000
moveax,dword ptr ds:               ;获取扫雷的行 rows
imuleax,dword ptr ds:               ;获取扫雷的列 eax = rows * columns -> 9+9 = 0x51
xoredi,edi                                                ;i=0 edi置零
testeax,eax                     
jleMineSweeper.0034014B         
movecx,dword ptr ds:               ;ecx = columns.....=3DC248
moveax,edi                                              ;eax = i
cdq                                 
idivecx                                                    ;此时ecx为columns   i/dwColumn=eax行号....edx列号
xorecx,ecx                                             ;ecx置零
subedx,dword ptr ss:               ;sub 0,0 鼠标点击的列号
subeax,dword ptr ss:               ;sub 0,0 鼠标点击的行号
testedx,edx                                              ;列号!!!
setnlcl                                                   ;根据列号是否正负,取绝对值
leaecx,dword ptr ds:
imulecx,edx                     
cmpecx,0x01                     
jnleMineSweeper.00340136                        ;第一个差值绝对值<=1,判断第二个差值
xorecx,ecx                                                ;ecx置零
testeax,eax                                             ;行号!!!
setnlcl                                                      ;根据行号是否正负,取绝对值
leaecx,dword ptr ds:
imulecx,eax                     
cmpecx,0x01                     
jleMineSweeper.0034013F                           ;第二个差值绝对值>=1
movecx,dword ptr ss:   
pushedi                           
callMineSweeper.00355A51         
moveax,dword ptr ds:                  ;行数
imuleax,dword ptr ds:                  ;列数   -> 行数 * 列数 = 0x51
incedi                                                         ;i++
cmpedi,eax                                                 ;判断是否布满81个格子
jlMineSweeper.00340102                              ;没有布满就继续
push0x00000010                  
callMineSweeper.0034DCA7                        ;第二次4个DWORD大小的申请空间
popecx                                                       ;变相平衡堆栈 ecx = 0x10
testeax,eax                     
jeMineSweeper.00340165                           ;可能是申请失败时的操作
pushdword ptr ds:                        ;雷数入栈
movecx,eax                                                ;ecx为第二次申请的首地址
callMineSweeper.0033F959                           ;第二次申请空间初始化 0x0,0x0,0xA,0x0
movedi,eax                                                 ;edi 为第二次申请的首地址
jmpMineSweeper.00340196                        ;无条件跳
xoredi,edi                        
jmpMineSweeper.00340196         
moveax,dword ptr ss:                  ;eax = 第一次申请的首地址
moveax,dword ptr ds:                        ;eax = 0x4D = 77
testeax,eax                     
jbeMineSweeper.0034019D                        ;判断雷是否布完了
deceax                           
pusheax                                                   ;循环从0x4D 开始减一   入栈
push0x00000000                  
callMineSweeper.0034D7F3                        ;rand函数 随机数是:0-0x4C之间 即0-76之间
movebx,eax                                                ;ebx = 雷的随机数
moveax,dword ptr ss:                  ;第一个申请的首地址
moveax,dword ptr ds:               ;eax = 0436F980
pushdword ptr ds:                  ;找到随机布局中放雷的位置
movecx,edi                                                 ;ecx = 第二个申请的首地址
callMineSweeper.00355A51                        ;将数据保存到第二个申请空间里
movecx,dword ptr ss:                   ;ecx第一个申请的首地址
pushebx                           
callMineSweeper.0034EC9E         
moveax,dword ptr ds:                            ;eax的值是存放布雷数
cmpeax,dword ptr ds:                   ;判断雷数
jneMineSweeper.00340169                            ;雷数=第二次申请空间的第一个属性值
xorecx,ecx                        
cmpdword ptr ds:,ecx         
jbeMineSweeper.003401C4         
moveax,dword ptr ds:               ;获取存雷数组的地址
moveax,dword ptr ds:               ;取第i(ecx)个雷的位置数
movebx,dword ptr ds:               ;扫雷初始化数据中第四个属性是列数
cdq                                 
idivebx                                                      ;雷的位置数 / 列数 = 真实布雷的地址(EAX行号,EDX列号)
movebx,dword ptr ds:               ;地址表
movebx,dword ptr ds:                ;[+0xc] 第二层地址表
incecx                                                       ;i++
movedx,dword ptr ds:   
movedx,dword ptr ds:                ;根据雷所在列号取第edx(列号)个地址
movbyte ptr ds:,0x01                   ;为雷时,填充0x1
cmpecx,dword ptr ds:                           ;判断是否布完了
jcMineSweeper.003401A3                            ;布雷完毕
push0x00000001                  
movecx,edi                        
callMineSweeper.0033FC96                        ;free
movecx,dword ptr ss:   
popedi                           
popesi                           
popebx                           
testecx,ecx                     
jeMineSweeper.003401DE            
push0x00000001                  
callMineSweeper.0033FC96                            ;free
pushdword ptr ss:      
callMineSweeper.0034D821         
leave                              
retn0x0008                        


这还没完,在堆栈窗口找到向上2层的CALL那个才是左键点击的CALL


movedi,edi                                                                                  ;左键单击函数
pushebp                                    
movebp,esp                                 
moveax,dword ptr ds:                              ;这玩意就是基址
pushebx                                    
pushesi                                    
movesi,dword ptr ss:            
pushedi                                    
movbyte ptr ds:,0x01      
pushdword ptr ds:                                                         ;这个是y 坐标
movedi,ecx                                 
pushdword ptr ds:                                                         ;这个是x 坐标
movecx,dword ptr ds:                               ;this 指针
xorbl,bl                                    
callMineSweeper.00341418                                                            ;判断单击的是不是雷,传X,Y坐标
testeax,eax                                                                                 ;比较返回值
jnleMineSweeper.00346FF1                  
movdword ptr ds:,esi      
incbl                                       
jmpMineSweeper.00346FF9                     
pusheax                                    
movecx,edi                                 
callMineSweeper.00346BCD                                                            ;后续CALL
movbyte ptr ds:,0x01      
popedi                                    
popesi                                    
moval,bl                                    
popebx                                    
popebp                                    
etn0x0004                                 


再分析一下这个CALL里面“主要”做了什么:callMineSweeper.00341418 --> 判断单击的是不是雷,传X,Y坐标

movedi,edi                                 
pushebp                                    
movebp,esp                                 
ecx,dword ptr ds:                      ;this指针偏移+0x10(第5个属性地址)
popebp                                    
jmpMineSweeper.00340C50                      ;无条件跳

movedi,edi                                 
pushebp                                    
movebp,esp                                 
pushecx                                                ;this->第5个属性地址
pushebx                                    
movebx,dword ptr ss:            ;x坐标
pushesi                                                   ; = 存放x,y坐标的地址
movesi,ecx                                              ;此时esi=ecx=this指针->第5个属性地址
moveax,dword ptr ds:               ;this->某个对象
moveax,dword ptr ds:            ;某个对象->属性
moveax,dword ptr ds:            ;ebx = x坐标
moveax,dword ptr ds:            ;这个eax指向的地址就是存储所有列状态的地址表
pushedi                                    
movedi,dword ptr ss:               ;y 坐标
moveax,dword ptr ds:             ;edi = y坐标
xorecx,ecx                                 
movdword ptr ss:,ecx            
cmpeax,0x09                                           ;未点击
jeMineSweeper.00340C95                     
cmpeax,0x0B                                           ;问号
jeMineSweeper.00340C95                     
moveax,dword ptr ds:
cmpbyte ptr ds:,cl               
jeMineSweeper.00340CE5                     
pushecx                                    
pushecx                                    
pushecx                                    
callMineSweeper.003505E9                  
xorecx,ecx                                 
jmpMineSweeper.00340CE5                     
cmpdword ptr ds:,ecx                ;this->第七属性
jneMineSweeper.00340CBA                        ;判断是否第一次鼠标点击
pushedi                                    
pushebx                                    
movecx,esi                                 
callMineSweeper.003400BB                     ;布雷CALL
push0x00000000                              
pushedi                                    
pushebx                                    
push0x00000000                              
pushedi                                    
pushebx                                    
movecx,esi                                 
callMineSweeper.00340A42                  
movdword ptr ds:,ebx            
movdword ptr ds:,edi            
jmpMineSweeper.00340CDD                     
moveax,dword ptr ds:            
moveax,dword ptr ds:            
moveax,dword ptr ds:            ;这个ecx里面就是存储所有列有雷的地址表   
moveax,dword ptr ds:            
cmpbyte ptr ds:,cl                      ;判断是否为雷 ->edi=行eax=地址偏移 cl=0(cl值不变)
jeMineSweeper.00340CD0                         ;不为雷跳转



最后分析得出:
真实基址 = 扫雷起始地址 + 0x868B4(RVA)

格子数据 = [[[[[[[真实基址] + 0x10] + 0x40] + 0x0C] + 4 * X坐标] + 0x0C]+ 4 * Y坐标]
取值范围:1~8数字9未开 10旗 11问号12空


雷数据 = [[[[[[[真实基址] + 0x10] + 0x44] + 0x0C] + 4 * X坐标] + 0x0C] + Y坐标]


esi = [[真实基址] + 0x10]
= 雷数

= 行数

= 列数

= 鼠标左键单机次数
第一次单机时:
列号:
行号:


这就是鼠标左键CALL分析了,至于右键CALL提供思路:在第一块数据方格中下硬件写入断点
然后回溯跟踪 直到返回2次后,就是我们要找的CALL


OK...............................分析到这就结束了。


具体实现核心代码:**** Hidden Message *****

附上超级难度下秒杀图:




下载完成后把后缀名改一下,另外我用的是VS2015写的。







Shark恒 发表于 2018-10-9 13:04

非常棒~ 很详细,精华走一走

slmlq123 发表于 2018-10-16 14:10

学习一下{:5_116:}

hc777 发表于 2018-10-16 16:43

看看 思路,学习学习

菜刀 发表于 2018-10-28 12:43

前来学习了

woaizhoulu 发表于 2018-10-28 19:58

记一次win7下逆向扫雷到DLL(HOOK)注入

abc1 发表于 2018-11-3 00:18

思路比较特别,调试还太不太懂

493688702 发表于 2018-11-3 09:41

互相学习
共同进步
支持恒大

TAOGE5387 发表于 2018-11-3 09:41

好好学习天天向上{:5_116:}

lcdxsun 发表于 2018-11-19 08:29

这个是win7自带的还是网上下的独立版本的 扫雷游戏
页: [1] 2 3 4 5 6 7 8
查看完整版本: 记一次win7下逆向扫雷到DLL(HOOK)注入