C# 具有原始函数调用的EasyHook
我正在开发一个应用程序,它使用EasyHook库向所需进程注入代码,并截获来自特定dll的调用。就我而言 该库是Oracle调用接口OCI.dll。我想截取已执行的sql语句,以便在客户端创建sql查询日志。以前我使用的是微软的detours(2.1版),但它的许可证不允许商业使用,3.0版的成本很高。 我开始使用EasyHook图书馆。我在交付的示例中更改了从kernel32.dll截取函数CreateFileW的代码,并将其调整为与oci.dll中的函数OCIStmtFetch2一起使用 我有头文件或oci库,我知道确切的函数参数和返回类型。根据头文件,签名为: 剑OCISMTFETCH2(OCISMT*stmtp, 错误*errhp, ub4 nrows, ub2方向, ub4滚动偏移, ub4模式) 根据Oracle提供的其他头文件,OCISMT是一种结构,OCIRROR是handle to error函数。ub2和ub4是无符号短(16位)和无符号整数(32位)的类型定义。剑的类型定义为有符号整数(也是32位) 我的EasyHook库注入代码如下所示(一些函数名与示例FileMonInject相同):C# 具有原始函数调用的EasyHook,c#,c++,hook,detours,easyhook,C#,C++,Hook,Detours,Easyhook,我正在开发一个应用程序,它使用EasyHook库向所需进程注入代码,并截获来自特定dll的调用。就我而言 该库是Oracle调用接口OCI.dll。我想截取已执行的sql语句,以便在客户端创建sql查询日志。以前我使用的是微软的detours(2.1版),但它的许可证不允许商业使用,3.0版的成本很高。 我开始使用EasyHook图书馆。我在交付的示例中更改了从kernel32.dll截取函数CreateFileW的代码,并将其调整为与oci.dll中的函数OCIStmtFetch2一起使用 我
使用系统;
使用System.Collections.Generic;
使用系统线程;
使用System.Runtime.InteropServices;
使用简易工具;
命名空间FileMonInject
{
公共类Main:EasyHook.IEntryPoint
{
FileMon.FileMonInterface接口;
LocalHook-CreateFileHook;
堆栈队列=新堆栈();
公用干管(
RemoteHooking.IContext InContext,
字符串(名称)
{
//连接到主机。。。
接口=RemoteHooking.IpcConnectClient(InChannelName);
接口Ping();
}
不安全的公共无效运行(
RemoteHooking.IContext InContext,
字符串(名称)
{
//安装挂钩。。。
尝试
{
CreateFileHook=LocalHook.Create(
LocalHook.GetProcAddress(“oci.dll”、“ocistftfetch2”),
新的DOCIStmtFetch2(DOCIStmtFetch2_钩住),
这),;
CreateFileHook.ThreadACL.SetExclusiveACL(新的Int32[]{0});
}
捕获(例外情况)
{
接口.ReportException(exterfo);
返回;
}
已安装接口(RemoteHooking.GetCurrentProcessId());
RemoteHooking.WakeUpProcess();
//等待主机进程终止。。。
尝试
{
while(true)
{
睡眠(500);
//传输新监视的文件访问。。。
如果(Queue.Count>0)
{
String[]Package=null;
锁(队列)
{
Package=Queue.ToArray();
Queue.Clear();
}
OnOCIStmtFetch2(RemoteHooking.GetCurrentProcessId(),包);
}
其他的
接口Ping();
}
}
抓住
{
}
}
[UnmanagedFunctionPointer(CallingConvention.StdCall,
CharSet=CharSet.Ansi,
SetLastError=true)]
不安全的委托int DOCIStmtFetch2(
void*stmtp,
无效*errhp,
UInt32 nrows,
UInt16方向,
UInt32卷轴,
UInt32模式);
/只需使用p-调用实现从C ^获得本地API访问(此步骤对于C++ .NET来说不是必需的)
[DllImport(“oci.dll”,CharSet=CharSet.Ansi,SetLastError=true,CallingConvention=CallingConvention.StdCall)]
//[返回:Marshallas(UnmanagedType.I4)]
不安全的静态外部程序Int32 OCISMTFETCH2(
void*stmtp,
无效*errhp,
UInt32 nrows,
UInt16方向,
UInt32卷轴,
UInt32模式);
//这就是我们拦截所有文件访问的地方!
不安全的静态Int32 DOCIStmtFetch2_已挂起(
void*stmtp,
无效*errhp,
UInt32 nrows,
UInt16方向,
UInt32卷轴,
UInt32模式)
{
尝试
{
Main This=(Main)HookRuntimeInfo.Callback;
This.Queue.Push(“[”+RemoteHooking.GetCurrentProcessId()+”:”+
RemoteHooking.GetCurrentThreadId()+“]:\”+nrows+“\”);
}
捕获(异常ee)
{
}
//调用原始API。。。
int E=OCISSTFTFETCH2(
stmtp,
呃,,
nrows,
方向,
纸卷
模式);
返回E;
}
}
}
正如你所看到的,我用UInt32映射了ub4,用UInt16映射了ub2,用Int32映射了剑。第一次我对指针使用IntPtr(两个第一个参数),但代码没有正常工作。注入dll截获函数调用非常完美,我可以在原始函数之前运行代码,我可以调用原始函数并返回预期值,但当执行返回E时,目标应用程序会导致内存冲突异常并退出。正如您在代码中看到的,然后我尝试使用void*指针和unsafe关键字来启用C#中的指针,得到了相同的结果。与使用Detours库的代码相比,我可以使用调试器检查的参数和指针值对于这两种情况都是相同的
using System;
using System.Collections.Generic;
using System.Threading;
using System.Runtime.InteropServices;
using EasyHook;
namespace FileMonInject
{
public class Main : EasyHook.IEntryPoint
{
FileMon.FileMonInterface Interface;
LocalHook CreateFileHook;
Stack<String> Queue = new Stack<String>();
public Main(
RemoteHooking.IContext InContext,
String InChannelName)
{
// connect to host...
Interface = RemoteHooking.IpcConnectClient<FileMon.FileMonInterface>(InChannelName);
Interface.Ping();
}
unsafe public void Run(
RemoteHooking.IContext InContext,
String InChannelName)
{
// install hook...
try
{
CreateFileHook = LocalHook.Create(
LocalHook.GetProcAddress("oci.dll", "OCIStmtFetch2"),
new DOCIStmtFetch2(DOCIStmtFetch2_Hooked),
this);
CreateFileHook.ThreadACL.SetExclusiveACL(new Int32[] { 0 });
}
catch (Exception ExtInfo)
{
Interface.ReportException(ExtInfo);
return;
}
Interface.IsInstalled(RemoteHooking.GetCurrentProcessId());
RemoteHooking.WakeUpProcess();
// wait for host process termination...
try
{
while (true)
{
Thread.Sleep(500);
// transmit newly monitored file accesses...
if (Queue.Count > 0)
{
String[] Package = null;
lock (Queue)
{
Package = Queue.ToArray();
Queue.Clear();
}
Interface.OnOCIStmtFetch2(RemoteHooking.GetCurrentProcessId(), Package);
}
else
Interface.Ping();
}
}
catch
{
}
}
[UnmanagedFunctionPointer(CallingConvention.StdCall,
CharSet = CharSet.Ansi,
SetLastError = true)]
unsafe delegate int DOCIStmtFetch2(
void* stmtp,
void* errhp,
UInt32 nrows,
UInt16 orientation,
UInt32 scroll,
UInt32 mode);
// just use a P-Invoke implementation to get native API access from C# (this step is not necessary for C++.NET)
[DllImport("oci.dll", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
// [return: MarshalAs(UnmanagedType.I4)]
unsafe static extern Int32 OCIStmtFetch2(
void* stmtp,
void* errhp,
UInt32 nrows,
UInt16 orientation,
UInt32 scroll,
UInt32 mode);
// this is where we are intercepting all file accesses!
unsafe static Int32 DOCIStmtFetch2_Hooked(
void* stmtp,
void* errhp,
UInt32 nrows,
UInt16 orientation,
UInt32 scroll,
UInt32 mode)
{
try
{
Main This = (Main)HookRuntimeInfo.Callback;
This.Queue.Push("[" + RemoteHooking.GetCurrentProcessId() + ":" +
RemoteHooking.GetCurrentThreadId() + "]: \"" + nrows + "\"");
}
catch (Exception ee)
{
}
// call original API...
int E = OCIStmtFetch2(
stmtp,
errhp,
nrows,
orientation,
scroll,
mode);
return E;
}
}
}