EasyHook 与原始函数调用
我正在开发一个应用程序,它使用 EasyHook 库将代码注入所需的进程并拦截来自特定 dll 的调用。就我而言 该库是Oracle Call Interface,OCI.dll。我想拦截执行的sql语句,以便在客户端创建sql查询日志。以前我用的是微软的detours(2.1版本),但是它的许可证不允许商业使用,而且3.0版本的费用很高。 我开始使用 EasyHook 库。我更改了提供的示例中从 kernel32.dll 拦截函数 CreateFileW 的代码,并将其调整为与 oci.dll 中的函数 OCIStmtFetch2 配合使用。
我有头文件或 oci 库,我确切地知道函数参数和返回类型。根据头文件签名为:
sword OCIStmtFetch2 ( OCIStmt *stmtp, OCI错误*errhp, ub4 行, ub2方向, ub4 滚动偏移量, ub4 模式);
根据Oracle提供的其他头文件,OCIStmt是一个结构体,OCIError是错误函数的句柄。 ub2 和 ub4 是 unsigned Short(16 位)和 unsigned int(32 位)的类型定义。 Sword 的 typedef 为signed int(也是 32 位) 我的 EasyHook 库注入的代码如下所示(一些函数名称与示例 FileMonInject 相同):
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;
}
}
}
如您所见,我将 ub4 映射为 UInt32,将 ub2 映射为 UInt16,将剑映射为 Int32。第一次我使用 IntPtr 作为指针(两个第一个参数),但代码无法正常工作。注入的dll完美拦截了函数调用,我可以在原始函数之前运行我的代码,我可以调用原始函数并且它返回预期值,但是当执行return E时目标应用程序会导致内存违规异常并退出。正如您在代码中看到的,然后我尝试使用 void* 指针和 unsafe 关键字来启用 C# 中的指针,并获得相同的结果。与我使用 Detours 库的代码相比,我可以使用调试器检查的参数和指针值对于两个库都是相同的,因此类型映射看起来不错。然而,当我从 DOCIStmtFetch2_Hooked 返回时,代码会中断。
有谁知道可能出了什么问题?即使我认为类型映射没问题,我也将错误归咎于它们。
问候。
我删除了锁定部分以缩短源代码。无论我是否锁定队列,问题仍然存在
I am developing an application, that uses EasyHook library to inject code to desired process and intercept calls from a specific dll. In my case
the library is Oracle Call Interface, OCI.dll. I want to intercept executed sql statements in order to create sql queries logs on client side. Formerly I used Microsoft detours (version 2.1), but it's license does not permit commercial use and version 3.0 costs a lot.
I started to use EasyHook library. I changed code in delivered example that intercepts function CreateFileW from kernel32.dll and adjusted it to work with function OCIStmtFetch2 in oci.dll.
I have got header files or oci library, co I know exactly function parameters and return type. According to header file the signature is:
sword OCIStmtFetch2 ( OCIStmt *stmtp,
OCIError *errhp,
ub4 nrows,
ub2 orientation,
ub4 scrollOffset,
ub4 mode);
According to other header files supplied from Oracle, OCIStmt is a structure and OCIError is handle to error function. ub2 and ub4 are typedefs to unsigned short (16 bit) and unsigned int (32 bit). Sword is typedef to signed int (also 32 bit)
My code for Injected by EasyHook library is shown below (Some function names are the same as the sample FileMonInject):
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;
}
}
}
As you can see I mapped ub4 with UInt32, ub2 with UInt16, sword with Int32. At first time I uset IntPtr for the pointers (two first parameters), but code did not work properly. Injected dll intercepted function call perfectly, I can run my code before original function, I can call original function and it returns expected value, but when return E is executed target applications causes an memory violation exception and exits. As you can see in the code, then I tried to use void* pointers and unsafe keyword to enable working with pointers in C#, with the same result. In compare to my code using Detours library, parameters and pointer values that I can check using debugger are the same for both libraries, so types mapping looks good. Nevertheless code breaks when I return from my DOCIStmtFetch2_Hooked.
Does anyone know what can be wrong? Even I think that type mappings are ok I blame them for the error.
Regards.
I removed lock part in order to shorten the source. No matter whether I lock queue or not, the problem remains
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
Oracle(oci.dll) 使用“Cdecl”调用约定,您使用 StdCall。尝试更改为“CallingConvention = CallingConvention.Cdecl”
Oracle(oci.dll) uses "Cdecl" calling convention, you uses StdCall. Try change to "CallingConvention = CallingConvention.Cdecl"
您忘记将 This.Queue 锁定在挂钩中,但我不确定修复此问题是否可以解决您的问题。
You forgot to lock This.Queue in your hook, but I'm not sure if fixing this solves your problem.