CISCN - rtthread是一个非常新颖的好题
题目中给的是一个 sh 文件和一个类似固件的bin rtthread.bin
CISCN CTF rthread.bin 逆向题

图片.png


运行起来,啥也没有
尝试 ?、help 等,看看会给我们提供什么信息
CISCN CTF rthread.bin 逆向题

图片.png


里面有一些提供的命令,比如 ifconfig,date 等信息
CISCN CTF rthread.bin 逆向题

图片.png


CTF 题目当然就会想要追求 flag,看到最前面的两个命令
CISCN CTF rthread.bin 逆向题

图片.png


可以看到是作者自定义的一个广告位置,真有意思~~~
然后尝试 get_flag 这个命令,得到一个迷宫
CISCN CTF rthread.bin 逆向题

图片.png


如果瞎输入的话,就是会报错的
CISCN CTF rthread.bin 逆向题

图片.png


不是上下左右键的话,就是 WASD 呗(多年来打小霸王游戏机的经验)
合理的猜想就是从 S(Start)点上下左右走到F(Finish)点
很多条可达的路径,通过 Oops 的方式 ban 掉了很多条,当然就只留下来了唯一确定的可行字符串
CISCN CTF rthread.bin 逆向题

图片.png


输入的字符串为:
dddwwawwwwaasdsasawawdwaaasawassssdwdsddssasddw
CISCN CTF rthread.bin 逆向题

图片.png


首先是判断长度,再是判断逻辑
ok,到了这里就需要开始逆向了!
CISCN CTF rthread.bin 逆向题

图片.png


CISCN CTF rthread.bin 逆向题

图片.png


CISCN CTF rthread.bin 逆向题

图片.png


CISCN CTF rthread.bin 逆向题

图片.png


可以发现,字符串是没有交叉引用的
不过既然函数不是很多,可以手动 F5 去看特征
CISCN CTF rthread.bin 逆向题

图片.png


这个是典型的常数值:0x61C88647、0xC6EF3720:典型的 TEA 算法特征
CISCN CTF rthread.bin 逆向题

图片.png


5F4 这个函数是递归,根据输入来处理地图中的迷宫的
CISCN CTF rthread.bin 逆向题

图片.png


可以看到这里的 sub_798 是 sub_5F4 的上层函数
根据 sub_798 的逻辑
CISCN CTF rthread.bin 逆向题

图片.png


第 16 行的 sub_5F4 的 if 语句需要成立
需要执行 sub_988C 函数,然后就双击不进去了,就很艰难
所以,我们换一种思路,从QEMU源码的角度来分析,QEMU是把该二进制文件rebase到了哪里呢?
[Asm] 纯文本查看 复制代码
https://github.com/qemu/qemu[url=https://github.com/qemu/qemu/tree/master/hw/arm]https://github.com/qemu/qemu/tree/master/hw/arm[/url][url=https://github.com/qemu/qemu/blob/master/hw/arm/boot.c]https://github.com/qemu/qemu/blob/master/hw/arm/boot.c[/url][url=https://github.com/qemu/qemu/blob/master/hw/arm/vexpress.c]https://github.com/qemu/qemu/blob/master/hw/arm/vexpress.c[/url]

[Asm] 纯文本查看 复制代码
qemu 中对于 arm 架构的 boot 启动方式[url=https://github.com/qemu/qemu/blob/master/hw/arm/boot.c]https://github.com/qemu/qemu/blob/master/hw/arm/boot.c[/url]Line 1079: /* 32-bit ARM */entry = info->loader_start + KERNEL_LOAD_ADDR;Line 35: #define KERNEL_LOAD_ADDR 0x00010000[url=https://github.com/qemu/qemu/blob/master/hw/arm/vexpress.c]https://github.com/qemu/qemu/blob/master/hw/arm/vexpress.c[/url]Line 339:static VEDBoardInfo a9_daughterboard = {    ……    .loader_start = 0x60000000,    ……};entry = 0x60010000

当没有 entry 的时候,IDA 里的字符串没有交叉引用的
CISCN CTF rthread.bin 逆向题

图片.png


设置 entry
CISCN CTF rthread.bin 逆向题

图片.png


CISCN CTF rthread.bin 逆向题

图片.png


CISCN CTF rthread.bin 逆向题

图片.png


CISCN CTF rthread.bin 逆向题

图片.png


CISCN CTF rthread.bin 逆向题

图片.png


顺着这个流程图,明显就能找到题中的 main 了
CISCN CTF rthread.bin 逆向题

图片.png


CISCN CTF rthread.bin 逆向题

图片.png


length = 0x28 = 40
长度不够,后续添加字符 'a',加上之前的 TEA 算法,就很容易搞明白程序的流程和逻辑了
该函数为输入flag后的程序函数,其首先会对输入的flag进行分组,每组两个int一共5组。
对key进行分组,每组4个int,一共3组。并对flag做5次tea加密。
[C++] 纯文本查看 复制代码
#include <bits/stdc++.h>using namespace std;#define UINT unsigned int#define DELTA 0x9e3779b9void tea_decrypt(UINT* v, UINT* key) {    UINT l = v[0], r = v[1], sum = 0;    sum = DELTA * 32;    for (size_t i = 0; i < 32; i++) {        r -= (((l << 4) ^ (l  5)) + l) ^ (sum + key[(sum  11) & 3]);        sum -= DELTA;        l -= (((r << 4) ^ (r  5)) + r) ^ (sum + key[sum & 3]);    }    v[0] = l;    v[1] = r;}UINT str2int(char* str){    UINT ret = 0;    for (int i = 0; i < 4; i++)        ret += pow(0x100, i) * str[i];    return ret;}void int2str(int num, char* str1){    char ch;    for (int i = 0; i < 4; i++)    {        ch = num & 0xff;        num = num  8;        str1[i] = ch;    }    return;}int main(){    char flag[100] = { 0 }, key[] = "dddwwawwwwaasdsasawawdwaaasawassssdwdsddssasddwa";    UINT keys[12], tea_cry[2], tea_key[4], cry[] = {3179062266, 2936962595, 3754839610, 2425968462, 1458506693, 3303317055, 1294083110, 1674144741, 1029754371, 3863932833};    for (int i = 0; i < 12; i++){        char newkey[4] = { 0 };        memcpy(newkey, key + i * 4, 4);        keys[i] = str2int(newkey);    }    for (int i = 0; i < 5; i++){        tea_cry[0] = cry[i * 2], tea_cry[1] = cry[i * 2 + 1];        for (int j = 0; j < 4; j++)            tea_key[j] = keys[(i * 4 + j) % 12];        tea_decrypt(tea_cry, tea_key);        cry[i * 2] = tea_cry[0], cry[i * 2 + 1] = tea_cry[1];    }    for (int i = 0; i < 10; i++)        cout << "0x" << hex << cry[i]<< " ";    cout << endl;    for (int i = 0; i < 10; i++)        int2str(cry[i], flag + i * 4);    cout << flag << endl;    return 0;}

结果为:
flag{932b424a9-9fe2-42d51-9403e-601db1baa5678}
广告合作:本站广告合作请联系QQ:858582 申请时备注:广告合作(否则不回)
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!