最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

算法分析:看雪CTF2019的一道逆向題目

2022-03-24 14:47 作者:rkvir逆向工程學(xué)院  | 我要投稿

1.查看程序的基本運(yùn)行邏輯

出現(xiàn)一個窗口,有一個提示標(biāo)簽password、一個輸入框,一個驗(yàn)證按鈕

當(dāng)再輸入框內(nèi)輸入一些字符按下驗(yàn)證按鈕后出現(xiàn)錯誤提示信息框

其運(yùn)行邏輯大概可視為下圖

2.查殼初探

MFC封裝vc寫的沒殼

3.使用IDA Pro進(jìn)行靜態(tài)分析

①拖入程序,先打開函數(shù)調(diào)用情況窗口(方便函數(shù)跟蹤)

②shift+F12查看引用字符

看到了剛才錯誤的提示字符“錯了”,還有嫌疑字符“pass!”,那我們找到pass字符所在的位置查看引用情況

③查看引用,找到引用函數(shù)

發(fā)現(xiàn)pass!字符的引用的函數(shù)是sub_401770,跟進(jìn)去

跟進(jìn)來看到的信息可以直接判斷sub_401770這個函數(shù)就是輸入提示我們輸入的password是正確的函數(shù)

④跟蹤函數(shù)調(diào)用情況,直至找到最終調(diào)用者

(1)做一個小提示:在ida中我們看到的函數(shù)都是一個以sub_函數(shù)地址值來命名這個函數(shù),不便于我們分析,所以我們只用將光標(biāo)放在函數(shù)名字上按下n鍵就可以更改為我們便于理解和記住的名字(不可以用中文)

先將sub_401770改名為Tip_Success,通過函數(shù)調(diào)用表點(diǎn)擊Caller字符函數(shù)名就會跳轉(zhuǎn)Instruction字段函數(shù)的對應(yīng)的調(diào)用者

(2)跟進(jìn)發(fā)現(xiàn)sub_4017F0函數(shù)中有關(guān)鍵邏輯

將Str1與"KanXueCTF2019JustForhappy"作對比,如果相等則執(zhí)行了提示成功的函數(shù)Tip_Success,那我們可以直接推測Str1就是Flag最后的變換值

(3)查找偽代碼中的關(guān)于Str1的邏輯語句

單機(jī)Str1看到了Str1是一個字符型數(shù)組局部變量,大小為28,經(jīng)歷了一個while中的計(jì)算

代碼中涉及了v4和a1,v4可以看到是一個初始化值為0的整型變量,a1則是一個該函數(shù)的形參,那說明此時(shí)我們要重點(diǎn)尋找a1.

分析循環(huán)體

?while ( *(_DWORD *)(a1 + 4 * v4) < 62 && *(_DWORD *)(a1 + 4 * v4) >= 0 )

? {

??? Str1[v4] = aAbcdefghiabcde[*(_DWORD *)(a1 + 4 * v4)];

??? ++v4;

? }

第二步我提到過Str1變量已經(jīng)可以確定是Flag最后的變換值

查看循環(huán)體內(nèi),其意思便是只要a1 + 4?v4這個地址里面的內(nèi)容小于62并且大于等于0則將a1 + 4?v4地址的值作為aAbcdefghiabcde數(shù)組的下標(biāo),然后將對應(yīng)的aAbcdefghiabcde數(shù)組內(nèi)容賦值給Str1

那么我們?nèi)ゲ榭匆幌耡Abcdefghiabcde數(shù)組的元素是什么?算擊aAbcdefghiabcde數(shù)組名字查看內(nèi)容

原來就是一串字符

此時(shí)分析到這里基本這個函數(shù)就分析完了,我們?nèi)绻^續(xù)分析則必須先找出a1到底是什么?

繼續(xù)通過函數(shù)調(diào)用表找到sub_4017F0(我們改名為Check_Encryption)函數(shù)的調(diào)用者

跟進(jìn)來以后看到了Check_Encryption函數(shù)中的形參就是此時(shí)函數(shù)sub_401890中的一個整型數(shù)組v5的首地址(該數(shù)組大小為26)

那我們此時(shí)就重點(diǎn)跟蹤v5的值了

