CN111290952B - 一种动态链接库函数的跟踪方法及装置 - Google Patents

一种动态链接库函数的跟踪方法及装置 Download PDF

Info

Publication number
CN111290952B
CN111290952B CN202010074420.XA CN202010074420A CN111290952B CN 111290952 B CN111290952 B CN 111290952B CN 202010074420 A CN202010074420 A CN 202010074420A CN 111290952 B CN111290952 B CN 111290952B
Authority
CN
China
Prior art keywords
function
library
address
library function
hook
Prior art date
Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
Active
Application number
CN202010074420.XA
Other languages
English (en)
Other versions
CN111290952A (zh
Inventor
张磊
Current Assignee (The listed assignees may be inaccurate. Google has not performed a legal analysis and makes no representation or warranty as to the accuracy of the list.)
Beijing Tongxin Software Technology Co ltd
Original Assignee
Beijing Tongxin Software Technology Co ltd
Priority date (The priority date is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the date listed.)
Filing date
Publication date
Application filed by Beijing Tongxin Software Technology Co ltd filed Critical Beijing Tongxin Software Technology Co ltd
Priority to CN202010074420.XA priority Critical patent/CN111290952B/zh
Publication of CN111290952A publication Critical patent/CN111290952A/zh
Application granted granted Critical
Publication of CN111290952B publication Critical patent/CN111290952B/zh
Active legal-status Critical Current
Anticipated expiration legal-status Critical

Links

Images

Classifications

    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F11/00Error detection; Error correction; Monitoring
    • G06F11/36Preventing errors by testing or debugging software
    • G06F11/362Software debugging
    • G06F11/3636Software debugging by tracing the execution of the program
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F11/00Error detection; Error correction; Monitoring
    • G06F11/36Preventing errors by testing or debugging software
    • G06F11/362Software debugging
    • G06F11/3644Software debugging by instrumenting at runtime
    • YGENERAL TAGGING OF NEW TECHNOLOGICAL DEVELOPMENTS; GENERAL TAGGING OF CROSS-SECTIONAL TECHNOLOGIES SPANNING OVER SEVERAL SECTIONS OF THE IPC; TECHNICAL SUBJECTS COVERED BY FORMER USPC CROSS-REFERENCE ART COLLECTIONS [XRACs] AND DIGESTS
    • Y02TECHNOLOGIES OR APPLICATIONS FOR MITIGATION OR ADAPTATION AGAINST CLIMATE CHANGE
    • Y02DCLIMATE CHANGE MITIGATION TECHNOLOGIES IN INFORMATION AND COMMUNICATION TECHNOLOGIES [ICT], I.E. INFORMATION AND COMMUNICATION TECHNOLOGIES AIMING AT THE REDUCTION OF THEIR OWN ENERGY USE
    • Y02D10/00Energy efficient computing, e.g. low power processors, power management or thermal management

Landscapes

  • Engineering & Computer Science (AREA)
  • Theoretical Computer Science (AREA)
  • Computer Hardware Design (AREA)
  • Quality & Reliability (AREA)
  • Physics & Mathematics (AREA)
  • General Engineering & Computer Science (AREA)
  • General Physics & Mathematics (AREA)
  • Stored Programmes (AREA)

Abstract

本发明公开了一种动态链接库函数的跟踪方法,包括:在目标程序运行前,设置用于跟踪各库函数的挂钩指令,将各库函数的名称和地址存储至数组中,将GOT表中记载的库函数的地址修改为相应的挂钩指令的地址;在目标程序调用库函数时,根据GOT表来确定挂钩指令的地址,跳转至该地址处执行挂钩指令;挂钩指令压栈库函数的下标,跳转至挂钩函数的地址处执行;挂钩函数从栈中获取库函数的下标,将相关寄存器的值保存至栈中,将库函数的下标传入跟踪函数以调用跟踪函数;跟踪函数根据库函数的下标,从数组中获取库函数的名称和地址,输出跟踪信息,将库函数的地址返回至挂钩函数;挂钩函数将栈中的值恢复至寄存器,跳转至库函数的地址处执行库函数。

Description

一种动态链接库函数的跟踪方法及装置
技术领域
本发明涉及Linux软件调试技术领域,尤其涉及一种用于对动态链接库函数进行跟踪调试的方法及装置。
背景技术
现代软件日益复杂,软件出现故障的现象普遍存在,为了解决软件故障,需要能对运行时的软件进行动态跟踪与调试。运行时的应用软件大体上可以被划分为三个部分,即应用软件的主体可执行程序,应用软件运行所依赖的动态链接库,以及应用软件运行所需要的操作系统内核。
Linux操作系统下的可执行程序普遍使用ELF格式,为了提高软件的模块化、运行性能与可维护性,减少软件启动时间与整体系统的内存占用,动态链接的技术被广泛使用。动态链接指的是软件运行所依赖的功能被存储在软件以外的动态链接库中,动态链接库暴露出字符串形式的函数接口,在运行期间,软件、动态链接器与动态链接库都被载入到软件的进程空间中。软件在调用某个动态链接库中的某个函数前,动态链接器会根据此函数的字符串名称解析得到动态链接库中函数的具体位置,并跳转到此函数的位置处执行代码,从而开始函数调用。由于函数名解析定位以及调用的整个过程是在软件运行期间发生的,而不是在软件编译链接生成可执行程序的过程中发生的,因此此项技术被称为动态链接。
动态链接库函数的正确调用是应用软件正常运行的必要条件。因此,需要提供一种用于对动态链接库函数进行跟踪调试的方法。
发明内容
为此,本发明提供一种动态链接库函数的跟踪方法及装置,以力图解决或至少缓解上面存在的问题。
根据本发明的第一个方面,提供一种动态链接库函数的跟踪方法,在计算设备中执行,包括:在待跟踪的目标程序运行之前,设置用于跟踪各个库函数的挂钩指令,将各个库函数的名称和地址存储至函数信息数组,将全局偏移表中记载的库函数的地址修改为相应的挂钩指令的地址;在目标程序调用动态链接库中的库函数时,根据所述全局偏移表来确定所述库函数的挂钩指令的地址,并跳转至所述地址处执行所述挂钩指令;所述挂钩指令适于压栈所述库函数的下标,并跳转至挂钩函数的地址处以执行所述挂钩函数;所述挂钩函数从栈中获取所述库函数的下标,将各个相关寄存器的值保存至栈中,将所述库函数的下标传入跟踪函数以调用所述跟踪函数;所述跟踪函数根据所述库函数的下标,从函数信息数组中获取所述库函数的名称和地址,输出跟踪信息,将库函数的地址返回至所述挂钩函数;所述挂钩函数将栈中的值恢复至相应的寄存器,并跳转至库函数的地址处以执行所述库函数。
可选地,在根据本发明的动态链接库函数的跟踪方法中,设置用于跟踪各个库函数的挂钩指令的步骤包括:分配一块内存空间,在所述内存空间中填充各个库函数的挂钩指令,所述挂钩指令包括用于压栈库函数的下标的压栈指令和用于跳转至挂钩函数的跳转指令;以及将所述内存空间的属性修改为可读可执行。
可选地,在根据本发明的动态链接库函数的跟踪方法中,将各个库函数的名称和地址存储至函数信息数组的步骤包括:对于重定位表中的第i个库函数,通过读取相应的重定位表项的r_info成员来确定该库函数在动态符号表中的下标,从而确定该库函数对应的动态符号表项;通过读取所述动态符号表项的st_name成员来确定该库函数的名称在动态字符串表中的索引,根据所述索引,在动态字符串表中查找确定该库函数的名称;通过读取相应的重定位表项的r_offset成员来确定该库函数在全局偏移表中的下标,根据所述全局偏移表中的下标,从所述全局偏移表中获取该库函数的地址;将该库函数的名称和地址存储至函数信息数组的第i个元素中。
可选地,在根据本发明的动态链接库函数的跟踪方法中,将全局偏移表中记载的库函数的地址修改为相应的挂钩指令的地址的步骤包括:将库函数i的地址修改为所述内存空间的起始地址加上i乘以所述挂钩指令的字节长度。
可选地,在根据本发明的动态链接库函数的跟踪方法中,重定位表、动态符号表、动态字符串表、全局偏移表的地址根据所述目标程序的进程空间虚拟文件和可执行文件来确定。
可选地,在根据本发明的动态链接库函数的跟踪方法中,内存空间中所存储的挂钩指令的组数与所述函数信息数组的长度相同。
可选地,在根据本发明的动态链接库函数的跟踪方法中,跟踪信息包括当前时间戳和被调用的库函数的名称。
可选地,在根据本发明的动态链接库函数的跟踪方法中,挂钩函数、跟踪函数实现为跟踪库的库函数,所述跟踪库为用于跟踪目标程序的库函数调用情况的动态链接库,所述设置用于跟踪各个库函数的挂钩指令,将各个库函数的名称和地址存储至函数信息数组,将全局偏移表中记载的库函数的地址修改为相应的挂钩指令的地址的步骤,由所述跟踪库的初始化函数执行。
可选地,在根据本发明的动态链接库函数的跟踪方法中,跟踪库在所述目标程序所调用的其他动态链接库之前被载入内存,所述跟踪库的初始化函数在所述目标程序所调用的其他动态链接库的初始化函数之后被执行。
根据本发明的第二个方面,提供一种计算设备,包括:至少一个处理器;和存储有程序指令的存储器,当所述程序指令被所述处理器读取并执行时,使得所述计算设备执行上述动态链接库函数的跟踪方法。
根据本发明的第三个方面,提供一种存储有程序指令的可读存储介质,当所述程序指令被计算设备读取并执行时,使得所述计算设备执行上述动态链接库函数的跟踪方法。
本发明的技术方案通过对进程执行过程中的全局偏移表的修改和挂钩,能提供高性能的、通用的动态链接库函数的跟踪分析。本方案依赖性小,通用性强,运行性能高,可广泛用于Linux操作系统下应用程序动态链接库的跟踪与分析中。
上述说明仅是本发明技术方案的概述,为了能够更清楚了解本发明的技术手段,而可依照说明书的内容予以实施,并且为了让本发明的上述和其它目的、特征和优点能够更明显易懂,以下特举本发明的具体实施方式。
附图说明
为了实现上述以及相关目的,本文结合下面的描述和附图来描述某些说明性方面,这些方面指示了可以实践本文所公开的原理的各种方式,并且所有方面及其等效方面旨在落入所要求保护的主题的范围内。通过结合附图阅读下面的详细描述,本公开的上述以及其它目的、特征和优势将变得更加明显。遍及本公开,相同的附图标记通常指代相同的部件或元素。
图1示出了根据本发明一个实施例的计算设备100的示意图;
图2示出了根据本发明一个实施例的动态链接库函数的跟踪方法200的流程图;
图3示出了根据本发明一个实施例的进程空间的内存地址分布的示意图;
图4示出了根据本发明一个实施例的重定位表、全局偏移表、挂钩指令的跳转关系的示意图;
图5示出了根据本发明一个实施例的对全局偏移表进行修改和挂钩的过程的示意图;
图6示出了根据本发明一个实施例的库函数调用过程的示意图。
具体实施方式
下面将参照附图更详细地描述本公开的示例性实施例。虽然附图中显示了本公开的示例性实施例,然而应当理解,可以以各种形式实现本公开而不应被这里阐述的实施例所限制。相反,提供这些实施例是为了能够更透彻地理解本公开,并且能够将本公开的范围完整的传达给本领域的技术人员。
为了便于理解本发明的技术方案,以下对本发明所涉及的一些概念和术语进行说明。
Linux操作系统下的可执行程序普遍使用ELF格式。更具体的,在ELF文件中存在多个节(section),与动态链接密切相关的节包括全局偏移表(GOT,Global Offset Table)、过程链接表(PLT,Procedure Linkage Table)等。程序调用库函数时实际上会调用PLT中的代码,PLT中的代码会跳转到GOT表中存储的地址处,而GOT表中存储的地址是程序所需要调用的外部动态链接库函数的地址。由于在动态链接时相应的地址是未知的,因此其初始值实际上此地址填写的是指向PLT中的另一段代码,这段代码配合动态链接器负责在程序运行时解析对应的动态链接库函数地址,并最终修改GOT表中相应的地址为此地址,然后再跳转到此地址去执行库函数。这样,当以后程序再次调用此库函数时,即可根据GOT表直接跳转到库函数处执行代码,而不用再进行解析查找了。
在ELF文件中,与动态链接密切相关的节包括.got.plt节(全局偏移表节)、.rela.plt节(重定位表节)、.dynsym节(动态符号表节)、.dynstr节(动态字符串表节)等。
.got.plt节为全局偏移表(GOT,Global Offset Table)节,全局偏移表GOT中存储有程序所需要调用的外部动态链接库函数的地址。
.rela.plt节为重定位表节,其中存储有每个库函数在动态符号表(.dynsym)中的下标,以及在全局偏移表(.got.plt)中的下标等信息。
.dynsym节为动态符号表节,用于描述动态链接的符号或函数结构信息。
.dynstr节为动态字符串表节,用于描述动态链接的符号字符串或函数名称。由于ELF文件中用到了很多字符串,例如段名、变量名、函数名等,字符串的长度往往是不确定的,所以用固定的结构来表示它比较困难。通常的做法是将动态链接所涉及到的字符串集中起来放到动态链接字符串表中,然后使用字符串在动态链接字符串表中的偏移(索引)来引用字符串。例如,表1是动态链接字符串表的一个示例:
表1
偏移 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9
+0 \0 h e l l o w o r l
+10 d \0 M y f u n c t i
+20 o n \0  
基于表1,偏移与字符串的对应关系如表2所示:
表2
偏移 字符串
0 空字符串
1 helloworld
6 world
12 Myfunction
这样,基于动态字符串表,引用一个字符串只需要给出一个数字下标即可,该数字下标即为字符串中的第一个字符在动态字符串表中的偏移量(或称为索引值)。
为了便于理解本发明的技术方案和技术效果,以下对现有技术的动态链接库函数的跟踪方法进行介绍。
现有的库函数跟踪方法主要有两种,分别是基于预加载技术(PRELOAD)的同名库函数跟踪与基于ptrace系统调用的断点式程序调试跟踪。
为了调整程序运行时的行为,动态链接器提供了PRELOAD机制,系统管理员或者用户可以通过修改/etc/ld.so.preload文件或者设置LD_PRELOAD环境变量,以告之动态链接器,在软件启动之后首先载入上述文件或环境变量指定的动态链接库L。如果希望跟踪程序对动态链接库M中的库函数func1的调用,开发人员可以在动态链接库L中声明一个外部可调用的,与func1完全一样的函数签名(function signature)。这样,在程序调用func1函数时,实际上将调用L中的func1函数,而不是M中的func1函数。通过此方法,即可对感兴趣的动态链接库函数进行跟踪。
PRELOAD方法经常被用在对特定库函数的跟踪上,其通用性较差。从上述PRELOAD的技术方案可以看出,如果需要跟踪某个库函数,例如跟踪glibc库中的用于写入文件数据的库函数write,则需要首先开发一个动态链接库,并在其中声明与write完全一样的函数签名(ssize_t write(int fd,const void*buf,size_t count)),然后再在自行开发的write函数内部实现函数的跟踪处理,并最终调用glibc实现的write函数(不然程序的逻辑显然会出现问题)。
因此,针对每个待跟踪的库函数,都需要进行手工函数声明,无法以通用的方式对未知的动态链接库函数进行跟踪,而在实际情况中,我们常常需要对一系列的库函数进行分析,这样带来的开发量与维护量就会非常巨大。
这种缺陷是上述技术方案本身所无法避免的。因为此方案实际上是利用了动态链接器在解析库函数的时候,同名函数在更先载入的动态链接库中被首先解析到的原理,因此为了使用PRELOAD技术跟踪库函数,就需要一一实现同样名称的库函数,并编译生成待PRELOAD的动态链接库。
现有技术中的另一种库函数跟踪方法是基于ptrace系统调用的断点式程序调试跟踪方法。
Linux内核提供了ptrace系统调用,第三方程序P可以通过ptrace调试应用软件S,包括暂停S,查看S的状态(内存与寄存器等数据),修改S的状态,恢复S的运行等。
如果P希望跟踪S的动态链接库函数调用,P可以在调用ptrace的时候使用PTRACE_POKETEXT参数,修改S的PLT(Procedure Linkage Table,过程链接表)中的代码,加入软中断指令(在x86下为int 3),这样在PLT解析动态链接库函数之后会触发这条软中断,从而使得内核开始处理来自于S的中断,并通知S的调试进程P,而P在收到了通知以后就可以查看S的进程状态,得知S将要调用的动态链接库函数,从而能对其进行跟踪了。在跟踪处理完毕后,P还需要再次调用ptrace,传入PTRACE_POKETEXT参数,删除修改后的软中断指令,恢复原有指令,以便程序继续正常运行。这种技术在通用动态链接库跟踪软件ltrace中被使用到了。
基于ptrace的断点式程序调试跟踪有三个问题,第一个问题是它在程序运行过程中需要不断地中断程序的运行,以修改程序的指令(加入软中断指令或者删除软中断指令),并且中间还牵涉到内核态到用户态的状态转换,会带来相当大的性能开销。第二个问题是ptrace系统调用是Linux操作系统下非常复杂的系统调用,牵涉到进程间通信、信号处理、进程状态查看与修改等,因此在国产处理器上的实现往往不完整或者有缺陷,会导致功能缺失或者性能下降。第三个问题同样也是因为ptrace接口特别复杂,而且又牵涉到PLT表的修改,因此应用开发与调试跟踪的人员很难使用此项技术定制自己的动态链接库函数跟踪,最常用的仍然是更为简单,但是无法通用化的基于PRELOAD的同名函数替代跟踪的技术方案。
针对现有库函数跟踪方法的通用性以及运行性能较差的问题,本发明提供一种动态链接库函数的跟踪方法,以实现通用的、高性能的动态链接库函数的跟踪分析。
本发明的动态链接库函数的跟踪方法在计算设备中执行。本发明的计算设备是安装有Linux操作系统的设备,其例如可以是桌面电脑、笔记本电脑等个人配置的计算机,或手机、平板电脑、多媒体播放器、智能可穿戴设备、物联网(Internet of Things,IoT)设备等终端设备,但不限于此。
图1示出了根据本发明一个实施例的计算设备100的示意图。需要说明的是,图1所示的计算设备100仅为一个示例,在实践中,用于实施本发明的动态链接库函数的跟踪方法的计算设备可以是任意型号的设备,其硬件配置情况可以与图1所示的计算设备100相同,也可以与图1所示的计算设备100不同。实践中用于实施本发明的动态链接库函数的跟踪方法的计算设备可以对图1所示的计算设备100的硬件组件进行增加或删减,本发明对计算设备的具体硬件配置情况不做限制。
如图1所示,在基本的配置102中,计算设备100典型地包括系统存储器106和一个或者多个处理器104。存储器总线108可以用于在处理器104和系统存储器106之间的通信。
取决于期望的配置,处理器104可以是任何类型的处理,包括但不限于:微处理器(μP)、微控制器(μC)、数字信息处理器(DSP)或者它们的任何组合。处理器104可以包括诸如一级高速缓存110和二级高速缓存112之类的一个或者多个级别的高速缓存、处理器核心114和寄存器116。示例的处理器核心114可以包括运算逻辑单元(ALU)、浮点数单元(FPU)、数字信号处理核心(DSP核心)或者它们的任何组合。示例的存储器控制器118可以与处理器104一起使用,或者在一些实现中,存储器控制器118可以是处理器104的一个内部部分。
取决于期望的配置,系统存储器106可以是任意类型的存储器,包括但不限于:易失性存储器(诸如RAM)、非易失性存储器(诸如ROM、闪存等)或者它们的任何组合。计算设备中的物理内存通常指的是易失性存储器RAM,磁盘中的数据需要加载至物理内存中才能够被处理器104读取。系统存储器106可以包括操作系统120、一个或者多个应用122以及程序数据124。在一些实施方式中,应用122可以布置为在操作系统上由一个或多个处理器104利用程序数据124执行指令。在本发明的实施例中,操作系统120为Linux操作系统,其包括用于处理基本系统服务以及执行依赖于硬件的任务的程序指令。应用122包括用于实现各种用户期望的功能的程序指令,应用122例如可以是浏览器、即时通讯软件、软件开发工具(例如集成开发环境IDE、编译器等)等,但不限于此。当应用122被安装到计算设备100中时,可以向操作系统120添加驱动模块。
在计算设备100启动运行时,处理器104会从存储器106中读取操作系统120的程序指令并执行。应用122运行在操作系统120之上,利用操作系统120以及底层硬件提供的接口来实现各种用户期望的功能。当用户启动应用122时,应用122会加载至存储器106中,处理器104从存储器106中读取并执行应用122的程序指令。
计算设备100还可以包括有助于从各种接口设备(例如,输出设备142、外设接口144和通信设备146)到基本配置102经由总线/接口控制器130的通信的接口总线140。示例的输出设备142包括图形处理单元148和音频处理单元150。它们可以被配置为有助于经由一个或者多个A/V端口152与诸如显示器或者扬声器之类的各种外部设备进行通信。示例外设接口144可以包括串行接口控制器154和并行接口控制器156,它们可以被配置为有助于经由一个或者多个I/O端口158和诸如输入设备(例如,键盘、鼠标、笔、语音输入设备、触摸输入设备)或者其他外设(例如打印机、扫描仪等)之类的外部设备进行通信。示例的通信设备146可以包括网络控制器160,其可以被布置为便于经由一个或者多个通信端口164与一个或者多个其他计算设备162通过网络通信链路的通信。
网络通信链路可以是通信介质的一个示例。通信介质通常可以体现为在诸如载波或者其他传输机制之类的调制数据信号中的计算机可读指令、数据结构、程序模块,并且可以包括任何信息递送介质。“调制数据信号”可以这样的信号,它的数据集中的一个或者多个或者它的改变可以在信号中编码信息的方式进行。作为非限制性的示例,通信介质可以包括诸如有线网络或者专线网络之类的有线介质,以及诸如声音、射频(RF)、微波、红外(IR)或者其它无线介质在内的各种无线介质。这里使用的术语计算机可读介质可以包括存储介质和通信介质二者。
在本发明的实施例中,操作系统120为Linux操作系统,应用122包括用于执行本发明的动态链接库函数的跟踪方法200的指令,以实现通用的、高性能的动态链接库函数的跟踪分析。
图2示出了根据本发明一个实施例的动态链接库函数的跟踪方法200的流程图。方法200在计算设备(例如前述计算设备100)中执行。
为了执行本发明的动态链接库函数的跟踪方法200,需要预先配置跟踪函数和挂钩函数。
跟踪函数用于对库函数进行跟踪处理以及输出跟踪信息。跟踪函数进行的跟踪处理的内容、输出的跟踪信息的类型等可以根据用户的需要进行灵活定制,例如,跟踪函数可以打印出当前时间戳与将要被调用的动态链接库函数的名称。多个库函数可以共用同一个跟踪函数,即对多个库函数进行相同的跟踪处理;也可以为不同的库函数设置不同的跟踪函数,即对不同的库函数进行不同的跟踪处理。在本发明的实施例中,跟踪函数的输入参数为库函数的下标,其类型通常为整数类型(int);返回值为库函数的地址,通常为长整数类型(long)。在下文的实施例中,跟踪函数被记为trace_fn。
挂钩函数在库函数被目标程序(即待跟踪的应用程序,其可以是任意需要进行库函数跟踪调试的应用程序)调用时执行,其先保存相关寄存器的值,然后将库函数的下标传递给该库函数的跟踪函数trace_fn,调用(call)该跟踪函数。跟踪函数完成跟踪处理后,挂钩函数将接收到跟踪函数返回的库函数的真实地址,然后将之前保存的值恢复至相应的寄存器中,随后跳转至库函数的地址处执行该库函数。在下文的实施例中,挂钩函数被记为fn_hook。
根据一种实施例,可以将跟踪函数和挂钩函数编译成动态链接库,该动态链接库用于跟踪目标程序的动态链接库函数调用情况,下文中,将用于跟踪目标程序的库函数调用情况的动态链接库记为跟踪库。
除了跟踪函数trace_fn和挂钩函数fn_hook之外,还需要设置跟踪库的初始化函数。下文中,跟踪库的初始化函数被记为constructor。
初始化函数在跟踪库被载入内存后执行,用于对目标程序的全局偏移表进行修改和挂钩,以对目标程序运行过程中的库函数调用情况进行跟踪。具体地,初始化函数用于执行方法200中的步骤S210,步骤S210的具体步骤将与下文中详述。
在本发明的实施例中,通过修改/etc/ld.so.preload文件或者设置LD_PRELOAD环境变量,来将跟踪库的加载优先级设置为最高。这样,跟踪库将在目标程序的主体可执行文件载入内存(具体地,载入目标程序的进程空间)之后、在目标程序所调用的其他动态链接库之前被载入内存,即,在所有动态链接库中,跟踪库是第一个被载入的动态链接库。并且,跟踪库的初始化函数在其他动态链接库的初始化程序之后被执行,即,在所有动态链接库的初始化函数中,跟踪库的初始化函数最后被执行。
在设置了跟踪函数trace_fn、挂钩函数fn_hook和初始化函数constructor,并且将跟踪库的加载优先级设置为最高后,当用户启动目标程序后,目标程序的主体可执行文件、跟踪库、目标程序所需要的其他动态链接库将被先后加载至内存。随后,跟踪库将执行本发明的动态链接库函数的跟踪方法200,以对目标程序运行过程中的动态链接库函数的调用情况进行跟踪分析。
如图2所示,方法200始于步骤S210。
在步骤S210中,在待跟踪的目标程序运行之前,设置用于跟踪各个库函数的挂钩指令,将各个库函数的名称和地址存储至函数信息数组,将全局偏移表中记载的库函数的地址修改为相应的挂钩指令的地址。
步骤S210由跟踪库的初始化函数(constructor)执行。参见前述描述,跟踪库是第一个被载入的动态链接库,并且在所有的动态链接库中,其初始化函数也是最后一个被执行的。在其初始化函数开始执行的时候,其他动态链接库的符号解析已经完成,主程序所依赖的动态链接库函数已经有一部分被解析填充了,因此此时全局偏移表GOT存储的是库函数的真实地址。根据一种实施例,如果希望全局偏移表中存储有所有库函数的地址,可以将环境变量LD_BIND_NOW设置为任意非空字符串。这样,在动态链接库载入时,即时进行库函数的解析和重定位。当跟踪库的初始化函数执行时,全局偏移表中将存有所有库函数的地址。
根据一种实施例,用于跟踪各个库函数的挂钩指令可以按照以下步骤设置:分配一块内存空间,在该内存空间中填充各个库函数的挂钩指令,挂钩指令包括用于压栈库函数下标的压栈指令(push)和用于跳转至挂钩函数的跳转指令(jmp)。然后将该内存空间的属性修改为可读可执行,以使得上述挂钩指令可以被执行。
例如,调用memalign函数分配一块足够大的、内存地址页边界对齐的内存空间,该内存空间大到足以存储所有待跟踪的库函数的挂钩指令。该内存空间对应于全局变量trampoline。通常地,32KB大小的内存空间即可满足要求。当然,在其他实施例中,也可以视情况分配16KB、64KB大小的内存空间,本发明对用于存储挂钩指令的内存空间的大小不做限制。
需要说明的是,在上述实施例中,需要使用memalign或者valloc函数进行trampoline内存块的内存分配,不能使用常见的malloc或者mmap函数。这是因为malloc无法保证分配的内存在内存页边界上,但是由于需要将此内存通过mprotect函数设置为可执行内存,而mprotect要求内存地址页边界对齐。不能使用mmap函数的原因是,mmap分配的内存距离程序的主体太远,在64位操作系统上一般都会超出4G(即32位)的距离,从而导致jmp指令后面紧跟的32位地址溢出。memalign与valloc分配的内存在堆(heap)中,距离程序主体最近,因此需要选择这些函数。图3示出了Linux下进程空间的内存地址分布,如图3所示,堆(heap)距离程序主体(即.text、.data、.bss等节)最近,因此,需要使用memalign或者valloc函数进行trampoline内存块的内存分配。
设置循环变量ndx的初始值为0,在对应于trampoline变量的内存空间中,从前向后循环填充多组挂钩指令,每次循环后,变量ndx的值加一。每组挂钩指令对应于一个待跟踪的库函数。每组挂钩指令包括两条指令,第一条指令为push ndx,即将当前的ndx值压栈;第二条指令为jmp fn_hook,即跳转到挂钩函数fn_hook函数去。需要说明的是,本实施例中的挂钩指令以X86汇编指令为例,在其他实施例中,挂钩指令也可以采用其他处理器的指令集。
在将上述内存空间填满指令后,记录下总循环次数total,并调用mprotect将上述内存空间的属性修改为可读可执行,以使得其中存储的挂钩指令可以被执行。填满指令的trampoline变量如图4所示,其中依次存储有库函数0的挂钩指令push 0、jmp fn_hook,库函数1的挂钩指令push 1、jmp fn_hook,库函数2的挂钩指令push 2、jmp fn_hook,…,以及库函数total-1的挂钩指令push total-1、jmp fn_hook。
需要说明的是,上述实施例中没有分析待跟踪的库函数的具体数量,而是分配了一块足够大的内存空间,并在该内存空间中填满挂钩指令。在其他实施例中,也可以先根据重定位表节来确定待跟踪的库函数的数量,并根据库函数的数量来分配内存空间,使分配的内存空间的大小与待跟踪的库函数的数量相符,即,分配的内存空间的大小刚好可以存储所有待跟踪的库函数的挂钩指令。
除了设置挂钩指令表trampoline之外,在步骤S210中,跟踪库的初始化函数constructor还需要声明一个用于存储库函数的名称和地址函数信息数组libfuncs,并初始化函数信息数组为全零。
根据一种实施例,函数信息数组的长度与内存空间中所存储的挂钩指令的组数相同,即函数信息数组的长度为total。
例如,声明lib_func结构体如下:
Figure BDA0002378127240000131
声明长度为total的lib_func类型的函数信息数组libfuncs,即:struct lib_func libfuncs[total],并将其初始化为全0。
初始化函数信息数组后,跟踪库的初始化函数需要将各个库函数的地址和名称填充至函数信息数组的相应位置中,并将全局偏移表中记载的库函数的地址修改为相应的挂钩指令的地址。
根据一种实施例,设置循环变量i,并将其初始值设置为0,采用循环变量i来循环处理重定位表(.rela.plt节)中的各个重定位表项,将每个重定位表项所对应的库函数的地址和名称存储至函数信息数组,并将全局偏移表中记载的库函数的地址修改为相应的挂钩指令的地址。
在进行上述循环之前,需要确定与动态链接相关的各个表的地址,即,确定重定位表(.rela.plt节)、动态符号表(.dynsym节)、动态字符串表(.dynstr节)、全局偏移表(.got.plt节)的地址。
根据一种实施例,重定位表、动态符号表、动态字符串表、全局偏移表的地址根据所述目标程序的进程空间虚拟文件和可执行文件来确定。具体地,读取当前进程(即目标程序)的进程空间虚拟文件/proc/self/maps,获得当前进程各个段(segment)的地址范围,由于进程的内存内容由目标程序的ELF文件中各个段一一映射而来,而ELF文件中的段又由节(section)组成,那么根据ELF的规范解析可以得到.rela.plt、.dynsym、.dynstr、.got.plt节在进程空间中的具体地址。
在确定了重定位表(.rela.plt节)、动态符号表(.dynsym节)、动态字符串表(.dynstr节)、全局偏移表(.got.plt节)的地址之后,对于重定位表中的第i个库函数,可以按照以下步骤a~d来将各个库函数的地址和名称存储至函数信息数组:
步骤a:通过读取相应的重定位表项的r_info成员来确定库函数i在动态符号表中的下标,从而确定库函数i对应的动态符号表项。
重定位表是一个结构体数组,数组中的每个元素对应于一个重定位表项。重定位表项的结构体描述如下(以64位操作系统为例):
Figure BDA0002378127240000141
由以上结构体描述可知,结构体的r_info成员记载了重定位入口在动态符号表中的索引下标。这样,通过调用ELF64_R_INFO宏来读取重定位表项的r_info成员,即可确定库函数i在动态符号表.dynsym中的下标。结合预先确定的.dynsym节的地址,即可定位出动态符号表.dynsym中对应于库函数i的动态符号表项的地址。
步骤b:通过读取步骤a得到的动态符号表项的st_name成员来确定库函数i的名称在动态字符串表中的索引,根据该索引,在动态字符串表中查找确定库函数i的名称。
动态符号表是一个结构体数组,数组中的每一个元素对应于一个动态链接符号(符号包括变量和函数)。动态符号表项的结构体描述如下(以64位操作系统为例):
Figure BDA0002378127240000151
由以上结构体描述可知,结构体的st_name成员记载了符号在动态字符串表中的下标,这样,通过读取库函数i所对应的动态符号表项的st_name成员,即可确定库函数i的名称在动态字符串表.dynstr中的索引。结合预先确定的.dynstr节的地址,即可在动态字符串表中查找确定出库函数i的名称fn_name。
步骤c:通过读取相应的重定位表项的r_offset成员来确定库函数i在全局偏移表中的下标,根据该全局偏移表中的下标,从全局偏移表中获取库函数i的地址。
由上述重定位表项的结构体描述可知,结构体的r_offset成员记载了重定位入口在全局偏移表(.got.plt节)中的索引下标。这样,通过调用ELF64_R_INFO宏来读取重定位表项的r_offset成员,即可确定库函数i在全局偏移表.got.plt中的下标。结合已确定的.got.plt节的地址,即可从.got.plt节中获取到库函数i的地址fn_addr。
步骤d:将库函数i的名称fn_name和地址fn_addr存储至函数信息数组的第i个元素libfuncs[i]中,即,libfuncs[i].name=fn_name;libfuncs[i].addr=fn_addr。
在将库函数i的名称和地址存储至函数信息数组后,执行下述步骤e。
步骤e:将全局偏移表中原本记载的库函数i的地址修改为相应的挂钩指令的地址,即,将.got.plt节中记载的库函数i的地址fn_addr修改为内存空间的起始地址(即trampoline变量的地址)加上i乘以挂钩指令的字节长度。
图5示出了根据本发明一个实施例的根据步骤S210对全局偏移表进行修改和挂钩的过程的示意图。
如图5所示,在步骤S512中,采用memalign函数为全局变量trampoline分配内存空间,全局变量trampoline为挂钩指令表,用于存储各个待跟踪的库函数的挂钩指令。
随后,在步骤S514~S520中,将循环变量ndx初始化为0,在trampoline中循环填充push ndx和jmp fn_hook两条挂钩指令,每次循环后,变量ndx的值加一,直至trampoline填满为止。trampoline填满后,执行步骤S522。
在步骤S522中,记录下填充trampoline的总循环次数total,并调用mprotect函数将trampoline修改为可读可执行。
在步骤S524中,声明结构体struct lib_func{long addr;char*name;},以及长度为total的lib_func类型的函数信息数组libfuncs,并将libfuncs初始化为全0。
在步骤S526中,读取当前进程(即目标程序)的进程空间虚拟文件/proc/self/maps,获得当前进程各个段(segment)的地址与范围;结合目标程序的ELF文件,解析得到.rela.plt、.dynsym、.dynstr、.got.plt节在进程空间中的具体地址。
在步骤S528~S538中,循环处理重定位表中的各个表项,将每个重定位表项所对应的库函数的地址和名称存储至函数信息数组libfuncs中,并将GOT表中记载的库函数的地址修改为相应的挂钩指令的地址,直至重定位表项全部处理完毕为止。具体地:
在步骤S530中,调用ELF64_R_INFO宏通过重定位表项的r_info成员获得动态符号表中对应的下标,并根据.dynsym节的地址得到相应的动态链接符号。
在步骤S532中,通过动态链接符号的st_name成员,以及dynstr节的地址得到此库函数的名称fn_name。
在步骤S534中,通过重定位表项的r_offset成员获得GOT表中的下标,并根据.got.plt节的地址得到GOT表中保存的对应库函数的地址fn_addr;
在步骤S536中,设置libfuncs[i]的addr成员的值为fn_addr,设置name成员的值为fn_name(通过strdup复制一个值)。
在步骤S538中,将GOT表中对应库函数的地址从fn_addr修改为trampoline加上i乘以步骤S518中两条挂钩指令的长度(以字节为单位)。
图4示出了步骤S210的执行效果图。在步骤S210执行之前,GOT表中存储的是库函数的真实地址,例如,如图4中的虚线箭头所示,GOT表中的got[3]表项存储有库函数0的真实地址,got[4]表项存储有库函数1的真实地址,got[5]表项存储有库函数2的真实地址,等等。
在执行了步骤S210之后,挂钩指令表(trampoline)中存储有用于跟踪各个库函数的挂钩指令,函数信息数组libfuncs中存储有各个库函数的名称和地址。GOT表中存储的不再是库函数的真实地址,而是库函数的挂钩指令的地址,如图4中的实线箭头所示。
在步骤S210完成对全局偏移表的修改和挂钩后,当目标程序调用动态链接库中的库函数时,即可按照下述步骤S220~S260来对库函数的调用情况进行跟踪分析。
在步骤S220中,在目标程序调用动态链接库中的库函数时,根据全局偏移表来确定库函数的挂钩指令的地址,并跳转至该地址处执行该挂钩指令。
在目标程序调用动态链接库中的库函数时,动态链接器将跳转至全局偏移表中的相应位置来获取该库函数的地址。由于此时,全局偏移表中存储的已不再是库函数的真实地址,而是该库函数的挂钩指令的地址,因此,接下来将跳转至该挂钩指令的地址处,执行该挂钩指令。
在步骤S230中,挂钩指令压栈库函数的下标,并跳转至挂钩函数的地址处以执行该挂钩函数。
参见步骤S210的相关描述,挂钩指令包括用于压栈库函数下标的push指令和用于跳转至挂钩函数的地址处的jmp指令。依次执行这两条挂钩指令,压栈库函数的下标,并跳转至挂钩函数的地址处以执行挂钩函数fn_hook。
在步骤S240中,挂钩函数从栈中获取库函数的下标,将各个相关寄存器的值保存至栈中,将库函数的下标传入跟踪函数以调用该跟踪函数。
根据一种实施例,挂钩函数fn_hook首先弹出(pop)栈顶数据,即弹出库函数的下标,并将其保存至rax寄存器中。随后,将各个相关寄存器,例如rbx、rcx、rdx、rsi、rdi、r8、r9、r10等寄存器的值依次压栈(push),继而将rax寄存器的值(即库函数的下标)复制到rdi寄存器中,接着将库函数的下标(rax寄存器的值)传入跟踪函数trace_fn以调用(call)跟踪函数。
需要说明的是,在步骤S240中,fn_hook函数中需要将栈上的库函数下标首先弹出到rax寄存器中,这是因为其它的寄存器,即rbx、rcx、…r10等寄存器在x86架构下都可能被函数调用用来保存调用参数,因此不能破坏这些寄存器的内容。但是由于调用跟踪函数trace_fn需要传递参数,call指令调用C语言的函数缺省使用rdi寄存器保存第一个参数的值,而且在trace_fn运行的过程中可能会使用到不同的寄存器,因此需要将rdi等寄存器的值保存在栈上,再将rax寄存器的值(保存着库函数的下标)复制给rdi寄存器,再调用trace_fn函数。
在步骤S250中,跟踪函数根据库函数的下标,从函数信息数组中获取该库函数的名称和地址,输出跟踪信息,将库函数的地址返回至挂钩函数。
由步骤S210中函数信息数组libfuncs的创建过程可知,库函数的下标与函数信息数组中存储有该库函数的名称和地址的元素的下标相同。若库函数的下标为i,则跟踪函数可以从函数信息数组的第i个元素,即libfuncs[i]中读取该库函数的名称和地址。
跟踪函数trace_fn获取到库函数的名称和地址后,可以对该库函数进行跟踪处理,输出跟踪信息,以使开发者能够了解库函数的调用情况。根据一种实施例,跟踪信息包括当前时间戳和被调用的库函数的名称。
需要说明的是,如果跟踪函数trace_fn在对库函数进行跟踪处理时调用了其他的库函数,例如printf、malloc、strstr等,均需要要么查找函数信息数组libfuncs中的地址进行调用,要么自行实现。如果直接使用原函数调用,由于trace_fn是在库函数被调用之前被调用的,则可能导致无限循环死锁。
跟踪函数trace_fn完成对库函数的跟踪处理后,将库函数的地址返回给挂钩函数fn_hook。在缺省情况下,函数的返回值(库函数的真实地址)保存在rax寄存器中。
在步骤S260中,挂钩函数将栈中的值恢复至相应的寄存器,并跳转至库函数的地址处以执行该库函数。
在步骤S260中,挂钩函数fn_hook依次弹出栈顶的数据值,将其恢复至r10、r9、r8、rdi、rsi、rdx、rcx、rbx等相关寄存器。随后跳转至库函数的真实地址处,开始执行该库函数。在缺省情况下,函数的返回值(库函数的真实地址)保存在rax寄存器中,因此需要跳转到rax寄存器保存的值对应的地址处开始执行。
图6示出了根据本发明一个实施例的根据步骤S220~S260的库函数调用过程的示意图。
如图6所示,当主程序调用库函数i时,将在步骤S612中调用PLT表代码,确定库函数i在GOT表中的下标,然后在步骤S614中,跳转至GOT的相应地址处。
在现有技术中,没有按照前述步骤S210来修改GOT表,则GOT表中存储的是库函数i的真实地址,那么接下来在步骤S616中,将直接跳转至库函数i的地址处,执行该库函数。这样便无法对库函数进行跟踪了。
而基于本发明的技术方案,在步骤S210中对GOT表进行了修改和挂钩,GOT表的相应地址中存储的不再是库函数i的地址,而是库函数i的挂钩指令的地址,因此,在步骤S618中,基于GOT表中存储的地址,跳转至挂钩指令表trampoline的相应位置处,以执行库函数i的挂钩指令。
在步骤S620中,执行push i指令,将库函数的下标i压栈,随后执行jmpfn_hook指令,跳转至挂钩fn_hook的地址处执行。
在步骤S622中,执行fn_hook函数,弹出(pop)栈顶数据,即弹出库函数的下标i,并将其保存至rax寄存器中。随后,将各个相关寄存器,例如rbx、rcx、rdx、rsi、rdi、r8、r9、r10等寄存器的值依次压栈(push),继而将rax寄存器的值(即库函数的下标i)复制到rdi寄存器中,接着将库函数的下标i(rax寄存器的值)传入库函数i的跟踪函数trace_fn(i)以调用该跟踪函数。
在步骤S624中,跟踪函数trace_fn(i)根据下标i,从函数信息数组的第i个元素,即libfuncs[i]中读取该库函数的名称和地址,进行相应的跟踪处理,输出当前时间戳和库函数的名称等信息,随后向挂钩函数fn_hook返回库函数i的地址。
挂钩函数fn_hook接收到trace_fn(i)返回的库函数i的地址后,将栈顶的数据依次恢复至r10、r9、r8、rdi、rsi、rdx、rcx、rbx等相关寄存器。随后,在步骤S616中,跳转至库函数的地址处,开始执行该库函数。
本发明的技术方案通过对进程执行过程中的全局偏移表的修改和挂钩,能提供高性能的、通用的动态链接库函数的跟踪分析。本发明的技术方案通过为库函数设置挂钩指令(即对库函数进行挂钩)和跟踪函数来实现对库函数的跟踪,基于该方案,可以对所有的库函数进行挂钩和跟踪,也可以根据用户的需求仅对部分库函数进行挂钩和跟踪,具有良好的通用性和可定制性。
本方案依赖性小,通用性强,运行性能高,可广泛用于Linux操作系统下应用程序动态链接库的跟踪与分析中。
A11、一种存储有程序指令的可读存储介质,当所述程序指令被计算设备读取并执行时,使得所述计算设备执行如权利要求1-9中任一项所述的动态链接库函数的跟踪方法。
虽然本发明已以较佳实施例披露如上,但本发明并非限定于此。任何本领域技术人员,在不脱离本发明的精神和范围内,均可作各种更动与修改,因此本发明的保护范围应当以权利要求所限定的范围为准。
这里描述的各种技术可结合硬件或软件,或者它们的组合一起实现。从而,本发明的方法和设备,或者本发明的方法和设备的某些方面或部分可采取嵌入有形媒介,例如可移动硬盘、U盘、软盘、CD-ROM或者其它任意机器可读的存储介质中的程序代码(即指令)的形式,其中当程序被载入诸如计算机之类的机器,并被所述机器执行时,所述机器变成实践本发明的设备。
在程序代码在可编程计算机上执行的情况下,计算设备一般包括处理器、处理器可读的存储介质(包括易失性和非易失性存储器和/或存储元件),至少一个输入装置,和至少一个输出装置。其中,存储器被配置用于存储程序代码;处理器被配置用于根据该存储器中存储的所述程序代码中的指令,执行本发明的动态链接库函数的跟踪方法。
以示例而非限制的方式,可读介质包括可读存储介质和通信介质。可读存储介质存储诸如计算机可读指令、数据结构、程序模块或其它数据等信息。通信介质一般以诸如载波或其它传输机制等已调制数据信号来体现计算机可读指令、数据结构、程序模块或其它数据,并且包括任何信息传递介质。以上的任一种的组合也包括在可读介质的范围之内。
在此处所提供的说明书中,算法和显示不与任何特定计算机、虚拟系统或者其它设备固有相关。各种通用系统也可以与本发明的示例一起使用。根据上面的描述,构造这类系统所要求的结构是显而易见的。此外,本发明也不针对任何特定编程语言。应当明白,可以利用各种编程语言实现在此描述的本发明的内容,并且上面对特定语言所做的描述是为了披露本发明的最佳实施方式。
在此处所提供的说明书中,说明了大量具体细节。然而,能够理解,本发明的实施例可以在没有这些具体细节的情况下被实践。在一些实例中,并未详细示出公知的方法、结构和技术,以便不模糊对本说明书的理解。
类似地,应当理解,为了精简本公开并帮助理解各个发明方面中的一个或多个,在上面对本发明的示例性实施例的描述中,本发明的各个特征有时被一起分组到单个实施例、图、或者对其的描述中。然而,并不应将该公开的方法解释成反映如下意图:即所要求保护的本发明要求比在每个权利要求中所明确记载的特征更多特征。更确切地说,如下面的权利要求书所反映的那样,发明方面在于少于前面公开的单个实施例的所有特征。因此,遵循具体实施方式的权利要求书由此明确地并入该具体实施方式,其中每个权利要求本身都作为本发明的单独实施例。
本领域那些技术人员应当理解在本文所公开的示例中的设备的模块或单元或组件可以布置在如该实施例中所描述的设备中,或者可替换地可以定位在与该示例中的设备不同的一个或多个设备中。前述示例中的模块可以组合为一个模块或者此外可以分成多个子模块。
本领域那些技术人员可以理解,可以对实施例中的设备中的模块进行自适应性地改变并且把它们设置在与该实施例不同的一个或多个设备中。可以把实施例中的模块或单元或组件组合成一个模块或单元或组件,以及此外可以把它们分成多个子模块或子单元或子组件。除了这样的特征和/或过程或者单元中的至少一些是相互排斥之外,可以采用任何组合对本说明书(包括伴随的权利要求、摘要和附图)中公开的所有特征以及如此公开的任何方法或者设备的所有过程或单元进行组合。除非另外明确陈述,本说明书(包括伴随的权利要求、摘要和附图)中公开的每个特征可以由提供相同、等同或相似目的的替代特征来代替。
此外,本领域的技术人员能够理解,尽管在此所述的一些实施例包括其它实施例中所包括的某些特征而不是其它特征,但是不同实施例的特征的组合意味着处于本发明的范围之内并且形成不同的实施例。例如,在下面的权利要求书中,所要求保护的实施例的任意之一都可以以任意的组合方式来使用。
此外,所述实施例中的一些在此被描述成可以由计算机系统的处理器或者由执行所述功能的其它装置实施的方法或方法元素的组合。因此,具有用于实施所述方法或方法元素的必要指令的处理器形成用于实施该方法或方法元素的装置。此外,装置实施例的在此所述的元素是如下装置的例子:该装置用于实施由为了实施该发明的目的的元素所执行的功能。
如在此所使用的那样,除非另行规定,使用序数词“第一”、“第二”、“第三”等等来描述普通对象仅仅表示涉及类似对象的不同实例,并且并不意图暗示这样被描述的对象必须具有时间上、空间上、排序方面或者以任意其它方式的给定顺序。
尽管根据有限数量的实施例描述了本发明,但是受益于上面的描述,本技术领域内的技术人员明白,在由此描述的本发明的范围内,可以设想其它实施例。此外,应当注意,本说明书中使用的语言主要是为了可读性和教导的目的而选择的,而不是为了解释或者限定本发明的主题而选择的。因此,在不偏离所附权利要求书的范围和精神的情况下,对于本技术领域的普通技术人员来说许多修改和变更都是显而易见的。对于本发明的范围,对本发明所做的公开是说明性的而非限制性的,本发明的范围由所附权利要求书限定。

Claims (11)

1.一种动态链接库函数的跟踪方法,在计算设备中执行,包括:
在待跟踪的目标程序运行之前,设置用于跟踪各个库函数的挂钩指令,将各个库函数的名称和地址存储至函数信息数组,将全局偏移表中记载的库函数的地址修改为相应的挂钩指令的地址;
在目标程序调用动态链接库中的库函数时,根据所述全局偏移表来确定所述库函数的挂钩指令的地址,并跳转至所述地址处执行所述挂钩指令;
所述挂钩指令适于压栈所述库函数的下标,并跳转至挂钩函数的地址处以执行所述挂钩函数;
所述挂钩函数从栈中获取所述库函数的下标,将各个相关寄存器的值保存至栈中,将所述库函数的下标传入跟踪函数以调用所述跟踪函数,所述相关寄存器为r10、r9、r8、rdi、rsi、rdx、rcx、rbx中的至少一个;
所述跟踪函数根据所述库函数的下标,从函数信息数组中获取所述库函数的名称和地址,输出跟踪信息,将库函数的地址返回至所述挂钩函数;
所述挂钩函数将栈中的值恢复至相应的所述相关寄存器,并跳转至库函数的地址处以执行所述库函数。
2.如权利要求1所述的方法,其中,所述设置用于跟踪各个库函数的挂钩指令的步骤包括:
分配一块内存空间,在所述内存空间中填充各个库函数的挂钩指令,所述挂钩指令包括用于压栈库函数的下标的压栈指令和用于跳转至挂钩函数的跳转指令;以及
将所述内存空间的属性修改为可读可执行。
3.如权利要求2所述的方法,其中,所述将各个库函数的名称和地址存储至函数信息数组的步骤包括:
对于重定位表中的第i个库函数,通过读取相应的重定位表项的r_info成员来确定该库函数在动态符号表中的下标,从而确定该库函数对应的动态符号表项;
通过读取所述动态符号表项的st_name成员来确定该库函数的名称在动态字符串表中的索引,根据所述索引,在动态字符串表中查找确定该库函数的名称;
通过读取相应的重定位表项的r_offset成员来确定该库函数在全局偏移表中的下标,根据所述全局偏移表中的下标,从所述全局偏移表中获取该库函数的地址;
将该库函数的名称和地址存储至函数信息数组的第i个元素中。
4.如权利要求3所述的方法,其中,所述将全局偏移表中记载的库函数的地址修改为相应的挂钩指令的地址的步骤包括:
将库函数i的地址修改为所述内存空间的起始地址加上i乘以所述挂钩指令的字节长度。
5.如权利要求3或4所述的方法,其中,所述重定位表、动态符号表、动态字符串表、全局偏移表的地址根据所述目标程序的进程空间虚拟文件和可执行文件来确定。
6.如权利要求2所述的方法,其中,所述内存空间中所存储的挂钩指令的组数与所述函数信息数组的长度相同。
7.如权利要求1所述的方法,其中,所述跟踪信息包括当前时间戳和被调用的库函数的名称。
8.如权利要求1所述的方法,其中,所述挂钩函数、所述跟踪函数实现为跟踪库的库函数,所述跟踪库为用于跟踪目标程序的库函数调用情况的动态链接库,
所述设置用于跟踪各个库函数的挂钩指令,将各个库函数的名称和地址存储至函数信息数组,将全局偏移表中记载的库函数的地址修改为相应的挂钩指令的地址的步骤,由所述跟踪库的初始化函数执行。
9.如权利要求8所述的方法,其中,所述跟踪库在所述目标程序所调用的其他动态链接库之前被载入内存,所述跟踪库的初始化函数在所述目标程序所调用的其他动态链接库的初始化函数之后被执行。
10.一种计算设备,包括:
至少一个处理器;和
存储有程序指令的存储器;
当所述程序指令被所述处理器读取并执行时,使得所述计算设备执行如权利要求1-9中任一项所述的动态链接库函数的跟踪方法。
11.一种存储有程序指令的可读存储介质,当所述程序指令被计算设备读取并执行时,使得所述计算设备执行如权利要求1-9中任一项所述的动态链接库函数的跟踪方法。
CN202010074420.XA 2020-01-22 2020-01-22 一种动态链接库函数的跟踪方法及装置 Active CN111290952B (zh)

Priority Applications (1)

Application Number Priority Date Filing Date Title
CN202010074420.XA CN111290952B (zh) 2020-01-22 2020-01-22 一种动态链接库函数的跟踪方法及装置

Applications Claiming Priority (1)

Application Number Priority Date Filing Date Title
CN202010074420.XA CN111290952B (zh) 2020-01-22 2020-01-22 一种动态链接库函数的跟踪方法及装置

Publications (2)

Publication Number Publication Date
CN111290952A CN111290952A (zh) 2020-06-16
CN111290952B true CN111290952B (zh) 2023-04-14

Family

ID=71026195

Family Applications (1)

Application Number Title Priority Date Filing Date
CN202010074420.XA Active CN111290952B (zh) 2020-01-22 2020-01-22 一种动态链接库函数的跟踪方法及装置

Country Status (1)

Country Link
CN (1) CN111290952B (zh)

Families Citing this family (9)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
CN114327467A (zh) * 2020-09-29 2022-04-12 武汉斗鱼网络科技有限公司 一种获取系统函数信息的方法以及相关设备
CN112731909A (zh) * 2021-01-07 2021-04-30 东风电子科技股份有限公司 实现车辆电机控制器故障数据记录读取的方法、系统、装置、处理器及其存储介质
CN112988570B (zh) * 2021-02-08 2023-03-10 芯华章科技股份有限公司 一种调试程序的方法、电子设备及存储介质
CN112948024B (zh) * 2021-04-15 2022-11-04 网易(杭州)网络有限公司 动态链接库的加载方法、装置、存储介质及电子设备
CN113297074B (zh) * 2021-05-21 2023-12-22 百果园技术(新加坡)有限公司 一种内存跟踪方法及装置
CN113778687B (zh) * 2021-09-16 2024-02-23 北京小米移动软件有限公司 内存分配信息处理方法、装置、电子设备及存储介质
CN113821273B (zh) * 2021-09-23 2023-10-13 武汉深之度科技有限公司 一种应用程序运行方法、计算设备及存储介质
CN114168489B (zh) * 2022-02-08 2022-12-30 统信软件技术有限公司 一种函数信息获取方法、计算设备及存储介质
CN115061685B (zh) * 2022-06-30 2023-07-21 上海弘玑信息技术有限公司 软件客户端的界面元素定位方法及电子设备、存储介质

Citations (3)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
US7757215B1 (en) * 2006-04-11 2010-07-13 Oracle America, Inc. Dynamic fault injection during code-testing using a dynamic tracing framework
CN108415739A (zh) * 2018-02-28 2018-08-17 腾讯科技(深圳)有限公司 一种动态链接库函数的钩挂方法、装置和存储介质
WO2019237866A1 (zh) * 2018-06-12 2019-12-19 杨力祥 一种运行时访问控制方法及计算装置

Family Cites Families (1)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
US20100095281A1 (en) * 2008-10-14 2010-04-15 Riverside Research Institute Internal Function Debugger

Patent Citations (3)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
US7757215B1 (en) * 2006-04-11 2010-07-13 Oracle America, Inc. Dynamic fault injection during code-testing using a dynamic tracing framework
CN108415739A (zh) * 2018-02-28 2018-08-17 腾讯科技(深圳)有限公司 一种动态链接库函数的钩挂方法、装置和存储介质
WO2019237866A1 (zh) * 2018-06-12 2019-12-19 杨力祥 一种运行时访问控制方法及计算装置

Non-Patent Citations (2)

* Cited by examiner, † Cited by third party
Title
DroidTrace: A Ptrace Based Android Dynamic;Min Zheng;《IEEE》;20140925;全文 *
基于Inject和Hook的安卓终端管控技术;秦中元;《信息网络安全》;20180930;全文 *

Also Published As

Publication number Publication date
CN111290952A (zh) 2020-06-16

Similar Documents

Publication Publication Date Title
CN111290952B (zh) 一种动态链接库函数的跟踪方法及装置
US9996696B2 (en) Systems and methods to optimize execution of a software program using a type based self assembling control flow graph
Wenzl et al. From hack to elaborate technique—a survey on binary rewriting
US5999732A (en) Techniques for reducing the cost of dynamic class initialization checks in compiled code
CN107291480B (zh) 一种函数调用方法及装置
US7596781B2 (en) Register-based instruction optimization for facilitating efficient emulation of an instruction stream
EP3267308B1 (en) Application loading method and device
CN114816417B (zh) 一种交叉编译方法、装置、计算设备及存储介质
CN114924810B (zh) 一种异构程序执行方法、装置、计算设备及可读存储介质
US9465595B2 (en) Computing apparatus, computing method, and computing program
CN110663082B (zh) 数据处理系统和方法
JP4004915B2 (ja) データ処理装置
US7065754B1 (en) Method and apparatus for switching between multiple implementations of a routine
CN115904486A (zh) 一种代码相似度检测方法及装置
CN114168489B (zh) 一种函数信息获取方法、计算设备及存储介质
CN111279308A (zh) 代码转换期间的屏障减少
US20040045018A1 (en) Using address space bridge in postoptimizer to route indirect calls at runtime
CN117130721B (zh) WebAssembly代码的执行方法及装置
JP4545777B2 (ja) データ処理装置
Kaufmann et al. Superblock compilation and other optimization techniques for a Java-based DBT machine emulator
CN114036066A (zh) 一种单元测试方法、装置、计算设备及可读存储介质
CN117492828A (zh) 二进制翻译调试方法、装置、计算设备及存储介质
CN114830097A (zh) 处理器、模拟器程序、汇编程序以及信息处理程序
JP4498338B2 (ja) データ処理装置
CN113760236A (zh) 重定位方法、装置、链接器及编译系统

Legal Events

Date Code Title Description
PB01 Publication
PB01 Publication
SE01 Entry into force of request for substantive examination
SE01 Entry into force of request for substantive examination
CB02 Change of applicant information

Address after: 17th Floor, Building 12, Yard 10, Kegu 1st Street, Beijing Economic and Technological Development Zone, Daxing District, Beijing 102600 (Beijing Pilot Free Trade Zone High-end Industry Zone Yizhuang Group)

Applicant after: Beijing Tongxin Software Technology Co.,Ltd.

Address before: 603, block B, Putian Desheng, No.28, xinjiekouwei street, Xicheng District, Beijing 100032

Applicant before: BEIJING SHENZHIDU TECHNOLOGY CO.,LTD.

CB02 Change of applicant information
GR01 Patent grant
GR01 Patent grant