今年逆向题目比较多,还挺顺手的,其他题目还算不难,除了babyAnti这题就AK逆向了。这题用的flutter库,研究了好久也完全找不到思路,只好放弃。后来才知道根据题目的名字,预期解就是去掉反作弊的检查,用作弊方法完成的。
RE:confuse_re
代码中有大量的call $+5混淆,ida的F5不好使了,但是还是可以看汇编进入真正的函数,所以没有什么区别。
主函数:
很多字符串都采用异或进行加密
前面是简单的红橙蓝的输入判断:
输入bor进入密码环节,下面是核心判断代码:
密码被分成前16字节和后16字节两部分,第一部分先加密,然后第二部分在和加密结果进行异或并加1:
查看密钥生成和加密的部分,判断为AES加密
但是在AddroundKey函数中又用了0x23进行异或,因此采用脚本进行解密,exp如下:
import re
import binascii
classAes:
sbox =[0x63,0x7C,0x77,0x7B,0xF2,0x6B,0x6F,0xC5,0x30,0x01,0x67,0x2B,0xFE,0xD7,0xAB,0x76,0xCA,0x82,0xC9,0x7D,0xFA,0x59,0x47,0xF0,0xAD,0xD4,0xA2,0xAF,0x9C,0xA4,0x72,0xC0,0xB7,0xFD,0x93,0x26,0x36,0x3F,0xF7,0xCC,0x34,0xA5,0xE5,0xF1,0x71,0xD8,0x31,0x15,0x04,0xC7,0x23,0xC3,0x18,0x96,0x05,0x9A,0x07,0x12,0x80,0xE2,0xEB,0x27,0xB2,0x75,0x09,0x83,0x2C,0x1A,0x1B,0x6E,0x5A,0xA0,0x52,0x3B,0xD6,0xB3,0x29,0xE3,0x2F,0x84,0x53,0xD1,0x00,0xED,0x20,0xFC,0xB1,0x5B,0x6A,0xCB,0xBE,0x39,0x4A,0x4C,0x58,0xCF,0xD0,0xEF,0xAA,0xFB,0x43,0x4D,0x33,0x85,0x45,0xF9,0x02,0x7F,0x50,0x3C,0x9F,0xA8,0x51,0xA3,0x40,0x8F,0x92,0x9D,0x38,0xF5,0xBC,0xB6,0xDA,0x21,0x10,0xFF,0xF3,0xD2,0xCD,0x0C,0x13,0xEC,0x5F,0x97,0x44,0x17,0xC4,0xA7,0x7E,0x3D,0x64,0x5D,0x19,0x73,0x60,0x81,0x4F,0xDC,0x22,0x2A,0x90,0x88,0x46,0xEE,0xB8,0x14,0xDE,0x5E,0x0B,0xDB,0xE0,0x32,0x3A,0x0A,0x49,0x06,0x24,0x5C,0xC2,0xD3,0xAC,0x62,0x91,0x95,0xE4,0x79,0xE7,0xC8,0x37,0x6D,0x8D,0xD5,0x4E,0xA9,0x6C,0x56,0xF4,0xEA,0x65,0x7A,0xAE,0x08,0xBA,0x78,0x25,0x2E,0x1C,0xA6,0xB4,0xC6,0xE8,0xDD,0x74,0x1F,0x4B,0xBD,0x8B,0x8A,0x70,0x3E,0xB5,0x66,0x48,0x03,0xF6,0x0E,0x61,0x35,0x57,0xB9,0x86,0xC1,0x1D,0x9E,0xE1,0xF8,0x98,0x11,0x69,0xD9,0x8E,0x94,0x9B,0x1E,0x87,0xE9,0xCE,0x55,0x28,0xDF,0x8C,0xA1,0x89,0x0D,0xBF,0xE6,0x42,0x68,0x41,0x99,0x2D,0x0F,0xB0,0x54,0xBB,0x16]
s_box ={}
ns_box ={}
Rcon ={1:['0x01','0x00','0x00','0x00'],2:['0x02','0x00','0x00','0x00'],3:['0x04','0x00','0x00','0x00'],4:['0x08','0x00','0x00','0x00'],5:['0x10','0x00','0x00','0x00'],6:['0x20','0x00','0x00','0x00'],7:['0x40','0x00','0x00','0x00'],8:['0x80','0x00','0x00','0x00'],9:['0x1B','0x00','0x00','0x00'],10:['0x36','0x00','0x00','0x00']}
Matrix =[['0x02','0x03','0x01','0x01'],['0x01','0x02','0x03','0x01'],['0x01','0x01','0x02','0x03'],['0x03','0x01','0x01','0x02']]
ReMatrix =[['0x0e','0x0b','0x0d','0x09'],['0x09','0x0e','0x0b','0x0d'],['0x0d','0x09','0x0e','0x0b'],['0x0b','0x0d','0x09','0x0e']]
plaintext =[[],[],[],[]]
plaintext1 =[[],[],[],[]]
subkey =[[],[],[],[]]def__init__(self, key):
self.s_box =dict(zip(["0x%02x"%i for i inrange(256)],["0x%02x"%i for i in self.sbox]))
self.ns_box =dict(zip(self.s_box.values(), self.s_box.keys()))for i inrange(4):for j inrange(0,8,2):
self.subkey[i].append("0x"+ key[i *8+ j:i *8+ j +2])# print(self.subkey)for i inrange(4,44):if i %4!=0:
tmp = xor_32(self.subkey[i -1], self.subkey[i -4],0)
self.subkey.append(tmp)else:# 4的倍数的时候执行
tmp1 = self.subkey[i -1][1:]
tmp1.append(self.subkey[i -1][0])# print(tmp1)for m inrange(4):
tmp1[m]= self.s_box[tmp1[m]]# tmp1 = self.s_box['cf']
tmp1 = xor_32(tmp1, self.Rcon[i /4],0)
self.subkey.append(xor_32(tmp1, self.subkey[i -4],0))# print(self.subkey)defAddRoundKey(self,round):for i inrange(4):
self.plaintext[i]= xor_32(self.plaintext[i], self.subkey[round*4+ i],0x23)# print('AddRoundKey',self.plaintext)defPlainSubBytes(self):for i inrange(4):for j inrange(4):
self.plaintext[i][j]= self.s_box[self.plaintext[i][j]]# print('PlainSubBytes',self.plaintext)defRePlainSubBytes(self):for i inrange(4):for j inrange(4):
self.plaintext[i][j]= self.ns_box[self.plaintext[i][j]]defShiftRows(self):
p1, p2, p3, p4 = self.plaintext[0][1], self.plaintext[1][1], self.plaintext[2][1], self.plaintext[3][1]
self.plaintext[0][1]= p2
self.plaintext[1][1]= p3
self.plaintext[2][1]= p4
self.plaintext[3][1]= p1
p1, p2, p3, p4 = self.plaintext[0][2], self.plaintext[1][2], self.plaintext[2][2], self.plaintext[3][2]
self.plaintext[0][2]= p3
self.plaintext[1][2]= p4
self.plaintext[2][2]= p1
self.plaintext[3][2]= p2
p1, p2, p3, p4 = self.plaintext[0][3], self.plaintext[1][3], self.plaintext[2][3], self.plaintext[3][3]
self.plaintext[0][3]= p4
self.plaintext[1][3]= p1
self.plaintext[2][3]= p2
self.plaintext[3][3]= p3
# print('ShiftRows',self.plaintext)defReShiftRows(self):
p1, p2, p3, p4 = self.plaintext[0][1], self.plaintext[1][1], self.plaintext[2][1], self.plaintext[3][1]
self.plaintext[3][1]= p3
self.plaintext[2][1]= p2
self.plaintext[0][1]= p4
self.plaintext[1][1]= p1
p1, p2, p3, p4 = self.plaintext[0][2], self.plaintext[1][2], self.plaintext[2][2], self.plaintext[3][2]
self.plaintext[0][2]= p3
self.plaintext[1][2]= p4
self.plaintext[2][2]= p1
self.plaintext[3][2]= p2
p1, p2, p3, p4 = self.plaintext[0][3], self.plaintext[1][3], self.plaintext[2][3], self.plaintext[3][3]
self.plaintext[0][3]= p2
self.plaintext[1][3]= p3
self.plaintext[2][3]= p4
self.plaintext[3][3]= p1
defMixColumns(self):for i inrange(4):for j inrange(4):
self.plaintext1[i].append(MatrixMulti(self.Matrix[j], self.plaintext[i]))# print('MixColumns',self.plaintext1)defReMixColumns(self):for i inrange(4):for j inrange(4):
self.plaintext1[i].append(MatrixMulti(self.ReMatrix[j], self.plaintext[i]))defAESEncryption(self, plaintext):
self.plaintext =[[],[],[],[]]for i inrange(4):for j inrange(0,8,2):
self.plaintext[i].append("0x"+ plaintext[i *8+ j:i *8+ j +2])
self.AddRoundKey(0)for i inrange(9):
self.PlainSubBytes()
self.ShiftRows()
self.MixColumns()
self.plaintext = self.plaintext1
self.plaintext1 =[[],[],[],[]]
self.AddRoundKey(i +1)
self.PlainSubBytes()
self.ShiftRows()
self.AddRoundKey(10)return Matrixtostr(self.plaintext)defAESDecryption(self, cipher):
self.plaintext =[[],[],[],[]]for i inrange(4):for j inrange(0,8,2):
self.plaintext[i].append('0x'+ cipher[i *8+ j:i *8+ j +2])# print(self.ns_box)
self.AddRoundKey(10)for i inrange(9):
self.ReShiftRows()
self.RePlainSubBytes()
self.AddRoundKey(9-i)
self.ReMixColumns()
self.plaintext = self.plaintext1
self.plaintext1 =[[],[],[],[]]
self.ReShiftRows()
self.RePlainSubBytes()
self.AddRoundKey(0)return Matrixtostr(self.plaintext)defEncryption(self, text):
group = PlaintextGroup(TextToByte(text),32,1)# print(group)
cipher =""for i inrange(len(group)):
cipher = cipher + self.AESEncryption(group[i])return cipher
defDecryption(self, cipher):
group = PlaintextGroup(cipher,32,0)# print(group)
text =''for i inrange(len(group)):
text = text + self.AESDecryption(group[i])
text = ByteToText(text)return text
defxor_32(start, end, key):
a =[]for i inrange(0,4):
xor_tmp =""
b = hextobin(start[i])
c = hextobin(end[i])
d =bin(key)[2:].rjust(8,'0')for j inrange(8):
tmp =int(b[j],10)^int(c[j],10)^int(d[j],10)
xor_tmp +=str(tmp )
a.append(bintohex(xor_tmp))return a
defxor_8(begin, end):
xor_8_tmp =""for i inrange(8):
xor_8_tmp +=str(int(begin[i])^int(end[i]))return xor_8_tmp
defhextobin(word):
word =bin(int(word,16))[2:]for i inrange(0,8-len(word)):
word ='0'+word
return word
defbintohex(word):
word =hex(int(word,2))iflen(word)==4:return word
eliflen(word)<4:return word.replace('x','x0')defMatrixMulti(s1, s2):
result =[]
s3 =[]for i inrange(4):
s3.append(hextobin(s2[i]))for i inrange(4):
result.append(MultiProcess(int(s1[i],16), s3[i]))for i inrange(3):
result[0]= xor_8(result[0], result[i+1])return bintohex(result[0])defMultiProcess(a, b):if a ==1:return b
elif a ==2:if b[0]=='0':
b = b[1:]+'0'else:
b = b[1:]+'0'
b = xor_8(b,'00011011')return b
elif a ==3:
tmp_b = b
if b[0]=='0':
b = b[1:]+'0'else:
b = b[1:]+'0'
b = xor_8(b,'00011011')return xor_8(b, tmp_b)elif a ==9:
tmp_b = b
return xor_8(tmp_b, MultiProcess(2, MultiProcess(2, MultiProcess(2, b))))elif a ==11:
tmp_b = b
return xor_8(tmp_b, xor_8(MultiProcess(2, MultiProcess(2, MultiProcess(2, b))), MultiProcess(2, b)))elif a ==13:
tmp_b = b
return xor_8(tmp_b, xor_8(MultiProcess(2, MultiProcess(2, MultiProcess(2, b))), MultiProcess(2, MultiProcess(2, b))))elif a ==14:return xor_8(MultiProcess(2, b), xor_8(MultiProcess(2, MultiProcess(2, MultiProcess(2, b))), MultiProcess(2, MultiProcess(2, b))))defMatrixtostr(matrix):
result =""for i inrange(4):for j inrange(4):
result += matrix[i][j][2:]return result
defPlaintextGroup(plaintext, length, flag):
group = re.findall('.{'+str(length)+'}', plaintext)
group.append(plaintext[len(group)*length:])if group[-1]==''and flag:
group[-1]='16161616161616161616161616161616'eliflen(group[-1])< length and flag:
tmp =int((length-len(group[-1]))/2)if tmp <10:for i inrange(tmp):
group[-1]= group[-1]+'0'+str(tmp)else:for i inrange(tmp):
group[-1]= group[-1]+str(tmp)elifnot flag:del group[-1]return group
defTextToByte(words):
text = words.encode('utf-8').hex()return text
defByteToText(encode):
tmp =int(encode[-2:])
word =''for i inrange(len(encode)-tmp*2):
word = word + encode[i]# print(word)
word =bytes.decode(binascii.a2b_hex(word))return word
defxorbytes(bytes1,bytes2):
length=min(len(bytes1),len(bytes2))
output=bytearray()for i inrange(length):
output.append(bytes1[i]^bytes2[i])returnbytes(output)
res='DCDCCC668DF33C15505EEF1646D9D7DF5027447765DCA73968CB7F7B88DD640F'.lower()
key ='CA9D7FF8A4099004FAD40661E93B775A'.lower()
A1 = Aes(key)
plaintext=A1.AESDecryption(res[:32])
a=bytes.fromhex(plaintext)
b=A1.AESDecryption(res[32:])
b=bytearray(bytes.fromhex(b))
d=bytes.fromhex(res[:32])for i inrange(16):
b[i]-=1
b[i]^=d[i]print((a+b).decode())
得到flag:
VNCTF{fa9ad36bd2de1586d944cf7b2935dd91}
RE:PZGalaxy
查看网页js源码,判断是RC4加密,写出计算日期的EXP:
password=bytes.fromhex('a6703adc92c397f31adf8d6412035907b6d4f7735f1d3a494c4358d1b94f998533e0697c')from Crypto.Cipher import ARC4
for i inrange(1,13):for j inrange(1,32):
arc4 = ARC4.new(('2023%02d%02d'%(i,j)).encode())ifb'flag'in arc4.decrypt(password):print('2023%02d%02d'%(i,j))
得到日期:20230127
然后到web上提交得到flag
flag{HitYourSoulAndSeeYouInTheGalaxy}
RE:jijiji
资源里有个shell,会自动启动一个进程,并终止父进程
将shell的资源解密后保存成dump.exe,并可以以如下命令行方式运行:
dump.exe jijiji.exe 16000
核心代码如下:
就是一个魔改的XTEA加密
exp:
import struct
defdecrypt(rounds, v, k):
v0 = v[0]
v1 = v[1]
delta =0x88408067
x = delta * rounds
for i inrange(rounds):
x -= delta
x = x &0xFFFFFFFF
v1 -=(((v0 <<4)^(v0 >>5))+ v0)^(x + k[(x >>11)&3])
v1 = v1 &0xFFFFFFFF
v0 -=(((v1 <<4)^(v1 >>5))+ v1)^(x + k[x &3])^ x
v0 = v0 &0xFFFFFFFFreturn[v0,v1]
key =[98,111,109,98]
rounds =33
res=bytes.fromhex('78F7D4AD32F1D7A690328161A6404A2D115FB0002494D5B6C6BF1B23315B40CD')#test=b'0123456789abcdef0123456789abcdef'for i inrange(len(res)//8):
data=res[i*8:i*8+8]
value=struct.unpack('<2I',data)
decrypted = decrypt(rounds, value, key)print(struct.pack('<2I',*decrypted).decode(),end='')
得到flag:
2d326e43eb8fea8837737fc0f50f83f2
WEB:象棋王子
签到题
复制出脚本,直接在控制台运行就好了
flag{w3lc0m3_t0_VNCTF_2023—}
MISC:snake on web
咋看是一个web,但是是wasm的代码,直接逆向分析得到核心逻辑
调试的时候记录数据,然后用脚本恢复flag:
b=b'sfaceratrebumverodolorindolortakimataverou'
a=bytes.fromhex('84fdffff7b02000075020000790200006b020000bbfdffff79020000b7fdffffa0fdffff75020000c0fdffffb7fdffffbcfdffffc8fdffffa7fdffffbafdffffc2fdffffa4fdffffd3fdffffbdfdffff8efdffff85fdffffc2fdffffd0fdffff96fdffffbdfdffffc1fdffffc2fdffffccfdffffd1fdffffa7fdffffc3fdffff8dfdffffbefdffffabfdffffa3fdffff74020000d3fdffffc1fdffffbbfdffffbbfdffff7d02000075020000')for i inrange(len(a)//4-1):
data=a[i*4:i*4+4]print(chr(((0x72^((data[0]^2)-5))+b[i])&0xff),end='')
得到:
flag{8e6ae178-7387-4db2-a788-039a27bd4185}
RE:dll_puzzle
按照题目提示进行调试执行
代码没有符号,需要调试才能看出如MessageBox这种系统函数,大量符号和变量也都在运行时会修改,比如SM4加密用到的Sbox和FK、Key等
注意代码的反调试功能,需要跳过,然后得到正确的解密参数后即可写出脚本(最终的解密居然就是没有魔改的SM4),后面判断结果时采用80个变量的方程组来进行,用Z3求解搞定,最终exp:
from sm4 import SM4Key
from z3 import*
s = Solver()
flag =[BitVec('flag%d'% i,16)for i inrange(80)]for i inrange(len(flag)):
s.add(And(flag[i]>=0x0,flag[i]<=0xff))
s.add(5*(flag[1])+8*(flag[0])==2669)
s.add(6*(flag[1])+4*(flag[2])==1402)
s.add(3*(flag[3])+6*(flag[2])==873)
s.add(7*(flag[4])+6*(flag[3])==2627)
s.add(8*(flag[5])+4*(flag[4])==2516)
s.add(9*(flag[6])+5*(flag[5])==2781)
s.add(3*(flag[6])+4*(flag[7])==1228)
s.add(5*(flag[8])+9*(flag[7])==1821)
s.add(7*(flag[9])+5*(flag[8])==554)
s.add(6*(flag[10])+9*(flag[9])==825)
s.add(5*(flag[11])+6*(flag[10])==1857)
s.add(3*(flag[11])+4*(flag[12])==1627)
s.add(7*(flag[13])+5*(flag[12])==2279)
s.add(3*(flag[14])+9*(flag[13])==1974)
s.add(6*(flag[15])+6*(flag[14])==2382)
s.add(7*(flag[15])+8*(flag[16])==1903)
s.add(8*(flag[17])+8*(flag[16])==1336)
s.add(3*(flag[18])+6*(flag[17])==822)
s.add(5*(flag[19])+8*(flag[18])==381)
s.add(3*(flag[20])+5*(flag[19])==823)
s.add(5*(flag[21])+5*(flag[20])==1680)
s.add(6*(flag[21])+8*(flag[22])==2116)
s.add(9*(flag[23])+3*(flag[22])==1059)
s.add(3*(flag[23])+8*(flag[24])==1314)
s.add(3*(flag[25])+9*(flag[24])==1641)
s.add(5*(flag[25])+8*(flag[26])==2148)
s.add(3*(flag[27])+3*(flag[26])==669)
s.add(5*(flag[28])+9*(flag[27])==953)
s.add(5*(flag[29])+7*(flag[28])==1896)
s.add(3*(flag[30])+3*(flag[29])==1275)
s.add(5*(flag[31])+7*(flag[30])==2874)
s.add(9*(flag[32])+6*(flag[31])==1518)
s.add(7*(flag[33])+5*(flag[32])==1312)
s.add(6*(flag[34])+5*(flag[33])==2148)
s.add(9*(flag[34])+8*(flag[35])==2979)
s.add(3*(flag[35])+4*(flag[36])==476)
s.add(6*(flag[37])+3*(flag[36])==1047)
s.add(7*(flag[38])+4*(flag[37])==1488)
s.add(6*(flag[39])+6*(flag[38])==1320)
s.add(5*(flag[40])+6*(flag[39])==1784)
s.add(3*(flag[41])+8*(flag[40])==1994)
s.add(7*(flag[42])+3*(flag[41])==712)
s.add(3*(flag[43])+3*(flag[42])==1002)
s.add(5*(flag[44])+7*(flag[43])==2094)
s.add(3*(flag[45])+3*(flag[44])==465)
s.add(5*(flag[46])+6*(flag[45])==1479)
s.add(3*(flag[47])+6*(flag[46])==1281)
s.add(7*(flag[48])+4*(flag[47])==1064)
s.add(3*(flag[49])+4*(flag[48])==985)
s.add(3*(flag[50])+4*(flag[49])==922)
s.add(7*(flag[51])+8*(flag[50])==1672)
s.add(9*(flag[51])+4*(flag[52])==1740)
s.add(6*(flag[53])+7*(flag[52])==1185)
s.add(6*(flag[54])+9*(flag[53])==711)
s.add(4*(flag[55])+4*(flag[54])==256)
s.add(7*(flag[56])+8*(flag[55])==744)
s.add(5*(flag[57])+8*(flag[56])==1674)
s.add(6*(flag[58])+3*(flag[57])==834)
s.add(3*(flag[59])+4*(flag[58])==348)
s.add(9*(flag[59])+4*(flag[60])==952)
s.add(3*(flag[60])+4*(flag[61])==1117)
s.add(7*(flag[62])+9*(flag[61])==1853)
s.add(6*(flag[63])+9*(flag[62])==399)
s.add(3*(flag[64])+6*(flag[63])==1011)
s.add(6*(flag[65])+9*(flag[64])==3171)
s.add(8*(flag[66])+8*(flag[65])==1760)
s.add(7*(flag[67])+7*(flag[66])==861)
s.add(6*(flag[68])+6*(flag[67])==1710)
s.add(7*(flag[68])+8*(flag[69])==1578)
s.add(7*(flag[70])+9*(flag[69])==1280)
s.add(3*(flag[71])+6*(flag[70])==1134)
s.add(3*(flag[72])+8*(flag[71])==1003)
s.add(9*(flag[72])+8*(flag[73])==1345)
s.add(5*(flag[74])+4*(flag[73])==928)
s.add(3*(flag[74])+4*(flag[75])==824)
s.add(6*(flag[76])+8*(flag[75])==1840)
s.add(9*(flag[77])+7*(flag[76])==1200)
s.add(3*(flag[77])+8*(flag[78])==2032)
s.add(5*(flag[79])+5*(flag[78])==1795)
s.add(7*(flag[79])+8*(flag[0])==2584)if s.check()!= sat:print("error!")
count=0while s.check()== sat:
m = s.model()
count+=1
data=[m[flag[i]].as_long()for i inrange(80)]for j inrange(256):
key_data =list(bytes.fromhex('206232332E74762F7946524337685900'))for k inrange(len(key_data)):
key_data[k]^=(j^0x2a)
flag=b''
sm4 = SM4Key(bytes(key_data))
flag = sm4.decrypt(bytes(data))if checkflag(flag[:10]):print(j,bytes.fromhex(flag.strip(b'\x00').decode()))break
得到TheAnswerToTheUltimateQuestionOfLifeTheUniverseAndEverything值和flag:
42 flag{3f27d7470d8967fd344ec7f1261e64b3}
填入license.ini验证通过:
这题其实在SM4解密的地方卡了好久,后来跟出题人沟通了下,才发现我用的SM4源码有问题,因为参数都是默认的,直接用Cyberchef也能解出来~
版权归原作者 sln_1550 所有, 如有侵权,请联系我们删除。