mirror of
https://github.com/mirror/processhacker
synced 2026-06-08 16:03:24 +00:00
470b82f807
git-svn-id: svn://svn.code.sf.net/p/processhacker/code@3213 21ef857c-d57f-4fe0-8362-d861dc6d29cd
484 lines
14 KiB
C
484 lines
14 KiB
C
/*
|
|
* Process Hacker -
|
|
* application support functions
|
|
*
|
|
* Copyright (C) 2010 wj32
|
|
*
|
|
* 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 <phapp.h>
|
|
#include <settings.h>
|
|
#include <wtsapi32.h>
|
|
|
|
BOOLEAN PhGetProcessIsSuspended(
|
|
__in PSYSTEM_PROCESS_INFORMATION Process
|
|
)
|
|
{
|
|
ULONG i;
|
|
|
|
for (i = 0; i < Process->NumberOfThreads; i++)
|
|
{
|
|
if (
|
|
Process->Threads[i].ThreadState != Waiting ||
|
|
Process->Threads[i].WaitReason != Suspended
|
|
)
|
|
return FALSE;
|
|
}
|
|
|
|
return Process->NumberOfThreads != 0;
|
|
}
|
|
|
|
NTSTATUS PhGetProcessKnownType(
|
|
__in HANDLE ProcessHandle,
|
|
__out PPH_KNOWN_PROCESS_TYPE KnownProcessType
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PH_KNOWN_PROCESS_TYPE knownProcessType;
|
|
PROCESS_BASIC_INFORMATION basicInfo;
|
|
PPH_STRING systemDirectory;
|
|
PPH_STRING fileName;
|
|
PPH_STRING newFileName;
|
|
PPH_STRING baseName;
|
|
|
|
if (!NT_SUCCESS(status = PhGetProcessBasicInformation(
|
|
ProcessHandle,
|
|
&basicInfo
|
|
)))
|
|
return status;
|
|
|
|
if (basicInfo.UniqueProcessId == SYSTEM_PROCESS_ID)
|
|
{
|
|
*KnownProcessType = SystemProcessType;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
systemDirectory = PhGetSystemDirectory();
|
|
|
|
if (!systemDirectory)
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
if (!NT_SUCCESS(status = PhGetProcessImageFileName(
|
|
ProcessHandle,
|
|
&fileName
|
|
)))
|
|
{
|
|
PhDereferenceObject(systemDirectory);
|
|
return status;
|
|
}
|
|
|
|
newFileName = PhGetFileName(fileName);
|
|
PhDereferenceObject(fileName);
|
|
|
|
knownProcessType = UnknownProcessType;
|
|
|
|
if (PhStringStartsWith(newFileName, systemDirectory, TRUE))
|
|
{
|
|
baseName = PhSubstring(
|
|
newFileName,
|
|
systemDirectory->Length / 2,
|
|
(newFileName->Length - systemDirectory->Length) / 2
|
|
);
|
|
|
|
// The system directory string never ends in a backslash, unless
|
|
// it is a drive root. We're not going to account for that case.
|
|
|
|
if (!baseName)
|
|
; // Dummy
|
|
else if (PhStringEquals2(baseName, L"\\smss.exe", TRUE))
|
|
knownProcessType = SessionManagerProcessType;
|
|
else if (PhStringEquals2(baseName, L"\\csrss.exe", TRUE))
|
|
knownProcessType = WindowsSubsystemProcessType;
|
|
else if (PhStringEquals2(baseName, L"\\wininit.exe", TRUE))
|
|
knownProcessType = WindowsStartupProcessType;
|
|
else if (PhStringEquals2(baseName, L"\\services.exe", TRUE))
|
|
knownProcessType = ServiceControlManagerProcessType;
|
|
else if (PhStringEquals2(baseName, L"\\lsass.exe", TRUE))
|
|
knownProcessType = LocalSecurityAuthorityProcessType;
|
|
else if (PhStringEquals2(baseName, L"\\lsm.exe", TRUE))
|
|
knownProcessType = LocalSessionManagerProcessType;
|
|
else if (PhStringEquals2(baseName, L"\\svchost.exe", TRUE))
|
|
knownProcessType = ServiceHostProcessType;
|
|
else if (PhStringEquals2(baseName, L"\\rundll32.exe", TRUE))
|
|
knownProcessType = RunDllAsAppProcessType;
|
|
else if (PhStringEquals2(baseName, L"\\dllhost.exe", TRUE))
|
|
knownProcessType = ComSurrogateProcessType;
|
|
|
|
PhDereferenceObject(baseName);
|
|
}
|
|
|
|
PhDereferenceObject(systemDirectory);
|
|
PhDereferenceObject(newFileName);
|
|
|
|
*KnownProcessType = knownProcessType;
|
|
|
|
return status;
|
|
}
|
|
|
|
static BOOLEAN NTAPI PhpSvchostCommandLineCallback(
|
|
__in_opt PPH_COMMAND_LINE_OPTION Option,
|
|
__in_opt PPH_STRING Value,
|
|
__in PVOID Context
|
|
)
|
|
{
|
|
PPH_KNOWN_PROCESS_COMMAND_LINE knownCommandLine = Context;
|
|
|
|
if (Option && Option->Id == 1)
|
|
{
|
|
PhSwapReference(&knownCommandLine->ServiceHost.GroupName, Value);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN PhaGetProcessKnownCommandLine(
|
|
__in PPH_STRING CommandLine,
|
|
__in PH_KNOWN_PROCESS_TYPE KnownProcessType,
|
|
__out PPH_KNOWN_PROCESS_COMMAND_LINE KnownCommandLine
|
|
)
|
|
{
|
|
switch (KnownProcessType)
|
|
{
|
|
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> ...
|
|
|
|
ULONG i;
|
|
ULONG 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 < (ULONG)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 = PhStringLastIndexOfChar(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 (PhStringIndexOfChar(dllName, 0, ':') == -1)
|
|
{
|
|
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>
|
|
|
|
ULONG i;
|
|
ULONG indexOfProcessId;
|
|
PPH_STRING argPart;
|
|
PPH_STRING guidString;
|
|
GUID guid;
|
|
HKEY clsidKeyHandle;
|
|
HKEY 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.
|
|
|
|
PhLowerString(argPart);
|
|
indexOfProcessId = PhStringIndexOfString(argPart, 0, L"/processid:");
|
|
|
|
if (indexOfProcessId == -1)
|
|
return FALSE;
|
|
|
|
guidString = PhaSubstring(
|
|
argPart,
|
|
indexOfProcessId + 11,
|
|
argPart->Length / 2 - indexOfProcessId - 11
|
|
);
|
|
|
|
if (!NT_SUCCESS(RtlGUIDFromString(
|
|
&guidString->us,
|
|
&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 (RegOpenKey(
|
|
HKEY_CLASSES_ROOT,
|
|
PhaConcatStrings2(L"CLSID\\", guidString->Buffer)->Buffer,
|
|
&clsidKeyHandle
|
|
) == ERROR_SUCCESS)
|
|
{
|
|
KnownCommandLine->ComSurrogate.Name =
|
|
PHA_DEREFERENCE(PhQueryRegistryString(clsidKeyHandle, NULL));
|
|
|
|
if (RegOpenKey(
|
|
clsidKeyHandle,
|
|
L"InprocServer32",
|
|
&inprocServer32KeyHandle
|
|
) == ERROR_SUCCESS)
|
|
{
|
|
KnownCommandLine->ComSurrogate.FileName =
|
|
PHA_DEREFERENCE(PhQueryRegistryString(inprocServer32KeyHandle, NULL));
|
|
|
|
if (fileName = PHA_DEREFERENCE(PhExpandEnvironmentStrings(
|
|
KnownCommandLine->ComSurrogate.FileName->Buffer
|
|
)))
|
|
{
|
|
KnownCommandLine->ComSurrogate.FileName = fileName;
|
|
}
|
|
|
|
RegCloseKey(inprocServer32KeyHandle);
|
|
}
|
|
|
|
RegCloseKey(clsidKeyHandle);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
PPH_STRING PhGetSessionInformationString(
|
|
__in HANDLE ServerHandle,
|
|
__in ULONG SessionId,
|
|
__in ULONG InformationClass
|
|
)
|
|
{
|
|
PPH_STRING string;
|
|
PWSTR buffer;
|
|
ULONG length;
|
|
|
|
if (WTSQuerySessionInformation(
|
|
ServerHandle,
|
|
SessionId,
|
|
(WTS_INFO_CLASS)InformationClass,
|
|
&buffer,
|
|
&length
|
|
))
|
|
{
|
|
string = PhCreateString(buffer);
|
|
WTSFreeMemory(buffer);
|
|
|
|
return string;
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
VOID PhSearchOnlineString(
|
|
__in HWND hWnd,
|
|
__in PWSTR String
|
|
)
|
|
{
|
|
PhShellExecuteUserString(hWnd, L"SearchEngine", String, TRUE);
|
|
}
|
|
|
|
VOID PhShellExecuteUserString(
|
|
__in HWND hWnd,
|
|
__in PWSTR Setting,
|
|
__in PWSTR String,
|
|
__in BOOLEAN UseShellExecute
|
|
)
|
|
{
|
|
PPH_STRING executeString = PhGetStringSetting(Setting);
|
|
ULONG indexOfReplacement;
|
|
PPH_STRING stringBefore;
|
|
PPH_STRING stringAfter;
|
|
PPH_STRING newString;
|
|
|
|
// Make sure the user executable string is absolute.
|
|
if (PhStringIndexOfChar(executeString, 0, L':') == -1)
|
|
{
|
|
newString = PhConcatStrings2(PhApplicationDirectory->Buffer, executeString->Buffer);
|
|
PhDereferenceObject(executeString);
|
|
executeString = newString;
|
|
}
|
|
|
|
indexOfReplacement = PhStringIndexOfString(executeString, 0, L"%s");
|
|
|
|
if (indexOfReplacement != -1)
|
|
{
|
|
// Replace "%s" with the string.
|
|
|
|
stringBefore = PhSubstring(executeString, 0, indexOfReplacement);
|
|
stringAfter = PhSubstring(
|
|
executeString,
|
|
indexOfReplacement + 2,
|
|
executeString->Length / 2 - indexOfReplacement - 2
|
|
);
|
|
|
|
newString = PhConcatStrings(
|
|
3,
|
|
stringBefore->Buffer,
|
|
String,
|
|
stringAfter->Buffer
|
|
);
|
|
|
|
if (UseShellExecute)
|
|
{
|
|
PhShellExecute(hWnd, newString->Buffer, NULL);
|
|
}
|
|
else
|
|
{
|
|
NTSTATUS status;
|
|
|
|
status = PhCreateProcessWin32(NULL, newString->Buffer, NULL, NULL, 0, NULL, NULL, NULL);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
PhShowStatus(hWnd, L"Unable to execute the command", status, 0);
|
|
}
|
|
|
|
PhDereferenceObject(newString);
|
|
PhDereferenceObject(stringAfter);
|
|
PhDereferenceObject(stringBefore);
|
|
}
|
|
|
|
PhDereferenceObject(executeString);
|
|
}
|
|
|
|
VOID PhCopyListViewInfoTip(
|
|
__inout LPNMLVGETINFOTIP GetInfoTip,
|
|
__in PPH_STRINGREF Tip
|
|
)
|
|
{
|
|
ULONG copyIndex;
|
|
ULONG bufferRemaining;
|
|
ULONG copyLength;
|
|
|
|
if (GetInfoTip->dwFlags == 0)
|
|
{
|
|
copyIndex = (ULONG)wcslen(GetInfoTip->pszText) + 1; // plus one for newline
|
|
|
|
if (GetInfoTip->cchTextMax - copyIndex < 2) // need at least two bytes
|
|
return;
|
|
|
|
bufferRemaining = GetInfoTip->cchTextMax - copyIndex - 1;
|
|
GetInfoTip->pszText[copyIndex - 1] = '\n';
|
|
}
|
|
else
|
|
{
|
|
copyIndex = 0;
|
|
bufferRemaining = GetInfoTip->cchTextMax;
|
|
}
|
|
|
|
copyLength = min((ULONG)Tip->Length / 2, bufferRemaining - 1);
|
|
memcpy(
|
|
&GetInfoTip->pszText[copyIndex],
|
|
Tip->Buffer,
|
|
copyLength * 2
|
|
);
|
|
GetInfoTip->pszText[copyIndex + copyLength] = 0;
|
|
}
|