• 标 题:[原创]heXer老兄的telock0.98脱壳机原理
  • 作 者:lordor
  • 时 间:004-06-16,15:44
  • 链 接:http://bbs.pediy.com

对象:heXer老兄的telock0.98脱壳机
作者:lordor
QQ:88378557
mail:lordor#163.com
From:

用ASM编写,没加壳,很容易会来到处理"Unpack"按键的代码:

004021C8  PUSHAD                                            ; |
004021C9  PUSH untelock.00404428                            ;  ASCII "C:\Program Files\starTV\starTV.exe"
004021CE  CALL untelock.00401B45                            ; \untelock.00401B45
004021D3  CMP DWORD PTR DS:[405744],1
004021DA  JNZ untelock.004022C8
004021E0  PUSH untelock.00404428                            ; /String2 = "C:\Program Files\starTV\starTV.exe"
004021E5  PUSH untelock.0040452C                            ; |String1 = untelock.0040452C
004021EA  CALL <JMP.&KERNEL32.lstrcpyA>                     ; \lstrcpyA
004021EF  PUSH untelock.00404428                            ; /String2 = "C:\Program Files\starTV\starTV.exe"
004021F4  PUSH untelock.00404630                            ; |String1 = untelock.00404630
004021F9  CALL <JMP.&KERNEL32.lstrcpyA>                     ; \lstrcpyA
004021FE  PUSH untelock.00404288                            ; /StringToAdd = ".BAK"
00402203  PUSH untelock.0040452C                            ; |ConcatString = "C:\Program Files\starTV\starTV.exe.BAK"
00402208  CALL <JMP.&KERNEL32.lstrcatA>                     ; \lstrcatA
0040220D  PUSH untelock.0040428D                            ; /StringToAdd = ".TMP"
00402212  PUSH untelock.00404630                            ; |ConcatString = "C:\Program Files\starTV\starTV.exe.TMP"
00402217  CALL <JMP.&KERNEL32.lstrcatA>                     ; \lstrcatA
0040221C  PUSH 0                                            ; /FailIfExists = FALSE
0040221E  PUSH untelock.0040452C                            ; |NewFileName = "C:\Program Files\starTV\starTV.exe.BAK"
00402223  PUSH untelock.00404428                            ; |ExistingFileName = "C:\Program Files\starTV\starTV.exe"
00402228  CALL <JMP.&KERNEL32.CopyFileA>                    ; \CopyFileA
0040222D  CALL untelock.00401DA2
00402232  CMP DWORD PTR DS:[405740],0
00402239  JE untelock.004022C8                              ;  上面是备份,并把文件映射到内存,判断是否为有效pe文件
0040223F  CALL untelock.00401CAD                            ;  判断是否为telock加密
00402244  CALL untelock.004016F1                            ;  这个很长,这里是模拟telock的解压代码,解到内存中
00402249  CALL untelock.004020A5                            ;  对内存中的数据,生成脱壳文件
0040224E  PUSH DWORD PTR DS:[405740]                        ; /BaseAddress = 01270000
00402254  CALL <JMP.&KERNEL32.UnmapViewOfFile>              ; \UnmapViewOfFile
00402259  PUSH DWORD PTR DS:[40573C]                        ; /hObject = 00000108 (window)
0040225F  CALL <JMP.&KERNEL32.CloseHandle>                  ; \CloseHandle
00402264  PUSH DWORD PTR DS:[405734]                        ; /hObject = 0000015C (window)
0040226A  CALL <JMP.&KERNEL32.CloseHandle>                  ; \CloseHandle
0040226F  PUSH 0                                            ; /FailIfExists = FALSE
00402271  PUSH untelock.00404428                            ; |NewFileName = "C:\Program Files\starTV\starTV.exe"
00402276  PUSH untelock.00404630                            ; |ExistingFileName = "C:\Program Files\starTV\starTV.exe.TMP"
0040227B  CALL <JMP.&KERNEL32.CopyFileA>                    ; \CopyFileA
00402280  PUSH untelock.00404630                            ; /FileName = "C:\Program Files\starTV\starTV.exe.TMP"
00402285  CALL <JMP.&KERNEL32.DeleteFileA>                  ; \DeleteFileA
0040228A  CALL untelock.00401DA2
0040228F  CALL untelock.00401D31
00402294  PUSH DWORD PTR DS:[405740]                        ; /BaseAddress = 01270000
0040229A  CALL <JMP.&KERNEL32.UnmapViewOfFile>              ; \UnmapViewOfFile
0040229F  PUSH DWORD PTR DS:[40573C]                        ; /hObject = 00000108 (window)
004022A5  CALL <JMP.&KERNEL32.CloseHandle>                  ; \CloseHandle
004022AA  PUSH DWORD PTR DS:[405734]                        ; /hObject = 0000015C (window)
004022B0  CALL <JMP.&KERNEL32.CloseHandle>                  ; \CloseHandle
004022B5  PUSH 0                                            ; /Style = MB_OK|MB_APPLMODAL
004022B7  PUSH untelock.004040C6                            ; |Title = " tElock v0.98+ unpacker Special   "
004022BC  PUSH untelock.00404241                            ; |Text = "         Success unpacked!"
004022C1  PUSH 0                                            ; |hOwner = NULL
004022C3  CALL <JMP.&USER32.MessageBoxA>                    ; \MessageBoxA
004022C8  POPAD
004022C9  RETN