紅框框住的就是一些mfc組件的代碼,不用管,可以看到,v5的變化初始化和變化來自于Str數(shù)組,

那么Str又是什么呢,仔細(xì)看從上往下第一個箭頭指向的地方GetBuffer函數(shù),這個函數(shù)會返回一個緩沖區(qū)指針,Str來接收了,說明Str很有可能就是我們輸入的password所在的地址,再往GetBuffer下看一行遍看到了一個if語句

判斷Str長度是否為0,也就是判斷是否空,空的話就執(zhí)行了return語句,不為空的話就進(jìn)行了一系列關(guān)于v5和Str的計(jì)算,那么此時(shí)可以直接肯定Str就是我們輸入的字符所在地址

通過代碼又可以看出我們輸入的password存到Str后進(jìn)行了一系列if判斷后計(jì)算賦值給了v5,而v5的值又作為了Check_Encryption函數(shù)的唯一實(shí)參

?if ( strlen(Str) )

? {

??? for ( i = 0; Str[i]; ++i )

??? {

????? if ( Str[i] > 57 || Str[i] < 48 )

????? {

??????? if ( Str[i] > 122 || Str[i] < 97 )

??????? {

????????? if ( Str[i] > 90 || Str[i] < 65 )

??????????? sub_4017B0();

????????? else

??????????? v5[i] = Str[i] - 29;

??????? }

??????? else

??????? {

????????? v5[i] = Str[i] - 87;

? ??????}

????? }

????? else

????? {

??????? v5[i] = Str[i] - 48;

????? }

??? }

??? result = Check_Encryption((int)v5);

? }

? else

? {

??? result = CWnd::MessageBoxA(v8, "請輸入pass!", 0, 0);

? }

(4)梳理大概邏輯

5)我們按照從頭到尾的順序來分析這個程序

既然我們知道了我們輸入的password是被Str指向(可以理解為Str是個字符數(shù)組存了我們輸入的password),那么我們試試是否可以從sub_401890這個函數(shù)推出Str

閱讀代碼,可以得到Str[i]在此時(shí)可以有三種情況,所以此時(shí)我們不可以確定Str的唯一性,也就是我們不可以在這里得到Str(我們輸入的)具體是多少,只能得到范圍,那么就繼續(xù)分析后面一步,跟進(jìn)Check_Encryption函數(shù)

(6)分析Check_Encryption關(guān)鍵代碼

? v4 = 0;

? v3 = 0;

? while ( *(_DWORD *)(a1 + 4 * v4) < 62 && *(_DWORD *)(a1 + 4 * v4) >= 0 )

? {

??? Str1[v4] = aAbcdefghiabcde[*(_DWORD *)(a1 + 4 * v4)];

??? ++v4;

? }

閱讀代碼可知,(_DWORD?)(a1 + 4 * v4)的作用便是遍歷上一個函數(shù)v5的每一個元素,若每一個元素滿足小于62并且大于0的話則將v5對應(yīng)的每一個元素作為aAbcdefghiabcde數(shù)組的下角標(biāo),將對應(yīng)的aAbcdefghiabcde元素賦值給Str1,之前提過Str1是最后的Flag變換結(jié)果

while ( *(_DWORD *)(a1 + 4 * v4) < 62 && *(_DWORD *)(a1 + 4 * v4) >= 0 )

? {

??? Str1[v4] = aAbcdefghiabcde[*(_DWORD *)(a1 + 4 * v4)];

??? ++v4;

? }

? Str1[v4] = 0;

? if ( !strcmp(Str1, "KanXueCTF2019JustForhappy") )

??? result = Tip_Success();

? else

result = sub_4017B0();

作者設(shè)計(jì),如果最后的Flag遍結(jié)果等于“KanXueCTF2019JustForhappy”則提示成功,那由上我們就可以寫腳本得到v5的值

char encryption[] = "KanXueCTF2019JustForhappy";

??????? char text[] = "abcdefghiABCDEFGHIJKLMNjklmn0123456789opqrstuvwxyzOPQRSTUVWXYZ";

??????? for (int i = 0; i <= strlen(encryption); i++)

