首页
论坛
课程
招聘
ASProtect SKE 2.2 SDK中的API修复
2006-7-10 20:22 57543

ASProtect SKE 2.2 SDK中的API修复

2006-7-10 20:22
57543
【文章标题】: ASProtect SKE 2.2 SDK中的API修复
【文章作者】: kanxue
--------------------------------------------------------------------------------
【详细过程】

   有关ASProtect的SDK,近期论坛不少文章涉及到了,如cyto的文章(本文一些补丁代码参考了cyto文章)。SDK的修复VolX、shoooo等大侠更是轻车熟路。这2天也学习了一下SDK修复,有少许心得,现拿出来希望大家帮忙指正一下。

    ASProtect的SDK种类比较多,本文主要介绍如何修复ASProtect自带的一些API,如GetHardwareID,CheckKeyAndDecrypt,GetRegistrationKeys,GetModeInformation,GetRegistrationInformation 等。  
    学习SDK最好的方法是将ASProtect的帮助文档看一遍,并结合其样例掌握用法。

1.准备工作

   本文以ASProtect自带的样例Examples\Reg Trial\VC\ 来讨论。为了降低难度,我将样例中的REG_CRYPT_BEGIN1与REG_CRYPT_END1注释掉,这对标签是加密代码的,无key代码就不能解密,当然有key还得修复这段代码,修复方法类似stolen OEP。


//REG_CRYPT_BEGIN1 //注释掉,不加密如下代码
strcpy( caption, "Registered version!" );
SetWindowText( hwnd, caption );
GetModeInformation( 0, &ModeName, &mode_status );
SetWindowText( GetDlgItem(hwnd,IDCANCEL), "Close" );
ShowWindow(GetDlgItem(hwnd,IDC_BUYNOW), SW_HIDE);
ShowWindow(GetDlgItem(hwnd,IDC_REG_BUTTON), SW_HIDE);
wsprintf( buffer,"Key: %s\nName: \t\t%s\nMode Name: \t%s",UserKey, UserName, ModeName );
SetDlgItemText(hwnd, IDC_TEXT, buffer);
//REG_CRYPT_END1 //注释掉


   然后用VC 6.0编译Reg Trial样例,得到trial.exe文件,运行ASProtect主程序,打开该样例提供的reg_trial.aspr2项目文件,本文主要是讨论SDK修复,因此protectin Options全部不选。Modes部分reg_trial.aspr2己设置好,如图:



   然后点击Protect按钮将trial.exe加壳保护,生成的trial.exe无key运行是试用版,需要输入key才能为注册版。key可以在Activation keys栏生成:


  本例将加密标签REG_CRYPT_BEGIN1与REG_CRYPT_END1注释掉了,因此不存在解码问题。

2.用脚本脱壳

   非常感谢VolX能与大家分享他那强大的脚本!OD加载trial.exe后,用ODbgScript 1.4x插件跑VolX的脚本:Asprotect 2.XX SKE IAT Fixer 。
http://bbs.pediy.com/showthread.php?s=&threadid=24557


运行一会儿,脚本有一个提示:“Import table is fixed, you can dump the file now or later. check the address and size of IAT in log window”
点击确定后,再单击ODbgScript/Resume继续执行脚本,不一会儿就到OEP:“OEP found, no stolen code at the OEP!”。

00401470    55              push    ebp                              ; trial.00400000
00401471    8BEC            mov     ebp, esp
00401473    6A FF           push    -1

此时就可Dump取trial.exe程序了,并用ImportREC重建输入表:



这里会发现有一些函数不能识别,这些函数就是ASProtect自己的API,可以直接Cut,就可重建输入表了,得到dumped_.exe。

在OD里查看这些ASProtect的API,会发现它们与IAT其他函数靠在一起:

00405000  00AA7FD8
00405004  00AA7EC4
00405008  00AA7CCC
0040500C  00AA8024
00405010  00AA7BE0
00405014  00000000
00405018  7C801D77  kernel32.LoadLibraryA
0040501C  7C80AC28  kernel32.GetProcAddress
00405020  7C9379FD  ntdll.RtlReAllocateHeap

