题目来源至 https://www.malwaretech.com/beginner-malware-reversing-challenges
所有挑战都是在不使用调试器的情况下完成的,你的目标应该是能够在不运行exe的情况下完成每个挑战。
ransomware1
勒索解密,难度等级1星。
题目说是一个脚本小子写的勒索软件,问能否解密flag.txt文件?
仅为静态分析,不需要使用调试器。
下载解压完如图:
文件夹为加密过的文件,exe为加密程序demo。
先分析exe文件,使用IDA打开。
自动识别了start程序,进入看看。
进入sub_401000
之前已分析过,所以已经做了些注释与重命名。
这个函数有两个参数,通过API可知,有打开文件与写入文件的操作,这里应该就是加密的核心了。
查snprintf函数的四个参数,结合已经加密的文件特征可以知道a1为需要加密的原始文件的文件名,这里的作用仅仅是拼接字符串作为加密后的文件名。
接下来的CreateFileA函数是打开已经存在的文件,第二个CreateFileA函数是新建一个文件。
do while循环里第一步先检查读取文件时是否成功,如果成功读取4096个字节则执行for循环。
for循环循环的次数为ReadFile实际读取的字节数v6,如果文件超过4096个字节,则v6第一次读取就为4096。
如果文件小于4096个字节,则v6为实际文件的大小。
for循环里有个参数a2未知,将a2的值加上i与0x20的取模运算后的结果再与当前文件从文件开头的第i个字节的值进行异或,
最后的结果再赋值到源位置里。
循环4096次后,就结束循环。最后关闭文件句柄,退出。
加密的原理是对文件的前4096个字节进行计算后重新赋值,如果文件小于4096就对整个文件内容进行处理再在对应位置赋值。
问题的关键是a2的值是什么?
第一次不使用a2,直接对flag.txt进行处理,发现打开后是乱码,说明解密不成功。
这里的话确实要发挥脑洞了,压缩包里给了两类文件,一类是加密后的图片,一类是存在flag的txt文件。
先看图片文件,发现是英文命名的,后缀都为jpg格式。既然a2的值是固定的,加上jpg格式都是有一定特征的,那么如果这些jpg文件里有部分内容是一样的话,说明就可以通过再进行异或运算得到a2这个key的值。
使用Beyond Compare依次打开这些图片,然后一一比较,发现前22个字节是一致的(这里以为找到了突破口,发现却不是)。
说明图片是突破口,然后弄了半天没有发现如果找到图片开头的特征码,因为每个jpg文件好像除了开头两个字节是特征码之外,其余的字节不一定是一致的,我陷入了无解中。
然后突然觉得这个很难解密了,因为无法知道a2的值到底是什么。
带着怀疑就复制加密后的文件名Chrysanthemum去谷歌搜索下,发现了原来是Win7 自带的壁纸图片,啊啊啊,确实不能放过任何信息。
突然醒悟,或许这就是突破口,马上打开Win7寻找原始的壁纸图片,编辑器打开,与加密后的文件进行对比。
源壁纸文件如下图:
加密后的壁纸文件如下图:
最后,通过上述两个图片里前4096个字节的每个字节进行异或运算后得到规律发现a2的取值是一个字节数组。
key = [
0x6E, 0xF7, 0x9B, 0x0E, 0x45, 0x55, 0x5E, 0x95,
0x96, 0xFE, 0xAB, 0x75, 0x80, 0xB4, 0x0E, 0x40,
0x3D, 0xF5, 0xA7, 0x1B, 0xED, 0xD5, 0x5B, 0x80,
0xA9, 0xD3, 0x8D, 0x2C, 0xB8, 0x0A, 0x40, 0x0F
]
并且经过32个字节运算后,会重复这个过程,直到处理的字节数达到4096个。
得到key值后,可以通过之前逆出的加密流程对flag.txt_encrypted进行解密了。
解密脚本如下:
# coding:utf-8
key = [
0x6E, 0xF7, 0x9B, 0x0E, 0x45, 0x55, 0x5E, 0x95,
0x96, 0xFE, 0xAB, 0x75, 0x80, 0xB4, 0x0E, 0x40,
0x3D, 0xF5, 0xA7, 0x1B, 0xED, 0xD5, 0x5B, 0x80,
0xA9, 0xD3, 0x8D, 0x2C, 0xB8, 0x0A, 0x40, 0x0F
]
decrypted = ''
file_name = "flag.txt_encrypted"
with open(file_name, 'rb') as f:
encrypted = f.read()
for i in range(len(encrypted)):
decrypted += chr(encrypted[i] ^ key[i % 0x20])
with open(file_name.replace('_encrypted', ''), 'w') as f:
f.write(decrypted)
print(decrypted)