I've hooked the TerminateProcess calls to identify the process which is being terminated, but I'm getting an unexpected handle from TerminateProcess
that does not match with the real process handle that I try to intercept.
I'm using Deviare library but I think this issue could be solved just knowing how the TerminateProcess
function works and what I need to do to perform a proper handle comparison.
If I know the handle of a process which I want to identify its termination, how I could identify that handle from hProcess
param of TerminateProcess
function?
Note the part where I try to compare the handles:
If Process.GetProcessesByName("notepad").FirstOrDefault.Handle = hProcessValue Then ...
It will never be the same handles (I also tried with MainWindowHandle
and the Process ID ID
)
So, the value of hProcess
parameter is very unknown for me.
Imports Nektra.Deviare2
Public NotInheritable Class Form1
Public WithEvents SpyMgr As NktSpyMgr
Public Hook As NktHook
ReadOnly libName As String = "kernel32.dll"
ReadOnly funcName As String = "TerminateProcess"
ReadOnly hookFlags As eNktHookFlags = eNktHookFlags.flgOnlyPreCall
' Processes to attach the hook.
ReadOnly processesToAttach As IEnumerable(Of Process) =
Process.GetProcessesByName("taskmgr")
Private Sub Test() Handles MyBase.Load
If Me.processesToAttach.Count = 0 Then
MsgBox("Any process found.")
Else
Me.SpyMgr = New NktSpyMgr()
Me.SpyMgr.Initialize()
Me.Hook = SpyMgr.CreateHook(String.Format("{0}!{1}", libName, funcName), hookFlags)
Me.Hook.Hook(sync:=True)
For Each proc As Process In processesToAttach
Debug.WriteLine("Attaching to: " & proc.ProcessName)
Me.Hook.Attach(procOrId:=proc.Id, sync:=True)
Next proc
End If
End Sub
<MTAThread>
Private Sub OnTerminateProcess_Called(ByVal hook As NktHook,
ByVal proc As NktProcess,
ByVal callInfo As NktHookCallInfo) Handles SpyMgr.OnFunctionCalled
' Function params.
Dim hProcessParam As NktParam = DirectCast(callInfo.Params(0), NktParam)
Dim uExitCodeParam As NktParam = DirectCast(callInfo.Params(1), NktParam)
' Param values.
Dim hProcessValue As IntPtr = New IntPtr(CInt(hProcessParam.Value))
Dim uExitCodeValue As UInteger = CUInt(uExitCodeParam.Value)
' Debuf info.
Trace.WriteLine(String.Format("hProcess : '{0}'", hProcessValue))
Trace.WriteLine(String.Format("uExitCode: '{0}'", uExitCodeValue))
' Handle Comparison
If Process.GetProcessesByName("notepad").FirstOrDefault.Handle = hProcessValue Then
' Skip precall to avoid process termination.
If callInfo.IsPreCall Then
callInfo.Result.Value = 1
callInfo.SkipCall()
End If
End If
End Sub
End Class
I've been reading the MSDN doc of TerminateProcess.
Note the parts where it says:
The handle must have the PROCESS_TERMINATE access right
I'm not sure whether I'm missed something to compare the handles.
Also I've been reading here but I didn't take any in clear:
Hooking TerminateProcess & Getting Info From The Handle It Supplies
I also designed this Enum if it could be necessary to perform a good handle comparison:
Public Enum ProcessAccessFlags As UInteger
All = &H1F0FFF
Terminate = &H1
CreateThread = &H2
VirtualMemoryOperation = &H8
VirtualMemoryRead = &H10
VirtualMemoryWrite = &H20
DuplicateHandle = &H40
CreateProcess = &H80
SetQuota = &H100
SetInformation = &H200
QueryInformation = &H400
QueryLimitedInformation = &H1000
Synchronize = &H100000
End Enum
Your code is assuming that there is only one handle per process. This is not right. There is one process ID per process. But every time someone requests a handle for a process, for example with OpenProcess(..., ..., procid)
he gets a new process handle (which also depends on the desired access).
So you cannot compare the handles, you should check the module name or the process id.