悬镜安全丨XNUCA逆向赛WRITEUP

阅读(576)

8月27日,Xmirror战队代表PKU参加XNUCA高校网安联赛逆向赛,经过团队小伙伴12小时的努力,最终以第三名成绩晋级决赛。下面是比赛Writeup。

ezpz

查看check函数,发现直接是base64编码内置的字符串,提取字符串base64解码即可。

indirect

逆向分析之后,算法就是将key的每一个字符拆成两个数字,然后和内置字符串运算,运算就是异或,再加减index,最终写出解密脚本,如下图所示:

    s1='\x40\x6a\x6b\x63\x75\x6c\x77\x79\x77\x6f\x81\x79\x74\x7a\x30'
    s2='\x72\x65\x74\x73\x74\x24\x79\x67\x5e\x5e\x66\x5c\x17\x6a\x65'

    sor='sorry,please try again!'
    con='Congratulation! you got a right flag!'

    ls1=[]
    ls2=[]
    result=[]

    for i in xrange(0,0xf):
        ls1.append((ord(s2[i])+i)^ord(sor[i]))
        ls2.append((ord(s1[i])-i)^ord(con[i]))
    
        result.append(chr(ls2[i]*16+ls1[i]))


    print ls1
    print ls2

    print ''.join(result)
    #1itt1e_r3v3rs31

Schrodinger’s Debug

算法和第三题差不多,但是需要输入两次key,进入到真正的计算流程里。和上一题的区别是绕过反调试和寻找*(dword_4413c+1)+12的值。这个关键的全局变量在反调试部分不断的计算和赋值。反调试在一个线程里做的,为了拿到这个值,不能粗暴的去掉反调试线程,一步步调试并绕过反调获取到这个关键的数值。但这里我拿到的数值总不正确,算出来的flag不对。最后只好开脑洞,自己计算,因为最后比较的数值都为0xCx,而最终结果要都为小于15的数字,才能组合为ASCII,所以这个数值只能为0xCx,把所有0xCx的结果跑一遍,得到0xC3为正确的值,拿到flag。

解密脚本如下所示:

    s3='\xc3\xc3\xce\xc4\xc6\xca\xc5\xd0\xc7\xc3\xc4\xcf\xca\xc3\xc4\xc9\xc7\x00'
    s4='\xc5\xc4\xc6\xc3\xbf\xc4\xbf\xc4\xc4\xbf\xc3\xc5\xc6\xbf\xc4\xc5\xc4\x00'

    ls3=[]
    ls4=[]

    result=[]

    for i in xrange(0,17):
    
        ls3.append((ord(s3[i])-3)^0xc3)
        ls4.append((ord(s4[i])+1)^0xc3)

    print ls3
    print ls4

    for i in xrange(0,17):
        result.append(chr(ls4[i]*16+ls3[i]))

    print ''.join(result)
    #ScHr0d1ng3r_D3bUg

BabyAndroid

APK程序通过check(password)函数对输入的密码进行一系列异或操作后,判断结果是否与用户名“x-nuca2016”相等,如果相等则输入的密码即为flag,解密代码如下。

    #!/usr/bin/python
    username = "x-nuca2016"
    lllll=len(username)
    aaaaa=[13, 9, 6, 9, 93, 1, 14, 84, 9, 14, 6, 91, 10, 5, 89, 6, 28, 23, 69, 65]
    flag = ""
    b= []
    for i in xrange(lllll):
        c=ord(username[i])-(lllll-i)*3
        h=c/10
        l=c%10
        h+=48
        l+=48
        h = h ^ aaaaa[2*i] ^ (2*i)

        l = l ^ aaaaa[2*i+1] ^ (2*i+1)
    flag += chr(h) + chr(l)
    print flag

解出flag:4852a21e964b50d085bc

Babyfuscator

Babyfuscator是个ELF的程序,反汇编后发现代码做了一些简单的混淆:

