一个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)

总结

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