首页
社区
课程
招聘
[原创]小白的第一次逆向 之 扫雷分析与辅助制作
发表于: 2017-11-25 09:38 2620

[原创]小白的第一次逆向 之 扫雷分析与辅助制作

2017-11-25 09:38
2620

扫雷逆向分析与辅助制作

目录

思路:

想要实现的功能

  • 鼠标悬停,自动提示是否有雷
  • 一键自动扫雷

如何实现这些功能

首先要了解如果想要实现想要的功能,需要进行什么操作

实现鼠标移动 ,自动识别有没有雷
  • 需要hook掉回调函数,响应WM_MOUSEMOVE消息

  • 怎么判断鼠标所在的位置是不是有雷?

    • 是不是需要把屏幕坐标转换成扫雷区域的数组坐标
    • 找到雷的分辨类型
    • 找到雷的数量
    • 找到扫雷区域的大小
  • 如何实现一键扫雷
    • 遍历扫雷的数组,对所有不是雷的区域,发送WM_LBUTTONDOWN的消息,这样应该实现了扫雷的功能
    • 同时,是不是还需要对数组坐标进行向屏幕坐标的转换

具体实现步骤

有了思路之后,进行具体的实现

找数据

找界面的区域大小和雷的数量的数据应该是最好找的

 

查看是否有重定位(如果有就关掉),上CE

  • 首先先找高度的基址
    通过几次尝试之后,发现

    那么这两地址应该就是高度的基址了,具体为什么有2个先不管,放到窗口中先放一放
  • 然后找宽度的基址
    同样的经过几次尝试之后,发现

    这两个地址就该就是跟宽度相关的地址

  • 找雷数的基址
    步骤一样

    但是这里发现了3条数据,上面都是2条,有点不符合规律,所有就测试一下,到底这3个地址是不是全部都跟地雷数量有关(暂且按下不表,具体中od去看到底哪个才是)
    根据地址的连续性,稍微整理了一下

  • 找初始化地图数据的地址
    找到了地雷和区域大小的基址,那么只要找到更改这个对区域进行更改的函数,猜想应该可以找到布雷的方法和各种雷等数据的判断类型
    关键是如何找到这个函数,首先要想明白的一件事是,游戏对初始化的时候,肯定是会对数据进行调用的,那么是不是可以通过游戏初始化的时候,访问或者更改这里面的代码从而找到调用的地址,试一下把

    通过故意还原游戏,从而找到了一访问某个数据的地址,或得这个地址的 数据为
    01003712
    这个时候,上od去看一下,是不是跟我们猜想的一样

01002ED5  /$  B8 60030000   MOV EAX,0x360                                    ;  eax = 0x360 ,不知道要干嘛,接着看
01002EDA  |>  48            /DEC EAX                                         ;  eax -=1
01002EDB  |.  C680 40530001>|MOV BYTE PTR DS:[EAX+<雷区界面基址>],0xF              ;  通过流程分析可以知道,0xf是空地的类型值,说明在初始化空地
01002EE2  |.^ 75 F6         \JNZ SHORT winmine.01002EDA                      ;  说明数组应该是0x360 这么大
01002EE4  |.  8B0D 34530001 MOV ECX,DWORD PTR DS:[<宽度0>]                     ;  ecx =宽度的数值,x轴
01002EEA  |.  8B15 38530001 MOV EDX,DWORD PTR DS:[<高度0>]                     ;  edx= 高度的数值,y轴
01002EF0  |.  8D41 02       LEA EAX,DWORD PTR DS:[ECX+0x2]                   ;  额,没看懂,把宽度+2 保存到eax中,eax == 宽度+2
01002EF3  |.  85C0          TEST EAX,EAX                                     ;  判断eax是不是为空
01002EF5  |.  56            PUSH ESI                                         ;  根据函数最后有pop esi,应该是保存环境
01002EF6  |.  74 19         JE SHORT winmine.01002F11                        ;  如果eax=0,跳转
01002EF8  |.  8BF2          MOV ESI,EDX                                      ;  esi  =高度的数值,y轴
01002EFA  |.  C1E6 05       SHL ESI,0x5                                      ;  esi = 代表y轴的高度*32
01002EFD  |.  8DB6 60530001 LEA ESI,DWORD PTR DS:[ESI+0x1005360]             ;  esi = [数组基址+0x20 +esi(高度*32)],应该是这个高度下的数组的最下一行
01002F03  |>  48            /DEC EAX                                         ;  eax = 宽度+2,说明左右的边界各占1,eax-=1
01002F04  |.  C680 40530001>|MOV BYTE PTR DS:[EAX+<雷区界面基址>],0x10             ;  10应该就是边界的类型了,这个应该是填充数组第一行的边界,从右往左
01002F0B  |.  C60406 10     |MOV BYTE PTR DS:[ESI+EAX],0x10                  ;  这个高度下区域最下面的边界,也是从右往左填充的
01002F0F  |.^ 75 F2         \JNZ SHORT winmine.01002F03                      ;  eax!=0 循环填充边界,也就是说填充的时候是 数组基址+0x20+高度*32+具体的列数
01002F11  |>  8D72 02       LEA ESI,DWORD PTR DS:[EDX+0x2]                   ;  同样的,esi 保存的是高度的数值+2,从而说明上下边界高度是1,而且不占游戏界面的区域
01002F14  |.  85F6          TEST ESI,ESI                                     ;  判断esi 是不是为空
01002F16  |.  74 21         JE SHORT winmine.01002F39                        ;  为空直接跳出了
01002F18  |.  8BC6          MOV EAX,ESI                                      ;  eax =高度的值+0x2
01002F1A  |.  C1E0 05       SHL EAX,0x5                                      ;  eax =(高度的值+0x2)*32
01002F1D  |.  8D90 40530001 LEA EDX,DWORD PTR DS:[EAX+<雷区界面基址>]              ;  这两行应该也是要填充边界的为止,具体的就不看了
01002F23  |.  8D8408 415300>LEA EAX,DWORD PTR DS:[EAX+ECX+0x1005341]         ;  edx 和eax应该是最下一行,最左边和最右边的值
01002F2A  |>  83EA 20       /SUB EDX,0x20                                    ;  0x20 应该是2行
01002F2D  |.  83E8 20       |SUB EAX,0x20
01002F30  |.  4E            |DEC ESI                                         ;  esi -=1
01002F31  |.  C602 10       |MOV BYTE PTR DS:[EDX],0x10                      ;  进行边界填充
01002F34  |.  C600 10       |MOV BYTE PTR DS:[EAX],0x10                      ;  边界填充
01002F37  |.^ 75 F1         \JNZ SHORT winmine.01002F2A
01002F39  |>  5E            POP ESI
01002F3A  \.  C3            RETN

通过od可以看到上面的代码,验证是不是真的,下个断点还原下场景,看看是不是回断下来
结果是断下来,说明这个地方很可能就是对界面进行初始化的函数,先来大致的分析一下这个函数到底做了什么

 

第一遍大体流程分析