可以看到主要处理过程:备份->判断特征码->解压->据解压生成未加壳的文件
下面是三个主要的call代码

--------------------------------
第一个:0040223F  CALL untelock.00401CAD

00401CAD  PUSHAD
00401CAE  MOV EDI,DWORD PTR DS:[405740]
00401CB4  ADD EDI,DWORD PTR DS:[EDI+3C]                     ;  pe头
00401CB7  MOV EAX,DWORD PTR DS:[EDI+28]                     ;  取oep值
00401CBA  PUSH EAX                                          ;  1bdbd6
00401CBB  PUSH DWORD PTR DS:[405740]
00401CC1  CALL untelock.0040117E                            ;  取rva在文件中的相对位移offset
-------------------
  0040117E  />PUSH EBP
  0040117F  |>MOV EBP,ESP
  00401181  |>PUSH EDI
  00401182  |>PUSH ESI
  00401183  |>PUSH EDX
  00401184  |>PUSH ECX
  00401185  |>MOV ESI,DWORD PTR SS:[EBP+8]                      ;  基址
  00401188  |>ADD ESI,DWORD PTR DS:[ESI+3C]                     ;  pe头
  0040118B  |>MOV EDI,DWORD PTR SS:[EBP+C]                      ;  eep
  0040118E  |>MOV EDX,ESI
  00401190  |>ADD EDX,0F8                                       ;  定位第一个段
  00401196  |>MOV CX,WORD PTR DS:[ESI+6]                        ;  有多少个节
  0040119A  |>MOVZX ECX,CX
  0040119D  |>JMP SHORT untelock.004011CC
  0040119F  |>/CMP EDI,DWORD PTR DS:[EDX+C]                     ;  oep与当前节的voffset比较
  004011A2  |>|JB SHORT untelock.004011C8
  004011A4  |>|MOV EAX,DWORD PTR DS:[EDX+C]
  004011A7  |>|ADD EAX,DWORD PTR DS:[EDX+10]                    ;  voffset+rawsize
  004011AA  |>|CMP EDI,EAX
  004011AC  |>|JNB SHORT untelock.004011C8
  004011AE  |>|MOV EAX,DWORD PTR DS:[EDX+10]                    ;  rawsize
  004011B1  |>|MOV DWORD PTR DS:[405768],EAX
  004011B6  |>|MOV EAX,DWORD PTR DS:[EDX+C]
  004011B9  |>|SUB EDI,EAX
  004011BB  |>|MOV EAX,DWORD PTR DS:[EDX+14]
  004011BE  |>|ADD EAX,EDI
  004011C0  |>|POP ECX
  004011C1  |>|POP EDX
  004011C2  |>|POP ESI
  004011C3  |>|POP EDI
  004011C4  |>|LEAVE
  004011C5  |>|RETN 8
  004011C8  |>|ADD EDX,28                                       ;  下一节
  004011CB  |>|DEC ECX
  004011CC  |> CMP ECX,0
  004011CF  |>\JA SHORT untelock.0040119F                       ;  判断oep是落在那一节上
  004011D1  |>MOV EAX,-1
  004011D6  |>POP ECX
  004011D7  |>POP EDX
  004011D8  |>POP ESI
  004011D9  |>POP EDI
  004011DA  |>LEAVE
  004011DB  \>RETN 8
