安恒月赛杯9月逆向

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以及它的长度,与我们的输入无关,功能也是为这段缓冲区赋值,所以得到的一定是定值,可以在调试器中查看

esi中存储的是输入经过base64加密的字符串首地址,这段代码将它和它的长度作为参数调用了sub_4010e0函数,该函数还有一个参数是var_238,大概猜到函数功能就是以var_238为密钥对经过base64加密的字符串再次加密,看到flag之后才知道这个加密函数是RC4加密

最后就是将再次加密的数据与byte_402104处的明文进行比较啦。

总结一下流程:

  1. 对输入进行base64加密
  2. 以固定明文生成密钥
  3. 使用密钥对数据再次加密
  4. 将生成的密文与正确的密文进行比较

首先已知的是密文,且密钥也可通过动态分析得到,所以通过逆向加密算法我们就可得到经base64加密的flag。进入加密函数中,

逆向加密算法得到解密脚本,这里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的返回值来判断输入的正确性

要得到flag,先从ck4入手,这个函数很简单,就是将两个二维数组进行比较,看是否相等,一个是该函数的参数,另一个是一段全局变量的数据,想必这就是最后的密文了,只要根据前面的函数还原出解密算法,就能得到最后的flag了。再看ck3,

先初始化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 result

def 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 flag

f = open('GodDriver', 'rb')
data = 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 += 1

buf1 = []
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)

猜你喜欢

转载自blog.csdn.net/qq_35713009/article/details/86603771