ransomeware - writeup
题目来源 http://reversing.kr
题目知识点:upx + 花指令 + 堆栈不平衡 + exe特征码提取key
前言
文章只是记录一下自己在reversing.kr上学习CTF逆向的经历,如果文中出现什么技术错误,烦请各位大佬,在评论中指正。本人技术刚刚入门,菜鸟一枚,大佬勿喷啊~
正文
首先在网站上下载附件,得到一个zip,里面包含了一个txt、一个exe和一个file。根据txt里面的提示,可以得到exe为加密程序,file为加密后的文件,并且file在加密前应该是一个exe文件。
接下来我就对exe文件进行了分析,使用PEID进行查壳发现,该exe使用了UPX进行加壳,这里大家可以使用ESP定律进行手工脱壳,而我嫌弃麻烦,直接使用UPX工具进行了脱壳,结果如下图。
在经过脱壳之后,exe文件就可以使用IDA进一步分析,但是不巧的是,在对main函数进行反编译时,出现了情况。
是的,你没看错,IDA意思是:“这个函数太大了,劳资分析不了”。
what?还有这种操作?作为一位菜鸟,还真是第一次看到IDA报这种错误。既然分析不了,那就去看看main函数的汇编代码吧。
好吧,出题人,!#@&%……#%,你开心就好啦!在main函数里面充斥了0x37195的无用代码,也可以称之为花指令,反正就是阻止IDA对其进行反编译。这里有两个思路,第一呢,使用nop指令,将大小为0x37195的指令进行替换,但是我没有选择这么做,我使用第二种方法,把main函数的起始地址进行了重新指定。既然我已经知道0x37195的数据全部是无用的,那我直接选择跳过去。如何改函数的起始地址?看下图。在IDA的function window中右键点击你想要改的函数,选择edit function就好。然后在start address填入你想要让函数起始的地址。这里是0044a775地址。
然后你是不是以为就可以F5大法了,不存在的大兄弟,你都把人家函数起始地址给改了,最后函数的堆栈极有可能是不平衡的。这不,果然是。
这里呢,就直接去调堆栈,让其平衡就好。option
-> General...
-> Stack pointer
。然后就出现了下图中红色方框中的标识。
然后我们根据IDA报错中提到的地址,将其retn指令前面的数据调节至0即可实现堆栈平衡。这里调节,需要找距离其最近的call指令,如图中箭头所指。将光标放置在该指令上,使用快捷键alt+k
。
通过改变箭头指向的数值,将retn指令前面的数值调整为0。这里我好像用的是-0x34
。然后就可以进行F5了。
好了,上面就是分析了,感觉很简单,但是,仔细想了一下,这个key值是出题人输入的,原始数据我们也没有,我们只有加密后的数据。这怎么实现逆向操作。那么小技巧来了?(圈起来,要考!)。相信大家都使用hex工具查看过exe文件。会发现,每个exe中都存在一个共同点。
上图中红框大家是不是很熟悉?那么这个题就根据这个来突破。exe中的这个数据位置是固定的,也就是说根据一个普通的exe文件该段数据的定位,我们可以找到加密后该段数据对应的密文数据。如下图。
如果我们用来加密的key值,并不是很长,在加密这段数据时发生了重复,那么我们就可以获取完整的key。我们直接取加密后的文件对应位置的16进制,进行异或操作。不多说了,用python跑了。
st1 = [0x54,0x68,0x69,0x73,0x20,0x70,0x72,0x6F,0x67,0x72,0x61,0x6D,0x20,0x63,0x61,0x6E,0x6E,0x6F,0x74,0x20,0x62,0x65,0x20,0x72,0x75,0x6E,0x20,0x69,0x6E,0x20,0x44,0x4F,0x53,0x20,0x6D,0x6F,0x64,0x65] st2 = [0xC7,0xF2,0xE2,0xFF,0xAF,0xE3,0xEC,0xE9,0xFB,0xE5,0xFB,0xE1,0xAC,0xF0,0xFB,0xE5,0xE2,0xE0,0xE7,0xBE,0xE4,0xF9,0xB7,0xE8,0xF9,0xE2,0xB3,0xF3,0xE5,0xAC,0xCB,0xDC,0xCD,0xA6,0xF1,0xF8,0xFE,0xE9] for i in range(len(st1)): print chr((~st2[i] ^ st1[i]) % 256),
得出用户输入的key为letsplaychess
。使用key对加密后的文件进行解密操作。脚本如下。
key = "letsplaychess" f = open("./ransomware/file","rb") data = f.read() fr = open("./ransomware/file.exe", "wb") for i in range(len(data)): fr.write(chr(ord(data[i]) ^ 0xFF ^ ord(key[i % len(key)]) % 256)) #小技巧,在进行取反的逆运算时,可以使用~,也可使用 ^ 0xFF f.close() fr.close()
最终得到加密前的exe文件。然后我本来想着运行就可以得到flag。但是缺少dll文件,我嫌弃下载太麻烦,就把生成的文件拖进IDA进行分析来着。结果又加了UPX的壳。行吧,我忍,脱壳,分析拿到flag。
后记
这道题目,其实仔细分析下来,并不是很难的一个题目,但是涉及的知识点还是可以的,如果再讲算法设计复杂一下,估计会更恶心。不过通过本道题目,我真是学习到了一些东西。
1、通过改函数起始地址,绕过花指令。
2、堆栈平衡。
3、exe文件中的特征值(应该不算exe的特征值吧,先这么叫着。哈哈),猜解key。
纯属个人学习经历,真的是很菜的知识。希望大家路过觉得可以,就留下来看看。感谢!
原文地址:https://www.cnblogs.com/0x1633/p/11364930.html