0100367A  /$  A1 AC560001   MOV EAX,DWORD PTR DS:[<宽度1>]                       ;  eax == 宽度,暂且规定宽度是x轴坐标
0100367F  |.  8B0D A8560001 MOV ECX,DWORD PTR DS:[<高度1>]
01003685  |.  53            PUSH EBX
01003686  |.  56            PUSH ESI
01003687  |.  57            PUSH EDI                                           ;  保存寄存器环境
01003688  |.  33FF          XOR EDI,EDI                                        ;  edi == 0
0100368A  |.  3B05 34530001 CMP EAX,DWORD PTR DS:[<宽度0>]                       ;  宽度1 和宽度0 的数据进行对比
01003690  |.  893D 64510001 MOV DWORD PTR DS:[0x1005164],EDI                   ;  把0 移动到这个地址所在的空间内
01003696  |.  75 0C         JNZ SHORT winmine.010036A4                         ;  宽度0 和宽度1 不想等,跳转
01003698  |.  3B0D 38530001 CMP ECX,DWORD PTR DS:[<高度0>]                       ;  高度1和高度0进行对比
0100369E  |.  75 04         JNZ SHORT winmine.010036A4                         ;  高度0和高度1进行对比,不想等跳转,现在我有点怀疑这两组数据应该是用户设置的数据和实际填充的数据进行对比,下面可能是对数据的填充
010036A0  |.  6A 04         PUSH 0x4
010036A2  |.  EB 02         JMP SHORT winmine.010036A6
010036A4  |>  6A 06         PUSH 0x6                                           ;  push 04和push 06很有可能判断用户是不是进行了跟更改界面大小的设置,现在的ebx可能就是对这个设置进行保存
010036A6  |>  5B            POP EBX                                            ;  猜测是保存是否更改界面的类型的值,ebx ==06 或0x4
010036A7  |.  A3 34530001   MOV DWORD PTR DS:[<宽度0>],EAX                       ;  eax == 宽度1 ,把宽度1 赋值给宽度0,说明宽度1才是真正的宽度的基址
010036AC  |.  890D 38530001 MOV DWORD PTR DS:[<高度0>],ECX                       ;  ecx  == 高度0,把高度0赋值给高度1,说明高度0才是真正的高度的基址
010036B2  |.  E8 1EF8FFFF   CALL winmine.01002ED5                              ;  call 的这个函数目测是一个循环,先不搞,把整个大体流程分析完之后再搞
010036B7  |.  A1 A4560001   MOV EAX,DWORD PTR DS:[<地雷1>]                       ;  eax == 地雷1的地址
010036BC  |.  893D 60510001 MOV DWORD PTR DS:[0x1005160],EDI                   ;  edi=0,把0 移动到这个地址,暂时不明白是干嘛的
010036C2  |.  A3 30530001   MOV DWORD PTR DS:[<地雷0>],EAX                       ;  eax == 地雷1的地址,把地雷1中的值赋值给地雷0,说明地雷1才是地雷的真正的基址
010036C7  |>  FF35 34530001 PUSH DWORD PTR DS:[<宽度0>]                          ;  把宽度0(x轴的坐标)入栈
010036CD  |.  E8 6E020000   CALL <winmine.产生随机数>                               ;  ctrl+a 发现这个是rand函数,然后根据入栈的数据就可以说明这个是根据某个值产生随机的值,这个函数可以不用看了
010036D2  |.  FF35 38530001 PUSH DWORD PTR DS:[<高度0>]                          ;  高度0入栈
010036D8  |.  8BF0          MOV ESI,EAX                                        ;  esi = eax应该是函数返回值
010036DA  |.  46            INC ESI                                            ;  esi +1 ,根据宽度产生的随机数+1,esi保存根据宽度产生的随机值
010036DB  |.  E8 60020000   CALL <winmine.产生随机数>
010036E0  |.  40            INC EAX                                            ;  根据高度产生的随机值+1
010036E1  |.  8BC8          MOV ECX,EAX                                        ;  ecx = 根据高度产生的随机值
010036E3  |.  C1E1 05       SHL ECX,0x5                                        ;  ecx  =ecx*32,根据高度产生的随机值左移5位
010036E6  |.  F68431 405300>TEST BYTE PTR DS:[ECX+ESI+<雷区界面基址>],0x80           ;  ecx是随机数,esi也是随机数,+一个地址应该是去锁定其中的数组为止,说明这个值就是数组基址
010036EE  |.^ 75 D7         JNZ SHORT winmine.010036C7                         ;  跟80进行比较,可能说明80就是非雷的区域,如果不是非雷的区域,要么是边界要么是雷,所以需要跳转重新计算
010036F0  |.  C1E0 05       SHL EAX,0x5                                        ;  eax左移5位就是ecx中的值
010036F3  |.  8D8430 405300>LEA EAX,DWORD PTR DS:[EAX+ESI+<雷区界面基址>]            ;  把区域具体的数组的地址放到eax中
010036FA  |.  8008 80       OR BYTE PTR DS:[EAX],0x80                          ;  把eax中第一个字节火上80,哎呦可能是设置雷了,说明80是并不是空地,运行起来发现0f是空地,8f是地雷
010036FD  |.  FF0D 30530001 DEC DWORD PTR DS:[<地雷0>]                           ;  设置好雷之后对设置的地雷数量进行-1
01003703  |.^ 75 C2         JNZ SHORT winmine.010036C7                         ;  判断地雷0中保存的值是否为0,不是的化重复设置地雷
01003705  |.  8B0D 38530001 MOV ECX,DWORD PTR DS:[<高度0>]                       ;  ecx = 高度0的值
0100370B  |.  0FAF0D 345300>IMUL ECX,DWORD PTR DS:[<宽度0>]                      ;  ecx = 用户设置的高度的值* 用户设置的宽度的值
01003712  |.  A1 A4560001   MOV EAX,DWORD PTR DS:[<地雷1>]                       ;  eax = 地雷的值
01003717  |.  2BC8          SUB ECX,EAX                                        ;  ecx = 高度*宽度 -地雷数,这是干啥的?
01003719  |.  57            PUSH EDI                                           ;  根据后面有pop edi,应该是保存环境
0100371A  |.  893D 9C570001 MOV DWORD PTR DS:[0x100579C],EDI
01003720  |.  A3 30530001   MOV DWORD PTR DS:[<地雷0>],EAX
01003725  |.  A3 94510001   MOV DWORD PTR DS:[0x1005194],EAX
0100372A  |.  893D A4570001 MOV DWORD PTR DS:[0x10057A4],EDI
01003730  |.  890D A0570001 MOV DWORD PTR DS:[0x10057A0],ECX
01003736  |.  C705 00500001>MOV DWORD PTR DS:[0x1005000],0x1
01003740  |.  E8 25FDFFFF   CALL winmine.0100346A
01003745  |.  53            PUSH EBX
01003746  |.  E8 05E2FFFF   CALL winmine.01001950
0100374B  |.  5F            POP EDI
0100374C  |.  5E            POP ESI
0100374D  |.  5B            POP EBX
0100374E  \.  C3            RETN

接下来对几个关键函数进行分析,比如产生随机雷之前有个有很多循环的函数,估计事初始化界面数组的函数,进去分析一下

