611 lines
15 KiB
C
611 lines
15 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1992 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
process.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module maintains state about each process/thread created by the application
|
||
|
setup/install program.
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Steve Wood (stevewo) 09-Aug-1994
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "instaler.h"
|
||
|
|
||
|
BOOLEAN
|
||
|
AddProcess(
|
||
|
LPDEBUG_EVENT DebugEvent,
|
||
|
PPROCESS_INFO *ReturnedProcess
|
||
|
)
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
PPROCESS_INFO Process;
|
||
|
RTL_USER_PROCESS_PARAMETERS ProcessParameters;
|
||
|
PEB Peb;
|
||
|
PWSTR FreeBuffer, s;
|
||
|
|
||
|
Process = AllocMem( sizeof( *Process ) );
|
||
|
if (Process == NULL) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
Process->Id = DebugEvent->dwProcessId;
|
||
|
Process->Handle = DebugEvent->u.CreateProcessInfo.hProcess;
|
||
|
InitializeListHead( &Process->ThreadListHead );
|
||
|
InitializeListHead( &Process->BreakpointListHead );
|
||
|
InitializeListHead( &Process->OpenHandleListHead );
|
||
|
InsertTailList( &ProcessListHead, &Process->Entry );
|
||
|
*ReturnedProcess = Process;
|
||
|
|
||
|
Status = NtQueryInformationProcess( Process->Handle,
|
||
|
ProcessBasicInformation,
|
||
|
&Process->ProcessInformation,
|
||
|
sizeof( Process->ProcessInformation ),
|
||
|
NULL
|
||
|
);
|
||
|
FreeBuffer = NULL;
|
||
|
if (ReadMemory( Process,
|
||
|
Process->ProcessInformation.PebBaseAddress,
|
||
|
&Peb,
|
||
|
sizeof( Peb ),
|
||
|
"PEB"
|
||
|
) &&
|
||
|
Peb.ProcessParameters != NULL &&
|
||
|
ReadMemory( Process,
|
||
|
Peb.ProcessParameters,
|
||
|
&ProcessParameters,
|
||
|
sizeof( ProcessParameters ),
|
||
|
"ProcessParameters"
|
||
|
) &&
|
||
|
ProcessParameters.ImagePathName.Length != 0 &&
|
||
|
(FreeBuffer = AllocMem( ProcessParameters.ImagePathName.Length + sizeof( UNICODE_NULL ) )) != NULL &&
|
||
|
ReadMemory( Process,
|
||
|
ProcessParameters.Flags & RTL_USER_PROC_PARAMS_NORMALIZED ?
|
||
|
ProcessParameters.ImagePathName.Buffer :
|
||
|
(PWSTR)((ULONG)(ProcessParameters.ImagePathName.Buffer) + (PCHAR)(Peb.ProcessParameters)),
|
||
|
FreeBuffer,
|
||
|
ProcessParameters.ImagePathName.Length,
|
||
|
"Image File Name"
|
||
|
)
|
||
|
) {
|
||
|
s = (PWSTR)((PCHAR)FreeBuffer + ProcessParameters.ImagePathName.Length);
|
||
|
while (s > FreeBuffer && s[ -1 ] != OBJ_NAME_PATH_SEPARATOR) {
|
||
|
s--;
|
||
|
}
|
||
|
|
||
|
wcsncpy( Process->ImageFileName,
|
||
|
s,
|
||
|
(sizeof( Process->ImageFileName ) - sizeof( UNICODE_NULL )) / sizeof( WCHAR )
|
||
|
);
|
||
|
}
|
||
|
FreeMem( &FreeBuffer );
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOLEAN
|
||
|
DeleteProcess(
|
||
|
PPROCESS_INFO Process
|
||
|
)
|
||
|
{
|
||
|
PLIST_ENTRY Next, Head;
|
||
|
PTHREAD_INFO Thread;
|
||
|
PBREAKPOINT_INFO Breakpoint;
|
||
|
POPENHANDLE_INFO p;
|
||
|
|
||
|
RemoveEntryList( &Process->Entry );
|
||
|
|
||
|
Head = &Process->ThreadListHead;
|
||
|
Next = Head->Flink;
|
||
|
while (Next != Head) {
|
||
|
Thread = CONTAINING_RECORD( Next, THREAD_INFO, Entry );
|
||
|
Next = Next->Flink;
|
||
|
DeleteThread( Process, Thread );
|
||
|
}
|
||
|
|
||
|
Head = &Process->BreakpointListHead;
|
||
|
Next = Head->Flink;
|
||
|
while (Next != Head) {
|
||
|
Breakpoint = CONTAINING_RECORD( Next, BREAKPOINT_INFO, Entry );
|
||
|
Next = Next->Flink;
|
||
|
DestroyBreakpoint( Breakpoint->Address, Process, NULL );
|
||
|
}
|
||
|
|
||
|
|
||
|
Head = &Process->OpenHandleListHead;
|
||
|
Next = Head->Flink;
|
||
|
while (Next != Head) {
|
||
|
p = CONTAINING_RECORD( Next, OPENHANDLE_INFO, Entry );
|
||
|
Next = Next->Flink;
|
||
|
DeleteOpenHandle( Process, p->Handle, p->Type );
|
||
|
}
|
||
|
|
||
|
FreeMem( &Process );
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOLEAN
|
||
|
AddThread(
|
||
|
LPDEBUG_EVENT DebugEvent,
|
||
|
PPROCESS_INFO Process,
|
||
|
PTHREAD_INFO *ReturnedThread
|
||
|
)
|
||
|
{
|
||
|
PTHREAD_INFO Thread;
|
||
|
|
||
|
Thread = AllocMem( sizeof( *Thread ) );
|
||
|
if (Thread == NULL) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
Thread->Id = DebugEvent->dwThreadId;
|
||
|
if (DebugEvent->dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT) {
|
||
|
Thread->Handle = DebugEvent->u.CreateProcessInfo.hThread;
|
||
|
Thread->StartAddress = DebugEvent->u.CreateProcessInfo.lpStartAddress;
|
||
|
}
|
||
|
else {
|
||
|
Thread->Handle = DebugEvent->u.CreateThread.hThread;
|
||
|
Thread->StartAddress = DebugEvent->u.CreateThread.lpStartAddress;
|
||
|
}
|
||
|
Thread->SingleStepExpected = FALSE;
|
||
|
InitializeListHead( &Thread->BreakpointListHead );
|
||
|
InsertTailList( &Process->ThreadListHead, &Thread->Entry );
|
||
|
*ReturnedThread = Thread;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOLEAN
|
||
|
DeleteThread(
|
||
|
PPROCESS_INFO Process,
|
||
|
PTHREAD_INFO Thread
|
||
|
)
|
||
|
{
|
||
|
PLIST_ENTRY Next, Head;
|
||
|
PBREAKPOINT_INFO Breakpoint;
|
||
|
|
||
|
RemoveEntryList( &Thread->Entry );
|
||
|
|
||
|
Head = &Thread->BreakpointListHead;
|
||
|
Next = Head->Flink;
|
||
|
while (Next != Head) {
|
||
|
Breakpoint = CONTAINING_RECORD( Next, BREAKPOINT_INFO, Entry );
|
||
|
Next = Next->Flink;
|
||
|
DestroyBreakpoint( Breakpoint->Address, Process, Thread );
|
||
|
}
|
||
|
|
||
|
FreeMem( &Thread );
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
PPROCESS_INFO
|
||
|
FindProcessById(
|
||
|
ULONG Id
|
||
|
)
|
||
|
{
|
||
|
PLIST_ENTRY Next, Head;
|
||
|
PPROCESS_INFO Process;
|
||
|
|
||
|
Head = &ProcessListHead;
|
||
|
Next = Head->Flink;
|
||
|
while (Next != Head) {
|
||
|
Process = CONTAINING_RECORD( Next, PROCESS_INFO, Entry );
|
||
|
if (Process->Id == Id) {
|
||
|
return Process;
|
||
|
}
|
||
|
|
||
|
Next = Next->Flink;
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
BOOLEAN
|
||
|
FindProcessAndThreadForEvent(
|
||
|
LPDEBUG_EVENT DebugEvent,
|
||
|
PPROCESS_INFO *ReturnedProcess,
|
||
|
PTHREAD_INFO *ReturnedThread
|
||
|
)
|
||
|
{
|
||
|
PLIST_ENTRY Next, Head;
|
||
|
PPROCESS_INFO Process;
|
||
|
PTHREAD_INFO Thread;
|
||
|
|
||
|
Head = &ProcessListHead;
|
||
|
Next = Head->Flink;
|
||
|
Process = NULL;
|
||
|
Thread = NULL;
|
||
|
while (Next != Head) {
|
||
|
Process = CONTAINING_RECORD( Next, PROCESS_INFO, Entry );
|
||
|
if (Process->Id == DebugEvent->dwProcessId) {
|
||
|
Head = &Process->ThreadListHead;
|
||
|
Next = Head->Flink;
|
||
|
while (Next != Head) {
|
||
|
Thread = CONTAINING_RECORD( Next, THREAD_INFO, Entry );
|
||
|
if (Thread->Id == DebugEvent->dwThreadId) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
Thread = NULL;
|
||
|
Next = Next->Flink;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
Process = NULL;
|
||
|
Next = Next->Flink;
|
||
|
}
|
||
|
|
||
|
*ReturnedProcess = Process;
|
||
|
*ReturnedThread = Thread;
|
||
|
|
||
|
if (DebugEvent->dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT) {
|
||
|
if (Process != NULL) {
|
||
|
DeclareError( INSTALER_DUPLICATE_PROCESS_ID, 0, DebugEvent->dwProcessId );
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
if (DebugEvent->dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT) {
|
||
|
if (Thread != NULL) {
|
||
|
DeclareError( INSTALER_DUPLICATE_THREAD_ID, 0, DebugEvent->dwThreadId, DebugEvent->dwProcessId );
|
||
|
return FALSE;
|
||
|
}
|
||
|
if (Process == NULL) {
|
||
|
DeclareError( INSTALER_MISSING_PROCESS_ID, 0, DebugEvent->dwProcessId );
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
if (Process == NULL) {
|
||
|
DeclareError( INSTALER_MISSING_PROCESS_ID, 0, DebugEvent->dwProcessId );
|
||
|
return FALSE;
|
||
|
}
|
||
|
else
|
||
|
if (Thread == NULL) {
|
||
|
DeclareError( INSTALER_MISSING_THREAD_ID, 0, DebugEvent->dwThreadId, DebugEvent->dwProcessId );
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
SuspendAllButThisThread(
|
||
|
PPROCESS_INFO Process,
|
||
|
PTHREAD_INFO Thread
|
||
|
)
|
||
|
{
|
||
|
PTHREAD_INFO Thread1;
|
||
|
PLIST_ENTRY Next, Head;
|
||
|
|
||
|
if (Thread != NULL) {
|
||
|
Head = &Process->ThreadListHead;
|
||
|
Next = Head->Flink;
|
||
|
while (Next != Head) {
|
||
|
Thread1 = CONTAINING_RECORD( Next, THREAD_INFO, Entry );
|
||
|
if (Thread1 != Thread) {
|
||
|
NtSuspendThread( Thread1->Handle, NULL );
|
||
|
}
|
||
|
|
||
|
Next = Next->Flink;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
ResumeAllButThisThread(
|
||
|
PPROCESS_INFO Process,
|
||
|
PTHREAD_INFO Thread
|
||
|
)
|
||
|
{
|
||
|
PTHREAD_INFO Thread1;
|
||
|
PLIST_ENTRY Next, Head;
|
||
|
|
||
|
if (Thread != NULL) {
|
||
|
Head = &Process->ThreadListHead;
|
||
|
Next = Head->Flink;
|
||
|
while (Next != Head) {
|
||
|
Thread1 = CONTAINING_RECORD( Next, THREAD_INFO, Entry );
|
||
|
if (Thread1 != Thread) {
|
||
|
NtResumeThread( Thread1->Handle, NULL );
|
||
|
}
|
||
|
|
||
|
Next = Next->Flink;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
PBREAKPOINT_INFO
|
||
|
FindBreakpoint(
|
||
|
LPVOID Address,
|
||
|
PPROCESS_INFO Process,
|
||
|
PTHREAD_INFO Thread
|
||
|
)
|
||
|
{
|
||
|
PBREAKPOINT_INFO Breakpoint;
|
||
|
PLIST_ENTRY Next, Head;
|
||
|
|
||
|
if (Thread != NULL) {
|
||
|
Head = &Thread->BreakpointListHead;
|
||
|
Next = Head->Flink;
|
||
|
while (Next != Head) {
|
||
|
Breakpoint = CONTAINING_RECORD( Next, BREAKPOINT_INFO, Entry );
|
||
|
if (Breakpoint->Address == Address) {
|
||
|
return Breakpoint;
|
||
|
}
|
||
|
|
||
|
Next = Next->Flink;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Head = &Process->BreakpointListHead;
|
||
|
Next = Head->Flink;
|
||
|
while (Next != Head) {
|
||
|
Breakpoint = CONTAINING_RECORD( Next, BREAKPOINT_INFO, Entry );
|
||
|
if (Breakpoint->Address == Address) {
|
||
|
return Breakpoint;
|
||
|
}
|
||
|
|
||
|
Next = Next->Flink;
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
BOOLEAN
|
||
|
CreateBreakpoint(
|
||
|
LPVOID Address,
|
||
|
PPROCESS_INFO Process,
|
||
|
PTHREAD_INFO Thread,
|
||
|
UCHAR ApiIndex,
|
||
|
PAPI_SAVED_PARAMETERS SavedParameters,
|
||
|
PBREAKPOINT_INFO *ReturnedBreakpoint
|
||
|
)
|
||
|
{
|
||
|
PBREAKPOINT_INFO Breakpoint;
|
||
|
|
||
|
Breakpoint = FindBreakpoint( Address, Process, Thread );
|
||
|
|
||
|
if (ARGUMENT_PRESENT( ReturnedBreakpoint )) {
|
||
|
*ReturnedBreakpoint = Breakpoint;
|
||
|
}
|
||
|
|
||
|
if (Breakpoint != NULL) {
|
||
|
return (Breakpoint->ApiIndex == ApiIndex);
|
||
|
}
|
||
|
|
||
|
Breakpoint = AllocMem( sizeof( *Breakpoint ) );
|
||
|
if (Breakpoint == NULL) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
Breakpoint->Address = Address;
|
||
|
Breakpoint->ApiIndex = ApiIndex;
|
||
|
if (ARGUMENT_PRESENT( SavedParameters )) {
|
||
|
Breakpoint->SavedParameters = *SavedParameters;
|
||
|
Breakpoint->SavedParametersValid = TRUE;
|
||
|
}
|
||
|
else {
|
||
|
Breakpoint->SavedParametersValid = FALSE;
|
||
|
}
|
||
|
|
||
|
if (Thread != NULL) {
|
||
|
InsertTailList( &Thread->BreakpointListHead, &Breakpoint->Entry );
|
||
|
}
|
||
|
else {
|
||
|
InsertTailList( &Process->BreakpointListHead, &Breakpoint->Entry );
|
||
|
}
|
||
|
|
||
|
InstallBreakpoint( Process, Breakpoint );
|
||
|
|
||
|
if (ARGUMENT_PRESENT( ReturnedBreakpoint )) {
|
||
|
*ReturnedBreakpoint = Breakpoint;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOLEAN
|
||
|
DestroyBreakpoint(
|
||
|
LPVOID Address,
|
||
|
PPROCESS_INFO Process,
|
||
|
PTHREAD_INFO Thread
|
||
|
)
|
||
|
{
|
||
|
PBREAKPOINT_INFO Breakpoint;
|
||
|
|
||
|
Breakpoint = FindBreakpoint( Address, Process, Thread );
|
||
|
if (Breakpoint == NULL) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
RemoveBreakpoint( Process, Breakpoint );
|
||
|
|
||
|
RemoveEntryList( &Breakpoint->Entry );
|
||
|
|
||
|
FreeMem( &Breakpoint );
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOLEAN
|
||
|
HandleThreadsForSingleStep(
|
||
|
PPROCESS_INFO Process,
|
||
|
PTHREAD_INFO ThreadToSingleStep,
|
||
|
BOOLEAN SuspendThreads
|
||
|
)
|
||
|
{
|
||
|
PLIST_ENTRY Next, Head;
|
||
|
PTHREAD_INFO Thread;
|
||
|
|
||
|
Head = &Process->ThreadListHead;
|
||
|
Next = Head->Flink;
|
||
|
while (Next != Head) {
|
||
|
Thread = CONTAINING_RECORD( Next, THREAD_INFO, Entry );
|
||
|
if (Thread != ThreadToSingleStep) {
|
||
|
if (SuspendThreads) {
|
||
|
if (Thread->BreakpointToStepOver == NULL) {
|
||
|
SuspendThread( Thread->Handle );
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
ResumeThread( Thread->Handle );
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
Next = Next->Flink;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOLEAN
|
||
|
ReadMemory(
|
||
|
PPROCESS_INFO Process,
|
||
|
PVOID Address,
|
||
|
PVOID DataRead,
|
||
|
ULONG BytesToRead,
|
||
|
PCHAR Reason
|
||
|
)
|
||
|
{
|
||
|
ULONG BytesRead;
|
||
|
|
||
|
if (!ReadProcessMemory( Process->Handle,
|
||
|
Address,
|
||
|
DataRead,
|
||
|
BytesToRead,
|
||
|
&BytesRead
|
||
|
) ||
|
||
|
BytesRead != BytesToRead
|
||
|
) {
|
||
|
DbgEvent( MEMORYERROR, ( "Read memory from %x for %x bytes failed (%u) - '%s'\n",
|
||
|
Address,
|
||
|
BytesToRead,
|
||
|
GetLastError(),
|
||
|
Reason
|
||
|
)
|
||
|
);
|
||
|
return FALSE;
|
||
|
}
|
||
|
else {
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOLEAN
|
||
|
WriteMemory(
|
||
|
PPROCESS_INFO Process,
|
||
|
PVOID Address,
|
||
|
PVOID DataToWrite,
|
||
|
ULONG BytesToWrite,
|
||
|
PCHAR Reason
|
||
|
)
|
||
|
{
|
||
|
ULONG BytesWritten;
|
||
|
ULONG OldProtection;
|
||
|
BOOLEAN Result;
|
||
|
|
||
|
if (WriteProcessMemory( Process->Handle,
|
||
|
Address,
|
||
|
DataToWrite,
|
||
|
BytesToWrite,
|
||
|
&BytesWritten
|
||
|
) &&
|
||
|
BytesWritten == BytesToWrite
|
||
|
) {
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
Result = FALSE;
|
||
|
if (GetLastError() == ERROR_NOACCESS &&
|
||
|
VirtualProtectEx( Process->Handle,
|
||
|
Address,
|
||
|
BytesToWrite,
|
||
|
PAGE_READWRITE,
|
||
|
&OldProtection
|
||
|
)
|
||
|
) {
|
||
|
if (WriteProcessMemory( Process->Handle,
|
||
|
Address,
|
||
|
DataToWrite,
|
||
|
BytesToWrite,
|
||
|
&BytesWritten
|
||
|
) &&
|
||
|
BytesWritten == BytesToWrite
|
||
|
) {
|
||
|
Result = TRUE;
|
||
|
}
|
||
|
VirtualProtectEx( Process->Handle,
|
||
|
Address,
|
||
|
BytesToWrite,
|
||
|
OldProtection,
|
||
|
&OldProtection
|
||
|
);
|
||
|
if (Result) {
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DbgEvent( MEMORYERROR, ( "Write memory to %x for %x bytes failed (%u) - '%s'\n",
|
||
|
Address,
|
||
|
BytesToWrite,
|
||
|
GetLastError(),
|
||
|
Reason
|
||
|
)
|
||
|
);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
PVOID
|
||
|
AllocMem(
|
||
|
ULONG Size
|
||
|
)
|
||
|
{
|
||
|
PVOID p;
|
||
|
|
||
|
p = HeapAlloc( AppHeap, HEAP_ZERO_MEMORY, Size );
|
||
|
if (p == NULL) {
|
||
|
DbgEvent( INTERNALERROR, ( "HeapAlloc( %0x8 ) failed\n", Size ) );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
FreeMem(
|
||
|
PVOID *p
|
||
|
)
|
||
|
{
|
||
|
if (*p != NULL) {
|
||
|
HeapFree( AppHeap, 0, *p );
|
||
|
*p = NULL;
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|