【文章标题】: ASProtect 2.1x SKE dll文件脱壳+去除时间限制
【作    者】: jinwj
【软件名称】: scxb4.dll
【大    小】: 1.61MB
【加壳方式】: ASProtect 2.1x SKE->Alexey Solodovnikov
【编写语言】: Borland Delphi
【工    具】: Win2000、OllyDbg、PEiD、LordPE、RecImport。
【操作平台】: Win2000
--------------------------------------------------------------------------------
【详细过程】
   这个scxb4.dll是bds2006的一个第三方插件,用来使bds2006支持符合微软scc api的版本控制软件。这个DEMO版有30天的时间限制。

   用 PEid 0.94 显示为 ASProtect 2.1x SKE -> Alexey Solodovnikov

   很奇怪,用loaddll.exe不能正常载入scxb4.dll,提示进程不能处理异常退出。用VC编个小程序测试,LoadLibrary后同样异常退出,不知是什么原因。
   正好看到一篇文章,大概意思是说通过DLL卸载时找OEP简单多了,正好用在这里。
   
   用flyDBG载入BDS2006(命令行"bds.exe -pDelphi"),ALT+O,忽略全部异常。

1D399001 S>  60                  pushad
1D399002     E8 03000000         call SCXB4.1D39900A
1D399007   - E9 EB045D45         jmp 629694F7
1D39900C     55                  push ebp
1D39900D     C3                  retn
1D39900E     E8 01000000         call SCXB4.1D399014
1D399013     EB 5D               jmp short SCXB4.1D399072
1D399015     BB EDFFFFFF         mov ebx,-13
1D39901A     03DD                add ebx,ebp
1D39901C     81EB 00903900       sub ebx,399000                    ; ASCII "em@TObjectii"



一、找到OEP 

F9 Run 直到bds正常运行。
HE 1D399001  ;SCXB4.DLL 代码入口点,关闭bds,DLL卸载时会再次中断在外壳入口处!可以跟下去走

到OEP了。 

1D2881C0     55                  push ebp  ;OEP 入口点,此处下硬件断点,方便下次停住。
1D2881C1     8BEC                mov ebp,esp
1D2881C3     83C4 C4             add esp,-3C
1D2881C6     B8 EC4C281D         mov eax,SCXB4.1D284CEC
1D2881CB     E8 DC94D7FF         call SCXB4.1D0016AC
1D2881D0     E8 AB90D7FF         call SCXB4.1D001280               ; jmp to 

rtl100.System::Halt0
1D2881D5     8D40 00             lea eax,dword ptr ds:[eax]
1D2881D8     0000                add byte ptr ds:[eax],al
1D2881DA     0000                add byte ptr ds:[eax],al
1D2881DC     0000                add byte ptr ds:[eax],al
1D2881DE     0000                add byte ptr ds:[eax],al

二、发现IAT。
  
  Ctrl+B:FF 25。

1D286000   - FF25 048B291D       jmp dword ptr ds:[1D298B04]       ; 

rtl100.System::initialization
1D286006     8BC0                mov eax,eax
1D286008     832D 1010291D 01    sub dword ptr ds:[1D291010],1
1D28600F     73 07               jnb short SCXB4.1D286018
1D286011     33C0                xor eax,eax
1D286013     A3 1410291D         mov dword ptr ds:[1D291014],eax
1D286018     C3                  retn
1D286019     8D40 00             lea eax,dword ptr ds:[eax]

右键--->数据窗口跟随--->内存地址。
  
  在数据窗口右键--->长型--->地址。
  
  向上滚动来到IAT开始。
1D298B00  00000000
1D298B04  51F7A000  rtl100.System::initialization  ;IAT开始
1D298B08  51F0A8EC  rtl100.System::Finalization
1D298B0C  51F0A7D0  rtl100.System::LoadResString
1D298B10  51F0A318  rtl100.System::FreeMemory
1D298B14  51F0A188  rtl100.System::TInterfacedObject::_Release
........................
1D298E48  77E69129  KERNEL32.LocalAlloc
1D298E4C  00000000
1D298E50  77E06485  USER32.CreateWindowExA
1D298E54  77E1CD8D  USER32.WindowFromPoint
1D298E58  F44143B6                              ; IAT加密
1D298E5C  77E1C7C2  USER32.WaitMessage
1D298E60  77E051E0  USER32.WaitForInputIdle
1D298E64  77E09419  USER32.ValidateRect
..........................
1D29AFDC  51F6C2B4  rtl100.Widestrutils::WStrLen
1D29AFE0  00000000
1D29AFE4  51F5BD84  rtl100.Maskutils::FormatMaskText
1D29AFE8  51F5B13C  rtl100.Maskutils::TEditMask   ; IAT结束
1D29AFEC  00000000
1D29AFF0  591B99B6



