add plugins-extra
This commit is contained in:
495
plugins-extra/DbgViewPlugin/log.c
Normal file
495
plugins-extra/DbgViewPlugin/log.c
Normal file
@@ -0,0 +1,495 @@
|
||||
/*
|
||||
* Process Hacker Extra Plugins -
|
||||
* Debug View Plugin
|
||||
*
|
||||
* Copyright (C) 2015 dmex
|
||||
*
|
||||
* This file is part of Process Hacker.
|
||||
*
|
||||
* Process Hacker is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Process Hacker is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
|
||||
PH_CALLBACK_DECLARE(DbgLoggedCallback);
|
||||
|
||||
VOID DbgFreeLogEntry(
|
||||
_Inout_ PDEBUG_LOG_ENTRY Entry
|
||||
)
|
||||
{
|
||||
PhClearReference(&Entry->FilePath);
|
||||
PhClearReference(&Entry->ProcessName);
|
||||
PhClearReference(&Entry->Message);
|
||||
|
||||
PhFree(Entry);
|
||||
}
|
||||
|
||||
VOID DbgAddLogEntry(
|
||||
_Inout_ PPH_DBGEVENTS_CONTEXT Context,
|
||||
_In_ PDEBUG_LOG_ENTRY Entry
|
||||
)
|
||||
{
|
||||
if (Context->LogMessageList->Count > PhGetIntegerSetting(SETTING_NAME_MAX_ENTRIES))
|
||||
{
|
||||
DbgFreeLogEntry(Context->LogMessageList->Items[0]);
|
||||
PhRemoveItemList(Context->LogMessageList, 0);
|
||||
}
|
||||
|
||||
PhAddItemList(Context->LogMessageList, Entry);
|
||||
PhInvokeCallback(&DbgLoggedCallback, Entry);
|
||||
}
|
||||
|
||||
VOID DbgClearLogEntries(
|
||||
_Inout_ PPH_DBGEVENTS_CONTEXT Context
|
||||
)
|
||||
{
|
||||
for (ULONG i = 0; i < Context->LogMessageList->Count; i++)
|
||||
{
|
||||
if (Context->LogMessageList->Items[i])
|
||||
{
|
||||
DbgFreeLogEntry(Context->LogMessageList->Items[i]);
|
||||
}
|
||||
}
|
||||
|
||||
PhClearList(Context->LogMessageList);
|
||||
}
|
||||
|
||||
VOID DbgShowErrorMessage(
|
||||
_Inout_ PPH_DBGEVENTS_CONTEXT Context,
|
||||
_In_ PWSTR Type
|
||||
)
|
||||
{
|
||||
ULONG errorCode = GetLastError();
|
||||
PPH_STRING errorMessage = PhGetWin32Message(errorCode);
|
||||
|
||||
if (errorMessage)
|
||||
{
|
||||
PhShowError(Context->DialogHandle, PhaFormatString(L"%s: [%u] %s", Type, errorCode, errorMessage->Buffer)->Buffer);
|
||||
PhDereferenceObject(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
VOID DbgFormatObjectName(
|
||||
_In_ BOOLEAN LocalName,
|
||||
_In_ PWSTR OriginalName,
|
||||
_Out_ PUNICODE_STRING ObjectName
|
||||
)
|
||||
{
|
||||
SIZE_T length;
|
||||
SIZE_T originalNameLength;
|
||||
|
||||
// Sessions other than session 0 require SeCreateGlobalPrivilege.
|
||||
if (LocalName && NtCurrentPeb()->SessionId != 0)
|
||||
{
|
||||
WCHAR buffer[256] = L"";
|
||||
|
||||
memcpy(buffer, L"\\Sessions\\", 10 * sizeof(WCHAR));
|
||||
_ultow(NtCurrentPeb()->SessionId, buffer + 10, 10);
|
||||
length = PhCountStringZ(buffer);
|
||||
originalNameLength = PhCountStringZ(OriginalName);
|
||||
memcpy(buffer + length, OriginalName, (originalNameLength + 1) * sizeof(WCHAR));
|
||||
length += originalNameLength;
|
||||
|
||||
ObjectName->Buffer = buffer;
|
||||
ObjectName->MaximumLength = (ObjectName->Length = (USHORT)(length * sizeof(WCHAR))) + sizeof(WCHAR);
|
||||
}
|
||||
else
|
||||
{
|
||||
RtlInitUnicodeString(ObjectName, OriginalName);
|
||||
}
|
||||
}
|
||||
|
||||
VOID DbgProcessLogMessageEntry(
|
||||
_Inout_ PPH_DBGEVENTS_CONTEXT Context,
|
||||
_In_ BOOLEAN GlobalEvents
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
PDBWIN_PAGE_BUFFER debugMessageBuffer;
|
||||
PDEBUG_LOG_ENTRY entry = NULL;
|
||||
HANDLE processHandle = NULL;
|
||||
PPH_STRING fileName = NULL;
|
||||
HICON icon = NULL;
|
||||
|
||||
debugMessageBuffer = GlobalEvents ? Context->GlobalDebugBuffer : Context->LocalDebugBuffer;
|
||||
|
||||
entry = PhAllocate(sizeof(DEBUG_LOG_ENTRY));
|
||||
memset(entry, 0, sizeof(DEBUG_LOG_ENTRY));
|
||||
|
||||
PhQuerySystemTime(&entry->Time);
|
||||
entry->ProcessId = UlongToHandle(debugMessageBuffer->ProcessId);
|
||||
entry->Message = PhConvertMultiByteToUtf16(debugMessageBuffer->Buffer);
|
||||
|
||||
if (WINDOWS_HAS_IMAGE_FILE_NAME_BY_PROCESS_ID)
|
||||
{
|
||||
status = PhGetProcessImageFileNameByProcessId(entry->ProcessId, &fileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (NT_SUCCESS(status = PhOpenProcess(&processHandle, ProcessQueryAccess, entry->ProcessId)))
|
||||
{
|
||||
status = PhGetProcessImageFileName(processHandle, &fileName);
|
||||
NtClose(processHandle);
|
||||
}
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
fileName = PhGetKernelFileName();
|
||||
|
||||
PhMoveReference(&fileName, PhGetFileName(fileName));
|
||||
|
||||
icon = PhGetFileShellIcon(PhGetString(fileName), L".exe", TRUE);
|
||||
|
||||
if (icon)
|
||||
{
|
||||
entry->ImageIndex = ImageList_AddIcon(Context->ListViewImageList, icon);
|
||||
DestroyIcon(icon);
|
||||
}
|
||||
|
||||
entry->FilePath = fileName;
|
||||
entry->ProcessName = PhGetBaseName(fileName);
|
||||
|
||||
// Drop event if it matches a filter
|
||||
for (ULONG i = 0; i < Context->ExcludeList->Count; i++)
|
||||
{
|
||||
PDBG_FILTER_TYPE filterEntry = Context->ExcludeList->Items[i];
|
||||
|
||||
if (filterEntry->Type == FilterByName)
|
||||
{
|
||||
if (PhEqualString(filterEntry->ProcessName, entry->ProcessName, TRUE))
|
||||
{
|
||||
DbgFreeLogEntry(entry);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (filterEntry->Type == FilterByPid)
|
||||
{
|
||||
if (filterEntry->ProcessId == entry->ProcessId)
|
||||
{
|
||||
DbgFreeLogEntry(entry);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DbgAddLogEntry(Context, entry);
|
||||
}
|
||||
|
||||
NTSTATUS DbgEventsLocalThread(
|
||||
_In_ PVOID Parameter
|
||||
)
|
||||
{
|
||||
LARGE_INTEGER timeout;
|
||||
NTSTATUS status;
|
||||
PPH_DBGEVENTS_CONTEXT context = (PPH_DBGEVENTS_CONTEXT)Parameter;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
NtSetEvent(context->LocalBufferReadyEvent, NULL);
|
||||
|
||||
status = NtWaitForSingleObject(
|
||||
context->LocalDataReadyEvent,
|
||||
FALSE,
|
||||
PhTimeoutFromMilliseconds(&timeout, 100)
|
||||
);
|
||||
|
||||
if (status == STATUS_TIMEOUT)
|
||||
continue;
|
||||
if (status != STATUS_SUCCESS)
|
||||
break;
|
||||
|
||||
// The process calling OutputDebugString is blocked here...
|
||||
// This gives us some time to extract information without the process exiting.
|
||||
DbgProcessLogMessageEntry(context, FALSE);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS DbgEventsGlobalThread(
|
||||
_In_ PVOID Parameter
|
||||
)
|
||||
{
|
||||
LARGE_INTEGER timeout;
|
||||
NTSTATUS status;
|
||||
PPH_DBGEVENTS_CONTEXT context = (PPH_DBGEVENTS_CONTEXT)Parameter;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
NtSetEvent(context->GlobalBufferReadyEvent, NULL);
|
||||
|
||||
status = NtWaitForSingleObject(
|
||||
context->GlobalDataReadyEvent,
|
||||
FALSE,
|
||||
PhTimeoutFromMilliseconds(&timeout, 100)
|
||||
);
|
||||
|
||||
if (status == STATUS_TIMEOUT)
|
||||
continue;
|
||||
if (status != STATUS_SUCCESS)
|
||||
break;
|
||||
|
||||
// The process calling OutputDebugString is blocked here...
|
||||
// This gives us some time to extract information without the process exiting.
|
||||
DbgProcessLogMessageEntry(context, TRUE);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
BOOLEAN DbgCreateSecurityAttributes(
|
||||
_Inout_ PPH_DBGEVENTS_CONTEXT Context
|
||||
)
|
||||
{
|
||||
Context->SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
Context->SecurityAttributes.bInheritHandle = TRUE;
|
||||
|
||||
if (ConvertStringSecurityDescriptorToSecurityDescriptor(
|
||||
L"D:(A;;GRGWGX;;;WD)(A;;GA;;;SY)(A;;GA;;;BA)(A;;GRGWGX;;;AN)(A;;GRGWGX;;;RC)(A;;GRGWGX;;;S-1-15-2-1)S:(ML;;NW;;;LW)",
|
||||
SDDL_REVISION,
|
||||
&Context->SecurityAttributes.lpSecurityDescriptor,
|
||||
NULL
|
||||
))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOLEAN DbgCleanupSecurityAttributes(
|
||||
_Inout_ PPH_DBGEVENTS_CONTEXT Context
|
||||
)
|
||||
{
|
||||
if (Context->SecurityAttributes.lpSecurityDescriptor)
|
||||
{
|
||||
LocalFree(Context->SecurityAttributes.lpSecurityDescriptor);
|
||||
Context->SecurityAttributes.lpSecurityDescriptor = NULL;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOLEAN DbgEventsCreate(
|
||||
_Inout_ PPH_DBGEVENTS_CONTEXT Context,
|
||||
_In_ BOOLEAN GlobalEvents
|
||||
)
|
||||
{
|
||||
if (GlobalEvents)
|
||||
{
|
||||
SIZE_T viewSize;
|
||||
LARGE_INTEGER maximumSize;
|
||||
OBJECT_ATTRIBUTES objectAttributes;
|
||||
UNICODE_STRING objectName;
|
||||
HANDLE threadHandle = NULL;
|
||||
|
||||
maximumSize.QuadPart = PAGE_SIZE;
|
||||
viewSize = sizeof(DBWIN_PAGE_BUFFER);
|
||||
|
||||
if (!(Context->GlobalBufferReadyEvent = CreateEvent(&Context->SecurityAttributes, FALSE, FALSE, L"Global\\" DBWIN_BUFFER_READY)))
|
||||
{
|
||||
DbgShowErrorMessage(Context, L"DBWIN_BUFFER_READY");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!(Context->GlobalDataReadyEvent = CreateEvent(&Context->SecurityAttributes, FALSE, FALSE, L"Global\\" DBWIN_DATA_READY)))
|
||||
{
|
||||
DbgShowErrorMessage(Context, L"DBWIN_DATA_READY");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DbgFormatObjectName(FALSE, DBWIN_BUFFER_SECTION_NAME, &objectName);
|
||||
InitializeObjectAttributes(
|
||||
&objectAttributes,
|
||||
&objectName,
|
||||
OBJ_CASE_INSENSITIVE,
|
||||
NULL,
|
||||
Context->SecurityAttributes.lpSecurityDescriptor
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(NtCreateSection(
|
||||
&Context->GlobalDataBufferHandle,
|
||||
STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ | SECTION_MAP_WRITE,
|
||||
&objectAttributes,
|
||||
&maximumSize,
|
||||
PAGE_READWRITE,
|
||||
SEC_COMMIT,
|
||||
NULL
|
||||
)))
|
||||
{
|
||||
DbgShowErrorMessage(Context, L"NtCreateSection");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(NtMapViewOfSection(
|
||||
Context->GlobalDataBufferHandle,
|
||||
NtCurrentProcess(),
|
||||
&Context->GlobalDebugBuffer,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
&viewSize,
|
||||
ViewShare,
|
||||
0,
|
||||
PAGE_READONLY
|
||||
)))
|
||||
{
|
||||
DbgShowErrorMessage(Context, L"NtMapViewOfSection");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Context->CaptureGlobalEnabled = TRUE;
|
||||
|
||||
if (threadHandle = PhCreateThread(0, DbgEventsGlobalThread, Context))
|
||||
{
|
||||
NtClose(threadHandle);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SIZE_T viewSize;
|
||||
LARGE_INTEGER maximumSize;
|
||||
OBJECT_ATTRIBUTES objectAttributes;
|
||||
UNICODE_STRING objectName;
|
||||
HANDLE threadHandle = NULL;
|
||||
|
||||
maximumSize.QuadPart = PAGE_SIZE;
|
||||
viewSize = sizeof(DBWIN_PAGE_BUFFER);
|
||||
|
||||
if (!(Context->LocalBufferReadyEvent = CreateEvent(&Context->SecurityAttributes, FALSE, FALSE, L"Local\\" DBWIN_BUFFER_READY)))
|
||||
{
|
||||
DbgShowErrorMessage(Context, L"DBWIN_BUFFER_READY");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!(Context->LocalDataReadyEvent = CreateEvent(&Context->SecurityAttributes, FALSE, FALSE, L"Local\\" DBWIN_DATA_READY)))
|
||||
{
|
||||
DbgShowErrorMessage(Context, L"DBWIN_DATA_READY");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DbgFormatObjectName(TRUE, DBWIN_BUFFER_SECTION_NAME, &objectName);
|
||||
InitializeObjectAttributes(
|
||||
&objectAttributes,
|
||||
&objectName,
|
||||
OBJ_CASE_INSENSITIVE,
|
||||
NULL,
|
||||
Context->SecurityAttributes.lpSecurityDescriptor
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(NtCreateSection(
|
||||
&Context->LocalDataBufferHandle,
|
||||
STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ | SECTION_MAP_WRITE,
|
||||
&objectAttributes,
|
||||
&maximumSize,
|
||||
PAGE_READWRITE,
|
||||
SEC_COMMIT,
|
||||
NULL
|
||||
)))
|
||||
{
|
||||
DbgShowErrorMessage(Context, L"NtCreateSection");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(NtMapViewOfSection(
|
||||
Context->LocalDataBufferHandle,
|
||||
NtCurrentProcess(),
|
||||
&Context->LocalDebugBuffer,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
&viewSize,
|
||||
ViewShare,
|
||||
0,
|
||||
PAGE_READONLY
|
||||
)))
|
||||
{
|
||||
DbgShowErrorMessage(Context, L"NtMapViewOfSection");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Context->CaptureLocalEnabled = TRUE;
|
||||
|
||||
if (threadHandle = PhCreateThread(0, DbgEventsLocalThread, Context))
|
||||
{
|
||||
NtClose(threadHandle);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID DbgEventsCleanup(
|
||||
_Inout_ PPH_DBGEVENTS_CONTEXT Context,
|
||||
_In_ BOOLEAN CleanupGlobal
|
||||
)
|
||||
{
|
||||
if (CleanupGlobal)
|
||||
{
|
||||
Context->CaptureGlobalEnabled = FALSE;
|
||||
|
||||
if (Context->GlobalDebugBuffer)
|
||||
{
|
||||
NtUnmapViewOfSection(NtCurrentProcess(), Context->GlobalDebugBuffer);
|
||||
Context->GlobalDebugBuffer = NULL;
|
||||
}
|
||||
|
||||
if (Context->GlobalDataBufferHandle)
|
||||
{
|
||||
NtClose(Context->GlobalDataBufferHandle);
|
||||
Context->GlobalDataBufferHandle = NULL;
|
||||
}
|
||||
|
||||
if (Context->GlobalBufferReadyEvent)
|
||||
{
|
||||
NtClose(Context->GlobalBufferReadyEvent);
|
||||
Context->GlobalBufferReadyEvent = NULL;
|
||||
}
|
||||
|
||||
if (Context->GlobalDataReadyEvent)
|
||||
{
|
||||
NtClose(Context->GlobalDataReadyEvent);
|
||||
Context->GlobalDataReadyEvent = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Context->CaptureLocalEnabled = FALSE;
|
||||
|
||||
if (Context->LocalDebugBuffer)
|
||||
{
|
||||
NtUnmapViewOfSection(NtCurrentProcess(), Context->LocalDebugBuffer);
|
||||
Context->LocalDebugBuffer = NULL;
|
||||
}
|
||||
|
||||
if (Context->LocalDataBufferHandle)
|
||||
{
|
||||
NtClose(Context->LocalDataBufferHandle);
|
||||
Context->LocalDataBufferHandle = NULL;
|
||||
}
|
||||
|
||||
if (Context->LocalBufferReadyEvent)
|
||||
{
|
||||
NtClose(Context->LocalBufferReadyEvent);
|
||||
Context->LocalBufferReadyEvent = NULL;
|
||||
}
|
||||
|
||||
if (Context->LocalDataReadyEvent)
|
||||
{
|
||||
NtClose(Context->LocalDataReadyEvent);
|
||||
Context->LocalDataReadyEvent = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user