--------------------------


00401CC6  MOV EDI,EAX                                       ;  取得oep的文件偏移be1d6
00401CC8  ADD EDI,DWORD PTR DS:[405740]                     ;  加上基址
00401CCE  MOV EAX,DWORD PTR DS:[405768]                     ;  eop所在段的大小2800
00401CD3  MOV EAX,-1
00401CD8  CMP DWORD PTR DS:[EDI-A],237
00401CDF  JNZ SHORT untelock.00401D0F                       ;  入口地址前第9及10字节(Word型)是否为237
00401CE1  CMP BYTE PTR DS:[EDI],0E9                         ;  入口处第一个字节是否为e9
00401CE4  JNZ SHORT untelock.00401D0F
00401CE6  CMP WORD PTR DS:[EDI+3],0FFFF                     ;  入口处第4、5个字节是否为0ffff
00401CEB  JNZ SHORT untelock.00401D0F
00401CED  MOV EDX,DWORD PTR DS:[EDI+1]          ==>取入口第二字节开始共4个字节,即取jmp后的地址
00401CF0  ADD EDI,5              ==>加上第一条指令的长度    
00401CF3  ADD EDI,EDX                          ==>edi再加上跳转的地址,即取得jmp后的地址 
00401CF5  CMP BYTE PTR DS:[EDI+16],0B9                      ;  判断第23字节是否为b9
00401CF9  JNZ SHORT untelock.00401D0F
00401CFB  CMP WORD PTR DS:[EDI+19],0        ==>26字节
00401D00  JNZ SHORT untelock.00401D0F
00401D02  CMP DWORD PTR DS:[EDI+25],6781448D      
==>38字节(005BC025    8D4481 67       LEA EAX,DWORD PTR DS:[ECX+EAX*4+67])    
00401D09  JNZ SHORT untelock.00401D0F
00401D0B  XOR EAX,EAX
00401D0D  JMP SHORT untelock.00401D10
00401D0F  NOP
00401D10  NOP
00401D11  CMP EAX,-1
00401D14  JNZ SHORT untelock.00401D2F
00401D16  PUSH 10                                           ; /Style = MB_OK|MB_ICONHAND|MB_APPLMODAL
00401D18  PUSH untelock.004040C6                            ; |Title = " tElock v0.98+ unpacker Special   "
00401D1D  PUSH untelock.004041F5                            ; |Text = "This file is not packed by tElock v0.98+"
00401D22  PUSH 0                                            ; |hOwner = NULL
00401D24  CALL <JMP.&USER32.MessageBoxA>                    ; \MessageBoxA
00401D29  PUSH EAX                                          ; /ExitCode
00401D2A  CALL <JMP.&KERNEL32.ExitProcess>                  ; \ExitProcess
00401D2F  POPAD
00401D30  RETN

可以看到这是判断入口代码的特征字



----------------------------------------
第二个:0402244  CALL untelock.004016F1:这里是模拟telock的解压代码,解到内存中

