Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468/* * PROJECT: ReactOS system libraries * LICENSE: GPL-2.0 (https://spdx.org/licenses/GPL-2.0) * PURPOSE: RTL_DEBUG_INFORMATION implementation * COPYRIGHT: Copyright James Tabor * Copyright 2020 Mark Jansen (mark.jansen@reactos.org) */
/* INCLUDES *****************************************************************/
#include <rtl.h>
#define NDEBUG#include <debug.h>
/* FUNCTIONS *****************************************************************/
PVOIDNTAPIRtlpDebugBufferCommit(_Inout_ PRTL_DEBUG_INFORMATION Buffer, _In_ SIZE_T Size){ ULONG Remaining = Buffer->CommitSize - Buffer->OffsetFree; PVOID Result; NTSTATUS Status;
if (Size > MAXLONG) return NULL;
if (Remaining < Size) { PVOID Buf; SIZE_T CommitSize;
Buf = (PVOID)((ULONG_PTR)Buffer->ViewBaseClient + Buffer->CommitSize); CommitSize = Size - Remaining;
/* this is not going to end well.. */ if (CommitSize > MAXLONG) return NULL;
Status = NtAllocateVirtualMemory(NtCurrentProcess(), (PVOID*)&Buf, 0, &CommitSize, MEM_COMMIT, PAGE_READWRITE); if (!NT_SUCCESS(Status)) return NULL;
Buffer->CommitSize += CommitSize; Remaining = Buffer->CommitSize - Buffer->OffsetFree; /* Sanity check */ ASSERT(Remaining >= Size); if (Remaining < Size) return NULL; }
Result = (PBYTE)Buffer->ViewBaseClient + Buffer->OffsetFree; Buffer->OffsetFree += Size;
return Result;}
/* * @unimplemented */PRTL_DEBUG_INFORMATIONNTAPIRtlCreateQueryDebugBuffer(_In_ ULONG Size, _In_ BOOLEAN EventPair){ NTSTATUS Status; PRTL_DEBUG_INFORMATION Buf = NULL; SIZE_T AllocationSize = Size ? Size : 0x400 * PAGE_SIZE; SIZE_T CommitSize = sizeof(*Buf);
/* Reserve the memory */ Status = NtAllocateVirtualMemory(NtCurrentProcess(), (PVOID*)&Buf, 0, &AllocationSize, MEM_RESERVE, PAGE_READWRITE); if (!NT_SUCCESS(Status)) return NULL;
/* Commit the first data, CommitSize is updated with the actual committed data */ Status = NtAllocateVirtualMemory(NtCurrentProcess(), (PVOID*)&Buf, 0, &CommitSize, MEM_COMMIT, PAGE_READWRITE); if (!NT_SUCCESS(Status)) { RtlDestroyQueryDebugBuffer(Buf); return NULL; }
/* Fill out the minimum data required */ Buf->ViewBaseClient = Buf; Buf->ViewSize = (ULONG)AllocationSize; Buf->CommitSize = CommitSize; Buf->OffsetFree = sizeof(*Buf);
return Buf;}
/* * @unimplemented */NTSTATUSNTAPIRtlDestroyQueryDebugBuffer(_In_ PRTL_DEBUG_INFORMATION Buf){ NTSTATUS Status = STATUS_SUCCESS; SIZE_T ViewSize = 0;
if (NULL != Buf) { Status = NtFreeVirtualMemory(NtCurrentProcess(), (PVOID*)&Buf, &ViewSize, MEM_RELEASE); } if (!NT_SUCCESS(Status)) { DPRINT1("RtlDQDB: Failed to free VM!\n"); } return Status;}
/* * Based on lib/epsapi/enum/modules.c by KJK::Hyperion. */NTSTATUSNTAPIRtlpQueryRemoteProcessModules(HANDLE ProcessHandle, IN PRTL_PROCESS_MODULES Modules OPTIONAL, IN ULONG Size OPTIONAL, OUT PULONG ReturnedSize){ PROCESS_BASIC_INFORMATION pbiInfo; PPEB_LDR_DATA ppldLdrData; LDR_DATA_TABLE_ENTRY lmModule; PLIST_ENTRY pleListHead; PLIST_ENTRY pleCurEntry;
PRTL_PROCESS_MODULE_INFORMATION ModulePtr = NULL; NTSTATUS Status = STATUS_SUCCESS; ULONG UsedSize = sizeof(ULONG); ANSI_STRING AnsiString; PCHAR p;
DPRINT("RtlpQueryRemoteProcessModules Start\n");
/* query the process basic information (includes the PEB address) */ Status = NtQueryInformationProcess(ProcessHandle, ProcessBasicInformation, &pbiInfo, sizeof(PROCESS_BASIC_INFORMATION), NULL);
if (!NT_SUCCESS(Status)) { /* failure */ DPRINT("NtQueryInformationProcess 1 0x%lx\n", Status); return Status; }
if (Modules == NULL || Size == 0) { Status = STATUS_INFO_LENGTH_MISMATCH; } else { Modules->NumberOfModules = 0; ModulePtr = &Modules->Modules[0]; Status = STATUS_SUCCESS; }
/* get the address of the PE Loader data */ Status = NtReadVirtualMemory(ProcessHandle, &(pbiInfo.PebBaseAddress->Ldr), &ppldLdrData, sizeof(ppldLdrData), NULL);
if (!NT_SUCCESS(Status)) { /* failure */ DPRINT("NtReadVirtualMemory 1 0x%lx\n", Status); return Status; }
/* head of the module list: the last element in the list will point to this */ pleListHead = &ppldLdrData->InLoadOrderModuleList;
/* get the address of the first element in the list */ Status = NtReadVirtualMemory(ProcessHandle, &(ppldLdrData->InLoadOrderModuleList.Flink), &pleCurEntry, sizeof(pleCurEntry), NULL);
if (!NT_SUCCESS(Status)) { /* failure */ DPRINT("NtReadVirtualMemory 2 0x%lx\n", Status); return Status; }
while(pleCurEntry != pleListHead) { UNICODE_STRING Unicode; WCHAR Buffer[256 * sizeof(WCHAR)];
/* read the current module */ Status = NtReadVirtualMemory(ProcessHandle, CONTAINING_RECORD(pleCurEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks), &lmModule, sizeof(LDR_DATA_TABLE_ENTRY), NULL);
if (!NT_SUCCESS(Status)) { /* failure */ DPRINT( "NtReadVirtualMemory 3 0x%lx\n", Status); return Status; }
/* Import module name from remote Process user space. */ Unicode.Length = lmModule.FullDllName.Length; Unicode.MaximumLength = lmModule.FullDllName.MaximumLength; Unicode.Buffer = Buffer;
Status = NtReadVirtualMemory(ProcessHandle, lmModule.FullDllName.Buffer, Unicode.Buffer, Unicode.Length, NULL);
if (!NT_SUCCESS(Status)) { /* failure */ DPRINT( "NtReadVirtualMemory 3 0x%lx\n", Status); return Status; }
DPRINT(" Module %wZ\n", &Unicode);
if (UsedSize > Size) { Status = STATUS_INFO_LENGTH_MISMATCH; } else if (Modules != NULL) { ModulePtr->Section = 0; ModulePtr->MappedBase = NULL; // FIXME: ?? ModulePtr->ImageBase = lmModule.DllBase; ModulePtr->ImageSize = lmModule.SizeOfImage; ModulePtr->Flags = lmModule.Flags; ModulePtr->LoadOrderIndex = 0; // FIXME: ?? ModulePtr->InitOrderIndex = 0; // FIXME: ?? ModulePtr->LoadCount = lmModule.LoadCount;
AnsiString.Length = 0; AnsiString.MaximumLength = 256; AnsiString.Buffer = ModulePtr->FullPathName; RtlUnicodeStringToAnsiString(&AnsiString, &Unicode, FALSE);
p = strrchr(ModulePtr->FullPathName, '\\'); if (p != NULL) ModulePtr->OffsetToFileName = (USHORT)(p - ModulePtr->FullPathName + 1); else ModulePtr->OffsetToFileName = 0;
ModulePtr++; Modules->NumberOfModules++; } UsedSize += sizeof(RTL_PROCESS_MODULE_INFORMATION);
/* address of the next module in the list */ pleCurEntry = lmModule.InLoadOrderLinks.Flink; }
if (ReturnedSize != 0) *ReturnedSize = UsedSize;
DPRINT("RtlpQueryRemoteProcessModules End\n");
/* success */ return (STATUS_SUCCESS);}
/* * @unimplemented */NTSTATUSNTAPIRtlQueryProcessDebugInformation(IN ULONG ProcessId, IN ULONG DebugInfoMask, IN OUT PRTL_DEBUG_INFORMATION Buf){ NTSTATUS Status = STATUS_SUCCESS; ULONG Pid = (ULONG)(ULONG_PTR) NtCurrentTeb()->ClientId.UniqueProcess;
Buf->Flags = DebugInfoMask; Buf->OffsetFree = sizeof(RTL_DEBUG_INFORMATION);
DPRINT("QueryProcessDebugInformation Start\n");
/* Currently ROS can not read-only from kenrel space, and doesn't check for boundaries inside kernel space that are page protected from every one but the kernel. aka page 0 - 2 */ if (ProcessId <= 1) { Status = STATUS_ACCESS_VIOLATION; } else if (Pid == ProcessId) { if (DebugInfoMask & RTL_DEBUG_QUERY_MODULES) { PRTL_PROCESS_MODULES Mp; ULONG ReturnSize = 0;
/* I like this better than the do & while loop. */ Status = LdrQueryProcessModuleInformation(NULL, 0, &ReturnSize);
Mp = RtlpDebugBufferCommit(Buf, ReturnSize); if (!Mp) { DPRINT1("RtlQueryProcessDebugInformation: Unable to commit %u\n", ReturnSize); }
Status = LdrQueryProcessModuleInformation(Mp, ReturnSize, &ReturnSize); if (!NT_SUCCESS(Status)) { return Status; }
Buf->Modules = Mp; }
if (DebugInfoMask & RTL_DEBUG_QUERY_HEAPS) { PRTL_PROCESS_HEAPS Hp; ULONG HSize;
Hp = (PRTL_PROCESS_HEAPS)((PUCHAR)Buf + Buf->OffsetFree); HSize = sizeof(RTL_PROCESS_HEAPS); if (DebugInfoMask & RTL_DEBUG_QUERY_HEAP_TAGS) { // TODO } if (DebugInfoMask & RTL_DEBUG_QUERY_HEAP_BLOCKS) { // TODO } Buf->Heaps = Hp; Buf->OffsetFree = Buf->OffsetFree + HSize;
}
if (DebugInfoMask & RTL_DEBUG_QUERY_LOCKS) { PRTL_PROCESS_LOCKS Lp; ULONG LSize;
Lp = (PRTL_PROCESS_LOCKS)((PUCHAR)Buf + Buf->OffsetFree); LSize = sizeof(RTL_PROCESS_LOCKS); Buf->Locks = Lp; Buf->OffsetFree = Buf->OffsetFree + LSize; }
DPRINT("QueryProcessDebugInformation end\n"); DPRINT("QueryDebugInfo : 0x%lx\n", Buf->OffsetFree); } else { HANDLE hProcess; CLIENT_ID ClientId; OBJECT_ATTRIBUTES ObjectAttributes;
Buf->TargetProcessHandle = NtCurrentProcess();
ClientId.UniqueThread = 0; ClientId.UniqueProcess = (HANDLE)(ULONG_PTR)ProcessId; InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
Status = NtOpenProcess(&hProcess, (PROCESS_ALL_ACCESS), &ObjectAttributes, &ClientId ); if (!NT_SUCCESS(Status)) { return Status; }
if (DebugInfoMask & RTL_DEBUG_QUERY_MODULES) { PRTL_PROCESS_MODULES Mp; ULONG ReturnSize = 0;
Status = RtlpQueryRemoteProcessModules(hProcess, NULL, 0, &ReturnSize);
Mp = RtlpDebugBufferCommit(Buf, ReturnSize); if (!Mp) { DPRINT1("RtlQueryProcessDebugInformation: Unable to commit %u\n", ReturnSize); }
Status = RtlpQueryRemoteProcessModules(hProcess, Mp, ReturnSize , &ReturnSize); if (!NT_SUCCESS(Status)) { return Status; }
Buf->Modules = Mp; }
if (DebugInfoMask & RTL_DEBUG_QUERY_HEAPS) { PRTL_PROCESS_HEAPS Hp; ULONG HSize;
Hp = (PRTL_PROCESS_HEAPS)((PUCHAR)Buf + Buf->OffsetFree); HSize = sizeof(RTL_PROCESS_HEAPS); if (DebugInfoMask & RTL_DEBUG_QUERY_HEAP_TAGS) { // TODO } if (DebugInfoMask & RTL_DEBUG_QUERY_HEAP_BLOCKS) { // TODO } Buf->Heaps = Hp; Buf->OffsetFree = Buf->OffsetFree + HSize;
}
if (DebugInfoMask & RTL_DEBUG_QUERY_LOCKS) { PRTL_PROCESS_LOCKS Lp; ULONG LSize;
Lp = (PRTL_PROCESS_LOCKS)((PUCHAR)Buf + Buf->OffsetFree); LSize = sizeof(RTL_PROCESS_LOCKS); Buf->Locks = Lp; Buf->OffsetFree = Buf->OffsetFree + LSize; }
DPRINT("QueryProcessDebugInformation end\n"); DPRINT("QueryDebugInfo : 0x%lx\n", Buf->OffsetFree); }
return Status;}
/* EOL */