代码逻辑是对输入的32位flag字符串按字节进行表达式检测,32个字节的检测规则分别如下所示:

    (((((((((((((flag[0] ^ 0x10) + 10) ^ 0x12) + 1) ^ 0x1B) + 6) ^ 0x39) + 8) ^ 0x29) + 8) ^ 0x3B) + 4) ^ 0xA) == 0xD8
    (((((((((((((flag[1] ^ 5) + 10) ^ 0x16) + 8) ^ 0x2F) + 9) ^ 0x32) + 10) ^ 0xB) + 6) ^ 0x2B) + 6) ^ 6) == 132
    (((((((((((((flag[2] ^ 0x26) + 10) ^ 0x14) + 7) ^ 7) + 7) ^ 9) + 5) ^ 0x3D) + 6) ^ 0x31) + 5) ^ 0xC) == 40
    (((((((((((flag[3] ^ 0x2F) + 5) ^ 0x29) + 10) ^ 0x27) + 6) ^ 0x31) + 9) ^ 0x26) + 8) ^ 0x32) == 12
    (((((((((((flag[4] ^ 0x1F) + 9) ^ 0x21) + 4) ^ 0x27) + 9) ^ 0x2D) + 7) ^ 0x19) + 9) ^ 0x39) == 52
    ((((((((((((flag[5] + 9) ^ 0x26) + 9) ^ 0x10) + 4) ^ 0x32) + 1) ^ 5) + 1) ^ 0xA) + 7) ^ 0x12) == 94
    (((((((((((flag[6] ^ 0x17) + 6) ^ 0x27) + 1) ^ 0x26) + 6) ^ 1) + 2) ^ 0x16) + 7) ^ 0x1C) == 45 
    ((((((((((((flag[7] ^ 0x1A) + 8) ^ 9) + 3) ^ 0x25) + 4) ^ 0x30) + 7) ^ 0x24) + 5) ^ 0x2F) ^ 0x2B) == 79
    (((((((((((((flag[8] ^ 0xC) + 1) ^ 0x34) + 1) ^ 6) + 8) ^ 0x27) + 8) ^ 0x3B) + 2) ^ 0x23) + 3) ^ 0x16) == 76
    (((((((((((((flag[9] ^ 0xA) + 4) ^ 0x3D) + 10) ^ 0x37) + 1) ^ 0x19) + 1) ^ 0x23) + 9) ^ 0x38) + 4) ^ 0x29) == 67
    (((((((((((((flag[10] ^ 0xD) + 5) ^ 0x3A) + 6) ^ 0x28) + 5) ^ 0x1B) + 1) ^ 0x1D) + 7) ^ 0x39) + 3) ^ 0x36) == 82
    (((((((((((flag[11] ^ 0x20) + 3) ^ 0x3C) + 10) ^ 0x3A) + 1) ^ 3) + 11) ^ 0x36) + 7) ^ 0x29) == 209
    (((((((((((flag[12] ^ 9) + 3) ^ 0x2F) + 1) ^ 0x38) + 1) ^ 0x3F) + 8) ^ 9) + 6) ^ 0x21) == 107
    (((((((((((flag[13] ^ 0x2C) + 9) ^ 0x35) + 7) ^ 0x21) + 8) ^ 0xA) + 6) ^ 0x26) + 10) ^ 0x2D) == 81
    (((((((((flag[14] ^ 0x1F) + 5) ^ 0x3A) + 2) ^ 0x27) + 2) ^ 0x1B) + 9) ^ 0x16) == 61
    (((((((((((((flag[15] ^ 0x10) + 10) ^ 0x14) + 7) ^ 3) + 1) ^ 0x1E) + 9) ^ 0x1A) + 7) ^ 0x24) + 2) ^ 3) == 234
    (((((((((((flag[16] ^ 4) + 3) ^ 7) + 15) ^ 0x33) + 6) ^ 0x1C) + 7) ^ 0x2A) + 8) ^ 0x2D) == 98
    (((((((((((((flag[17] ^ 0x20) + 3) ^ 0x1D) + 9) ^ 0x3F) + 8) ^ 8) + 10) ^ 0x23) + 3) ^ 0x11) + 5) ^ 0x28) == 101
    (((((((((((flag[18] ^ 0x22) + 5) ^ 0x12) + 8) ^ 0x25) + 1) ^ 0x29) + 4) ^ 0x1F) + 4) ^ 0xF) == 72
    (((((((((((((flag[19] ^ 0x11) + 6) ^ 0x2E) + 7) ^ 0xB) + 6) ^ 0x24) + 9) ^ 0x1E) + 4) ^ 0x2A) + 5) ^ 0x21) == 98
    ((((((((((flag[20] ^ 0x3C) + 4) ^ 0x27) + 3) ^ 4) + 9) ^ 3) + 4) ^ 0x36) ^ 0x27) == 150
    (((((((((((flag[21] ^ 0x2C) + 1) ^ 0x28) + 5) ^ 0x27) ^ 0x3A) + 7) ^ 1) + 10) ^ 0x2F) ^ 0x1B) == 69
    (((((((((((((flag[22] ^ 0x33) + 4) ^ 0x38) + 5) ^ 0x3A) + 7) ^ 0x1A) + 7) ^ 0xC) + 2) ^ 0x28) + 5) ^ 0x2A) == 101
    (((((((((((flag[23] ^ 0x23) + 3) ^ 9) + 3) ^ 0x1B) + 9) ^ 0x11) + 2) ^ 0x3A) + 8) ^ 0xC) == 115
    (((((((((((flag[24] ^ 0x29) + 2) ^ 0x18) + 3) ^ 8) + 5) ^ 0x22) + 10) ^ 0x22) + 5) ^ 0x3A) == 98
    (((((((((((((flag[25] ^ 0x2B) + 1) ^ 0x1F) + 7) ^ 2) + 5) ^ 0x20) + 5) ^ 0x37) + 4) ^ 8) + 9) ^ 0x1F) == 129
    (((((((((((((flag[26] ^ 9) + 3) ^ 0x35) + 3) ^ 0x2E) + 10) ^ 0xE) + 8) ^ 0x1B) + 3) ^ 0x1E) + 10) ^ 0x34) == 181 
    (((((((((((((flag[27] ^ 0x36) + 3) ^ 0x14) + 2) ^ 0x3B) + 7) ^ 0x24) + 9) ^ 0x39) + 3) ^ 0x36) + 3) ^ 0x16) == 171
    ((((((((((((flag[28] ^ 0x30) + 5) ^ 0x11) + 8) ^ 0x13) + 8) ^ 0x21) ^ 0x35) + 4) ^ 0x19) + 7) ^ 0x12) == 111
    (((((((((((((flag[29] ^ 0x11) + 9) ^ 6) + 1) ^ 0x15) + 1) ^ 0x3E) + 9) ^ 0xF) + 9) ^ 0x2D) + 5) ^ 2) == 237
    (((((((((((((flag[30] ^ 6) + 9) ^ 0x19) + 6) ^ 0x2C) + 7) ^ 0xF) + 10) ^ 0x24) + 7) ^ 8) + 7) ^ 0x2E) == 187
    (((((((((((((flag[31] ^ 8) + 7) ^ 0x2C) + 6) ^ 0x3C) + 3) ^ 0x17) + 8) ^ 0x30) + 6) ^ 0x3C)+ 6) ^ 0x17) == 56