3.修复SDK

  如果此时运行脱壳后的文件dumped_.exe,就会异常,因为程序里会调用ASProtect的API函数:

00404A18   $- FF25 0C504000 jmp     [40500C]  //F2下断点
00404A1E   $- FF25 08504000 jmp     [405008]  //F2下断点
00404A24   $- FF25 04504000 jmp     [405004]  //F2下断点
00404A2A   $- FF25 00504000 jmp     [405000]  //F2下断点
00404A30   $- FF25 10504000 jmp     [405010]  //F2下断点
00404A36   $- FF25 A8504000 jmp     [<&kernel32.RtlUnwind>]          ;  ntdll.RtlUnwind

  接下来就是要猜这些API函数了,运行加壳的trial.exe,来到OEP后,对00404A18~00404A36这段代码下断点。再运行程序,首先会中断在00404A30这行。

00404A18  - FF25 0C504000   jmp     [40500C]
00404A1E  - FF25 08504000   jmp     [405008]
00404A24  - FF25 04504000   jmp     [405004]
00404A2A  - FF25 00504000   jmp     [405000]
00404A30  - FF25 10504000   jmp     [405010]     //首先中断这行
00404A36  - FF25 A8504000   jmp     [4050A8]                         ; ntdll.RtlUnwind

然后查看堆栈,对返回地址设断:

0012FA84   004011AA  返回到 trial.004011AA 来自 trial.00404A30
0012FA88   00000000
0012FA8C   004086C0  trial.004086C0
0012FA90   004086C4  trial.004086C4

对004011AA 设断后,会来到:

00401196  |.  53            push    ebx
00401197  |.  56            push    esi
00401198  |.  57            push    edi
00401199  |.  68 C4864000   push    004086C4
0040119E  |.  68 C0864000   push    004086C0
004011A3  |.  6A 00         push    0
004011A5  |.  E8 86380000   call    00404A30
004011AA  |.  8B3D C0864000 mov     edi, [4086C0]  //来到这里

此时EAX=1,结合源码及ASProtect帮助文档,可以猜出这个是GetRegistrationInformation。
用这种方法就可确定其他几个函数:

00404A18  - FF25 0C504000   jmp     [40500C]                         ; GetHardwareID
00404A1E  - FF25 08504000   jmp     [405008]                         ; CheckKeyAndDecrypt
00404A24  - FF25 04504000   jmp     [405004]                         ; GetTrialDays
00404A2A  - FF25 00504000   jmp     [405000]                         ; GetModeInformation
00404A30  - FF25 10504000   jmp     [405010]                         ; GetRegistrationInformation
00404A36  - FF25 A8504000   jmp     [4050A8]                         ; ntdll.RtlUnwind

其中带key脱壳后,只有GetRegistrationInformation与GetModeInformation被调用(其他函数确定,请删除注册文件aspr_keys.ini尝试),因此只需要修复这2个函数即可。

3.1 构造 GetRegistrationInformation函数的参数及返回值

函数原型:
GetRegistrationInformation( 0, &Key, &Name );  

dumped_.exe程序中的代码:
00401199  |.  68 C4864000   push    004086C4   //&Name
0040119E  |.  68 C0864000   push    004086C0   //&Key
004011A3  |.  6A 00         push    0
004011A5  |.  E8 86380000   call    00404A30

00404A30   $ /FF25 10504000 jmp     [405010]                         ;  GetRegistrationInformation

找一段空地写下如下代码:

00404A41         mov     eax, [esp+8]
00404A45         mov     dword ptr [eax], 00404A5E        ;  ASCII "78787878" //参数Key
00404A4B         mov     eax, [esp+C]
00404A4F         mov     dword ptr [eax], 00404A68        ;  ASCII "pediy"   //参数Name
00404A55         mov     eax, 1                           //返回值
00404A5A         retn    0C

00404A5E  37 38 37 38 37 38 37 38 00 00 70 65 64 69 79 00  78787878..pediy.

再将00405010改成如下:
00405010  41 4A 40 00                                      AJ@.

这样jmp     [405010] 就能跳到00404A41 执行了。

3.2 构造GetModeInformation函数的参数及返回值

