背景技术
视窗操作系统提供了一系列的应用程序接口(API)函数,亦称作系统函数,供基于视窗操作系统的应用程序调用,几乎所有的运行于视窗操作系统的应用程序都会调用所述的API。例如:进行文字输入操作时,相应的文字处理软件则调用视窗操作系统提供的用于文字输出的API,实现在机器屏幕上进行文字显示。
在程序执行过程中,为了完成操作,一个程序通常还需要获取其他正在执行的程序的执行参数。例如:即时翻译软件对记事本所打开的文本文件中的某个词进行取词操作,要实现对该词的取词操作,即时翻译软件需要获取输出该词时API调用的相关参数,然而该文本文件中内容的输出是记事本应用程序直接调用视窗操作系统提供的API完成的,其所传递的参数是所述即时翻译软件无法直接从记事本中获取的。因此,某个应用程序要获取其他应用程序中的某个参数,就需要在这些应用程序调用视窗操作系统API时执行截获。
现有技术在32位视窗操作系统上实现了上述功能,以应用程序APP2要获取应用程序APP1调用系统函数TextOutA所传递的参数为例说明现有32位系统下的实现方法。
在应用程序APP2中设计一个函数,用于处理被拦截的参数,称其为陷阱函数(Trap);图1为地址空间示意图,该图示出了在虚拟地址空间中函数的存储结构,即通过访问函数入口地址实现调用,当APP1调用TextOutA时,修改TextOutA的入口地址所对应的指令,修改其为跳转指令,目的在于跳转到陷阱函数的入口地址,从而执行陷阱函数;由于修改TextOutA函数的入口指令为一条跳转指令,在32位视窗操作系统下,跳转指令一般占有5个字节,从TextOutA函数的入口开始的5个字节的指令条数N的范围是,N>=1且N<=5,这N条指令被跳转指令所取代,导致TextOutA将不能被完整执行,基于这个原因,需要在修改TextOutA函数入口地址之前,就计算出N值,并把这N条指令复制到缓冲区中,并在这N条指令后增加一条跳转指令(用于跳转回TextOutA函数原入口地址开始的第N+1跳指令继续执行),生成桩函数(Stub)。
基于上述方法,并参照图2所示的参数获取流程图可知。(1)APP1调用系统函数TextoutA时,(2)陷阱函数将截获APP1发送给系统函数TextoutA的参数,(3)并在对参数进行处理后调用桩函数,依据所述参数执行被复制的所述N条指令,(4)进而通过跳转指令跳转回TextoutA第N+1条指令,继续执行TextOutA,这样不仅获取了APP2传递给TextoutA的参数,并且能保证TextoutA的正常执行。上述过程对于APP1是透明的。
上述方法中系统函数入口的前N个指令将被覆盖,由于32位操作系统需要由栈保存/恢复寄存器中的数据,函数入口开始通常为堆栈指令,因此被覆盖/备份的指令一般情况下都是该些堆栈指令而不会涉及地址的操作,该些指令备份到桩函数中执行依然正常。即使在入口指令中出现了涉及地址操作指令,由于32位寻址空间小,因而只需进行简单计算即可获取所述指令所指向的正确位置。
然而64位操作系统不使用栈传递数据,函数入口开始的指令就可能有是涉及地址的操作;并且,64位操作系统下,指令所占用字节数增大,使得所备份的指令中包含地址操作指令的可能性相应的增大。因此将现有技术应用于64位操作系统中时将出现大量地址运算的问题,并且,由于64位系统环境下,由于寻址空间很大,因而采用32位系统下简单的计算方法无法得到正确的地址。
发明内容
为了解决上述问题,本发明的目的是提供一种能够实现在64位视窗操作系统下获取函数参数的方法。
为解决上述技术问题,本发明的目的是通过以下技术方案实现的:
一种64位视窗操作系统下获取函数参数的方法,用于在应用程序调用系统函数时获取其参数,包括:预置陷阱函数;修改系统函数入口指令为指向预置的陷阱函数入口地址的第一跳转指令;生成桩函数,包括:将系统函数入口被第一跳转指令覆盖的指令集合复制到预先确定的缓冲区;使桩函数包含上述指令集合,将其中相对地址操作变换为绝对地址操作,并在所述指令集后添加指向系统函数中所述第一跳转指令后的第一条指令的第二跳转指令;在应用程序调用系统函数时,通过所述第一跳转指令调用陷阱函数获取参数并进行处理,进而调用桩函数完成系统函数中被覆盖的指令,并通过第二跳转指令返回继续执行系统函数。
上述方法基础上,通过查找预置的指令代码表实现相对地址操作指令到绝对地址操作指令的变换。
上述方法基础上,通过反汇编计算出第一跳转指令在系统函数中占用地址空间的指令数,进而确定复制到缓冲区的指令集。
上述方法基础上,序应用程序完成系统函数调用后,还包括将备份到缓冲区的指令恢复到系统函数中。
所述方法中的地址操作包括寻址操作。
一种64位视窗系统中获取函数参数的系统,用于在应用程序调用系统函数时获取其参数,包括:系统函数入口指令修改单元,将系统函数的入口地址指令修改为指向陷阱函数入口地址的第一跳转指令;陷阱函数单元,对获取的参数进行处理,并且将其中相对地址操作变换为绝对地址操作;桩函数单元,包括系统函数中被第一跳转指令覆盖的指令集,该指令集中包括绝对地址操作的指令;所述指令集后还包括第二跳转指令,指向系统函数入口指令修改单元中所述第一跳转指令后的第一个指令地址。
其中,所述地址操作包括寻址操作。
以上技术方案可以看出,由于本发明中将桩函数中指令集中的相对地址操作指令变换为绝对地址操作指令,所述地址指向不随该指令存储地址的改变而改变,进而所述指令集被复制到确定缓冲区后,其中的地址操作指令(寻址操作或地址跳转)仍然可以指向正确的指令地址,保证了系统函数的顺利执行,使得本发明获取函数参数的操作不会影响程序的正常执行。
具体实施方式
本发明所涉及64位系统中函数参数的获取方法。
所述64位是指CPU通用寄存器(General-Purpose Register,GPRs)的数据宽度(位宽)为64位。64位的处理器可以一次传输和运算64bit即8个字节的数据,相比现行的32位处理器一次只能处理32bit即4个字节的数据,理论上在相同的时钟周期内,64位平台处理的数据量是32位平台处理数据量的两倍;并且,64位处理器的优势还体现在系统对内存的控制上,现行32位处理器的寻址空间最大为4GB,而64位平台的寻址空间的282TB(1TB=1024GB),使得可以进行更大范围的数据计算以及支持更大容量的内存。
现行系统中采用相对地址操作的方式。由于程序和函数每次加载到内存后,系统所分配的地址空间都是不同的,即每次程序或函数被加载到内存中的绝对地址都是不同的,因此程序中涉及到地址的寻址或跳转等操作通常都使用相对地址,相对地址是在函数首地址基础上进行的地址偏移;使用相对地址才能保证即使每次加载到内存中的绝对地址不同,寻址指令依然能正常执行。
然而,对于使用相对地址的指令来说,将相对地址操作指令备份到桩函数后,由于桩函数的首地址和函数的首地址不同,因此导致在桩函数的首地址基础上进行偏移后的地址,并不是原先函数首地址基础上进行偏移的地址,使得程序执行出现错误。
基于上述分析,本发明主要针对于现有32位操作系统的解决方案中复制指令步骤所做的改进,使其能够适用于64位操作系统之上。其核心思想在于:把相对指令转换成绝对地址。具体的,对于备份到确定缓冲区的指令进行指令分析,将所有涉及相对地址的指令,例如相对寻址方式的操作或/和相对跳转指令,采用绝对寻址和绝对跳转指令进行变换,由于所述过程需要生成额外的CPU指令才能完成,因而称之为动态重汇编,动态汇编的过程通过查表完成;动态重汇编完成后,生成桩函数,这个函数的最后一条指令为绝对跳转指令,用于跳转回系统函数以保证系统函数的正常执行。
以下具体说明本发明所述的64位视窗操作系统下获取函数参数方法的实现方式。
生成陷阱函数,用于对所获取参数的操作;所述陷阱函数依据业务具体需求进行生成,本发明不进行具体限定。
设应用程序APP2需要获取应用程序APP1的参数,则在APP2中编写代码注入函数,当应用程序APP2加载到内存后,代码注入函数把用户代码加载到与应用程序APP1以及APP1将要调用的系统函数的同一个地址空间中,完成对系统函数的修改以及桩函数的生成。
参照图3说明本发明中桩函数的生成以及对系统函数的修改。
步骤31:获取系统函数的入口地址;
步骤32:修改系统函数入口指令为第一跳转指令指向预置的陷阱函数入口地址;并且,计算系统函数入口被第一跳转指令所占用地址空间的指令数N;
指令占用至少一个字节的地址空间。处理器每次从存储器中读取一条指令,并在取指令完成后,根据指令类别自动将程序计数器值变成下一条指令的地址;同时,获取的指令被放入指令寄存器中,处理器解释并执行该指令。64位操作系统下,绝对跳转指令(jmp)通常占用14个字节,因此在系统函数入口可能需要备份最少1条,最多14条的指令到桩函数中;
如图1所示,存储在地址空间的为机器语言,计算机只能识别所述机器语言,即由0和1构成的代码;但通常在编程时,不采用机器语言,因而所有应用程序执行时都要由解释器或编译器转换成机器语言才能运行于机器上;本步骤中采用反汇编的方法实现对出第一跳转指令在系统函数中占用地址空间的指令数的计算;
步骤33:将该些N条指令进行复制,保存到缓冲区;
步骤34:对所述N条指令构成的指令集进行分析,将其中的相对地址操作变换为绝对地址操作;
依据预置的指令代码表实现所述相对地址操作指令到绝对地址操作指令的变换;
步骤35:在所述指令集最后添加第二跳转指令,该跳转指令为绝对地址跳转指令,用于跳转到原系统函数入口指令的第N+1条指令,即系统函数入口所述第一跳转指令后的第一条指令;
步骤36:生成桩函数。
在上述方法基础上,参照图4,进一步说明上述方法基础上本发明获取函数参数的实现流程。
步骤41:应用程序调用系统函数;
步骤42:跳转到陷阱函数,使得陷阱函数得以获取应用程序发出的相应参数,执行陷阱函数对参数进行相应的操作;
步骤43:调用桩函数,并执行;
步骤44:跳转到系统函数第N+1条指令,继续执行系统函数中的后续指令;
步骤45:将备份到缓冲区中的指令恢复到系统函数中;所述恢复备份的指令的时机可依据功能的需求,如果要持续拦截参数,则不进行步骤45的指令回复,如果仅仅是拦截一次,则执行本步骤。
本发明还提供了一种64位视窗系统中获取函数参数的系统,用于在应用程序调用确定系统函数入口指令修改单元时获取其参数。该系统包括:
系统函数入口指令修改单元,入口地址指令为第一跳转指令,指向所述陷阱函数入口地址;
陷阱函数单元,对获取的参数进行处理,并在完成操作后调用桩函数单元;
桩函数单元,包括系统函数中被第一跳转指令覆盖的指令集,该指令集中包括绝对地址操作的指令;所述指令集后还包括第二跳转指令指向系统函数入口指令修改单元中所述第一跳转指令后的第一个指令地址。
上述系统中各单元的生成方法可参见上文方法的相应说明,此处不再赘述。
以上对本发明所提供的一种64位视窗操作系统下获取函数参数的方法及系统进行了详细介绍,本文中应用了具体个例对本发明的原理及实施方式进行了阐述,以上实施例的说明只是用于帮助理解本发明的方法及其核心思想;同时,对于本领域的一般技术人员,依据本发明的思想,在具体实施方式及应用范围上均会有改变之处,综上所述,本说明书内容不应理解为对本发明的限制。