/** * Allocates a text table. * * \param Table A variable which receives a pointer to the text table. * \param Rows The number of rows in the table. * \param Columns The number of columns in the table. */ VOID PhaCreateTextTable( __out PPH_STRING ***Table, __in ULONG Rows, __in ULONG Columns ) { PPH_STRING **table; ULONG i; PhCreateAlloc((PVOID *)&table, sizeof(PPH_STRING *) * Rows); PhaDereferenceObject(table); for (i = 0; i < Rows; i++) { PhCreateAlloc((PVOID *)&table[i], sizeof(PPH_STRING) * Columns); PhaDereferenceObject(table[i]); memset(table[i], 0, sizeof(PPH_STRING) * Columns); } *Table = table; }
/** * Formats a text table to a list of lines. * * \param Table A pointer to the text table. * \param Rows The number of rows in the table. * \param Columns The number of columns in the table. * \param Mode The export formatting mode. * * \return A list of strings for each line in the output. The list object and * string objects are not auto-dereferenced. */ PPH_LIST PhaFormatTextTable( __in PPH_STRING **Table, __in ULONG Rows, __in ULONG Columns, __in ULONG Mode ) { PPH_LIST lines; // The tab count array contains the number of tabs need to fill the biggest // row cell in each column. PULONG tabCount; ULONG i; ULONG j; if (Mode == PH_EXPORT_MODE_TABS || Mode == PH_EXPORT_MODE_SPACES) { // Create the tab count array. PhCreateAlloc(&tabCount, sizeof(ULONG) * Columns); PhaDereferenceObject(tabCount); memset(tabCount, 0, sizeof(ULONG) * Columns); // zero all values for (i = 0; i < Rows; i++) { for (j = 0; j < Columns; j++) { ULONG newCount; if (Table[i][j]) newCount = (ULONG)(Table[i][j]->Length / sizeof(WCHAR) / TAB_SIZE); else newCount = 0; // Replace the existing count if this tab count is bigger. if (tabCount[j] < newCount) tabCount[j] = newCount; } } } // Create the final list of lines by going through each cell and appending // the proper tab count (if we are using tabs). This will make sure each column // is properly aligned. lines = PhCreateList(Rows); for (i = 0; i < Rows; i++) { PH_STRING_BUILDER stringBuilder; PhInitializeStringBuilder(&stringBuilder, 100); switch (Mode) { case PH_EXPORT_MODE_TABS: { for (j = 0; j < Columns; j++) { ULONG k; if (Table[i][j]) { // Calculate the number of tabs needed. k = (ULONG)(tabCount[j] + 1 - Table[i][j]->Length / sizeof(WCHAR) / TAB_SIZE); PhAppendStringBuilder(&stringBuilder, Table[i][j]); } else { k = tabCount[j] + 1; } PhAppendCharStringBuilder2(&stringBuilder, '\t', k); } } break; case PH_EXPORT_MODE_SPACES: { for (j = 0; j < Columns; j++) { ULONG k; if (Table[i][j]) { // Calculate the number of spaces needed. k = (ULONG)((tabCount[j] + 1) * TAB_SIZE - Table[i][j]->Length / sizeof(WCHAR)); PhAppendStringBuilder(&stringBuilder, Table[i][j]); } else { k = (tabCount[j] + 1) * TAB_SIZE; } PhAppendCharStringBuilder2(&stringBuilder, ' ', k); } } break; case PH_EXPORT_MODE_CSV: { for (j = 0; j < Columns; j++) { PhAppendCharStringBuilder(&stringBuilder, '\"'); if (Table[i][j]) { PhpEscapeStringForCsv(&stringBuilder, Table[i][j]); } PhAppendCharStringBuilder(&stringBuilder, '\"'); if (j != Columns - 1) PhAppendCharStringBuilder(&stringBuilder, ','); } } break; } PhAddItemList(lines, PhFinalStringBuilderString(&stringBuilder)); } return lines; }
BOOLEAN PhaGetProcessKnownCommandLine( __in PPH_STRING CommandLine, __in PH_KNOWN_PROCESS_TYPE KnownProcessType, __out PPH_KNOWN_PROCESS_COMMAND_LINE KnownCommandLine ) { switch (KnownProcessType & KnownProcessTypeMask) { case ServiceHostProcessType: { // svchost.exe -k <GroupName> static PH_COMMAND_LINE_OPTION options[] = { { 1, L"k", MandatoryArgumentType } }; KnownCommandLine->ServiceHost.GroupName = NULL; PhParseCommandLine( &CommandLine->sr, options, sizeof(options) / sizeof(PH_COMMAND_LINE_OPTION), PH_COMMAND_LINE_IGNORE_UNKNOWN_OPTIONS, PhpSvchostCommandLineCallback, KnownCommandLine ); if (KnownCommandLine->ServiceHost.GroupName) { PhaDereferenceObject(KnownCommandLine->ServiceHost.GroupName); return TRUE; } else { return FALSE; } } break; case RunDllAsAppProcessType: { // rundll32.exe <DllName>,<ProcedureName> ... SIZE_T i; ULONG_PTR lastIndexOfComma; PPH_STRING dllName; PPH_STRING procedureName; i = 0; // Get the rundll32.exe part. dllName = PhParseCommandLinePart(&CommandLine->sr, &i); if (!dllName) return FALSE; PhDereferenceObject(dllName); // Get the DLL name part. while (i < CommandLine->Length / 2 && CommandLine->Buffer[i] == ' ') i++; dllName = PhParseCommandLinePart(&CommandLine->sr, &i); if (!dllName) return FALSE; PhaDereferenceObject(dllName); // The procedure name begins after the last comma. lastIndexOfComma = PhFindLastCharInString(dllName, 0, ','); if (lastIndexOfComma == -1) return FALSE; procedureName = PhaSubstring( dllName, lastIndexOfComma + 1, dllName->Length / 2 - lastIndexOfComma - 1 ); dllName = PhaSubstring(dllName, 0, lastIndexOfComma); // If the DLL name isn't an absolute path, assume it's in system32. // TODO: Use a proper search function. if (RtlDetermineDosPathNameType_U(dllName->Buffer) == RtlPathTypeRelative) { dllName = PhaConcatStrings( 3, ((PPH_STRING)PHA_DEREFERENCE(PhGetSystemDirectory()))->Buffer, L"\\", dllName->Buffer ); } KnownCommandLine->RunDllAsApp.FileName = dllName; KnownCommandLine->RunDllAsApp.ProcedureName = procedureName; } break; case ComSurrogateProcessType: { // dllhost.exe /processid:<Guid> static PH_STRINGREF inprocServer32Name = PH_STRINGREF_INIT(L"InprocServer32"); SIZE_T i; ULONG_PTR indexOfProcessId; PPH_STRING argPart; PPH_STRING guidString; UNICODE_STRING guidStringUs; GUID guid; HANDLE clsidKeyHandle; HANDLE inprocServer32KeyHandle; PPH_STRING fileName; i = 0; // Get the dllhost.exe part. argPart = PhParseCommandLinePart(&CommandLine->sr, &i); if (!argPart) return FALSE; PhDereferenceObject(argPart); // Get the argument part. while (i < (ULONG)CommandLine->Length / 2 && CommandLine->Buffer[i] == ' ') i++; argPart = PhParseCommandLinePart(&CommandLine->sr, &i); if (!argPart) return FALSE; PhaDereferenceObject(argPart); // Find "/processid:"; the GUID is just after that. PhUpperString(argPart); indexOfProcessId = PhFindStringInString(argPart, 0, L"/PROCESSID:"); if (indexOfProcessId == -1) return FALSE; guidString = PhaSubstring( argPart, indexOfProcessId + 11, (ULONG)argPart->Length / 2 - indexOfProcessId - 11 ); PhStringRefToUnicodeString(&guidString->sr, &guidStringUs); if (!NT_SUCCESS(RtlGUIDFromString( &guidStringUs, &guid ))) return FALSE; KnownCommandLine->ComSurrogate.Guid = guid; KnownCommandLine->ComSurrogate.Name = NULL; KnownCommandLine->ComSurrogate.FileName = NULL; // Lookup the GUID in the registry to determine the name and file name. if (NT_SUCCESS(PhOpenKey( &clsidKeyHandle, KEY_READ, PH_KEY_CLASSES_ROOT, &PhaConcatStrings2(L"CLSID\\", guidString->Buffer)->sr, 0 ))) { KnownCommandLine->ComSurrogate.Name = PHA_DEREFERENCE(PhQueryRegistryString(clsidKeyHandle, NULL)); if (NT_SUCCESS(PhOpenKey( &inprocServer32KeyHandle, KEY_READ, clsidKeyHandle, &inprocServer32Name, 0 ))) { KnownCommandLine->ComSurrogate.FileName = PHA_DEREFERENCE(PhQueryRegistryString(inprocServer32KeyHandle, NULL)); if (fileName = PHA_DEREFERENCE(PhExpandEnvironmentStrings( &KnownCommandLine->ComSurrogate.FileName->sr ))) { KnownCommandLine->ComSurrogate.FileName = fileName; } NtClose(inprocServer32KeyHandle); } NtClose(clsidKeyHandle); } } break; default: return FALSE; } return TRUE; }
INT_PTR CALLBACK PhpLogDlgProc( __in HWND hwndDlg, __in UINT uMsg, __in WPARAM wParam, __in LPARAM lParam ) { switch (uMsg) { case WM_INITDIALOG: { ListViewHandle = GetDlgItem(hwndDlg, IDC_LIST); PhSetListViewStyle(ListViewHandle, FALSE, TRUE); PhSetControlTheme(ListViewHandle, L"explorer"); PhAddListViewColumn(ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 140, L"Time"); PhAddListViewColumn(ListViewHandle, 1, 1, 1, LVCFMT_LEFT, 260, L"Message"); PhLoadListViewColumnsFromSetting(L"LogListViewColumns", ListViewHandle); PhInitializeLayoutManager(&WindowLayoutManager, hwndDlg); PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_LIST), NULL, PH_ANCHOR_ALL); PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_COPY), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_SAVE), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_AUTOSCROLL), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_CLEAR), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); MinimumSize.left = 0; MinimumSize.top = 0; MinimumSize.right = 290; MinimumSize.bottom = 150; MapDialogRect(hwndDlg, &MinimumSize); PhLoadWindowPlacementFromSetting(L"LogWindowPosition", L"LogWindowSize", hwndDlg); Button_SetCheck(GetDlgItem(hwndDlg, IDC_AUTOSCROLL), BST_CHECKED); PhRegisterCallback(&PhLoggedCallback, LoggedCallback, NULL, &LoggedRegistration); PhpUpdateLogList(); ListView_EnsureVisible(ListViewHandle, ListViewCount - 1, FALSE); } break; case WM_DESTROY: { PhSaveListViewColumnsToSetting(L"LogListViewColumns", ListViewHandle); PhSaveWindowPlacementToSetting(L"LogWindowPosition", L"LogWindowSize", hwndDlg); PhDeleteLayoutManager(&WindowLayoutManager); PhUnregisterCallback(&PhLoggedCallback, &LoggedRegistration); PhUnregisterDialog(PhLogWindowHandle); PhLogWindowHandle = NULL; } break; case WM_COMMAND: { switch (LOWORD(wParam)) { case IDCANCEL: case IDOK: DestroyWindow(hwndDlg); break; case IDC_CLEAR: { PhClearLogEntries(); PhpUpdateLogList(); } break; case IDC_COPY: { PPH_STRING string; ULONG selectedCount; selectedCount = ListView_GetSelectedCount(ListViewHandle); if (selectedCount == 0) { // User didn't select anything, so copy all items. string = PhpGetStringForSelectedLogEntries(TRUE); PhSetStateAllListViewItems(ListViewHandle, LVIS_SELECTED, LVIS_SELECTED); } else { string = PhpGetStringForSelectedLogEntries(FALSE); } PhSetClipboardStringEx(hwndDlg, string->Buffer, string->Length); PhDereferenceObject(string); SetFocus(ListViewHandle); } break; case IDC_SAVE: { static PH_FILETYPE_FILTER filters[] = { { L"Text files (*.txt)", L"*.txt" }, { L"All files (*.*)", L"*.*" } }; PVOID fileDialog; fileDialog = PhCreateSaveFileDialog(); PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); PhSetFileDialogFileName(fileDialog, L"Process Hacker Log.txt"); if (PhShowFileDialog(hwndDlg, fileDialog)) { NTSTATUS status; PPH_STRING fileName; PPH_FILE_STREAM fileStream; PPH_STRING string; fileName = PhGetFileDialogFileName(fileDialog); PhaDereferenceObject(fileName); if (NT_SUCCESS(status = PhCreateFileStream( &fileStream, fileName->Buffer, FILE_GENERIC_WRITE, FILE_SHARE_READ, FILE_OVERWRITE_IF, 0 ))) { PhWritePhTextHeader(fileStream); string = PhpGetStringForSelectedLogEntries(TRUE); PhWriteStringAsAnsiFileStreamEx(fileStream, string->Buffer, string->Length); PhDereferenceObject(string); PhDereferenceObject(fileStream); } if (!NT_SUCCESS(status)) PhShowStatus(hwndDlg, L"Unable to create the file", status, 0); } PhFreeFileDialog(fileDialog); } break; } } break; case WM_NOTIFY: { LPNMHDR header = (LPNMHDR)lParam; switch (header->code) { case LVN_GETDISPINFO: { NMLVDISPINFO *dispInfo = (NMLVDISPINFO *)header; PPH_LOG_ENTRY entry; entry = PhGetItemCircularBuffer_PVOID(&PhLogBuffer, ListViewCount - dispInfo->item.iItem - 1); if (dispInfo->item.iSubItem == 0) { if (dispInfo->item.mask & LVIF_TEXT) { SYSTEMTIME systemTime; PPH_STRING dateTime; PhLargeIntegerToLocalSystemTime(&systemTime, &entry->Time); dateTime = PhFormatDateTime(&systemTime); wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, dateTime->Buffer, _TRUNCATE); PhDereferenceObject(dateTime); } } else if (dispInfo->item.iSubItem == 1) { if (dispInfo->item.mask & LVIF_TEXT) { PPH_STRING string; string = PhFormatLogEntry(entry); wcsncpy_s(dispInfo->item.pszText, dispInfo->item.cchTextMax, string->Buffer, _TRUNCATE); PhDereferenceObject(string); } } } break; } } break; case WM_SIZE: { PhLayoutManagerLayout(&WindowLayoutManager); } break; case WM_SIZING: { PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom); } break; case WM_PH_LOG_UPDATED: { PhpUpdateLogList(); } break; } return FALSE; }
static INT_PTR CALLBACK PhpInformationDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ) { switch (uMsg) { case WM_INITDIALOG: { PWSTR string = (PWSTR)lParam; PPH_LAYOUT_MANAGER layoutManager; PhCenterWindow(hwndDlg, GetParent(hwndDlg)); SetDlgItemText(hwndDlg, IDC_TEXT, string); layoutManager = PhAllocate(sizeof(PH_LAYOUT_MANAGER)); PhInitializeLayoutManager(layoutManager, hwndDlg); PhAddLayoutItem(layoutManager, GetDlgItem(hwndDlg, IDC_TEXT), NULL, PH_ANCHOR_ALL); PhAddLayoutItem(layoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhAddLayoutItem(layoutManager, GetDlgItem(hwndDlg, IDC_COPY), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); PhAddLayoutItem(layoutManager, GetDlgItem(hwndDlg, IDC_SAVE), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM); if (MinimumSize.left == -1) { RECT rect; rect.left = 0; rect.top = 0; rect.right = 200; rect.bottom = 140; MapDialogRect(hwndDlg, &rect); MinimumSize = rect; MinimumSize.left = 0; } SetProp(hwndDlg, L"LayoutManager", (HANDLE)layoutManager); SetProp(hwndDlg, L"String", (HANDLE)string); } break; case WM_DESTROY: { PPH_LAYOUT_MANAGER layoutManager; layoutManager = (PPH_LAYOUT_MANAGER)GetProp(hwndDlg, L"LayoutManager"); PhDeleteLayoutManager(layoutManager); PhFree(layoutManager); RemoveProp(hwndDlg, L"String"); RemoveProp(hwndDlg, L"LayoutManager"); } break; case WM_COMMAND: { switch (LOWORD(wParam)) { case IDCANCEL: case IDOK: EndDialog(hwndDlg, IDOK); break; case IDC_COPY: { HWND editControl; LONG selStart; LONG selEnd; PWSTR buffer; PH_STRINGREF string; editControl = GetDlgItem(hwndDlg, IDC_TEXT); SendMessage(editControl, EM_GETSEL, (WPARAM)&selStart, (LPARAM)&selEnd); buffer = (PWSTR)GetProp(hwndDlg, L"String"); if (selStart == selEnd) { // Select and copy the entire string. PhInitializeStringRef(&string, buffer); Edit_SetSel(editControl, 0, -1); } else { string.Buffer = buffer + selStart; string.Length = (selEnd - selStart) * 2; } PhSetClipboardString(hwndDlg, &string); SetFocus(editControl); } break; case IDC_SAVE: { static PH_FILETYPE_FILTER filters[] = { { L"Text files (*.txt)", L"*.txt" }, { L"All files (*.*)", L"*.*" } }; PVOID fileDialog; fileDialog = PhCreateSaveFileDialog(); PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); PhSetFileDialogFileName(fileDialog, L"Information.txt"); if (PhShowFileDialog(hwndDlg, fileDialog)) { NTSTATUS status; PPH_STRING fileName; PPH_FILE_STREAM fileStream; fileName = PhGetFileDialogFileName(fileDialog); PhaDereferenceObject(fileName); if (NT_SUCCESS(status = PhCreateFileStream( &fileStream, fileName->Buffer, FILE_GENERIC_WRITE, FILE_SHARE_READ, FILE_OVERWRITE_IF, 0 ))) { PH_STRINGREF string; PhInitializeStringRef(&string, (PWSTR)GetProp(hwndDlg, L"String")); PhWriteStringAsAnsiFileStream(fileStream, &string); PhDereferenceObject(fileStream); } if (!NT_SUCCESS(status)) PhShowStatus(hwndDlg, L"Unable to create the file", status, 0); } PhFreeFileDialog(fileDialog); } break; } } break; case WM_SIZE: { PPH_LAYOUT_MANAGER layoutManager; layoutManager = (PPH_LAYOUT_MANAGER)GetProp(hwndDlg, L"LayoutManager"); PhLayoutManagerLayout(layoutManager); } break; case WM_SIZING: { PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom); } break; } return FALSE; }