1

EasyHook ライブラリを使用して目的のプロセスにコードを挿入し、特定の dll からの呼び出しをインターセプトするアプリケーションを開発しています。私の場合、ライブラリは Oracle Call Interface、OCI.dll です。クライアント側で SQL クエリ ログを作成するために、実行された SQL ステートメントをインターセプトしたいと考えています。以前は Microsoft detours (バージョン 2.1) を使用していましたが、ライセンス上商用利用が許可されておらず、バージョン 3.0 は高額です。EasyHook ライブラリを使い始めました。配布された例のコードを変更して、kernel32.dll から関数 CreateFileW をインターセプトし、oci.dll の関数 OCIStmtFetch2 で動作するように調整しました。

ヘッダー ファイルまたは oci ライブラリを持っているので、関数のパラメーターと戻り値の型を正確に知っています。ヘッダーファイルによると、署名は次のとおりです。

剣 OCIStmtFetch2 ( OCIStmt *stmtp, OCIError *errhp, ub4 nrows, ub2 向き, ub4 scrollOffset, ub4 モード);

Oracle から提供された他のヘッダー ファイルによると、OCIStmt は構造体であり、OCIError はエラー関数のハンドルです。ub2 と ub4 は、unsigned short (16 ビット) と unsigned int (32 ビット) の typedef です。Sword は、signed int (同じく 32 ビット) への typedef です。

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 に、sword を Int32 にマッピングしました。最初はポインター (最初の 2 つのパラメーター) に IntPtr を使用しましたが、コードが正しく動作しませんでした。挿入された dll インターセプト関数呼び出しは完全に、元の関数の前にコードを実行でき、元の関数を呼び出すことができ、期待値を返しますが、return E が実行されると、ターゲット アプリケーションでメモリ違反例外が発生して終了します。コードでわかるように、void* ポインターと unsafe キーワードを使用して、C# でポインターを操作できるようにしましたが、結果は同じでした。Detours ライブラリを使用したコードと比較すると、デバッガーを使用して確認できるパラメーターとポインター値は両方のライブラリーで同じであるため、型マッピングは適切に見えます。それにもかかわらず、DOCIStmtFetch2_Hooked から戻るとコードが壊れます。

誰が何が間違っているのか知っていますか? タイプマッピングは問題ないと思いますが、エラーのせいにしています。

よろしく。


ソースを短くするためにロック部分を外しました。キューをロックするかどうかに関係なく、問題は残ります

4

2 に答える 2

1

Oracle(oci.dll) は「Cdecl」呼び出し規約を使用し、StdCall を使用します。「CallingConvention = CallingConvention.Cdecl」に変更してみてください

于 2013-06-27T02:54:15.300 に答える
0

フックで This.Queue をロックするのを忘れましたが、これを修正しても問題が解決するかどうかはわかりません。

于 2011-05-19T21:58:32.113 に答える