2011-05-19 106 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”