题目描述如下:
赛题背景: 员工小A收到了一封邮件,带一个文档附件,小A随手打开了附件。随后IT部门发现小A的电脑发出了异常网络访问请求,进一步调查发现小A当时所打开的附件其实是一个伪装成word文档的恶意可执行文件。
赛题描述: 请在试着分析evil.exe和其所下载的x.jpg, 从中找出key.
评分标准: 密钥正确则可进入下一题。
主要附件为一个evil.exe程序和一个x.jpg.点击evil.exe运行后发现生成了一个evil.docx的文档(附加:要交的flag为邮箱地址!)
一开始思路以为是会有类似于与dll注入的现象,后来使用PEview发现并没有可疑的dll,随后用正常思路分析
①使用exeinfope查看该exe文件发现说有三个节区像是被upx压缩,使用upx解压缩失败
②使用ollydebug动态调试找到OEP,并脱壳
程序入口点在0043dc85处,继续调试会发现要经历eax(1190)次才能运行到0043dca3 即jmp evil.043dab0处(我最开始调试不用这么多次的!!!不知道为什么后来就是这么多次了,有试着改汇编代码让它直接跳过去,后来不行!!!这部分也是很关键的部分,f9运行到断点处时会在retn停下来,呀呀呀,只能能不停按了)
2)运行到0043dca3处,执行跳到43dab0处,发现
执行完pushad操作后,在相应的栈地址处设置硬件断点(图里面不小心多运行了几步>^<,不过问题不大,设置断点的操作是一样的)
设置完断点后,直接f9件运行,程序会在执行popad访问到设置断点的地址后自动停下来,在其之后的jmp指令跳到的地方,也就是oep处
OEP处如下:
此时使用od的dump即可成功脱壳!
③使用ida打开脱壳后的文件,f5反编译进入主函数,代码片段如下:
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { void *v5; // ST10_4 char v6; // [esp+4h] [ebp-118h] size_t dwSize; // [esp+114h] [ebp-8h] void *v8; // [esp+118h] [ebp-4h] if ( sub_401370(hInstance) == 6 ) return 0; sub_401620(); v8 = (void *)sub_4018F0(&dwSize); if ( v8 ) { if ( dwSize ) { v5 = malloc(dwSize); sub_401740(&v6, -176926348, 4884308);//Initkey sub_401800(&v6, v8, v5, dwSize);//decrypt sub_401220(v5, dwSize);//Execshellcode } free(v8); } return 0; }
逐个点击函数,sub_4018f0()函数如下:
可发现此函数通过使用InternetOpenUrlA()API函数从网站上下载x.jpg文件(也就是附件中所给处的文件),最后函数返回,v8为数据的首地址,dwsize为数据大小
④继续往下看,发现三个不知名函数(不晓得用途,猜测和要求的flag有关,之后实在有点不明所以,看writeup发现那个v6是key,函数名注释中给出),因此大概的流程就是根据x.jpg中的数据以及经过sub_401740函数(Initkey)给出的key来求出原本从网上下载来的数据。
⑤进入sub_401740(&v6, 0x4A8754F5745174)函数,如下:
这里求出了key的值,通过写脚本,我们也可以得到
⑥进入sub_401800(v6, (int)v8, (int)v5, dwSize);函数,如下:
此函数对下载文件中的内容进行了一轮异或运算。最终的结果放在了a3中,也就是主函数中的v5
⑦进入sub_401220(v5, dwSize);函数中,如下:
此函数对经过decrypt函数处理后的数据再进行了一次异或运算 ,因此到这里程序的运行流程就清楚了!
⑧写出脚本,如下:
a=open("D:Desktop做题文件8.4\rebuilt.3.Evil.exe\x.jpg","rb") b=a.read() print(b) a2=[] c=0x4A8754F5745174 v6=[] v6.append(0) v6.append(0) v4=[] for i in range(8): v4.append(c&0xff) c=c>>8 for i in range(256):#求出key值 x=i+v4[i%8] v6.append(x) #print(v6) d=open("D:Desktop做题文件8.4\dump.txt","wb") temp=b'' for i in range(len(b)): v6[0]=(v6[0]+1)%256 v6[1]=(v6[v6[0]+2]+v6[1])%256#这里要注意!IDA代码中类型从int转变为了int8类型 v4=v6[v6[0]+2] v5=v6[v6[1]+2] v6[v6[0]+2]=v5 v6[v6[1]+2]=v4 x=(b[i]^v6[(v5+v4)%256+2]^i)%256 print(hex(x),end=' ') temp+=bytes([x]) print(temp) d.write(temp)#将数据写入dump.txt文件中 d.close()
运行后,dump.txt中结果如下:
emmm感觉flag已经出来了哈但又不对劲,看了writeup说这是shellcode,里面的元数据0x68代表push,每个push后的数据就是我们的flag片段,因此写脚本可得出(注意数据在内存中的顺序为小端顺序!!!),这里还可以把数据在ollydebug中直接copy上去,od会将硬编码转换为看的懂的汇编代码,从中筛选处有push的,把数据结合起来一样是答案!
如下:
flag = [] i = 0 while(i<len(dump)): if(new_data[i]==0x68): flag.append(dump[i+1:i+5]) i += 3 i += 1 print(flag[::-1])#转换顺序 for i in flag[::-1]: print(str(i)[2:-1], end='')#去掉数据前的b'以及数据末尾的'
运行结果如下
到这里就得到了我们的flag!!!(过程艰辛!调试过程中,电脑还崩溃了>~<)