??????? {

??????????????? for (int j = 0; j <= strlen(text); j++)

??????????????? {

??????????????????????? if (encryption[i] == text[j])

??????????????????????? {

??????????????????????????????? //printf("%d--", j);

??????????????????????????????? v5[i] = j;

??????????????????????? }

??????????????? }

此時(shí)我們既然得到了v5的值那么就可以去分析上一個函數(shù)sub_401890得到Str(我們輸入的password)了

?for ( i = 0; Str[i]; ++i )

??? {

????? if ( Str[i] > 57 || Str[i] < 48 )

????? {

??????? if ( Str[i] > 122 || Str[i] < 97 )

??????? {

????????? if ( Str[i] > 90 || Str[i] < 65 )

??????????? sub_4017B0();

????????? else

??????????? v5[i] = Str[i] - 29;

??????? }

??????? else

??????? {

????????? v5[i] = Str[i] - 87;

??????? }

????? }

????? else

????? {

??????? v5[i] = Str[i] - 48;

????? }

??? }

這個循環(huán)結(jié)構(gòu)就是判斷Strp[i]是否在一個規(guī)定的范圍,通過Str[i]所屬的范圍來進(jìn)行加密或者推=退出程序,因?yàn)関5是Str[i]-常數(shù)得到的,那么我們就可以用v5+常數(shù)來判斷Str[i]的范圍以及確卻數(shù)值了,反推代碼如下,input數(shù)組就是Str(用戶輸入)

for (int i = 0; i <= 26; i++)

??????? {

??????????????? if (48 <= (v5[i] + 48) && (v5[i] + 48) <= 57)

??????????????? {

??????????????????????? input[i] = v5[i]+48;

??????????????? }

??????????????? if (97 <= (v5[i] + 87) && (v5[i] + 87) <= 122)

??????????????? {

??????????????????????? input[i] = v5[i]+87;

??????????????? }

??????????????? if (65 <= (v5[i] + 29) && (v5[i] + 29) <= 90)

??????????????? {

??????????????????????? input[i] = v5[i] + 29;

??????????????? }

??????? }

最后寫出第一輪和第二輪的解密代碼,即可得到flag

#include

#include

int main()

{

??????? int input[26] = { 1 };

??????? int v5[26] = {1};

??????? int Str[26] = { 1 };

??????? char encryption[] = "KanXueCTF2019JustForhappy";

??????? char text[] = "abcdefghiABCDEFGHIJKLMNjklmn0123456789opqrstuvwxyzOPQRSTUVWXYZ";

??????? for (int i = 0; i <= strlen(encryption); i++)

??????? {

?????? ?????????for (int j = 0; j <= strlen(text); j++)

??????????????? {

??????????????????????? if (encryption[i] == text[j])

??????????????????????? {

??????????????????????????????? //printf("%d--", j);

??????????????????????????????? v5[i] = j;

???????????? ???????????}

??????????????? }

??????? }

??????? for (int i = 0; i <= 26; i++)

??????? {

??????????????? if (48 <= (v5[i] + 48) && (v5[i] + 48) <= 57)

??????????????? {

??????????????????????? input[i] = v5[i]+48;

??????????????? }

??????????????? if (97 <= (v5[i] + 87) && (v5[i] + 87) <= 122)

??????????????? {

??????????????????????? input[i] = v5[i]+87;

??????????????? }

??????????????? if (65 <= (v5[i] + 29) && (v5[i] + 29) <= 90)

??????????????? {

??????????????????????? input[i] = v5[i] + 29;

???????? ???????}

??????? }

??????? for (int i = 0; i < 26; i++)

??????? {

??????????????? printf("%c",input[i]);

??????? }

??????? return 0;


算法分析:看雪CTF2019的一道逆向題目的評論 (共 條)

分享到微博請遵守國家法律
乐业县| 和龙市| 日照市| 阿克苏市| 烟台市| 贵南县| 芦溪县| 宜黄县| 陇西县| 樟树市| 出国| 石城县| 浑源县| 墨竹工卡县| 修文县| 米脂县| 花莲县| 商城县| 旺苍县| 京山县| 乌拉特前旗| 资阳市| 九江市| 莒南县| 溆浦县| 婺源县| 奉节县| 抚顺县| 楚雄市| 墨江| 夏邑县| 吴川市| 砚山县| 库伦旗| 云安县| 依安县| 杭州市| 三江| 株洲市| 文安县| 海伦市|