01002ED5  /$  B8 60030000   MOV EAX,0x360                                      ;  eax = 0x360 ,不知道要干嘛,接着看
01002EDA  |>  48            /DEC EAX                                           ;  eax -=1
01002EDB  |.  C680 40530001>|MOV BYTE PTR DS:[EAX+<雷区界面基址>],0xF                ;  通过流程分析可以知道,0xf是空地的类型值,说明在初始化空地
01002EE2  |.^ 75 F6         \JNZ SHORT winmine.01002EDA                        ;  说明数组应该是0x360 这么大
01002EE4  |.  8B0D 34530001 MOV ECX,DWORD PTR DS:[<宽度0>]                       ;  ecx =宽度的数值,x轴
01002EEA  |.  8B15 38530001 MOV EDX,DWORD PTR DS:[<高度0>]                       ;  edx= 高度的数值,y轴
01002EF0  |.  8D41 02       LEA EAX,DWORD PTR DS:[ECX+0x2]                     ;  额,没看懂,把宽度+2 保存到eax中,eax == 宽度+2
01002EF3  |.  85C0          TEST EAX,EAX                                       ;  判断eax是不是为空
01002EF5  |.  56            PUSH ESI                                           ;  根据函数最后有pop esi,应该是保存环境
01002EF6  |.  74 19         JE SHORT winmine.01002F11                          ;  如果eax=0,跳转
01002EF8  |.  8BF2          MOV ESI,EDX                                        ;  esi  =高度的数值,y轴
01002EFA  |.  C1E6 05       SHL ESI,0x5                                        ;  esi = 代表y轴的高度*32
01002EFD  |.  8DB6 60530001 LEA ESI,DWORD PTR DS:[ESI+0x1005360]               ;  esi = [数组基址+0x20 +esi(高度*32)],应该是这个高度下的数组的最下一行
01002F03  |>  48            /DEC EAX                                           ;  eax = 宽度+2,说明左右的边界各占1,eax-=1
01002F04  |.  C680 40530001>|MOV BYTE PTR DS:[EAX+<雷区界面基址>],0x10               ;  10应该就是边界的类型了,这个应该是填充数组第一行的边界,从右往左
01002F0B  |.  C60406 10     |MOV BYTE PTR DS:[ESI+EAX],0x10                    ;  这个高度下区域最下面的边界,也是从右往左填充的
01002F0F  |.^ 75 F2         \JNZ SHORT winmine.01002F03                        ;  eax!=0 循环填充边界
01002F11  |>  8D72 02       LEA ESI,DWORD PTR DS:[EDX+0x2]                     ;  同样的,esi 保存的是高度的数值+2,从而说明上下边界高度是1,而且不占游戏界面的区域
01002F14  |.  85F6          TEST ESI,ESI                                       ;  判断esi 是不是为空
01002F16  |.  74 21         JE SHORT winmine.01002F39                          ;  为空直接跳出了
01002F18  |.  8BC6          MOV EAX,ESI                                        ;  eax =高度的值+0x2
01002F1A  |.  C1E0 05       SHL EAX,0x5                                        ;  eax =(高度的值+0x2)*32
01002F1D  |.  8D90 40530001 LEA EDX,DWORD PTR DS:[EAX+<雷区界面基址>]                ;  这两行应该也是要填充边界的为止,具体的就不看了
01002F23  |.  8D8408 415300>LEA EAX,DWORD PTR DS:[EAX+ECX+0x1005341]           ;  edx 和eax应该是最下一行,最左边和最右边的值
01002F2A  |>  83EA 20       /SUB EDX,0x20                                      ;  0x20 应该是2行
01002F2D  |.  83E8 20       |SUB EAX,0x20
01002F30  |.  4E            |DEC ESI                                           ;  esi -=1
01002F31  |.  C602 10       |MOV BYTE PTR DS:[EDX],0x10                        ;  进行边界填充
01002F34  |.  C600 10       |MOV BYTE PTR DS:[EAX],0x10                        ;  边界填充
01002F37  |.^ 75 F1         \JNZ SHORT winmine.01002F2A
01002F39  |>  5E            POP ESI
01002F3A  \.  C3            RETN

通过分析可以看出,这个函数只是对空地和边界进行填充

 

通过上述的分析,大体知道了初始化雷区的的公式

 

划重点:数组基址+0x20 +esi(高度*32),如果这个位置的opcode是0x8f,说明是雷,0xf说明是空地

 

然后去看一下内存图

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 8F 8F 8F 0F 0F 0F 0F 8F 0F 0F 8F 0F 0F 8F 10  弿????
01005370   0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  
01005380   10 8F 8F 0F 0F 0F 8F 0F 0F 0F 0F 8F 8F 0F 0F 10  弿?弿
01005390   0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  
010053A0   10 0F 8F 0F 0F 0F 8F 8F 0F 8F 0F 0F 8F 8F 8F 10  ?弿?弿?
010053B0   0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  
010053C0   10 0F 8F 8F 0F 0F 8F 8F 0F 0F 8F 0F 8F 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 8F 8F 0F 0F 8F 0F 8F 0F 8F 8F 10  弿??弿
010053F0   0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  
01005400   10 8F 8F 8F 0F 0F 8F 8F 8F 8F 8F 8F 0F 8F 0F 10  弿?弿弿弿?
01005410   0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  
01005420   10 8F 0F 0F 8F 8F 0F 8F 0F 0F 8F 8F 8F 0F 0F 10  ?弿?弿?
01005430   0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  
01005440   10 0F 8F 0F 0F 0F 0F 0F 0F 8F 0F 0F 0F 8F 8F 10  ??弿
01005450   0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  
01005460   10 8F 8F 8F 8F 0F 8F 0F 8F 0F 8F 0F 8F 0F 8F 10  弿弿?????
01005470   0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  
01005480   10 8F 8F 8F 0F 0F 0F 8F 0F 0F 8F 0F 0F 8F 8F 10  弿???弿
01005490   0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  
010054A0   10 0F 8F 8F 0F 0F 0F 0F 0F 8F 0F 0F 8F 0F 8F 10  弿???
010054B0   0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  
010054C0   10 8F 8F 0F 0F 8F 8F 8F 0F 8F 8F 8F 8F 0F 8F 10  弿弿?弿弿?
010054D0   0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  
010054E0   10 8F 8F 0F 8F 0F 0F 8F 8F 8F 0F 8F 0F 8F 8F 10  弿?弿??弿
010054F0   0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  
01005500   10 8F 8F 8F 0F 8F 0F 0F 0F 8F 8F 0F 8F 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  

从内存图可以看出,是每隔一行进行填充 ,因此可以总结数组的遍历公式

 

具体的某个x,y坐标下的值= 数组基址+ 高<<5(也就是+32,每隔一行进行填充)+x

 

而且通过填充的时候add eax ,2 等类似的消息可以看出,边界应该是0,内容是从1开始的,循环的时候要注意

 

现在去分析一下窗口回调函数(主要是找怎么把鼠标按下的点转换成数组下标的方法)

 

祭出 大微软的 spy ++

 

od直接定位到这个回调函数的位置

 

主要是想看看怎么把鼠标点击的屏幕坐标转换成数组下标的

 

定位之后发现 代码真长,可能超过300行了QAQ

