跨进程API Hook.net

2024-05-02

跨进程API Hook.net(精选2篇)

篇1:跨进程API Hook.net

近日,由于程序设计需要,我对WincowsCE的内存布局进行了研究,由于发现国内在这方面的文档资料较少,于是在研究告一段落之际,形成这篇示例文档,以望抛砖引玉,得到别的高手的指正,

一、程序实现的先决条件

由于Windows系统的窗体消息总是投递至一个特定进程的指定窗体消息函数中。于是在本地进程(自己的应用程序)中取得属于其它进程的窗体的消息必须实现以下两个部分:

1、将需要挂接窗体的代码放到目标进程的地址空间中去。

2、执行这一段代码,并获得目标进程窗体的消息。

这两步看起来很简单,但在实现过程中就比较困难。由于WindowsCE作为嵌入式移动设备操作系统,与Windows98/2000/XP等桌面操作系统在内核的设计理念以及API的支持上有极大的区别。这就直接导致了常规的桌面系统利用全局鼠标钩子注入/远程线程注入等方法在CE中完全得不通。不过可喜的是,微软在开发工具中提供的remotexxx等远程调试程序使我清楚这个目标并不是不可能的任务,微软既然可以做到,那就是说在CE的内部一定有一套完整的跨进程内存访问/代码注入的机制。

二、程序实现的基本原理

经过两天的google搜索,在网上我发现了一个没有在微软文档中声明的有趣的API函数:PerformCallBack4,传说中这个函数可以在自己的应用程序中执行指定的进程中的一个函数,SoCool!这好象正是我所需要的东西。虽然网上也传闻这个函数在wm5不受支持,其实经过实践这个传闻只是谣传而已!

PerformCallBack4函数的定义:

publicstaticexternuintPerformCallBack4(refCallBackInfoCallBackInfo,

IntPtrni_pVoid1,IntPtrni_pVoid2,IntPtrni_pVoid3);

其中函数的参数CallBackInfo结构定义:

publicstructCallBackInfo

{

publicIntPtrhProc;//远程的目标进程

publicIntPtrpfn;//指向远程目标进程的函数地址的指针

publicIntPtrpvArg0;//函数的需要的第一个参数

}//endstruct

而PerformCallback4的ni_pVoid1、ni_pVoid2、ni_pVoid3为传递到远程目标进程执行函数的其它三个参数,

至于将代码放到目标进程的内存空间,我们可以利用CE设计上的一个特性:

1、为了节约内存使用,CE将所有程序调用的动态链接库(DLL)都映射到同一个内存地址中。

2、CE的内存布局中划分有一个slot0的内存位置,这个内存位置是由正在执行的进程所占有的,每一个特定的时间片,只能有一个进程可以占有这个内存空间。在进程要求执行时,系统并不直接执行进程所处内存位置的代码,而是将该进程的执行代码复制到slot0的内存位置中产生一个副本执行。也就是说进程在执行时内存将会有进程执行代码的两个完全一样的版本:存在于slot0中正在执行的进程代码和进程本身所处的内存中的代码。

在这个特性下,可以得到结论:如果进程A通过LoadLibrary函数装载Test.dll,而进程B也通过LoadLibrary函数装载同一个Test.dll,这个Test.dll的所有函数在进程A和进程B中执行时,相对于slot0中的进程执行代码都会得到同一地址。

3、在CE中,系统在内存中划分出33个slot,slot0保留给正在执行的进程,然后在进程启动时将所有的代码放到除slot0以外的一个slot中(这就是臭名昭著的CE系统中内存最多只能有不多于32个程序执行的限制的来由)。在进程执行时,每个应用程序的内存访问默认只能访问slot0内存空间中的地址以及进程所处的slot内存空间的地址。但为使设备驱动程序可以访问到它们所需的其它应用程序数据,CE提供了两个函数以打破这个限制,SetKmode和SetProcPermission,SetKmode函数告诉系统,当前运行的进程是否需要在内核模式中执行;SetProcPermission函数可以接受一个位掩码,每一位代码一个slot的访问控制,1代表可以访问该slot的内存内容。0表示不能访问该slot的内存内容。这两个函数在msdn中有帮助文档,可参阅msdn的文档说明。

篇2:跨进程API Hook.net

关键词:Elastos,对象调用,构件,DBus

软件工程的向前发展,带来了编程模型的不断进步,从最初的结构化编程,到后面的面向对象编程,再到现在比较流行的构件编程,都体现了人们希望开发出一套可以像积木拼装一样的编程模型。构件编程不同于面向对象编程,面向对象编程强调对个体的抽象,而构件编程是对面向对象编程的发展,它更加强调系统中各个组成部分的协调关系。在构件编程中,系统是由构件组成的,构件可以用某种方式很轻松地组装成一个系统。在一个复杂系统中,构件可能由多种不同的语言实现,而且会分布在不同的进程里面,这就需要系统提供一种机制,能够使得不同进程、不同语言中的构件对象能够相互调用。

