BUUCTF Re部分wp(MIPS特别篇)

mips指令集不同,而且ida F5不支持,分析时把自动注释打开挺好用的

在本文中主要使用了retdec

ida插件:https://github.com/avast-tl/retdec-idaplugin

retdec:  https://github.com/avast-tl/retdec/releases

(这插件没装明白,一直报错,所以我没用。。。)

使用方法

$ retdec-decompiler.sh test.exe

 

[QCTF2018]Xman-babymips

int32_t function_4009a8(void) {
    // 0x4009a8
    setbuf(g6, NULL);
    setbuf(g7, NULL);
    printf("Give me your flag:");
    int32_t str = 0; // bp-44
    scanf("%32s", &str);
    int32_t v1 = 0; // bp-48
    int32_t v2 = 0; // 0x400a58
    char * v3 = (char *)(v2 + (int32_t)&v1 + 4); // 0x400a28
    *v3 = (char)((int32_t)*v3 ^ 32 - v2);
    int32_t v4 = v1 + 1; // 0x400a70
    v1 = v4;
    // branch -> 0x400a1c
    while (v4 < 32) {
        // 0x400a1c
        v2 = v4;
        v3 = (char *)(v2 + (int32_t)&v1 + 4);
        *v3 = (char)((int32_t)*v3 ^ 32 - v2);
        v4 = v1 + 1;
        v1 = v4;
        // continue -> 0x400a1c
    }
    int32_t str2 = *(int32_t *)&g8; // 0x400a90
    int32_t puts_rc;
    if (strncmp((char *)&str, (char *)str2, 5) == 0) {
        // 0x400ab4
        puts_rc = function_4007f0((char *)&str);
        // branch -> 0x400adc
    } else {
        // 0x400acc
        puts_rc = puts("Wrong");
        // branch -> 0x400adc
    }
    // 0x400adc
    return puts_rc;
}
View Code
int32_t function_4007f0(char * a1) {
    int32_t v1 = (int32_t)a1; // 0x400800
    char * str = (char *)v1; // 0x400800
    int32_t puts_rc;
    int32_t str2; // 0x400944
    if (strlen(str) <= 5) {
        // 0x400934
        str2 = *(int32_t *)&g9;
        if (strncmp((char *)(v1 + 5), (char *)str2, 27) == 0) {
            // 0x400964
            puts_rc = puts("Right!");
            // branch -> 0x40098c
        } else {
            // 0x40097c
            puts_rc = puts("Wrong!");
            // branch -> 0x40098c
        }
        // 0x40098c
        return puts_rc;
    }
    int32_t v2 = 5;
    while (true) {
        char * v3 = (char *)(v2 + v1); // 0x4008a8
        int32_t v4 = (int32_t)*v3; // 0x4008a8
        char v5;
        if (v2 % 2 == 0) {
            char v6 = *v3; // 0x4008cc
            v5 = (int32_t)v6 / 64 | 0x4000000 * v4 / 0x1000000;
            // branch -> 0x400900
        } else {
            // 0x400828
            v5 = 64 * (int32_t)*v3 | v4 / 4;
            // branch -> 0x400900
        }
        // 0x400900
        *v3 = v5;
        int32_t v7 = v2 + 1; // 0x400908
        if (v7 >= strlen(str)) {
            // break -> 0x400934
            break;
        }
        v2 = v7;
        // continue -> 0x400814
    }
    // 0x400934
    str2 = *(int32_t *)&g9;
    if (strncmp((char *)(v1 + 5), (char *)str2, 27) == 0) {
        // 0x400964
        puts_rc = puts("Right!");
        // branch -> 0x40098c
    } else {
        // 0x40097c
        puts_rc = puts("Wrong!");
        // branch -> 0x40098c
    }
    // 0x40098c
    return puts_rc;
}
View Code

反编译效果一般,不过比指令好多了。。。

可以分析得到逻辑,用到的数据可结合ida获得

[UTCTF2020]babymips

int main(int argc, char ** argv) {
    // 0x400de8
    int32_t v1; // bp-152
    _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1Ev((int32_t)&v1);
    int32_t v2; // bp-104
    int32_t v3; // bp-128
    function_401164((int32_t)&v2, (int32_t)&v3, 84);
    int32_t v4 = *(int32_t *)g4; // 0x400f40
    return *(int32_t *)g4 == v4 ? 0 : g1;
}

