// MainFrm.cpp : implementation of the CMainFrame class
//
#include "stdafx.h"
#include "HandleMon.h"
#include "sysinf.h"
#include "handletable.h"
#include "MainFrm.h"
#include "helpdlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// UnDocs
typedef enum _THREADINFOCLASS {
ThreadBasicInformation,
ThreadTimes,
ThreadPriority,
ThreadBasePriority,
ThreadAffinityMask,
ThreadImpersonationToken,
ThreadDescriptorTableEntry,
ThreadEnableAlignmentFaultFixup,
ThreadEventPair,
ThreadQuerySetWin32StartAddress,
ThreadZeroTlsCell,
ThreadPerformanceCount,
ThreadAmILastThread,
MaxThreadInfoClass
} THREADINFOCLASS;
typedef enum _PROCESSINFOCLASS {
ProcessBasicInformation,
ProcessQuotaLimits,
ProcessIoCounters,
ProcessVmCounters,
ProcessTimes,
ProcessBasePriority,
ProcessRaisePriority,
ProcessDebugPort,
ProcessExceptionPort,
ProcessAccessToken,
ProcessLdtInformation,
ProcessLdtSize,
ProcessDefaultHardErrorMode,
ProcessIoPortHandlers, // Note: this is kernel mode only
ProcessPooledUsageAndLimits,
ProcessWorkingSetWatch,
ProcessUserModeIOPL,
ProcessEnableAlignmentFaultFixup,
ProcessPriorityClass,
MaxProcessInfoClass
} PROCESSINFOCLASS;
typedef struct _PROCESS_BASIC_INFORMATION {
DWORD ExitStatus;
PVOID PebBaseAddress;
DWORD AffinityMask;
DWORD BasePriority;
DWORD UniqueProcessId;
DWORD InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION;
extern "C"
{
DWORD __stdcall NtQueryObject (HANDLE handle,
DWORD funcnum,
PVOID data,
DWORD datalen,
PVOID num_bytes_for_function);
DWORD __stdcall NtTestAlert();
DWORD __stdcall NtAlertThread (HANDLE);
DWORD __stdcall NtQueryInformationFile (HANDLE FileHandle,
PVOID IoStatusBlock,
PVOID FileInformation,
DWORD Length,
DWORD FileInformationClass);
DWORD __stdcall NtQueryInformationProcess (HANDLE ProcessHandle,
PROCESSINFOCLASS ProcessInformationClass,
PVOID ProcessInformation,
DWORD ProcessInformationLength,
DWORD *ReturnLength);
DWORD __stdcall NtQueryInformationThread (HANDLE hthread,
THREADINFOCLASS ThreadInfoClass,
PVOID ThreadInformation,
DWORD Length,
DWORD *ReturnLength);
DWORD __stdcall NtDuplicateObject (HANDLE SourceProcessHandle,
HANDLE SourceHandle,
HANDLE CurrentProcessHandle,
HANDLE *NewHandle,
DWORD Access,
BOOL InheritHandle,
DWORD Options);
}
// Uebergabe-Struct fuer FilenameFromHandle
typedef struct
{
HANDLE handle;
char *txt;
} HTT;
void WcharToAnsi (WCHAR *wc, char *chr)
{
int cnt = 0;
while (wc[cnt])
chr[cnt] = (char)wc[cnt++];
chr[cnt] = (char)0;
}
// Ermittelt die PID
void ProcessIdFromHandle (HANDLE handle, char *txt)
{
CSysinfo csi;
char temp[256];
PROCESS_BASIC_INFORMATION pbi;
ZeroMemory (&pbi, sizeof (PROCESS_BASIC_INFORMATION));
NtQueryInformationProcess (handle,
ProcessBasicInformation,
&pbi,
sizeof (PROCESS_BASIC_INFORMATION),
NULL);
csi.GetProcessName (pbi.UniqueProcessId, temp);
sprintf (txt, "PID: 0x%04x (%s)", pbi.UniqueProcessId, temp);
}
// Ermittelt die Thread ID
void ThreadIdFromHandle (HANDLE handle, char *txt)
{
CSysinfo csi;
char temp[256] = "DEAD";
DWORD pid;
DWORD buff[7] = {0,0,0,0,0,0,0};
NtQueryInformationThread (handle,
ThreadBasicInformation,
buff,
28,
NULL);
pid = csi.FindThreadProcess (buff[3]);
if (pid != 0xffffffff)
csi.GetProcessName (pid, temp);
sprintf (txt, "TID: 0x%04x (%s)", buff[3], temp);
}
// Gibt den Typ eines HANDLEs als Text aus
DWORD QueryHandleType (HANDLE handle, char *txt)
{
DWORD buff[256];
DWORD retval;
DWORD num_bytes = 0;
txt[0] = (char)0;
NtQueryObject (handle, 2, buff, 0, &num_bytes);
retval = NtQueryObject (handle, 2, buff, num_bytes, NULL);
if (!retval)
WcharToAnsi ((WCHAR*)buff[1], txt);
return retval;
}
// Gibt den Namen eines Files aus HFILE!!!
// Parametereingabe ueber struct HTT weil extra Thread
DWORD FilenameFromHandle (HTT *htt)
{
BYTE buff[512];
DWORD retval;
struct
{ DWORD v1;
DWORD v2;
} iob;
retval = NtQueryInformationFile (htt->handle, &iob, buff, 512, 9);
if (!retval)
{
DWORD cnt = ((DWORD*)buff)[0]/2;
DWORD s;
WCHAR *ustring = (WCHAR*)&buff[4];
for (s=0; s<cnt; s++)
htt->txt[s] = (char)ustring[s];
htt->txt[s] = (char)0;
}
return retval;
}
// Versucht den Namen eines NT-Objects zu ermitteln
DWORD QueryObjectName (HANDLE handle, char *txt)
{
DWORD buff[0x1000];
DWORD retval;
DWORD num_bytes = 0;
txt[0] = (char)0;
NtQueryObject (handle, 1, buff, 0, &num_bytes);
if (num_bytes)
{
retval = NtQueryObject (handle, 1, buff, num_bytes, NULL);
if (!retval && buff[1])
WcharToAnsi ((WCHAR*)buff[1], txt);
}
else
{
DWORD tid;
HANDLE hthread;
HTT htt = {handle, txt};
hthread = CreateThread (NULL, 0,
(LPTHREAD_START_ROUTINE)FilenameFromHandle,
&htt, 0, &tid);
if (WaitForSingleObject (hthread, 500) == WAIT_TIMEOUT)
{
TerminateThread (hthread, 0);
strcpy (txt, "THREAD BLOCKED... ACCESS DENIED!");
retval = 1;
}
else
{
char tmp[512] = {0,0,0,0};
retval = NtQueryObject (handle, 1, buff, 0x1000, NULL);
if (!retval && buff[1])
{
WcharToAnsi ((WCHAR*)buff[1], tmp);
if (strlen (tmp) > strlen(txt))
strcpy (txt, tmp);
}
}
CloseHandle (hthread);
}
return retval;
}
DWORD GetObjectFlags (HANDLE handle, char *flags, char *refs)
{
DWORD bytes[14];
DWORD retval;
retval = NtQueryObject (handle, 0, bytes, 56, NULL);
if (!retval)
{
sprintf (flags, "%08lx", bytes[1]);
sprintf (refs, "%d", bytes[2]-1);
}
return retval;
}
void FillThread (CMainFrame *cmf)
{
CComboBox *combo = (CComboBox*)(cmf->m_dlgbar).GetDlgItem (IDC_COMBO_PROCESS);
cmf->m_dlgbar.GetDlgItem (IDC_HANDLECOUNT)->SetWindowText ("wait...");
char txt[256];
char txt2[256];
char txt3[256];
DWORD pid;
DWORD objectaddress;
HANDLE hprocess;
HANDLE duphandle;
HANDLE remote_handle;
combo->GetLBText (combo->GetCurSel(), txt);
sscanf (txt, "%x", &pid);
CHandleTable cht(pid);
hprocess = OpenProcess (PROCESS_DUP_HANDLE, TRUE, pid);
if (!hprocess)
cmf->MessageBox ("Process cannot be opened...");
DWORD counter = 0;
cmf->m_listctrl.DeleteAllItems();
for (;;)
{
if (NtTestAlert())
break;
remote_handle = cht.GetNextHandle (&objectaddress);
if (!remote_handle)
break;
NtDuplicateObject (hprocess, remote_handle,
(HANDLE)0xffffffff, &duphandle,
0,//DUPLICATE_SAME_ACCESS, //0xfffffffe,
TRUE,
0xfffffffe);//DUPLICATE_SAME_ACCESS);
sprintf (txt, "%04x", remote_handle);
cmf->m_listctrl.InsertItem (counter, txt);
QueryHandleType (duphandle, txt2);
cmf->m_listctrl.SetItemText (counter, 1, txt2);
GetObjectFlags (duphandle, txt, txt3);
cmf->m_listctrl.SetItemText (counter, 2, txt3);
cmf->m_listctrl.SetItemText (counter, 3, txt);
sprintf (txt, "%08lx", objectaddress);
cmf->m_listctrl.SetItemText (counter, 4, txt);
if (!strcmp (txt2, "Process"))
ProcessIdFromHandle (duphandle, txt);
else if (!strcmp (txt2, "Thread"))
ThreadIdFromHandle (duphandle, txt);
else if (QueryObjectName (duphandle, txt) == 1)
cmf->m_listctrl.SetItemData (counter, 0xffffffff);
cmf->m_listctrl.SetItemText (counter, 5, txt);
CloseHandle (duphandle);
counter++;
}
sprintf (txt, "...has %d open handles.", counter);
cmf->m_dlgbar.GetDlgItem (IDC_HANDLECOUNT)->SetWindowText (txt);
CloseHandle (hprocess);
}
void StartFillThread (CMainFrame *cmf)
{
static HANDLE hthread = NULL;
DWORD tid;
if (hthread)
{
NtAlertThread (hthread);
Sleep (100);
CloseHandle (hthread);
}
hthread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)FillThread,
cmf, 0, &tid);
}
/////////////////////////////////////////////////////////////////////////////
// CMainFrame
IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
ON_WM_CREATE()
ON_WM_SIZE()
ON_BN_CLICKED(IDC_BUTTON_HELP, OnButtonHelp)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CMainFrame construction/destruction
CMainFrame::CMainFrame()
{
// TODO: add member initialization code here
}
CMainFrame::~CMainFrame()
{
}
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return CFrameWnd::PreCreateWindow(cs);
}
/////////////////////////////////////////////////////////////////////////////
// CMainFrame diagnostics
#ifdef _DEBUG
void CMainFrame::AssertValid() const
{
CFrameWnd::AssertValid();
}
void CMainFrame::Dump(CDumpContext& dc) const
{
CFrameWnd::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CMainFrame message handlers
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
m_listctrl.Create (LVS_REPORT | WS_VISIBLE | LVS_NOSORTHEADER,
CRect(0,0,300,300), this, 101);
m_dlgbar.Create (this, IDD_DIALOGBAR, CBRS_BOTTOM, 102);
char *ColTxt[] = {"Handle", "Object Type", "RefCnt", "AccessMask", "Pointer", "Name or ID"};
int widths[] = {50, 80, 50, 80, 80, 0};
LV_COLUMN lvc;
lvc.mask=LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH;
lvc.iSubItem=-1;
for (int i=0; i<6; i++)
{
lvc.pszText = ColTxt[i];
lvc.cx = widths[i];
lvc.fmt = LVCFMT_LEFT;
m_listctrl.InsertColumn (i,&lvc);
}
return 0;
}
void CMainFrame::OnSize(UINT nType, int cx, int cy)
{
CFrameWnd::OnSize(nType, cx, cy);
RECT rect_c;
m_dlgbar.GetWindowRect (&rect_c);
int y_offset = rect_c.bottom-rect_c.top;
m_listctrl.MoveWindow (0,
0,
cx,
cy-y_offset);
m_listctrl.SetColumnWidth (5, cx-340);
}
BOOL CMainFrame::OnCommand(WPARAM wParam, LPARAM lParam)
{
if (HIWORD(wParam) == CBN_DROPDOWN)
{
CSysinfo csi;
csi.FillProcessBox ((CComboBox*)m_dlgbar.GetDlgItem (IDC_COMBO_PROCESS));
}
else if (HIWORD(wParam) == CBN_SELCHANGE)
{
StartFillThread (this);
}
return CFrameWnd::OnCommand(wParam, lParam);
}
BOOL CMainFrame::OnNotify (WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
NM_LISTVIEW *hdr = (NM_LISTVIEW*)lParam;
if (hdr->hdr.code == NM_CLICK)
{
POINT pt;
GetCursorPos (&pt);
::ScreenToClient (m_listctrl.GetSafeHwnd(), &pt);
int hit = m_listctrl.HitTest (pt);
if (hit != -1)
{
if (m_listctrl.GetItemData (hit) == 0xffffffff)
MessageBox ("Cannot close Handle", "Sorry", MB_ICONSTOP);
else
{
CComboBox *combo = (CComboBox*)(m_dlgbar).GetDlgItem (IDC_COMBO_PROCESS);
CString cs1, cs2, cs3, cs_message;
cs1 = m_listctrl.GetItemText (hit, 0);
cs2 = m_listctrl.GetItemText (hit, 1);
combo->GetLBText (combo->GetCurSel(), cs3);
cs_message = "Do you want to close: " + cs1 + " (" + cs2 +
")\nof Process " + cs3;
if (MessageBox (cs_message, "Close Handle", MB_YESNO | MB_ICONQUESTION) == IDYES)
{
DWORD pid;
HANDLE h_process;
HANDLE h_victim;
HANDLE h_duplicate;
sscanf (cs3, "%x", &pid);
sscanf (cs1, "%x", &h_victim);
h_process = OpenProcess (PROCESS_DUP_HANDLE, FALSE, pid);
NtDuplicateObject (h_process, h_victim,
GetCurrentProcess(), &h_duplicate,
DUPLICATE_SAME_ACCESS,
FALSE,
DUPLICATE_CLOSE_SOURCE);
SetHandleInformation (h_duplicate, HANDLE_FLAG_PROTECT_FROM_CLOSE, 0);
CloseHandle (h_duplicate);
CloseHandle (h_process);
StartFillThread (this);
}
}
}
}
return CFrameWnd::OnNotify(wParam, lParam, pResult);
}
void CMainFrame::OnButtonHelp()
{
CHelpDlg dlg;
dlg.DoModal();
}