004016F1  PUSHAD
004016F2  MOV EDI,DWORD PTR DS:[405740]            ;  基址
004016F8  ADD EDI,DWORD PTR DS:[EDI+3C]            ;  pe
004016FB  MOV EAX,DWORD PTR DS:[EDI+28]            ;  eop
004016FE  PUSH EAX
004016FF  PUSH DWORD PTR DS:[405740]
00401705  CALL untelock.0040117E                   ;  fileoffset
0040170A  MOV EDI,EAX
0040170C  ADD EDI,DWORD PTR DS:[405740]
00401712  MOV EAX,DWORD PTR DS:[EDI+1]             ;  jmp后的地址
00401715  ADD EDI,5
00401718  ADD EDI,EAX
0040171A  MOV DWORD PTR DS:[40574C],EDI            ;  保存跳转后的地址
00401720  MOV EBP,EDI
00401722  MOV ESI,EDI
00401724  ADD ESI,41                               ;  add 41
00401727  MOV ECX,DWORD PTR DS:[EDI+17]            ;  14
0040172A  MOV EAX,ECX
0040172C  PUSH ESI
0040172D  /LEA EAX,DWORD PTR DS:[ECX+EAX*4+67]
00401731  |XOR BYTE PTR DS:[ESI],AL
00401733  |INC ESI
00401734  |AAM 9
00401736  |DEC ECX
00401737  \JG SHORT untelock.0040172D              ;  模拟解压
00401739  POP ESI
0040173A  PUSH ESI
0040173B  MOV EAX,DWORD PTR DS:[ESI+1]                         ;  esi为解后的地址
0040173E  ADD ESI,5
00401741  ADD ESI,EAX                                          ;  跳转的地址
00401743  MOV EAX,DWORD PTR DS:[ESI+8]
00401746  ADD ESI,5
00401749  SUB ESI,EAX
0040174B  MOV ECX,0D
00401750  CALL untelock.004013D2
00401755  MOV CL,BYTE PTR DS:[ESI-1D]
00401758  MOV CH,BYTE PTR DS:[ESI-16]
0040175B  MOV EBX,DWORD PTR DS:[ESI-2C]
0040175E  MOV ESI,EDI
00401760  POP ESI
00401761  ADD ESI,6
00401764  /ROL BYTE PTR DS:[ESI+EBX],CL
00401767  |ADD BYTE PTR DS:[ESI+EBX],BL
0040176A  |XOR BYTE PTR DS:[ESI+EBX],CH
0040176D  |INC BYTE PTR DS:[ESI+EBX]
00401770  |DEC EBX
00401771  \JG SHORT untelock.00401764    ;  模拟解压


--------------------
第三个:保存文件的模块:

