一种残膜回收机防缠绕挑膜装置的制 一种秧草收获机用电力驱动行走机构

一种基于内联函数分析的内核函数动态定位方法与流程

2023-01-05 17:28:52 来源:中国专利 TAG:

1.本发明属于计算机技术领域,具体涉及一种基于内联函数分析的内核函数动态定位方法。


背景技术:

2.linux内核用来管理软件发出的数据i/o(输入与输出)要求,将这些要求转译为数据处理的指令,交由中央处理器(cpu)及计算机中其他电子组件进行处理,是操作系统中最基本的部分。内核函数一般指内核支持函数,又称例程,是指只能在内核模式下调用的例程或子程序,目的是保证内核支持函数不被用户程序破坏。
3.编写linux内核模块时往往需要使用其他模块提供的内核函数,从linux 2.6版本内核开始引入了导出符号的机制,只有在内核中使用export_symbol或export_symbol_gpl导出的符号才能在内核模块中被直接使用。由于linux系统版本间的差异性等问题,并不是所有内核函数都存在与之对应的导出符号,例如,在3.8.0版本的内核中内核函数do_page_fault就未被导出,这就会导致内核模块加载失败。
4.现有的获取linux内核未导出符号的方式主要包括:修改linux内核、使用kallsyms_lookup_name读取、读取/boot/system.map-《kernel-version》后再使用内核模块参数传入内核模块及读取/proc/kallsyms后再使用内核模块参数传入内核模块等,然而,由于某些内核文件不支持被修改或是依赖的函数本身也未被导出等问题,在内核模块运行过程中上述方法的有效性均存在一定的局限。


技术实现要素:

