具有原始函数调用的 EasyHook

本文关键字:EasyHook 函数调用 原始 | 更新日期: 2023-09-27 17:57:20

我正在开发一个应用程序,它使用 EasyHook 库将代码注入所需的进程并拦截来自特定 dll 的调用。就我而言该库是 Oracle Call Interface,OCI.dll。我想拦截已执行的 sql 语句,以便在客户端创建 sql 查询日志。以前我用Microsoft弯路(2.1版),但它的许可证不允许商业用途,3.0版成本很高。我开始使用EasyHook库。我更改了从 kernel32 拦截函数 CreateFileW 的交付示例中的代码.dll并将其调整为与 oci.dll 中的函数 OCIStmtFetch2 一起使用。

我有头文件或 oci 库,因为我确切地知道函数参数和返回类型。根据头文件,签名为:

sword OCIStmtFetch2 ( OCIStmt *stmtp, OCIError *errhp, UB4 nrows, UB2取向, ub4 滚动偏移量, UB4 模式);

根据 Oracle 提供的其他头文件,OCIStmt 是一个结构体,OCIError 是错误函数的句柄。 ub2 和 ub4 是无符号短(16 位)和无符号 int(32 位)的类型定义。Sword 是 typedef to signed int(也是 32 位)我的 Injection by 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拦截函数调用完美,我可以在原始函数之前运行我的代码,我可以调用原始函数并且它返回预期值,但是当返回E时执行目标应用程序会导致内存违例异常并退出。正如您在代码中看到的那样,然后我尝试使用 void* 指针和 unsafe 关键字来启用 C# 中的指针,结果相同。与使用 Detours 库的代码相比,我可以使用调试器检查的参数和指针值对于两个库是相同的,因此类型映射看起来不错。然而,当我从DOCIStmtFetch2_Hooked回来时,代码会中断。

有谁知道可能出了什么问题?即使我认为类型映射是可以的,我也会将错误归咎于它们。

问候。


我删除了锁定部分以缩短源。无论我是否锁定队列,问题仍然存在

具有原始函数调用的 EasyHook

Oracle(oci.dll)使用"Cdecl"调用约定,您使用StdCall。尝试更改为"调用约定 = 调用约定.Cdecl"

你忘了在你的钩子中锁定这个队列,但我不确定解决这个问题是否能解决你的问题。