“函数调用反转”我们应该如何来理解这个词呢?假设:函数A调用函数B,那么函数B的调用方为函数A;那么在.NET中,你可以采取接口或继承重写的方式把函数A的调用原始函数B的行为进行代理;但这仅限于你可以继承重写或者实现的情况下;在大多数情况下你无法办到这些事情;尤其是在使用第三方密封库的前提下;而且上述提到的方式虽然属于调用反转但它们都有各自的缺陷,从现实角度上看它们并不符合实际;
有人说或许可以通过Remoting它由CLR层面实现;但如果我说我想要劫持.NET框架系统中某个FCL或者BCL库中的某个私有函数,而它无法重写而且Remoting只允许动态库内明确标明相关特性的同时要求此类必须公开;显然它根本不可取,这里并未有谈Remoting效率的问题。
当前如果仅仅只是第三方库或许可以采取一些静态注入代码的方式,比如利用Mono.Cecil直接修改编译好的对应程序集库,从实际角度上是可行的应该它并不是很复杂;但它的实现一般是专用的可服用性较差;如果想单独插入一些简单的代码自动化是或许是最佳选择;但利用它实现还是具备很多的缺点。
从上述的内容可以看出,这些方面都有各自的一些缺陷,那么有没有一种更好的方式;在不需要上述任何方法的前提则可以实现,而且即便是任何第三方库无论它是否密封都可以强制的对其函数进行控制反转呢?~答案是可行的。
那么它到底是采取何种方式呢?即内链hook,在函数头的部分修改其的汇编代码,植入一个跳板的方式实现,对于.NET Hook相关的可以参考 http://blog.csdn.net/liulilittle/article/details/56280052 内的内容。
.NET/CLR编译的函数的调用协议为__fastcall而且它与一般的VC++编译的二进制代码结构是不同的,即.NET/CLR编译的函数是严格按照32bit元相对布局编译的,简单的说法就是x86与x64平台编译的二进制代码的VA与RVA范围不超过0xFFFFFFFF;实际它比这个范围更小;而且.NET/CLR对函数头会做一些相关的测量,如果你置入的汇编代码不符合要求的话则会引发JIT执行引擎故障;那么我们先写几种在x64上可以实现跳板的指令;推测JITEngine是否会出现故障
push rax, hook函数
jmp rax
上述代码在x64平台被用于作为hook的跳板函数是最多的,即便是.NET理论上应该是可行的,但事实情况下它不可行,或许从
我们的角度上看直接jmp到hook函数的头开始执行是没有问题的,但CLR并不允许类似的调用 而且它具备一些缺点,它需要借
助于rax寄存器;而一般这个寄存器主要被用于寄存加减乘除的结果或者寄存一些变量的值,如果处理不当那么则会造成程序出现
错误;那么RSI、RDI呢?这更不可能CLR有一些特殊的数据会存入这类寄存器;RCX、RDX呢?这个看看__fastcall调用协议参数
布局方式就可以直接PASS了;
那么还剩下几类方式?CALL?不可能,那么只能是采取Jmp 但要如何进行Jmp到hook处理函数呢?这是一个问题,jmp指令
不支持64bit/RVA跳转,只支持32bit/RVA跳转;基于这种特性那么你在研究x64下对.NET托管函数进行hook时 则是一个必要的准则
因为你已经很难找到第二种方法。
上面已经提到了.NET/CLR编译的函数是严格意义按照按照32bit元相对布局编译的,那么jmp的写法则必须按照x86的格式,即
采取以下指令
jmp hook函数的RVA
最主要的一个特性在于x64与x86平台的指令格式对于CPU而言是兼容的;即你可以在x64平台使用x86平台的汇编指令;并不是说
x64平台无法兼容x86平台,否则32bit应用还怎么在64bit处理器上跑。
本人封装了一个MethodSource类用于对任何托管方法进行hook,下方代码展示如何使用MethodSource对托管Add函数进行调
用反转
static MethodSource s = MethodSource.From(typeof(ServoApplication).GetMethod("Add", BindingFlags.NonPublic | BindingFlags.Static));
static int Add(int x, int y)
{
return x + y;
}
static int Hook_Add(int x, int y)
{
s.Suspend();
int value = Add(x, y);
s.Resume();
Console.WriteLine("x={0},y={1}", x, y);
return value;
}
static void Test()
{
s.AddHook(typeof(ServoApplication).GetMethod("Hook_Add", BindingFlags.NonPublic | BindingFlags.Static));
Console.WriteLine(Add(1, 2));
}
MethodSource code: https://pan.baidu.com/s/1o8dztNk

1025

被折叠的 条评论
为什么被折叠?



