红心大战c语言程序设计教程课后答案,[原创]Windows 红心大战随机发牌程序分析...
[調試逆向]
[原創(chuàng)]Windows 紅心大戰(zhàn)隨機發(fā)牌程序分析
2007-11-27 23:28
13191
[調試逆向]
[原創(chuàng)]Windows 紅心大戰(zhàn)隨機發(fā)牌程序分析
2007-11-27 23:28
13191
Windows 紅心大戰(zhàn)有52張牌,每次開局時,程序會自動洗牌和發(fā)牌。
按照我們一般的想法,隨機發(fā)牌無非就是隨機產生0..51個隨機數,代表52張牌。然后分發(fā)給四個玩家。當隨機產生0...51之間的隨機數時,可能會產生相同的隨機數,此時,就要將這種情況去除,并重新產生一個隨機數,直到完全產生0...51之間所有的數值,這種方式下,調用隨機函數的次數是不固定的,而且肯定大于52次。
研究了一下紅心大戰(zhàn),發(fā)現(xiàn)這個程序并不是這樣洗牌的,它的洗牌方式有點巧妙,只需調用52次隨機函數,就可以完全隨機地整理出一幅牌來。這里面相關的代碼并不多,只有四十來行,卻花了我一個晚上,才看明白其中的道理,高興之余,趕快拿出來與我一樣的菜鳥分享。失誤之處,請高手指正。
在OD中跟蹤紅心大戰(zhàn),很容易跟蹤到隨機發(fā)牌的地方,這里就不多說了。確定了函數地址后,再用IDA定位到這一段程序,如下:
.text:01007F89 private: void __thiscall CMainWindow::Shuffle(void) proc near
.text:01007F89? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???; CODE XREF: OnNewGame+10Fp
.text:01007F89? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???; CMainWindow::DispatchCards(void):loc_1008966p
.text:01007F89? ?? ?? ?? ?? ???mov? ???eax, offset unknown_libname_40 ; MFC4.2 release library by ForEver[RCT]
.text:01007F89? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???; __ehhandler$?ExecCommand@?$CHtmlEditCtrlBase@VCHtmlEditView@@@@QBEJPBU_GUID@@JJPAUtagVARIANT@@1@Z
.text:01007F8E? ?? ?? ?? ?? ???call? ? __EH_prolog
.text:01007F8E
.text:01007F93? ?? ?? ?? ?? ???sub? ???esp, 104h
.text:01007F99? ?? ?? ?? ?? ???push? ? ebx
.text:01007F9A? ?? ?? ?? ?? ???push? ? esi
.text:01007F9B? ?? ?? ?? ?? ???push? ? edi
.text:01007F9C? ?? ?? ?? ?? ???push? ? 34h
.text:01007F9E? ?? ?? ?? ?? ???mov? ???esi, ecx
.text:01007FA0? ?? ?? ?? ?? ???xor? ???eax, eax
.text:01007FA2? ?? ?? ?? ?? ???pop? ???ecx? ?? ?? ?? ? ; ecx=34h (52張牌)
.text:01007FA2
.text:01007FA3 在內存中產生一幅牌
.text:01007FA3
.text:01007FA3 loc_1007FA3:? ?? ?? ?? ?? ?? ?? ?? ?? ? ; CODE XREF: CMainWindow::Shuffle(void)+24j
.text:01007FA3? ?? ?? ?? ?? ???mov? ???[ebp+eax*4-110h], eax
.text:01007FAA? ?? ?? ?? ?? ???inc? ???eax
.text:01007FAB? ?? ?? ?? ?? ???cmp? ???eax, ecx
.text:01007FAD? ?? ?? ?? ?? ???jl? ?? ?short loc_1007FA3
.text:01007FAD
.text:01007FAF? ?? ?? ?? ?? ???and? ???dword ptr [ebp-14h], 0 ? ? ? ? ? ? ? ? ; [ebp-14h] 已發(fā)牌數,置初值0
.text:01007FB3? ?? ?? ?? ?? ???mov? ???[ebp-18h], ecx??? ? ? ? ? ? ? ? ? ? ? ? ; [ebp-18h]:末發(fā)牌數,置初值:52
.text:01007FB3
.text:01007FB6 發(fā)牌
.text:01007FB6
.text:01007FB6 locNextCard:? ?? ?? ?? ?? ?? ?? ?? ?? ? ; CODE XREF: CMainWindow::Shuffle(void)+8Aj
.text:01007FB6? ?? ?? ?? ?? ???call? ? ds:__imp__rand
.text:01007FBC? ?? ?? ?? ?? ???cdq
.text:01007FBD? ?? ?? ?? ?? ???idiv? ? dword ptr [ebp-18h] ? ? ? ? ? ? ? ? ; 隨機數/末發(fā)牌數 (余數edx 就是要抽取的牌的位置)
.text:01007FC0? ?? ?? ?? ?? ???mov? ???eax, [ebp-14h]??? ? ? ? ? ? ? ? ? ? ? ? ; eax=當前已發(fā)牌數
.text:01007FC3? ?? ?? ?? ?? ???push? ? 0Dh
.text:01007FC5? ?? ?? ?? ?? ???pop? ???edi? ?? ?? ?? ? ? ? ? ? ? ? ? ? ? ? ? ? ; edi=13
.text:01007FC6? ?? ?? ?? ?? ???push? ? 4
.text:01007FC8? ?? ?? ?? ?? ???pop? ???ebx
.text:01007FC9? ?? ?? ?? ?? ???mov? ???ecx, edx? ?? ???? ? ? ? ? ? ? ? ? ? ? ? ; 要抽取的牌的位置
.text:01007FCB? ?? ?? ?? ?? ???cdq
.text:01007FCC? ?? ?? ?? ?? ???idiv? ? edi? ?? ?? ?? ? ? ? ? ? ? ? ? ? ? ? ? ? ; edi=13, eax就只能是0,1,2,3, edx只能是:0...12
.text:01007FCE? ?? ?? ?? ?? ???sub? ???eax, [esi+140h] ? ? ? ? ? ? ? ? ? ? ? ? ; [esi+140h]=0, eax得到當前是給哪一位發(fā)牌,只可能是0,1,2,3
.text:01007FD4? ?? ?? ?? ?? ???mov? ???edi, edx? ?? ???? ? ? ? ? ? ? ? ? ? ? ? ; edi只能是0...12
.text:01007FD6? ?? ?? ?? ?? ???add? ???eax, 4? ?? ?? ? ? ? ? ? ? ? ? ? ? ? ? ? ; eax只能是4,5,6,7
.text:01007FD9? ?? ?? ?? ?? ???cdq
.text:01007FDA? ?? ?? ?? ?? ???idiv? ? ebx? ?? ?? ?? ? ? ? ? ? ? ? ? ? ? ? ? ? ; ebx=4, edx就只能為0,1,2,3 分別代表四個玩家
.text:01007FDC? ?? ?? ?? ?? ???lea? ???eax, [ebp+ecx*4-110h]
.text:01007FE3? ?? ?? ?? ?? ???mov? ???ebx, [eax]? ???? ? ? ? ? ? ? ???? ? ? ? ; ebx=[ebp+ecx*4-110h] 這里面就是內存中的那副牌
.text:01007FE3? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???? ? ? ? ? ? ? ? ? ? ? ? ; 抽出這張牌,傳給ebx
.text:01007FE5? ?? ?? ?? ?? ???shl? ???edi, 4? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ; 玩家的當前牌和第一張牌偏移地址(相鄰兩張牌的地址相隔10h)
.text:01007FE8? ?? ?? ?? ?? ???lea? ???ecx, [esi+edx*4+130h]? ? ? ? ? ? ? ? ; 要發(fā)往玩家牌當前牌的地址
.text:01007FEF? ?? ?? ?? ?? ???mov? ???edx, [ecx]
.text:01007FF1? ?? ?? ?? ?? ???mov? ???[edi+edx+1Ch], ebx ? ? ? ? ? ? ? ? ; 發(fā)牌給某一個玩家
.text:01007FF5? ?? ?? ?? ?? ???mov? ???ecx, [ecx]
.text:01007FF7? ?? ?? ?? ?? ???xor? ???ebx, ebx
.text:01007FF9? ?? ?? ?? ?? ???dec? ???dword ptr [ebp-18h] ? ? ? ? ? ? ? ? ; 統(tǒng)計末發(fā)牌數
.text:01007FFC? ?? ?? ?? ?? ???inc? ???dword ptr [ebp-14h] ? ? ? ? ? ? ? ? ; 統(tǒng)計已發(fā)牌數
.text:01007FFF? ?? ?? ?? ?? ???cmp? ???dword ptr [ebp-14h], 34h ? ? ? ?? ?? ?? ?? ?? ???; 已發(fā)牌數達到52張?
.text:01008003? ?? ?? ?? ?? ???mov? ???[edi+ecx+28h], ebx
.text:01008007? ?? ?? ?? ?? ???mov? ???ecx, [ebp-18h]
.text:0100800A? ?? ?? ?? ?? ???mov? ???ecx, [ebp+ecx*4-110h]
.text:01008011? ?? ?? ?? ?? ???mov? ???[eax], ecx? ?? ?? ? ? ? ? ? ? ? ? ? ? ? ; 將最后一張牌插入當前抽出牌的位置上來
.text:01008013? ?? ?? ?? ?? ???jl? ?? ?short locNextCard
.text:01008013
.text:01008015? ?? ?? ?? ?? ???cmp? ???dword ptr [esi+144h], 3
.text:0100801C? ?? ?? ?? ?? ???jz? ?? ?short loc_100806A
--------------------------------------------------------------------------------------------------------------------------------
程序分析說明:
程序先在內存中按照: 梅A 方A 紅A 黑A??梅2 方2 紅2 黑2 ... 梅K 方K 紅K 黑K 的順序有規(guī)率地產生一幅牌。
內存數據如下:
0006F9E4??? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ?? ? 00 00 00 00??燣/.`K/.........
0006F9F4??01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00??............
0006FA04??05 00 00 00 06 00 00 00 07 00 00 00 08 00 00 00??............
0006FA14??09 00 00 00 0A 00 00 00 0B 00 00 00 0C 00 00 00??...............
0006FA24??0D 00 00 00 0E 00 00 00 0F 00 00 00 10 00 00 00??.............
0006FA34??11 00 00 00 12 00 00 00 13 00 00 00 14 00 00 00??............
0006FA44??15 00 00 00 16 00 00 00 17 00 00 00 18 00 00 00??............
0006FA54??19 00 00 00 1A 00 00 00 1B 00 00 00 1C 00 00 00??............
0006FA64??1D 00 00 00 1E 00 00 00 1F 00 00 00 20 00 00 00??......... ...
0006FA74??21 00 00 00 22 00 00 00 23 00 00 00 24 00 00 00??!..."...#...$...
0006FA84??25 00 00 00 26 00 00 00 27 00 00 00 28 00 00 00??3...&...'...(...
0006FA94??29 00 00 00 2A 00 00 00 2B 00 00 00 2C 00 00 00??)...*...+...,...
0006FAA4??2D 00 00 00 2E 00 00 00 2F 00 00 00 30 00 00 00??-......./...0...
0006FAB4??31 00 00 00 32 00 00 00 33 00 00 00
程序將牌按順序整理好后,然后隨機抽牌,分發(fā)給四個玩家。
發(fā)牌的順序是先給第一個玩家發(fā)13張牌,然后給第二個玩家發(fā)13張牌,再給第三個玩家發(fā)13張牌,最后給第四個玩家發(fā)13張牌。
程序中設置一個變量,記住末發(fā)牌數,假設為n,每次發(fā)牌時,就是在 0...(n-1) 的范圍內產生一個隨機數,這個隨機數就是內存中那幅牌中的第幾張牌,然后將這張牌抽出,發(fā)給玩家后,再將余下牌中的最后一張牌(索引號:n-1)放到這張牌的位置上來。
這樣,產生的隨機數雖然可能相同,那只是表示要抽取的牌的位置是相同的,由于牌已經被更換,所以每次抽取的牌肯定是不一樣的。
這種方法的確很巧妙!對于其它的相關編程也有觸類旁通的效果。自我感覺從這里受益不少!
總結
以上是生活随笔為你收集整理的红心大战c语言程序设计教程课后答案,[原创]Windows 红心大战随机发牌程序分析...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c语言 将点同时保证x坐标从小到大,y坐
- 下一篇: 计算机启动完成后操作系统负责管理的是,终