QCTF - re -babyre(Rust逆向)

前言

这是一个Rust语言编写的程序,之前也没有接触过这种语言,一时确实无从下手,因此我也将此题分析放到了最后。为了更好的了解Rust编程以及逆向,先尝试使用Rust编写一个helloworld。所以我在自己的电脑上搭建的Rust编译环境。

Rust环境搭建与测试

官网
在网上找了好久才找到一些Rust的编程示例,这好像是最近兴起的类C的语言。
gitbook上有其第一版的程序设计指导。
因此我使用Rust编写如下代码,并且编译运行。

fn main(){
println!("Hello,world!");
}

编译 rustc hello.rs
说实话编译完了吓一跳,程序居然有5.5Mb
将生成的程序丢到IDA中,23333,表示想哭,连最简单的hellworld都看不懂了,而且我这还没去除符号表。

QCTF - re -babyre(Rust逆向)_第1张图片
看来这Rust作为最安全的编程语言是有道理的。
这里写图片描述
其中第一个很长的main才是真正的主函数
接着尝试加入简单判断的程序,代码如下:

fn main() {
    println!("Guess the number!");
let x =5;
if x == 5 {
    println!("x is five!");
} else {
    println!("x is not five :(");
}
}

丢到IDA中,实在是看不下去了。有点无奈了。
QCTF - re -babyre(Rust逆向)_第2张图片
其实冷静下来分析一下,虽然Rust的API有变化,但是代码块与代码块之间的关系并没有发生变化,所以还是头铁。

分析题目

0x0

大概了解了一下Rust编程,接下来还是老老实实的分析题目代码。首先定位到main函数。试图寻找cmp指令。幸运的是找到了cmp rax ,32并且看到了分支.
QCTF - re -babyre(Rust逆向)_第3张图片
所以可以确定flag的长度为32位,F5失效了。静态看确实看不出来,所以动态调试一番.

0x01

第一次变化,以四个为一组进行0 = 2;1 = 0;2 = 3;3 = 1变换
QCTF - re -babyre(Rust逆向)_第4张图片

0x02

第二次变化,这里需要仔细的去看下输入是如何变化的。说白了就是在找规律
QCTF - re -babyre(Rust逆向)_第5张图片

 63 61 64 62 67 65 68 66  6B 69 6C 6A 6F 6D 70 6E  cadbgehfkiljompn
 73 71 74 72 77 75 78 76  41 79 42 7A 45 43 46 44  sqtrwuxvAyBzECFD

 6A 73 BC E3 6E 77 C0 E7  72 7B C4 EB 76 7F C8 EF  js......r{..v...
 7A 83 CC F3 7E 87 D0 F7  48 8B 9A FB 4C 55 9E C5  z...~...H...LU..

E3 6E 77 C0E7 72 7B C4,相差4,略微思考一下,猜测出这个函数的功能是从a[3]开始每四位加上固定的值。
继续往下看。

0x03

第三次变换!
QCTF - re -babyre(Rust逆向)_第6张图片

53 DC 79 3E 73 DD 81 7E  93 DE 89 BE B3 DF 91 FE  S..>s݁ ~.މ ..ߑ .
D3 E0 99 3F F3 E1 A1 7F  42 E2 35 BF 62 55 3D 5C  ...?....B...bU=\

6A 73 BC E3 6E 77 C0 E7  72 7B C4 EB 76 7F C8 EF  js......r{..v...
7A 83 CC F3 7E 87 D0 F7  48 8B 9A FB 4C 55 9E C5  z...~...H...LU..

可以看到3E 3F变成了E3 F3,每四位有着同样的规律,并且每四个为一组,各组的第一位应该相差4.
便可以得到如下对应:

73 BC E3 6E  -> DC 79 3E 73
77 C0 E7 72  -> DD 81 7E 93
7B C4 EB 76  -> DE 89 BE B3

各组中相同位上的值应该是经过同样的变换。仅从16进制观察比较困难,因此转化为二进制观察每一bit的变化,当然看出这个函数功能的方法有多种,还可以通过IDA,F5识别,虽然代码看着很乱,但是整体的功能已经猜测出来了,下面就是找具体的变换了,还可以将所有字符手动的过一遍sub_55F7C8B3B300得出转化表也是可行的一种思路。
QCTF - re -babyre(Rust逆向)_第7张图片
结合IDA,并且猜测验证一番,得出此函数功能。

    print (0x73 >> 2 | 0x73 <<6)%256    
    print (0xbc >> 7 | 0xbc <<1)%256
    print (0xe3 >> 4 | 0xe3 <<4)%256
    print (0x6e >> 5 | 0x6e <<3)%256

了解到大致规律后,最后一位的变化就猜测了一下。

0x04

继续往下走sub_55F7C8B3BF50函数中找到一组数据,并且出现了分支,一般照着题目的套路,肯定会和一个固定数组进行比较,因此我们将数据提取出,结合以上的分析,写出脚本。
完整代码:

from libnum import n2s, s2n
import string
cm = [0xDA, 0xD8, 0x3D, 0x4C, 0xE3, 0x63, 0x97, 0x3D,
      0xC1, 0x91, 0x97, 0x0E, 0xE3, 0x5C, 0x8D, 0x7E,
      0x5B, 0x91, 0x6F, 0xFE, 0xDB, 0xD0, 0x17, 0xFE,
      0xD3, 0x21, 0x99, 0x4B, 0x73, 0xD0, 0xAB, 0xFE]


def test():
    print (0x73 >> 2 | 0x73 << 6) % 256
    print (0xbc >> 7 | 0xbc << 1) % 256
    print (0xe3 >> 4 | 0xe3 << 4) % 256
    print (0x6e >> 5 | 0x6e << 3) % 256


def change3():
    re = []
    for i in range(32):
        for j in range(256):
            if i % 4 == 1 and ((j >> 2 | j << 6) % 256 == cm[i]):
                re.append(j)
            elif i % 4 == 2 and ((j >> 7 | j << 1) % 256 == cm[i]):
                re.append(j)
            elif i % 4 == 3 and ((j >> 4 | j << 4) % 256 == cm[i]):
                re.append(j)
            elif i % 4 == 0 and ((j >> 5 | j << 3) % 256 == cm[i]):
                re.append(j)
    print re
    return re


def change2(in3):
    re = []
    for i in range(32):
        if i % 4 == 1:
            re.append(in3[i] - 18)
        elif i % 4 == 2:
            re.append(in3[i] - 88)
        elif i % 4 == 3:
            re.append(in3[i] - 129)
        elif i % 4 == 0:
            re.append(in3[i] - 7)
    print re
    return re


def change1(in2):
    re = []
    for i in range(32):
        if i % 4 == 1:
            re.append(chr(in2[i + 2]))
        elif i % 4 == 2:
            re.append(chr(in2[i - 2]))
        elif i % 4 == 3:
            re.append(chr(in2[i - 1]))
        elif i % 4 == 0:
            re.append(chr(in2[i + 1]))
    print re
    return re


def main():
    # test()
    c3 = change3()
    c2 = change2(c3)
    c1 = change1(c2)
    print "".join(c1)


if __name__ == '__main__':
    main()

总结

至此,QCTF的re总算是分析完了,题目不算难,选择合适的方法进行合理的猜测,可以更快的找到正确的答案

你可能感兴趣的:(CTF,Re)