我在这里下载了“RemoteFileMonitor”项目:
https://github.com/EasyHook/EasyHook-Tutorials/tree/master/Managed/RemoteFileMonitor
此项目生成由输入进程 ID 打开的所有文件的控制台日志。
应用程序运行没有问题,但日志显示意外结果。
我已经用不同的过程(包括记事本)对其进行了测试,结果如下:
简而言之,如果您多次打开某个文件,则日志仅第一次显示它,并且仅针对不同文件显示更多结果。
我需要它来实时监控外部进程的文件访问,但该进程经常尝试打开某个文件,并且对我来说日志中的这些信息很重要。
这里是原始源代码的主要部分:
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
}
}
我一般没有钩子经验,有人可以告诉我,如果可以解决这个问题吗?