日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

逆向-扫雷算法分析

發(fā)布時(shí)間:2024/1/8 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 逆向-扫雷算法分析 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

最近思來(lái)想去,眼看著自己就要進(jìn)某廠(chǎng)游戲安全團(tuán)隊(duì)實(shí)習(xí)了,也不能整天的無(wú)所事事,所以就尋思著先找點(diǎn)最簡(jiǎn)單的游戲用來(lái)練練手。想到之前逆向過(guò)一些小游戲,就把之前分析的掃雷整理了一下啊,寫(xiě)了個(gè)外掛,發(fā)了上來(lái)。


最近實(shí)在是比較忙,快期中考試了,什么都不會(huì),所以忙著預(yù)習(xí)去了,本文只寫(xiě)了關(guān)于掃雷逆向的部分,相關(guān)的外掛編寫(xiě)已經(jīng)寫(xiě)差不多了,等最近有時(shí)間整理出來(lái)o(╯□╰)o

工具

分析對(duì)象:winmine/掃雷(windows xp版本)
逆向工具:ollydbg,IDA,peid,ResHacker
操作平臺(tái):windows7 旗艦版

分析過(guò)程

main函數(shù)定位

peid加載winmine發(fā)現(xiàn)為vc編寫(xiě)的,沒(méi)有加過(guò)殼,則可以確定加載程序的流程為:獲取當(dāng)前版本號(hào),堆初始化,獲取命令行參數(shù),獲取環(huán)境變量,分離出命令行參數(shù),全局?jǐn)?shù)據(jù)和浮點(diǎn)寄存器初始化所以在main(這里應(yīng)該是winmain了)調(diào)用前,調(diào)用流程為:
GetVersion()—–>_heap_init()—–>GetCommandLine()—–>_crtGetEnvironmentStrings()—–>_setargv()—–>_setenvp()—–>_cinit()
所以很容易找到winmain的調(diào)用地址,跟進(jìn)之后發(fā)現(xiàn)

發(fā)現(xiàn)這里便是在做一些初始化
很快找到:

:010022D5 mov ecx, yBottom .text:010022DB mov edx, xRight .text:010022E1 push edi ; lpParam .text:010022E2 push hInstance ; hInstance .text:010022E8 add ecx, eax .text:010022EA push edi ; hMenu .text:010022EB push edi ; hWndParent .text:010022EC push ecx ; nHeight .text:010022ED mov ecx, dword_1005A90 .text:010022F3 add edx, ecx .text:010022F5 push edx ; nWidth .text:010022F6 mov edx, Y .text:010022FC sub edx, eax .text:010022FE mov eax, X .text:01002303 push edx ; Y .text:01002304 sub eax, ecx .text:01002306 push eax ; X .text:01002307 push 0CA0000h ; dwStyle .text:0100230C push esi ; lpWindowName .text:0100230D push esi ; lpClassName .text:0100230E push edi ; dwExStyle .text:0100230F call ds:CreateWindowExW .text:01002315 cmp eax, edi .text:01002317 mov hWnd, eax .text:0100231C jnz short loc_1002325 .text:0100231E push 3E8h .text:01002323 jmp short loc_1002336 .text:01002325 ; --------------------------------------------------------------------------- .text:01002325 .text:01002325 loc_1002325: ; CODE XREF: WinMain+12Cj .text:01002325 push ebx .text:01002326 call sub_1001950 ;位置 .text:0100232B call sub_1002B14 ; 裝載資源 .text:01002330 test eax, eax .text:01002332 jnz short loc_1002342 .text:01002334 push 5 .text:01002336 .text:01002336 loc_1002336: ; CODE XREF: WinMain+133j .text:01002336 call sub_1003950 .text:0100233B .text:0100233B loc_100233B: ; CODE XREF: WinMain+ABj .text:0100233B xor eax, eax .text:0100233D jmp loc_10023C6 .text:01002342 ; --------------------------------------------------------------------------- .text:01002342 .text:01002342 loc_1002342: ; CODE XREF: WinMain+142j .text:01002342 push dword_10056C4 .text:01002348 call sub_1003CE5 .text:0100234D call SetMine ; 布置雷區(qū) .text:01002352 push ebx ; nCmdShow .text:01002353 push hWnd ; hWnd .text:01002359 call ds:ShowWindow .text:0100235F push hWnd ; hWnd .text:01002365 call ds:UpdateWindow .text:0100236B mov esi, ds:GetMessageW .text:01002371 mov dword_1005B38, edi .text:01002377 jmp short loc_10023A4

分析可疑函數(shù)

在createwindow,分別調(diào)用了4個(gè)函數(shù),然后就showwindow了,那么這4個(gè)函數(shù)肯定完成了在掃雷前用戶(hù)的選擇,資源的加載,雷區(qū)的繪制.
跟進(jìn)第一個(gè)函數(shù)sub_1001950,發(fā)現(xiàn)主要調(diào)用了GetMenuItemRect和MoveWindow函數(shù)將窗口待會(huì)創(chuàng)建到制定位置,這里跟我們關(guān)心的算法沒(méi)有太大關(guān)系,所以不做分析。
跟進(jìn)第二個(gè)函數(shù)sub_1002B14,發(fā)現(xiàn)主要在調(diào)用LoadResource進(jìn)行加載資源
跟進(jìn)第三個(gè)函數(shù)sub_1003CE5