004020A5  PUSH 0                                            ; /hTemplateFile = NULL
004020A7  PUSH 80                                           ; |Attributes = NORMAL
004020AC  PUSH 2                                            ; |Mode = CREATE_ALWAYS
004020AE  PUSH 0                                            ; |pSecurity = NULL
004020B0  PUSH 1                                            ; |ShareMode = FILE_SHARE_READ
004020B2  PUSH C0000000                                     ; |Access = GENERIC_READ|GENERIC_WRITE
004020B7  PUSH untelock.00404630                            ; |FileName = "C:\Program Files\starTV\starTV.exe.TMP"
004020BC  CALL <JMP.&KERNEL32.CreateFileA>                  ; \CreateFileA
004020C1  MOV DWORD PTR DS:[405738],EAX
004020C6  XOR EBX,EBX
004020C8  MOV DWORD PTR DS:[405774],EBX
004020CE  PUSH 0
004020D0  PUSH DWORD PTR DS:[405740]
004020D6  CALL untelock.0040110D
004020DB  PUSH 0                                            ; /pOverlapped = NULL
004020DD  PUSH untelock.00405748                            ; |pBytesWritten = untelock.00405748
004020E2  PUSH EBX                                          ; |nBytesToWrite
004020E3  PUSH DWORD PTR DS:[405740]                        ; |Buffer = 01270000
004020E9  PUSH DWORD PTR DS:[405738]                        ; |hFile = 00000120 (window)
004020EF  CALL <JMP.&KERNEL32.WriteFile>                    ; \WriteFile
004020F4  MOV EAX,DWORD PTR DS:[405748]
004020F9  MOV DWORD PTR DS:[405778],EAX
004020FE  PUSH ESI
004020FF  PUSH EDI
00402100  PUSH ECX
00402101  MOV ECX,EAX
00402103  MOV ESI,DWORD PTR DS:[405740]
00402109  LEA EDI,DWORD PTR DS:[404734]
0040210F  REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
00402111  POP ECX
00402112  POP EDI
00402113  POP ESI
00402114  ADD DWORD PTR DS:[405774],EAX
0040211A  CALL untelock.00401E4F
0040211F  MOV DWORD PTR DS:[40576C],EAX
00402124  XOR ESI,ESI
00402126  JMP SHORT untelock.00402186
00402128  /PUSH ESI
00402129  |PUSH DWORD PTR DS:[405740]
0040212F  |CALL untelock.0040110D  ==>节
00402134  |MOV ECX,EAX
00402136  |MOV DWORD PTR DS:[405748],0
00402140  |CMP DWORD PTR DS:[405760],0
00402147  |JE SHORT untelock.00402167
00402149  |CALL untelock.00401FEB  ==>写入文件
0040214E  |PUSH EAX
0040214F  |PUSH DWORD PTR DS:[405774]
00402155  |CALL untelock.0040115B
0040215A  |MOV EAX,DWORD PTR DS:[405748]
0040215F  |ADD DWORD PTR DS:[405774],EAX
00402165  |JMP SHORT untelock.00402185
00402167  |XOR EAX,EAX
00402169  |MOV DWORD PTR DS:[405748],EAX
0040216E  |PUSH EAX
0040216F  |PUSH DWORD PTR DS:[405774]
00402175  |CALL untelock.0040115B
0040217A  |MOV EAX,DWORD PTR DS:[405748]
0040217F  |ADD DWORD PTR DS:[405774],EAX
00402185  |INC ESI
00402186   CMP ESI,DWORD PTR DS:[40576C]
0040218C  \JNZ SHORT untelock.00402128
0040218E  PUSH 0                                            ; /Origin = FILE_BEGIN
00402190  PUSH 0                                            ; |pOffsetHi = NULL
00402192  PUSH 0                                            ; |OffsetLo = 0
00402194  PUSH DWORD PTR DS:[405738]                        ; |hFile = 00000120 (window)
0040219A  CALL <JMP.&KERNEL32.SetFilePointer>               ; \SetFilePointer
0040219F  PUSH 0                                            ; /pOverlapped = NULL
004021A1  PUSH untelock.00405748                            ; |pBytesWritten = untelock.00405748
004021A6  PUSH DWORD PTR DS:[405778]                        ; |nBytesToWrite = 400 (1024.)
004021AC  PUSH untelock.00404734                            ; |Buffer = untelock.00404734
004021B1  PUSH DWORD PTR DS:[405738]                        ; |hFile = 00000120 (window)
004021B7  CALL <JMP.&KERNEL32.WriteFile>                    ; \WriteFile
004021BC  PUSH DWORD PTR DS:[405738]                        ; /hObject = 00000120 (window)
004021C2  CALL <JMP.&KERNEL32.CloseHandle>                  ; \CloseHandle
004021C7  RETN

总结:
可以看到脱壳机是模拟telock的原理进行脱壳的,heXer编写了大量的解压代码,直接对文件代码进行解压出正确的代码。
防范:对于这种脱壳机,防范的方法是针对两种:一中它在判断特征码是作修改,另一个是它在解压时的数据作修改。如用telock加壳后,对入口代码作一些变形,这样特征码不起作用,也就脱不了。


by lordor  04.6.16