-
-
[原创]小白的第一次逆向 之 扫雷分析与辅助制作
-
发表于: 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
//不知道图床正常加载了没
赞赏
- [原创]ida pro mac版F5插件移植过程分享 14487
- [原创]第一次病毒分析:利用傀儡进程隐藏的文件加密勒索病毒 13341
- [原创]UPX 脱壳之upx壳部分的代码分析 7433
- [原创]小白的第一次逆向 之 扫雷分析与辅助制作 10364