.text:01003CE5 sub_1003CE5 proc near ; CODE XREF: sub_1001BC9:loc_1001D00p .text:01003CE5 ; WinMain+158p .text:01003CE5 .text:01003CE5 arg_0 = dword ptr 4 .text:01003CE5 .text:01003CE5 mov eax, [esp+arg_0] .text:01003CE9 mov dword_10056C4, eax .text:01003CEE call sub_1001516 ; 菜單選項(xiàng) .text:01003CF3 mov eax, dword_10056C4 .text:01003CF8 and al, 1 .text:01003CFA neg al .text:01003CFC sbb eax, eax .text:01003CFE not eax .text:01003D00 and eax, hMenu .text:01003D06 push eax ; hMenu .text:01003D07 push hWnd ; hWnd .text:01003D0D call ds:SetMenu .text:01003D13 push 2 .text:01003D15 call sub_1001950 .text:01003D1A retn 4 .text:01003D1A sub_1003CE5 endp

發(fā)現(xiàn)在調(diào)用sub_1001516之后調(diào)用了SerMenu,之后再次調(diào)用了第一個(gè)函數(shù)sub_1001950,應(yīng)該就是處理用戶(hù)選擇不同難度而對(duì)窗口進(jìn)行的重新布置吧

跟進(jìn)sub_1001516
為了之后分析方便,將sub_1001516改名為MenuChoose,sub_1001950改名為SetWindow

/*注:本代碼中CheckMenu為自己分析后自己起的函數(shù)名*/ .text:01001516 MenuChoose proc near ; CODE XREF: sub_1001B49+24p .text:01001516 ; sub_1003CE5+9p .text:01001516 xor eax, eax .text:01001518 cmp word ptr dword_10056A0, ax .text:0100151F setz al .text:01001522 push eax .text:01001523 push 209h ; 521 .text:01001528 call CheckMenu .text:0100152D xor eax, eax .text:0100152F cmp word ptr dword_10056A0, 1 .text:01001537 setz al .text:0100153A push eax .text:0100153B push 20Ah ; 522 .text:01001540 call CheckMenu .text:01001545 xor eax, eax .text:01001547 cmp word ptr dword_10056A0, 2 .text:0100154F setz al .text:01001552 push eax .text:01001553 push 20Bh ; 523 .text:01001558 call CheckMenu .text:0100155D xor eax, eax .text:0100155F cmp word ptr dword_10056A0, 3 .text:01001567 setz al .text:0100156A push eax .text:0100156B push 20Ch ; 524 .text:01001570 call CheckMenu .text:01001575 push dword_10056C8 .text:0100157B push 211h ; 529 .text:01001580 call CheckMenu .text:01001585 push Data .text:0100158B push 20Fh ; 527 .text:01001590 call CheckMenu .text:01001595 push dword_10056B8 .text:0100159B push 20Eh .text:010015A0 call CheckMenu .text:010015A5 retn .text:010015A5 MenuChoose endp

這里差不多就應(yīng)該是通過(guò)資源ID選擇了,用ResHacker分析一下得證

然后分析最后一個(gè)函數(shù)SetMine(原函數(shù)名為sun_xxxxxx,通過(guò)分析已經(jīng)修改函數(shù)名)

.text:010036A4 .text:010036A4 loc_10036A4: ; CODE XREF: SetMine+1Cj .text:010036A4 ; SetMine+24j .text:010036A4 push 6 .text:010036A6 .text:010036A6 loc_10036A6: ; CODE XREF: SetMine+28j .text:010036A6 pop ebx .text:010036A7 mov dword_1005334, eax .text:010036AC mov dword_1005338, ecx .text:010036B2 call PaintMine .text:010036B7 mov eax, dword_10056A4 .text:010036BC mov dword_1005160, edi .text:010036C2 mov dword_1005330, eax .text:010036C7 .text:010036C7 loc_10036C7: ; CODE XREF: SetMine+74j .text:010036C7 ; SetMine+89j .text:010036C7 push dword_1005334 .text:010036CD call Rand .text:010036D2 push dword_1005338 .text:010036D8 mov esi, eax .text:010036DA inc esi .text:010036DB call Rand .text:010036E0 inc eax .text:010036E1 mov ecx, eax .text:010036E3 shl ecx, 5 .text:010036E6 test byte_1005340[ecx+esi], 80h .text:010036EE jnz short loc_10036C7

繪制雷區(qū)函數(shù)分析

發(fā)現(xiàn)期中一個(gè)函數(shù)(PaintMine)便是在繪制雷區(qū)
大體F5把握一下大致的意思

