bugku逆向(Easy_Re):使用retdec解题思路

对了, 我写的东西一般会比较放飞自我, 如果要严谨学习的话最好就别参考我的writeup了, 毕竟编程这种东西我懂不了一点.

介绍

flag格式:DUTCTF{xxxx}

使用工具

retdec

blackarch不知道是什么原因配置不上retdec,最后还是直接在github下载,不得不说这是个很强大的反编译工具,相比r2确实能少死很多脑细胞.(当然retdec也存在自己的问题,之前打codegate时电脑差点原地爆炸)

配置方法

主要使用的是retdec-decompiler工具(linux环境下,windows可能会在后面多一个.exe),二进制文件可在gitee获取,希望大家可以顺便关照以下我自己的仓库,我自己也写过一些有意思的东西,能给点star就更好了.

使用

可以通过官方wiki学习相关的使用教程. 我还在缓慢翻译部分文档, 其中可以注意一下Decompiler-outputs文件, 这里我只针对要用到的进行引用:

  • input.exe.c: The decompiled C code. This is the main output.
  • input.exe.ll: Human-readable disassembly of LLVM bitcode in the LLVM IR format.

然后是个人的随缘翻译:

  • input.exe.c:反编译的C代码, 这是反编译的核心文件
  • input.exe.ll:用人能看懂的方式反编译LLVM中间码

程序

> retdec re
> ls
re  re.bc  re.c  re.config.json  re.dsm  re.ll

本次主要观察re.cre.ll文件:

re.c

主要观察的反编译文件,好像有人测试过可以用gcc强制运行部分反编译过的文件.主要内容如下:

在全局变量中定义g1, g2两组字符串,还有g3, g4两个整形变量

// --------------------- Global Variables ---------------------

char * g1 = "\xd5\xe2\xca\xc7\xd2\xbb\xb5\xc0\xba\xdc\xbf\xc9\xb0\xae\xba\xdc\xbc\xf2\xb5\xa5\xb5\xc4\xc4\xe6\xcf\xf2\xcc\xe2\xdf\xcf\n"; // 0x413e60
char * g2 = "\xca\xe4\xc8\xeb\x66lag\xb0\xc9:"; // 0x413e80
int32_t g3 = 0x67616c66; // 0x413e90
int32_t g4 = 0x67616c66; // 0x413e9c

进入主函数, 使用__asm_movdqu_2和__asm_movq_3等汇编指令初始化变量,

// ------------------------ Functions -------------------------

// Address range: 0x401000 - 0x4010c2
int main(int argc, char ** argv) {
    int32_t v1 = __asm_movdqu_2(__asm_movdqu(0x3074656d30633165577b465443545544)); // bp-72, 0x40101f
    int64_t v2; // 0x401000
    __asm_movq_3(v2, __asm_movq(0x7d465443545544));

打印g1、g2, 将输入值赋予v3 -> v4, v1-> v5, v6赋予v5指针, g4地址指针什么v7阿巴阿巴, 这些乱七八糟的不想理了, 差不多知道大概意思就好.

    _printf(NULL);
    _printf((char *)&g1);
    _printf((char *)&g2);
    int32_t v3; // bp-40, 0x401000
    _scanf("%s", &v3);
    int32_t v4 = &v3; // 0x401065
    int32_t v5 = &v1; // 0x401065
    char v6 = *(char *)v5; // 0x401068
    char * v7 = (char *)&g4; // 0x40106c

快乐while循环, 如果v6(即v5指向的字符) 等于v4循环, 反之break. 将v7设为g3, 判断v6是否为0, 是则跳出循环;接着获取v5和v4后一个字符, 将其赋值给v8, 再次将v7设为g4;最后判断v8是否等于v4后一个字符,如果不相等则跳出循环。 人话就是让输入的v3(v4)等于v6(v1).

    while (v6 == *(char *)v4) {
        // 0x40106e
        v7 = (char *)&g3;
        if (v6 == 0) {
            // break -> 0x40108d
        }
        char v8 = *(char *)(v5 | 1); // 0x401072
        v7 = (char *)&g4;
        if (v8 != *(char *)(v4 || 1)) {
            // break -> 0x40108d
            break;
        }
        // 0x40107a
        v4 += 2;
        v5 += 2;
        v7 = (char *)&g3;
        if (v8 == 0) {
            // break -> 0x40108d
            break;
        }
        v6 = *(char *)v5;
        v7 = (char *)&g4;
    }

输出v7指向的地址,并调用_system函数使程序暂停。

    // 0x40108d
    _printf(v7);
    _system("pause");
    return ___report_gsfailure();
}

小插曲

其实如果有了解radare2的话可以试试用如下指令查看汇编指令, arch系用户可直接通过sudo pacman -S radare2进行安装使用:

> r2 re
[0x004014a5]> aa
INFO: Analyze all flags starting with sym. and entry0 (aa)
INFO: Analyze all functions arguments/locals (afva@@@F)
[0x004014a5]> afl
0x004014a5   23    304 entry0
0x00401000   11    194 main
[0x004014a5]> pdc @ main

可以发现其实已经有指向我们要找的关键词DUTCTF大概在0x413e44位置了. 详细不过多介绍, 感兴趣可以自己试着折腾一下.

re.ll

现在来re.ll文件找while循环到底判定了个什么, 答案很明显在第2行, 不过从个人角度还是想安利一下vim编辑器, 打开快, 编写容易, 只需要一点学习成本, 便可以让自己在未来的很多内容中省掉很多不必要的操作. 由题目已知格式为BUTCTF{},在vim编辑器下可以使用:/BUTCTF直接定位到所在行.

@global_var_415000 = local_unnamed_addr global i32 -1153374642
@global_var_413e34 = local_unnamed_addr constant [24 x i8] c"DUTCTF{We1c0met0DUTCTF}\00"
@global_var_413e44 = local_unnamed_addr constant [8 x i8] c"DUTCTF}\00"
@global_var_413e8c = constant [3 x i8] c"%s\00"
@global_var_413e90 = constant i32 1734437990
@global_var_413e9c = constant i32 1734437990
......
!21 = !{i64 4198528}
!22 = !{i64 4198530}
!23 = !{i64 4198557}
!24 = !{i64 4198570}
!25 = !{i64 4198585}
!26 = !{i64 4198593}

回代

打开程序, 是个用来给我们检验flag的小程序, 把拿到的flag带进去试试:

reverse·llvm·c
220 views
Comments
登录后评论
Sign In
·

打完韩赛以后又只剩下我一个孤寡队长了, 强网杯只剩我自己报名. sakana战队尝试招一波同好, 战队介绍: 底层战队,坚持报名,看完题目就跑路

·

我是笨蛋,gitee上传后需要在设置重新选择开源,现在给的网址已经可以正常访问了