NewDriver
本题主要涉及base64加密和RC4加密的知识
拿到一个PE文件,运行之后是个控制台程序,简单的要求输入flag,然后判断是否正确,无壳。
用32位IDA打开,找到main函数,由于栈帧不平衡无法反编译,可以修改堆栈指针使其平衡然后进行反编译,不过该题主函数逻辑不复杂,可以直接看汇编代码。
直接来到开始输入的指令位置
文章图片
显然,var_38便是用来存储输入的变量
文章图片
然后是一段计算输入长度的指令,输入长度必须为0x21,之后让输入作为参数调用一个函数,跟进这个函数,发现十分复杂,用xdbg调试后发现,调用该函数后,产生了非常像base64编码的字段,姑且先认为它就是base64加密函数吧。
文章图片
这里var_138在最开始初始化为一段字符串flag{this_is_not_the_flag_hahaha}。计算var_138的长度,然后调用sub_401000函数,由于这个函数的参数分别是一段缓冲区地址,var_138以及它的长度,与我们的输入无关,功能也是为这段缓冲区赋值,所以得到的一定是定值,可以在调试器中查看
【安恒月赛杯9月逆向】
文章图片
esi中存储的是输入经过base64加密的字符串首地址,这段代码将它和它的长度作为参数调用了sub_4010e0函数,该函数还有一个参数是var_238,大概猜到函数功能就是以var_238为密钥对经过base64加密的字符串再次加密,看到flag之后才知道这个加密函数是RC4加密
文章图片
最后就是将再次加密的数据与byte_402104处的明文进行比较啦。
总结一下流程:
- 对输入进行base64加密
- 以固定明文生成密钥
- 使用密钥对数据再次加密
- 将生成的密文与正确的密文进行比较
文章图片
逆向加密算法得到解密脚本,这里s是密文,key是密钥
文章图片
解密得到flag的base64的形式 ZeptZ3l5UHQra25nd19yYzMrYR5wX2Jtc2P2VF9gYNM9。
若本题使用的是标准base64,那通过常用工具或命令行就可以直接得到答案,但本题修改了base64的编码表,置换了一些字符的位置,进入base64加密函数中可以看到给出的编码表为ABCDEFGHIJSTUVWKLMNOPQRXYZabcdqrstuvwxefghijklmnopyz0123456789+/
所以这里我们手写base64的解密脚本。
base64的加密方式是以24位为一个缓冲区,每次加密3个字节,将3个字节分为4个6位二进制数作为4个索引,然后通过索引得到编码表的映射。相对的,解密脚本就是以4个字符为一组,映射成索引,然后组合成24位,再分为3字节即可解密。脚本如下(写得真丑):
文章图片
然后以4个字符为一组对ZeptZ3l5UHQra25nd19yYzMrYR5wX2Jtc2P2VF9gYNM9进行解密就可以得到flag辣
GodDriver
本题主要涉及rot13加密和解矩阵乘法
和第一题相同,ida依旧无法反编译主函数,不过同样主函数的逻辑比较清晰,可以直接看汇编代码。
分析下来主函数大概做了几件事:
- 从标准输入流读入flag
- 创建管道和子进程使父进程能与其相互通信
- 在子进程中将flag作为参数调用ck1函数
- 将ck1的返回值发送到父进程
- 父进程接收数据,调用ck2,ck3,ck4三个函数
- 根据ck4的返回值来判断输入的正确性
文章图片
先初始化a3这个二维数组,然后一个三重的嵌套循环给a3赋值,实际上这就是两个矩阵相乘然后把结果赋给a3的算法。这里a3是已知的,就是那段密文,a1也是已知的,那么通过解这个矩阵乘法就可以得到a2,而a2就是经过ck1的flag再经过ck2处理后得到的,于是再看ck2
文章图片
f5出来这一句很迷,直接看汇编,循环体内部是这样的
文章图片
乍看之下也很奇怪,但细看之后发现它就是一个复制的功能,也就是说输入的经过ck1的flag会直接复制到一个缓冲区中作为ck3的a2参数,最后就只剩ck1函数了
文章图片
这里都不用仔细看,看到什么小于a大于z,又是加13又是减13的肯定就是rot13了,就是以13为步长的移位加密。
至此,所有加密过程都已知了,根据这些过程写出解密脚本就好了,rot13可以直接写,而解矩阵乘法可以用微软的z3库比较容易地得到结果(算法大佬绕道),最后附上脚本
from z3 import *def bytes_to_dwords(str):
result = []
str = list(str)
for i in range(len(str)):
str[i] = ord(str[i])
for i in range(0, len(str), 4):
s = str[i:i+4]
n = s[3]
n = n << 8
n += s[2]
n = n << 8
n += s[1]
n = n << 8
n += s[0]
result.append(n)
return resultdef rot13(s):
flag = ''
lenth = len(s)
for c in s:
tmp = ord(c) + 13
if c.isupper():
if tmp > 90:
tmp = tmp - 26
elif c.islower():
if tmp > 122:
tmp = tmp - 26
else:
tmp = ord(c)
flag += chr(tmp)
return flagf = open('GodDriver', 'rb')
data = https://www.it610.com/article/f.read()
f.close()
flag_table = data[0x1160:0x1260]
box = data[0x1060:0x1160]
flag_table = bytes_to_dwords(flag_table)
box = bytes_to_dwords(box)
buf1_x = [BitVec('flag%d' % i, 16) for i in range(8 * 8)]
s = Solver()
k = 0
while True:
if k >= 8:
break
for l in range(8):
sum = 0
for m in range(8):
sum += box[8 * k + m] * buf1_x[8 * m + l]
s.add(sum == flag_table[8 * k + l])
k += 1buf1 = []
if (s.check() == sat):
m = s.model()
for i in range(64):
buf1.append(m[buf1_x[i]].as_long())
for i in range(len(buf1)):
buf1[i] = chr(buf1[i] & 0Xff)
flag = ''.join(buf1)print rot13(flag)
推荐阅读
- 解护网杯一道web(EasyChallenge)
- ctf|ctf-htctf-misc
- C++|一些关于程序内存布局的问题
- QCTF 2018xman夏令营选拔赛
- 第一届桂林电子科技大学绿盟杯CTF大赛 wp
- Capture the flag
- CTF|BUUOJ [2019红帽杯]easyRE
- Buuctf -web wp汇总(二)
- #|CTF-网络信息安全攻防学习平台(脚本关)
- ctf