程序分析 - task4

程序流程

程序的起始点在.reloc段,应该是被改过的

image-20191031143539668

首先会进入与他相邻的sub_407012函数。


sub_407012函数

.reloc:00407012 sub_407012      proc near               ; CODE XREF: start+2↑p
.reloc:00407012
.reloc:00407012 arg_1C          = dword ptr  20h
.reloc:00407012
.reloc:00407012                 push    dword ptr fs:0
.reloc:00407018                 mov     fs:0, esp       ; 保存fs:0,并替换掉esp
.reloc:0040701E                 call    $+5
.reloc:00407023                 pop     ebp             ; ebp = 0x00407023,取得call指令eip的下一条地址
.reloc:00407024                 sub     ebp, 23h        ; ebp -= 0x23 (0x00407000)
.reloc:00407024                                         ; 通过固定偏移得到start函数地址
.reloc:00407027                 mov     eax, ebp        ; eax = ebp == 0x00407000
.reloc:00407029                 sub     eax, 7000h      ; 得到image_base = 0x00407000 - 0x7000 = 0x00400000
.reloc:00407029                                         ; 通过start函数与木马文件本身偏移计算出基地址
.reloc:0040702E                 mov     [ebp+77Eh], eax ; *(0x407000 + 0x77E) = eax = image_base
.reloc:00407034                 push    eax
.reloc:00407035                 add     eax, 3F00h      ; eax += 0x3F00 (0x403f00)
.reloc:00407035                                         ; 通过基地址相对运算得到运行的主函数
.reloc:0040703A                 mov     [ebp+241h], eax ; *(0x407000 + 0x241) = eax = main_func
.reloc:0040703A                                         ; 执行了类似于SMC的操作,修改了后面的一个跳转地址
.reloc:00407040                 xor     eax, eax
.reloc:00407042                 lea     edi, [ebp+78Eh] ; 得到一段什么都没有的地址(0x40778E)
.reloc:00407048                 stosd                   ; edi += 4
.reloc:00407049                 stosd
.reloc:0040704A                 stosd
.reloc:0040704B                 mov     [ebp+786h], eax
.reloc:00407051                 pop     eax             ; eax = image_base(0x400000)
.reloc:00407052                 mov     ebx, eax        ; ebx = eax = image_base
.reloc:00407054                 add     ebx, [eax+3Ch]  ; image_base + 0x3C = 0x40003C (100)
.reloc:00407054                                         ; 当前位置不在代码段,取到了PE文件的AddressOfNewExeHeader
.reloc:00407057                 mov     ebx, [ebx+80h]  ; 得到(0x400100 + 0x80) = 0x400180
.reloc:00407057                                         ; 这里是导入表的RVA
.reloc:0040705D                 add     ebx, eax        ; 计算得到导入表的地址
.reloc:0040705F
.reloc:0040705F loc_40705F:                             ; CODE XREF: sub_407012+7D↓j
.reloc:0040705F                 mov     esi, [ebx+0Ch]  ; 得到User32.dll的Name
.reloc:00407062                 or      esi, esi
.reloc:00407064                 jz      loc_4070F1      ; 获得返回地址(在kernel32上)
.reloc:0040706A                 add     esi, eax        ; 得到当前User32.dll的Name并做运算判断是否正确
.reloc:0040706C                 mov     ecx, [esi]
.reloc:0040706E                 and     ecx, 0DFDFDFDFh
.reloc:00407074                 cmp     ecx, 4E52454Bh  ; 为了取到KERNEL32的导入表信息项
.reloc:0040707A                 jnz     short loc_40708C ; 得到下一个导入表项的信息
.reloc:0040707C                 mov     ecx, [esi+4]
.reloc:0040707F                 and     cx, 0DFDFh
.reloc:00407084                 cmp     ecx, 32334C45h  ; EL32
.reloc:0040708A                 jz      short loc_407091 ; 得到程序kernel32.dll的导入表信息
.reloc:0040708C
.reloc:0040708C loc_40708C:                             ; CODE XREF: sub_407012+68↑j
.reloc:0040708C                 add     ebx, 14h        ; 得到下一个导入表项的信息
.reloc:0040708F                 jmp     short loc_40705F ; 得到User32.dll的Name
.reloc:00407091 ; ---------------------------------------------------------------------------
.reloc:00407091
.reloc:00407091 loc_407091:                             ; CODE XREF: sub_407012+78↑j
.reloc:00407091                 mov     [ebp+786h], ebx ; 得到程序kernel32.dll的导入表信息
.reloc:00407097                 mov     edx, [ebx]
.reloc:00407099                 or      edx, edx
.reloc:0040709B                 jz      short loc_4070F1 ; 获得返回地址(在kernel32上)
.reloc:0040709D                 add     edx, eax
.reloc:0040709F                 push    5
.reloc:004070A1                 pop     ecx
.reloc:004070A2
.reloc:004070A2 loc_4070A2:                             ; CODE XREF: sub_407012+B1↓j
.reloc:004070A2                 movzx   edi, word ptr [ebp+ecx*2+736h] ; 0x00407000 + 5 * 2 + 0x736 = *((WORD *)0x00407740)
.reloc:004070AA                 add     edi, ebp        ; edi += ebp (0x004075F0)
.reloc:004070AC                 push    ecx
.reloc:004070AD                 call    get_addr_from_self
.reloc:004070B2                 or      esi, esi        ; 判断esi是否存在,也就是是否获得了指针
.reloc:004070B4                 jz      short loc_4070C2 ; 跳转生效
.reloc:004070B6                 pop     ecx
.reloc:004070B7                 push    ecx
.reloc:004070B8                 dec     ecx
.reloc:004070B9                 shr     ecx, 1
.reloc:004070BB                 mov     [ebp+ecx*4+78Eh], esi ; *(0x0040778E + ecx * 4) = esi
.reloc:004070BB                                         ; 保存import table by name得到的API指针
.reloc:004070C2
.reloc:004070C2 loc_4070C2:                             ; CODE XREF: sub_407012+A2↑j
.reloc:004070C2                 pop     ecx
.reloc:004070C3                 loop    loc_4070A2      ; 0x00407000 + 5 * 2 + 0x736 = *((WORD *)0x00407740)
.reloc:004070C5                 mov     ecx, [ebp+78Eh]
.reloc:004070CB                 jcxz    loc_4070DB
.reloc:004070CE                 lea     eax, [ebp+599h]
.reloc:004070D4                 push    eax
.reloc:004070D5                 call    ecx
.reloc:004070D7                 or      eax, eax
.reloc:004070D9                 jnz     short loc_40711D
.reloc:004070DB
.reloc:004070DB loc_4070DB:                             ; CODE XREF: sub_407012+B9↑j
.reloc:004070DB                 mov     ecx, [ebp+792h]
.reloc:004070E1                 jcxz    loc_4070F1      ; 获得返回地址(在kernel32上)
.reloc:004070E4                 lea     eax, [ebp+5A2h]
.reloc:004070EA                 push    eax
.reloc:004070EB                 call    ecx
.reloc:004070ED                 or      eax, eax
.reloc:004070EF                 jnz     short loc_40711D
.reloc:004070F1
.reloc:004070F1 loc_4070F1:                             ; CODE XREF: sub_407012+52↑j
.reloc:004070F1                                         ; sub_407012+89↑j ...
.reloc:004070F1                 mov     eax, [esp+0Ch+arg_1C] ; 获得返回地址(在kernel32上)
.reloc:004070F5                 and     eax, 0FFFFF000h ; eax = a_kernel_addr
.reloc:004070F5                                         ; 间接获得kernel32上的一个特定地址
.reloc:004070FA                 push    32h
.reloc:004070FC                 pop     ecx
.reloc:004070FD
.reloc:004070FD loc_4070FD:                             ; CODE XREF: sub_407012+104↓j
.reloc:004070FD                 cmp     word ptr [eax], 5A4Dh ; 重复确定指针到达正确的位置
.reloc:004070FD                                         ; 貌似触发了异常,走了SEH,Handle为0x00407007
.reloc:00407102                 jnz     short loc_407111 ; 每次将指针 - 0x1000 直到得到正确kernel_base
.reloc:00407104                 mov     ebx, eax
.reloc:00407106                 add     ebx, [eax+3Ch]
.reloc:00407109                 cmp     dword ptr [ebx], 4550h
.reloc:0040710F                 jz      short loc_40711D
.reloc:00407111
.reloc:00407111 loc_407111:                             ; CODE XREF: sub_407012+F0↑j
.reloc:00407111                 sub     eax, 1000h      ; 每次将指针 - 0x1000 直到得到正确kernel_base
.reloc:00407116                 loop    loc_4070FD      ; 重复确定指针到达正确的位置
.reloc:00407116                                         ; 貌似触发了异常,走了SEH,Handle为0x00407007
.reloc:00407118                 jmp     loc_407237
.reloc:0040711D ; ---------------------------------------------------------------------------
.reloc:0040711D
.reloc:0040711D loc_40711D:                             ; CODE XREF: sub_407012+C7↑j
.reloc:0040711D                                         ; sub_407012+DD↑j ...
.reloc:0040711D                 mov     [ebp+782h], eax
.reloc:00407123                 cmp     dword ptr [ebp+796h], 0
.reloc:0040712A                 jnz     short loc_407178
.reloc:0040712C                 mov     ebx, [eax+3Ch]
.reloc:0040712F                 add     ebx, eax
.reloc:00407131                 mov     ebx, [ebx+78h]
.reloc:00407134                 add     ebx, eax
.reloc:00407136                 xor     ecx, ecx
.reloc:00407138                 mov     edx, [ebx+18h]
.reloc:0040713B                 mov     esi, [ebx+20h]
.reloc:0040713E                 add     esi, eax
.reloc:00407140
.reloc:00407140 loc_407140:                             ; CODE XREF: sub_407012+146↓j
.reloc:00407140                 xchg    eax, edi
.reloc:00407141                 lodsd
.reloc:00407142                 xchg    eax, edi
.reloc:00407143                 add     edi, eax
.reloc:00407145                 pusha
.reloc:00407146                 lea     esi, [ebp+5F0h]
.reloc:0040714C                 push    0Fh
.reloc:0040714E                 pop     ecx
.reloc:0040714F                 cld
.reloc:00407150                 repe cmpsb
.reloc:00407152                 popa
.reloc:00407153                 jz      short loc_40715F
.reloc:00407155                 inc     ecx
.reloc:00407156                 cmp     ecx, edx
.reloc:00407158                 jl      short loc_407140
.reloc:0040715A                 jmp     loc_407237
.reloc:0040715F ; ---------------------------------------------------------------------------
.reloc:0040715F
.reloc:0040715F loc_40715F:                             ; CODE XREF: sub_407012+141↑j
.reloc:0040715F                 mov     edx, [ebx+24h]
.reloc:00407162                 add     edx, eax
.reloc:00407164                 movzx   ecx, word ptr [edx+ecx*2]
.reloc:00407168                 mov     edx, [ebx+1Ch]
.reloc:0040716B                 add     edx, eax
.reloc:0040716D                 mov     edx, [edx+ecx*4]
.reloc:00407170                 add     edx, eax
.reloc:00407172                 mov     [ebp+796h], edx
.reloc:00407178
.reloc:00407178 loc_407178:                             ; CODE XREF: sub_407012+118↑j
.reloc:00407178                 lea     esi, [ebp+742h]
.reloc:0040717E                 lea     edi, [ebp+79Ah]
.reloc:00407184                 push    15h
.reloc:00407186                 pop     ecx
.reloc:00407187
.reloc:00407187 loc_407187:                             ; CODE XREF: sub_407012+193↓j
.reloc:00407187                 push    ecx
.reloc:00407188                 xor     eax, eax
.reloc:0040718A                 lodsw
.reloc:0040718C                 add     eax, ebp
.reloc:0040718E                 push    eax
.reloc:0040718F                 push    dword ptr [ebp+782h]
.reloc:00407195                 call    dword ptr [ebp+796h]
.reloc:0040719B                 stosd
.reloc:0040719C                 pop     ecx
.reloc:0040719D                 or      eax, eax
.reloc:0040719F                 jz      loc_407237
.reloc:004071A5                 loop    loc_407187
.reloc:004071A7                 lea     eax, [ebp+0A30h]
.reloc:004071AD                 push    eax
.reloc:004071AE                 push    104h
.reloc:004071B3                 call    dword ptr [ebp+7AEh]
.reloc:004071B9                 push    104h
.reloc:004071BE                 lea     eax, [ebp+92Ch]
.reloc:004071C4                 push    eax
.reloc:004071C5                 call    dword ptr [ebp+7AAh]
.reloc:004071CB                 lea     eax, [ebp+92Ch]
.reloc:004071D1                 push    eax
.reloc:004071D2                 call    sub_407286
.reloc:004071D7                 lea     eax, [ebp+0A30h]
.reloc:004071DD                 push    eax
.reloc:004071DE                 call    sub_407286
.reloc:004071E3                 mov     eax, [ebp+77Eh]
.reloc:004071E9                 mov     ebx, [ebp+786h]
.reloc:004071EF                 or      ebx, ebx
.reloc:004071F1                 jz      short loc_407237
.reloc:004071F3                 mov     edx, [ebx]
.reloc:004071F5                 or      edx, edx
.reloc:004071F7                 jz      short loc_407237
.reloc:004071F9                 add     edx, eax
.reloc:004071FB                 lea     edi, [ebp+70Eh]
.reloc:00407201                 call    get_addr_from_self
.reloc:00407206                 or      esi, esi
.reloc:00407208                 jz      short loc_407219
.reloc:0040720A                 lea     esi, [ebp+286h]
.reloc:00407210                 mov     edi, ecx
.reloc:00407212                 call    sub_407584
.reloc:00407217                 mov     [edi], esi
.reloc:00407219
.reloc:00407219 loc_407219:                             ; CODE XREF: sub_407012+1F6↑j
.reloc:00407219                 lea     edi, [ebp+723h]
.reloc:0040721F                 call    get_addr_from_self
.reloc:00407224                 or      esi, esi
.reloc:00407226                 jz      short loc_407237
.reloc:00407228                 lea     esi, [ebp+299h]
.reloc:0040722E                 mov     edi, ecx
.reloc:00407230                 call    sub_407584
.reloc:00407235                 mov     [edi], esi
.reloc:00407237
.reloc:00407237 loc_407237:                             ; CODE XREF: start+D↑j
.reloc:00407237                                         ; sub_407012+106↑j ...
.reloc:00407237                 pop     dword ptr fs:0
.reloc:0040723D                 pop     eax
.reloc:0040723E                 popa
.reloc:0040723F                 popf
.reloc:00407240                 mov     eax, offset unk_406F10
.reloc:00407245                 jmp     eax
.reloc:00407245 sub_407012      endp ; sp-analysis failed