三、测试IAT加密
Ctrl+F2重起OD,硬件中断在SCXB4.DLL代码入口点。

bp GetModuleHandleA,中断两次,F2 取消中断,Alt-F9返回(注意:下面的地址在每次重启机器后可

能不同)。

06AB34AC     85C0                test eax,eax    ; KERNEL32.77E60000 返回到这里
06AB34AE     75 07               jnz short 06AB34B7
06AB34B0     53                  push ebx
06AB34B1     FF95 F0314400       call dword ptr ss:[ebp+4431F0]



右键--->搜索--->文本字符串,在第一个85下双击,来到这里。

06A9D95B     68 F8DBA906         push 6A9DBF8               ; ASCII "85"
06A9D960     E8 4B7DFFFF         call 06A956B0
06A9D965     A1 6CB8AA06         mov eax,dword ptr ds:[6AAB86C]
06A9D96A     8B00                mov eax,dword ptr ds:[eax]
06A9D96C     E8 27BD0000         call 06AA9698 ;F4运行到这里,F7进入
06A9D971     84C0                test al,al
06A9D973     75 0A               jnz short 06A9D97F
06A9D975     68 F8DBA906         push 6A9DBF8                ; ASCII "85"
06A9D97A     E8 317DFFFF         call 06A956B0
06A9D97F     A1 34B9AA06         mov eax,dword ptr ds:[6AAB934]

光标定位到地址06A9D96C,F4运行,F7进入。

06AA97B3     50                  push eax
06AA97B4     56                  push esi
06AA97B5     E8 9EFCFFFF         call 06AA9458 ;F4运行到这里,F7进入
06AA97BA     0FB707              movzx eax,word ptr ds:[edi]
06AA97BD     83C0 02             add eax,2
06AA97C0     03F8                add edi,eax
06AA97C2     8A1F                mov bl,byte ptr ds:[edi]

向下拉动,光标定位到地址06AA97B5,F4运行,F7进入。

06AA948C     6933 C08A433B       imul esi,dword ptr ds:[ebx],3B438AC0
06AA9492     3BF0                cmp esi,eax ;下F2断点
06AA9494     75 5E               jnz short 06AA94F4
06AA9496     EB 01               jmp short 06AA9499
06AA9498     C7                  ???                                   ; 未知命令
06AA9499     66:8B02             mov ax,word ptr ds:[edx]


在数据窗口定位IAT区段,Ctrl+G:1D298B04 (IAT头)。
  
  在06AA9492地址连续F9,注意数据窗口第一个出现了,看寄存器ESI为12,继续F9。
  ====================================================
  1D298AF4  00000000
1D298AF8  4A5976B7
1D298AFC  4CBF7535
1D298B00  00000000
1D298B04  51F7A000  rtl100.System::initialization
1D298B08  3536F873
1D298B0C  7F9E9F8D
1D298B10  10ADBDF3
  ====================================================
  
  通过测试,12、46是没有加密,7c是加密,还有一种情况都不同于以上值,经测试是GetProcAddress。

四、IAT解密
  
  Ctrl+F2重起,重复进行到06AA9492这个比较,F2断点,F9,中断,F2取消断点。
  
  用OD的插件HideOD申请内存,我这里分配给06E80000。
  
  修改06AA9494:
  06AA9494    75 5E            jnz short 06AA94F4  ;-->jmp 06E80000
  
  F8步进,来到申请内存06E80000,键入以下补丁代码。
  ===============================
