mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1028 lines
26 KiB
1028 lines
26 KiB
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
csrdebug.c
|
|
|
|
Abstract:
|
|
|
|
This module implements CSR Debug Services.
|
|
|
|
Author:
|
|
|
|
Mark Lucovsky (markl) 02-Apr-1991
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "csrsrv.h"
|
|
#include "ntrtl.h"
|
|
#define WIN32_CONSOLE_APP
|
|
#include <windows.h>
|
|
#include <ntsdexts.h>
|
|
|
|
PCSR_PROCESS CsrDebugProcessPtr;
|
|
BOOLEAN fWin32ServerDebugger = FALSE;
|
|
CLIENT_ID ClientIdWin32ServerDebugger;
|
|
|
|
PIMAGE_DEBUG_DIRECTORY
|
|
CsrpLocateDebugSection(
|
|
IN HANDLE ProcessHandle,
|
|
IN PVOID Base
|
|
);
|
|
|
|
NTSTATUS
|
|
CsrDebugProcess(
|
|
IN ULONG TargetProcessId,
|
|
IN PCLIENT_ID DebugUserInterface,
|
|
IN PCSR_ATTACH_COMPLETE_ROUTINE AttachCompleteRoutine
|
|
)
|
|
{
|
|
|
|
PLIST_ENTRY ListHead, ListNext;
|
|
PCSR_PROCESS Process;
|
|
NTSTATUS Status;
|
|
BOOLEAN ProcessFound = FALSE;
|
|
HANDLE ProcessHandle;
|
|
|
|
//
|
|
// only allow CSR debugging if it has not been disabled in the
|
|
// ntglobalflag
|
|
//
|
|
|
|
if ( TargetProcessId == -1 ) {
|
|
if (!(RtlGetNtGlobalFlags() & FLG_ENABLE_CSRDEBUG)) {
|
|
KdPrint(( "CSRSRV: CSR Debugging not enabled - NtGlobalFlag == %x\n", RtlGetNtGlobalFlags()));
|
|
return STATUS_ACCESS_DENIED;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Locate the target process
|
|
//
|
|
|
|
AcquireProcessStructureLock();
|
|
|
|
ListHead = &CsrRootProcess->ListLink;
|
|
ListNext = ListHead->Flink;
|
|
while (ListNext != ListHead) {
|
|
Process = CONTAINING_RECORD( ListNext, CSR_PROCESS, ListLink );
|
|
if (Process->ClientId.UniqueProcess == (HANDLE)TargetProcessId
|
|
|| (TargetProcessId == -1 && CsrDebugProcessPtr == NULL)
|
|
) {
|
|
ProcessFound = TRUE;
|
|
if ( TargetProcessId == -1 ) {
|
|
|
|
CsrpServerDebugInitialize = TRUE;
|
|
|
|
Process = CsrInitializeCsrDebugProcess(NULL);
|
|
|
|
//
|
|
// Mark the process as being debugged
|
|
//
|
|
|
|
Process->DebugFlags = CSR_DEBUG_THIS_PROCESS;
|
|
Process->DebugUserInterface = *DebugUserInterface;
|
|
|
|
fWin32ServerDebugger = TRUE;
|
|
ClientIdWin32ServerDebugger = *DebugUserInterface;
|
|
}
|
|
else {
|
|
|
|
//
|
|
// Mark the process as being debugged
|
|
//
|
|
|
|
Process->DebugFlags = CSR_DEBUG_THIS_PROCESS;
|
|
Process->DebugUserInterface = *DebugUserInterface;
|
|
|
|
Process = CsrInitializeCsrDebugProcess(Process);
|
|
}
|
|
if ( !Process ) {
|
|
ReleaseProcessStructureLock();
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
CsrSuspendProcess(Process);
|
|
|
|
if ( TargetProcessId != -1 ) {
|
|
|
|
//
|
|
// Process is being debugged, so set up debug port
|
|
//
|
|
|
|
Status = NtSetInformationProcess(
|
|
Process->ProcessHandle,
|
|
ProcessDebugPort,
|
|
(PVOID)&CsrApiPort,
|
|
sizeof(HANDLE)
|
|
);
|
|
if ( !NT_SUCCESS(Status) ){
|
|
CsrResumeProcess(Process);
|
|
CsrTeardownCsrDebugProcess(Process);
|
|
ReleaseProcessStructureLock();
|
|
return Status;
|
|
}
|
|
}
|
|
else {
|
|
ProcessHandle = Process->ProcessHandle;
|
|
}
|
|
|
|
break;
|
|
}
|
|
ListNext = ListNext->Flink;
|
|
}
|
|
ReleaseProcessStructureLock();
|
|
|
|
if ( !ProcessFound ) {
|
|
return( STATUS_UNSUCCESSFUL );
|
|
}
|
|
|
|
|
|
Status = CsrSendProcessAndThreadEvents(Process,AttachCompleteRoutine);
|
|
CsrResumeProcess(Process);
|
|
CsrTeardownCsrDebugProcess(Process);
|
|
|
|
CsrpServerDebugInitialize = FALSE;
|
|
|
|
if ( NT_SUCCESS(Status) ) {
|
|
if ( TargetProcessId == -1 ) {
|
|
NtSetInformationProcess(
|
|
ProcessHandle,
|
|
ProcessDebugPort,
|
|
(PVOID)&CsrSmApiPort,
|
|
sizeof(HANDLE)
|
|
);
|
|
NtClose(ProcessHandle);
|
|
DbgBreakPoint();
|
|
}
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
CsrSendProcessAndThreadEvents(
|
|
IN PCSR_PROCESS Process,
|
|
IN PCSR_ATTACH_COMPLETE_ROUTINE AttachCompleteRoutine
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This procedure sends the create process and create thread
|
|
debug events to the debug subsystem.
|
|
|
|
Arguments:
|
|
|
|
Process - Supplies the address of the process being debugged.
|
|
|
|
AttachCompleteRoutine - Supplies the address of the function in the
|
|
clients address space that is remote called to cause entry into
|
|
the debugger.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PPEB Peb;
|
|
NTSTATUS Status;
|
|
PROCESS_BASIC_INFORMATION BasicInfo;
|
|
PLDR_DATA_TABLE_ENTRY LdrEntry;
|
|
LDR_DATA_TABLE_ENTRY LdrEntryData;
|
|
PLIST_ENTRY LdrHead,LdrNext;
|
|
PPEB_LDR_DATA Ldr;
|
|
PLIST_ENTRY ThreadListHead, ThreadListNext;
|
|
PCSR_THREAD Thread, FirstThread;
|
|
DBGKM_APIMSG m;
|
|
PDBGKM_CREATE_THREAD CreateThreadArgs;
|
|
PDBGKM_CREATE_PROCESS CreateProcessArgs;
|
|
PDBGKM_LOAD_DLL LoadDllArgs;
|
|
PVOID ImageBaseAddress;
|
|
HANDLE ReplyEvent;
|
|
|
|
Status = NtCreateEvent(
|
|
&ReplyEvent,
|
|
EVENT_ALL_ACCESS,
|
|
NULL,
|
|
SynchronizationEvent,
|
|
FALSE
|
|
);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
return Status;
|
|
}
|
|
|
|
Status = NtQueryInformationProcess(
|
|
Process->ProcessHandle,
|
|
ProcessBasicInformation,
|
|
&BasicInfo,
|
|
sizeof(BasicInfo),
|
|
NULL
|
|
);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
goto bail;
|
|
}
|
|
|
|
Peb = BasicInfo.PebBaseAddress;
|
|
|
|
//
|
|
// Ldr = Peb->Ldr
|
|
//
|
|
|
|
Status = NtReadVirtualMemory(
|
|
Process->ProcessHandle,
|
|
&Peb->Ldr,
|
|
&Ldr,
|
|
sizeof(Ldr),
|
|
NULL
|
|
);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
goto bail;
|
|
}
|
|
|
|
LdrHead = &Ldr->InLoadOrderModuleList;
|
|
|
|
//
|
|
// LdrNext = Head->Flink;
|
|
//
|
|
|
|
Status = NtReadVirtualMemory(
|
|
Process->ProcessHandle,
|
|
&LdrHead->Flink,
|
|
&LdrNext,
|
|
sizeof(LdrNext),
|
|
NULL
|
|
);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
goto bail;
|
|
}
|
|
|
|
if ( LdrNext != LdrHead ) {
|
|
|
|
//
|
|
// This is the entry data for the image.
|
|
//
|
|
|
|
LdrEntry = CONTAINING_RECORD(LdrNext,LDR_DATA_TABLE_ENTRY,InLoadOrderLinks);
|
|
Status = NtReadVirtualMemory(
|
|
Process->ProcessHandle,
|
|
LdrEntry,
|
|
&LdrEntryData,
|
|
sizeof(LdrEntryData),
|
|
NULL
|
|
);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
goto bail;
|
|
}
|
|
Status = NtReadVirtualMemory(
|
|
Process->ProcessHandle,
|
|
&Peb->ImageBaseAddress,
|
|
&ImageBaseAddress,
|
|
sizeof(ImageBaseAddress),
|
|
NULL
|
|
);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
goto bail;
|
|
}
|
|
|
|
LdrNext = LdrEntryData.InLoadOrderLinks.Flink;
|
|
|
|
}
|
|
else {
|
|
LdrEntry = NULL;
|
|
}
|
|
|
|
FirstThread = NULL;
|
|
|
|
ThreadListHead = &Process->ThreadList;
|
|
ThreadListNext = ThreadListHead->Flink;
|
|
while (ThreadListNext != ThreadListHead) {
|
|
Thread = CONTAINING_RECORD( ThreadListNext, CSR_THREAD, Link );
|
|
|
|
if ( !FirstThread ) {
|
|
FirstThread = Thread;
|
|
|
|
//
|
|
// Send the CreateProcess Message
|
|
//
|
|
|
|
CreateThreadArgs = &m.u.CreateProcessInfo.InitialThread;
|
|
CreateThreadArgs->SubSystemKey = 0;
|
|
|
|
CreateProcessArgs = &m.u.CreateProcessInfo;
|
|
CreateProcessArgs->SubSystemKey = 0;
|
|
|
|
CsrComputeImageInformation(
|
|
Process,
|
|
&LdrEntryData,
|
|
&CreateProcessArgs->BaseOfImage,
|
|
&CreateProcessArgs->DebugInfoFileOffset,
|
|
&CreateProcessArgs->DebugInfoSize
|
|
);
|
|
|
|
CsrOpenLdrEntry(
|
|
FirstThread,
|
|
Process,
|
|
&LdrEntryData,
|
|
&CreateProcessArgs->FileHandle
|
|
);
|
|
|
|
CreateThreadArgs->StartAddress = NULL;
|
|
|
|
DBGKM_FORMAT_API_MSG(m,DbgKmCreateProcessApi,sizeof(*CreateProcessArgs));
|
|
|
|
m.h.ClientId = Thread->ClientId;
|
|
DbgSsHandleKmApiMsg(&m,ReplyEvent);
|
|
Status = NtWaitForSingleObject(ReplyEvent,FALSE,NULL);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
goto bail;
|
|
}
|
|
}
|
|
else {
|
|
|
|
//
|
|
// Send the CreateThread Message
|
|
//
|
|
|
|
CreateThreadArgs = &m.u.CreateThread;
|
|
CreateThreadArgs->SubSystemKey = 0;
|
|
CreateThreadArgs->StartAddress = NULL;
|
|
|
|
DBGKM_FORMAT_API_MSG(m,DbgKmCreateThreadApi,sizeof(*CreateThreadArgs));
|
|
|
|
m.h.ClientId = Thread->ClientId;
|
|
|
|
DbgSsHandleKmApiMsg(&m,ReplyEvent);
|
|
Status = NtWaitForSingleObject(ReplyEvent,FALSE,NULL);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
goto bail;
|
|
}
|
|
}
|
|
ThreadListNext = ThreadListNext->Flink;
|
|
}
|
|
|
|
//
|
|
// Send all of the load module messages
|
|
//
|
|
|
|
while ( LdrNext != LdrHead ) {
|
|
LdrEntry = CONTAINING_RECORD(LdrNext,LDR_DATA_TABLE_ENTRY,InLoadOrderLinks);
|
|
Status = NtReadVirtualMemory(
|
|
Process->ProcessHandle,
|
|
LdrEntry,
|
|
&LdrEntryData,
|
|
sizeof(LdrEntryData),
|
|
NULL
|
|
);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
goto bail;
|
|
}
|
|
|
|
LoadDllArgs = &m.u.LoadDll;
|
|
|
|
CsrComputeImageInformation(
|
|
Process,
|
|
&LdrEntryData,
|
|
&LoadDllArgs->BaseOfDll,
|
|
&LoadDllArgs->DebugInfoFileOffset,
|
|
&LoadDllArgs->DebugInfoSize
|
|
);
|
|
|
|
CsrOpenLdrEntry(
|
|
FirstThread,
|
|
Process,
|
|
&LdrEntryData,
|
|
&LoadDllArgs->FileHandle
|
|
);
|
|
if ( LoadDllArgs->FileHandle ) {
|
|
DBGKM_FORMAT_API_MSG(m,DbgKmLoadDllApi,sizeof(*LoadDllArgs));
|
|
m.h.ClientId = FirstThread->ClientId;
|
|
DbgSsHandleKmApiMsg(&m,ReplyEvent);
|
|
Status = NtWaitForSingleObject(ReplyEvent,FALSE,NULL);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
goto bail;
|
|
}
|
|
}
|
|
|
|
LdrNext = LdrEntryData.InLoadOrderLinks.Flink;
|
|
}
|
|
bail:
|
|
NtClose(ReplyEvent);
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
CsrComputeImageInformation(
|
|
IN PCSR_PROCESS Process,
|
|
IN PLDR_DATA_TABLE_ENTRY LdrEntry,
|
|
OUT PVOID *BaseOfImage,
|
|
OUT PULONG DebugInfoFileOffset,
|
|
OUT PULONG DebugInfoSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called to compute the image base and
|
|
debug information from a ldr entry.
|
|
|
|
Arguments:
|
|
|
|
Process - Supplies the address of the process whose context this
|
|
information is to be calculated from.
|
|
|
|
LdrEntry - Supplies the address of the loader data table entry
|
|
whose info is being computed relative to. This pointer is
|
|
valid in the callers (current) context.
|
|
|
|
BaseOfImage - Returns the image's base.
|
|
|
|
DebugInfoFileOffset - Returns the offset of the debug info.
|
|
|
|
DebugInfoSize - Returns the size of the debug info.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PIMAGE_DEBUG_DIRECTORY pDebugDir;
|
|
IMAGE_DEBUG_DIRECTORY DebugDir;
|
|
IMAGE_COFF_SYMBOLS_HEADER DebugInfo;
|
|
NTSTATUS Status;
|
|
|
|
*BaseOfImage = LdrEntry->DllBase;
|
|
|
|
pDebugDir = CsrpLocateDebugSection(
|
|
Process->ProcessHandle,
|
|
LdrEntry->DllBase
|
|
);
|
|
|
|
*DebugInfoFileOffset = 0;
|
|
*DebugInfoSize = 0;
|
|
if ( pDebugDir ) {
|
|
|
|
Status = NtReadVirtualMemory(
|
|
Process->ProcessHandle,
|
|
pDebugDir,
|
|
&DebugDir,
|
|
sizeof(IMAGE_DEBUG_DIRECTORY),
|
|
NULL
|
|
);
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
return;
|
|
}
|
|
|
|
Status = NtReadVirtualMemory(
|
|
Process->ProcessHandle,
|
|
(PVOID)((ULONG)LdrEntry->DllBase + DebugDir.AddressOfRawData),
|
|
&DebugInfo,
|
|
sizeof(IMAGE_COFF_SYMBOLS_HEADER),
|
|
NULL
|
|
);
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
return;
|
|
}
|
|
|
|
*DebugInfoFileOffset = DebugDir.PointerToRawData + DebugInfo.LvaToFirstSymbol;
|
|
*DebugInfoSize = DebugInfo.NumberOfSymbols;
|
|
}
|
|
else {
|
|
*DebugInfoFileOffset = 0;
|
|
*DebugInfoSize = 0;
|
|
}
|
|
}
|
|
|
|
PIMAGE_DEBUG_DIRECTORY
|
|
CsrpLocateDebugSection(
|
|
IN HANDLE ProcessHandle,
|
|
IN PVOID Base
|
|
)
|
|
|
|
{
|
|
PVOID ImageHeaderRawData;
|
|
PIMAGE_DOS_HEADER DosHeaderRawData;
|
|
PIMAGE_NT_HEADERS NtHeaders;
|
|
ULONG AllocSize, Addr;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Allocate a buffer, and read the image header from the
|
|
// target process
|
|
//
|
|
|
|
DosHeaderRawData = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ),
|
|
sizeof(IMAGE_DOS_HEADER));
|
|
|
|
if ( !DosHeaderRawData ) {
|
|
return NULL;
|
|
}
|
|
|
|
Status = NtReadVirtualMemory(
|
|
ProcessHandle,
|
|
Base,
|
|
DosHeaderRawData,
|
|
sizeof(IMAGE_DOS_HEADER),
|
|
NULL
|
|
);
|
|
|
|
AllocSize = DosHeaderRawData->e_lfanew + sizeof(IMAGE_NT_HEADERS);
|
|
RtlFreeHeap(RtlProcessHeap(), 0, DosHeaderRawData);
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
return NULL;
|
|
}
|
|
|
|
ImageHeaderRawData = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), AllocSize);
|
|
if ( !ImageHeaderRawData ) {
|
|
return NULL;
|
|
}
|
|
Status = NtReadVirtualMemory(
|
|
ProcessHandle,
|
|
Base,
|
|
ImageHeaderRawData,
|
|
AllocSize,
|
|
NULL
|
|
);
|
|
if ( !NT_SUCCESS(Status) ){
|
|
RtlFreeHeap(RtlProcessHeap(),0,ImageHeaderRawData);
|
|
return NULL;
|
|
}
|
|
|
|
NtHeaders = RtlImageNtHeader(ImageHeaderRawData);
|
|
if ( NtHeaders ) {
|
|
Addr = (ULONG)NtHeaders->OptionalHeader.DataDirectory
|
|
[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
|
|
|
|
if ( Addr ) {
|
|
Addr += (ULONG)Base;
|
|
}
|
|
}
|
|
else {
|
|
Addr = 0;
|
|
}
|
|
|
|
RtlFreeHeap(RtlProcessHeap(),0,ImageHeaderRawData);
|
|
return((PIMAGE_DEBUG_DIRECTORY)Addr);
|
|
}
|
|
|
|
VOID
|
|
CsrOpenLdrEntry(
|
|
IN PCSR_THREAD Thread,
|
|
IN PCSR_PROCESS Process,
|
|
IN PLDR_DATA_TABLE_ENTRY LdrEntry,
|
|
OUT PHANDLE FileHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function opens a handle to the image/dll file described
|
|
by the ldr entry in the context of the specified process.
|
|
|
|
Arguments:
|
|
|
|
Thread - Supplies the address of the first thread in the process
|
|
|
|
Process - Supplies the address of the process whose context this
|
|
file is to be opened in.
|
|
|
|
LdrEntry - Supplies the address of the loader data table entry
|
|
whose file is to be opened.
|
|
|
|
FileHandle - Returns a handle to the associated file
|
|
valid in the context of the process being attached to.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
UNICODE_STRING DosName;
|
|
UNICODE_STRING FileName;
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
HANDLE LocalHandle;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
BOOLEAN TranslationStatus;
|
|
NTSTATUS ImpersonationStatus;
|
|
HANDLE NewToken;
|
|
|
|
*FileHandle = NULL;
|
|
DosName.Length = LdrEntry->FullDllName.Length;
|
|
DosName.MaximumLength = LdrEntry->FullDllName.MaximumLength;
|
|
DosName.Buffer = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), DosName.MaximumLength);
|
|
if ( !DosName.Buffer ) {
|
|
return;
|
|
}
|
|
|
|
Status = NtReadVirtualMemory(
|
|
Process->ProcessHandle,
|
|
LdrEntry->FullDllName.Buffer,
|
|
DosName.Buffer,
|
|
DosName.MaximumLength,
|
|
NULL
|
|
);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
RtlFreeHeap(RtlProcessHeap(),0,DosName.Buffer);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// special case CSR
|
|
//
|
|
if ( RtlDetermineDosPathNameType_U(DosName.Buffer) == RtlPathTypeRooted ) {
|
|
InitializeObjectAttributes(
|
|
&Obja,
|
|
&DosName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Status = NtOpenFile(
|
|
&LocalHandle,
|
|
(ACCESS_MASK)(GENERIC_READ | SYNCHRONIZE),
|
|
&Obja,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_SYNCHRONOUS_IO_NONALERT
|
|
);
|
|
|
|
RtlFreeHeap(RtlProcessHeap(),0,DosName.Buffer);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// The file is open in our context. Dup this to target processes context
|
|
// so that dbgss can dup it to the user interface
|
|
//
|
|
|
|
Status = NtDuplicateObject(
|
|
NtCurrentProcess(),
|
|
LocalHandle,
|
|
Process->ProcessHandle,
|
|
FileHandle,
|
|
0L,
|
|
0L,
|
|
DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES |
|
|
DUPLICATE_CLOSE_SOURCE
|
|
);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
*FileHandle = NULL;
|
|
}
|
|
return;
|
|
}
|
|
|
|
TranslationStatus = RtlDosPathNameToNtPathName_U(
|
|
DosName.Buffer,
|
|
&FileName,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if ( !TranslationStatus ) {
|
|
RtlFreeHeap(RtlProcessHeap(),0,DosName.Buffer);
|
|
return;
|
|
}
|
|
|
|
InitializeObjectAttributes(
|
|
&Obja,
|
|
&FileName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Status = NtOpenFile(
|
|
&LocalHandle,
|
|
(ACCESS_MASK)(GENERIC_READ | SYNCHRONIZE),
|
|
&Obja,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_SYNCHRONOUS_IO_NONALERT
|
|
);
|
|
if ( !NT_SUCCESS(Status) && Thread ) {
|
|
ImpersonationStatus = NtImpersonateThread(
|
|
NtCurrentThread(),
|
|
Thread->ThreadHandle,
|
|
&CsrSecurityQos
|
|
);
|
|
if ( NT_SUCCESS(ImpersonationStatus) ) {
|
|
Status = NtOpenFile(
|
|
&LocalHandle,
|
|
(ACCESS_MASK)(GENERIC_READ | SYNCHRONIZE),
|
|
&Obja,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_SYNCHRONOUS_IO_NONALERT
|
|
);
|
|
|
|
NewToken = NULL;
|
|
ImpersonationStatus = NtSetInformationThread(
|
|
NtCurrentThread(),
|
|
ThreadImpersonationToken,
|
|
(PVOID)&NewToken,
|
|
(ULONG)sizeof(HANDLE)
|
|
);
|
|
ASSERT( NT_SUCCESS(ImpersonationStatus) );
|
|
}
|
|
}
|
|
RtlFreeHeap(RtlProcessHeap(),0,DosName.Buffer);
|
|
RtlFreeHeap(RtlProcessHeap(),0,FileName.Buffer);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// The file is open in our context. Dup this to target processes context
|
|
// so that dbgss can dup it to the user interface
|
|
//
|
|
|
|
Status = NtDuplicateObject(
|
|
NtCurrentProcess(),
|
|
LocalHandle,
|
|
Process->ProcessHandle,
|
|
FileHandle,
|
|
0L,
|
|
0L,
|
|
DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES |
|
|
DUPLICATE_CLOSE_SOURCE
|
|
);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
*FileHandle = NULL;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
CsrSuspendProcess(
|
|
IN PCSR_PROCESS Process
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This procedure is called when doing a debug attach to suspend all
|
|
threads within the effected process.
|
|
|
|
Arguments:
|
|
|
|
Process - Supplies the address of the process to suspend.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PLIST_ENTRY ListHead, ListNext;
|
|
PCSR_THREAD Thread;
|
|
NTSTATUS Status;
|
|
|
|
if ( Process == CsrDebugProcessPtr ) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Now walk through the processes thread list and
|
|
// suspend all of its threads.
|
|
//
|
|
|
|
ListHead = &Process->ThreadList;
|
|
ListNext = ListHead->Flink;
|
|
while (ListNext != ListHead) {
|
|
Thread = CONTAINING_RECORD( ListNext, CSR_THREAD, Link );
|
|
NtSuspendThread(Thread->ThreadHandle,NULL);
|
|
ListNext = ListNext->Flink;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
CsrResumeProcess(
|
|
IN PCSR_PROCESS Process
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This procedure is called when doing a debug attach to resume all
|
|
threads within the effected process.
|
|
|
|
Arguments:
|
|
|
|
Process - Supplies the address of the process to resume.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PLIST_ENTRY ListHead, ListNext;
|
|
PCSR_THREAD Thread;
|
|
NTSTATUS Status;
|
|
|
|
if ( Process == CsrDebugProcessPtr ) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Now walk through the processes thread list and
|
|
// suspend all of its threads.
|
|
//
|
|
|
|
ListHead = &Process->ThreadList;
|
|
ListNext = ListHead->Flink;
|
|
while (ListNext != ListHead) {
|
|
Thread = CONTAINING_RECORD( ListNext, CSR_THREAD, Link );
|
|
NtResumeThread(Thread->ThreadHandle,NULL);
|
|
ListNext = ListNext->Flink;
|
|
}
|
|
}
|
|
|
|
PCSR_PROCESS
|
|
CsrInitializeCsrDebugProcess(
|
|
PCSR_PROCESS TargetProcess
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called to build a side process tree to use when
|
|
doing debug attaches.
|
|
|
|
After the attach completes, this structure is torn down.
|
|
|
|
Arguments:
|
|
|
|
Process - Supplies the address of the process to attach to. A value of
|
|
NULL indicates CSR.
|
|
|
|
Return Value:
|
|
|
|
Returns the address of the dummy CSR process.
|
|
|
|
--*/
|
|
|
|
{
|
|
PCSR_PROCESS Process;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
PCSR_THREAD Thread;
|
|
PLIST_ENTRY ProcessListHead, ProcessListNext;
|
|
PLIST_ENTRY ThreadListHead, ThreadListNext;
|
|
PCSR_THREAD ThreadPtr;
|
|
PCSR_PROCESS ProcessPtr;
|
|
THREAD_BASIC_INFORMATION BasicInfo;
|
|
NTSTATUS Status;
|
|
PCSR_THREAD ServerThread;
|
|
|
|
Process = RtlAllocateHeap(RtlProcessHeap(),MAKE_TAG( PROCESS_TAG ),sizeof(*Process));
|
|
if (!Process) {
|
|
return NULL;
|
|
}
|
|
|
|
if ( TargetProcess == NULL ) {
|
|
CsrDebugProcessPtr = Process;
|
|
InitializeListHead(&Process->ThreadList);
|
|
Process->ClientId = NtCurrentTeb()->ClientId;
|
|
|
|
InitializeObjectAttributes(
|
|
&Obja,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
Status = NtOpenProcess(
|
|
&Process->ProcessHandle,
|
|
PROCESS_ALL_ACCESS,
|
|
&Obja,
|
|
&Process->ClientId
|
|
);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
RtlFreeHeap(RtlProcessHeap(),0,Process);
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Compute the threads. This is cumbersome. First we have to
|
|
// locate the static threads, then walk through the entire structure
|
|
// looking for threads with associated server threads.
|
|
//
|
|
|
|
ThreadListHead = &CsrRootProcess->ThreadList;
|
|
ThreadListNext = ThreadListHead->Flink;
|
|
while (ThreadListNext != ThreadListHead) {
|
|
ServerThread = CONTAINING_RECORD( ThreadListNext, CSR_THREAD, Link );
|
|
Thread = RtlAllocateHeap(RtlProcessHeap(),MAKE_TAG( PROCESS_TAG ),sizeof(*Thread));
|
|
if ( Thread ) {
|
|
Thread->ClientId = ServerThread->ClientId;
|
|
Thread->ThreadHandle = ServerThread->ThreadHandle;
|
|
InsertTailList( &Process->ThreadList, &Thread->Link );
|
|
}
|
|
ThreadListNext = ThreadListNext->Flink;
|
|
}
|
|
|
|
}
|
|
else {
|
|
|
|
//
|
|
// Regular non-csr process attach... Just copy the thread and
|
|
// process to a new set of structures
|
|
//
|
|
|
|
InitializeListHead(&Process->ThreadList);
|
|
Process->ClientId = TargetProcess->ClientId;
|
|
Process->ProcessHandle = TargetProcess->ProcessHandle;
|
|
|
|
ThreadListHead = &TargetProcess->ThreadList;
|
|
ThreadListNext = ThreadListHead->Flink;
|
|
while (ThreadListNext != ThreadListHead) {
|
|
ThreadPtr = CONTAINING_RECORD( ThreadListNext, CSR_THREAD, Link );
|
|
Thread = RtlAllocateHeap(RtlProcessHeap(),MAKE_TAG( PROCESS_TAG ),sizeof(*Thread));
|
|
if ( Thread ) {
|
|
Thread->ThreadHandle = ThreadPtr->ThreadHandle;
|
|
Thread->ClientId = ThreadPtr->ClientId;
|
|
InsertTailList( &Process->ThreadList, &Thread->Link );
|
|
}
|
|
ThreadListNext = ThreadListNext->Flink;
|
|
}
|
|
}
|
|
return Process;
|
|
}
|
|
|
|
VOID
|
|
CsrTeardownCsrDebugProcess(
|
|
PCSR_PROCESS TargetProcess
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called after a debug attach to
|
|
a process is complete
|
|
|
|
It's purpose is to tear down the structure created in the
|
|
initialization phase.
|
|
|
|
Arguments:
|
|
|
|
TargetProcess - Supplies the address of the process to teardown.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PCSR_PROCESS Process;
|
|
PLIST_ENTRY ThreadListHead, ThreadListNext;
|
|
PCSR_THREAD ThreadPtr;
|
|
NTSTATUS Status;
|
|
|
|
if ( TargetProcess == CsrDebugProcessPtr ) {
|
|
CsrDebugProcessPtr = (PCSR_PROCESS)-1;
|
|
}
|
|
Process = TargetProcess;
|
|
|
|
|
|
ThreadListHead = &Process->ThreadList;
|
|
ThreadListNext = ThreadListHead->Flink;
|
|
while (ThreadListNext != ThreadListHead) {
|
|
ThreadPtr = CONTAINING_RECORD( ThreadListNext, CSR_THREAD, Link );
|
|
ThreadListNext = ThreadListNext->Flink;
|
|
RemoveEntryList(&ThreadPtr->Link);
|
|
RtlFreeHeap(RtlProcessHeap(),0,ThreadPtr);
|
|
}
|
|
|
|
RtlFreeHeap(RtlProcessHeap(),0,Process);
|
|
}
|