5.有鉴于此,本发明提供了一种基于内联函数分析的内核函数动态定位方法,能够实现运行时的未导出内核函数内核地址的动态获取。
6.本发明提供的一种基于内联函数分析的内核函数动态定位方法,具体包括以下步骤:步骤1、根据linux内核版本源代码,建立未导出内核函数的内核函数依赖库,对于存在内联可能的未导出内核函数建立内联函数特征库,其中,内核函数依赖库保存由多个具有调用关系的函数节点组成的、起点为已导出内核函数且终点为未导出内核函数的函数调用关系,函数节点采用函数名及被调用位次表示,被调用位次是指该函数节点在上级函数节点中第一次被调用时在上级函数节点的所有函数调用中的排序;内联函数特征库保存与未导出内核函数相关的内联函数代码;步骤2、加载包含未导出内核函数的内核模块,查找内联函数特征库,若存在未导出内核函数的记录且记录为二元组,则执行步骤3;若存在未导出内核函数的记录且记录为四元组,则获取所有包含未导出内核函数的四元组执行步骤4;若不存在未导出内核函数的记录,则执行步骤5;步骤3、将内联函数代码的长度记为codelength;动态申请大小为memorylength字
节、起始地址为codeaddress的内存,且将该内存的权限设置为可读写与可执行,其中,memorylength的取值为codelength与设定偏移量之和;在codeaddress地址处写入与函数入口初始化操作相关的二进制代码,该二进制代码的长度为functionentrycodelength,执行函数入口的初始化操作,再将内联函数代码复制到codeaddress functionentrycodelength地址处,在内联函数代码后写入函数返回指令;将codeaddress作为未导出内核函数的内核地址,结束本流程;步骤4、获取四元组中的已导出内核函数的内核地址,采用所有四元组中的内联函数代码逐一与已导出内核函数的当前二进制代码进行代码匹配,选取具有最高相似度的内联函数代码作为未导出内核函数的内联函数代码,执行步骤3;步骤5、查找内核函数依赖库得到未导出内核函数相关的函数调用关系,从函数调用关系中起点位置的已导出内核函数的内核地址处开始执行反编译,再根据函数节点中的调用位次依次获取下级函数节点的内核地址,直至获取未导出内核函数的内核地址,结束本流程。
7.进一步地,所述步骤1中所述函数调用关系为:采用有向图表示,有向图中的节点表示函数节点,有向图中的有向边表示函数间的调用关系。
8.进一步地,所述步骤1中所述对于存在内联可能的未导出内核函数建立内联函数特征库的过程,包括以下步骤:步骤1.1、在linux内核版本源代码中,若存在已导出内核函数对未导出内核函数的调用,则执行步骤1.2;若调用未导出内核函数的内核函数为未导出内核函数,则执行步骤1.5;步骤1.2、选取编译优化选项,编译调用了未导出内核函数的已导出内核函数所在的代码文件得到目标文件;步骤1.3、对步骤1.2中得到的目标文件进行反编译,确定未导出内核函数的调用处是否为调用语句,如果是则执行步骤1.4;如果不是则获取未导出内核函数的内联函数代码,将由未导出内核函数、已导出内核函数、编译优化选项及内联函数代码组成的四元组作为内联函数特征保存到内联函数特征库中,执行步骤1.4;步骤1.4、若未遍历编译优化选项,则更换编译优化选项执行步骤1.2;否则结束当前流程;步骤1.5、选取编译优化选项,编译调用了未导出内核函数的内核函数所在的代码文件生成目标文件;步骤1.6、对步骤1.5中得到的目标文件进行反编译,确定未导出内核函数的调用处是否为调用语句,如果是则执行步骤1.7;如果不是则获取未导出内核函数的内联函数代码,将由未导出内核函数及内联函数代码组成的二元组作为内联函数特征保存到内联函数特征库中,执行步骤1.7;步骤1.7、若未遍历编译优化选项,则更换编译优化选项执行步骤1.5;否则结束当前流程。
9.进一步地,所述步骤3中所述将codeaddress作为未导出内核函数的内核地址之后将codeaddress地址对应内存的权限设置为可读与可执行。
10.进一步地,所述步骤3中的所述设定偏移量为256字节。
11.进一步地,所述编译优化选项为:
“‑
o”、
“‑
o1”、
“‑
o2”、
“‑
o3”或
“‑
ofast”。
12.有益效果:本发明通过分析已有内核版本的源代码为未导出内核函数建立内核函数依赖库及内联函数特征库,在内核模块加载过程中对于存在内联函数代码的未导出内核函数采用内联函数代码动态构建未导出内核函数的代码区域,对于不存在内联函数代码的未导出内核函数则根据内核函数依赖库迭代查找未导出内核函数的内核地址,从而在不修改内核代码、不依赖内核函数的情况下实现了运行时的未导出内核函数的内核地址的动态获取。
具体实施方式
13.下面列举实施例,对本发明进行详细描述。
14.本发明提供的一种基于内联函数分析的内核函数动态定位方法,包括以下步骤:步骤1、确定需要使用的未导出内核函数,根据已公开的linux内核版本源代码,建立未导出内核函数的内核函数依赖库,对于存在内联可能的未导出内核函数建立内联函数特征库,其中,内核函数依赖库用于保存由多个具有调用关系的函数节点组成的、起点为已导出内核函数且终点为未导出内核函数的函数调用关系,函数节点采用函数名及被调用位次表示,被调用位次是指该函数节点在上级函数节点中第一次被调用时在上级函数节点的所有函数调用中的排序;内联函数特征库用于保存与未导出内核函数相关的内联函数代码。
15.与未导出内核函数相关的函数调用关系可采用有向图来表示,有向图由节点和有向边组成,节点表示函数节点包括函数名及调用位次,有向边表示函数间的调用关系,由此,内核函数依赖库采用图数据结构来表示。建立未导出内核函数的内核函数依赖库的方式为:分析已公开的linux内核版本源码从中获取与未导出内核函数相关的所有调用路径,从所有调用路径中选取起点为已导出内核函数、终点为未导出内核函数的路径作为与未导出内核函数相关的函数调用关系保存到内核函数依赖库中。
16.若未导出内核函数的声明中包含内联相关的关键字,如inline等,或者采用最高级别的优化选项对内核模块进行编译后,未导出内核函数都存在成为内联函数的可能,即存在内联可能,因此为了实现动态获取内核函数的内核地址,就需要对未导出内核函数可能产生的内联的情况进行分析,进而建立未导出内核函数的内联函数特征库。对于存在内联可能的未导出内核函数,建立未导出内核函数的内联函数特征库的过程,包括以下步骤:步骤1.1、分析已公开的linux内核版本源代码,若存在已导出内核函数对未导出内核函数的调用,则执行步骤1.2;若调用未导出内核函数的内核函数为未导出内核函数,则执行步骤1.5。
17.步骤1.2、选取编译优化选项,编译调用了未导出内核函数的已导出内核函数所在的代码文件得到目标文件。
18.步骤1.3、对步骤1.2中得到的目标文件进行反编译,确定未导出内核函数的调用处是否为调用语句,如果是则说明未导出内核函数未转换为内联函数,执行步骤1.4;如果不是则说明未导出内核函数已转换为内联函数,获取该内联函数的内联函数代码,将由未导出内核函数、已导出内核函数、编译优化选项及内联函数代码组成的四元组作为内联函数特征保存到内联函数特征库中,执行步骤1.4。
19.步骤1.4、若未遍历编译优化选项,则更换编译优化选项执行步骤1.2;否则结束当前流程。其中,编译优化选项如-o、-o1、-o2、-o3及-ofast等。
20.步骤1.5、选取编译优化选项,编译调用了未导出内核函数的内核函数所在的代码文件生成目标文件。
21.步骤1.6、对步骤1.5中得到的目标文件进行反编译,确定未导出内核函数的调用处是否为调用语句,如果是则说明未导出内核函数未转换为内联函数,执行步骤1.7;如果不是则说明未导出内核函数已转换为内联函数,获取该内联函数的内联函数代码,将由未导出内核函数及内联函数代码组成的二元组作为内联函数特征保存到内联函数特征库中,执行步骤1.7。
22.步骤1.7、若未遍历编译优化选项,则更换编译优化选项执行步骤1.5;否则结束当前流程。
23.步骤2、加载包含未导出内核函数的内核模块,在内核模块的入口处查找内联函数特征库,若存在未导出内核函数的相关记录且记录为二元组,则执行步骤3;若存在未导出内核函数的相关记录且记录为四元组,则获取所有包含未导出内核函数的四元组执行步骤4;若不存在未导出内核函数的相关记录,则执行步骤5。
24.步骤3、获取内联函数代码的长度,记为codelength;动态申请大小为memorylength字节、起始地址为codeaddress的内存,且将该内存的权限设置为可读写与可执行,其中,memorylength的取值为codelength与设定偏移量之和,例如,memorylength=codelength 256;在codeaddress地址处写入与函数入口初始化操作相关的二进制代码,该二进制代码的长度为functionentrycodelength,并执行函数入口的初始化操作,再将内联函数代码复制到codeaddress functionentrycodelength地址处,并在内联函数代码后写入函数返回指令;将codeaddress作为未导出内核函数的内核地址,结束本流程。
25.为了进一步提高代码执行的安全性,在步骤3得到未导出内核函数的内核地址后将内存的权限设置为可读与可执行。
26.步骤4、获取四元组中的已导出内核函数的内核地址,采用所有四元组中的内联函数代码逐一与已导出内核函数的当前二进制代码进行代码匹配,选取具有最高相似度的内联函数代码作为未导出内核函数的内联函数代码,执行步骤3。
27.由于用户无法确定当前系统中加载和运行内核模块时实际采用的编译优化选项,因此,本发明采用内联函数特征库中保存的基于不同编译优化选项编译生成的二进制代码即内联函数代码,逐一与当前动态生成的已导出内核函数的二进制代码段进行代码匹配,具有最高代码相似度的内联函数代码即为基于与当前系统实际采用的编译优化选项相同的编译优化选项生成的二进制代码。
28.步骤5、查找内核函数依赖库得到未导出内核函数相关的函数调用关系,通过从函数调用关系中起点位置的已导出内核函数的内核地址处开始执行反编译,并根据函数节点中的调用位次依次获取下级函数节点的内核地址,直到获取未导出内核函数的内核地址。具体包括以下步骤:步骤5.1、获取函数调用关系中起点的函数节点的信息,即获取了已导出内核函数的函数名,根据函数名获取已导出内核函数的内核地址entryaddress。
29.步骤5.2、获取下级函数节点的调用位次,根据该调用位次即可获取其在上级函数
节点的所有函数调用中的相对顺序位次,从entryaddress处开始执行当前函数节点的反编译,执行到调用位次处时,调用位次处的调用指令对应的内核地址即为下级函数节点的内核地址nextaddress。
30.步骤5.3、若下级函数节点为终点的函数节点,则下级函数节点即为未导出内核函数,下级函数节点的内核地址即为未导出内核函数的内核地址,结束本流程;否则,将nextaddress作为entryaddress执行步骤5.2。
31.实施例:本实施例在linux系统上采用本发明提供的一种基于内联函数分析的内核函数动态定位方法实现了对多个未导出内核函数的动态定位,具体包括以下步骤:s1、确定需要使用的多个未导出内核函数,建立未导出内核函数列表,记为unexportedfunctionlist。
32.s2、分析linux社区发布的每个内核版本,为unexportedfunctionlist中的每个未导出内核函数unexportedfunction构建内核函数依赖库,并为其中存在内联可能的unexportedfunction建立内联函数特征库。
33.其中,构建内核函数依赖库的过程为:分析已公开的linux内核版本源码从中获取与未导出内核函数相关的所有调用路径,具体来说,可采用c/c 源码分析工具对linux内核版本源码进行分析,也可访问linux的内核源码交叉引用数据库获取所有调用路径,linux的内核源码交叉引用数据库的网址为https://elixir.bootlin.com/linux/latest/source;在所有调用路径中,选取起点为已导出内核函数且终点为unexportedfunction的函数调用关系,函数节点采用函数名及被调用位次组成的二元组描述。
34.若unexportedfunction的声明中存在与内联函数相关的inline等关键字,则说明unexportedfunction存在内联可能,或者通过分析调用了unexportedfunction的函数的所在代码文件的目标文件即可判断该unexportedfunction是否在使用最高级别的编译优化选项(-ofast)编译后形成了内联函数。
35.对于存在内联可能的unexportedfunction构建内联函数特征库的过程包括以下步骤:s2.1、分析已公开的linux内核版本源码,若存在已导出内核函数对unexportedfunction的调用,则执行s2.2;若调用unexportedfunction的内核函数为未导出内核函数,则执行s2.5。
36.s2.2、从-o、-o1、-o2、-o3、-ofast等编译优化选项选择一项,编译调用了unexportedfunction的已导出内核函数kernelfunctioncalledunexportedinlinedfunc所在的代码文件,得到“.o”的目标文件。
37.s2.3、反编译该“.o
”ꢀ
目标文件,判断调用unexportedfunction的位置是否为调用语句,如果是则说明unexportedfunction未转换为内联函数,执行s2.4;如果不是则说明unexportedfunction已转换为内联函数,获取unexportedfunction被内联后生成的代码即内联函数代码,将unexportedfunction、kernelfunctioncalledunexportedinlinedfunc、编译优化选项及内联函数代码作为四元组加入内联函数特征库中,执行s2.4。
38.s2.4、若未遍历编译优化选项,则更换编译优化选项执行s2.2;否则结束当前流
程。
39.s2.5、从-o、-o1、-o2、-o3、-ofast等编译优化选项选择一项,编译调用了unexportedfunction的未导出内核函数所在的代码文件,得到“.o”的目标文件。
40.s2.6、反编译该“.o
”ꢀ
目标文件,判断调用unexportedfunction的位置是否为调用语句,如果是则说明unexportedfunction未转换为内联函数,执行s2.7;如果不是则说明unexportedfunction已转换为内联函数,获取unexportedfunction被内联后生成的代码即内联函数代码,将unexportedfunction及内联函数代码作为四元组加入内联函数特征库中,执行s2.7。
41.s2.7、若未遍历编译优化选项,则更换编译优化选项执行s2.5;否则结束当前流程。
42.s3、加载内核模块,在内核模块入口处根据内核版本、内核函数依赖库和内联函数特征库动态获取unexportedfunctionlist中每个unexportedfunction的内核地址。
43.s3.1、在内核模块入口,在内联函数特征库中查找unexportedfunction,若存在与之对应的记录且为二元组,则执行s3.2;若存在与之对应的记录且为四元组,则执行s3.3;若不存在与之对应的记录,则执行s3.4。
44.s3.2、获取记录中的内联函数代码,记为inlinedcode,计算inlinedcode的长度记为codelength;动态申请大小为codelength 256字节的内存,该内存的起始地址记为codeaddress,并将该内存的权限设置为可读写及可执行;在codeaddress的位置写入长度为functionentrycodelength的与函数入口初始化操作相关的二进制代码,执行如保存栈地址等的函数入口初始化操作;将二元组中的内联函数代码复制到codeaddress functionentrycodelength的位置,并在内联函数代码之后,写入函数返回指令;将unexportedfunction的入口记为codeaddress,再将codeaddress地址处的内存的权限设置为可读及可执行。
45.s3.3、获取记录中的第二个元素,即调用了unexportedfunction的已导出内核函数记为kernelfunctioncalledunexportedinlinedfunc,获取kernelfunctioncalledunexportedinlinedfunc的内核地址;找到所有第一个元素为unexportedfunction的四元组,将每个四元组中的内联函数代码与kernelfunctioncalledunexportedinlinedfunc对应的二进制代码进行代码匹配;其中匹配度最大的内联函数代码记为inlinedcode,执行s3.2。
46.s3.4、在内核函数依赖库中查找unexportedfunction相关的函数调用关系,记为callpath;获取callpath中的第一个函数节点的函数名,并获取其对应的内核地址,记为entryaddress;获取callpath中的第二个节点的二元组中的第二个值即调用位次记为n,从entryaddress开始反编译当执行到第n个调用指令时即可获取第二个函数节点的内核地址,依次类推,直到获取最后一个节点unexportedfunction的内核地址。
47.综上所述,以上仅为本发明的较佳实施例而已,并非用于限定本发明的保护范围。凡在本发明的精神和原则之内,所作的任何修改、等同替换、改进等,均应包含在本发明的保护范围之内。
再多了解一些

本文用于创业者技术爱好者查询,仅供学习研究,如用于商业用途,请联系技术所有人。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

相关文献