06E80000   - 0F84 9394C2FF       je 06AA9499
06E80006     83FE 7C             cmp esi,7C
06E80009     74 05               je short 06E80010
06E8000B     83FE 12             cmp esi,12
06E8000E     75 0A               jnz short 06E8001A
06E80010     BE 12000000         mov esi,12
06E80015   - E9 DA94C2FF         jmp 06AA94F4
06E8001A     CC                  int3
06E8001B   ^ EB F3               jmp short 06E80010
06E8001D     90                  nop

0F 84 93 94 C2 FF 83 FE 7C 74 05 83 FE 12 75 0A BE 12 00 00 00 E9 DA 94 C2 FF CC EB F3 90
  ================================
HE 6A9D971以便IAT解密完毕可以停下。
Alt+O,取消忽略int3异常,定位数据窗口在IAT区段,F9运行,会停在06E8001B,单步运行,来到下面。

006AA95B9     8B45 FC             mov eax,dword ptr ss:[ebp-4]
06AA95BC     50                  push eax
06AA95BD     8B45 10             mov eax,dword ptr ss:[ebp+10]
06AA95C0     50                  push eax
06AA95C1     53                  push ebx
06AA95C2     E8 9DFCFFFF         call 06AA9264
06AA95C7     8B55 0C             mov edx,dword ptr ss:[ebp+C]
06AA95CA     8B12                mov edx,dword ptr ds:[edx]
06AA95CC     8902                mov dword ptr ds:[edx],eax 

;记住edx=1d29932c,eax=KERNEL32.GetStringTypeExA
06AA95CE     E9 95000000         jmp 06AA9668

1d29932c处应该是GetProcAddress,手工更改:

AB 0C E8 77  getprocaddress

F9继续,停在6A9D971,现在IAT已经全部解密了。

五、patch CALL XXXXXXXX

F9继续运行,停在OEP入口处。

CTRL+G来到6A9D971处,取消6A9D971处的硬件断点,查找mov eax,700,来到下面

06AA9028     8945 F0             mov dword ptr ss:[ebp-10],eax
06AA902B     B8 00070000         mov eax,700
06AA9030     E8 0F95FDFF         call 06A82544 ;改为-->jmp 06E80041,见下面patch代码
06AA9035     8945 E4             mov dword ptr ss:[ebp-1C],eax

在申请的内存06E80000处写上下面patch代码

06E80000     E8 00000000         call 06E80005
06E80005     5B                  pop ebx
06E80006     83EB 05             sub ebx,5
06E80009     8B93 00010000       mov edx,dword ptr ds:[ebx+100]
06E8000F     803A E8             cmp byte ptr ds:[edx],0E8
06E80012     0F85 94000000       jnz 06E800AC
06E80018     8B42 01             mov eax,dword ptr ds:[edx+1]
06E8001B     03C2                add eax,edx
06E8001D     83C0 05             add eax,5
06E80020     3B83 18010000       cmp eax,dword ptr ds:[ebx+118]
06E80026     0F85 80000000       jnz 06E800AC
06E8002C     90                  nop
06E8002D     90                  nop
06E8002E     90                  nop
06E8002F     90                  nop
06E80030     90                  nop
06E80031     90                  nop
06E80032     90                  nop
06E80033     90                  nop
06E80034     90                  nop
06E80035     90                  nop
06E80036     90                  nop
06E80037     90                  nop
06E80038     60                  pushad
06E80039     89A3 08010000       mov dword ptr ds:[ebx+108],esp
06E8003F     FFE2                jmp edx
06E80041     E8 00000000         call 06E80046
06E80046     5B                  pop ebx
06E80047     83EB 46             sub ebx,46
06E8004A     8993 0C010000       mov dword ptr ds:[ebx+10C],edx
06E80050     8BA3 08010000       mov esp,dword ptr ds:[ebx+108]
06E80056     61                  popad
06E80057     8B8B 10010000       mov ecx,dword ptr ds:[ebx+110]
06E8005D     8B83 0C010000       mov eax,dword ptr ds:[ebx+10C]
06E80063     3901                cmp dword ptr ds:[ecx],eax
06E80065     0F85 0D000000       jnz 06E80078
06E8006B     66:C702 FF25        mov word ptr ds:[edx],25FF
06E80070     894A 02             mov dword ptr ds:[edx+2],ecx
06E80073     E9 34000000         jmp 06E800AC
06E80078     83C1 04             add ecx,4
06E8007B     3B8B 14010000       cmp ecx,dword ptr ds:[ebx+114]
06E80081   ^ 0F82 DCFFFFFF       jb 06E80063
06E80087     FF83 1C010000       inc dword ptr ds:[ebx+11C]
06E8008D     90                  nop
06E8008E     90                  nop
06E8008F     90                  nop
06E80090     90                  nop
06E80091     90                  nop
06E80092     90                  nop
06E80093     90                  nop
06E80094     90                  nop
06E80095     90                  nop
06E80096     90                  nop
06E80097     90                  nop
06E80098     90                  nop
06E80099     90                  nop
06E8009A     90                  nop
06E8009B     90                  nop
06E8009C     90                  nop
06E8009D     90                  nop
06E8009E     90                  nop
06E8009F     90                  nop
06E800A0     90                  nop
06E800A1     90                  nop
06E800A2     90                  nop
06E800A3     90                  nop
06E800A4     90                  nop
06E800A5     90                  nop
06E800A6     90                  nop
06E800A7     90                  nop
06E800A8     90                  nop
06E800A9     90                  nop
06E800AA     90                  nop
06E800AB     90                  nop
06E800AC     42                  inc edx
06E800AD     3B93 04010000       cmp edx,dword ptr ds:[ebx+104]
06E800B3   ^ 0F82 56FFFFFF       jb 06E8000F
06E800B9   - EB FE               jmp short 06E800B9 ;下F2断点

