本帖最后由 whklhh 于 2017-12-24 21:51 编辑
挑战:《恶意软件分析》
赛题背景: 员工小A收到了一封邮件,带一个文档附件,小A随手打开了附件。随后IT部门发现小A的电脑发出了异常网络访问请求,进一步调查发现小A当时所打开的附件其实是一个伪装成word文档的恶意可执行文件。
赛题描述: 请在试着分析evil.exe和其所下载的x.jpg, 从中找出key.
评分标准: 密钥正确则可进入下一题。
打开x.jpg查看一下,发现是乱码
那么还是分析evil.exe吧
首先查壳,ExeInfoPE认为有可能是UPX
拿UPX脱壳失败,只能乖乖手脱
ESP定律轻松解决,dump下来拖入IDA进行分析
首先可以确定它进行了联网,那么一定调用了相关的函数
到Imports导入函数列表查看
最下面几个InternetOpenUrl很明显就是连接网络的函数,跟过去
发现确实是在下载x.jpg
查看调用,发现在WinMain函数中
下载的内容放在v8中,根据指针可以发现在Decrypt函数中引用了它
发现在Decrypt函数中进行了异或解码,异或的值来自于v6,也就是InitKey函数中由常数0x4A8754F5745174进行初始化的Key数组
初始化过程就是从低向高循环取1个字节再加i
生成长度为256的表
解码过程中还进行了对Key的变换,来进一步增加难度。不过由于提供的是解码函数,因此只需要照样操作即可
之后在ExecShellcode函数中,再次对data进行了一次异或解码
data[i] ^= data[i]+i
最后直接跳转执行
最简单的方法就是修改Dns,搭建本地服务器来传递x.jpg,在函数中正常解码,通过动态调试来查看Shellcode
复杂一点的方法就是重现算法,解码x.jpg并反汇编Shellcode
前者除了搭服务器麻烦点外其他都很简单,正常下断点调试即可,因此下面给出后者的脚本
# InitKey
a = 0x4A8754F5745174
key = [0 for i in range(8)]
for i in range(256):
key.append((((a>>(i%8*8))+i)&0xff))
f = open("x.jpg", "rb")
data = f.read()
f.close()
# Decrypt
new_data = b""
j = 0
print(data)
for ii in range(len(data)):
i = (ii+1)%256
j = (key[`i] + j) % 256
key[`i], key[j] = key[j], key[`i]
new_data += bytes((((data[ii] ^ key[(key[`i] + key[j]) % 256])^ii)%256, ) )
print(new_data)
f = open("decrypt.jpg", "wb")
f.write(new_data)
f.close()
这样就能得到Shellcode了
十六进制查看发现有明文字符串
每4个字符前有一个0x68,即汇编的push
并且由于push一次只有4个字符,因此顺序还有点反人类
再写下脚本提取(续在刚才的脚本之后)即可
flag = []
i = 0
while(i<len(new_data)):
if(new_data[`i]==0x68):
flag.append(new_data[i+1:i+5])
i += 3
i += 1
print(flag[::-1])
for i in flag[::-1]:
print(str(i)[2:-1], end='')
ShellCode分析
将Shellcode复制到OD随便一段空白处中进行分析
注意跳转执行的时候是从第二个字节开始,第一个字节0xEE是没有用的
右击第二个字节,设置EIP进行执行
可以发现它动态获取Kernel32.dll和通过LoadLibrary函数加载MessageBox和ExitPorcess函数
从43DD11开始
TEB(线程环境块)→PEB(进程环境块)→_PEB_LDR_DATA→InInitializetionOrderModuleList
通过双向链表遍历加载的模块,最终取到kernel32.dll的入口,然后进入下一个代码块加载函数
最前面几行是初始化,之后push 0xEC0E4E8E这个硬编码,再push edx,即kernel32.dll的入口点,以这两个参数调用43DD2D取函数地址
这个函数里面通过参数1入口点来遍历模块内的所有函数,将函数名进行hash(逐字符相加并循环右移13位)后与参数2的硬编码比较,符合则证明是需要的函数,保存地址后退出
通过这个函数分别取到LoadLibraryA、ExitProcess和MessageBoxA,并通过LoadLibraryA加载后两个函数
然后push字符串,调用MessageBoxA显示成功提示,最后Exit结束
|