Elastos是基于构件的操作系统[1],它实现了构件的组装和构件对象跨进程调用,但现有的模型存在无法与非Elastos系统的构件进行调用的问题。本文在Elastos现有构件编程模型的基础上,将构件调用模型分成了marshal,数据传输,unmarshal三个部分,并将三个部分设计成可替换的,即用户可以自行决定这三个部分如何实现。这样一来可以兼容现在的调用模型,二来可以使用户根据自己的系统环境对各个部分进行优化。本文在进行分析比较后,marsh和unmarshal使用了Elastos现有的实现方式,而数据传输使用了在Linux上已经广泛应用并且易于移植的DBus。

1 相关技术介绍

1.1 DBus

DBus是一种低延迟,低开销,易用的进程间通信机制(IPC)[2]。DBus里面有两种总线(Bus):system bus和session bus。system bus是所有用户都可以访问的总线,一般用于系统通知各种事件;session bus一般是用于属于特定用户的程序之间的通信。

DBus里面有下面几个概念很重要:

1)Bus Name:连接的总线名字。存在两种类型的Bus Name:公共名(well-known names)和唯一名(Unique Connection Name)。

2)接口(interface):接口是多个方法和信号的集合,每个接口有一个或多个的方法,接口相当于C++里面的纯虚类,DBus使用简单的命名空间字符串来表示接口。

3)对象(Object):对象是处理消息的一个实例,对象有一个或多个接口。

4)对象路径(Object Path):对象路径是一个用于引用对象实例的名字。

5)方法(methods)和信号(signals):对象有两种成员:方法和信号,方法可以被调用,信号会被广播到对这个信号感兴趣的对象。

DBus是一种类似于总线(bus)的通信方式,要成为一条总线,只是点对点是不够的,必须具备一点对多点的通信机制。总线隔离了各个应用程序,使得各个应用程序的耦合变小了。在DBus中,存在一个守护进程DBus-daemon,它就是DBus实现总线通信方式的核心。如果没有Dbus-daemon,DBus协议只相当于一个普通IPC通信机制。Dbus-daemon就是在模拟总线(bus)机制,它提供了接口让别的程序加入到总线,并提供消息转发,管理程序(主要是服务)的生命周期,错误处理,日志记录的功能。

1.2 Elastos构件编程

Elastos是一种基于构件的操作系统,它通过元数据(metadata)实现了构件动态组装。元数据是描述数据的数据(data about data),它是对数据的抽象,主要描述了数据的类型信息。在Elastos中,元数据被编译进了构件的二进制代码中。在运行时,Elastos运行环境会在加载构件时加载元数据,然后根据元数据实现构件的动态组装。

在构件中加入元数据的另外一个好处是可以实现反射机制。反射的意思是只通过构件本身,就可以知道构件提供那些功能和如何调用这个功能。在Elastos中,构件的元数据包括类(class),类里面的接口(interface),接口里面的方法(method)和方法里面的参数(argument)等。Elastos提供了一组用于反射的API,使得程序员可以通过这些API获取构件对象元数据信息,并且调用构件对象[3]。迄今为止,实现了反射机制的语言有Java,C#,Ruby等,而Elastos的反射是在C/C++里面实现。嵌入式设备因为效率的原因,大部分是由C/C++开发的,而Elastos可以在C/C++里面使用反射机制,将可以极大地方便程序的开发。在本文中,跨进程调用C/C++对象就是通过反射机制实现的。

2 对象调用模型的设计

2.1 跨进程跨语言调用的实现

实现跨进程调用包括三个部分:如何描述调用信息,如何传输调用信息,如何根据调用信息调用对象。

一般来说,要调用对象里面的一个方法,我们需要这些信息:对象指针(或引用),方法相对于对象指针的偏移量,方法的参数信息(个数和参数类型)。而在一个具备反射机制的系统里面,我们根据对象就可以获取方法相对于对象指针的偏移量和方法的参数信息,因此我们只需要一个对象指针就可以了。为了便于程序员使用和安全,构件系统里面一般会将构件注册为服务,也就是说,程序员可以根据服务名来获取对象指针。综上所述,在一个具备反射机制的系统里面,描述调用信息只需要:构件对象的服务名,要调用的方法名称,参数。

由于进程间的地址空间是独立的,因此我们不能支持操纵其他进程的对象,而是必须将调用信息传输给另外一个进程,由这个进程的Stub来完成具体的操作。要实现跨进程数据传输,一般使用的方法有:共享内存,管道通信,Socket通信等。在本文中,传输调用信息采用的是DBus。DBus是一种基于Socket的进程间通信机制。在linux平台上,DBus采用的是Unix Socket,由于Unix Socke省去了包校验等环节,其效率基本和管道通信相近。在windows平台上,DBus采用的是一般的Socket通信,因此效率会有轻微下降。同时,DBus提供了多种语言的Binding,使得这些语言编写的程序可以很容易地通过DBus进行通信。