函数原型:
GetModeInformation( 0, &ModeName, &mode_status );

dumped_.exe程序中的代码:
00401205    52              push    edx       //&mode_status
00401206    68 CC864000     push    004086CC  //&ModeName
0040120B    6A 00           push    0
0040120D    E8 18380000     call    00404A2A // call GetModeInformation
……
00404A2A  - FF25 00504000   jmp     [405000]                         ; GetModeInformation

找一段空地写下如下代码:

00404A79       mov     eax, [esp+8]
00404A7D       mov     dword ptr [eax], 00404A8D        ;  ASCII "Registered"  //参数ModeName
00404A83       mov     eax, 1
00404A88       retn    0C

00404A8D  52 65 67 69 73 74 65 72 65 64 00 00 00 00 00 00  Registered......

再将00405000改成如下:
00405000  79 4A 40 00         

这样jmp     [405000]  就能跳到00404A79 执行了

--------------------------------------------------------------------------------

                                                      2006年07月10日 20:10:21

[招生]科锐逆向工程师培训46期预科班将于 2023年02月09日 正式开班

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (93)
雪    币: 2199
活跃值: 活跃值 (50)
能力值: (RANK:410 )
在线值:
发帖
回帖
粉丝
小虾 活跃值 10 2006-7-10 20:35
2
0
第一个学习。
雪    币: 106
活跃值: 活跃值 (373)
能力值: ( LV13,RANK:970 )
在线值:
发帖
回帖
粉丝
nbw 活跃值 24 2006-7-10 20:37
3
0
学习!
雪    币: 1141
能力值: (RANK:460 )
在线值:
发帖
回帖
粉丝
monkeycz 活跃值 11 2006-7-10 20:38
4
0
学习!
雪    币: 190
活跃值: 活跃值 (704)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
freecat 活跃值 1 2006-7-10 20:39
5
0
学习
雪    币: 231
活跃值: 活跃值 (156)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
liuyilin 活跃值 2006-7-10 20:41
6
0
还是学习
雪    币: 2133
活跃值: 活跃值 (793)
能力值: ( LV9,RANK:850 )
在线值:
发帖
回帖
粉丝
wofan[OCN] 活跃值 21 2006-7-10 20:42
7
0
对于好文是不顶不行了
雪    币: 201
活跃值: 活跃值 (10)
能力值: ( LV9,RANK:650 )
在线值:
发帖
回帖
粉丝
hbqjxhw 活跃值 16 2006-7-10 20:44
8
0
我说我第二个学习呢,没想到看完了,一下到了第八楼了
雪    币: 203
活跃值: 活跃值 (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
libozi 活跃值 2006-7-10 20:44
9
0
支持,学习中!
雪    币: 201
活跃值: 活跃值 (10)
能力值: ( LV9,RANK:210 )
在线值:
发帖
回帖
粉丝
windycandy 活跃值 5 2006-7-10 21:07
10
0
学习并不断成长ing.............
雪    币: 0
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
chinadev 活跃值 2006-7-10 22:09
11
0
好文不断~
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV9,RANK:1250 )
在线值:
发帖
回帖
粉丝
cyto 活跃值 31 2006-7-10 22:27
12
0
看完后有一种茅塞顿开的感觉。
坛主的这篇文章真是及时雨。
谢谢!
雪    币: 104
活跃值: 活跃值 (18)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
sbright 活跃值 2 2006-7-10 23:10
13
0
收藏!!!!
雪    币: 218
活跃值: 活跃值 (166)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Bewaar 活跃值 2006-7-11 00:07
14
0
老大的文章每次都有一种里程碑似的指导意义,学习了。
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
血草 活跃值 1 2006-7-11 01:01
15
0
此时EAX=1,结合源码及ASProtect帮助文档,可以猜出这个是GetRegistrationInformation。
用这种方法就可确定其他几个函数:

都用猜来判断下面的API吗?
雪    币: 10184
活跃值: 活跃值 (12807)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
kanxue 活跃值 8 2006-7-11 08:31
16
0
最初由 血草 发布

都用猜来判断下面的API吗?


