攻防世界-REVERSE新手練習 解題思路


逆向工具下載

題一.open-source

原題:

難度系數: ★★★
題目來源: HackYou CTF
題目描述: 菜雞學逆向學得頭皮發麻,終於它拿到了一段源代碼
題目場景: 暫無
題目附件: 附件1
原題鏈接

解題思路

打開源碼就可以看見主函數一運行就是一個判斷。

if (argc != 4) {
    printf("what?\n");
    exit(1);
}


但是可以看到,argc這個變量只在第一次判斷的時候被調用了,所以直接把這個判斷去掉也能順利運行。

繼續往下看第二個判斷:

unsigned int first = atoi(argv[1]);
if (first != 0xcafe)
{
    printf("you are wrong, sorry.\n");
    exit(2);
}

如果first不等於0xcafe就退出,直接倒着推first是0xcafe就繼續執行。所以first的值是0xcafe

繼續往下看

unsigned int second = atoi(argv[2]);
if (second % 5 == 3 || second % 17 != 8) {
    printf("ha, you won't get it!\n");
    exit(3);
}

還是一樣,根據他的判斷來倒着推出式子。

for(int second{0};true;++second)
    if((second % 5 != 3) && (second % 17 == 8))
    {
        std::cout << second;
        break;
    }

執行完之后得到我們的second為25

接着看最后一個判斷

if (strcmp("h4cky0u", argv[3])) {
    printf("so close, dude!\n");
    exit(4);
}

strcmp函數字符串比較,用於比較兩個字符串並根據比較結果返回整數。基本形式為strcmp(str1,str2),若str1=str2,則返回零;若str1<str2,則返回負數;若str1>str2,則返回正數。
所以得到結果argv[3]就是"h4cky0u"。

最后我們把我們得到的值套進公式里面進行計算。

#include <iostream>
int main()
{
    unsigned int first = 0xcafe;
    unsigned int second = 25;
    char* argv[0xff];
    argv[3] = "h4cky0u";
    unsigned int hash = first * 31337 + (second % 17) * 11 + strlen(argv[3]) - 1615810207;
    printf("%x\n", hash);
}

flag:c0ffee


題二.simple-unpack

原題:

難度系數: ★★★
題目來源: 暫無
題目描述: 菜雞拿到了一個被加殼的二進制文件
題目場景: 暫無
題目附件:附件1
原題地址

解題思路

下載好后附件拖入Exeinfo_PE查看,得知這是一個Linux下的二進制文件。

注:Windows下的文件是PE文件,Linux/Unix下的文件是ELF文件。

它不僅是一個ELF文件他還被PUX進行了加殼,那我們現在就用UPX進行脫殼,進入軟件路徑后使用脫殼指令給附件解密。

upx -d X

這個X就是我們需要脫殼的程序
前去GitHub下載UPX(UPX自帶解密):UPX下載地址

OK解密之后就直接拖入IDA進行查看.flag直接出現在我們面前

flag:flag{Upx_1s_n0t_a_d3liv3r_c0mp4ny}


題三.logmein

原題:

難度系數: ★★★
題目來源: RC3 CTF 2016
題目描述: 菜雞開始接觸一些基本的算法逆向了
題目場景: 暫無
題目附件:附件1
原題地址

解題思路

還是和上一題一樣。下載附件然后拖入Exeinfo_PE查看,得知這又是一個Linux下的二進制文件。

但是它這次沒有加密,還算是簡單。
直接拖入IDA進行查看一下。

稍微翻譯一下英文就看到了“You entered the correct password!Great job!”這一句。我們直接點進去找到關鍵函數。

找到函數后雙擊進去,按下F5查看偽函數。


分析完之后按下X鍵,查看交叉引用。看看都有誰使用了這個函數,然后直接雙擊跳到使用的地方。

OK跳過來之后發現這里就是主函數,算法部分貌似也是寫在了主函數里面。

大概看了下他主函數的內容。
最主要的判斷就是最后一個v7 v6 v8三個變量的異或。

if(s[i]!= (char)(*((_BYTE *)&v7 + i % v6) ^ v8[i]) )

只要把三個變量用循環異或一下得到的值就是我們想要的flag

#include <iostream>
#include <string.h>
#define BYTE char
int main()
{
    std::string key1 = ":\"AL_RT^L*.?+6/46";
    __int64 key2 = 28537194573619560;
    int key3 = 7;
    char Flag[0xff]{};
    for (size_t i = 0; i < key1.length(); i++)
    {
        Flag[i] = (char)(*((BYTE*)&key2 + i % key3) ^ key1[i]);
    }
    std::cout << Flag;
}

flag:RC3-2016-XORISGUD


題四.insanity

原題

