walk in winmine

原创 2012年03月26日 16:55:57

貌似下午很无聊,就玩了下winmine.

用OD(OllyICE v1.10 HA_second)加载winmine.停在了入口.庆幸下,标准的WinMainCRTStartup.

01003E21 > $  6A 70         push    70
01003E23   .  68 90130001   push    01001390
01003E28   .  E8 DF010000   call    0100400C
01003E2D   .  33DB          xor     ebx, ebx
01003E2F   .  53            push    ebx                                 ; /pModule => NULL
01003E30   .  8B3D 8C100001 mov     edi, dword ptr [<&KERNEL32.GetModul>; |kernel32.GetModuleHandleA
01003E36   .  FFD7          call    edi                                 ; \GetModuleHandleA
...

so直接向下滚鼠标,找到传说中的GetStartupInfo.

01003F68   .  50            push    eax                                 ; /pStartupinfo
01003F69   .  FF15 90100001 call    dword ptr [<&KERNEL32.GetStartupInf>; \GetStartupInfoA
...
01003F89   >  50            push    eax
01003F8A   .  56            push    esi
01003F8B   .  53            push    ebx
01003F8C   .  53            push    ebx
01003F8D   .  FFD7          call    edi
01003F8F   .  50            push    eax
01003F90   .  E8 5BE2FFFF   call    010021F0 ;WinMain
...
01003F9F   .  56            push    esi                                 ; /status
01003FA0   .  FF15 94110001 call    dword ptr [<&msvcrt.exit>]          ; \exit

在下面发现exit.在二者之间找call,显然,010021F0应该是WinMain了.点击下WinMain(010021F0),回车进入,随便翻了下,创建窗口什么什么的,并没有好东西找到.猜测扫雷是随机生成的,所以应该会调用rand一类的函数,所以,在command栏>bp rand,然后F9直接跑着.果然停住了.

76D6C070 >  E8 59E5FFFF     call    76D6A5CE
76D6C075    8B48 14         mov     ecx, dword ptr [eax+14]
76D6C078    69C9 FD430300   imul    ecx, ecx, 343FD
76D6C07E    81C1 C39E2600   add     ecx, 269EC3
76D6C084    8948 14         mov     dword ptr [eax+14], ecx
76D6C087    8BC1            mov     eax, ecx
76D6C089    C1E8 10         shr     eax, 10
76D6C08C    25 FF7F0000     and     eax, 7FFF
76D6C091    C3              retn

看下栈

0006FE70   01003946  返回到 winmine.01003946 来自 msvcrt.rand
0006FE74   010036D2  返回到 winmine.010036D2 来自 winmine.01003940

返回到winmine.01003946.直接回车到01003946.看来应该是个好玩的函数.

_01003940 PROC N
call rand
cdq
idiv    dword 
ptr [esp+4]
mov     eaxedx
retn    4
_01003940 ENDP

还原成C

__declspec(naked) int _3940_rnd(int n)
{
	return rand() % n;
}

 先不管有什么用.F4到01003946.F8直到回到上一个函数.向上滚一下.

0100367A  /$  A1 AC560001   mov     eax, dword ptr [10056AC]
0100367F  |.  8B0D A8560001 mov     ecx, dword ptr [10056A8]
...
0100368A  |.  3B05 34530001 cmp     eax, dword ptr [1005334]
01003690  |.  893D 64510001 mov     dword ptr [1005164], edi
01003696  |.  75 0C         jnz     short 010036A4
01003698  |.  3B0D 38530001 cmp     ecx, dword ptr [1005338]
...
01003746  |.  E8 05E2FFFF   call    01001950
0100374B  |.  5F            pop     edi
0100374C  |.  5E            pop     esi
0100374D  |.  5B            pop     ebx
0100374E  \.  C3            retn

访问了几个全局变量.[10056AC],[10056A8],[1005334],[1005338],[1005164]...把rand的断点删了.不过,为了让思路更清晰,给0100367A下个bp.然后随便给上面找到的某全局变量下个硬断,我下了[1005338].Ctrl+F2重新开始.然后在01002C09停住.

01002BF9  |.  6A 1E         push    1E
01002BFB  |.  56            push    esi
01002BFC  |.  56            push    esi
01002BFD  |.  6A 03         push    3
01002BFF  |.  A3 A8560001   mov     dword ptr [10056A8], eax
01002C04  |.  A3 38530001   mov     dword ptr [1005338], eax
01002C09  |.  E8 19FFFFFF   call    01002B27
01002C0E  |.  6A 03         push    3
01002C10  |.  57            push    edi
01002C11  |.  57            push    edi
01002C12  |.  57            push    edi
01002C13  |.  A3 AC560001   mov     dword ptr [10056AC], eax
01002C18  |.  A3 34530001   mov     dword ptr [1005334], eax
01002C1D  |.  E8 05FFFFFF   call    01002B27
...


good lucky!一直在call 01002B27,然后把eax给某全局变量.其实隐约可以猜到什么了,进去看看.

01002B27  /$  55            push    ebp
01002B28  |.  8BEC          mov     ebp, esp
01002B2A  |.  51            push    ecx
01002B2B  |.  8D45 FC       lea     eax, dword ptr [ebp-4]
01002B2E  |.  50            push    eax                                 ; /pBufSize
01002B2F  |.  8D45 08       lea     eax, dword ptr [ebp+8]              ; |
01002B32  |.  50            push    eax                                 ; |Buffer
01002B33  |.  8B45 08       mov     eax, dword ptr [ebp+8]              ; |
01002B36  |.  6A 00         push    0                                   ; |pValueType = NULL
01002B38  |.  6A 00         push    0                                   ; |Reserved = NULL
01002B3A  |.  FF3485 D05000>push    dword ptr [eax*4+10050D0]           ; |ValueName
01002B41  |.  C745 FC 04000>mov     dword ptr [ebp-4], 4                ; |
01002B48  |.  FF35 50590001 push    dword ptr [1005950]                 ; |hKey = D4
01002B4E  |.  FF15 00100001 call    dword ptr [<&ADVAPI32.RegQueryValue>; \RegQueryValueExW
...


从注册表里读取数据,然后再给全局变量!直接在ValueName下断点.删除硬件断点,Ctrl+F2,重新开始.F9到断点处.
第一次

01002B3A  |.  FF3485 D05000>push    dword ptr [eax*4+10050D0]           ; |ValueName = "AlreadyPlayed"

eax是索引,4是指针长度,猜测10050D0应该是个字符串表,保存注册表里每个文件的名字.
然后继续第二次ValueName = "Height",读取失败,然后把一种类似于默认值的东西返回了.写入到全局变量.

[56A8]=[5338]=Height(高) //返回了9 记得扫雷默认大小么
[56AC]=[5334]=Witdh(宽) //也是返回9
[56A0]=Difficulty(难度?)
[55A4]=Mines(雷数量) //返回了A,默认10个雷
[56B0]=Xpos
[56B4]=Ypos
[56B8]=Sound
[56BC]=Mark
[56C0]=Tick
[56C4]=Menu


接下来就是一些记录了

[56CC]=Time1 //0x3E7 也就是999
[56D0]=Time2 //999
[56D4]=Time3 //999

测试下,把56D4改成15,运行下,高级变成了15秒...然后是记录的名字

[56D8]=Name1(Unicode)
[5718]=Name2(Unicode)
[5758]=Name3(Unicode)

找到了这些以后,go on,记得之前下过的bp么,F9后停在了这里.把汇编代码copy出来.简单修改下

_2ED5_initTable PROC
  
mov     eax360 ;eax = 0x360
L001:
  
dec     eax ;while(eax--)
  
mov     byte ptr [eax+1005340], 0F ;_byte_5340[eax] = 0xf;
  
jnz L001
  
;...make a circle & set state 0x10 with Width5334 & Heigth5338
  
retn
_2ED5_initTable ENDP

_36A7_initMineTable PROC
  
mov     eax, [Width56AC]
  
mov     ecx, [Heigth56A8]
  
push    ebx
  
push    esi
  
push    edi
  edi 
0
  
cmp     eax, [Width5334]
  
mov     dword ptr [1005164], edi ;dw_1005164 = 0
  
jnz L013
  
cmp     ecx, [Heigth5338]
  
jnz L013
  
push    4
  
jmp L014
L013
:
  
push    6
L014:
  
;ebx = (Width5334 != Width56AC || Heigth5338 != Heigth56A8)? 6: 4;
  
pop     ebx
  
mov     [Width5334], eax ;Width5334 = Width56AC
  
mov     [Heigth5338], ecx ;Heigth5338 = Heigth56A8
  
call    _2ED5_initTable ;initialize _byte_5340[360](5340-569F)
  
mov     eax, [Mines]
  
mov     dword ptr [1005160], edi ;dw_1005160 = 0
  
mov     [temp_Mines], eax ;temp_Mines = Mines
L021:  ;do {
  
push    [Width5334]
  
call    _3940_rnd
  
push    [Heigth5338]
  
mov     esieax
  
inc     esi ;esi = _3940_rnd(Width5334) + 1;
  
call    _3940_rnd
  
inc     eax ;eax = _3940_rnd(Heigth5338) + 1;
  
mov     ecxeax ;ecx = eax
  
shl     ecx5
  
test    byte ptr [ecx+esi+1005340], 80
  
jnz L021 ;if(_byte_5340[ecx][esi] & 0x80) coutinue;
  
shl     eax5
  
lea     eaxdword ptr [eax+esi+1005340]
  
or      byte ptr [eax], 80 ;_byte_5340[eax][esi] |= 0x80
  
dec     [temp_Mines]
  
jnz L021 ;} while(--temp_Mines);
  
mov     ecx, [Heigth5338]
  
imul    ecx, [Width5334]
  
mov     eax, [Mines]
  
sub     ecxeax
  
push    edi
  
mov     dword ptr [100579C], edi ;[_Tick_579C]=0 //测试出来的.
  
mov     [temp_Mines], eax
  
mov     dword ptr [1005194], eax ;[_Mines_5194] = [Mines];
  
mov     dword ptr [10057A4], edi ;[_57A4] = 0
  
mov     dword ptr [10057A0], ecx ;[_TableSize_57A0] = [Heigth5338] * [Width5334]
  
mov     dword ptr [1005000], 1
  
call    0100346A ;DrawMines
  
push    ebx ;flags
  
call    01001950
  
pop     edi
  
pop     esi
  
pop     ebx
  
retn
_36A7_initMineTable ENDP

其实程序到这里就差不多了,用_initTable初始化下表,然后用两个Rnd()来随机生成雷,在雷的标记是0x80,空的标记是0xF,其实可以跟一下DFS,我这里就不跟了,就简单说下,如果一个块周围有雷,那么它会被设置成0x40 | 周围雷的个数.

接下来的图片凑字数


感谢OD(OllyDbg v1.10),记事本,QQ截图工具,对本文的大力支持.
完全不知道自己在干什么.

版权声明:本文为博主原创文章,未经博主允许不得转载。

golang walk界面库 最小化事件

示例图:package mainimport ( "fmt" "log" "syscall" "github.com/lxn/walk" . "github.co...
  • CodyGuo
  • CodyGuo
  • 2017年06月02日 23:29
  • 1157

go的gui----walk的使用

go虽然是服务端语言,但是使用go也可以用于实现客户端,这里使用walk来实现。 walk的git地址:https://github.com/lxn/walk walk的说明文档:https://go...
  • hangeqq685042
  • hangeqq685042
  • 2016年08月09日 14:37
  • 1442

snmp walk 跟 get 的区别

一、snmpwalk和snmpget的区别: snmpwalk是对OID值的遍历(比如某个OID值下面有N个节点,则依次遍历出这N个节点的值。如果对某个叶子节点的OID值做walk,则取得到数据...
  • wdsafmy468619
  • wdsafmy468619
  • 2015年04月30日 13:41
  • 1504

Go语言GUI Demo 之 Walk

Go语言没有自带官方Gui,目前找到的Gui框架中感觉Walk还不错,但该库只支持Windows操作系统(一般也只用到Windows)。本次我把官方的example编译成exe,方便网友参考Walk ...
  • sunansheng
  • sunansheng
  • 2016年11月10日 15:35
  • 14463

随机漫步(random walk)

1、题目 有一类问题总称为“随机漫步”(Random Walk)问题,这类问题长久以来吸引着数学界的兴趣。所有这些问题即使是最简单的解决起来也是极其困难的。而且它们在很大程度上还远没有得到解决。一个...
  • q547550831
  • q547550831
  • 2015年08月09日 13:56
  • 4458

《挑战》例题4.1 Random Walk

1.题目描述:有一个n*m的网格,从(0,0)出发,每一步可以朝着上下左右4个方向等概率地移动,另外一些格子中有石头,因此无法移动到这些格子,求第一次到达(n-1,m-1)格子的期望步数。可以保证至少...
  • u014800748
  • u014800748
  • 2015年10月20日 14:50
  • 468

Random Walks on the Click Graph

这是一篇微软剑桥研究院的文章。在搜索引擎领域,有几大公司和研究院产出了大量论文。论文最多的是“yahoo ! research”,其次可能就是 mircosoft Research和google re...
  • poson
  • poson
  • 2012年03月29日 09:40
  • 2381

Seminar《Fast Random Walk with Restart and Its Applications》

Optimization about inverse of big matrix though partition and low rank approximation by making use ...
  • zzchust
  • zzchust
  • 2015年11月18日 21:18
  • 710

URAL 1016. Cube on the Walk(搜索)比较难

题意:给你一个立方体,每一个面都有一个数字。。从一个坐标滚到另一个坐标,使底面的数字之和最小。。 思路:搜索,对每一个坐标记录起底面和前面,,就有24种状态。。。 #include #inclu...
  • binwin20
  • binwin20
  • 2012年08月27日 09:53
  • 533

Random Walk分割算法

引言 RandomWalk是基于图论分割方法的一个重要分支。在根据图像建立的图模型上,RandomWalk根据随机游走模型,来求解未标记的像素(unseeded pixels)到达已标记的种子点(se...
  • menjiawan
  • menjiawan
  • 2015年07月27日 16:31
  • 3547
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:walk in winmine
举报原因:
原因补充:

(最多只允许输入30个字)