我正在開發一個應用程序,該應用程序使用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