E8 00 00 00 00 5B 83 EB 05 8B 93 00 01 00 00 80 3A E8 0F 85 94 00 00 00 8B 42 01 03 C2 83 

C0 05
3B 83 18 01 00 00 0F 85 80 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 60 89 A3 08 01 00 

00 FF
E2 E8 00 00 00 00 5B 83 EB 46 89 93 0C 01 00 00 8B A3 08 01 00 00 61 8B 8B 10 01 00 00 8B 

83 0C
01 00 00 39 01 0F 85 0D 00 00 00 66 C7 02 FF 25 89 4A 02 E9 34 00 00 00 83 C1 04 3B 8B 14 

01 00
00 0F 82 DC FF FF FF FF 83 1C 01 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 

90 90
90 90 90 90 90 90 90 90 90 90 90 90 42 3B 93 04 01 00 00 0F 82 56 FF FF FF EB FE

这段代码可以贴在任何地址处而不用修改任何一个字节,但是它需要一些变量,你在运行之前要填上这

些变量。如果
你的代码被贴在06E80000,那么:

  06E80000+100 程序代码段开始地址
  06E80000+104 程序代码段结束地址+1
  06E80000+108 ESP保存地址
  06E80000+10C 保存解码API地址
  06E80000+110 IAT开始地址
  06E80000+114 IAT结束地址+4
  06E80000+118 解码call地址
  06E80000+11C 未找到API个数记录

你需要填的是目标程序的代码段开始地址、程序代码段结束地址+1、IAT开始地址、IAT结束地址+4和解

码call地址。
其余的就不用管了,我们这里:
  
  程序代码段开始地址=1D001000
  程序代码段结束地址+1=1D289000
  IAT开始地址=1D298B04
  IAT结束地址+4=1D29AFEC
  解码call地址(AIP call)=06EA0000
 
填完后06E80000+100 开始的数据应该是这样:

00 10 00 1D 00 90 28 1D 04 8B 29 1D 00 00 00 00 04 8B 29 1D EC AF 29 1D 00 00 EA 06 00 00 

00 00

然后回到我们的Patch代码处,在第一句上右键-〉此处新建EIP,F9运行,停在06E800B9处,F2取消断点

,这时AIP call都已经修复了。

取消06AA9494,06AA9030两处的修改,在OEP入口处右键-〉此处新建EIP,接着就是Dump+Imp修复了。

六、去除时间限制
    备份原文件,copy dumped_.dll scxb4.dll,运行bds2006,发生内存写异常,scxb4.dll不能正常载

入,看来还有问题。

    用flyDBG载入BDS2006(注意:scxb4.dll是脱壳后的),停在1D2881C0处后,HE 1D284AC9,1D284AC9

是scxb4.dll的输出函数入口,跟下去看看。

