EasyHook with original function call
I am developing an application, that uses EasyHook library to inject code to desired process and intercept calls from a specific dll. In my case the library is Oracle Call Interface, OCI.dll. I want to intercept executed sql statements in order to create sql queries logs on client side. Formerly I used Microsoft detours (version 2.1), but it's license does not permit commercial use and version 3.0 costs a lot. I started to use EasyHook library. I changed code in delivered example that intercepts function CreateFileW from kernel32.dll and adjusted it to work with function OCIStmtFetch2 in oci.dll.
I have got header files or oci library, co I know exactly function parameters and return type. According to header file the signature is:
sword OCIStmtFetch2 ( OCIStmt *s开发者_运维技巧tmtp, OCIError *errhp, ub4 nrows, ub2 orientation, ub4 scrollOffset, ub4 mode);
According to other header files supplied from Oracle, OCIStmt is a structure and OCIError is handle to error function. ub2 and ub4 are typedefs to unsigned short (16 bit) and unsigned int (32 bit). Sword is typedef to signed int (also 32 bit) My code for Injected by EasyHook library is shown below (Some function names are the same as the sample 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;
}
}
}
As you can see I mapped ub4 with UInt32, ub2 with UInt16, sword with Int32. At first time I uset IntPtr for the pointers (two first parameters), but code did not work properly. Injected dll intercepted function call perfectly, I can run my code before original function, I can call original function and it returns expected value, but when return E is executed target applications causes an memory violation exception and exits. As you can see in the code, then I tried to use void* pointers and unsafe keyword to enable working with pointers in C#, with the same result. In compare to my code using Detours library, parameters and pointer values that I can check using debugger are the same for both libraries, so types mapping looks good. Nevertheless code breaks when I return from my DOCIStmtFetch2_Hooked.
Does anyone know what can be wrong? Even I think that type mappings are ok I blame them for the error.
Regards.
I removed lock part in order to shorten the source. No matter whether I lock queue or not, the problem remains
Oracle(oci.dll) uses "Cdecl" calling convention, you uses StdCall. Try change to "CallingConvention = CallingConvention.Cdecl"
You forgot to lock This.Queue in your hook, but I'm not sure if fixing this solves your problem.
精彩评论