// Address range: 0x401164 - 0x401334
int32_t function_401164(int32_t a1, int32_t a2, int32_t a3) {
    // 0x401164
    if (_ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE4sizeEv(a2) == 78) {
        // 0x4011fc
        if (*(int32_t *)0x4120a0 != 0) {
            int32_t v1 = 0;
            // branch -> 0x40122c
            while (true) {
                char v2 = *(char *)(v1 + a1); // 0x401274
                if (((int32_t)*g3 ^ v1 + 23) != (int32_t)v2) {
                    // 0x401288
                    // branch -> 0x40131c
                    // 0x40131c
                    return g2;
                }
                int32_t v3 = v1 + 1; // 0x4012d0
                if (v3 >= *(int32_t *)0x4120a0) {
                    // break -> 0x4012e0
                    break;
                }
                v1 = v3;
                // continue -> 0x40122c
            }
            // 0x4012e0
            // branch -> 0x40131c
            // 0x40131c
            return g2;
        }
View Code

可以看到是个简单的异或,并且用这段数据比对

a="62 6C 7F 76 7A 7B 66 73 76 50 52 7D 40 54 55 79 40 49 47 4D 74 19 7B 6A 42 0A 4F 52 7D 69 4F 53 0C 64 10 0F  1E 4A 67 03 7C 67 02 6A 31 67 61 37 7A 62 2C 2C  0F 6E 17 00 16 0F 16 0A 6D 62 73 25 39 76 2E 1C  63 78 2B 74 32 16 20 22 44 19"
a=a.split()
for i in range(len(a)):
    print(chr(eval("0x"+a[i])^(i+23)),end="")
#utflag{mips_cpp_gang_5VDm:~`N]ze;)5%vZ=C'C(r#$q=*efD"ZNY_GX>6&sn.wF8$v*mvA@'}

这个flag是我目前见过最丑的了,我一度怀疑自己有什么地方做错了。。。 

[CISCN2018]2ex

这题文件比前几个大,符号表也没有,看着挺困难,先拖进ida

.text:0040020C loc_40020C:                              # CODE XREF: start+4↑j
.text:0040020C                 li      $gp, 0x429EA0    # Load Immediate
.text:00400214                 move    $ra, $zero
.text:00400218                 la      $a0, sub_400788  # Load Address
.text:0040021C                 lw      $a1, arg_0($sp)  # Load Word
.text:00400220                 addiu   $a2, $sp, arg_4  # Add Immediate Unsigned
.text:00400224                 li      $at, 0xFFFFFFF8  # Load Immediate
.text:00400228                 and     $sp, $at         # AND
.text:0040022C                 addiu   $sp, -0x20       # Add Immediate Unsigned
.text:00400230                 la      $a3, sub_400128  # Load Address
.text:00400234                 la      $t0, sub_4101B0  # Load Address
.text:00400238                 sw      $t0, 0x20+var_10($sp)  # Store Word
.text:0040023C                 sw      $v0, 0x20+var_C($sp)  # Store Word
.text:00400240                 sw      $sp, 0x20+var_8($sp)  # Store Word
.text:00400244                 la      $t9, sub_4013D8  # Load Address
.text:00400248                 bal     sub_4013D8       # Branch Always and Link

入口函数用了sub_4013D8,,参数有sub_400788,sub_400128,sub_4101B0

用retdec反编译一下,发现主要应分析sub_400788

int32_t function_400788(void) {
    // 0x400788
    int32_t v1; // bp-80
    g5 = &v1;
    g80 = g27;
    int32_t v2 = 0; // bp-56
    function_400840((char *)&v2);
    int32_t v3; // bp-36
    int32_t v4 = &v3; // 0x4007c0
    g80 = g28;
    function_4010f0(v4, 25);
    function_400430((int32_t)&v2, 17, v4);
    g80 = g29;
    function_4009c0(v4);
    return 0;
}

这里调用了四个函数,运行程序发现,程序获取一个输入后输出密文,所以假设,

function_4009c0(v4)为输出函数,v4为密文

function_400840((char *)&v2)为输入函数,v2为输入

function_400430((int32_t)&v2, 17, v4)为加密函数,v2加密后存在v4里

接下来分析function_400430((int32_t)&v2, 17, v4)

int32_t function_400430(int32_t a1, int32_t a2, int32_t a3) {
    g2 = a2;
    uint32_t v1 = g2; // 0x400440
    int32_t v2 = 0;
    int32_t v3 = -1;
    if (v1 != 0) {
        int32_t v4 = 0; // 0x40061019
        int64_t v5 = 0;
        int32_t v6 = 0;
        // branch -> 0x40045c
        int32_t v7;
        while (true) {
            uint64_t v8 = 0xaaaaaaab * (v5 & 0xffffffff) / 0x200000000; // 0x40047010
            int32_t v9 = v4 - (int32_t)v8 - (int32_t)(2 * v8); // 0x400480
            int32_t v10; // 0x400608
            if (v9 == 1) {
                int32_t v11 = 16 * (int32_t)*(char *)(v4 - 1 + a1) & 48; // 0x400524
                int32_t v12 = (int32_t)(*(char *)(a1 + v4) / 16) | v11; // 0x400544
                char v13 = *(char *)(v12 + (int32_t)"@,.1fgvw#`/2ehux$~"3dity%_;4cjsz^+{5bkrA&=}6alqB*-[70mpC()]89noD/dev/null"); // 0x400554
                *(char *)(v6 + a3) = v13;
                v7 = v6 + 1;
                // branch -> 0x400604
              lab_0x400604_2:
                // 0x400604
                v10 = v4 + 1;
                if (v10 >= v1) {
                    // break -> 0x400610
                    break;
                }
                v4 = v10;
                v5 = v10;
                v6 = v7;
                // continue -> 0x40045c
                continue;
            } else {
                // 0x400498
                v7 = v6;
                switch (v9) {
                    case 2: {
                        int32_t v14 = 4 * (int32_t)*(char *)(v4 - 1 + a1) & 60; // 0x400590
                        g2 = a1;
                        int32_t v15 = (int32_t)(*(char *)(a1 + v4) / 64) | v14; // 0x4005b0
                        char v16 = *(char *)(v15 + (int32_t)"@,.1fgvw#`/2ehux$~"3dity%_;4cjsz^+{5bkrA&=}6alqB*-[70mpC()]89noD/dev/null"); // 0x4005c0
                        *(char *)(v6 + a3) = v16;
                        int32_t v17 = (int32_t)(*(char *)(a1 + v4) % 64); // 0x4005ec
                        char v18 = *(char *)(v17 + (int32_t)"@,.1fgvw#`/2ehux$~"3dity%_;4cjsz^+{5bkrA&=}6alqB*-[70mpC()]89noD/dev/null"); // 0x4005fc
                        *(char *)(a3 + 1 + v6) = v18;
                        v7 = v6 + 2;
                        // branch -> 0x400604
                        goto lab_0x400604_2;
                    }
                    case 0: {
                        int32_t v19 = (int32_t)(*(char *)(a1 + v4) / 4); // 0x4004d0
                        char v20 = *(char *)(v19 + (int32_t)"@,.1fgvw#`/2ehux$~"3dity%_;4cjsz^+{5bkrA&=}6alqB*-[70mpC()]89noD/dev/null"); // 0x4004e8
                        *(char *)(v6 + a3) = v20;
                        v7 = v6 + 1;
                        // branch -> 0x400604
                        goto lab_0x400604_2;
                    }
                }
                // 0x400604
                v10 = v4 + 1;
                if (v10 >= v1) {
                    // break (via goto) -> 0x400610
                    goto lab_0x400610;
                }
                v4 = v10;
                v5 = v10;
                v6 = v7;
                // continue -> 0x40045c
                continue;
            }
        }
      lab_0x400610:
        // 0x400610
        v2 = v7;
        v3 = v1 - 1;
        // branch -> 0x400624
    }
    uint64_t v21 = 0xaaaaaaab * (int64_t)v3 / 0x200000000; // 0x4006442
    int32_t v22 = v3 - ((int32_t)(2 * v21) + (int32_t)v21); // 0x400654
    if (v22 == 0) {
        int32_t v23 = 16 * (int32_t)*(char *)(a1 + v3) & 48; // 0x400688
        char v24 = *(char *)(v23 + (int32_t)"@,.1fgvw#`/2ehux$~"3dity%_;4cjsz^+{5bkrA&=}6alqB*-[70mpC()]89noD/dev/null"); // 0x400698
        *(char *)(v2 + a3) = v24;
        *(char *)(a3 + 1 + v2) = 61;
        g82 = 61;
        *(char *)(a3 + 2 + v2) = 61;
        // branch -> 0x400770
    } else {
        // 0x4006e0
        g82 = v22;
        if (v22 == 1) {
            int32_t v25 = 4 * (int32_t)*(char *)(a1 + v3) & 60; // 0x40073c
            char v26 = *(char *)(v25 + (int32_t)"@,.1fgvw#`/2ehux$~"3dity%_;4cjsz^+{5bkrA&=}6alqB*-[70mpC()]89noD/dev/null"); // 0x40074c
            *(char *)(v2 + a3) = v26;
            g82 = 61;
            *(char *)(a3 + 1 + v2) = 61;
            // branch -> 0x400770
        }
    }
    // 0x400770
    return 0;
}

可以看出来就是个换表base64

import base64

c="│_r-+_Cl5;vgq_pdme7#7eC0="
flag=""

table="@,.1fgvw#`/2ehux$~"3dity%_;4cjsz^+{5bkrA&=}6alqB*-[70mpC()]89noD"
table2="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
for i in c:
    for j in range(len(table)):
        if i==table[j]:
            flag+=table2[j]

flag=base64.b64decode(flag)
print(flag)
原文地址:https://www.cnblogs.com/harmonica11/p/13395639.html