C# EasyHook示例项目“;RemoteFileMonitor";得到意想不到的结果
我已在此处下载了项目“RemoteFileMonitor”: 此项目生成由输入进程id打开的所有文件的控制台日志 应用程序运行时没有问题,但日志显示意外结果 我用不同的程序(包括记事本)对其进行了测试,结果如下: 简而言之,如果多次打开某个文件,则日志仅第一次显示该文件,并且仅显示不同文件的更多结果 我需要它来实时监控外部进程的文件访问,但预进程经常试图打开某个文件,因此日志中的这些信息对我来说很重要 这里是原始源代码的主要部分:C# EasyHook示例项目“;RemoteFileMonitor";得到意想不到的结果,c#,c++,hook,C#,C++,Hook,我已在此处下载了项目“RemoteFileMonitor”: 此项目生成由输入进程id打开的所有文件的控制台日志 应用程序运行时没有问题,但日志显示意外结果 我用不同的程序(包括记事本)对其进行了测试,结果如下: 简而言之,如果多次打开某个文件,则日志仅第一次显示该文件,并且仅显示不同文件的更多结果 我需要它来实时监控外部进程的文件访问,但预进程经常试图打开某个文件,因此日志中的这些信息对我来说很重要 这里是原始源代码的主要部分: namespace FileMonitorHook { pu
namespace FileMonitorHook
{
public class InjectionEntryPoint: EasyHook.IEntryPoint
{
/// <summary>
/// Reference to the server interface within FileMonitor
/// </summary>
ServerInterface _server = null;
/// <summary>
/// Message queue of all files accessed
/// </summary>
Queue<string> _messageQueue = new Queue<string>();
/// <summary>
/// EasyHook requires a constructor that matches <paramref name="context"/> and any additional parameters as provided
/// in the original call to <see cref="EasyHook.RemoteHooking.Inject(int, EasyHook.InjectionOptions, string, string, object[])"/>.
///
/// Multiple constructors can exist on the same <see cref="EasyHook.IEntryPoint"/>, providing that each one has a corresponding Run method (e.g. <see cref="Run(EasyHook.RemoteHooking.IContext, string)"/>).
/// </summary>
/// <param name="context">The RemoteHooking context</param>
/// <param name="channelName">The name of the IPC channel</param>
public InjectionEntryPoint(
EasyHook.RemoteHooking.IContext context,
string channelName)
{
// Connect to server object using provided channel name
_server = EasyHook.RemoteHooking.IpcConnectClient<ServerInterface>(channelName);
// If Ping fails then the Run method will be not be called
_server.Ping();
}
/// <summary>
/// The main entry point for our logic once injected within the target process.
/// This is where the hooks will be created, and a loop will be entered until host process exits.
/// EasyHook requires a matching Run method for the constructor
/// </summary>
/// <param name="context">The RemoteHooking context</param>
/// <param name="channelName">The name of the IPC channel</param>
public void Run(
EasyHook.RemoteHooking.IContext context,
string channelName)
{
// Injection is now complete and the server interface is connected
_server.IsInstalled(EasyHook.RemoteHooking.GetCurrentProcessId());
// Install hooks
// CreateFile https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
var createFileHook = EasyHook.LocalHook.Create(
EasyHook.LocalHook.GetProcAddress("kernel32.dll", "CreateFileW"),
new CreateFile_Delegate(CreateFile_Hook),
this);
// ReadFile https://msdn.microsoft.com/en-us/library/windows/desktop/aa365467(v=vs.85).aspx
var readFileHook = EasyHook.LocalHook.Create(
EasyHook.LocalHook.GetProcAddress("kernel32.dll", "ReadFile"),
new ReadFile_Delegate(ReadFile_Hook),
this);
// WriteFile https://msdn.microsoft.com/en-us/library/windows/desktop/aa365747(v=vs.85).aspx
var writeFileHook = EasyHook.LocalHook.Create(
EasyHook.LocalHook.GetProcAddress("kernel32.dll", "WriteFile"),
new WriteFile_Delegate(WriteFile_Hook),
this);
// Activate hooks on all threads except the current thread
createFileHook.ThreadACL.SetExclusiveACL(new Int32[] { 0 });
readFileHook.ThreadACL.SetExclusiveACL(new Int32[] { 0 });
writeFileHook.ThreadACL.SetExclusiveACL(new Int32[] { 0 });
_server.ReportMessage("CreateFile, ReadFile and WriteFile hooks installed");
// Wake up the process (required if using RemoteHooking.CreateAndInject)
EasyHook.RemoteHooking.WakeUpProcess();
try
{
// Loop until FileMonitor closes (i.e. IPC fails)
while (true)
{
System.Threading.Thread.Sleep(500);
string[] queued = null;
lock (_messageQueue)
{
queued = _messageQueue.ToArray();
_messageQueue.Clear();
}
// Send newly monitored file accesses to FileMonitor
if (queued != null && queued.Length > 0)
{
_server.ReportMessages(queued);
}
else
{
_server.Ping();
}
}
}
catch
{
// Ping() or ReportMessages() will raise an exception if host is unreachable
}
// Remove hooks
createFileHook.Dispose();
readFileHook.Dispose();
writeFileHook.Dispose();
// Finalise cleanup of hooks
EasyHook.LocalHook.Release();
}
/// <summary>
/// P/Invoke to determine the filename from a file handle
/// https://msdn.microsoft.com/en-us/library/windows/desktop/aa364962(v=vs.85).aspx
/// </summary>
/// <param name="hFile"></param>
/// <param name="lpszFilePath"></param>
/// <param name="cchFilePath"></param>
/// <param name="dwFlags"></param>
/// <returns></returns>
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint GetFinalPathNameByHandle(IntPtr hFile, [MarshalAs(UnmanagedType.LPTStr)] StringBuilder lpszFilePath, uint cchFilePath, uint dwFlags);
#region CreateFileW Hook
/// <summary>
/// The CreateFile delegate, this is needed to create a delegate of our hook function <see cref="CreateFile_Hook(string, uint, uint, IntPtr, uint, uint, IntPtr)"/>.
/// </summary>
/// <param name="filename"></param>
/// <param name="desiredAccess"></param>
/// <param name="shareMode"></param>
/// <param name="securityAttributes"></param>
/// <param name="creationDisposition"></param>
/// <param name="flagsAndAttributes"></param>
/// <param name="templateFile"></param>
/// <returns></returns>
[UnmanagedFunctionPointer(CallingConvention.StdCall,
CharSet = CharSet.Unicode,
SetLastError = true)]
delegate IntPtr CreateFile_Delegate(
String filename,
UInt32 desiredAccess,
UInt32 shareMode,
IntPtr securityAttributes,
UInt32 creationDisposition,
UInt32 flagsAndAttributes,
IntPtr templateFile);
/// <summary>
/// Using P/Invoke to call original method.
/// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
/// </summary>
/// <param name="filename"></param>
/// <param name="desiredAccess"></param>
/// <param name="shareMode"></param>
/// <param name="securityAttributes"></param>
/// <param name="creationDisposition"></param>
/// <param name="flagsAndAttributes"></param>
/// <param name="templateFile"></param>
/// <returns></returns>
[DllImport("kernel32.dll",
CharSet = CharSet.Unicode,
SetLastError = true, CallingConvention = CallingConvention.StdCall)]
static extern IntPtr CreateFileW(
String filename,
UInt32 desiredAccess,
UInt32 shareMode,
IntPtr securityAttributes,
UInt32 creationDisposition,
UInt32 flagsAndAttributes,
IntPtr templateFile);
/// <summary>
/// The CreateFile hook function. This will be called instead of the original CreateFile once hooked.
/// </summary>
/// <param name="filename"></param>
/// <param name="desiredAccess"></param>
/// <param name="shareMode"></param>
/// <param name="securityAttributes"></param>
/// <param name="creationDisposition"></param>
/// <param name="flagsAndAttributes"></param>
/// <param name="templateFile"></param>
/// <returns></returns>
IntPtr CreateFile_Hook(
String filename,
UInt32 desiredAccess,
UInt32 shareMode,
IntPtr securityAttributes,
UInt32 creationDisposition,
UInt32 flagsAndAttributes,
IntPtr templateFile)
{
try
{
lock (this._messageQueue)
{
if (this._messageQueue.Count < 1000)
{
string mode = string.Empty;
switch (creationDisposition)
{
case 1:
mode = "CREATE_NEW";
break;
case 2:
mode = "CREATE_ALWAYS";
break;
case 3:
mode = "OPEN_ALWAYS";
break;
case 4:
mode = "OPEN_EXISTING";
break;
case 5:
mode = "TRUNCATE_EXISTING";
break;
}
// Add message to send to FileMonitor
this._messageQueue.Enqueue(
string.Format("[{0}:{1}]: CREATE ({2}) \"{3}\"",
EasyHook.RemoteHooking.GetCurrentProcessId(), EasyHook.RemoteHooking.GetCurrentThreadId()
, mode, filename));
}
}
}
catch
{
// swallow exceptions so that any issues caused by this code do not crash target process
}
// now call the original API...
return CreateFileW(
filename,
desiredAccess,
shareMode,
securityAttributes,
creationDisposition,
flagsAndAttributes,
templateFile);
}
#endregion
#region ReadFile Hook
/// <summary>
/// The ReadFile delegate, this is needed to create a delegate of our hook function <see cref="ReadFile_Hook(IntPtr, IntPtr, uint, out uint, IntPtr)"/>.
/// </summary>
/// <param name="hFile"></param>
/// <param name="lpBuffer"></param>
/// <param name="nNumberOfBytesToRead"></param>
/// <param name="lpNumberOfBytesRead"></param>
/// <param name="lpOverlapped"></param>
/// <returns></returns>
[UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = true)]
delegate bool ReadFile_Delegate(
IntPtr hFile,
IntPtr lpBuffer,
uint nNumberOfBytesToRead,
out uint lpNumberOfBytesRead,
IntPtr lpOverlapped);
/// <summary>
/// Using P/Invoke to call the orginal function
/// </summary>
/// <param name="hFile"></param>
/// <param name="lpBuffer"></param>
/// <param name="nNumberOfBytesToRead"></param>
/// <param name="lpNumberOfBytesRead"></param>
/// <param name="lpOverlapped"></param>
/// <returns></returns>
[DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
static extern bool ReadFile(
IntPtr hFile,
IntPtr lpBuffer,
uint nNumberOfBytesToRead,
out uint lpNumberOfBytesRead,
IntPtr lpOverlapped);
/// <summary>
/// The ReadFile hook function. This will be called instead of the original ReadFile once hooked.
/// </summary>
/// <param name="hFile"></param>
/// <param name="lpBuffer"></param>
/// <param name="nNumberOfBytesToRead"></param>
/// <param name="lpNumberOfBytesRead"></param>
/// <param name="lpOverlapped"></param>
/// <returns></returns>
bool ReadFile_Hook(
IntPtr hFile,
IntPtr lpBuffer,
uint nNumberOfBytesToRead,
out uint lpNumberOfBytesRead,
IntPtr lpOverlapped)
{
bool result = false;
lpNumberOfBytesRead = 0;
// Call original first so we have a value for lpNumberOfBytesRead
result = ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, out lpNumberOfBytesRead, lpOverlapped);
try
{
lock (this._messageQueue)
{
if (this._messageQueue.Count < 1000)
{
// Retrieve filename from the file handle
StringBuilder filename = new StringBuilder(255);
GetFinalPathNameByHandle(hFile, filename, 255, 0);
// Add message to send to FileMonitor
this._messageQueue.Enqueue(
string.Format("[{0}:{1}]: READ ({2} bytes) \"{3}\"",
EasyHook.RemoteHooking.GetCurrentProcessId(), EasyHook.RemoteHooking.GetCurrentThreadId()
, lpNumberOfBytesRead, filename));
}
}
}
catch
{
// swallow exceptions so that any issues caused by this code do not crash target process
}
return result;
}
#endregion
#region WriteFile Hook
/// <summary>
/// The WriteFile delegate, this is needed to create a delegate of our hook function <see cref="WriteFile_Hook(IntPtr, IntPtr, uint, out uint, IntPtr)"/>.
/// </summary>
/// <param name="hFile"></param>
/// <param name="lpBuffer"></param>
/// <param name="nNumberOfBytesToWrite"></param>
/// <param name="lpNumberOfBytesWritten"></param>
/// <param name="lpOverlapped"></param>
/// <returns></returns>
[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
delegate bool WriteFile_Delegate(
IntPtr hFile,
IntPtr lpBuffer,
uint nNumberOfBytesToWrite,
out uint lpNumberOfBytesWritten,
IntPtr lpOverlapped);
/// <summary>
/// Using P/Invoke to call original WriteFile method
/// </summary>
/// <param name="hFile"></param>
/// <param name="lpBuffer"></param>
/// <param name="nNumberOfBytesToWrite"></param>
/// <param name="lpNumberOfBytesWritten"></param>
/// <param name="lpOverlapped"></param>
/// <returns></returns>
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool WriteFile(
IntPtr hFile,
IntPtr lpBuffer,
uint nNumberOfBytesToWrite,
out uint lpNumberOfBytesWritten,
IntPtr lpOverlapped);
/// <summary>
/// The WriteFile hook function. This will be called instead of the original WriteFile once hooked.
/// </summary>
/// <param name="hFile"></param>
/// <param name="lpBuffer"></param>
/// <param name="nNumberOfBytesToWrite"></param>
/// <param name="lpNumberOfBytesWritten"></param>
/// <param name="lpOverlapped"></param>
/// <returns></returns>
bool WriteFile_Hook(
IntPtr hFile,
IntPtr lpBuffer,
uint nNumberOfBytesToWrite,
out uint lpNumberOfBytesWritten,
IntPtr lpOverlapped)
{
bool result = false;
// Call original first so we get lpNumberOfBytesWritten
result = WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, out lpNumberOfBytesWritten, lpOverlapped);
try
{
lock (this._messageQueue)
{
if (this._messageQueue.Count < 1000)
{
// Retrieve filename from the file handle
StringBuilder filename = new StringBuilder(255);
GetFinalPathNameByHandle(hFile, filename, 255, 0);
// Add message to send to FileMonitor
this._messageQueue.Enqueue(
string.Format("[{0}:{1}]: WRITE ({2} bytes) \"{3}\"",
EasyHook.RemoteHooking.GetCurrentProcessId(), EasyHook.RemoteHooking.GetCurrentThreadId()
, lpNumberOfBytesWritten, filename));
}
}
}
catch
{
// swallow exceptions so that any issues caused by this code do not crash target process
}
return result;
}
#endregion
}
名称空间文件监视器挂钩
{
公共类InjectionEntryPoint:EasyHook.IEntryPoint
{
///
///对FileMonitor中服务器接口的引用
///
服务器接口_server=null;
///
///访问的所有文件的消息队列
///
队列_messageQueue=新队列();
///
///EasyHook需要一个与所提供的任何其他参数匹配的构造函数
///在最初的通话中。
///
///同一个构造函数上可以存在多个构造函数,前提是每个构造函数都有相应的Run方法(例如)。
///
///远程挂钩上下文
///IPC通道的名称
公共注射剂入口点(
EasyHook.RemoteHooking.IContext上下文,
字符串(名称)
{
//使用提供的通道名称连接到服务器对象
_server=EasyHook.RemoteHooking.IpcConnectClient(channelName);
//如果Ping失败,则不会调用Run方法
_Ping();
}
///
///我们的逻辑的主要入口点一旦被注入到目标进程中。
///在这里将创建钩子,并将进入一个循环,直到主机进程退出。
///EasyHook要求构造函数具有匹配的运行方法
///
///远程挂钩上下文
///IPC通道的名称
公开募捐(
EasyHook.RemoteHooking.IContext上下文,
字符串(名称)
{
//注入现已完成,服务器接口已连接
_已安装server.IsInstalled(EasyHook.RemoteHooking.GetCurrentProcessId());
//安装挂钩
//创建文件https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
var createFileHook=EasyHook.LocalHook.Create(
EasyHook.LocalHook.GetProcAddress(“kernel32.dll”、“CreateFileW”),
新的CreateFile_委托(CreateFile_钩子),
这),;
//读取文件https://msdn.microsoft.com/en-us/library/windows/desktop/aa365467(v=vs.85).aspx
var readFileHook=EasyHook.LocalHook.Create(
EasyHook.LocalHook.GetProcAddress(“kernel32.dll”、“ReadFile”),
新的ReadFile_委托(ReadFile_钩子),
这),;
//写文件https://msdn.microsoft.com/en-us/library/windows/desktop/aa365747(v=vs.85).aspx
var writeFileHook=EasyHook.LocalHook.Create(
EasyHook.LocalHook.GetProcAddress(“kernel32.dll”,“WriteFile”),
新的WriteFile\u委托(WriteFile\u钩子),
这),;
//激活除当前线程外的所有线程上的挂钩
createFileHook.ThreadACL.SetExclusiveACL(新的Int32[]{0});
readFileHook.ThreadACL.SetExclusiveACL(新的Int32[]{0});
writeFileHook.ThreadACL.SetExclusiveACL(新的Int32[]{0});
_ReportMessage(“已安装CreateFile、ReadFile和WriteFile挂钩”);
//唤醒进程(如果使用RemoteHooking.CreateAndInject,则需要)
EasyHook.RemoteHooking.WakeUpProcess();
尝试
{
//循环直到FileMonitor关闭(即IPC失败)
while(true)
{
系统.线程.线程.睡眠(500);
字符串[]排队=空;
锁定(_messageQueue)
{
排队=_messageQueue.ToArray();
_messageQueue.Clear();
}
//将新监视的文件访问发送到FileMonitor
if(排队!=null&&queued.Length>0)
{
_server.ReportMessages(排队);
}
其他的
{
_Ping();
}
}
}
抓住
{
//如果无法访问主机,Ping()或ReportMessages()将引发异常
}
//脱钩
createFileHook.Dispose();
readFileHook.Dispose();
writeFileHook.Dispose();
//完成吊钩的清理工作
EasyHook.LocalHook.Release();
}
///
///P/Invoke从文件句柄确定文件名
/// https://msdn.microsoft.com/en-us/library/windows/desktop/aa364962(v=vs.85).aspx
///
///
///
///
///
///
[DllImport(“Kernel32.dll”,SetLastError=true,CharSet=CharSet.Auto)]
静态外部uint GetFinalPathNameByHandle(IntPtr hFile[Marshallas(UnmanagedType.LPTStr)]StringBuilder lpszFilePath、uint cchFilePath、uint dwFlags);
#区域创建文件钩子
///
///CreateFile委托,这是创建钩子函数的委托所必需的。
///
///
///
///
///
///
///
///
///
[UnmanagedFunctionPointer(CallingConvention.StdCall,
CharSet=CharSet.Unicode,
SetLastError=true)]
委托IntPtr CreateFile_委托(
字符串文件名,
UInt32期望访问,
UInt32共享模式,
IntPtr安全属性,
UInt32创建位置,
UInt32标志和属性,
IntPtr模板文件);
///
///使用P/Invoke