一个mips64架构的Re题目。

检查文件格式

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

分析代码

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

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

  • 用ghidra反汇编,进入主函数

1

  • 时间做随机种子, cipher应该就是加密函数了。

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

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

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

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

    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种情况。

    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,然后直接逆向解决就好了。

    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

    
    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)
    
    

    总结

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