EasyHook с оригинальным вызовом функции

#c# #c #hook #detours #easyhook

#c# #c #перехват #обходные пути #easyhook

Вопрос:

Я разрабатываю приложение, которое использует библиотеку EasyHook для внедрения кода в нужный процесс и перехвата вызовов из определенной библиотеки dll. В моем случае библиотека представляет собой интерфейс вызова Oracle, OCI.dll . Я хочу перехватывать выполняемые инструкции sql, чтобы создавать журналы запросов sql на стороне клиента. Раньше я использовал Microsoft detours (версия 2.1), но его лицензия не разрешает коммерческое использование, а версия 3.0 стоит дорого. Я начал использовать библиотеку EasyHook. Я изменил код в поставленном примере, который перехватывает функцию CreateFileW из kernel32.dll и настроил его для работы с функцией OCIStmtFetch2 в oci.dll .

У меня есть заголовочные файлы или библиотека oci, поэтому я точно знаю параметры функции и возвращаемый тип. В соответствии с заголовочным файлом подпись:

sword OCIStmtFetch2 (OCIStmt * stmtp, OCIError * errhp, ub4 nrows, ub2 ориентация, ub4 scrollOffset, режим ub4);

Согласно другим заголовочным файлам, предоставленным Oracle, OCIStmt — это структура, а OCIError — это дескриптор функции ошибки. ub2 и ub4 являются определениями типов для unsigned short (16 бит) и unsigned int (32 бита). Sword имеет значение typedef для signed 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, ub2 с UInt16, sword с Int32. В первый раз я использовал IntPtr для указателей (два первых параметра), но код не работал должным образом. Внедренная dll отлично перехватила вызов функции, я могу запустить свой код перед исходной функцией, я могу вызвать исходную функцию, и она возвращает ожидаемое значение, но когда выполняется возврат E, целевые приложения вызывают исключение нарушения памяти и завершают работу. Как вы можете видеть в коде, затем я попытался использовать указатели void * и ключевое слово unsafe, чтобы включить работу с указателями в C #, с тем же результатом. По сравнению с моим кодом, использующим библиотеку Detours, параметры и значения указателей, которые я могу проверить с помощью debugger, одинаковы для обеих библиотек, поэтому сопоставление типов выглядит хорошо. Тем не менее, код прерывается, когда я возвращаюсь из моего DOCIStmtFetch2_Hooked.

Кто-нибудь знает, что может быть не так? Даже я думаю, что сопоставления типов в порядке, я обвиняю их в ошибке.

С уважением.


Я удалил часть блокировки, чтобы сократить исходный код. Независимо от того, блокирую я очередь или нет, проблема остается

Ответ №1:

Оракул(oci.dll ) использует соглашение о вызовах «Cdecl», вы используете StdCall. Попробуйте изменить на «CallingConvention = CallingConvention.Cdecl»

Ответ №2:

Вы забыли заблокировать This.Queue в вашем перехватчике, но я не уверен, решит ли это вашу проблему.