经验很重要,根据参数及返回值来判断。
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
闲云 活跃值 2006-7-11 10:31
17
0
顶,学习中!!!
雪    币: 411
活跃值: 活跃值 (561)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
daxia200N 活跃值 6 2006-7-11 12:53
18
0
最初由 kanxue 发布
经验很重要,根据参数及返回值来判断。

做个通用版本的api ida签名,也许更容易些。
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
whg3249 活跃值 2006-7-11 13:03
19
0
看学老大就是牛,学习收藏
雪    币: 7137
活跃值: 活跃值 (3459)
能力值: (RANK:1130 )
在线值:
发帖
回帖
粉丝
海风月影 活跃值 22 2006-7-12 18:08
20
0
由KANXUE版主的教程看来,GetRegistrationInformation是ASP SDK中一个重要函数,
几乎每一个用到SDK的程序都要修复这个函数(由源代码可见,它是第一个被调用的)
但是,对于 构造 GetRegistrationInformation函数的参数及返回值
有一点不解:

以下是源代码:

  GetRegistrationInformation( 0, &UserKey,  &UserName );

  if ((UserKey != NULL) && (strlen(UserKey) > 0))
  {


GetRegistrationInformation这个函数并没有返回值,后面的判断也没用到返回值,
只是用到UserKey,为什么构造 GetRegistrationInformation函数的参数及返回值时要有个返回值 MOV EAX,1


00404A41         mov     eax, [esp+8]
00404A45         mov     dword ptr [eax], 00404A5E        ;  ASCII "78787878" //参数Key
00404A4B         mov     eax, [esp+C]
00404A4F         mov     dword ptr [eax], 00404A68        ;  ASCII "pediy"   //参数Name
00404A55         mov     eax, 1                           //返回值
00404A5A         retn    0C



确实有点不解,在ASProtect help中,作者的例子是:


 For Delphi:  
 
  
 
 Var  
 
   Key  : PChar;  
 
   Name : PChar;  
 
  
 
 begin  
 
   GetRegistrationInformation( 0, Key, Name );  
 
   MessageBox(0,StrPas(Key) + #13#10 + StrPas(Name),'Key/Name:',0);  
 
 end;   
 
  
 
 For C++:  
 
  
 
 {  
 
 char* Key = "";  
 
 char* Name = "";  
 
  
 
 GetRegistrationInformation( 0, &Key, &Name );  
 
 printf( " Key: %s\n Name: %s\n", Key, Name );  
 
 }  



也没用到返回值
雪    币: 10184
活跃值: 活跃值 (12807)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
kanxue 活跃值 8 2006-7-12 18:16
21
0
最初由 海风月影 发布
对于 构造 GetRegistrationInformation函数的参数及返回值 有一点不解:


你跟踪加壳程序,带key与不带key都跟一下,你会发现有key时这函数返回1,否则返回0.
当然此例中返回任何值都不影响程序功能。
雪    币: 7137
活跃值: 活跃值 (3459)
能力值: (RANK:1130 )
在线值:
发帖
回帖
粉丝
海风月影 活跃值 22 2006-7-12 22:57
22
0
最初由 kanxue 发布
你跟踪加壳程序,带key与不带key都跟一下,你会发现有key时这函数返回1,否则返回0.
当然此例中返回任何值都不影响程序功能。


也就是说,可以把程序写出这样了:


IsReg=GetRegistrationInformation( 0, &UserKey,  &UserName );

  if (IsReg) 
 {
  ...
 }



去试试看
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
木头 活跃值 2006-7-13 22:49
23
0
跟着老大的文章练习,很受益!
雪    币: 201
活跃值: 活跃值 (10)
能力值: ( LV9,RANK:650 )
在线值:
发帖
回帖
粉丝
hbqjxhw 活跃值 16 2006-7-14 01:33
24
0
#include "stdafx.h"
#include "resource.h"
#include <shellapi.h>
#include "include/aspr_api.h"
#include "include/asprotect.h"
#pragma comment(lib,"include/aspr_ide.lib")
kanxue楼主这几个文件在哪找?
雪    币: 202
活跃值: 活跃值 (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
snowshow 活跃值 2006-7-14 02:02
25
0
游客
登录 | 注册 方可回帖
返回