2011-05-19 63 views
0

我正在開發一個應用程序,該應用程序使用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返回時代碼會中斷。

有誰知道什麼是錯的?即使我認爲這種類型映射是可以的,我怪他們的錯誤。

問候。


我刪除了鎖定部分以縮短源代碼。無論我是否鎖定隊列,問題仍然存在

回答

0

您忘記將This.Queue鎖定在您的掛鉤中,但我不確定解決此問題是否能解決您的問題。

+0

應該可能是一條評論.. – 2013-06-27 05:43:13

0

Oracle(oci.dll)使用「Cdecl」調用約定,您使用StdCall。嘗試更改爲「CallingConvention = CallingConvention.Cdecl」