(资料图片仅供参考)
ez_cpp
这个题目看了两种办法,受益匪浅
by Arr3stY0u
打开去花得到主函数,反编译后看到单字节判断,可以进行单字节爆破首先改掉不对就跳到wrong这个逻辑,判断错误后直接跳到exit函数上,然后改掉exit的参数,让它的参数变成ecx,也就是判断正确了几次反编译后就变成了这样那么就可以利用这样一个知识点在main中:return v; 与 exit(v); 的效果相同。返回值就是j,可以捕获这个j,来当成单字节爆破的判断依据师傅的脚本如下
import stringimport osimport timetable = string.ascii_letters+string.digits+"!-{}"# table = string.printable# "SYC{Y3S-yE5-y0u-S0Ve-Th3-C9P!!!}"theflag = ""while len(theflag) < 32: for ch in table: flag = (theflag+ch).ljust(32, "#") exitcode = os.system(f"echo {flag} | ez_cpp.exe 1>&0") if exitcode >= len(theflag) + 1: theflag += ch print(theflag, exitcode) break else: print("not found") time.sleep(0.1)
拼接flag部分并把flag输入到程序里,exitcode就是返回值,也就是ecx的值,如果ecx>=输入的flag的前几位+1,那么这几位就是部分正确的flag,接下来继续拼接即可SYC{Y3S-yE5-y0u-S0Ve-Th3-C9P!!!}
by Blu3e
这个思路就是直接逆向依然是去花,然后爆破凯撒加密之后的密文
result=[]opcode=[0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]cmp=[0x22, 0x00, 0x00, 0x00, 0xA2, 0xFF, 0xFF, 0xFF, 0x72, 0x00, 0x00, 0x00, 0xE6, 0xFF, 0xFF, 0xFF, 0x52, 0x00, 0x00, 0x00, 0x8C, 0xFF, 0xFF, 0xFF, 0xF2, 0xFF, 0xFF, 0xFF, 0xD4, 0xFF, 0xFF, 0xFF, 0xA6, 0xFF, 0xFF, 0xFF, 0x0A, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0xA6, 0xFF, 0xFF, 0xFF, 0x9C, 0xFF, 0xFF, 0xFF, 0x86, 0xFF, 0xFF, 0xFF, 0x24, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0xD4, 0xFF, 0xFF, 0xFF, 0x22, 0x00, 0x00, 0x00, 0xB6, 0xFF, 0xFF, 0xFF, 0x14, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0xCE, 0xFF, 0xFF, 0xFF, 0xAC, 0xFF, 0xFF, 0xFF, 0x14, 0x00, 0x00, 0x00, 0x6A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0xE4, 0xFF, 0xFF, 0xFF, 0xE4, 0xFF, 0xFF, 0xFF, 0xE4, 0xFF, 0xFF, 0xFF, 0x1E, 0x00, 0x00, 0x00]for i in range(32): for j in range(0x100): if i<=16: if i>=16: a=j^4 else: if opcode[i*4]==1: a=j^9 else: a=j-2 else: if opcode[i*4]==1: a=j^6 else: a=j-5 v2=0 v3=0 v4=7 a2=8 while v3>v3)&1)<
ezr3
by Blu3e
拖进ida,看见函数很少,于是拖进winhex,看见了类似UPX的标志全部改成UPX,然后脱壳把得到的程序拖进ida,看见了两个可疑函数p和v在主函数里面也能找到这两个函数的调用并且没有其他条件,那么我们直接逆先逆v做了异或操作,逆一下是这样的
v2 = 0for i in range(0,len(auth),6): for j in range(6): auth[i + j] ^= mere[v2+j*12] v2 += 2
再逆p,先进行了一次对前四位和后四位的转换,然后进行异或,最后进行验证逆向脚本如下
v2 = 0for i in range(0,len(auth),6): for j in range(6): flag.append(auth[i + j]//mere[(v2+j*6)*2]) v2 += 1for i in range(len(flag)): flag[len(flag)-1-i] ^= flag[i] flag[len(flag)-1-i] = (flag[len(flag)-1-i]>>4|flag[len(flag)-1-i]<<4)&0xff
所以总的脚本如下
auth = [0x0003BC69, 0x000D3FA0, 0x0003A94A, 0x00044AFF, 0x00045254, 0x0000CDD1, 0x00001815, 0x00003B08, 0x00070868, 0x000C6560, 0x00065662, 0x000855C8, 0x0000DCF6, 0x00004CE6, 0x0014EEC2, 0x0002CFD6, 0x00032766, 0x0014F6BA, 0x00025E69, 0x0006A9A3, 0x00121EBD, 0x0005991C, 0x00050016, 0x00004A3D, 0x00097485, 0x0008D0A0, 0x0003B916, 0x00054C58, 0x00096F94, 0x00010334, 0x000DAD22, 0x0004B234, 0x0002FE96, 0x000F33CC, 0x0012C1E8, 0x00148F9E]mere = [0x00000D21, 0x00000000, 0x0000009D, 0x00000000, 0x0000094B, 0x00000000, 0x000003C9, 0x00000000, 0x00000C3F, 0x00000000, 0x000017E9, 0x00000000, 0x0000130E, 0x00000000, 0x00000088, 0x00000000, 0x00000486, 0x00000000, 0x0000202F, 0x00000000, 0x00002230, 0x00000000, 0x000024B4, 0x00000000, 0x000008B1, 0x00000000, 0x00000A9F, 0x00000000, 0x00001AD2, 0x00000000, 0x000023EB, 0x00000000, 0x00000C7E, 0x00000000, 0x0000042B, 0x00000000, 0x000005BF, 0x00000000, 0x0000113C, 0x00000000, 0x00000449, 0x00000000, 0x00001751, 0x00000000, 0x00000ACE, 0x00000000, 0x00001894, 0x00000000, 0x0000208A, 0x00000000, 0x00000E82, 0x00000000, 0x000006BD, 0x00000000, 0x00000CEE, 0x00000000, 0x00002386, 0x00000000, 0x000013D4, 0x00000000, 0x00000111, 0x00000000, 0x00000D1C, 0x00000000, 0x0000238E, 0x00000000, 0x00001759, 0x00000000, 0x0000012B, 0x00000000, 0x0000214D, 0x00000000, 0x00000040]v2 = 0flag = []for i in range(0,len(auth),6): for j in range(6): auth[i + j] ^= mere[v2+j*12] v2 += 2v2 = 0for i in range(0,len(auth),6): for j in range(6): flag.append(auth[i + j]//mere[(v2+j*6)*2]) v2 += 1for i in range(len(flag)): flag[len(flag)-1-i] ^= flag[i] flag[len(flag)-1-i] = (flag[len(flag)-1-i]>>4|flag[len(flag)-1-i]<<4)&0xffprint(bytes(flag))
babythread
by ATC Team
进入main函数,查看,发现是一个RC4调试不动,查看TLS回调函数里有反调试,去掉然后进行调试,找到RC4的密文Buf2和密钥v12dump下来后写脚本,这个是RC4脚本
def KSA(key): key_length = len(key) S = list(range(256)) j = 0 for i in range(256): j = (j + S[i] + key[i % key_length]) % 256 S[i], S[j] = S[j], S[i] return Sdef PRGA(S): i = 0 j = 0 while True: i = (i + 1) % 256 j = (j + S[i]) % 256 S[i], S[j] = S[j], S[i] K = S[(S[i] + S[j]) % 256] yield Kdef RC4(key): S = KSA(key) keystream = PRGA(S) return keystream# 使用示例if __name__ == "__main__": key = [0x01, 0xE5, 0xD5, 0x40, 0xC3, 0xD5, 0x76, 0x36, 0xFE, 0x66, 0x2D, 0x05, 0xC9, 0xFB, 0x50, 0xE7] Buf1 = [0xDE, 0x1C, 0x22, 0x27, 0x1D, 0xAE, 0xAD, 0x65, 0xAD, 0xEF, 0x6E, 0x41, 0x4C, 0x34, 0x75, 0xF1, 0x16, 0x50, 0x50, 0xD4, 0x48, 0x69, 0x6D, 0x93, 0x36, 0x1C, 0x86, 0x3B, 0xBB, 0xD0, 0x4C, 0x91] # 解密 plaintext2 = bytearray() keystream = RC4(key) for b in Buf1: plaintext2.append(b ^ next(keystream)) # 异或操作 print(plaintext2)