该函数用到了call混淆的一种方式,不过这里主要是为了得到eip方便计算偏移以及改变之后新的绝对地址。


如果按照我的理解,这应该是病毒添加节区的方式,首先将自己的代码写进新的节区.reloc,之后更改文件的entrypoint,让文件运行的时候首先运行附加的新节区,运行新节区的时候会按照比较常用的方式获得kernel base image的地址,方便在运行的时候调用API

方式1(前一道题的方式):

image-20191031144304153

PEB struct --> PEB LDR DATA --> InIntializationOrderModuleList --> Flink --> kernel_base

方式2(这道题的方式):

通过获得EIP的值,减去固定的偏移得到了EntryPoint的地址,之后再减去EntryPointIMAGE_DOS_HEADER之间的偏移,就等于得到了PE文件最开头的地址,也就是Imagebase,并存储到了局部变量,后面会用到。


在这个程序里,通过Imagebase + 0x3F00计算出了一个函数地址,并覆盖了**.reloc**段的汇编代码中的地址(被覆盖的位置为0x00407241,这里就是SEH处理函数最后要走的地方,也就是真正该执行病毒代码的地方)

image-20191031145816345


通过Imagebase + 0x3C得到了结构AddressOfNewExeHeader的值,这里是一个偏移,指向PE文件头。