1D284AC9     55                  push ebp
1D284ACA     68 5C4C281D         push 1D284C5C
1D284ACF     64:FF30             push dword ptr fs:[eax]
1D284AD2     64:8920             mov dword ptr fs:[eax],esp
1D284AD5     E8 4AFFFFFF         call 1D284A24
1D284ADA     57                  push edi
1D284ADB     56                  push esi
1D284ADC     E8 80000000         call 1D284B61
1D284AE1     0BFD                or edi,ebp
1D284AE3     81EF 261F18CB       sub edi,CB181F26
1D284AE9     8D7C0C 18           lea edi,dword ptr ss:[esp+ecx+18]
1D284AED     2BF9                sub edi,ecx
1D284AEF     8D7C2F E4           lea edi,dword ptr ds:[edi+ebp-1C]
1D284AF3     2BFD                sub edi,ebp
1D284AF5     8B3F                mov edi,dword ptr ds:[edi]
1D284AF7     8DBC0F 27CDD7FF     lea edi,dword ptr ds:[edi+ecx+FFD7CD27]
1D284AFE     2BF9                sub edi,ecx
1D284B00     8D7451 5C           lea esi,dword ptr ds:[ecx+edx*2+5C]
1D284B04     8D740E A4           lea esi,dword ptr ds:[esi+ecx-5C]
1D284B08     2BF1                sub esi,ecx
1D284B0A     8B37                mov esi,dword ptr ds:[edi]
1D284B0C     81E6 FF000000       and esi,0FF
1D284B12     83EF 75             sub edi,75
1D284B15     BF 62314700         mov edi,473162                            ; ASCII "        

           
                                                                                

                    
                                                                       

                             
               "...
1D284B1A     337C24 08           xor edi,dword ptr ss:[esp+8]
1D284B1E     C1CF E5             ror edi,0E5
1D284B21     8DBC35 88104800     lea edi,dword ptr ss:[ebp+esi+481088]
1D284B28     8DBC08 EDFCEB4F     lea edi,dword ptr ds:[eax+ecx+4FEBFCED]
1D284B2F     2BF9                sub edi,ecx
1D284B31     2BF8                sub edi,eax
1D284B33     8DB6 2B0214B0       lea esi,dword ptr ds:[esi+B014022B]
1D284B39     03F7                add esi,edi
1D284B3B     85F6                test esi,esi
1D284B3D     0F84 28000000       je 1D284B6B ;此处要跳,否则会出现内存写异常
1D284B43     BD B6AC4700         mov ebp,47ACB6
1D284B48     83DD 37             sbb ebp,37
1D284B4B     8D740B DE           lea esi,dword ptr ds:[ebx+ecx-22]
1D284B4F     81E7 C8090384       and edi,840309C8
1D284B55     68 548C0323         push 23038C54
1D284B5A     6A 52               push 52
1D284B5C     E9 0A000000         jmp 1D284B6B
1D284B61     037C24 18           add edi,dword ptr ss:[esp+18]
1D284B65     BF 2E9E4900         mov edi,499E2E
1D284B6A     C3                  retn
1D284B6B     5E                  pop esi
1D284B6C     5F                  pop edi
1D284B6D     EB 7B               jmp short 1D284BEA

修改1D284B3D处代码,必须要跳转。运行,正常了。

下面去除时间限制,CTRL+F2重新载入,到上面修改处继续跟踪,来到下面。

1D284C0B     E8 00D6FBFF         call 1D242210
1D284C10     E8 EBD6FBFF         call 1D242300
1D284C15     E9 12000000         jmp 1D284C2C

改为
1D284C0B     E8 00D6FBFF         call 1D242210 ;全部改为90
1D284C10     E8 EBD6FBFF         call 1D242300 ;全部改为90
1D284C15     EB 24               jmp short 1D284C3B

运行,时间提示没有了,保存,退出。

修改系统时间到过期时间以后,运行bds2006验证,试一下几个功能,OK,时间限制去除了。

七、后记
    本来是不想写这篇文章的,第一次手工脱壳,水平真的是太菜,不想出来献丑了,权当是凑发帖数吧!文章里面基本没有自己的东西,patch代码也是抄别人的,在这里要感谢论坛里的牛人们,无数牛人的文章使我受益良多。