解决卡巴斯基实验室的难题

一天的天气好, 电报中的不同渠道开始向LK的骗子链接 ,成功完成任务的人将被邀请接受采访! 。 经过这么大声的发言,我想知道相反的困难有多困难。 我如何解决此任务的方法可以在裁减下阅读(很多图片)。

到家后,我再次仔细阅读了作业,下载了档案文件,然后开始查看里面的内容。 在里面是:



我们启动x64dbg,解压后转储,看看里面到底是什么:





我们从命令行参数中获取文件名->打开,读取->第一步加密->加密第二步->写入新文件。

很简单,是时候考虑加密了。

让我们从stage1开始


在地址0x4033f4处,有一个我称为crypt_64bit_up的函数(稍后您将了解原因),它是从stage1内部某个循环调用的



反汇编结果有点歪



最初,我试图用python重写相同的算法,将其杀死了几个小时,结果却是这样的(名称中应该清楚get_dword和byteswap)

def _add(x1, x2): return (x1+x2) & 0xFFFFFFFF def get_buf_val(t, buffer): t_0 = t & 0xFF t_1 = (t >> 8) & 0xFF t_2 = (t >> 16) & 0xFF t_3 = (t >> 24) & 0xFF res = _add(get_dword(buffer, t_0 + 0x312), (get_dword(buffer, t_1 + 0x212) ^ _add(get_dword(buffer, t_2+0x112), get_dword(buffer, t_3+0x12)))) # print('Got buf val: 0x%X' % res) return res def crypt_64bit_up(initials, buffer): steps = [] steps.append(get_dword(buffer, 0) ^ byteswap(initials[0])) # = z steps.append(get_buf_val(steps[-1], buffer) ^ byteswap(initials[1]) ^ get_dword(buffer, 1)) for i in range(2, 17): steps.append(get_buf_val(steps[-1], buffer) ^ get_dword(buffer, i) ^ steps[i-2]) res_0 = steps[15] ^ get_dword(buffer, 17) res_1 = steps[16] print('Res[0]=0x%X, res[1]=0x%X' % (res_0, res_1)) 

但是后来我决定注意常数0x12、0x112、0x212、0x312(没有十六进制18、274、536……与异常情况不太相似)。 我们尝试在Google上搜索它们,并找到一个具有加密和解密功能的完整存储库(提示:NTR),这是好运。 我们尝试在原始程序中使用随机内容对测试文件进行加密,将其转储并使用小的脚本对同一文件进行加密,一切应该正常工作,并且结果应该相同。 之后,我们尝试对其解密(我决定不做详细介绍,而只是从源代码处复制并粘贴解密功能)

 def crypt_64bit_down(initials, keybuf): x = initials[0] y = initials[1] for i in range(0x11, 1, -1): z = get_dword(keybuf, i) ^ x x = get_buf_val(z, keybuf) x = y ^ x y = z res_0 = x ^ get_dword(keybuf, 0x01) # x - step[i], y - step[i-1] res_1 = y ^ get_dword(keybuf, 0x0) return (res_1, res_0) def stage1_unpack(packed_data, state): res = bytearray() for i in range(0, len(packed_data), 8): ciphered = struct.unpack('>II', packed_data[i:i+8]) res += struct.pack('>II', *crypt_64bit_down(ciphered, state)) return res 

重要说明:存储库中的密钥与程序中的密钥不同(这是很合逻辑的)。 因此,在密钥初始化之后,我只是将其转储到文件中,这是buffer / keybuf

我们转到第二部分


一切都变得更加简单:首先,创建一个唯一字符数组,大小为0x55字节,范围为(33,118)(可打印字符),然后将32位值打包到先前创建的数组中的5个可打印字符中。





由于创建上述数组时没有随机性,因此每次程序启动时,该数组都是相同的,我们在初始化后将其转储,并可以使用简单的函数解压缩stage_2

 def stage2_unpack(packed_data, state): # checked! res = bytearray() for j in range(0, len(packed_data), 5): mapped = [state.index(packed_data[j+i]) for i in range(5)] res += struct.pack('>I', sum([mapped[4-i]*0x55**i for i in range(5)])) return res 

我们做这样的事情:

 f = open('stage1.state.bin', 'rb') stage1 = f.read() f.close() f = open('stage2.state.bin', 'rb') stage2 = f.read() f.close() f = open('rprotected.dat', 'rb') packed = f.read() f.close() unpacked_from_2 = stage2_unpack(packed, stage2) f = open('unpacked_from_2', 'wb') f.write(unpacked_from_2) f.close() unpacked_from_1 = stage1_unpack(unpacked_from_2, stage1) f = open('unpacked_from_1', 'wb') f.write(unpacked_from_1) f.close() 

我们得到结果

Source: https://habr.com/ru/post/zh-CN431690/


All Articles