01001BC9  /.  55            PUSH EBP                                         ;  回调函数
01001BCA  |.  8BEC          MOV EBP,ESP
01001BCC  |.  83EC 40       SUB ESP,0x40                                     ;  开辟局部空间
01001BCF  |.  8B55 0C       MOV EDX,[ARG.2]                                  ;  edx  =uMsg
01001BD2  |.  8B4D 14       MOV ECX,[ARG.4]                                  ;  edx = lParam
01001BD5  |.  53            PUSH EBX                                         ;  保存寄存器环境
01001BD6  |.  56            PUSH ESI                                         ;  保存寄存器环境
01001BD7  |.  33DB          XOR EBX,EBX                                      ;  ebx = 0
01001BD9  |.  57            PUSH EDI                                         ;  保存寄存器环境
01001BDA  |.  BE 00020000   MOV ESI,0x200                                    ;  esi =0x200,通过下面确定esi是wm_mousemove
01001BDF  |.  43            INC EBX                                          ;  ebx =1
01001BE0  |.  33FF          XOR EDI,EDI                                      ;  edi =0
01001BE2  |.  3BD6          CMP EDX,ESI                                      ;  edx和esi进行比较,也就是uMsg和0x200进行比较,现在可以确定esi是WM_MOUSEMOVE
01001BE4  |.  0F87 75030000 JA winmine.01001F5F                              ;  大于跳到这个地方去,需要看LBUTTONDOWN或LBUTTONUP的处理
01001BEA  |.  0F84 95040000 JE winmine.01002085                              ;  等于mousemove跳转到这个地方,小于的话就继续下面的代码,因为LBUTTONDOWN和LBUTTONUP都大于0x200,暂时先不看下面的了
01001BF0  |.  B8 00010000   MOV EAX,0x100
01001BF5  |.  3BD0          CMP EDX,EAX
01001BF7  |.  0F87 5C010000 JA winmine.01001D59
01001BFD  |.  0F84 97000000 JE winmine.01001C9A
01001C03  |.  8BC2          MOV EAX,EDX
01001C05  |.  48            DEC EAX                                          ;  Switch (cases 2..47)
01001C06  |.  48            DEC EAX
01001C07  |.  74 76         JE SHORT winmine.01001C7F
01001C09  |.  83E8 04       SUB EAX,0x4
01001C0C  |.  74 57         JE SHORT winmine.01001C65
01001C0E  |.  83E8 09       SUB EAX,0x9
01001C11  |.  74 2B         JE SHORT winmine.01001C3E
01001C13  |.  83E8 38       SUB EAX,0x38
01001C16  |.  0F85 8D050000 JNZ winmine.010021A9
01001C1C  |.  F605 00500001>TEST BYTE PTR DS:[0x1005000],0x8                 ;  Case 47 of switch 01001C05
01001C23  |.  0F85 80050000 JNZ winmine.010021A9
01001C29  |.  8B41 08       MOV EAX,DWORD PTR DS:[ECX+0x8]
01001C2C  |.  A3 B0560001   MOV DWORD PTR DS:[0x10056B0],EAX
01001C31  |.  8B41 0C       MOV EAX,DWORD PTR DS:[ECX+0xC]
01001C34  |.  A3 B4560001   MOV DWORD PTR DS:[0x10056B4],EAX
01001C39  |.  E9 6B050000   JMP winmine.010021A9
01001C3E  |>  8D45 C0       LEA EAX,[LOCAL.16]                               ;  Case F of switch 01001C05
01001C41  |.  50            PUSH EAX                                         ; /pPaintstruct
01001C42  |.  FF75 08       PUSH [ARG.1]                                     ; |hWnd
01001C45  |.  FF15 44110001 CALL DWORD PTR DS:[<&USER32.BeginPaint>]         ; \BeginPaint
01001C4B  |.  50            PUSH EAX
01001C4C  |.  E8 720E0000   CALL winmine.01002AC3
01001C51  |.  8D45 C0       LEA EAX,[LOCAL.16]
01001C54  |.  50            PUSH EAX                                         ; /pPaintstruct
01001C55  |.  FF75 08       PUSH [ARG.1]                                     ; |hWnd
01001C58  |.  FF15 40110001 CALL DWORD PTR DS:[<&USER32.EndPaint>]           ; \EndPaint
01001C5E  |>  33C0          XOR EAX,EAX
01001C60  |.  E9 56050000   JMP winmine.010021BB
01001C65  |>  66:837D 10 02 CMP WORD PTR SS:[EBP+0x10],0x2                   ;  Case 6 of switch 01001C05
01001C6A  |.  0F85 39050000 JNZ winmine.010021A9
01001C70  |.  C705 48510001>MOV DWORD PTR DS:[0x1005148],0x1
01001C7A  |.  E9 2A050000   JMP winmine.010021A9
01001C7F  |>  6A 01         PUSH 0x1                                         ; /TimerID = 0x1; Case 2 of switch 01001C05
01001C81  |.  FF35 245B0001 PUSH DWORD PTR DS:[0x1005B24]                    ; |hWnd = 000F44AE ('扫雷',class='扫雷')
01001C87  |.  FF15 3C110001 CALL DWORD PTR DS:[<&USER32.KillTimer>]          ; \KillTimer
01001C8D  |.  6A 00         PUSH 0x0                                         ; /ExitCode = 0x0
01001C8F  |.  FF15 38110001 CALL DWORD PTR DS:[<&USER32.PostQuitMessage>]    ; \PostQuitMessage
01001C95  |.  E9 0F050000   JMP winmine.010021A9
01001C9A  |>  8B45 10       MOV EAX,[ARG.3]
01001C9D  |.  83E8 10       SUB EAX,0x10                                     ;  Switch (cases 10..75)
01001CA0  |.  0F84 9A000000 JE winmine.01001D40
01001CA6  |.  83E8 63       SUB EAX,0x63
01001CA9  |.  74 5F         JE SHORT winmine.01001D0A
01001CAB  |.  48            DEC EAX
01001CAC  |.  74 43         JE SHORT winmine.01001CF1
01001CAE  |.  48            DEC EAX
01001CAF  |.  74 2F         JE SHORT winmine.01001CE0
01001CB1  |.  A1 54510001   MOV EAX,DWORD PTR DS:[0x1005154]                 ;  Default case of switch 01001C9D
01001CB6  |.  83F8 05       CMP EAX,0x5
01001CB9  |.  0F8D EA040000 JGE winmine.010021A9
01001CBF  |.  66:8B0C45 345>MOV CX,WORD PTR DS:[EAX*2+0x1005034]
01001CC7  |.  66:2B4D 10    SUB CX,WORD PTR SS:[EBP+0x10]
01001CCB  |.  40            INC EAX
01001CCC  |.  66:F7D9       NEG CX
01001CCF  |.  1BC9          SBB ECX,ECX
01001CD1  |.  F7D1          NOT ECX
01001CD3  |.  23C8          AND ECX,EAX
01001CD5  |.  890D 54510001 MOV DWORD PTR DS:[0x1005154],ECX
01001CDB  |.  E9 C9040000   JMP winmine.010021A9
01001CE0  |>  833D C4560001>CMP DWORD PTR DS:[0x10056C4],0x0                 ;  Case 75 of switch 01001C9D
01001CE7  |.  0F84 BC040000 JE winmine.010021A9
01001CED  |.  6A 02         PUSH 0x2
01001CEF  |.  EB 0F         JMP SHORT winmine.01001D00
01001CF1  |>  833D C4560001>CMP DWORD PTR DS:[0x10056C4],0x0                 ;  Case 74 of switch 01001C9D
01001CF8  |.  0F84 AB040000 JE winmine.010021A9
01001CFE  |.  6A 01         PUSH 0x1
01001D00  |>  E8 E01F0000   CALL winmine.01003CE5
01001D05  |.  E9 9F040000   JMP winmine.010021A9
01001D0A  |>  A1 B8560001   MOV EAX,DWORD PTR DS:[0x10056B8]                 ;  Case 73 of switch 01001C9D
01001D0F  |.  83F8 01       CMP EAX,0x1
01001D12  |.  0F8E 91040000 JLE winmine.010021A9
01001D18  |.  83F8 03       CMP EAX,0x3
01001D1B  |.  75 14         JNZ SHORT winmine.01001D31
01001D1D  |.  E8 B51B0000   CALL winmine.010038D7
01001D22  |.  C705 B8560001>MOV DWORD PTR DS:[0x10056B8],0x2
01001D2C  |.  E9 78040000   JMP winmine.010021A9
01001D31  |>  E8 8C1B0000   CALL winmine.010038C2
01001D36  |.  A3 B8560001   MOV DWORD PTR DS:[0x10056B8],EAX
01001D3B  |.  E9 69040000   JMP winmine.010021A9
01001D40  |>  833D 54510001>CMP DWORD PTR DS:[0x1005154],0x5                 ;  Case 10 of switch 01001C9D
01001D47  |.  0F8C 5C040000 JL winmine.010021A9
01001D4D  |.  8335 54510001>XOR DWORD PTR DS:[0x1005154],0x14
01001D54  |.  E9 50040000   JMP winmine.010021A9
01001D59  |>  8BC2          MOV EAX,EDX
01001D5B  |.  2D 11010000   SUB EAX,0x111                                    ;  Switch (cases 111..113)
01001D60  |.  74 5A         JE SHORT winmine.01001DBC
01001D62  |.  48            DEC EAX
01001D63  |.  74 11         JE SHORT winmine.01001D76
01001D65  |.  48            DEC EAX
01001D66  |.  0F85 3D040000 JNZ winmine.010021A9
01001D6C  |.  E8 6F120000   CALL winmine.01002FE0                            ;  Case 113 (WM_TIMER) of switch 01001D5B
01001D71  |.^ E9 E8FEFFFF   JMP winmine.01001C5E
01001D76  |>  8B45 10       MOV EAX,[ARG.3]                                  ;  Case 112 (WM_SYSCOMMAND) of switch 01001D5B
01001D79  |.  25 F0FF0000   AND EAX,0xFFF0
01001D7E  |.  3D 20F00000   CMP EAX,0xF020
01001D83  |.  74 26         JE SHORT winmine.01001DAB
01001D85  |.  3D 20F10000   CMP EAX,0xF120
01001D8A  |.  0F85 19040000 JNZ winmine.010021A9
01001D90  |.  8125 00500001>AND DWORD PTR DS:[0x1005000],0xF5
01001D9A  |.  E8 AD160000   CALL winmine.0100344C
01001D9F  |.  8325 48510001>AND DWORD PTR DS:[0x1005148],0x0
01001DA6  |.  E9 FE030000   JMP winmine.010021A9
01001DAB  |>  E8 6C160000   CALL winmine.0100341C
01001DB0  |.  830D 00500001>OR DWORD PTR DS:[0x1005000],0xA
01001DB7  |.  E9 ED030000   JMP winmine.010021A9
01001DBC  |>  0FB745 10     MOVZX EAX,WORD PTR SS:[EBP+0x10]                 ;  Case 111 (WM_COMMAND) of switch 01001D5B
01001DC0  |.  B9 10020000   MOV ECX,0x210
01001DC5  |.  3BC1          CMP EAX,ECX
01001DC7  |.  0F8F 0F010000 JG winmine.01001EDC
01001DCD  |.  0F84 FF000000 JE winmine.01001ED2
01001DD3  |.  3D FE010000   CMP EAX,0x1FE
01001DD8  |.  0F84 EA000000 JE winmine.01001EC8
01001DDE  |.  3BC6          CMP EAX,ESI
01001DE0  |.  0F84 B7000000 JE winmine.01001E9D
01001DE6  |.  3D 08020000   CMP EAX,0x208                                    ;  Switch (cases 209..20F)
01001DEB  |.  0F8E B8030000 JLE winmine.010021A9
01001DF1  |.  3D 0B020000   CMP EAX,0x20B
01001DF6  |.  7E 61         JLE SHORT winmine.01001E59
01001DF8  |.  3D 0C020000   CMP EAX,0x20C
01001DFD  |.  74 50         JE SHORT winmine.01001E4F
01001DFF  |.  3D 0E020000   CMP EAX,0x20E
01001E04  |.  74 20         JE SHORT winmine.01001E26
01001E06  |.  3D 0F020000   CMP EAX,0x20F
01001E0B  |.  0F85 98030000 JNZ winmine.010021A9
01001E11  |.  33C0          XOR EAX,EAX                                      ;  Case 20F of switch 01001DE6
01001E13  |.  3905 BC560001 CMP DWORD PTR DS:[0x10056BC],EAX
01001E19  |.  0F94C0        SETE AL
01001E1C  |.  A3 BC560001   MOV DWORD PTR DS:[0x10056BC],EAX
01001E21  |.  E9 24010000   JMP winmine.01001F4A
01001E26  |>  33FF          XOR EDI,EDI                                      ;  Case 20E of switch 01001DE6
01001E28  |.  393D B8560001 CMP DWORD PTR DS:[0x10056B8],EDI
01001E2E  |.  74 10         JE SHORT winmine.01001E40
01001E30  |.  E8 A21A0000   CALL winmine.010038D7
01001E35  |.  893D B8560001 MOV DWORD PTR DS:[0x10056B8],EDI
01001E3B  |.  E9 0A010000   JMP winmine.01001F4A
01001E40  |>  E8 7D1A0000   CALL winmine.010038C2
01001E45  |.  A3 B8560001   MOV DWORD PTR DS:[0x10056B8],EAX
01001E4A  |.  E9 FB000000   JMP winmine.01001F4A
01001E4F  |>  E8 F5FCFFFF   CALL winmine.01001B49                            ;  Case 20C of switch 01001DE6
01001E54  |.  E9 50030000   JMP winmine.010021A9
01001E59  |>  8B45 10       MOV EAX,[ARG.3]                                  ;  Cases 209,20A,20B of switch 01001DE6
01001E5C  |.  05 F7FDFFFF   ADD EAX,-0x209
01001E61  |.  66:A3 A056000>MOV WORD PTR DS:[0x10056A0],AX
01001E67  |.  0FB7C0        MOVZX EAX,AX
01001E6A  |.  8D0440        LEA EAX,DWORD PTR DS:[EAX+EAX*2]
01001E6D  |.  C1E0 02       SHL EAX,0x2
01001E70  |.  8B88 10500001 MOV ECX,DWORD PTR DS:[EAX+0x1005010]
01001E76  |.  890D A4560001 MOV DWORD PTR DS:[<地雷1>],ECX
01001E7C  |.  8B88 14500001 MOV ECX,DWORD PTR DS:[EAX+0x1005014]
01001E82  |.  8B80 18500001 MOV EAX,DWORD PTR DS:[EAX+0x1005018]
01001E88  |.  890D A8560001 MOV DWORD PTR DS:[<高度1>],ECX
01001E8E  |.  A3 AC560001   MOV DWORD PTR DS:[<宽度1>],EAX
01001E93  |.  E8 E2170000   CALL winmine.0100367A
01001E98  |.  E9 AD000000   JMP winmine.01001F4A
01001E9D  |>  33FF          XOR EDI,EDI
01001E9F  |.  57            PUSH EDI                                         ; /ShowState => SW_HIDE
01001EA0  |.  FF35 245B0001 PUSH DWORD PTR DS:[0x1005B24]                    ; |hWnd = 000F44AE ('扫雷',class='扫雷')
01001EA6  |.  FF15 34110001 CALL DWORD PTR DS:[<&USER32.ShowWindow>]         ; \ShowWindow
01001EAC  |>  57            PUSH EDI                                         ; /lParam
01001EAD  |.  68 60F00000   PUSH 0xF060                                      ; |wParam = 0xF060
01001EB2  |.  68 12010000   PUSH 0x112                                       ; |Message = WM_SYSCOMMAND
01001EB7  |.  FF35 245B0001 PUSH DWORD PTR DS:[0x1005B24]                    ; |hWnd = 0xF44AE
01001EBD  |.  FF15 00110001 CALL DWORD PTR DS:[<&USER32.SendMessageW>]       ; \SendMessageW
01001EC3  |.^ E9 96FDFFFF   JMP winmine.01001C5E
01001EC8  |>  E8 AD170000   CALL winmine.0100367A
01001ECD  |.  E9 D7020000   JMP winmine.010021A9
01001ED2  |>  E8 D3FCFFFF   CALL winmine.01001BAA
01001ED7  |.  E9 CD020000   JMP winmine.010021A9
01001EDC  |>  2D 11020000   SUB EAX,0x211                                    ;  Switch (cases 211..251)
01001EE1  |.  74 36         JE SHORT winmine.01001F19
01001EE3  |.  83E8 3D       SUB EAX,0x3D
01001EE6  |.  74 23         JE SHORT winmine.01001F0B
01001EE8  |.  48            DEC EAX
01001EE9  |.  74 1A         JE SHORT winmine.01001F05
01001EEB  |.  48            DEC EAX
01001EEC  |.  74 11         JE SHORT winmine.01001EFF
01001EEE  |.  48            DEC EAX
01001EEF  |.  0F85 B4020000 JNZ winmine.010021A9
01001EF5  |.  E8 231E0000   CALL winmine.01003D1D                            ;  Case 251 of switch 01001EDC
01001EFA  |.^ E9 5FFDFFFF   JMP winmine.01001C5E
01001EFF  |>  6A 00         PUSH 0x0                                         ;  Case 250 of switch 01001EDC
01001F01  |.  6A 04         PUSH 0x4
01001F03  |.  EB 0A         JMP SHORT winmine.01001F0F
01001F05  |>  6A 02         PUSH 0x2                                         ;  Case 24F of switch 01001EDC
01001F07  |.  6A 01         PUSH 0x1
01001F09  |.  EB 04         JMP SHORT winmine.01001F0F
01001F0B  |>  6A 00         PUSH 0x0                                         ;  Case 24E of switch 01001EDC
01001F0D  |.  6A 03         PUSH 0x3
01001F0F  |>  E8 621E0000   CALL winmine.01003D76
01001F14  |.  E9 90020000   JMP winmine.010021A9
01001F19  |>  33C0          XOR EAX,EAX                                      ;  Case 211 of switch 01001EDC
01001F1B  |.  33FF          XOR EDI,EDI
01001F1D  |.  393D C8560001 CMP DWORD PTR DS:[0x10056C8],EDI
01001F23  |.  0F94C0        SETE AL
01001F26  |.  A3 C8560001   MOV DWORD PTR DS:[0x10056C8],EAX
01001F2B  |.  E8 D7060000   CALL winmine.01002607
01001F30  |.  E8 DF040000   CALL winmine.01002414
01001F35  |.  85C0          TEST EAX,EAX
01001F37  |.  75 0C         JNZ SHORT winmine.01001F45
01001F39  |.  6A 05         PUSH 0x5
01001F3B  |.  E8 101A0000   CALL winmine.01003950
01001F40  |.^ E9 67FFFFFF   JMP winmine.01001EAC
01001F45  |>  E8 A60B0000   CALL winmine.01002AF0
01001F4A  |>  FF35 C4560001 PUSH DWORD PTR DS:[0x10056C4]
01001F50  |.  C705 5C510001>MOV DWORD PTR DS:[0x100515C],0x1
01001F5A  |.^ E9 A1FDFFFF   JMP winmine.01001D00
01001F5F  |>  8D82 FFFDFFFF LEA EAX,DWORD PTR DS:[EDX-0x201]                 ;  Switch (cases 201..212)
01001F65  |.  83F8 11       CMP EAX,0x11                                     ;  跟WM_EXITMENULOOP 进行比较
01001F68  |.  0F87 3B020000 JA winmine.010021A9
01001F6E  |.  0FB680 DE2100>MOVZX EAX,BYTE PTR DS:[EAX+0x10021DE]
01001F75  |.  FF2485 C22100>JMP DWORD PTR DS:[EAX*4+0x10021C2]
01001F7C  |>  393D 48510001 CMP DWORD PTR DS:[0x1005148],EDI                 ;  Case 207 (WM_MBUTTONDOWN) of switch 01001F5F
01001F82  |.  74 0B         JE SHORT winmine.01001F8F
01001F84  |>  893D 48510001 MOV DWORD PTR DS:[0x1005148],EDI
01001F8A  |.^ E9 CFFCFFFF   JMP winmine.01001C5E
01001F8F  |>  841D 00500001 TEST BYTE PTR DS:[0x1005000],BL
01001F95  |.  0F84 0E020000 JE winmine.010021A9
01001F9B  |.  891D 44510001 MOV DWORD PTR DS:[0x1005144],EBX
01001FA1  |.  E9 B9000000   JMP winmine.0100205F
01001FA6  |>  393D 48510001 CMP DWORD PTR DS:[0x1005148],EDI                 ;  Case 201 (WM_LBUTTONDOWN) of switch 01001F5F
01001FAC  |.^ 75 D6         JNZ SHORT winmine.01001F84
01001FAE  |.  FF75 14       PUSH [ARG.4]                                     ;  lparam
01001FB1  |.  E8 56F4FFFF   CALL winmine.0100140C                            ;  获取鼠标点击时的坐标,判断坐标是不是在rect中
01001FB6  |.  85C0          TEST EAX,EAX
01001FB8  |.^ 0F85 A0FCFFFF JNZ winmine.01001C5E
01001FBE  |.  841D 00500001 TEST BYTE PTR DS:[0x1005000],BL                  ;  ebx是在PtInRect中设置的,按位于
01001FC4  |.  0F84 DF010000 JE winmine.010021A9
01001FCA  |.  8B45 10       MOV EAX,[ARG.3]                                  ;  eax =wParam
01001FCD  |.  24 06         AND AL,0x6                                       ;  用wParam来判断down的是什么
01001FCF  |.  F6D8          NEG AL                                           ;  求补运算
01001FD1  |.  1BC0          SBB EAX,EAX                                      ;  借位减
01001FD3  |.  F7D8          NEG EAX
01001FD5  |.  A3 44510001   MOV DWORD PTR DS:[0x1005144],EAX
01001FDA  |.  E9 80000000   JMP winmine.0100205F
01001FDF  |>  33FF          XOR EDI,EDI                                      ;  Cases 202 (WM_LBUTTONUP),205 (WM_RBUTTONUP),208 (WM_MBUTTONUP) of switch 01001F5F
01001FE1  |.  393D 40510001 CMP DWORD PTR DS:[0x1005140],EDI
01001FE7  |.  0F84 BC010000 JE winmine.010021A9
01001FED  |>  893D 40510001 MOV DWORD PTR DS:[0x1005140],EDI
01001FF3  |.  FF15 D8100001 CALL DWORD PTR DS:[<&USER32.ReleaseCapture>]     ; [ReleaseCapture
01001FF9  |.  841D 00500001 TEST BYTE PTR DS:[0x1005000],BL
01001FFF  |.  0F84 B6000000 JE winmine.010020BB
01002005  |.  E8 D7170000   CALL winmine.010037E1
0100200A  |.  E9 9A010000   JMP winmine.010021A9
0100200F  |>  393D 48510001 CMP DWORD PTR DS:[0x1005148],EDI                 ;  Case 204 (WM_RBUTTONDOWN) of switch 01001F5F
01002015  |.^ 0F85 69FFFFFF JNZ winmine.01001F84
0100201B  |.  841D 00500001 TEST BYTE PTR DS:[0x1005000],BL
01002021  |.  0F84 82010000 JE winmine.010021A9
01002027  |.  393D 40510001 CMP DWORD PTR DS:[0x1005140],EDI
0100202D  |.  74 27         JE SHORT winmine.01002056
0100202F  |.  6A FD         PUSH -0x3
01002031  |.  6A FD         PUSH -0x3
01002033  |.  E8 9C110000   CALL winmine.010031D4
01002038  |.  FF75 14       PUSH [ARG.4]                                     ; /lParam
0100203B  |.  891D 44510001 MOV DWORD PTR DS:[0x1005144],EBX                 ; |
01002041  |.  FF75 10       PUSH [ARG.3]                                     ; |wParam
01002044  |.  56            PUSH ESI                                         ; |Message
01002045  |.  FF35 245B0001 PUSH DWORD PTR DS:[0x1005B24]                    ; |hWnd = 0xF44AE
0100204B  |.  FF15 30110001 CALL DWORD PTR DS:[<&USER32.PostMessageW>]       ; \PostMessageW
01002051  |.^ E9 08FCFFFF   JMP winmine.01001C5E
01002056  |>  845D 10       TEST BYTE PTR SS:[EBP+0x10],BL
01002059  |.  0F84 09010000 JE winmine.01002168
0100205F  |>  FF75 08       PUSH [ARG.1]                                     ; /hWnd
01002062  |.  FF15 E4100001 CALL DWORD PTR DS:[<&USER32.SetCapture>]         ; \SetCapture
01002068  |.  830D 18510001>OR DWORD PTR DS:[0x1005118],0xFFFFFFFF           ;  上面进行了鼠标捕获
0100206F  |.  830D 1C510001>OR DWORD PTR DS:[0x100511C],0xFFFFFFFF           ;  这边都进行填0不是很理解
01002076  |.  53            PUSH EBX
01002077  |.  891D 40510001 MOV DWORD PTR DS:[0x1005140],EBX
0100207D  |.  E8 91080000   CALL winmine.01002913
01002082  |.  8B4D 14       MOV ECX,[ARG.4]                                  ;  ecx = lparam
01002085  |>  393D 40510001 CMP DWORD PTR DS:[0x1005140],EDI                 ;  没理解
0100208B  |.  74 34         JE SHORT winmine.010020C1
0100208D  |.  841D 00500001 TEST BYTE PTR DS:[0x1005000],BL                  ;  这个bl是在哪设置的也忘记了
01002093  |.^ 0F84 54FFFFFF JE winmine.01001FED
01002099  |.  8B45 14       MOV EAX,[ARG.4]                                  ;  从这里的代码开始,下面的就是坐标转成数组的公式了eax = lparam
0100209C  |.  C1E8 10       SHR EAX,0x10                                     ;  eax 右移16位,相当于eax  =(HIWORD)lparam
0100209F  |.  83E8 27       SUB EAX,0x27                                     ;  eax(HIWORD的lParam)-0x27
010020A2  |.  C1F8 04       SAR EAX,0x4                                      ;  eax算数右移4位
010020A5  |.  50            PUSH EAX                                         ;  eax 入栈
010020A6  |.  0FB745 14     MOVZX EAX,WORD PTR SS:[EBP+0x14]                 ;  入栈的第四个参数,就是lparam,eax = (LOWORD)lparam
010020AA  |.  83C0 04       ADD EAX,0x4                                      ;  (LOWROD)lparam 加0x4
010020AD  |.  C1F8 04       SAR EAX,0x4                                      ;  然后右移4为
010020B0  |.  50            PUSH EAX                                         ;  找到,这个地方就是转换为数组的下标了
010020B1  |>  E8 1E110000   CALL winmine.010031D4
010020B6  |.  E9 EE000000   JMP winmine.010021A9
010020BB  |>  6A FE         PUSH -0x2
010020BD  |.  6A FE         PUSH -0x2
010020BF  |.^ EB F0         JMP SHORT winmine.010020B1
010020C1  |>  A1 54510001   MOV EAX,DWORD PTR DS:[0x1005154]
010020C6  |.  3BC7          CMP EAX,EDI
010020C8  |.  0F84 DB000000 JE winmine.010021A9
010020CE  |.  83F8 05       CMP EAX,0x5
010020D1  |.  75 08         JNZ SHORT winmine.010020DB
010020D3  |.  F645 10 08    TEST BYTE PTR SS:[EBP+0x10],0x8
010020D7  |.  75 08         JNZ SHORT winmine.010020E1
010020D9  |.  3BC0          CMP EAX,EAX
010020DB  |>  0F8E C8000000 JLE winmine.010021A9
010020E1  |>  0FB7C1        MOVZX EAX,CX
010020E4  |.  C1E9 10       SHR ECX,0x10
010020E7  |.  83C0 04       ADD EAX,0x4
010020EA  |.  83E9 27       SUB ECX,0x27
010020ED  |.  C1F8 04       SAR EAX,0x4
010020F0  |.  C1F9 04       SAR ECX,0x4
010020F3  |.  3BC7          CMP EAX,EDI
010020F5  |.  A3 18510001   MOV DWORD PTR DS:[0x1005118],EAX
010020FA  |.  890D 1C510001 MOV DWORD PTR DS:[0x100511C],ECX
01002100  |.  0F8E A3000000 JLE winmine.010021A9
01002106  |.  3BCF          CMP ECX,EDI
01002108  |.  0F8E 9B000000 JLE winmine.010021A9
0100210E  |.  3B05 34530001 CMP EAX,DWORD PTR DS:[<宽度0>]
01002114  |.  0F8F 8F000000 JG winmine.010021A9
0100211A  |.  3B0D 38530001 CMP ECX,DWORD PTR DS:[<高度0>]
01002120  |.  0F8F 83000000 JG winmine.010021A9
01002126  |.  57            PUSH EDI                                         ; /hWnd
01002127  |.  FF15 2C110001 CALL DWORD PTR DS:[<&USER32.GetDC>]              ; \GetDC
0100212D  |.  8B0D 18510001 MOV ECX,DWORD PTR DS:[0x1005118]
01002133  |.  8BF0          MOV ESI,EAX
01002135  |.  A1 1C510001   MOV EAX,DWORD PTR DS:[0x100511C]
0100213A  |.  C1E0 05       SHL EAX,0x5
0100213D  |.  8A8408 405300>MOV AL,BYTE PTR DS:[EAX+ECX+<雷区界面基址>]
01002144  |.  24 80         AND AL,0x80
01002146  |.  F6D8          NEG AL
01002148  |.  1BC0          SBB EAX,EAX
0100214A  |.  25 010000FF   AND EAX,0xFF000001
0100214F  |.  05 FFFFFF00   ADD EAX,0xFFFFFF
01002154  |.  50            PUSH EAX                                         ; /Color
01002155  |.  57            PUSH EDI                                         ; |Y
01002156  |.  57            PUSH EDI                                         ; |X
01002157  |.  56            PUSH ESI                                         ; |hDC
01002158  |.  FF15 58100001 CALL DWORD PTR DS:[<&GDI32.SetPixel>]            ; \SetPixel
0100215E  |.  56            PUSH ESI                                         ; /hDC
0100215F  |.  57            PUSH EDI                                         ; |hWnd
01002160  |.  FF15 28110001 CALL DWORD PTR DS:[<&USER32.ReleaseDC>]          ; \ReleaseDC
01002166  |.  EB 41         JMP SHORT winmine.010021A9
01002168  |>  393D 4C510001 CMP DWORD PTR DS:[0x100514C],EDI
0100216E  |.^ 0F85 EAFAFFFF JNZ winmine.01001C5E
01002174  |.  8B45 14       MOV EAX,[ARG.4]
01002177  |.  C1E8 10       SHR EAX,0x10
0100217A  |.  83E8 27       SUB EAX,0x27
0100217D  |.  C1F8 04       SAR EAX,0x4
01002180  |.  50            PUSH EAX
01002181  |.  0FB745 14     MOVZX EAX,WORD PTR SS:[EBP+0x14]
01002185  |.  83C0 04       ADD EAX,0x4
01002188  |.  C1F8 04       SAR EAX,0x4
0100218B  |.  50            PUSH EAX
0100218C  |.  E8 BE150000   CALL winmine.0100374F
01002191  |.^ E9 C8FAFFFF   JMP winmine.01001C5E
01002196  |>  C705 4C510001>MOV DWORD PTR DS:[0x100514C],0x1                 ;  Case 211 (WM_ENTERMENULOOP) of switch 01001F5F
010021A0  |.  EB 07         JMP SHORT winmine.010021A9
010021A2  |>  8325 4C510001>AND DWORD PTR DS:[0x100514C],0x0                 ;  Case 212 (WM_EXITMENULOOP) of switch 01001F5F
010021A9  |>  FF75 14       PUSH [ARG.4]                                     ; /lParam; Default case of switch 01001F5F
010021AC  |.  FF75 10       PUSH [ARG.3]                                     ; |wParam
010021AF  |.  FF75 0C       PUSH [ARG.2]                                     ; |Message
010021B2  |.  FF75 08       PUSH [ARG.1]                                     ; |hWnd
010021B5  |.  FF15 24110001 CALL DWORD PTR DS:[<&USER32.DefWindowProcW>]     ; \DefWindowProcW
010021BB  |>  5F            POP EDI
010021BC  |.  5E            POP ESI
010021BD  |.  5B            POP EBX
010021BE  |.  C9            LEAVE
010021BF  \.  C2 1000       RETN 0x10

只贴上回调函数的图了,其实还分析了很多的函数来掌握流程

 

通过

01002099  |.  8B45 14       MOV EAX,[ARG.4]                                  ;  从这里的代码开始,下面的就是坐标转成数组的公式了eax = lparam
0100209C  |.  C1E8 10       SHR EAX,0x10                                     ;  eax 右移16位,相当于eax  =(HIWORD)lparam
0100209F  |.  83E8 27       SUB EAX,0x27                                     ;  eax(HIWORD的lParam)-0x27
010020A2  |.  C1F8 04       SAR EAX,0x4                                      ;  eax算数右移4位
010020A5  |.  50            PUSH EAX                                         ;  eax 入栈
010020A6  |.  0FB745 14     MOVZX EAX,WORD PTR SS:[EBP+0x14]                 ;  入栈的第四个参数,就是lparam,eax = (LOWORD)lparam
010020AA  |.  83C0 04       ADD EAX,0x4                                      ;  (LOWROD)lparam 加0x4
010020AD  |.  C1F8 04       SAR EAX,0x4                                      ;  然后右移4为
010020B0  |.  50            PUSH EAX                                         ;  找到,这个地方就是转换为数组的下标了

这几行的汇编代码可以看出,再LBUTTONDOWN消息中,通过lParam的高低分分别获得y,x轴坐标
然后通过公式转换为具体的数组下标,转换方式如下

    //首先获取x和y轴的坐标
        WORD xPos = GET_X_LPARAM(lParam);
        WORD yPos = GET_Y_LPARAM(lParam);
        //然后进行转换

        //y轴转换
        yPos -= 0x27;
        yPos /= 16;


        //x轴转换
        xPos += 0x4;
        xPos /= 16;

地图填充的公式和屏幕坐标转换为数组下标的方式已经找到了,

 

总结一下找到的数据

  • 数组基地址:0x1005340

  • 高度基地址:0x10056A8

  • 宽度基地址: 0x10056AC

  • 地雷数基地址: 0x10056A4

  • 查找具体某个数组下标中内容的公式:数组基址+ 高<<5(也就是+32,每隔一行进行填充)+宽

  • 坐标与数组下标转换方法在上面

开写

DLL代码

MFC dll 静态编译

// MFCSAOLEI.cpp : 定义 DLL 的初始化例程。
//

#include "stdafx.h"
#include "MFCSAOLEI.h"
#include <windows.h>
#include <minwindef.h>
#include <Windef.h>

#pragma once
#ifdef _DEBUG
#define new DEBUG_NEW
#endif

//
//TODO:  如果此 DLL 相对于 MFC DLL 是动态链接的,
//        则从此 DLL 导出的任何调入
//        MFC 的函数必须将 AFX_MANAGE_STATE 宏添加到
//        该函数的最前面。
//
//        例如: 
//
//        extern "C" BOOL PASCAL EXPORT ExportedFunction()
//        {
//            AFX_MANAGE_STATE(AfxGetStaticModuleState());
//            // 此处为普通函数体
//        }
//
//        此宏先于任何 MFC 调用
//        出现在每个函数中十分重要。  这意味着
//        它必须作为函数中的第一个语句
//        出现,甚至先于所有对象变量声明,
//        这是因为它们的构造函数可能生成 MFC
//        DLL 调用。
//
//        有关其他详细信息,
//        请参阅 MFC 技术说明 33 和 58。
//

// CMFCSAOLEIApp
BEGIN_MESSAGE_MAP(CMFCSAOLEIApp, CWinApp)
END_MESSAGE_MAP()


// CMFCSAOLEIApp 构造

CMFCSAOLEIApp::CMFCSAOLEIApp()
{
    // TODO:  在此处添加构造代码,
    // 将所有重要的初始化放置在 InitInstance 中
}


// 唯一的一个 CMFCSAOLEIApp 对象

CMFCSAOLEIApp theApp;

//扫雷窗口句柄
HWND g_hWnd =NULL;

//旧的回调函数的
WNDPROC g_oldProc =NULL;


BYTE *g_BaseOfArray = (BYTE*)0x1005340;
DWORD *g_BaseOfHight= (DWORD*)0x10056A8;
DWORD *g_BaseOfWidth  =(DWORD*)0x10056AC;
DWORD *g_BaseOfLandmine =(DWORD*)0x10056A4;


//是不是要写一个函数,用来获取

//自定义回调函数
LRESULT WINAPI CustomWinProc(
    _In_  HWND hWnd,
    _In_  UINT Msg,
    _In_  WPARAM wParam,
    _In_  LPARAM lParam
)
{
    //用来获取地图的信息
    int * pMapArray = new int[(*g_BaseOfHight)* (*g_BaseOfWidth)]{};

    //进行数组遍历
    //主要作用,保留
    for (DWORD y =1;y<*g_BaseOfHight+1;y++)
    {
        for (DWORD x = 1;x<*g_BaseOfWidth+1;x++)
        {
            BYTE code = *(BYTE*)(g_BaseOfArray + y * 32+x);
            //然后判断是不是地雷
            if (code ==0x8F)
            {
                //说明是地雷
                pMapArray[(y - 1)*(*g_BaseOfWidth)+(x-1)] = 0x8f;
            }
            else
            {
                pMapArray[(y - 1)*(*g_BaseOfWidth) + (x - 1)] = 0xf;
            }
        }
    }

    //移动鼠标的设置
    if (Msg == WM_MOUSEMOVE)
    {
        /*
        功能实现要求:
            实现能在窗口区显示坐标,有没有地雷
        */
        //首先获取x和y轴的坐标
        WORD xPos= GET_X_LPARAM(lParam);
        WORD yPos =  GET_Y_LPARAM(lParam);
        //然后进行转换

        //y轴转换
        yPos -= 0x27;
        yPos /= 16;


        //x轴转换
        xPos += 0x4;
        xPos /= 16;

        //然后去判断这个坐标是不是在数组中,在数组中就显示到标题栏上,以及是不是有雷
        //进行判断
        int LandMine = pMapArray[(yPos - 1)*(*g_BaseOfWidth) + (xPos - 1)];
        CString titleText;
        if (LandMine ==0x8f)
        {
            titleText.Format(L"扫雷 x:%d,y:%d,有雷", xPos, yPos);
        }
        else
        {
            titleText.Format(L"扫雷 x:%d,y:%d,没雷", xPos, yPos);
        }

        ::SetWindowText(g_hWnd,titleText);
        delete[] pMapArray;//效率低没办法啊,扫雷还要高啥啊
        return DefWindowProc(hWnd, Msg, wParam, lParam);
    }

    //f5快捷键的设置
    if (Msg == WM_KEYDOWN && wParam == VK_F5)
    {
        /*
            功能:
                实现自动扫雷
        */
        //进行循环遍历,然后发送点击数据
        for (DWORD y = 1;y < *g_BaseOfHight + 1;y++)
        {
            for (DWORD x = 1;x < *g_BaseOfWidth + 1;x++)
            {
                BYTE code = *(BYTE*)(g_BaseOfArray + y * 32 + x);
                //然后判断是不是地雷
                if (code!=0x8f)
                {
                    //进行lParam的转换
                    WORD xPos = x;
                    xPos *= 16;
                    xPos -= 0x4;

                    WORD yPos = y;
                    yPos *= 16;
                    yPos += 0x27;
                    DWORD dwLParam = MAKELONG(xPos, yPos);
                    //发送按键消息
                    SendMessage(g_hWnd, WM_LBUTTONDOWN, MK_LBUTTON, (LPARAM)dwLParam);
                    SendMessage(g_hWnd, WM_LBUTTONUP, MK_LBUTTON, (LPARAM)dwLParam);
                }
            }
        }




        delete[] pMapArray;//效率低没办法啊,扫雷还要高啥啊
        return DefWindowProc(hWnd, Msg, wParam, lParam);
    }


    //返回调用原本的回调函数
    delete[] pMapArray;//效率低没办法啊,扫雷还要高啥啊
    return CallWindowProc(g_oldProc, g_hWnd,Msg, wParam, lParam);
}





// CMFCSAOLEIApp 初始化
BOOL CMFCSAOLEIApp::InitInstance()
{
    CWinApp::InitInstance();
    // 获取窗口句柄
    g_hWnd = FindWindow(NULL, L"扫雷");
    if (g_hWnd == NULL)
    {
        OutputDebugString(L"获取扫雷程序的窗口句柄错误");

    }
    //然后更改扫雷的回调函数
    g_oldProc = (WNDPROC)SetWindowLong(g_hWnd, GWL_WNDPROC, (LONG)CustomWinProc);

    return TRUE;
}

//退出实例子
int CMFCSAOLEIApp::ExitInstance()
{
    // TODO: 在此添加专用代码和/或调用基类

    //把回调函数设置回去
    if (g_oldProc)
    {
        (WNDPROC)SetWindowLong(g_hWnd, GWL_WNDPROC, (LONG)g_oldProc);
    }

    return CWinApp::ExitInstance();
}

dll 注入代码就不贴了

 

看一下效果图 :标题栏显示坐标并提示有无雷,F5 一键扫雷

 


最后:迷之logo

 

//不知道图床正常加载了没


[培训]科锐逆向工程师培训第53期2025年7月8日开班!

收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回