一个mips64架构的Re题目。
检查文件格式
检查文件是个一个mips64大端程序,穷人用不起IDA pro 7.5,只能上ghidra来进行反编译操作。
分析代码
- 题目给出了一个加密后的文本
最后多出来的0A是个换行符。
- 用ghidra反汇编,进入主函数
- 时间做随机种子, cipher应该就是加密函数了。
- 进入cipher,发现有个循环,每16位为一组数据,由于我们结果为48位,所以应该是就分为三组进行操作。encrypt是加密函数,第一个参数是加密结果,第二个参数是输入内容。
- 再次进入encrypt函数,由于反汇编偏差,rand这个随机数参数未能识别传进来。in_a2就是这个参数。
- 根据代码,修复一些变量名。
- 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)
总结
这个题目比较坑的两个地方是注意大小端,还有就是加号与异或运算优先级,如果这两个搞错,很容易被卡住的。