617 lines
14 KiB
C
617 lines
14 KiB
C
/*******************************************************************************
|
|
*
|
|
* (C) COPYRIGHT AUTHORS, 2015
|
|
*
|
|
* TITLE: PROPPROCESS.C
|
|
*
|
|
* VERSION: 1.00
|
|
*
|
|
* DATE: 19 Feb 2015
|
|
*
|
|
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
|
|
* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
* PARTICULAR PURPOSE.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
#include "global.h"
|
|
#include "propDlg.h"
|
|
#include "propProcess.h"
|
|
|
|
//page imagelist
|
|
HIMAGELIST ProcessImageList = NULL;
|
|
//page listview
|
|
HWND ProcessList = NULL;
|
|
//column to sort
|
|
static LONG ProcessListSortColumn = 0;
|
|
//sort direction
|
|
BOOL bProcessListSortInverse = FALSE;
|
|
|
|
/*
|
|
* ProcessListCompareFunc
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Process page listview comparer function.
|
|
*
|
|
*/
|
|
INT CALLBACK ProcessListCompareFunc(
|
|
_In_ LPARAM lParam1,
|
|
_In_ LPARAM lParam2,
|
|
_In_ LPARAM lParamSort
|
|
)
|
|
{
|
|
LPWSTR lpItem1, lpItem2;
|
|
INT nResult, k;
|
|
SIZE_T sz1, sz2;
|
|
ULONG_PTR Value1, Value2;
|
|
|
|
sz1 = 0;
|
|
lpItem1 = supGetItemText(ProcessList, (INT)lParam1, (INT)lParamSort, &sz1);
|
|
if (lpItem1 == NULL)
|
|
return 0;
|
|
|
|
sz2 = 0;
|
|
lpItem2 = supGetItemText(ProcessList, (INT)lParam2, (INT)lParamSort, &sz2);
|
|
if (lpItem2 == NULL)
|
|
return 0;
|
|
|
|
switch (lParamSort) {
|
|
case 0: //name column
|
|
|
|
if (bProcessListSortInverse)
|
|
nResult = _strcmpi(lpItem2, lpItem1);
|
|
else
|
|
nResult = _strcmpi(lpItem1, lpItem2);
|
|
|
|
break;
|
|
case 1: // id column
|
|
Value1 = strtou64(lpItem1);
|
|
Value2 = strtou64(lpItem2);
|
|
if (bProcessListSortInverse)
|
|
nResult = Value2 > Value1;
|
|
else
|
|
nResult = Value1 > Value2;
|
|
break;
|
|
|
|
//anything else is hex
|
|
default:
|
|
|
|
k = 0;
|
|
if ((sz1 > 1) && (sz2 > 1)) {
|
|
if (lpItem1[1] == L'x')
|
|
k = 2;
|
|
}
|
|
|
|
Value1 = hextou64(&lpItem1[k]);
|
|
Value2 = hextou64(&lpItem2[k]);
|
|
if (bProcessListSortInverse)
|
|
nResult = Value2 > Value1;
|
|
else
|
|
nResult = Value1 > Value2;
|
|
break;
|
|
}
|
|
|
|
HeapFree(GetProcessHeap(), 0, lpItem1);
|
|
HeapFree(GetProcessHeap(), 0, lpItem2);
|
|
return nResult;
|
|
}
|
|
|
|
|
|
/*
|
|
* ProcessListHandleNotify
|
|
*
|
|
* Purpose:
|
|
*
|
|
* WM_NOTIFY processing for Process page listview.
|
|
*
|
|
*/
|
|
VOID ProcessListHandleNotify(
|
|
LPNMLISTVIEW nhdr
|
|
)
|
|
{
|
|
LVCOLUMNW col;
|
|
INT c;
|
|
|
|
if (nhdr == NULL)
|
|
return;
|
|
|
|
if (nhdr->hdr.idFrom != ID_PROCESSLIST)
|
|
return;
|
|
|
|
switch (nhdr->hdr.code) {
|
|
|
|
case LVN_COLUMNCLICK:
|
|
bProcessListSortInverse = !bProcessListSortInverse;
|
|
ProcessListSortColumn = ((NMLISTVIEW *)nhdr)->iSubItem;
|
|
ListView_SortItemsEx(ProcessList, &ProcessListCompareFunc, ProcessListSortColumn);
|
|
|
|
RtlSecureZeroMemory(&col, sizeof(col));
|
|
col.mask = LVCF_IMAGE;
|
|
col.iImage = -1;
|
|
|
|
for (c = 0; c < 4; c++)
|
|
ListView_SetColumn(ProcessList, c, &col);
|
|
|
|
if (bProcessListSortInverse)
|
|
col.iImage = 1;
|
|
else
|
|
col.iImage = 2;
|
|
|
|
ListView_SetColumn(ProcessList, ((NMLISTVIEW *)nhdr)->iSubItem, &col);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* ProcessQueryInfo
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Extracts icon resource from given process for use in listview and determines process WOW64 status
|
|
*
|
|
*/
|
|
BOOL ProcessQueryInfo(
|
|
_In_ DWORD ProcessId,
|
|
_Out_ HICON *pProcessIcon,
|
|
_Out_ BOOL *pbIs32
|
|
)
|
|
{
|
|
BOOL bResult = FALSE, bIconFound, bWow64State;
|
|
ULONG bytesNeeded;
|
|
HANDLE hProcess;
|
|
NTSTATUS status;
|
|
PVOID Buffer;
|
|
PUNICODE_STRING dynUstr;
|
|
OBJECT_ATTRIBUTES obja;
|
|
CLIENT_ID cid;
|
|
|
|
PROCESS_EXTENDED_BASIC_INFORMATION pebi;
|
|
|
|
if ((pProcessIcon == NULL) || (pbIs32 == NULL)) {
|
|
return bResult;
|
|
}
|
|
|
|
*pProcessIcon = NULL;
|
|
*pbIs32 = FALSE;
|
|
|
|
bWow64State = FALSE;
|
|
bIconFound = FALSE;
|
|
__try {
|
|
cid.UniqueProcess = (HANDLE)ProcessId;
|
|
cid.UniqueThread = NULL;
|
|
|
|
InitializeObjectAttributes(&obja, NULL, 0, NULL, NULL);
|
|
status = NtOpenProcess(&hProcess, PROCESS_QUERY_LIMITED_INFORMATION, &obja, &cid);
|
|
if (!NT_SUCCESS(status)) {
|
|
return bResult;
|
|
}
|
|
//query process icon, first query win32 imagefilename then parse image resources
|
|
bytesNeeded = 0;
|
|
NtQueryInformationProcess(hProcess, ProcessImageFileNameWin32, NULL, 0, &bytesNeeded);
|
|
if (bytesNeeded) {
|
|
Buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bytesNeeded);
|
|
if (Buffer) {
|
|
status = NtQueryInformationProcess(hProcess, ProcessImageFileNameWin32, Buffer, bytesNeeded, &bytesNeeded);
|
|
if (NT_SUCCESS(status)) {
|
|
dynUstr = (PUNICODE_STRING)Buffer;
|
|
if (dynUstr->Buffer && dynUstr->Length) {
|
|
*pProcessIcon = supGetMainIcon(dynUstr->Buffer, 16, 16);
|
|
bIconFound = TRUE;
|
|
}
|
|
}
|
|
HeapFree(GetProcessHeap(), 0, Buffer);
|
|
}
|
|
}
|
|
|
|
//query if this is wow64 process
|
|
RtlSecureZeroMemory(&pebi, sizeof(pebi));
|
|
pebi.Size = sizeof(PROCESS_EXTENDED_BASIC_INFORMATION);
|
|
status = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pebi, sizeof(pebi), NULL);
|
|
if (NT_SUCCESS(status)) {
|
|
*pbIs32 = (pebi.IsWow64Process);
|
|
bWow64State = TRUE;
|
|
}
|
|
|
|
NtClose(hProcess);
|
|
}
|
|
__except (exceptFilter(GetExceptionCode(), GetExceptionInformation())) {
|
|
return FALSE;
|
|
}
|
|
bResult = (bIconFound && bWow64State);
|
|
return bResult;
|
|
}
|
|
|
|
/*
|
|
* ProcessListAddItem
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Adds an item to the listview.
|
|
*
|
|
*/
|
|
VOID ProcessListAddItem(
|
|
_In_ PVOID ProcessesList,
|
|
_In_ PSYSTEM_HANDLE_TABLE_ENTRY_INFO phti
|
|
)
|
|
{
|
|
BOOL bIsWow64;
|
|
INT nIndex, iImage;
|
|
LVITEMW lvitem;
|
|
HICON hIcon;
|
|
WCHAR szBuffer[MAX_PATH * 2];
|
|
|
|
if ((phti == NULL) || (ProcessesList == NULL)) {
|
|
return;
|
|
}
|
|
|
|
//default image index
|
|
iImage = 0;
|
|
|
|
//set default process name as Unknown
|
|
RtlSecureZeroMemory(&szBuffer, sizeof(szBuffer));
|
|
_strcpyW(szBuffer, T_Unknown);
|
|
|
|
if (supQueryProcessName(phti->UniqueProcessId,
|
|
ProcessesList, szBuffer, MAX_PATH)) {
|
|
|
|
//id exists, extract icon
|
|
//skip idle, system
|
|
if (phti->UniqueProcessId <= 4) {
|
|
iImage = 0;
|
|
}
|
|
else {
|
|
hIcon = NULL;
|
|
bIsWow64 = FALSE;
|
|
if (ProcessQueryInfo(phti->UniqueProcessId, &hIcon, &bIsWow64)) {
|
|
if (hIcon) {
|
|
iImage = ImageList_ReplaceIcon(ProcessImageList, -1, hIcon);
|
|
DestroyIcon(hIcon);
|
|
}
|
|
if (bIsWow64) {
|
|
_strcatW(szBuffer, L"*32");
|
|
}
|
|
} //ProcessQueryInfo
|
|
} //else
|
|
}
|
|
|
|
//Name
|
|
RtlSecureZeroMemory(&lvitem, sizeof(lvitem));
|
|
lvitem.mask = LVIF_TEXT | LVIF_IMAGE;
|
|
lvitem.iImage = iImage;
|
|
lvitem.iSubItem = 0;
|
|
lvitem.pszText = szBuffer;
|
|
lvitem.iItem = MAXINT;
|
|
nIndex = ListView_InsertItem(ProcessList, &lvitem);
|
|
|
|
//ID
|
|
RtlSecureZeroMemory(&szBuffer, sizeof(szBuffer));
|
|
ultostr(phti->UniqueProcessId, szBuffer);
|
|
lvitem.mask = LVIF_TEXT;
|
|
lvitem.iSubItem = 1;
|
|
lvitem.pszText = szBuffer;
|
|
lvitem.iItem = nIndex;
|
|
ListView_SetItem(ProcessList, &lvitem);
|
|
|
|
//Value
|
|
RtlSecureZeroMemory(&szBuffer, sizeof(szBuffer));
|
|
_strcpyW(szBuffer, L"0x");
|
|
ultohex(phti->HandleValue, _strendW(szBuffer));
|
|
lvitem.mask = LVIF_TEXT;
|
|
lvitem.iSubItem = 2;
|
|
lvitem.pszText = szBuffer;
|
|
lvitem.iItem = nIndex;
|
|
ListView_SetItem(ProcessList, &lvitem);
|
|
|
|
//GrantedAccess
|
|
RtlSecureZeroMemory(&szBuffer, sizeof(szBuffer));
|
|
_strcpyW(szBuffer, L"0x");
|
|
ultohex(phti->GrantedAccess, _strendW(szBuffer));
|
|
lvitem.mask = LVIF_TEXT;
|
|
lvitem.iSubItem = 3;
|
|
lvitem.pszText = szBuffer;
|
|
lvitem.iItem = nIndex;
|
|
ListView_SetItem(ProcessList, &lvitem);
|
|
}
|
|
|
|
/*
|
|
* ProcessListSetInfo
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Query information and fill listview.
|
|
* Called each time when page became visible.
|
|
*
|
|
*/
|
|
VOID ProcessListSetInfo(
|
|
PROP_OBJECT_INFO *Context,
|
|
_In_ HWND hwndDlg
|
|
)
|
|
{
|
|
BOOL cond = FALSE;
|
|
UCHAR ObjectTypeIndex;
|
|
ULONG i;
|
|
DWORD CurrentProcessId = GetCurrentProcessId();
|
|
ULONG_PTR ObjectAddress;
|
|
HICON hIcon;
|
|
ACCESS_MASK DesiredAccess;
|
|
PVOID ProcessesList;
|
|
HANDLE hObject, tmpb;
|
|
PSYSTEM_HANDLE_INFORMATION pHandles;
|
|
|
|
if (Context == NULL) {
|
|
return;
|
|
}
|
|
|
|
hObject = NULL;
|
|
pHandles = NULL;
|
|
ProcessesList = NULL;
|
|
ObjectAddress = 0;
|
|
ObjectTypeIndex = 0;
|
|
|
|
//empty process list images
|
|
ImageList_RemoveAll(ProcessImageList);
|
|
|
|
//empty process list
|
|
ListView_DeleteAllItems(GetDlgItem(hwndDlg, ID_PROCESSLIST));
|
|
|
|
//set default app icon
|
|
hIcon = LoadIcon(NULL, IDI_APPLICATION);
|
|
if (hIcon) {
|
|
ImageList_ReplaceIcon(ProcessImageList, -1, hIcon);
|
|
DestroyIcon(hIcon);
|
|
}
|
|
//sort images
|
|
tmpb = LoadImage(g_hInstance, MAKEINTRESOURCE(IDI_ICON_SORTUP), IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
|
|
if (tmpb) {
|
|
ImageList_ReplaceIcon(ProcessImageList, -1, tmpb);
|
|
DestroyIcon(tmpb);
|
|
}
|
|
tmpb = LoadImage(g_hInstance, MAKEINTRESOURCE(IDI_ICON_SORTDOWN), IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
|
|
if (tmpb) {
|
|
ImageList_ReplaceIcon(ProcessImageList, -1, tmpb);
|
|
DestroyIcon(tmpb);
|
|
}
|
|
|
|
//check if additional info available
|
|
if (Context->ObjectInfo.ObjectAddress != 0) {
|
|
ObjectAddress = Context->ObjectInfo.ObjectAddress;
|
|
ObjectTypeIndex = Context->ObjectInfo.ObjectHeader.TypeIndex;
|
|
}
|
|
|
|
do {
|
|
//object info not present
|
|
if (ObjectAddress == 0) {
|
|
switch (Context->TypeIndex) {
|
|
case TYPE_DIRECTORY:
|
|
DesiredAccess = DIRECTORY_QUERY;
|
|
break;
|
|
case TYPE_EVENT:
|
|
DesiredAccess = EVENT_QUERY_STATE;
|
|
break;
|
|
case TYPE_MUTANT:
|
|
DesiredAccess = MUTANT_QUERY_STATE;
|
|
break;
|
|
case TYPE_SEMAPHORE:
|
|
DesiredAccess = SEMAPHORE_QUERY_STATE;
|
|
break;
|
|
case TYPE_SECTION:
|
|
DesiredAccess = SECTION_QUERY;
|
|
break;
|
|
case TYPE_SYMLINK:
|
|
DesiredAccess = SYMBOLIC_LINK_QUERY;
|
|
break;
|
|
case TYPE_TIMER:
|
|
DesiredAccess = TIMER_QUERY_STATE;
|
|
break;
|
|
case TYPE_JOB:
|
|
DesiredAccess = JOB_OBJECT_QUERY;
|
|
break;
|
|
case TYPE_WINSTATION:
|
|
DesiredAccess = WINSTA_READATTRIBUTES;
|
|
break;
|
|
default:
|
|
DesiredAccess = MAXIMUM_ALLOWED;
|
|
break;
|
|
}
|
|
//open temporary object handle to query object address
|
|
if (!propOpenCurrentObject(Context, &hObject, DesiredAccess)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
pHandles = (PSYSTEM_HANDLE_INFORMATION)supGetSystemInfo(SystemHandleInformation);
|
|
if (pHandles == NULL) {
|
|
break;
|
|
}
|
|
|
|
ProcessesList = supGetSystemInfo(SystemProcessInformation);
|
|
if (ProcessesList == NULL) {
|
|
break;
|
|
}
|
|
|
|
//no additional info available which mean we must query object address by yourself
|
|
if (ObjectAddress == 0) {
|
|
//find our handle object by handle value
|
|
for (i = 0; i < pHandles->NumberOfHandles; i++)
|
|
if (pHandles->Handles[i].UniqueProcessId == CurrentProcessId)
|
|
if (pHandles->Handles[i].HandleValue == (USHORT)(ULONG_PTR)hObject) {
|
|
ObjectAddress = (ULONG_PTR)pHandles->Handles[i].Object;
|
|
ObjectTypeIndex = pHandles->Handles[i].ObjectTypeIndex;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//object no longer needed
|
|
if (hObject) {
|
|
NtClose(hObject);
|
|
hObject = NULL;
|
|
}
|
|
|
|
//nothing to compare
|
|
if (ObjectAddress == 0) {
|
|
break;
|
|
}
|
|
|
|
//retake snapshot
|
|
HeapFree(GetProcessHeap(), 0, pHandles);
|
|
pHandles = (PSYSTEM_HANDLE_INFORMATION)supGetSystemInfo(SystemHandleInformation);
|
|
if (pHandles == NULL) {
|
|
break;
|
|
}
|
|
|
|
//find any handles with the same object address and object type
|
|
for (i = 0; i < pHandles->NumberOfHandles; i++)
|
|
if (pHandles->Handles[i].ObjectTypeIndex == ObjectTypeIndex) {
|
|
if ((ULONG_PTR)pHandles->Handles[i].Object == ObjectAddress) {
|
|
//decode and add information to the list
|
|
ProcessListAddItem(ProcessesList, &pHandles->Handles[i]);
|
|
}
|
|
}
|
|
|
|
} while (cond);
|
|
|
|
//cleanup
|
|
if (pHandles) {
|
|
HeapFree(GetProcessHeap(), 0, pHandles);
|
|
}
|
|
if (ProcessList) {
|
|
HeapFree(GetProcessHeap(), 0, ProcessesList);
|
|
}
|
|
if (Context->TypeIndex == TYPE_WINSTATION && hObject) {
|
|
CloseWindowStation(hObject);
|
|
hObject = NULL;
|
|
}
|
|
if (hObject) {
|
|
NtClose(hObject);
|
|
}
|
|
//show/hide notification text
|
|
ShowWindow(GetDlgItem(hwndDlg, ID_PROCESSLISTNOALL), (ObjectAddress == 0) ? SW_SHOW : SW_HIDE);
|
|
}
|
|
|
|
/*
|
|
* ProcessListCreate
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Initialize listview for process list.
|
|
* Called once.
|
|
*
|
|
*/
|
|
VOID ProcessListCreate(
|
|
_In_ HWND hwndDlg
|
|
)
|
|
{
|
|
LVCOLUMNW col;
|
|
|
|
ProcessList = GetDlgItem(hwndDlg, ID_PROCESSLIST);
|
|
if (ProcessList == NULL)
|
|
return;
|
|
|
|
ProcessImageList = ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, 32, 8);
|
|
if (ProcessImageList) {
|
|
ListView_SetImageList(ProcessList, ProcessImageList, LVSIL_SMALL);
|
|
}
|
|
|
|
ListView_SetExtendedListViewStyle(ProcessList, LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_GRIDLINES | LVS_EX_LABELTIP);
|
|
|
|
RtlSecureZeroMemory(&col, sizeof(col));
|
|
col.mask = LVCF_TEXT | LVCF_SUBITEM | LVCF_FMT | LVCF_WIDTH | LVCF_ORDER | LVCF_IMAGE;
|
|
col.iSubItem = 1;
|
|
col.pszText = L"Process";
|
|
col.fmt = LVCFMT_LEFT | LVCFMT_BITMAP_ON_RIGHT;
|
|
col.iOrder = 0;
|
|
col.iImage = 2;
|
|
col.cx = 160;
|
|
ListView_InsertColumn(ProcessList, 1, &col);
|
|
|
|
col.iSubItem = 2;
|
|
col.pszText = L"ID";
|
|
col.iOrder = 1;
|
|
col.iImage = -1;
|
|
col.cx = 60;
|
|
ListView_InsertColumn(ProcessList, 2, &col);
|
|
|
|
col.iSubItem = 3;
|
|
col.pszText = L"Handle";
|
|
col.iOrder = 2;
|
|
col.iImage = -1;
|
|
col.cx = 80;
|
|
ListView_InsertColumn(ProcessList, 3, &col);
|
|
|
|
col.iSubItem = 4;
|
|
col.pszText = L"Access";
|
|
col.iOrder = 3;
|
|
col.iImage = -1;
|
|
col.cx = 80;
|
|
ListView_InsertColumn(ProcessList, 4, &col);
|
|
}
|
|
|
|
/*
|
|
* ProcessListDialogProc
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Process list page for various object types.
|
|
*
|
|
* WM_INITDIALOG - Initialize listview, set window prop with context.
|
|
* WM_NOTIFY - Handle list view notifications.
|
|
* WM_SHOWWINDOW - Collect processes info and fill list.
|
|
* WM_DESTROY - Free image list and remove window prop.
|
|
*
|
|
*/
|
|
INT_PTR CALLBACK ProcessListDialogProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
)
|
|
{
|
|
LPNMLISTVIEW nhdr;
|
|
PROPSHEETPAGE *pSheet = NULL;
|
|
PROP_OBJECT_INFO *Context = NULL;
|
|
|
|
switch (uMsg) {
|
|
|
|
case WM_SHOWWINDOW:
|
|
if (wParam) {
|
|
Context = GetProp(hwndDlg, T_PROPCONTEXT);
|
|
ProcessListSetInfo(Context, hwndDlg);
|
|
if (ProcessList) {
|
|
ListView_SortItemsEx(ProcessList, &ProcessListCompareFunc, ProcessListSortColumn);
|
|
}
|
|
return 1;
|
|
}
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
nhdr = (LPNMLISTVIEW)lParam;
|
|
ProcessListHandleNotify(nhdr);
|
|
return 1;
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
if (ProcessImageList) {
|
|
ImageList_Destroy(ProcessImageList);
|
|
}
|
|
RemoveProp(hwndDlg, T_PROPCONTEXT);
|
|
break;
|
|
|
|
case WM_INITDIALOG:
|
|
|
|
pSheet = (PROPSHEETPAGE *)lParam;
|
|
if (pSheet) {
|
|
SetProp(hwndDlg, T_PROPCONTEXT, (HANDLE)pSheet->lParam);
|
|
}
|
|
ProcessListCreate(hwndDlg);
|
|
return 1;
|
|
break;
|
|
|
|
}
|
|
return 0;
|
|
} |