C++程序反編譯筆記(19) 雷區(qū)數(shù)據(jù)結(jié)構(gòu)分析
? ? 我們接著上文繼續(xù)分析點(diǎn)擊菜單的處理代碼.
????

????點(diǎn)擊某個(gè)菜單項(xiàng)后窗口會(huì)收到WM_COMMAND消息, 上文已經(jīng)將這個(gè)消息的處理代碼放到了OnCommand函數(shù)中, 其中WPARAM參數(shù)的低2個(gè)字節(jié)是菜單項(xiàng)的ID.

分析菜單代碼
????

????? ??開局菜單項(xiàng)的ID是520, 那里調(diào)用了sub_100367A這個(gè)函數(shù), 里面全是不認(rèn)識的全局變量, 不適合現(xiàn)在分析.

????初級, 中級, 高級 三個(gè)菜單項(xiàng)的ID分別是521, 522, 523. 整理了一下它們的處理代碼后

????這里直接將dword_10056A0命名為g_level_10056A0了, 我猜測是用0, 1, 2表示3個(gè)游戲難度, 起一個(gè)有意義的名字方便分析. 即使錯(cuò)了也沒關(guān)系, 后面再改個(gè)名字就行了.
????從這里可以看出來, 這三個(gè)數(shù)組都應(yīng)該至少有7個(gè)元素, 那么看一下它們的定義

????這三個(gè)數(shù)組都只有一個(gè)元素, 明顯存在數(shù)組越界的問題. 而且這3個(gè)數(shù)組的后綴地址只相差4個(gè)字節(jié)(int在Windows系統(tǒng)中是4個(gè)字節(jié)), 說明前兩個(gè)數(shù)組確實(shí)只有一個(gè)元素. 這就矛盾了.
? ? 解決這個(gè)矛盾的唯一辦法是將三個(gè)數(shù)組和并成一個(gè), 實(shí)際上對第2個(gè)和第3個(gè)數(shù)組的訪問是在訪問第1個(gè)數(shù)組的第2個(gè)和第3個(gè)元素, v8可能的值是0, 3, 6, 那么這個(gè)數(shù)組的長度至少是6 + 2 + 1 = 9(索引從0開始, +1得到數(shù)組長度). 這說明IDA 將數(shù)組長度識別錯(cuò)了. 修正后的代碼如下

????如果對數(shù)組和指針比較熟悉的話, 這里的轉(zhuǎn)換應(yīng)該不難理解. 使用的公式是
????array[index] = *(array + index)
????上圖中, 拿uValue = dword_1005014[v8] 來解釋一下的話, 就是
原來的 uValue?是 從 1005014 + v8 * 4 的地址處取值,
修改后的 uValue 是從 1005010 + (v8 + 1) * 4 = 1005010 + 4 + v8 * 4 = 1005014 + v8 * 4處取值.?
????所以, 修改前的代碼和修改后的代碼等價(jià).

修正數(shù)組越界
????在IDA 中 按G跳轉(zhuǎn)到1005010 處, 將這個(gè)變量命名為g_gameLevelSetting, 并右鍵菜單點(diǎn)擊 "Array... ", 然后將數(shù)組長度設(shè)置為9. 然后用"Edit"菜單下的"Export Data"菜單項(xiàng)導(dǎo)出數(shù)組

????在Visual Studio中, 使用導(dǎo)出的數(shù)組替換原來的三個(gè)數(shù)組并修正編譯錯(cuò)誤即可.

成果
????在這篇文章中, 如果細(xì)心的話, 會(huì)發(fā)現(xiàn)有個(gè)成果還蠻讓人歡喜的. 那就是導(dǎo)出的9個(gè)元素的數(shù)組, 3個(gè)元素一組, 第1個(gè)元素是地雷個(gè)數(shù), 第2個(gè)元素雷區(qū)寬度, 第3個(gè)元素是雷區(qū)長度.
????比如, 點(diǎn)擊"高級"菜單時(shí), v8 = 2 * 3 = 6,? 那么dword_1005010[6] = 99 時(shí)地雷個(gè)數(shù),?dword_1005010[7] = 16是雷區(qū)寬度,?dword_1005010[8] =?40是雷區(qū)長度.
????因此, 可以知道dword_1005010就是預(yù)定義的雷區(qū)數(shù)據(jù). 到此已經(jīng)接觸到掃雷的數(shù)據(jù)結(jié)構(gòu)了!
????