題外
飛秋是一款局域網(wǎng)內(nèi)的IM軟件,界面類似QQ,實(shí)現(xiàn)上與飛鴿(IP message)有點(diǎn)淵源,免費(fèi),不開源。
公司大概兩年前開始使用這款軟件作為員工之間辦公吹牛的工具。最近游戲玩得少,就想徹底換到linux下,
組內(nèi)也有其他兩人是llinux-er,不過(guò)悲劇的是換到linux下就無(wú)法收取飛秋群里的聊天信息了,不免寂寞。
所以,就想寫個(gè)協(xié)議兼容的程序(或者說(shuō)改個(gè)東西)來(lái)收取群信息。
準(zhǔn)備
我本身并不擅長(zhǎng)逆向工程,破解什么的純碎業(yè)余。在GOOGLE/BAIDU之后發(fā)現(xiàn)并沒有前人留下的成果。
使用抓包程序,以及綜合網(wǎng)絡(luò)上的信息,還是可以得出不少有用的信息:
# 飛秋兼容了飛鴿的協(xié)議,其協(xié)議格式基本上基于文本形式,各個(gè)內(nèi)容之間使用冒號(hào)作為分隔,例如:
1:100:user:pcname:32:message_body
# 飛秋在私聊情況下的消息內(nèi)容是沒有加密的,但群聊信息加密了,解密這個(gè)內(nèi)容也是我的目標(biāo)所在
# 在抓包軟件下根據(jù)消息的目標(biāo)IP地址可以推斷飛秋發(fā)送群信息是基于UDP組播的,即就算你不是這個(gè)群
的成員,也會(huì)收到群消息
有用的文章: 《局域網(wǎng)內(nèi)實(shí)現(xiàn)飛鴿欺騙》、《飛鴿傳書數(shù)據(jù)加密分析》(個(gè)人感覺沒有任何實(shí)質(zhì)內(nèi)容,而
且飛鴿傳書并不是飛秋,屬于誤導(dǎo)性文章,但是依然有用)。最重要的,稍微瀏覽IP message的代碼,
以及l(fā)inux下的iptux(另一個(gè)兼容飛鴿的局域網(wǎng)IM)代碼,都是對(duì)接下來(lái)的破解有益的。
破解
我希望我提供更多的,是一種crack的思路,雖然我不是一個(gè)cracker。破解和寫程序不太一樣,它需要
更多的耐心、運(yùn)氣、程序之外的思考。如前所做的準(zhǔn)備,尤其重要。
工具及環(huán)境:飛秋2.4版本、OllyDbg,為了方便接收群信息,最好有兩臺(tái)電腦。
STEP 1 找入手點(diǎn)
在開始面對(duì)一大推匯編代碼時(shí),我們需要一個(gè)最接近目標(biāo)的點(diǎn)。獲取這個(gè)點(diǎn)根據(jù)目標(biāo)的不同而不同。例如,
這里主要是針對(duì)網(wǎng)絡(luò)數(shù)據(jù)的解密。所以,最直接的就是去找這些網(wǎng)絡(luò)數(shù)據(jù)。當(dāng)然,根據(jù)具體程序的表現(xiàn),也
可以從其他點(diǎn)入手,例如飛秋收到群消息后會(huì)在任務(wù)欄閃爍圖標(biāo),也可以從這個(gè)功能逆向過(guò)去。
因?yàn)轱w秋使用UDP協(xié)議,所以我們可以在recvfrom函數(shù)下斷點(diǎn)(bp recvfrom)。因?yàn)榻邮誙DP包的接口
可能還有WSARecvFrom,甚至winsock1.0中的recvfrom,所以最好都下斷點(diǎn)。另一臺(tái)機(jī)器發(fā)送群消息,
程序在winsock1.0里的recvfrom斷下來(lái):
71A43001 > 8BFF mov edi, edi
71A43003 55 push ebp
71A43004 8BEC mov ebp, esp
71A43006 51 push ecx
這個(gè)不是我們需要的,我們需要根據(jù)這個(gè)點(diǎn)獲得用戶層代碼,這將是整個(gè)破解過(guò)程的起點(diǎn)。所以,OD中
ALT+K查看調(diào)用堆棧,然后跳到調(diào)用recvfrom的函數(shù)處:
00490890 /$ 56 push esi ; 接收數(shù)據(jù)的函數(shù)入口
00490891 |. 8B7424 08 mov esi, dword ptr [esp+8]
00490895 |. 8D46 10 lea eax, dword ptr [esi+10]
00490898 |. 50 push eax ; /pFromLen
00490899 |. 56 push esi ; |pFrom
0049089A |. C700 10000000 mov dword ptr [eax], 10 ; |
004908A0 |. 8B09 mov ecx, dword ptr [ecx] ; |
004908A2 |. 6A 00 push 0 ; |Flags = 0
004908A4 |. 8D46 18 lea eax, dword ptr [esi+18] ; |
004908A7 |. 68 FF3F0000 push 3FFF ; |BufSize = 3FFF (16383.)
004908AC |. 50 push eax ; |Buffer
004908AD |. 51 push ecx ; |Socket
004908AE |. E8 C7F30C00 call <jmp.&WSOCK32.#17> ; \recvfrom
邪惡的OD已經(jīng)將調(diào)用recvfrom時(shí)傳入?yún)?shù)的指令標(biāo)記出來(lái)了。中文注釋是我分析時(shí)加的。recvfrom里傳入
的接收緩存,是我們應(yīng)該關(guān)注的。如果能跟進(jìn)這個(gè)緩存,假設(shè)程序的流程比較簡(jiǎn)單:接收了數(shù)據(jù),然后在某個(gè)
地方直接解密,不管它的加密方式是什么,只要能找到這個(gè)緩存數(shù)據(jù)從加密變?yōu)榻饷艿牡胤剑瑢?duì)于整個(gè)破解而言,
都算是邁進(jìn)了一大步。
于是,在00490890(上面找到的函數(shù)入口)下斷點(diǎn),準(zhǔn)備跟進(jìn)接收緩存。注意:在OD里調(diào)試跟在vc里不一樣,
跳到調(diào)用堆棧里的某個(gè)函數(shù),寄存器依然是當(dāng)前的值。所以需要重新跟。
STEP 2 內(nèi)存斷點(diǎn)
F9讓程序繼續(xù)運(yùn)行,再次在另一臺(tái)機(jī)器上發(fā)送群消息。這回程序在00490890處斷下,然后跟接收緩存:
004908AC |. 50 push eax ; |Buffer = 0011F4CC
004908AD |. 51 push ecx ; |Socket
004908AE |. E8 C7F30C00 call <jmp.&WSOCK32.#17> ; \recvfrom
接收緩存Buffer的值為0011F4CC,如前所述,我們要跟進(jìn)這個(gè)地址指向的內(nèi)存的變化情況。F8單步運(yùn)行到
recvfrom后,也就是接收了網(wǎng)絡(luò)數(shù)據(jù)后,查看內(nèi)存內(nèi)容
(d 0011F4CC):
0011F4CC 31 5F 6C 62 74 34 5F 30 23 31 32 38 23 38 38 41 1_lbt4_0#128#88A
0011F4DC 45 31 44 44 34 36 36 46 44 23 30 23 30 23 37 32 E1DD466FD#0#0#72
0011F4EC 3A 31 32 39 35 37 32 31 32 31 33 3A 41 64 6D 69 :1295721213:Admi
0011F4FC 6E 69 73 74 72 61 74 6F 72 3A 50 43 2D 32 30 31 nistrator:PC-201
0011F50C 30 31 31 30 34 32 30 30 35 3A 34 31 39 34 33 33 011042005:419433
0011F51C 39 3A 5E 3B 83 A1 14 6D A4 D2 E3 D8 E8 AB B1 3A 9:^;儭mひ闔璜?
0011F52C 5B BC C2 FE E9 DA CB DD 00 BC 59 FC 9D A7 D7 91 [悸謁?糦鼭ё
內(nèi)容開頭正是飛秋的協(xié)議頭,未加密,不過(guò)沒多大用。根據(jù)之前獲取的飛秋協(xié)議,可知,在0011F51E
處就是聊天內(nèi)容的密文。
很自然地,為了監(jiān)視這段內(nèi)存的變化情況,在該位置下內(nèi)存訪問(wèn)斷點(diǎn)(右擊數(shù)據(jù)區(qū)即可看到下斷點(diǎn)的選項(xiàng))。
F9繼續(xù)走,然后馬上斷下來(lái):
0049010F |. F3:A5 rep movs dword ptr es:[edi], dword ptr [>
00490111 |. 8B4A 04 mov ecx, dword ptr [edx+4]
00490114 |. C74424 24 000>mov dword ptr [esp+24], 0
0049011C |. 894D 64 mov dword ptr [ebp+64], ecx
0049011F |. 33C9 xor ecx, ecx
程序到了一個(gè)陌生的環(huán)境(在這種滿世界都是匯編代碼的情況下,幾乎一不小心就會(huì)迷失其中),看了下
附近的代碼,沒什么可疑。通過(guò)下內(nèi)存訪問(wèn)斷點(diǎn)的思路,似乎顯得荊棘叢生。
STEP 3 靠近目標(biāo)
不妨冷靜下來(lái)思考,如果沒有直接的路,我們可能需要悲慘地大海撈針。在寫一個(gè)網(wǎng)絡(luò)程序時(shí),網(wǎng)絡(luò)底層
收到數(shù)據(jù)包,無(wú)非要么直接進(jìn)行邏輯處理,要么緩存到一個(gè)邏輯處理隊(duì)列里稍后處理。后者雖然對(duì)于程序員
而言是個(gè)好方法,但是因?yàn)榭缌司€程,又涉及到隊(duì)列緩存,對(duì)于逆向而言,絕對(duì)是悲劇。
但是如果使用了前者呢?對(duì)于一個(gè)網(wǎng)絡(luò)客戶端程序而言,也許直接進(jìn)行邏輯處理才是最KISS的方法。(這種猜測(cè)
的破解方式,絕對(duì)需要運(yùn)氣。)所以,如果是直接進(jìn)行處理,那么在接收到網(wǎng)絡(luò)數(shù)據(jù)附近,必然就有解密函數(shù)。
所以,不妨順著收包函數(shù)附近隨意瀏覽一番。(但不要走進(jìn)太深的call,不然又迷失了。)
0048FE10 /$ B8 18400000 mov eax, 4018
0048FE15 |. E8 560A0C00 call 00550870
0048FE1A |. 8D4424 00 lea eax, dword ptr [esp]
0048FE1E |. 56 push esi
0048FE1F |. 8BF1 mov esi, ecx
0048FE21 |. 50 push eax
0048FE22 |. E8 690A0000 call 00490890 ; 接收網(wǎng)絡(luò)數(shù)據(jù)
0048FE10函數(shù)調(diào)用了剛才發(fā)現(xiàn)的收包函數(shù)。這個(gè)函數(shù)在收完數(shù)據(jù)后,不久就調(diào)用了另一個(gè)函數(shù):
0048FE3F |. 51 push ecx
0048FE40 |. 52 push edx
0048FE41 |. 8BCE mov ecx, esi
0048FE43 |. E8 88020000 call 004900D0 ; 似乎很可疑?
進(jìn)到004900D0函數(shù),發(fā)現(xiàn)這個(gè)函數(shù)真TMD巨大。隨意瀏覽之,發(fā)現(xiàn)OD有這種提示:
00490178 |. 68 34FD5E00 push 005EFD34 ; ASCII "_lbt"
0049017D |. 8D4C24 14 lea ecx, dword ptr [esp+14]
00490181 |. 89BC24 544000>mov dword ptr [esp+4054], edi
_lbt,恩,消息頭里有這個(gè)字符串標(biāo)識(shí)。估計(jì)是在做些消息頭的邏輯操作。這個(gè)函數(shù)太長(zhǎng),里面還有若干call,
可謂頭大。所以說(shuō),代碼寫得丑,可讀性差,對(duì)于防破解還是頗有益處的。跳回到0048FE43,發(fā)現(xiàn)當(dāng)前
函數(shù)基本完了。
于是往上看,來(lái)到調(diào)用這個(gè)函數(shù)的地方:
0050F647 |. E8 C407F8FF call 0048FE10
0050F64C |. BF 01000000 mov edi, 1
回顧下,我們有函數(shù)A接收網(wǎng)絡(luò)數(shù)據(jù),有函數(shù)B調(diào)用A,現(xiàn)在回到了C,來(lái)到了調(diào)用B的地方0050F647。C函數(shù)
也很巨大,直接往下瀏覽,會(huì)發(fā)現(xiàn)一些switch語(yǔ)句:
0050F71A |. 81E6 FF000000 and esi, 0FF
0050F720 |. 8D46 FF lea eax, dword ptr [esi-1] ; Switch (cases 1..D3)
0050F723 |. 3D D2000000 cmp eax, 0D2
0050F728 |. 0F87 8C000000 ja 0050F7BA
0050F72E |. 33C9 xor ecx, ecx
0050F730 |. 8A88 60315100 mov cl, byte ptr [eax+513160]
0050F736 |. FF248D 403051>jmp dword ptr [ecx*4+513040]
0050F73D |> 8D9424 F40000>lea edx, dword ptr [esp+F4] ; Case 1 of switch 0050F720
往后瀏覽下這個(gè)switch…case,發(fā)現(xiàn)非常之大,這個(gè)函數(shù)也因此非常巨大。不妨猜測(cè)這個(gè)是根據(jù)不同消息做不同
邏輯處理的地方。這個(gè)想法正是給予我們靈感的關(guān)鍵。
群聊消息必然也有個(gè)類型,通過(guò)之前OD獲取到的網(wǎng)絡(luò)數(shù)據(jù)(或者截取網(wǎng)絡(luò)封包所得),群聊消息的類型為:4194339
(16進(jìn)制400023H),去掉高位,也就是23H。仔細(xì)地對(duì)比每一個(gè)case,果然發(fā)現(xiàn)了一段處理代碼:
00512787 |> \39AC24 640100>cmp dword ptr [esp+164], ebp ; Case 23 of switch 0050F720
0051278E |. 75 07 jnz short 00512797 ; 群聊天處理
00512790 |. 8BC7 mov eax, edi
00512792 |. E9 8C080000 jmp 00513023
這個(gè)代碼之下的處理也有不少代碼。在不涉及到更多細(xì)節(jié)之前,我們可以大膽地將注意力放在接下來(lái)的call上。從這個(gè)case
往下,第一個(gè)call為:
005127E6 |. 50 push eax
005127E7 |. E8 A4A20000 call 0051CA90 ; 非常可疑
005127EC |. B8 01000000 mov eax, 1
005127F1 |. E9 2D080000 jmp 00513023
STEP 4 多嘗試
有懷疑,就用事實(shí)來(lái)證明。果斷地在005127E6處下斷點(diǎn)。然后發(fā)群消息,程序斷下來(lái)。因?yàn)檫@個(gè)函數(shù)壓入了
eax作為參數(shù),且對(duì)ecx做了賦值:
005127E4 |. 8BCB mov ecx, ebx
005127E6 |. 50 push eax
005127E7 |. E8 A4A20000 call 0051CA90 ; 非常可疑
在調(diào)用一個(gè)函數(shù)前對(duì)ecx做賦值,一般都是C++成員函數(shù)調(diào)用。eax作為一個(gè)參數(shù),非常值得關(guān)注,果斷查看eax
指向的內(nèi)存值:
001235C8 41 64 6D 69 6E 69 73 74 72 61 74 6F 72 00 6D 00 Administrator.m.
001235D8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
001235E8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
001235F8 00 00 50 43 2D 32 30 31 30 31 31 30 34 32 30 30 ..PC-20101104200
00123608 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 5...............
00123618 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00123628 8A 7B 00 00 C0 A8 00 03 09 79 00 00 01 00 00 00 妠..括..y.....
00123638 04 00 00 00 00 00 00 00 80 00 00 00 38 38 41 45 .......€...88AE
00123648 31 44 44 34 36 36 46 44 00 00 00 00 00 00 00 00 1DD466FD........
00123658 00 00 00 00 F4 C7 23 00 FD 22 3B 4D 23 00 40 00 ....羥#.?;M#.@.
00123668 49 00 00 00 36 00 00 00 5E 3B 83 A1 14 6D A4 D2 I...6...^;儭mひ
有用戶名、機(jī)器名、發(fā)送者M(jìn)AC地址,這么多可疑信息。完全可以猜測(cè),eax傳入的是一個(gè)結(jié)構(gòu)體地址,
當(dāng)然對(duì)象地址也可以,反正是個(gè)復(fù)雜數(shù)據(jù)結(jié)構(gòu)。更重要的,在這塊內(nèi)存往下不遠(yuǎn)處,果斷地發(fā)現(xiàn)了從
網(wǎng)絡(luò)接收到的加密的聊天內(nèi)容:
00123670 5E 3B 83 A1 14 6D A4 D2 E3 D8 E8 AB B1 3A 5B BC ^;儭mひ闔璜?[
00123680 C2 FE E9 DA CB DD 00 BC 59 FC 9D A7 D7 91 CF 5A 漫櫞溯.糦鼭ё懴Z
F8直接步過(guò)0051CA90函數(shù)。任務(wù)欄開始出現(xiàn)閃爍的圖標(biāo)(雖然沒有閃),上面的內(nèi)存數(shù)據(jù)變了:
00123670 74 65 73 74 7B 2F 66 6F 6E 74 3B 2D 31 34 20 30 test{/font;-14 0
00123680 20 30 20 30 20 34 30 30 20 30 20 30 20 30 20 31 0 0 400 0 0 0 1
00123690 33 34 20 33 20 32 20 31 20 32 20 CB CE CC E5 20 34 3 2 1 2 宋體
test正是我發(fā)的內(nèi)容。
STEP 5 縮小范圍
實(shí)際上走到這里,憑借運(yùn)氣和程序編寫的常識(shí),已經(jīng)找到關(guān)鍵點(diǎn)。不過(guò)看來(lái)0051CA90這個(gè)函數(shù)做的事情
有點(diǎn)多,除了解密內(nèi)容似乎還有UI上的一些處理(例如那個(gè)閃爍的任務(wù)欄圖標(biāo))。所以,我們要做的是,進(jìn)一步
跟進(jìn),找到關(guān)鍵點(diǎn)。
現(xiàn)在縮小范圍要容易得多,因?yàn)槲覀兊玫搅艘粋€(gè)會(huì)變化的內(nèi)存地址:00123670。只需要F8一步一步地
運(yùn)行代碼,一旦發(fā)現(xiàn)內(nèi)存內(nèi)容改變,則可以進(jìn)一步進(jìn)如,從而找到關(guān)鍵call。具體過(guò)程我就不給了,大概為:
0051CB02 |. 52 push edx
0051CB03 |. 68 00400000 push 4000
0051CB08 |. 56 push esi
0051CB09 |. 50 push eax
0051CB0A |. 56 push esi
0051CB0B |. E8 F041F7FF call 00490D00 ; 跟進(jìn)
00490DB0 |. 6A 00 push 0
00490DB2 |. 83E1 03 and ecx, 3
00490DB5 |. 6A 22 push 22
00490DB7 |. F3:A4 rep movs byte ptr es:[edi], byte ptr [es>
00490DB9 |. 8BBC24 344000>mov edi, dword ptr [esp+4034]
00490DC0 |. 50 push eax ; 數(shù)據(jù)長(zhǎng)度
00490DC1 |. 8D4424 20 lea eax, dword ptr [esp+20]
00490DC5 |. 57 push edi ; 輸出緩存
00490DC6 |. 50 push eax ; 輸入緩存(加密內(nèi)容)
00490DC7 |. 8D4C24 20 lea ecx, dword ptr [esp+20]
00490DCB |. E8 5049F7FF call 00405720 ; 最終解密函數(shù)
00405720函數(shù)內(nèi)的實(shí)現(xiàn)基本上全是數(shù)據(jù)操作指令。加解密算法無(wú)非就是搗鼓這些數(shù)據(jù),所以當(dāng)我進(jìn)到
00405720函數(shù)時(shí),基本上可以斷定它就是最終的解密函數(shù)。
STEP 6 解密
事實(shí)上我們并不需要去弄懂它的具體解密算法,就算是直接的C++代碼,沒有算法論文的話也很難看懂,更何況
是這里的匯編。最直接的方式,就是查看這個(gè)解密函數(shù)對(duì)外界的依賴情況,例如需要的參數(shù),this里是否有依賴
的數(shù)據(jù)。在了解了這些情況后,大可以將這段匯編復(fù)制出來(lái)直接作為C++內(nèi)嵌匯編代碼使用。
不過(guò),這里我想到了更簡(jiǎn)單的方式。因?yàn)槲易⒁獾斤w秋和飛鴿在實(shí)現(xiàn)上有著不解之緣,而且我琢磨著作者也不會(huì)
為了一個(gè)加解密不太重要的應(yīng)用場(chǎng)合而去整些高深的算法。我想到,飛秋也許會(huì)直接使用飛鴿里的加解密代碼!
在IP message的源碼里,有blowfish加密算法的實(shí)現(xiàn),我們來(lái)看接口:
class CBlowFish
{
private:
DWORD *PArray;
DWORD (*SBoxes)[256];
void Blowfish_encipher(DWORD *xl, DWORD *xr);
void Blowfish_decipher(DWORD *xl, DWORD *xr);
public:
CBlowFish(const BYTE *key=NULL, int keybytes=0);
~CBlowFish();
void Initialize(const BYTE *key, int keybytes);
DWORD GetOutputLength(DWORD lInputLong, int mode);
DWORD Encrypt(const BYTE *pInput, BYTE *pOutput, DWORD lSize, int mode=BF_CBC|BF_PKCS5, _int64 IV=0);
DWORD Decrypt(const BYTE *pInput, BYTE *pOutput, DWORD lSize, int mode=BF_CBC|BF_PKCS5, _int64 IV=0);
};
從接口實(shí)現(xiàn)來(lái)說(shuō)算是簡(jiǎn)潔漂亮友好和諧。我也用Decrypt這個(gè)函數(shù)的參數(shù)比對(duì)了上面沒找到的那個(gè)call(00405720),
因?yàn)檫@里只是懷疑這個(gè)call就是這里的Decrypt,但并沒有確切的證據(jù)。不過(guò),對(duì)比下他們的參數(shù)就可以非常肯定了:
00490DB0 |. 6A 00 push 0 ;參數(shù)IV
00490DB2 |. 83E1 03 and ecx, 3
00490DB5 |. 6A 22 push 22 ;參數(shù)mode
00490DB7 |. F3:A4 rep movs byte ptr es:[edi], byte ptr [es>
00490DB9 |. 8BBC24 344000>mov edi, dword ptr [esp+4034]
00490DC0 |. 50 push eax ; 參數(shù) 數(shù)據(jù)長(zhǎng)度
00490DC1 |. 8D4424 20 lea eax, dword ptr [esp+20]
00490DC5 |. 57 push edi ; 參數(shù)輸出緩存
00490DC6 |. 50 push eax ; 參數(shù)輸入緩存(加密內(nèi)容)
00490DC7 |. 8D4C24 20 lea ecx, dword ptr [esp+20]
00490DCB |. E8 5049F7FF call 00405720 ; 最終解密函數(shù)
最重要的,是參數(shù)mode。Decrypt默認(rèn)參數(shù)mode是BF_CBC|BF_PKCS5的位組合,結(jié)果,恰好為22!
所以,基本上可以斷定:飛秋的加解密實(shí)現(xiàn),就是使用了IP message的blowfish算法:blowfish.cpp/h/h2。
STEP 7 密鑰
查看CBlowFish的使用,在解密前需要初始化,大概就是傳入密鑰之類。如果我們上面的猜測(cè)沒有錯(cuò),那么我們
從網(wǎng)絡(luò)上取得的數(shù)據(jù),然后取得密鑰,直接使用blowfish的源碼,就可以解密出消息內(nèi)容。
接下來(lái)的關(guān)鍵就是,找到這個(gè)密鑰。關(guān)于這個(gè)密鑰,之前在飛秋的配置文件FeiqCfg.xml里繞了很久的圈子,因?yàn)?/p>
發(fā)現(xiàn)加入一個(gè)群的時(shí)候,這個(gè)文件里就會(huì)多出一項(xiàng)很長(zhǎng)的16進(jìn)制字符串。也一度猜測(cè)密鑰就是保存在這個(gè)字符串的
某個(gè)偏移里。接下來(lái)會(huì)讓人大跌眼鏡。
因?yàn)镃BlowFish這個(gè)類確實(shí)簡(jiǎn)單,使用它的最簡(jiǎn)單方式就是直接創(chuàng)建局部對(duì)象,然后傳入key和keysize,即可完成
初始化。在之前展示的思路里,我也一度先去嘗試最簡(jiǎn)單的方法。對(duì)于C++局部對(duì)象的創(chuàng)建,有個(gè)顯著特征就是
mov ecx, dword ptr [esp+xxx],也就是往ecx里寫入一個(gè)棧地址。而且可以肯定的是,這個(gè)構(gòu)造代碼,必然發(fā)生
于call 00405720前面不遠(yuǎn)處,往上跟進(jìn):
00490D3F |> \8B8C24 304000>mov ecx, dword ptr [esp+4030]
00490D46 |> 51 push ecx
00490D47 |. 52 push edx
00490D48 |. 8D4C24 0C lea ecx, dword ptr [esp+C]
00490D4C |. E8 3F3DF7FF call 00404A90
一個(gè)壓入兩個(gè)參數(shù)的函數(shù)調(diào)用,對(duì)比CBlowFish的構(gòu)造函數(shù),剛好是2個(gè)參數(shù)。跟進(jìn)00404A90:
00404A90 /$ 56 push esi
00404A91 |. 8BF1 mov esi, ecx
00404A93 |. 6A 48 push 48
00404A95 |. E8 69301600 call 00567B03
00404A9A |. 68 00100000 push 1000
00404A9F |. 8906 mov dword ptr [esi], eax
00404AA1 |. E8 5D301600 call 00567B03
又是可愛的立即數(shù)!48H、1000H,這種特別的立即數(shù)總能讓人安心,對(duì)比CBlowFish構(gòu)造函數(shù)實(shí)現(xiàn):
CBlowFish::CBlowFish (const BYTE *key, int keybytes)
{
PArray = new DWORD [NPASS + 2];//NPASS=16
SBoxes = new DWORD [4][256];
if (key)
Initialize(key, keybytes);
}
sizeof(DWORD)*18=48H,sizeof(DWORD)*4*256=1000H!這么極具喜劇意義的匯編C++代碼映射,
基本可以肯定,00404AA1處,正是構(gòu)造CBlowFish對(duì)象的地方,而構(gòu)造的參數(shù),正是我們魂?duì)繅?mèng)縈的解密密鑰:
00490D46 |> \51 push ecx ; key長(zhǎng)度
00490D47 |. 52 push edx ; 密鑰key
00490D48 |. 8D4C24 0C lea ecx, dword ptr [esp+C]
00490D4C |. E8 3F3DF7FF call 00404A90 ; 構(gòu)造blowfish對(duì)象
在此處下斷點(diǎn),發(fā)送群消息,程序斷下來(lái),看看密鑰究竟是什么。如果它確實(shí)是FeiqCfg.xml里的某個(gè)值,
那么我們還要進(jìn)一步跟這個(gè)值具體在哪個(gè)配置項(xiàng)里。看看吧,密鑰edx:
edx=00123644, (ASCII "88AE1DD466FD")
TM的密鑰居然是發(fā)送者的MAC地址!當(dāng)我看到這個(gè)的時(shí)候我?guī)缀蹩焖さ沟厣稀H绻w秋使用一個(gè)MAC地址
作為密鑰,那么這意味著:通過(guò)自己寫的程序,可以取得局域網(wǎng)內(nèi)其他群里的聊天內(nèi)容!這個(gè)實(shí)在太邪惡了。
上回抓包的時(shí)候,雖然看不到內(nèi)容,但可以看到美術(shù)、策劃在群里聊的無(wú)比歡樂(lè)。這回有喜感了。
STEP END 可略
看看時(shí)間,悲劇地發(fā)現(xiàn)整篇文章花了接近3個(gè)小時(shí)才寫完。此刻我正躊躇要不要把代碼發(fā)上來(lái),但轉(zhuǎn)念一想
最后那個(gè)STEP的發(fā)現(xiàn)實(shí)在讓人蛋疼,所以還是算了。打算稍微封裝下,然后使用這份代碼在iptux 上改改包裝
個(gè)界面,目的就算達(dá)成了。相信瀏覽完整篇文章,寫出自己的代碼不是什么大問(wèn)題。
其實(shí)我大可以直接給結(jié)論,但是我依然樂(lè)于分享過(guò)程和思路。一來(lái)算是自我總結(jié)記錄(每次拿起OD,總是快捷
鍵一路忘);二來(lái)也給有心人一個(gè)指引。
最后,對(duì)這種東西還是有必要出個(gè)免責(zé)聲明:根據(jù)本文章所造成的一切后果與文章作者無(wú)關(guān)。為了不糟蹋我這3個(gè)
小時(shí)的時(shí)間,轉(zhuǎn)載麻煩注明出處。
PS,最后回顧下結(jié)論,其實(shí)發(fā)現(xiàn)這個(gè)解密非常非常簡(jiǎn)單。你說(shuō)如果直接給盧本陶(飛秋作者)發(fā)封郵件,他會(huì)不
會(huì)直接告訴我?