发明内容
有鉴于现有技术中存在的上述问题,本申请提供了一种函数调用方法、装置及计算机可读存储介质,本申请实施例采用的技术方案如下:
函数调用方法,包括:
以重定位方式记录函数的第一地址;
随机确定地址空间;
响应于所记录的第一地址导入地址空间,在所述地址空间中随机配置并记录用于进行函数调用的第二地址,在多个函数的情况下,多个第二地址与多个第一地址的顺序不同;
响应于基于第二地址调用函数的指令进行函数调用。
在一些实施例中,所述以重定位方式记录函数的第一地址,包括:
构建第一地址表,记录以重定位方式处理后每个被引用过的函数的第一地址。
在一些实施例中,所述随机确定地址空间,包括:
至少随机获取不包含初始内容的地址空间,用于构建第二地址表,该地址空间不小于能够容纳所述第一地址的数量的空间。
在一些实施例中,所述响应于所记录的第一地址导入地址空间,在所述地址空间中随机配置并记录用于进行函数调用的第二地址,包括:
按照与所述第一表中不同的顺序将第一地址随机导入所述第二地址表,配置包含在所述第二地址表中的第二地址;
所述方法还包括:
配置基于所述第二地址表中的第二地址调用函数的指令。
在一些实施例中,所述响应于基于第二地址调用函数的指令进行函数调用,包括:
响应于基于第三地址调用函数的指令进行函数调用,所述第三地址为所述第二地址的实际地址。
在一些实施例中,所述第三地址包括内存地址。
在一些实施例中,所述按照与所述第一表中不同的顺序将第一地址随机导入所述第二地址表,包括:
对导入操作进行防解析处理,防止函数被分析出算法内容;所述防解析处理包括:将与导入操作相关的函数通过混淆和/或虚拟化进行更改。
函数调用装置,包括:
第一配置模块,其配置为用于以重定位方式记录函数的第一地址;
第二配置模块,其配置为用于随机确定地址空间;
初始化模块,其配置为用于响应于所记录的第一地址导入地址空间,在所述地址空间中随机配置并记录用于进行函数调用的第二地址,在多个函数的情况下,多个第二地址与多个第一地址的顺序不同;
调用模块,其配置为用于响应于基于第二地址调用函数的指令进行函数调用。
在一些实施例中,所述调用模块,进一步配置为用于:
响应于基于第三地址调用函数的指令进行函数调用,所述第三地址为所述第二地址的实际地址。
计算机可读存储介质,所述计算机可读存储介质中存储有计算机可执行指令,在执行所述计算机可读存储介质中的所述计算机可执行指令时实现如上任一项所述的方法。
本申请实施例的函数调用方法,记录了作为函数的实际地址的第一地址,在程序非运行状态下,所记录的第一地址并未导入调取函数的指令所指向的地址空间,调取函数的指令与函数的第一地址并未形成调用关系,能够防止通过静态分析方式查看函数调用逻辑;在程序运行过程中,将所记录的第一地址随机写入地址空间以形成第二地址,使得指向地址空间的调用函数的指令与函数的实际地址形成调用关系,执行调用函数的指令时,能够基于第二地址调用相应的函数并执行相应的操作,以保证程序的正常运行。
具体实施方式
此处参考附图描述本申请的各种方案以及特征。
应理解的是,可以对此处申请的实施例做出各种修改。因此,上述说明书不应该视为限制,而仅是作为实施例的范例。本领域的技术人员将想到在本申请的范围和精神内的其他修改。
包含在说明书中并构成说明书的一部分的附图示出了本申请的实施例,并且与上面给出的对本申请的大致描述以及下面给出的对实施例的详细描述一起用于解释本申请的原理。
通过下面参照附图对给定为非限制性实例的实施例的优选形式的描述,本申请的这些和其它特性将会变得显而易见。
还应当理解,尽管已经参照一些具体实例对本申请进行了描述,但本领域技术人员能够确定地实现本申请的很多其它等效形式。
当结合附图时,鉴于以下详细说明,本申请的上述和其他方面、特征和优势将变得更为显而易见。
此后参照附图描述本申请的具体实施例;然而,应当理解,所申请的实施例仅仅是本申请的实例,其可采用多种方式实施。熟知和/或重复的功能和结构并未详细描述以避免不必要或多余的细节使得本申请模糊不清。因此,本文所申请的具体的结构性和功能性细节并非意在限定,而是仅仅作为权利要求的基础和代表性基础用于教导本领域技术人员以实质上任意合适的详细结构多样地使用本申请。
本说明书可使用词组“在一种实施例中”、“在另一个实施例中”、“在又一实施例中”或“在其他实施例中”,其均可指代根据本申请的相同或不同实施例中的一个或多个。
图1为本申请实施例的函数调用方法的流程图,参见图1所示,本申请实施例的函数调用方法具体包括如下步骤:
S1,以重定位方式记录函数的第一地址。
重定位是把程序中逻辑地址变换成内存中物理地址的过程。逻辑地址是指一个源程序在编译或者连接装配后指令和数据所用的相对地址。物理地址为内存中存储单元对应的实际地址。通过重定位方式所记录的函数的第一地址,实际即为内存中存储该函数的存储单元的实际地址。
S2,随机确定地址空间。
该地址空间为用于容纳函数的实际地址的空间,初始状态下,该地址空间可为空,也即,该随机确定的地址空间不包含初始内容。该地址空间也为供调用函数的指令所指向的地址空间。在具体实施时,该随机确定地址空间可包括:随机确定地址空间,并配置指向所述地址空间的调用函数的指令。
S3,响应于所记录的第一地址导入地址空间,在所述地址空间中随机配置并记录用于进行函数调用的第二地址,在多个函数的情况下,多个第二地址与多个第一地址的顺序不同。
在程序初始化阶段,可通过一初始化程序调取所记录的函数的第一地址,并在地址空间中随机写入第一地址以形成第二地址,从而使得指向所述地址空间的调用函数的指令与第二地址形成调用关系。在具体实施时,可在初始化程序中配置随机化算法,初始化程序可基于该随机化算法在地址空间中随机写入第一地址。在程序引用多个函数的情况下,随机化配置第二地址,可以调整第二地址的排序,使得第一地址和第二地址的排序不同,以隐藏调用函数的指令与函数的实际地址之间的真实调用关系。
S4,响应于基于第二地址调用函数的指令进行函数调用。
在程序运行过程中,根据调取函数的指令从地址空间中调取对应的第二地址,进而基于该第二地址调取相应的函数,以执行相应的操作,从而保证程序能够正常运行。
本申请实施例的函数调用方法,记录了作为函数的实际地址的第一地址,在程序非运行状态下,所记录的第一地址并未导入调取函数的指令所指向的地址空间,调取函数的指令与函数的第一地址并未形成调用关系,能够防止通过静态分析方式查看函数调用逻辑;在程序运行过程中,将所记录的第一地址随机写入地址空间以形成第二地址,使得指向地址空间的调用函数的指令与函数的实际地址形成调用关系,执行调用函数的指令时,能够基于第二地址调用相应的函数并执行相应的操作,以保证程序的正常运行。
在一些实施例中,所述以重定位方式记录函数的第一地址,包括:
构建第一地址表,记录以重定位方式处理后每个被引用过的函数的第一地址。
在实际应用时,每个静态库中通常包含多个函数,但应用程序并不一定会引用该静态库中的全部函数,通常只是基于需求引用从静态库中引用所需的函数。因此,可确定被程序所引用的函数,并通过重定位的方式获取被应用的函数的实际地址,将这些被引用的函数的实际地址写入第一地址表的各个表项中作为第一地址。
以下结合一具体实施例对该步骤进行详细说明,本实施例以C语言程序示例,并不限制以其他程序代码构建的应用程序运行场景。在该具体实施例中包括_f1、_f2和printf三个被引用的函数,故第一地址表中包含3个表项,每项4个字节,C语言的程序代码如下:
基于上述C语言程序代码显示,第一地址表中第一地址位于.data字段中,字节数为0xC(即12),按照_f1、_f2、_printf顺序添加了三个重定位。
在一些实施例中,随机确定地址空间,可包括:
至少随机获取不包含初始内容的地址空间,用于构建第二地址表,该地址空间不小于能够容纳所述第一地址的数量的空间。
在确定被引用的函数的数量的情况下,可构建足以容纳相应数量的函数的第一地址的第二地址表,优选的,该第二地址表没有初始内容,仅预留有足够容纳全部被引用的函数的第一地址的空表项。
仍然以上述包括_f1、_f2和_printf三个被引用的函数的具体实施例为例,则该第二地址表可预留3个表项,每个表项可预留4个字节的空间,C语言的程序代码可如下:
在一些实施例中,所述方法还可包括:
配置基于所述第二地址表中的第二地址调用函数的指令。
构建完成第二地址表,虽然第二地址表没有初始内容,但可基于例如初始化函数中的随机化算法确定第一地址表中第一地址与第二地址表中第二地址的预置映射关系,基于该预置映射关系可预先确定第二地址表中的第二地址将要导入的函数的实际地址,进而能够预先确定第二地址表中第二地址的排序,基于该预先确定的第二地址表中第二地址的排序可预先配置调用函数的指令与第二地址的调用关系。
仍然以上述包括_f1、_f2和_printf三个被引用的函数的具体实施例为例,基于上述C语言程序代码可知,在第一地址表中三个被引用函数的排序如下:
(1)_f1
(2)_f2
(3)_printf
假定预先确定的第二地址表中第二地址的排序如下:
(1)_f2
(2)_f1
(3)_printf
在调用函数的指令直接调用函数的情况下,C语言程序代码通常如下所示:
00000028:E8 00 00 00 00 call _printf
00000030:E8 00 00 00 00 call _f1
00000035:E8 00 00 00 00 call _f2
应用在本申请实施例中,可将如上所述的三条调用函数的指令进行如下修改,从而使这三条指令指向第二地址表中的第二地址:
将第1条指令"call_printf"修改为调用g_static_table中的第3项,即"calldword ptr[g_static_table+8]";
将第2条指令"call_f1"修改为调用g_static_table中的第2项,即"call dwordptr[g_static_table+4]";
将第3条指令"call_f2"修改为调用g_static_table中的第1项即"call dwordptr[g_static_table+0]"。
经过如上所述的修改后,调用函数的指令指向第二地址表中的第二地址,在第一地址未导入第二地址表的情况下,第二地址表中的各个表项均为空,无法确定各条指令所调用的具体函数,即使获取到第一地址表中各个函数的实际地址,但由于第一地址表和第二地址表的随机映射关系,极大地增大了破解难度。
在一些实施例中,所述响应于基于第二地址调用函数的指令进行函数调用,包括:
响应于基于第三地址调用函数的指令进行函数调用,所述第三地址为所述第二地址的实际地址。
具体的,所述响应于基于第三地址调用函数的指令进行函数调用可包括:基于调用函数的指令中的第三地址,获取与之相对应的第二地址,基于所述第二地址进行函数调用。也即,将调用函数的指令配置为指向作为第二地址的实际地址的第三地址,如此,在执行调用函数的执行时,首先获取第三地址,继而基于第三地址获取第二地址,然后在基于第二地址进行函数调用。在具体实施时,该第三地址可为第二地址对应的内存中的实际地址。当然,在基于虚拟机的应用程序运行环境下,本实施例的第三地址也可以关联于映射物理机的虚拟机,作为虚拟机中的地址。如此,调用函数的指令指向内存中的地址,在程序非运行状态下,不仅第二地址表是空的,而且内存中也没有任何有效信息,达到了隐藏调用关系,防止静态分析的目的。
在一些实施例中,所述响应于所记录的第一地址导入地址空间,在所述地址空间中随机配置并记录用于进行函数调用的第二地址,包括:
按照与所述第一表中不同的顺序将第一地址随机导入所述第二地址表,配置包含在所述第二地址表中的第二地址。
在程序运行过程中,可通过一初始化程序按照与第一地址表中不同的顺序将第一地址随机导入第二地址表中,以实现第一地址表中第一地址与第二地址表中第二地址排序不同的目的。该初始化程序可包括一随机化算法,并基于该随机化算法确定第一地址在第二地址表中所需要导入的位置。
继续以上述包括_f1、_f2和_printf三个被引用的函数的具体实施例为例,该初始化程序的C语言程序代码可如下所示:
在一些优选实施例中,所述按照与所述第一表中不同的顺序将第一地址随机导入所述第二地址表,包括:
对导入操作进行防解析处理,防止函数被分析出算法内容;所述防解析处理包括:将与导入操作相关的函数通过混淆和/或虚拟化进行更改。
以通过初始化程序执行导入操作为例,可对该初始化程序执行防解析处理,例如,可对该初始化程序的代码进行混淆和/或虚拟化处理。或者,在基于初始化程序中的随机化算法确定第一地址在第二地址表中的导入位置时,也可对包含该随机化算法的函数进行防解析处理,以防止非法破解该随机化算法的情况下,破解函数的调用逻辑。当然,也可在第一地址的导入操作的执行过程中执行该防解析处理,如配置多个中间节点来混淆第一地址和第二地址的导入关系。
参见图2所示,本申请实施例还提供了一种函数调用装置,包括:
第一配置模块10,其配置为用于以重定位方式记录函数的第一地址。
重定位是把程序中逻辑地址变换成内存中物理地址的过程。逻辑地址是指一个源程序在编译或者连接装配后指令和数据所用的相对地址。物理地址为内存中存储单元对应的实际地址。通过重定位方式所记录的函数的第一地址,实际即为内存中存储该函数的存储单元的实际地址。
第二配置模块20,其配置为用于随机确定地址空间。
该地址空间为用于容纳函数的实际地址的空间,初始状态下,该地址空间可为空,也即,该随机确定的地址空间不包含初始内容。该地址空间也为供调用函数的指令所指向的地址空间。在具体实施时,该随机确定地址空间可包括:随机确定地址空间,并配置指向所述地址空间的调用函数的指令。
初始化模块30,其配置为用于响应于所记录的第一地址导入地址空间,在所述地址空间中随机配置并记录用于进行函数调用的第二地址,在多个函数的情况下,多个第二地址与多个第一地址的顺序不同。
在程序初始化阶段,可通过一初始化程序调取所记录的函数的第一地址,并在地址空间中随机写入第一地址以形成第二地址,从而使得指向所述地址空间的调用函数的指令与第二地址形成调用关系。在具体实施时,可在初始化程序中配置随机化算法,初始化程序可基于该随机化算法在地址空间中随机写入第一地址。在程序引用多个函数的情况下,随机化配置第二地址,可以调整第二地址的排序,使得第一地址和第二地址的排序不同,以隐藏调用函数的指令与函数的实际地址之间的真实调用关系。
调用模块40,其配置为用于响应于基于第二地址调用函数的指令进行函数调用。
在程序运行过程中,根据调取函数的指令从地址空间中调取对应的第二地址,进而基于该第二地址调取相应的函数,以执行相应的操作,从而保证程序能够正常运行。
本申请实施例的函数调用装置,记录了作为函数的实际地址的第一地址,在程序非运行状态下,所记录的第一地址并未导入调取函数的指令所指向的地址空间,调取函数的指令与函数的第一地址并未形成调用关系,能够防止通过静态分析方式查看函数调用逻辑;在程序运行过程中,将所记录的第一地址随机写入地址空间以形成第二地址,使得指向地址空间的调用函数的指令与函数的实际地址形成调用关系,执行调用函数的指令时,能够基于第二地址调用相应的函数并执行相应的操作,以保证程序的正常运行。
在一些实施例中,所述第一配置模块10,进一步配置为用于:
构建第一地址表,记录以重定位方式处理后每个被引用过的函数的第一地址。
在一些实施例中,所述第二配置模块20,进一步配置为用于:
至少随机获取不包含初始内容的地址空间,用于构建第二地址表,该地址空间不小于能够容纳所述第一地址的数量的空间。
在一些实施例中,所述初始化模块30,进一步配置为用于:
按照与所述第一表中不同的顺序将第一地址随机导入所述第二地址表,配置包含在所述第二地址表中的第二地址;
所述装置还包括:
第三配置模块,其配置为用于配置基于所述第二地址表中的第二地址调用函数的指令。
在一些实施例中,所述调用模块40,进一步配置为用于:
响应于基于第三地址调用函数的指令进行函数调用,所述第三地址为所述第二地址的实际地址。
在一些实施例中,所述第三地址包括内存地址。
在一些实施例中,所述初始化模块30,进一步配置为用于:
对导入操作进行防解析处理,防止函数被分析出算法内容;所述防解析处理包括:将与导入操作相关的函数通过混淆和/或虚拟化进行更改。
本申请实施例还提供了一种计算机可读存储介质,所述计算机可读存储介质中存储有计算机可执行指令,在执行所述计算机可读存储介质中的所述计算机可执行指令时实现如上任一项实施例所述的函数调用方法。
以上实施例仅为本申请的示例性实施例,不用于限制本申请,本申请的保护范围由权利要求书限定。本领域技术人员可以在本申请的实质和保护范围内,对本申请做出各种修改或等同替换,这种修改或等同替换也应视为落在本申请的保护范围内。