由于flag的取值范围被限定在小写字母和数字,因此可以一个字节一个字节求解出完整的flag字符串,代码如下:

    #!/usr/bin/python
    choice = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']

    def check_idx_0(value): 
        return (((((((((((((value ^ 0x10) + 10) ^ 0x12) + 1) ^ 0x1B) + 6) ^ 0x39) + 8) ^ 0x29) + 8) ^ 0x3B) + 4) ^ 0xA) == 0xD8
    def check_idx_1(value):
        return (((((((((((((value ^ 5) + 10) ^ 0x16) + 8) ^ 0x2F) + 9) ^ 0x32) + 10) ^ 0xB) + 6) ^ 0x2B) + 6) ^ 6) == 132
    def check_idx_2(value):
        return (((((((((((((value ^ 0x26) + 10) ^ 0x14) + 7) ^ 7) + 7) ^ 9) + 5) ^ 0x3D) + 6) ^ 0x31) + 5) ^ 0xC) == 40
    def check_idx_3(value):
        return (((((((((((value ^ 0x2F) + 5) ^ 0x29) + 10) ^ 0x27) + 6) ^ 0x31) + 9) ^ 0x26) + 8) ^ 0x32) == 12
    def check_idx_4(value):
        return (((((((((((value ^ 0x1F) + 9) ^ 0x21) + 4) ^ 0x27) + 9) ^ 0x2D) + 7) ^ 0x19) + 9) ^ 0x39) == 52
    def check_idx_5(value):
        return ((((((((((((value + 9) ^ 0x26) + 9) ^ 0x10) + 4) ^ 0x32) + 1) ^ 5) + 1) ^ 0xA) + 7) ^ 0x12) == 94
    def check_idx_6(value):
        return (((((((((((value ^ 0x17) + 6) ^ 0x27) + 1) ^ 0x26) + 6) ^ 1) + 2) ^ 0x16) + 7) ^ 0x1C) == 45 
    def check_idx_7(value):
        return ((((((((((((value ^ 0x1A) + 8) ^ 9) + 3) ^ 0x25) + 4) ^ 0x30) + 7) ^ 0x24) + 5) ^ 0x2F) ^ 0x2B) == 79
    def check_idx_8(value):
        return (((((((((((((value ^ 0xC) + 1) ^ 0x34) + 1) ^ 6) + 8) ^ 0x27) + 8) ^ 0x3B) + 2) ^ 0x23) + 3) ^ 0x16) == 76
    def check_idx_9(value):
        return (((((((((((((value ^ 0xA) + 4) ^ 0x3D) + 10) ^ 0x37) + 1) ^ 0x19) + 1) ^ 0x23) + 9) ^ 0x38) + 4) ^ 0x29) == 67
    def check_idx_10(value):
        return (((((((((((((value ^ 0xD) + 5) ^ 0x3A) + 6) ^ 0x28) + 5) ^ 0x1B) + 1) ^ 0x1D) + 7) ^ 0x39) + 3) ^ 0x36) == 82
    def check_idx_11(value):
        return (((((((((((value ^ 0x20) + 3) ^ 0x3C) + 10) ^ 0x3A) + 1) ^ 3) + 11) ^ 0x36) + 7) ^ 0x29) == 209
    def check_idx_12(value):
        return (((((((((((value ^ 9) + 3) ^ 0x2F) + 1) ^ 0x38) + 1) ^ 0x3F) + 8) ^ 9) + 6) ^ 0x21) == 107
    def check_idx_13(value):
        return (((((((((((value ^ 0x2C) + 9) ^ 0x35) + 7) ^ 0x21) + 8) ^ 0xA) + 6) ^ 0x26) + 10) ^ 0x2D) == 81
    def check_idx_14(value):
        return (((((((((value ^ 0x1F) + 5) ^ 0x3A) + 2) ^ 0x27) + 2) ^ 0x1B) + 9) ^ 0x16) == 61
    def check_idx_15(value):
        return (((((((((((((value ^ 0x10) + 10) ^ 0x14) + 7) ^ 3) + 1) ^ 0x1E) + 9) ^ 0x1A) + 7) ^ 0x24) + 2) ^ 3)  == 234
    def check_idx_16(value):
        return (((((((((((value ^ 4) + 3) ^ 7) + 15) ^ 0x33) + 6) ^ 0x1C) + 7) ^ 0x2A) + 8) ^ 0x2D) == 98
    def check_idx_17(value):
        return (((((((((((((value ^ 0x20) + 3) ^ 0x1D) + 9) ^ 0x3F) + 8) ^ 8) + 10) ^ 0x23) + 3) ^ 0x11) + 5) ^ 0x28) == 101
    def check_idx_18(value):
        return (((((((((((value ^ 0x22) + 5) ^ 0x12) + 8) ^ 0x25) + 1) ^ 0x29) + 4) ^ 0x1F) + 4) ^ 0xF) == 72
    def check_idx_19(value):
        return (((((((((((((value ^ 0x11) + 6) ^ 0x2E) + 7) ^ 0xB) + 6) ^ 0x24) + 9) ^ 0x1E) + 4) ^ 0x2A) + 5) ^ 0x21) == 98
    def check_idx_20(value):
        return ((((((((((value ^ 0x3C) + 4) ^ 0x27) + 3) ^ 4) + 9) ^ 3) + 4) ^ 0x36) ^ 0x27) == 150
    def check_idx_21(value):
        return (((((((((((value ^ 0x2C) + 1) ^ 0x28) + 5) ^ 0x27) ^ 0x3A) + 7) ^ 1) + 10) ^ 0x2F) ^ 0x1B) == 69
    def check_idx_22(value):
        return (((((((((((((value ^ 0x33) + 4) ^ 0x38) + 5) ^ 0x3A) + 7) ^ 0x1A) + 7) ^ 0xC) + 2) ^ 0x28) + 5) ^ 0x2A) == 101
    def check_idx_23(value):
        return (((((((((((value ^ 0x23) + 3) ^ 9) + 3) ^ 0x1B) + 9) ^ 0x11) + 2) ^ 0x3A) + 8) ^ 0xC) == 115
    def check_idx_24(value):
        return (((((((((((value ^ 0x29) + 2) ^ 0x18) + 3) ^ 8) + 5) ^ 0x22) + 10) ^ 0x22) + 5) ^ 0x3A) == 98
    def check_idx_25(value):
        return (((((((((((((value ^ 0x2B) + 1) ^ 0x1F) + 7) ^ 2) + 5) ^ 0x20) + 5) ^ 0x37) + 4) ^ 8) + 9) ^ 0x1F) == 129
    def check_idx_26(value):
        return (((((((((((((value ^ 9) + 3) ^ 0x35) + 3) ^ 0x2E) + 10) ^ 0xE) + 8) ^ 0x1B) + 3) ^ 0x1E) + 10) ^ 0x34) == 181 
    def check_idx_27(value):
        return (((((((((((((value ^ 0x36) + 3) ^ 0x14) + 2) ^ 0x3B) + 7) ^ 0x24) + 9) ^ 0x39) + 3) ^ 0x36) + 3) ^ 0x16) == 171
    def check_idx_28(value):
        return ((((((((((((value ^ 0x30) + 5) ^ 0x11) + 8) ^ 0x13) + 8) ^ 0x21) ^ 0x35) + 4) ^ 0x19) + 7) ^ 0x12) == 111
    def check_idx_29(value):
        return (((((((((((((value ^ 0x11) + 9) ^ 6) + 1) ^ 0x15) + 1) ^ 0x3E) + 9) ^ 0xF) + 9) ^ 0x2D) + 5) ^ 2) == 237
    def check_idx_30(value):
        return (((((((((((((value ^ 6) + 9) ^ 0x19) + 6) ^ 0x2C) + 7) ^ 0xF) + 10) ^ 0x24) + 7) ^ 8) + 7) ^ 0x2E) == 187
    def check_idx_31(value):
        return (((((((((((((value ^ 8) + 7) ^ 0x2C) + 6) ^ 0x3C) + 3) ^ 0x17) + 8) ^ 0x30) + 6) ^ 0x3C)+ 6) ^ 0x17) == 56 

    checker = {
        0:check_idx_0,
        1:check_idx_1,
        2:check_idx_2,
        3:check_idx_3,
        4:check_idx_4,
        5:check_idx_5,
        6:check_idx_6,
        7:check_idx_7,
        8:check_idx_8,
        9:check_idx_9,
        10:check_idx_10,
        11:check_idx_11,
        12:check_idx_12,
        13:check_idx_13,
        14:check_idx_14,
        15:check_idx_15,
        16:check_idx_16,
        17:check_idx_17,
        18:check_idx_18,
        19:check_idx_19,
        20:check_idx_20,
        21:check_idx_21,
        22:check_idx_22,
        23:check_idx_23,
        24:check_idx_24,
        25:check_idx_25,
        26:check_idx_26,
        27:check_idx_27,
        28:check_idx_28,
        29:check_idx_29,
        30:check_idx_30,
        31:check_idx_31,
    } 

    def check(index, value):
    return checker.get(index)(value)

    flag=""
    for i in xrange(32):
        for c in choice:
            if True == check(index=i, value=ord(c)):
                flag+=c
                print c
    print flag