int __cdecl PaintMine() {signed int v0; // eax@1int v1; // ecx@3int v2; // edx@3int result; // eax@3int v4; // esi@5char *v5; // edx@6v0 = 864;do{--v0;byte_1005340[v0] = 15;}while ( v0 );v1 = dword_1005334;v2 = dword_1005338;result = dword_1005334 + 2;if ( dword_1005334 != -2 ){do{--result;byte_1005340[result] = 16;*(&byte_1005360[32 * v2] + result) = 16;}while ( result );}v4 = v2 + 2;if ( v2 != -2 ){v5 = &byte_1005340[32 * v4];result = (int)((char *)&unk_1005341 + 32 * v4 + v1);do{v5 -= 32;result -= 32;--v4;*v5 = 16;*(_BYTE *)result = 16;}while ( v4 );}return result; }

大體意思就是先將最大可能的雷區(qū)內(nèi)數(shù)據(jù)全部設(shè)置為0xF,然后在根據(jù)用戶(hù)選擇菜單中的等級(jí),繪制雷區(qū)的邊界
OD動(dòng)態(tài)跟蹤:

01002ED5 /$ B8 60030000 mov eax,0x360 ; 算法如下,最大面積吧 01002EDA |> 48 /dec eax ; 循環(huán)0x360次 01002EDB |. C680 40530001>|mov byte ptr ds:[eax+0x1005340],0xF ; 全部設(shè)置成0xf 01002EE2 |.^ 75 F6 \jnz Xwinmine.01002EDA 01002EE4 |. 8B0D 34530001 mov ecx,dword ptr ds:[0x1005334] ; 長(zhǎng)度 01002EEA |. 8B15 38530001 mov edx,dword ptr ds:[0x1005338] ; 寬度 01002EF0 |. 8D41 02 lea eax,dword ptr ds:[ecx+0x2] ; 長(zhǎng)度+2 01002EF3 |. 85C0 test eax,eax 01002EF5 |. 56 push esi 01002EF6 |. 74 19 je Xwinmine.01002F11 01002EF8 |. 8BF2 mov esi,edx 01002EFA |. C1E6 05 shl esi,0x5 ; 長(zhǎng)度左移5位 01002EFD |. 8DB6 60530001 lea esi,dword ptr ds:[esi+0x1005360] ; 為定位到邊界值 01002F03 |> 48 /dec eax 01002F04 |. C680 40530001>|mov byte ptr ds:[eax+0x1005340],0x10 ; 雷區(qū)的上邊界設(shè)置為0x10 01002F0B |. C60406 10 |mov byte ptr ds:[esi+eax],0x10 ; 設(shè)置下邊界的標(biāo)志位0x10 01002F0F |.^ 75 F2 \jnz Xwinmine.01002F03 01002F11 |> 8D72 02 lea esi,dword ptr ds:[edx+0x2] 01002F14 |. 85F6 test esi,esi 01002F16 |. 74 21 je Xwinmine.01002F39 01002F18 |. 8BC6 mov eax,esi 01002F1A |. C1E0 05 shl eax,0x5 ; 寬度移位 01002F1D |. 8D90 40530001 lea edx,dword ptr ds:[eax+0x1005340] 01002F23 |. 8D8408 415300>lea eax,dword ptr ds:[eax+ecx+0x1005341] ; 定位到左邊界 01002F2A |> 83EA 20 /sub edx,0x20 ; 一行的長(zhǎng)度 01002F2D |. 83E8 20 |sub eax,0x20 01002F30 |. 4E |dec esi 01002F31 |. C602 10 |mov byte ptr ds:[edx],0x10 ; 設(shè)置左右邊界 01002F34 |. C600 10 |mov byte ptr ds:[eax],0x10 01002F37 |.^ 75 F1 \jnz Xwinmine.01002F2A 01002F39 |> 5E pop esi ; winmine.01005AA0

最后在內(nèi)存中畫(huà)成的雷區(qū)的樣子:(0x10為邊界值)

而我們打開(kāi)游戲界面如圖,剛好與之對(duì)應(yīng)

生成地雷函數(shù)分析

之后回到SetMine函數(shù)中,在調(diào)用PaintMine之后繪制雷區(qū)之后通過(guò)調(diào)用Rand隨機(jī)在雷區(qū)中生成雷。
直接F5看一下SetMine

do{do{v1 = Rand(dword_1005334) + 1;v2 = Rand(dword_1005338) + 1;}while ( *(&byte_1005340[32 * v2] + v1) & 0x80 );*(&byte_1005340[32 * v2] + v1) |= 0x80u;--Num;}while ( Num );

通過(guò)分析,可以明白這里的v2即是縱坐標(biāo),v1為橫坐標(biāo),然后判斷此處是否有地雷,沒(méi)有在設(shè)置地雷(0x8F)
OD動(dòng)態(tài)分析證明上述分析:

最后生成完雷就是這個(gè)樣子:

按照這個(gè)自然就很好掃雷咯

關(guān)于掃雷 游戲的核心算法大體就分析這么多了,因?yàn)橹饕菫榱讼乱黄膾呃淄鈷斓木帉?xiě),所以相關(guān)的鼠標(biāo)點(diǎn)擊算法就沒(méi)有記錄下來(lái)了。
未完待續(xù),大牛勿噴!

總結(jié)

以上是生活随笔為你收集整理的逆向-扫雷算法分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。