轉載Tracy'BlogTracy_梓朋
http://www.purpleroc.com/html/623079.html
--------------------------------------------------------------------
有了在涉外混跡四年,寫下的《校園網那些事》的經歷后,寫這篇文章似乎要比以前容易些。來重慶也有1個半月了,一直昏昏忽忽的,總提醒自己要打起精神來,卻總打不起精神。可能是很久沒什么能夠刺激自己、給自己增加自信心吧,於是決定看看學校的客戶端。
以前做過類似的事,於是,也就有些思維固定,不想再去做同類型的事了,屬於眼高手低型。然而賬號到期了,又想起了以前做過的事。那,來找找自信吧~~不過,這客戶端比涉外的安騰高級了好幾倍~~~~
其實,先前也看過這個客戶端,不過,一直想的是能夠實現linux下撥號上網。好了,廢話不多說了,進入正文吧。
先說目的:從文件中還原出我們撥號時輸入的賬號、密碼。那先從文件看起,看看是哪個文件保存了這些信息。
打開netkeeper的安裝目錄,看看每個文件是干嘛用的:
這個應該是沒可以理解的。那,保存密碼的文件應該是在bin或者是config文件夾中了(省去推論文字,沒看懂的可以先看看《校園網那些事》……)。其實,我們對比剛安裝好程序,和撥號一次之后文件夾中的內容就可以清楚的看到,在bin文件中多了一個Credit文件。那,它很有可能就是我們要找的文件了。
ok,我們拿出peid看看程序有沒加殼,
提示沒找到,不過,看區段就知道vmp的殼。我等菜鳥是沒想過要去挑戰它的。那,帶殼運行來調試吧。
OD載入(忽略所有異常),直接對下斷bp CreateFileA(分析見《校園網那些事》),F9跑起來,發現了類似如下call
0018785C 7266C4A4 つfr /CALL 到 CreateFileA 來自 AcLayers.7266C4A1 00187860 00187CA0 爘. |FileName = "\\.\Global\NPF_{C97F955E-E47F-4270-9432-764A2C7C41D3}"
我們暫且把它當作是vmp殼對程序自解壓時的一些操作吧(知道的還麻煩告知一聲),這也是為什么在我們確定了讀取文件的位置后不能直接對地址下斷,而必須每次都跑完對類似這些|FileName = "\\.\Global\NPF_文件的操作的原因。我理解為,因為程序還沒解壓完,你直接下斷,會引起程序解壓出錯,而導致程序出錯。
一直F9到FileName為C:\ChinaNetSn\時就要注意了。
一下下的摁F9,到出現讀取Credit文件:
取消斷點,Alt+F9返回用戶代碼區。我看到的是非常亂的數據:
沒關系,CTRL+A分析一下。就出現了我們可愛的反匯編代碼了:
我們可以看到,剛才程序僅僅是訪問Credit文件,而還沒進行讀取。以下是讀取片段。
為了節省篇幅,直接復制代碼吧:
0041B049 > \817C24 0C 8C1>cmp dword ptr ss:[esp+C],168C ; 文件完整性校驗
0041B051 . 74 17 je short NetKeepe.0041B06A
……
0041B06A > \56 push esi ; /hObject
0041B06B . FF15 30425000 call dword ptr ds:[504230] ; \CloseHandle
0041B071 . 6A 00 push 0
0041B073 . 57 push edi
0041B074 . 8BCB mov ecx,ebx
0041B076 . E8 25000000 call NetKeepe.0041B0A0 ; 加解密入口
為什么判斷0041B076時解密入口呢?你可以自己直接F8過去,然后看寄存器啊,內存啊,等等之類的變化來確定。好吧,主題來了,我們要解決的就是這個call。
先看反匯編代碼以及我的注釋:(有點長,放到最后附錄一中。想看的忍一忍看完吧!)
這里解釋下主要代碼段:
這段標准的代碼中,我們可以看出,解密有三個步驟,第一和第三步是進行移位操作,第二部才是真正的各種轉換。
我們要進行解密,也就是把這段代碼換成我們的C語言,來進行解密。在解密入口處寫了個xinlides,其實我也不知道他是不是用的des。目測不是吧:
附上C程序解密代碼。(見附錄二)
這里解釋下主要代碼段:
void encode(char *buffer, int len)
{
char *p;
while (len)
{
p = encode1(buffer);//位置交換
encode2(buffer, p);//解密
encode3(buffer);//順序改回
len = len - 8;
buffer = buffer + 8;
}
}
最難的問題應該在於第二步了,為了偷懶,少寫點代碼,就直接用C語言嵌套asm來實現。
不過這樣做的最困難的地方應該在於,保護現場以及,匹配好各傳入參數。我們來對比一下C和反匯編的代碼。
在反匯編代碼中,進行第二步加密中 mov eax, dword ptr [ecx]前,push了以下參數:
00404256 |. 68 80755400 push NetKeepe.00547580 ; 要用到的pass
0040425B |. 52 push edx ; 放入地址
0040425C |. E8 DF000000 call NetKeepe.00404340 ; 解密第二步
00404340 /$ 51 push ecx
00404341 |. 8B4C24 08 mov ecx,dword ptr ss:[esp+8]
00404345 |. 53 push ebx
00404346 |. 55 push ebp
00404347 |. 56 push esi
那么,我們要做的就是,弄清楚這些push進去的東西,是什么,在后面用不用得上。
通過分析可以得到00404256處push的是要用到的解密矩陣。0040425B是什么要解密的內容(已被第一步解密的內容)。00404340是push此次要解密的最后一位數的地址。其實可以看作保護現場。00404341是把0040425B處放入的內容彈出,即ecx中保存的是實際上要進行解密的那四個字符。后面連續三個push是為了保護現場。
所以,在進行代碼嵌套的時候,我們要想這段反匯編代碼能夠按我們的想法運行,我們就要給他創造好條件。所以,在開頭,我們構造如下:
void encode2(char *buffer, char *key)
{
__asm
{
lea eax, key
push [eax] //生成的key的地址壓棧 0018fe1c
lea eax, pass
push eax //把pass的地址壓棧 0018fe18
lea eax, buffer
push [eax] //剩余的要解密的內容入棧 0018fe14
mov ecx, dword ptr [esp+8] //把key給ecx
push ebx //10
push ebp //0c
push esi //08
mov eax, dword ptr [ecx]
mov edx, dword ptr [ecx+4]
mov ecx, eax
mov esi, edx
shr ecx, 4
and ecx, 0x0F0F0F0F
and esi, 0x0F0F0F0F
xor ecx, esi
……
xor esi, eax //esi中為解密后,前四個字節
mov eax, dword ptr [esp+0x6C] //將buffer的地址給eax 重點是,是否成功得到buffer地址
xor edx, ecx //edx中為解密后,后四位字節
mov dword ptr [eax], esi //寫入解密后的前四位字符
pop esi
pop ebp
mov dword ptr [eax+4], edx //寫入解密后的后四位字符
pop ebx
pop edx
pop ecx
pop ecx//后來自己加上去的(不然,彈出的esp恢復不了)
}
}
當然,要嵌套好反匯編的asm為自己所用,你必須自己單步去一一調試,對比每一步得到的結果。有差異,就更改~~~
其中還有個很有趣的代碼如下:
原反匯編代碼中所有的類似如下的內存賦值:
mov ebp,dword ptr ds:[ebx*4+536408]
均被替換為:
push ecx
lea ecx, key3
mov ebp, dword ptr [ebx*4+ecx]
pop ecx
很巧妙的用到了堆棧作為臨時存儲點。
好吧,就寫到這里吧。
代碼實現的功能是:
把Credit文件中的所有賬號密碼解密后取出,以明文形式保存到Credit.txt文件中。
其實,我們還可想象下一些盜號程序的工作原理,我們設立一個服務端用作收信,程序把得到的buf發送到服務端,就是一個典型的盜號程序了。
好了,就寫到這,大家,看得懂的給點點評,看不懂的碰個人場吧。
下一步要做的,盡量找到心跳包原理,希望能夠完全脫離netkeeper吧,動態用戶名的生成算法網上已經有了。我也拿了分,不過,暫時沒用上,有想研究的,可以聯系我,一起努力把。
最后,感謝monsterok ,文中代碼是基於他的帖子中給出的代碼做的更改 :http://bbs.pediy.com/showthread.php?t=136534&highlight=%E9%97%AA%E8%AE%AF