雙程序是什麼
不是吧,雙程序?
使用工具:
IDA6。8(反彙編分析)
notepad(記錄)
vc6。0(解碼)
OD(除錯)
關鍵步驟:
一、程式碼自解密
IDA載入看入口點和匯入表,沒有發現任何有用的東西,考慮該程式已經加密處理。
進入sub_44701F函式,發現該函式主要是解碼。
OD動態跟蹤發現如下圖所示,004473A8處的長跳轉代表本段解碼完成。
此時可以從dump出記憶體用IDA觀察,此時函式已經完成解密,但由於匯入函式全部經由LoadLibrary和GetProcAddress動態載入,匯入表中也找不到有用資訊。
二、識別真正流程
繼續OD動態跟蹤,在此處發現DialogBoxParamW,有過MFC程式設計經驗的朋友應該不陌生,說明我們已經找到關鍵點了(其實不然)。
跟蹤發現此處的JE跳轉會實現,也就是DialogBoxParamW根本沒有執行,但程式執行起來的視窗是哪兒來的呢?
其實作者手動建立了一個程序,該程序和主程序基本相同,JE前的call判斷是主程序還是子程序。如果是主程序就直接跳過,是子程序則進入執行DialogBoxParamW。
由於子程序無法直接附加(如下圖),從原理分析,可以直接將004016AF處的JE用NOP替換,強制進入主程序的流程。
此時,視窗回撥函式為sub_00401740,其中和註冊有關的是sub_401A40如下。
和註冊有關的邏輯在紅線之間,最多19個0xFF以下的數相加,結果等於0x127514D,明顯不可能成立。
思路錯誤。
既然附加不了,可以dump子程序記憶體,用IDA分析。再看sub_401A40,發現就剩一個頭了,真正的邏輯在sub_402300。
三、第一個關鍵演算法
實際除錯時可以在4016AF處將JE用NOP代替,將401A43處修改為jmp402303,即可繞過,直接除錯主程序。
另外,此題動態記憶體執行程式碼較多,建議關鍵位置下好“硬體執行”斷點,便於除錯。
sub_402300函式比較長,IDA中F5後還有800多行,結合動態除錯,找到關鍵位置。
考慮對第9、10位的數字進行列舉,動態除錯找到待解碼和比較的資料,編寫程式碼如下。
#include
unsigned m_DE0000[] = { 0x83F08EA7,0x3F0FBA29,0xE747E97C,0x93D03647,0xEC72CD2C,0x93C0BA2E,0x90A578A3,0x2A40BA2F, 0xDB3FF233,0x9031FB09,0xD1477258,0x905E3DAC,0xAB817C35,0x6BD43434,0xC49E84E4,0x83B426AF,0x51C0BA3A,0x280080B8,0x93BE3FF3,0x8E36BA3B,0xE9C0BA3C,0x93C0BA29,0x93C0B2C5,0x1680CD3F};
unsigned m_4340B0[] = { 0x1070EC81,0x55530000,0xBC8B5756,0x00108424,0xBBF63300,0x00000001,0x0725C68B,0x79800000,0xC8834805,0x07B140F8,0xC68BC82A,0x07E28399,0xF8C1C203,0x38148A03,0xD322FAD2,0x10349488,0x46000002,0x7C40FE83,0x0002BDCF,0x05BA0000,0xBE000000,0x00000014,0x000008B9,0x8DC03300};
int main()
{
unsigned xx = 0;
unsigned yy,zz1,zz2;
for(xx=0;xx =0xff;xx++)
{
yy = 0x1010101*xx;
zz1=(m_DE0000[0]+yy)^m_4340B0[0];
zz2=(m_DE0000[1]+yy)^m_4340B0[1];
if(zz1 == (zz2-1))
{
printf(“%02X\n”,xx);
printf(“%08X\n”,zz1);
}
}
return 0;
}
得到結果。
因此註冊碼前10位為“75A29C09E1”。前10位輸入此註冊碼,可以看到解碼結果為正常的反彙編,說明是正確的。
四、第二個關鍵演算法
還是sub_402300中,剛解碼的函式對輸入註冊碼第10位以後的字串進行處理,處理結果與“!HelloHaniella!”比較,返回值與sub_402240的返回值比較。
此處,可將記憶體中已解碼的函式dump出來,用IDA分析。
IDA載入,發現非常直觀,但也非常長,F5後還有2838行,難以下手。
百度搜索常量,發現是DES的置換表,該程式將DES中所有的東西都放在一個函式中,顯得特別龐大,也加大了分析難度。
將函式的輸入輸出與標準DES對比,發現不一樣。接下來就是對照標準DES和該函式,修改DES和該函式一樣。
不同點1: ByteToBit
該函式中,如下
故,修改標準DES中對應函式,如下
不同點2 :子秘鑰使用順序
該函式中,與子秘鑰的異或操作從最後一個開始
故修改標準DES加密操作中對應位置如下
相對的,修改解密操作程式碼
不同點3 :ByteToBit1
故修改標準DES中程式碼如下
不同點4 :調整R、L順序
除錯發現,最後的R和L順序反了,故修改程式碼。在加密操作最後和解密操作最前均加上如下程式碼。
這四處修改後,DES演算法加密結果和該函式一致,且能正常解密。
此加密結果還要經過如下過程,將偶數字節0、1互換。
然後再轉換為16進位制Byte,與“!HelloHaniella!”比較。故解密可以將此字串轉化為bit,然後偶數位取反,再透過修改後的DES演算法解密,結果即為註冊碼10位以後的正確結果。
分兩次,各8位,分別得到結果“80217C048420956C” 和 “15DA309FF2B69170” ,如下。
五、結論
組合兩個關鍵演算法的結果,得到註冊碼“75A29C09E180217C048420956C15DA309FF2B69170”,輸入程式,結果如下。
當然,由於作者沒有考慮到結尾的0x00,導致結尾加上(0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00)解密後的結果“FAB17827375A8685”後依然正確,如下。理論上講有無數個 即“75A29C09E180217C048420956C15DA309FF2B69170(FAB17827375A8685迴圈)”。
題目連結:看雪CTF2017年中賽第11題
長按關注