解出flag:wk608t84naoce60t8cx0o82hrtoxxae8

Transformation

Transformation是mips架构的程序,代码逻辑是对用户输入的22字节的flag字符串进行相关的字节异或操作,并将计算出的22字节异或数据与0x00410A90内存上的22个WORD数值进行比较,如果全部相等,则为正确的flag。具体检测代码在flag_check函数中,如下所示:

0x00410A90上的校验数据:

最终的解密代码如下所示:

    #!/usr/bin/python
    def crack():
        flag_plain = ""
        # 0x00410A90  => flag_cipher
        flag_cipher = [0x45,0x74,0x19,0x69,0x58,0x3D,0x62,0xF,0x66,0x16,0x65,0x3A,0xA,0x64,1,0x5E,0x3C,0x45,0x1A,0x75,0x1B,0x7E]
        length = 22
        tmp = length
        for i in xrange(length):
            c = flag_cipher[i] ^ tmp
            tmp ^= c
            flag_plain += chr(c)
        return flag_plain

    if __name__ == '__main__':
        print "flag: " + crack()

解出flag:S1mp1e_mips_0ne_by_one
其实已经在binary中内置了flag

LookAtMe

点击按钮后通过jni调用check函数对输入字符进行比较,
用IDA打开so文件后找到Java_oct_rd6_iie_crackme_MainActivity_check函数,该函数首先判断长度是否大于14,然后交换某些位置数据