難度系數: ★★★
題目來源: 9447 CTF 2014
題目描述: 菜雞覺得前面的題目太難了,來個簡單的緩一下
題目場景: 暫無
題目附件: 附件1
原題地址

解題思路

還是一樣下載附件直接拖入查殼軟件查殼。發現是一個32位的ELF文件。

那沒辦法OD不能用只能拖入IDA查看了。

拖入IDA發現直接就有主函數的入口。直接雙擊之后F5查看偽函數。

然后發現這個函數是輸出的這個字符串。猜測和flag有關聯,雙擊進去之后發現 flag就直接出現在我們的面前了。

一開始還以為只有{}內的字符是flag哪知道9447也是flag

flag:9447{This_is_a_flag}


題五.python-trade

原題

難度系數: ★★★
題目來源: NJUPT CTF 2017
題目描述: 菜雞和菜貓進行了一場Py交易
題目場景: 暫無
題目附件: 附件1
原題地址

解題思路

附件下載下來之后發現是一個.pyc的的文件

注:pyc文件是py文件編譯后生成的字節碼文件。
我們直接利用Py在線反編譯工具進行代碼還原。
以下就是反編譯后代碼

import base64
def encode(message):
    s = ''
    for i in message:
        x = ord(i) ^ 32
        x = x + 16
        s += chr(x)
    return base64.b64encode(s)

correct = 'XlNkVmtUI1MgXWBZXCFeKY+AaXNt'
flag = ''
print 'Input flag:'
flag = raw_input()
if encode(flag) == correct:
    print 'correct'
else:
    print 'wrong'

看了下大概流程就是輸入一段字符然后進行加密,看加密過后是不是等於內置的字符串。
那直接拿它內置的字符串進行解密就可以得到他的flag了。
再看一下他加密函數的流程。先給字符串拆分成數組進行循環ord函數是字符轉ascll碼,然后和32異或。接着加上16,然后把每個元素進行拼接。最后字符串進行base64加密。
那首先我們把內置碼進行base64解密。
然后給他拆分成數組然后-16之后^32 然后給它合並成字符串。

#include <iostream>
#include <string>
using namespace std;
int main()
{
    string Nei_Code{ "^SdVkT#S ]`Y\!^)ism" };
    string Flag{};
    for ( int i = 0; i < Nei_Code.length(); i++)
    {
        Flag += (char)(Nei_Code[i] - 16) ^ 32;
    }
    cout << Flag;
}

運行之后得到我們的Flag

flag:nctf{d3c0mpi1n9yC}


題六.game

原題

難度系數: ★★★★
題目來源: ZSCTF
題目描述: 菜雞最近迷上了玩游戲,但它總是贏不了,你可以幫他獲勝嗎
題目場景: 暫無
題目附件: 附件1
原題地址

解題思路

下載附件之后直接進行查殼。終於是來了一個可執行文件了。

無殼,直接拖OD看看吧。

運行之后發現題目邀請是讓我把所有燈全部點亮,但是在點亮這個燈的時候會把旁邊兩個燈的狀態取反。
先拿OD看看字符串之類的。

看到了貌似很關鍵的地方。雙擊進去看看。

進來之后發現這個字符串下面有很長的一段十六進制數。那這肯定就是要找到flag了,但是它太長了一個一個轉換過來太麻煩。想個辦法讓他執行起來,來到函數頭,發現是一個很長的跳轉。

這就很明顯了,它這個程序的函數都是使用長跳轉進的函數。我們只要找到它會執行的一個函數把他的jmp的地址改成這個函數的地址就行了。

有點像我們要找的地方,點進去看看之后確實是一個函數,然后去函數頭部給移動到它跳轉的地址。給他改成jmp 00E2E940



OK 隨便輸入一個數看看效果。flag直接出現了。

flag:zsctf{T9is_tOpic_1s_v5ry_int7resting_b6t_others_are_n0t}


題七.Hello, CTF

原題

難度系數: ★★★★
題目來源: Pediy CTF 2018
題目描述: 菜雞發現Flag似乎並不一定是明文比較的
題目場景: 暫無
題目附件: 附件1
原題地址

解題思路

還是一樣下載完附件之后先查殼。

無殼,可執行文件先拖OD查字符串看看。能夠很明顯看見一個成功,一個錯誤,直接點進去看看。

然后發現並沒有什么可以得到它flag的地方,現在再拖IDA看看的判斷算法。

注:因為弄算法IDA比OD方便很多。


拖入IDA之后發現一段很奇怪的數據,看偽函數如何給他進行解密。

從圖中可以看出來,它把這段數據復制給了v13這個變量
然后,又對輸入進行了判斷,輸入的字符串不能大於0x11
接着,將字符串以十六進制輸出
然后,再將得到的十六進制字符添加到v10
最后,進行比較,看輸入的字符串是否和v10的字符串相等,如果相等,則得到真確的flag。
那直接把內置的16進制碼轉成字符就得到想要的flag了

