具体实施方式
为使本发明的目的、技术方案和优点更加清楚,下面将结合附图对本发明实施方式做进一步地详细描述。
实施例1
本实施例提供了一种模拟软件运行功能的方法。
参见图1,一种模拟软件运行功能的方法,具体实现步骤如下:
步骤101:外壳工具接收用户输入的对被加壳程序进行分析的信息,调用入口函数准备对被加壳程序进行分析;
在本实施例中,入口函数具体为OnAppOperateAnalyseIl()。
步骤102:判断上述被加壳程序中是否存在连续的指令序列,若不存在,则提示出错,若存在,则执行步骤103;
其中,指令序列具体可以为运算指令序列、常量加载指令序列、局部变量加载指令序列和局部变量存储指令序列;
在实施例步骤102中,外壳工具一次性从被加壳程序中查找出所有的连续的指令序列,再判断上述所有的连续的指令序列是否满足步骤103到步骤105所说的条件,最后步骤105得到的连续的指令序列则为满足所有条件的指令序列;
具体地,在本实施例中,以如下被加壳程序为例进行说明,被加壳程序如下:
.method assembly instance void DrawIsoMap(class
[System.Drawing]System.Drawing.Graphics A_1,
uint16A_2,
uint16A_3)cil
managed
{
.locals init(int16V_0,
int16V_1,
uint16V_2,
uint16V_3,
uint16V_4,
uint16V_5,
uint8V_6,
uint8V_7,
uint8V_8,
uint8V_9,
int16V_10,
int16V_11,
int16V_12,
int16V_13,
int16V_14,
int16V_15,
int16V_16,
int16V_17,
int32V_18,
int32V_19,
int32V_20,
int32V_21,
int32V_22,
int32V_23,
int32V_24,
int32V_25,
int32V_26,
uint16V_27)
IL_0000:ldc.i4.0
IL_0001:stloc.s V_6
……
IL_0035:ldarg.3
IL_0036:ldc.i4.s 15
IL_0038:and
IL_0039:stloc.s V_15
IL_003b:ldloc.s V_14
IL_003d:conv.i4
IL_003e:ldloc.s V_15
IL_0040:conv.i4
IL_0041:sub
IL_0042:conv.i2
IL_0043:stloc.s V_16
IL_0045:ldloc.s V_14
IL_0047:conv.i4
IL_0048:ldc.i4.1
IL_0049:shr.un
IL_004a:ldloc.s V_15
IL_004c:conv.i4
IL_004d:ldc.i4.1
IL_004e:shr.un
IL_004f:add
IL_0050:conv.i2
IL_0051:stloc.s V_17
IL_0053:ldc.i40xff
IL_0058:stloc.s V_8
IL_005a:ldloc.s V_10
IL_005c:stloc.s V_12
IL_005e:ldloc.s V_11
IL_0060:stloc.s V_13
IL_0062:ldc.i4.8
IL_0063:ldloc.s V_17
IL_0065:conv.i4
IL_0066:sub
IL_0067:stloc.s V_19
IL_0069:ldc.i4.0
IL_006a:stloc.s V_4
IL_006c:ldloc.s V_12
IL_006e:stloc.0
IL_006f:ldloc.s V_13
IL_0071:stloc.1
IL_0072:ldc.i4.s 16
IL_0074:ldloc.s V_16
IL_0076:conv.i4
IL_0077:sub
IL_0078:stloc.s V_18
IL_007a:ldc.i4.s 24
IL_007c:stloc.s V_20
IL_007e:ldloc.s V_4
IL_0080:conv.u4
IL_0081:ldc.i4.1
IL_0082:and
IL_0083:brfalse.s IL_0092
IL_0085:ldloc.s V_20
……
IL_0160:ldarg.0
IL_0161:ldfld int16Ma in.TIsoForm::FSpriteY
IL_0166:ldc.i4.s 15
IL_0168:and
IL_0169:stloc.s V_15
IL_016b:ldloc.s V_14
IL_016d:conv.i4
IL_016e:ldloc.s V_15
IL_0170:conv.i4
IL_0171:sub
IL_0172:stloc.s V_25
IL_0174:ldloc.s V_14
IL_0176:conv.i4
IL_0177:ldc.i4.1
IL_0178:shr.un
IL_0179:ldloc.s V_15
IL_017b:conv.i4
IL_017c:ldc.i4.1
IL_017d:shr.un
IL_017e:add
IL_017f:stloc.s V_26
IL_0181:ldarg.1
……
IL_02cd:ble.un IL_0053
IL_02d2:ret
}
经过判断之后可以得到上述被加壳程序中存在两段连续的指令序列,分别如下:
IL_0038:and
IL_0039:stloc.s V_15
IL_003b:ldloc.s V_14
IL_003d:conv.i4
IL_003e:ldloc.s V_15
IL_0040:conv.i4
IL_0041:sub
IL_0042:conv.i2
IL_0043:stloc.s V_16
IL_0045:ldloc.s V_14
IL_0047:conv.i4
IL_0048:ldc.i4.1
IL_0049:shr.un
IL_004a:ldloc.s V_15
IL_004c:conv.i4
IL_004d:ldc.i4.1
IL_004e:shr.un
IL_004f:add
IL_0050:conv.i2
IL_0051:stloc.s V_17
IL_0053:ldc.i4 0xff
IL_0058:stloc.s V_8
IL_005a:ldloc.s V_10
IL_005c:stloc.s V_12
IL_005e:ldloc.s V_11
IL_0060:stloc.s V_13
IL_0062:ldc.i4.8
IL_0063:ldloc.s V_17
IL_0065:conv.i4
IL_0066:sub
IL_0067:stloc.s V_19
IL_0069:ldc.i4.0
IL_006a:stloc.s V_4
IL_006c:ldloc.s V_12
IL_006e:stloc.0
IL_006f:ldloc.s V_13
IL_0071:stloc.1
IL_0072:ldc.i4.s 16
IL_0074:ldloc.s V_16
IL_0076:conv.i4
IL_0077:sub
IL_0078:stloc.s V_18
IL_007a:ldc.i4.s 24
IL_007c:stloc.s V_20
IL_007e:ldloc.s V_4
IL_0080:conv.u4
IL_0081:ldc.i4.1
IL_0082:and
和
IL_0168:and
IL_0169:stloc.s V_15
IL_016b:ldloc.s V_14
IL_016d:conv.i4
IL_016e:ldloc.s V_15
IL_0170:conv.i4
IL_0171:sub
IL_0172:stloc.s V_25
IL_0174:ldloc.s V_14
IL_0176:conv.i4
IL_0177:ldc.i4.1
IL_0178:shr.un
IL_0179:ldloc.s V_15
IL_017b:conv.i4
IL_017c:ldc.i4.1
IL_017d:shr.un
IL_017e:add
IL_017f:stloc.s V_26
具体地,在实际操作中从被加壳程序中得到的连续的指令序列可能为两个以上的多个,而本实施例具体以两个连续的指令序列为例进行说明。
步骤103:判断步骤102得到的连续的指令序列中是否存在其所访问的局部变量的类型为卡片中所支持类型的连续的指令序列,若否,则提示出错,若是,则执行步骤104;
在本实施例中,根据方法头中的信息可以知道上述两段连续的指令序列所访问的局部变量的类型具体为uint16、uint 8、int16和int32,并且局部变量的类型uint16、uint8、int16和int32均是卡片所支持的类型,因此上述两段连续的指令序列均满足条件,执行步骤104。
步骤104:判断将上述连续的指令序列分别组装成卡内服务后得到的堆栈中是否存在平衡的堆栈,若否,则提示出错,若是,则执行步骤105;
在本实施例中,将上述两段连续的指令序列组装成卡内服务后,第一段连续的指令序列得到的堆栈不为0,不是平衡的,第二段连续的指令序列得到的堆栈为0,是平衡的,因此第二段连续的指令序列满足步骤104所说的条件,继续执行步骤105。
步骤105:判断堆栈平衡的连续指令序列是否为其他指令的跳转目的地,若是,则提示出错信息,若否,则执行步骤106;
在本实施例中,对上述被加壳程度中的所有指令逐行进行分析,没有发现有跳转指令的目的地址,因此可以知道上述堆栈平衡的连续指令序列也不是其他指令的跳转目的地,继续执行步骤106;
并且本实施例中的步骤102-步骤105具体为被加壳程序进行分析的步骤,通过上述步骤就可以分析出满足条件的指令序列,并且步骤102-步骤105的4个步骤之间的执行可以是没有顺序的,可以是先执行步骤102,再执行步骤105,然后执行步骤103和步骤104等等,本实施例中为了提高对加壳程序的分析的效率,选择了顺序执行步骤102-步骤105,但不以此执行顺序为限制;
进一步地,本实施例中对被加壳程序进行分析的方法还可以为:从被加壳程序中查找连续的指令序列,每查找到一个指令序列就判断该指令序列是否满足步骤103至步骤105所说的条件,如果不满足,则继续查找下一个连续的指令序列,并对该指令序列进行判断,若满足,则记录下该指令序列的具体位置,并判断是否已查找完上述被加壳程序,若否,则继续查找下一个连续的指令序列,并进行判断,若是,则执行步骤107;
具体地,在实际操作中经过分析满足上述条件的连续的指令序列一般要大于一个,而本实施例具体以一个满足条件的连续的指令序列为例进行说明。
步骤106:记录下满足条件的连续指令序列的具体位置;
其中,具体位置可以是上述满足条件的指令序列的起始位置,也可以是上述指令序列的终止位置。
步骤107:生成被加壳程序的副本,在被加壳程序的副本的上述具体位置上插入对本地动态库的调用语句;
在本实施例中,可以在步骤107生成被加壳程序的副本,也可以在步骤102判断被加壳程序中是否存在连续的指令序列之前生成被加壳程序的副本,相应地,步骤102至步骤105也可以是对被加壳程序的副本进行分析;
由于具体位置可以是分析得到的指令序列的起始位置或终止位置,因此可以是在指令序列的起始位置插入对本地动态库的调用语句,也可以是在指令序列的终止位置插入对本地动态库的调用语句;
其中插入的对本地动态库的调用语句具体为:call Fun2();
具体地,当分析得到有多个连续的指令序列都满足条件时,则步骤106中会相应地记录下多个具体位置,因此本步骤中外壳工具根据用户的选择在被加壳程序的副本的相应的具体位置上插入对本地动态库的调用语句,其中用户可以选择一个具体位置,也可以选择多个具体位置;
进一步地,在本实施例中,本地动态库是通过对如下的源代码进行编译来实现的,是一个标准的Win32动态库文件,源代码具体如下:
//
//动态库入口函数
//
int WINAPI DllMain(HINSTANCE hInstance,DWORD dwReason,VOID*
pReserved)
{
g_hModule=hInstance;
switch(dwReason)
{
case DLL_PROCESS_ATTACH://动态链接库被加载
Attach();
break;
case DLL_PROCESS_DETACH://动态链接库被卸载
Detach();
break;
case DLL_THREAD_ATTACH://宿主程序中创建了一个新的线程
break;
case DLL_THREAD_DETACH://宿主程序中结束了一个线程
break;
}
hMutex=CreateMutex(NULL,FALSE,NULL);
return TRUE;
}
//
//创建共享内存
//
extern″C″void__declspec(dllexport)Fun2(int methodSerial)
{
//打开或创建指定名称的共享内存
g_hSimulantFile=::OpenFileMapping(FILE_MAP_READ|
FILE_MAP_WRITE,0,″R7_Simulant_Share″);
if(!g_hSimulantFile)
{
g_hSimulantFile=::CreateFileMapping((HANDLE)-1,NULL,
PAGE_READWRITE,0,1024,″R7_Simulant_Share″);
if(!g_hSimulantFile)
{
return;
}
}
//获取共享内存基址
g_pSimulantMemory=::MapViewOfFile(g_hSimulantFile,
FILE_MAP_READ|FILE_MAP_WRITE,0,0,0);
if(!g_pSimulantMemory)
{
return;
}
//记录相应函数被调用的次数
*(DWORD*)((DWORD*)g_pSimulantMemory+methodSerial)+=1;
具体地,在动态库中包括一个固定的方法,每次动态库被调用时都是调用该方法,该方法中有具体的参数,通过对参数的设置可以将该方法模拟为具体地将连续的指令序列组装成锁内服务后的方法,因此通过将该方法中设置不同参数就可以表示将不同的连续的指令序列组装成锁内服务后的方法,这样通过对动态库的调用就可以模拟为对加密锁内的组装成卡内服务的方法的调用,而不用实际的将连续的指令序列放入加密锁中,再访问加密锁就可以预先知道相应的效果;
进一步地,当上述动态库被调用时,动态库中的Fun2函数模块会判断是否存在预先约定名称的共享内存,若不存在,则创建一个预先约定名称的共享内存,若存在,则打开上述预先约定名称的共享内存,其中共享内存用来与外壳工具之间进行传递有关模拟运行信息,具体地也可以用文件来替代共享内存,用文件来记录有关模拟运行信息;
在本实施例中,共享内存的具体格式是一个DWORD数组,具体如下所示,每一项中存储了一个数值,该数值代表了不同参数的方法被调用的次数,因此当上述被加壳程序模拟运行完成后,外壳工具就可以从该共享内存中读取并分析出来的连续的指令序列组装成完整锁内服务的方法后被调用的次数。
第1个方法的运行次数 |
第2个方法的运行次数 |
第3个方法的运行次数 |
… |
… |
… |
… |
第n个方法的运行次数 |
步骤108:外壳工具启动并运行上述插入对本地动态库的调用语句之后的被加壳程序副本,进行模拟运行,并且在运行时调用上述本地动态库;
在本实施例中,当上述本地动态库被调用时,本地动态库中的函数会判断是否存在预先约定名称的共享内存,若不存在,则创建一个预先约定名称的共享内存,并在共享内存中记录下模拟运行信息;若存在,则打开预先约定名称的共享内存,在共享内存中记录下模拟运行信息;
具体地,本实施例中,由于在步骤107中已经建立约定名称的共享内存,本地动态库中的函数直接打开预先约定名称的共享内存,并在动态库中的方法每被调用一次时,根据该方法中的参数查找该方法在共享内存中的对应位置,并将对应位置的计数信息加1,表示设为该参数的方法再一次被调用。
步骤109:上述被加壳程序的副本运行结束后,外壳工具从共享内存中读取模拟运行信息并显示在界面上;
在本实施例中,模拟运行信息具体为计数信息。
步骤110:外壳工具删除上述用来模拟的被加壳程序的副本,不改变原有的被加壳程序;
步骤111:外壳工具对读取得到的多个模拟运行信息进行分析和比较,查看模拟运行效果,选择保护方案。
在本实施例中,对多个模拟运行信息进行分析和比较的操作具体为:由于模拟运行信息具体为计数信息,因此通过计数信息可以知道实际运行上述被加壳程序时各个被分析出来的连续代码段被调用的次数,从而可以明确模拟运行的效果,例如当某个连续代码段对应的计数信息为0时,则表示该连续代码段没有被调用,将该连续代码段放在加密锁内的作用不大,当某个连续代码段对应的计数信息达到1000时,则表示该连续代码段被调用的次数太多,将其放在加密锁内可以能影响效率,因此可以根据具体需求按照各个连续代码段的模拟运行信息来决定将哪个连续代码段放在加密锁内。
本实施例提供了一种模拟软件运行的方法,通过该方法预先模拟各种保护方案,并自动分析模拟得到的相关数据,提供评定保护效果,并且在模拟过程中可预先处理保护信息,提升最终真正保护软件的效率,进一步实现了透明的软件保护,提高了效率,节约了资源,方便直观得选择最合适的保护方案。
实施例2
本实施例提供了另一种模拟软件运行功能的方法,在本实施例中,通过在被加壳程序的副本中嵌入一段代码,并在被加壳程序的副本的特定位置插入跳转指令,直接跳转到嵌入的代码,通过执行嵌入的代码来实现模拟软件运行,其中该嵌入的代码段实现的功能与实施例1中的动态库实现的功能一样。
参见图2,另一种模拟软件运行功能的方法,具体实现如下:
步骤201:外壳工具接收用户输入的对被加壳程序进行分析的信息,调用入口函数准备对被加壳程序进行分析;
在本实施例中,入口函数具体为OnAppOperateAnalyseIl()。
步骤202:外壳工具在上述被加壳程序中查找连续的指令序列,若查找到连续的指令序列,则执行步骤203,否则提示出错;
其中,指令序列具体可以为运算指令序列、常量加载指令序列、局部变量加载指令序列和局部变量存储指令序列;
并且在本实施例中,外壳工具在被加壳程序中查找连续的指令序列时具体为:当外壳工具每查找到一个连续的指令序列时就判断该连续的指令序列是否满足步骤203至步骤205所说的条件,若该连续的指令序列不满足条件时,则返回步骤202继续在上述被加壳程序中查找下一个连续的指令序列,并进行判断,若该连续的指令序列满足条件时,则执行步骤206记录下该连续的指令序列的具体位置,并返回步骤202继续在上述被加壳程序中查找下一个连续的指令序列,并进行判断,如此反复,直到查找完该被加壳程序。
步骤203:判断查找到的该连续的指令序列所访问的局部变量的类型是否为卡片中所支持的类型,若否,则返回到步骤202继续在被加壳程序中查找下一个连续的指令序列,若是,则执行步骤204;
步骤204:判断将上述连续的指令序列组装成卡内服务后得到的堆栈是否平衡,若否,则返回到步骤202继续在被加壳程序中查找下一个连续的指令序列,若是,则执行步骤205;
步骤205:判断上述连续指令序列是否为其他指令的跳转目的地,若是,则返回到步骤202继续在被加壳程序中查找下一个连续的指令序列,若否,则执行步骤206;
在本实施例中,判断上述连续指令序列是否为其他指令的跳转目的地的方法具体为:对上述被加壳程度中的所有指令逐行进行分析,没有发现有跳转指令的目的地址,因此上述连续指令序列也不是其他指令的跳转目的地;
具体地,本实施例中的步骤202-步骤205具体为对被加壳程序进行分析的步骤,通过上述步骤就可以分析出满足条件的指令序列,并且步骤202-步骤205的4个步骤之间的执行可以是没有顺序的,可以是先执行步骤202,再执行步骤205,然后执行步骤203和步骤204等等,本实施例中为了提高对加壳程序的分析的效率,选择了顺序执行步骤202-步骤205,但不以此执行顺序为限制;
进一步地,本实施例中对被加壳程序进行分析的方法还可以如实施例1中所说的一样,即先从被加壳程序中查找到所有的连续的指令序列,再判断上述查找到的所有的指令序列所访问的局部变量的类型是否为卡片中所支持的类型,再判断满足上述条件的指令序列组装成卡内服务后得到的堆栈是否平衡,最后判断满足上述条件的指令序列是否为其他指令的跳转目的地,最后得到的指令序列则为满足所有条件的指令序列;
具体地,在实际操作中经过分析满足上述条件的连续的指令序列一般要大于一个。
步骤206:记录下上述连续的指令序列的具体位置;
在本实施例中,具体位置可以是上述指令序列的起始位置,也可以是上述指令序列的终止位置。
步骤207:判断是否查找完上述被加壳程序,若否,则返回到步骤202继续在被加壳程序中查找下一个连续的指令序列,若是,则执行步骤208;
步骤208:生成被加壳程序的副本,在被加壳程序的副本的上述具体位置上插入跳转语句;
在本实施例中,进一步地,在插入跳转语句的同时在上述被加壳程序的副本的后面嵌入代码段,其中代码段具体用于实现模拟软件运行,并且由于具体位置可以是分析得到的指令序列的起始位置或终止位置,因此可以是在指令序列的起始位置插入跳转语句,也可以是在指令序列的终止位置插入跳转语句;
其中插入的跳转语句具体为:jmp FLAG,具体用于跳转到嵌入的代码段;
具体地,当分析得到有多个连续的指令序列都满足条件时,则步骤206中会相应地记录下多个具体位置,因此本步骤中外壳工具根据用户的选择在被加壳程序的副本的相应的具体位置上插入跳转语句,其中用户可以选择一个具体位置,也可以选择多个具体位置;
并且本实施例中可以在步骤208生成被加壳程序的副本,也可以在步骤202判断被加壳程序中是否存在连续的指令序列之前生成被加壳程序的副本,相应地,步骤202至步骤205也可以是对被加壳程序的副本进行分析;
在本实施例中,在被加壳程序的副本中嵌入的代码段实现的功能与实施例1中的动态库实现的功能是一样的,并且嵌入的代码段中有一个固定的方法,每次该代码段执行时则执行该方法,该方法中有具体的参数,通过对参数的设置可以将该方法模拟为具体地将连续的指令序列组装成锁内服务后的方法,因此不同参数的上述方法就表示将不同的连续的指令序列组装成锁内服务后的方法,这样通过对上述代码段的执行就可以模拟为对加密锁内的组装成卡内服务的方法的执行,而不用实际的将连续的指令序列放入加密锁中,再访问加密锁就可以预先知道相应的效果,并且代码段是在外壳工具启动并运行上述插入跳转语句之后的被加壳程序的副本之前的插入到被加壳程序的副本中的;
进一步地,当上述代码段执行时,代码段中的函数会判断是否存在预先约定名称的文件,若不存在,则创建一个预先约定名称的文件,若存在,则打开上述预先约定名称的文件,其中预先约定名称的文件是用来与外壳工具之间进行传递有关模拟运行信息,具体地,也可以如实施例1中所说的通过共享内存来记录有关模拟运行信息,通过共享内存与外壳工具之间进行传递;
步骤209:外壳工具启动并运行上述插入跳转语句之后的被加壳程序副本,进行模拟运行,并且在运行时跳转到上述嵌入的代码段;
在本实施例中,当上述嵌入的代码段执行时,代码段中的函数会判断是否存在预先约定名称的文件,若不存在,则创建一个预先约定名称的文件,并在文件中记录下模拟运行的相关信息;若存在,则打开预先约定名称的文件,在文件中记录下模拟运行的相关信息;
具体地,本实施例中,代码段中的函数直接打开预先约定名称的文件,并在代码段中的方法每执行一次时,根据该方法中的参数查找该方法在文件中的对应位置,并将对应位置的计数信息加1,表示设为该参数的方法再一次执行。
步骤210:运行结束后,外壳工具从文件中读取模拟运行信息并显示在界面上;
在本实施例中,模拟运行信息具体为计数信息。
步骤211:外壳工具删除上述用来模拟的被加壳程序的副本,不改变原有的被加壳程序;
步骤212:外壳工具对读取得到的多个模拟运行信息进行分析和比较,查看模拟运行效果,选择保护方案。
在本实施例中,由于模拟运行信息具体为计数信息,因此通过计数信息可以知道实际运行上述被加壳程序时各个被分析出来的连续代码段被调用的次数,从而可以明确模拟运行的效果,例如当某个连续代码段对应的计数信息为0时,则表示该连续代码段没有被调用,将该连续代码段放在加密锁内的作用不大,当某个连续代码段对应的计数信息达到1000时,则表示该连续代码段被调用的次数太多,将其放在加密锁内可以能影响效率,因此可以根据具体需求按照各个连续代码段的模拟运行信息来决定将哪个连续代码段放在加密锁内。
本实施例提供了一种模拟软件运行的方法,通过该方法预先模拟各种保护方案,并自动分析模拟得到的相关数据,提供评定保护效果,并且在模拟过程中可预先处理保护信息,提升最终真正保护软件的效率,进一步实现了透明的软件保护,提高了效率,节约了资源,方便直观得选择最合适的保护方案。
实施例3
本实施例提供了又一种模拟软件运行功能的方法,在本实施例中,将分析得到的指令序列放入软加密锁中,在被加壳程序的副本的具体位置插入对软加密锁的调用指令,并通过对软加密锁的调用来实现模拟软件运行。
参见图3,又一种模拟软件运行功能的方法,具体实现如下:
步骤301:外壳工具接收用户输入的对被加壳程序进行分析的信息,调用入口函数准备对被加壳程序进行分析;
在本实施例中,入口函数具体为OnAppOperateAnalyseIl()。
步骤302:外壳工具在上述被加壳程序中查找出所有的连续的指令序列,若查找到连续的指令序列,则执行步骤303,否则提示出错;
其中,指令序列具体可以为运算指令序列、常量加载指令序列、局部变量加载指令序列和局部变量存储指令序列;
在本实施例中,在被加壳程序中查找连续的指令序列的方法与实施例1中所说的方法一致,在此不再重复。
步骤303:判断上述所有的连续的指令序列中是否存在其所访问的局部变量的类型为卡片中所支持类型的连续的指令序列,若是,则执行步骤304,否则提示出错;
步骤304:判断将上述满足步骤303的条件的指令序列分别组装成卡内服务后得到的堆栈中是否存在平衡的堆栈,若否,则提示出错,若是,则执行步骤305;
步骤305:判断上述满足步骤304的条件的指令序列是否为其他指令的跳转目的地,若是,则返回到步骤302继续在被加壳程序中查找连续的指令序列,若否,则执行步骤306;
在本实施例中,判断上述连续指令序列是否为其他指令的跳转目的地的方法与实施例1中的方法相似,在此不再重复;
具体地,本实施例中的步骤302-步骤305具体为对被加壳程序进行分析的步骤,通过上述步骤就可以分析出满足条件的指令序列,并且步骤302-步骤305的4个步骤之间的执行可以是没有顺序的,本实施例中为了提高对加壳程序的分析的效率,选择了顺序执行步骤302-步骤305,但不以此执行顺序为限制;
进一步地,本实施例中对被加壳程序进行分析的方法还可以如实施例2中所述相同,即从被加壳程序中查找连续的指令序列,每查找到一个指令序列就判断该指令序列是否满足步骤303至步骤305所说的条件,如果不满足,则继续查找下一个连续的指令序列,并对该指令序列进行判断,若满足则记录下该指令序列的具体位置,并判断是否已查找完上述被加壳程序,若否,则继续查找下一个连续的指令序列,并进行判断,若是,则执行步骤307;
具体地,在实际操作中经过分析满足上述条件的连续的指令序列一般要大于一个。
步骤306:记录下满足上述条件的连续的指令序列的具体位置;
步骤307:生成一个被加壳程序的副本,在被加壳程序的副本的上述具体位置插入对软加密锁的调用语句;
在本实施例中,由于具体位置可以是分析得到的指令序列的起始位置或终止位置,因此可以是在指令序列的起始位置插入对软加密锁的调用语句,也可以是在指令序列的终止位置插入对软加密锁的调用语句;
其中插入的对软加密锁的调用语句具体为:call Fun2();
具体地,当分析得到有多个连续的指令序列都满足条件时,则步骤306中会相应地记录下多个具体位置,因此本步骤中外壳工具根据用户的选择在被加壳程序的副本的相应的具体位置上插入对软加密锁的调用语句,其中用户可以选择一个具体位置,也可以选择多个具体位置;
并且本实施例中可以在步骤307生成被加壳程序的副本,也可以在步骤302判断被加壳程序中是否存在连续的指令序列之前生成被加壳程序的副本,相应地,步骤302至步骤305也可以是对被加壳程序的副本进行分析;
在本实施例中,软加密锁实现的功能与实施例1中的动态库实现的功能是一样的,并且软加密锁中有一个固定的方法,每次调用软加密锁时时则调用该方法,该方法中有具体的参数,并且外壳工具将需要调用的方法的相关内容以参数的形式通过软加密锁提供的接口传给上述软加密锁中的方法,这样就可以对上述软加密锁中的方法中的参数进行设置,从而可以将上述软加密锁中的方法模拟为将不同的连续的指令序列组装成锁内服务后的方法,因此不同参数的上述方法就表示将不同的连续的指令序列组装成锁内服务后的方法,这样通过对上述代码段的执行就可以模拟为对加密锁内的组装成卡内服务的方法的执行,而不用实际的将连续的指令序列放入加密锁中,在访问加密锁前就可以预先知道相应的效果;
进一步地,当上述软加密锁被调用时,软加密锁中的函数会判断是否存在预先约定名称的文件,若不存在,则创建一个预先约定名称的文件,若存在,则打开上述预先约定名称的文件,其中预先约定名称的文件是用来与外壳工具之间进行传递有关模拟运行的相关信息,具体地,也可以如实施例1中所说的通过共享内存来记录有关模拟运行的相关信息,通过共享内存与外壳工具之间进行传递;
步骤308:外壳工具启动并运行上述插入对软加密锁的调用语句之后的被加壳程序的副本,进行模拟运行,并且在运行时调用软加密锁;
在本实施例中,当上述软加密锁被调用时,软加密锁中的函数会判断是否存在预先约定名称的文件,若不存在,则创建一个预先约定名称的文件,并在文件中记录下模拟运行信息;若存在,则打开预先约定名称的文件,在文件中记录下模拟运行信息;
具体地,本实施例中,软加密锁中的函数直接打开预先约定名称的文件,并在软加密锁中的方法每被调用一次时,根据该方法中的参数查找该方法在共享内存中的对应位置,并将对应位置的计数信息加1,表示设为该参数的方法再一次被调用。
步骤309:运行结束后,外壳工具从文件中读取模拟运行信息并显示在界面上;
在本实施例中,模拟运行信息具体为计数信息。
步骤310:外壳工具删除上述用来模拟的被加壳程序的副本,不改变原有的被加壳程序;
步骤311:外壳工具对读取得到的多个模拟运行信息进行分析和比较,查看模拟运行效果,选择保护方案。
在本实施例中,对多个模拟运行信息进行分析和比较的操作具体为:由于模拟运行信息具体为计数信息,因此通过计数信息可以知道实际运行上述被加壳程序时各个被分析出来的连续代码段被调用的次数,从而可以明确模拟运行的效果,例如当某个连续代码段对应的计数信息为0时,则表示该连续代码段没有被调用,将该连续代码段放在加密锁内的作用不大,当某个连续代码段对应的计数信息达到1000时,则表示该连续代码段被调用的次数太多,将其放在加密锁内可以能影响效率,因此可以根据具体需求按照各个连续代码段的模拟运行信息来决定将哪个连续代码段放在加密锁内。
本实施例提供了一种模拟软件运行的方法,通过该方法预先模拟各种保护方案,并自动分析模拟得到的相关数据,提供评定保护效果,并且在模拟过程中可预先处理保护信息,提升最终真正保护软件的效率,进一步实现了透明的软件保护,提高了效率,节约了资源,方便直观得选择最合适的保护方案。