之后,又通过PE文件头 + 0x80得到了struct IMAGE_DATA_DIRECTORY Import -> VirtualAddress,并存储起来

image-20191031150503929

通过查询,能够看到VirtualAddress0x5000的地方对应的文件偏移为0x3E00


image-20191031150644780

通过遍历导入表动态链接库名称的方式确定KERNEL32导入表的结构偏移(中间有个and来对值运算,判断结果是否相等,而不是直接cmp)。


image-20191031151114342

接下来,取得Kernel32.dll的导入表信息,同时找到在附加区段**.reloc段上地址为0x00407740Point to import name**的偏移

image-20191031151329702

image-20191031151343493

并且调用函数sub_004072D1,这个函数被我重命名为get_addr_from_self,整体的作用为,在当前运行的文件本体导入表中寻找附加区段对应地址的前五个函数,如果找到则在esi返回函数地址,并且保存在局部变量里,后面有运算(不过我实际运行的时候并未触发,直接走SEHHandle了)。

当前文件,他寻找的5个函数名,一个都没有


image-20191031152312155

接下来,通过栈空间获取到一个返回地址,该返回地址位于Kernel32.dll,然后通过将该地址后三位清空的方式,试图暴力搜寻出Kernel32的基地址(其中有cmp,用于对比汇编的前几个字节是不是满足他的要求),不过直接触发了异常,不清楚是不是win7系统的问题。


SEHHandle在栈空间中直接找到0x00407007

image-20191031153033767

image-20191031153058614

之后会跳转到一个地址,不过这个地址是错误的,之前说了会修改地址0x00407241的汇编,所以这里被改为了mov eax, 0x403F00


image-20191031153227900

接下来,程序会尝试打开同目录下的名叫POLY-PE06.exe的文件,打开成功与否,最后都会弹出消息框。

中间还会校验文件内容算出来的一个值是否等于0xD8C25C1C,但是好像满足与否并不重要,没有太多的操作。

总结

认识了reloc区段,熟悉了PE结构的一部分内容,不过还是得开着010editor才行不然,背不完东西。

这个病毒比较老,后续还有我没分析到的地方还会补上的