至于如何根据调用信息调用对象,这涉及反射的相关细节,每种语言的处理反射不尽相同,本文将在后面的2个小节中对C++和Java的实现进行详细的介绍,其他具备反射能力的语言(例如C#,Ruby)处理方式与此类似。

具体到设计,整个调用过程分为三个阶段:marshal,IPC数据传输,unmarshal。在marshal阶段,主要完成调用信息的打包,即将调用信息转换成二进制格式化的数据[4]。在IPC数据传输传输阶段,主要完成根据调用信息将marshal阶段产生的数据传送到对应的构件进程。在unmarshal阶段,主要完成对接收到数据进行解包,然后根据解包后的信息调用具体的对象并返回结果。这个调用过程如图1。

在marshal和unmarshal时,采用的是Elastos规定的数据格式,这种格式是更加C/C++语言制定的。当涉及到不同语言的对象调用时,例如C++里面调用Java对象,由于每种语言对基本数据类型的定义存在细微差别,因此需要进行产生参数的转换。由于参数类型的意义是固定,只是不同语言对参数所占字节数规定的不同,因此参数的转换可以用相应语言提供的API进行实现。当各种语言的构件可以相互调用后,整个构件调用模型如图2。

2.2 动态调用C/C++对象

这小节主要讲述如何利用方式机制实现动态调用C/C++对象。首先需要说明的是,这里所说的C/C++对象并不是普通的C/C++对象(不带元数据的C/C++对象),而是在Elastos环境下用CAR技术编写的C/C++对象。如果要调用普通的C/C++对象,程序员需要在Elastos环境对这个普通的C/C++对象进行一下简单的封装。

在Elastos中,提供了CReflector这个类用于反射,并提供了IClassInfo,IMethodInfo,IArgumentList等接口用与获取类,方法,参数等信息。一个最简单的通过反射调用对象的例子如下:

在进行动态调用时,由于对象已经提前创建,上面代码的前3行是不需要的,我们可以直接使用CObject::ReflectClassInfo来获取IClassInfo接口,我们可以用CSystem::FindRunningObject来根据对象的服务名来获取pObj指针。

2.3 动态调用Java对象

反射(Refelection)是Java语言的特性之一,它允许Java程序在运行时获取对象的信息,并操作对象的内部属性(成员方法和成员变量)等。在Java的JDK中,实现反射的类都在java.lang.reflection包中[5],主要有:

1)Class类:用于与类相关操作,例如加载类,获取类的成员方法和成员变量等。

2)Field类:用于类的成员变量相关的操作。

3)Method类:用于类的成员方法相关的操作。

4)Constructor类:用于类的构造方法相关的操作。

由于Java对反射的内置支持,在Java里面使用反射式非常容易了,程序员可以查阅相关资料来了解如何使用Java的反射,本文就不再赘述。

在本文中,调用Java对象的难点在于参数的转换。由于Elastos的元数据使用二进制格式进行表示的,而用Java直接处理这个二进制存在难转换和效率问题,因此本文通过Java调用Jni来实现参数的转换。这样带来好处有:1.效率高;2.可以直接使用Elastos API,方便开发。

3 实验分析

为了测试跨进程跨语言进行对象调用的效率,本文搭建了测试环境:本文基于如下设备进行测试的:一台型号为F902装有Android系统的手机(主频为500MHz,内存为128MB),一台装有Windows XP的PC机(主频为3.6MHz,内存为1GB),在这台PC上装有Elastos运行环境。测试所进行的操作为:构件A调用构件B,构件B将传递过来的参数加1,然后返回,构件A将结果打印出,测试后得到的输入如表1。

从上面的测试数据可以看出,跨进程调用所花时间基本是同一进程调用所花时间的4倍左右,但还属于可以接受的范围,但随着硬件水平的提升和软件成本的增高,跨进程跨语言对象调用所带来的软件开发时间的缩短将比无味追求运行效率更加吸引人,而且本文提出的模型还存在很大的优化余地。

4 结束语

本文在Elastos构件编程的基础上提出了一种新的对象调用模型,使得不同进程、不同语言间的对象可以相互调用,这将使得不同进程、不同语言里面的构件进行相互调用,进而进行组装。本文还给出了相关的测试数据,以供需要采用类似技术的人员进行参考。随着构件技术的发展,跨进程和跨语言调用肯定会成为构件编程的基础,本文所提出的模型就为跨进程和跨语言调用提供了一种解决方案。

参考文献

[1]上海科泰世纪技术有限公司.Elastos资料大全[EB/OL].http://www.koretide.com.cn.

[2]Havoc Pennington.D-Bus Tutorial[EB/OL].http://dbus.freedesktop.org/doc/dbus-tutorial.html.

[3]张久安.CAR构件与Java构件的互调机制研究与开发[D].上海:同济大学硕士论文,2007.

[4]刘文荣.Elastos应用跨平台运行机制研究与实现[D].上海:同济大学硕士论文,2008.

本文来自 360文秘网(www.360wenmi.com),转载请保留网址和出处

【跨进程API Hook.net】相关文章:

上一篇:难忘的生日高中作文下一篇:管理学院班主任日常工作常规

本站热搜

    相关推荐