读取/data/data/oct.rd6.iie.crackme/file/cache文件的头三个字节和0xffdc30异或后,得到偏移,再读取该处位置一个字节0x76,并将输入子节与之异或

sub_8086函数可以看出异或后第0、4、8、12个字节分别是70, 68, 18, 65

然后通过反射调用CrackmeApp对每四个字节进行检查
最后读取cache文件一个字节0xa6,通过sub_8088进行变换字节后得到4个字节58, 109, 105, 104,此时检查通过并返回true
逆向算法如下:

    a2 = 0xffd8a6
    v3 = []
    ans = [58, 109, 105, 104]
    for i in ans:
        v3.append((i-a2)&0xff)
    for i in range(4):
        print((v3[i]+a2)%128),
    print ""
    v22 = [90454, 109609, 99753, 246925]
    v21 = [3, 0x57, 0x50, 0xe]
    tar = [70, 68, 18, 65]
    for i in range(4):
        b4 = v3[i] & 0xff
        b1 = tar[i] & 0xff
        b2 = (b1 ^ v21[i])&0xff
        for k in range(256):
            b3 = k
            res = (b3*12*b3)+(b4*13*b4)+(b3*14*b4)+(b2*15*b1)+16
            if res == v22[i]:
                print "Found:", i, b1, b2, b3, b4
    print(“Done")

将得到的字节组合成4个int,最后异或并交换字节即可。

混淆迷宫

这一题有两个的坑
1、 所有的系统调用都是通过svc中断来实现,用ida静态看看不到任何的熟悉的系统调用函数;
2、 许多地方使用了ollvm混淆,即使动态调试也十分耗时间。
这一题是从给了第一个提示开始做的,看到需要输入文件但是用ida看不到任何和文件操作相关的函数就可以知道是通过svc中断来实现系统调用,这里对每个svc调用结合系统调用号可以将系统调用函数恢复。
后来出了第二个提示,程序会生成一个地图。动态跟了一会,就能够从内存中把这个地图dump出来,我之前跟的时候跟得比较马虎,没有把地图的长宽记录,不过从地图总大小132可以推测是12*11或11*12.

从地图由*、#、空格三种字符组成,从图形可以猜测是沿着空格走一直走到#号,然后需要逆向操控行走的方法。这部分使用了ollvm混淆,单步跟起来很耗时,不过跟个一两次就可以发现,跳转时,R0中的值是不变的,R1会被不断的赋值,直到与R0相等,所以在进入跳转阶段时,通过搜索与R0相等的立即数且正要赋值给R1的地方,直接下断点,即可快速跳过ollvm中的跳转过程(不是最优的办法,不过也能省不少时间)。
慢慢跟就可以把控制行走的逻辑逆向出来,刚开始十几步是用wasd来控制,这个其实不逆也能知道,但是十几步之后又换成1234,这个就需要多试几次,看一下每个执行的效果来记录,继续走十来步又换成ijkl来控制,这个类比wasd也可以直接推测出来。
最后控制行走到#的字符串就是flag。

从地图由*、#、空格三种字符组成,从图形可以猜测是沿着空格走一直走到#号,然后需要逆向操控行走的方法。这部分使用了ollvm混淆,单步跟起来很耗时,不过跟个一两次就可以发现,跳转时,R0中的值是不变的,R1会被不断的赋值,直到与R0相等,所以在进入跳转阶段时,通过搜索与R0相等的立即数且正要赋值给R1的地方,直接下断点,即可快速跳过ollvm中的跳转过程(不是最优的办法,不过也能省不少时间)。
慢慢跟就可以把控制行走的逻辑逆向出来,刚开始十几步是用wasd来控制,这个其实不逆也能知道,但是十几步之后又换成1234,这个就需要多试几次,看一下每个执行的效果来记录,继续走十来步又换成ijkl来控制,这个类比wasd也可以直接推测出来。
最后控制行走到#的字符串就是flag。

评论:

Your email address will not be published.


*