一个mips64架构的Re题目。

检查文件格式

检查文件是个一个mips64大端程序,穷人用不起IDA pro 7.5,只能上ghidra来进行反编译操作。

分析代码

  • 题目给出了一个加密后的文本
12
12

最后多出来的0A是个换行符。

  • 用ghidra反汇编,进入主函数
1
1
  • 时间做随机种子, cipher应该就是加密函数了。

  • 进入cipher,发现有个循环,每16位为一组数据,由于我们结果为48位,所以应该是就分为三组进行操作。encrypt是加密函数,第一个参数是加密结果,第二个参数是输入内容。

    2
    2
  • 再次进入encrypt函数,由于反汇编偏差,rand这个随机数参数未能识别传进来。in_a2就是这个参数。

    3
    3
  • 根据代码,修复一些变量名。

    4
    4
  • while循环为主要加密过程,主要进行了一些位运算。,写出位运算逆向脚本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    ld =[s2]
    lc = [s1]
    for i in range(31):
    ld.append((rright(ld[i],8) + lc[i] ^ i)&0xffffffffffffffff )
    lc.append(rright(lc[i],61) ^ ld[i+1])
    for i in range(31,-1,-1):
    x1 = rright(x1^x2,3)
    x2 = rright(((x2^lc[i])-x1)&0xffffffffffffffff,56)
    return x1,x2

    解决思路

  • while循环中,srand未知,输出结果已知,输入内容未知。所以我们逆向出这个运算,还是需要得到srand值,才可能解决题目

  • srand 可以采取爆破的形式,由于比赛flag形式为RCTF{xxxxx},所以我们可以根据第一组数据进行爆破,得到srand。每个srand255(无符号)种情况,255*255总共65535种情况。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    for i in range(65536):
    s1 = i
    s2 = 0
    s1,s2 = struct.unpack('QQ',struct.pack('>QQ',s1,s2))
    x1,x2 = reverse(lists2[0],lists2[1],s1,s2)
    str1 = struct.pack('>Q',x1)
    if 'RCTF' in str1:
    print(i)
    break
  • 得到srand,然后直接逆向解决就好了。

    1
    2
    3
    4
    5
    6
    for i in range(len(lists2)/2):
    s1,s2 = struct.unpack('QQ',struct.pack('>QQ',4980,0))
    x1,x2 = reverse(lists2[2*i],lists2[2*i+1],s1,s2)
    flag += struct.pack('>Q',x1)
    flag += struct.pack('>Q',x2)
    print (flag)

    exp

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47

    import struct

    def encrypt(a,b,c,d ):
    b = (rright(b,8) + a ^ c)&0xffffffffffffffff
    a = rright(a,61) ^ b
    for i in range(0x1f):
    d = (rright(d,8) + c ^ i)&0xffffffffffffffff
    c = rright(c,61) ^ d
    b = (rright(b,8) + a ^ c)&0xffffffffffffffff
    a = rright(a,61) ^ b
    return a,b

    def recerse(x1,x2,s1,s2):
    ld =[s2]
    lc = [s1]
    for i in range(31):
    ld.append((rright(ld[i],8) + lc[i] ^ i)&0xffffffffffffffff )
    lc.append(rright(lc[i],61) ^ ld[i+1])
    for i in range(31,-1,-1):
    x1 = rright(x1^x2,3)
    x2 = rright(((x2^lc[i])-x1)&0xffffffffffffffff,56)
    return x1,x2

    def rright(v,n):
    return ((v >> n) + (v << (64-n)))&0xffffffffffffffff
    lists = [0x2A, 0x00, 0xF8, 0x2B, 0xE1, 0x1D, 0x77, 0xC1, 0xC3, 0xB1, 0x71, 0xFC, 0x23, 0xD5, 0x91, 0xF4, 0x30, 0xF1, 0x1E, 0x8B, 0xC2, 0x88, 0x59, 0x57, 0xD5, 0x94, 0xAB, 0x77, 0x42, 0x2F, 0xEB, 0x75, 0xE1, 0x5D, 0x76, 0xF0, 0x46, 0x6E, 0x98, 0xB9, 0xB6, 0x51, 0xFD, 0xB5, 0x5D, 0x77, 0x36, 0xF2]
    lists2 =[]
    for i in lists:
    lists2.append(chr(i))
    lists2 = struct.unpack('>QQQQQQ',''.join(lists2))
    for i in range(65536):
    s1 = i
    s2 = 0
    s1,s2 = struct.unpack('QQ',struct.pack('>QQ',s1,s2))
    x1,x2 = reverse(lists2[0],lists2[1],s1,s2)
    str1 = struct.pack('>Q',x1)
    if 'RCTF' in str1:
    print(i)
    break
    flag = ''
    for i in range(len(lists2)/2):
    s1,s2 = struct.unpack('QQ',struct.pack('>QQ',4980,0))
    x1,x2 = reverse(lists2[2*i],lists2[2*i+1],s1,s2)
    flag += struct.pack('>Q',x1)
    flag += struct.pack('>Q',x2)
    print (flag)

    总结

    这个题目比较坑的两个地方是注意大小端,还有就是加号与异或运算优先级,如果这两个搞错,很容易被卡住的。