我正在开发一个应用程序,该应用程序使用EasyHook库将代码注入到所需的进程并拦截来自特定dll的调用。在我的情况下,该库是Oracle Call Interface,OCI.dll。我想拦截执行的sql语句,以便在客户端创建sql查询日志。以前我使用微软弯路(版本2.1),但它的许可证不允许商业使用,版本3.0的成本很高。 我开始使用EasyHook库。我更改了交付示例中的代码,该代码从kernel32.dll中截取了函数CreateFileW,并将其调整为与Oci.dll中的函数OCIStmtFetch2一起使用。EasyHook原始函数调用
我有头文件或oci库,我知道确切的函数参数和返回类型。根据头文件中的签名是:
剑OCIStmtFetch2(OCIStmt * stmtp, OCIError * errhp, UB4 NROWS, UB2取向, UB4 scrollOffset, UB4模式);
根据Oracle提供的其他头文件,OCIStmt是一个结构,OCIError是错误函数的句柄。 ub2和ub4是unsigned short(16位)和unsigned int(32位)的typedefs。剑是的typedef符号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,带UInt16的ub2,带Int32的剑。我第一次使用IntPtr指针(两个第一个参数),但代码无法正常工作。注入dll拦截函数调用完美,我可以在原始函数之前运行我的代码,我可以调用原始函数并返回期望值,但是当返回E执行时,目标应用程序会导致内存违例异常并退出。正如你在代码中看到的那样,我尝试使用void *指针和不安全的关键字来启用C#中的指针,结果相同。与使用Detours库的代码相比,使用调试器可以检查的参数和指针值对于两个库都是相同的,因此类型映射看起来不错。不过,当我从我的DOCIStmtFetch2_Hooked返回时代码会中断。
有谁知道什么是错的?即使我认为这种类型映射是可以的,我怪他们的错误。
问候。
我删除了锁定部分以缩短源代码。无论我是否锁定队列,问题仍然存在
应该可能是一条评论.. – 2013-06-27 05:43:13