flag:CrackMeJustForFun


題八.getit

原題

難度系數: ★★★★
題目來源: SharifCTF 2016
題目描述: 菜雞發現這個程序偷偷摸摸在自己的機器上搞事情,它決定一探究竟
題目場景: 暫無
題目附件: 附件1
原題地址

解題思路

下載完附件之后,進行查殼。發現是一個Linux下的64位文件

拖進IDA,看看為偽代碼。

它首先是判斷v5的大小是不是小於s的長度。

然后再進行一個運算將flag寫入到“/tmp/flag.txt”文件里面。所以他的算法就是要的flag。然后我們直接寫一遍運行一下就得到了flag

#include <iostream>
#include <string>
#include <windows.h>
using namespace std;
int main()
{
    string s = "c61b68366edeb7bdce3c6820314b7498";
    DWORD v5 = 0;
    char v3;
    string flag{};
    while ( v5<s.length())
    {
        if (v5&1) v3 = 1;
        else v3 = -1;
        flag += (char)((int)(s[v5]) + v3);
        v5++;
    }
    cout << flag;
}

但是它前面還有一個變量t
我們還得看看t是什么東西。

大概已經猜想到他的flag是什么了。

flag:SharifCTF{b70c59275fcfa8aebf2d5911223c6589}


題九.re1

原題

難度系數: ★★★★★
題目來源: DUTCTF
題目描述: 菜雞開始學習逆向工程,首先是最簡單的題目
題目場景: 暫無
題目附件: 附件1
原題地址

解題思路

下載完附件之后,進行查殼。發現是一個無殼的可執行文件

直接上OD運行

入口的,但是進去之后發現要逆算法,還是進IDA看。
拖入IDA找到主函數按F5

我們雙擊進去之后,這一看就是一個字符串。直接按R鍵轉換成字符。

把兩個字符合並之后就是要找的一個flag

注:這里要跟大家普及一個知識了,及大端與小端
假設一個十六進制數0x12345678
大端的存儲方式是:12,34,56,78,然后讀取的時候也是從前往后讀
小端的存儲方式是:78,56,34,12,然后讀取的時候是從后往前讀取
所以,最后的flag應該是:DUTCTF{We1c0met0DUTCTF}


題十.no-strings-attached

原題

難度系數: ★★★★★
題目來源: 9447 CTF 2014
題目描述: 菜雞聽說有的程序運行就能拿Flag?
題目場景: 暫無
題目附件: 附件1
原題地址

解題思路

下載完附件之后,進行查殼。發現是一個無殼Linux下的32位文件

直接進IDA,找到主函數,按F5查看它的一個偽代碼

這主函數里面就這么幾個函數,分別進入函數分析,發現banner是輸出程序提示信息的,prompt_authentication是程
序提示我們輸入authentication details。
而authenticate則是通過比較輸入與decrypt解密后得到的字符串是否相等判斷是否通過驗證。這說明flag就是decrypt(&s, &byte_8048A90)得到的字符串。
進入這個函數分析一下邏輯

分析它的邏輯后發現,它先把參數s復制給dest,然后把dest的每個值減去a2的值
然后返回加密后的dest,再在上級調用函數里與輸入的字符串進行比較,相同則提示Success!不相同則提示Access denied!
然后我們把兩個參數的值取出來。雙擊參數,選中按shift+e。

注意:兩個參數的類型都是 wchar_t 類型(長度 16 位或 32 位,本機 32 位,4 字節) 由於有大量的 0,所以不能用 char 類型的數組,否則讀到第三位直接結束。此外,刪除后面 4 個字節的 0,因為字符串的結尾默認加 0。

然后我們把代碼寫出來

#include <iostream>
using namespace std;
int main()
{
    wchar_t a[] =
    {
        0x1401,0x1402,0x1403,0x1404,0x1405
    };
    wchar_t dest[] =
    {
      0x143a,0x1436,0x1437,0x143b,0x1480,
      0x147a,0x1471,0x1478,0x1463,0x1466,
      0x1473,0x1467,0x1462,0x1465,0x1473,
      0x1460,0x146b,0x1471,0x1478,0x146a,
      0x1473,0x1470,0x1464,0x1478,0x146e,
      0x1470,0x1470,0x1464,0x1470,0x1464,
      0x146e,0x147b,0x1476,0x1478,0x146a,
      0x1473,0x147b,0x1480,0x0
    };
    int v4{};
    for (int i = 0, j = 0; i < wcslen(dest); i++)
    { 
        dest[i] -= a[j++];
        j = j < 5 ? j : 0;
    }
    wprintf(dest);
}

然后計算出想要的flag

flag:9447{you_are_an_international_mystery}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM