|
|
/*++
Copyright (c) 1999-2002 Microsoft Corporation
Module Name:
nt4.c
Abstract:
NT 4 specific routines.
The following routine are exported from this file:
o Nt4OpenThread
o Nt4GetProcessInfo
o Nt4EnumProcessModules
o Nt4GetModuleFileNameExW
Author:
Matthew D Hendel (math) 10-Sept-1999
Revision History:
Environment:
NT 4.0 only. --*/
#include "pch.h"
#include "ntx.h"
#include "nt4.h"
#include "nt4p.h"
#include "impl.h"
BOOL WINAPI Nt4EnumProcessModules( HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded );
HANDLE WINAPI Nt4OpenThread( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId ) { NTSTATUS Status; NT4_OBJECT_ATTRIBUTES Obja; HANDLE Handle; NT4_CLIENT_ID ClientId;
ClientId.UniqueThread = (HANDLE)LongToHandle(dwThreadId); ClientId.UniqueProcess = (HANDLE)NULL;
Nt4InitializeObjectAttributes( &Obja, NULL, (bInheritHandle ? NT4_OBJ_INHERIT : 0), NULL, NULL );
Status = NtOpenThread( &Handle, (ACCESS_MASK)dwDesiredAccess, (POBJECT_ATTRIBUTES)&Obja, (PCLIENT_ID)&ClientId ); if ( NT_SUCCESS(Status) ) { return Handle; } else { return NULL; } }
BOOL Nt4GetProcessInfo( IN HANDLE hProcess, IN ULONG ProcessId, IN ULONG DumpType, IN MINIDUMP_CALLBACK_ROUTINE CallbackRoutine, IN PVOID CallbackParam, OUT PINTERNAL_PROCESS * ProcessRet ) { BOOL Succ; ULONG i; NTSTATUS Status; ULONG BufferSize; LPVOID Buffer; PNT4_SYSTEM_PROCESS_INFORMATION ProcessInfo; PNT4_SYSTEM_THREAD_INFORMATION ThreadInfo; PINTERNAL_THREAD Thread; PINTERNAL_MODULE Module; PINTERNAL_PROCESS Process; HMODULE Modules [ 512 ]; ULONG ModulesSize; ULONG NumberOfModules; ULONG_PTR Next;
BufferSize = 64 * KBYTE; Buffer = NULL;
do {
if (Buffer) { FreeMemory (Buffer); } Buffer = AllocMemory ( BufferSize );
if ( Buffer == NULL) { return FALSE; } Status = NtQuerySystemInformation ( Nt4SystemProcessInformation, Buffer, BufferSize, NULL );
if (!NT_SUCCESS (Status) && Status != STATUS_INFO_LENGTH_MISMATCH) { GenAccumulateStatus(MDSTATUS_CALL_FAILED); return FALSE; }
BufferSize += (8 * KBYTE);
} while (Status == STATUS_INFO_LENGTH_MISMATCH);
//
// Find the correct process in the process list.
//
ProcessInfo = (PNT4_SYSTEM_PROCESS_INFORMATION) Buffer;
while (ProcessInfo->NextEntryOffset && ProcessInfo->UniqueProcessId != (HANDLE) ProcessId) {
Next = ((ULONG_PTR)ProcessInfo + ProcessInfo->NextEntryOffset); ProcessInfo = (PNT4_SYSTEM_PROCESS_INFORMATION) Next; }
//
// Could not find a matching process in the process list.
//
if (ProcessInfo->UniqueProcessId != (HANDLE) ProcessId) { Succ = FALSE; GenAccumulateStatus(MDSTATUS_INTERNAL_ERROR); goto Exit; }
//
// Create an INTERNAL_PROCESS object and copy the process information
// into it.
//
Process = GenAllocateProcessObject ( hProcess, ProcessId ); if ( Process == NULL ) { return FALSE; }
//
// Walk the thread list for this process, copying thread information
// for each thread. Walking the thread list also suspends all the threads
// in the process. This should be done before walking the module list
// to minimize the number of race conditions.
//
ThreadInfo = (PNT4_SYSTEM_THREAD_INFORMATION)(ProcessInfo + 1); Process->NumberOfThreads = 0;
for (i = 0; i < ProcessInfo->NumberOfThreads; i++) {
ULONG WriteFlags;
if (!GenExecuteIncludeThreadCallback(hProcess, ProcessId, DumpType, (ULONG)ThreadInfo->ClientId.UniqueThread, CallbackRoutine, CallbackParam, &WriteFlags) || IsFlagClear(WriteFlags, ThreadWriteThread)) { ThreadInfo++; continue; } Status = GenAllocateThreadObject ( Process, hProcess, (ULONG) ThreadInfo->ClientId.UniqueThread, DumpType, WriteFlags, &Thread ); if (FAILED(Status)) { Succ = FALSE; goto Exit; }
// If Status is S_FALSE it means that the thread
// couldn't be opened and probably exited before
// we got to it. Just continue on.
if (Status == S_OK) { InsertTailList (&Process->ThreadList, &Thread->ThreadsLink); Process->NumberOfThreads++; } ThreadInfo++; }
//
// Get the module information. Use PSAPI since it actually works.
//
ModulesSize = 0; Succ = Nt4EnumProcessModules ( Process->ProcessHandle, Modules, sizeof (Modules), &ModulesSize ); if ( !Succ ) { GenAccumulateStatus(MDSTATUS_CALL_FAILED); goto Exit; }
NumberOfModules = ModulesSize / sizeof (HMODULE); for (i = 0; i < NumberOfModules; i++) { ULONG WriteFlags;
if (!GenExecuteIncludeModuleCallback(hProcess, ProcessId, DumpType, (LONG_PTR)Modules[i], CallbackRoutine, CallbackParam, &WriteFlags) || IsFlagClear(WriteFlags, ModuleWriteModule)) { continue; }
Module = NtxAllocateModuleObject ( Process, Process->ProcessHandle, (LONG_PTR) Modules [ i ], DumpType, WriteFlags, NULL );
if ( Module == NULL ) { Succ = FALSE; goto Exit; } InsertTailList (&Process->ModuleList, &Module->ModulesLink); }
Process->NumberOfModules = NumberOfModules;
Succ = TRUE;
Exit:
if ( Buffer ) { FreeMemory ( Buffer ); Buffer = NULL; } if ( !Succ && Process != NULL ) { GenFreeProcessObject ( Process ); Process = NULL; } *ProcessRet = Process;
return Succ; }
//
// From PSAPI
//
BOOL Nt4FindModule( IN HANDLE hProcess, IN HMODULE hModule, OUT PNT4_LDR_DATA_TABLE_ENTRY LdrEntryData )
/*++
Routine Description:
This function retrieves the loader table entry for the specified module. The function copies the entry into the buffer pointed to by the LdrEntryData parameter.
Arguments:
hProcess - Supplies the target process.
hModule - Identifies the module whose loader entry is being requested. A value of NULL references the module handle associated with the image file that was used to create the process.
LdrEntryData - Returns the requested table entry.
Return Value:
TRUE if a matching entry was found.
--*/
{ NT4_PROCESS_BASIC_INFORMATION BasicInfo; NTSTATUS Status; PNT4_PEB Peb; PNT4_PEB_LDR_DATA Ldr; PLIST_ENTRY LdrHead; PLIST_ENTRY LdrNext;
Status = NtQueryInformationProcess( hProcess, Nt4ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL );
if ( !NT_SUCCESS(Status) ) { return(FALSE); }
Peb = BasicInfo.PebBaseAddress;
if ( hModule == NULL ) { if (!ReadProcessMemory(hProcess, &Peb->ImageBaseAddress, &hModule, sizeof(hModule), NULL)) { return(FALSE); } }
//
// Ldr = Peb->Ldr
//
if (!ReadProcessMemory(hProcess, &Peb->Ldr, &Ldr, sizeof(Ldr), NULL)) { return (FALSE); }
if (!Ldr) { // Ldr might be null (for instance, if the process hasn't started yet).
SetLastError(ERROR_INVALID_HANDLE); return (FALSE); }
LdrHead = &Ldr->InMemoryOrderModuleList;
//
// LdrNext = Head->Flink;
//
if (!ReadProcessMemory(hProcess, &LdrHead->Flink, &LdrNext, sizeof(LdrNext), NULL)) { return(FALSE); }
while (LdrNext != LdrHead) {
PNT4_LDR_DATA_TABLE_ENTRY LdrEntry;
LdrEntry = CONTAINING_RECORD( LdrNext, NT4_LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
if (!ReadProcessMemory(hProcess, LdrEntry, LdrEntryData, sizeof(*LdrEntryData), NULL)) { return(FALSE); }
if ((HMODULE) LdrEntryData->DllBase == hModule) { return(TRUE); }
LdrNext = LdrEntryData->InMemoryOrderLinks.Flink; }
SetLastError(ERROR_INVALID_HANDLE); return(FALSE); }
BOOL WINAPI Nt4EnumProcessModules( HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded ) { NT4_PROCESS_BASIC_INFORMATION BasicInfo; NTSTATUS Status; PNT4_PEB Peb; PNT4_PEB_LDR_DATA Ldr; PLIST_ENTRY LdrHead; PLIST_ENTRY LdrNext; DWORD chMax; DWORD ch;
Status = NtQueryInformationProcess( hProcess, Nt4ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL );
if ( !NT_SUCCESS(Status) ) { return(FALSE); }
Peb = BasicInfo.PebBaseAddress;
//
// Ldr = Peb->Ldr
//
if (!ReadProcessMemory(hProcess, &Peb->Ldr, &Ldr, sizeof(Ldr), NULL)) { return(FALSE); }
LdrHead = &Ldr->InMemoryOrderModuleList;
//
// LdrNext = Head->Flink;
//
if (!ReadProcessMemory(hProcess, &LdrHead->Flink, &LdrNext, sizeof(LdrNext), NULL)) { return(FALSE); }
chMax = cb / sizeof(HMODULE); ch = 0;
while (LdrNext != LdrHead) { PNT4_LDR_DATA_TABLE_ENTRY LdrEntry; NT4_LDR_DATA_TABLE_ENTRY LdrEntryData;
LdrEntry = CONTAINING_RECORD( LdrNext, NT4_LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
if (!ReadProcessMemory(hProcess, LdrEntry, &LdrEntryData, sizeof(LdrEntryData), NULL)) { return(FALSE); }
if (ch < chMax) { try { lphModule[ch] = (HMODULE) LdrEntryData.DllBase; } except (EXCEPTION_EXECUTE_HANDLER) { return(FALSE); } }
ch++;
LdrNext = LdrEntryData.InMemoryOrderLinks.Flink; }
try { *lpcbNeeded = ch * sizeof(HMODULE); } except (EXCEPTION_EXECUTE_HANDLER) { return(FALSE); }
return(TRUE); }
DWORD WINAPI Nt4GetModuleFileNameExW( HANDLE hProcess, HMODULE hModule, LPWSTR lpFilename, DWORD nSize )
/*++
Routine Description:
This function retrieves the full pathname of the executable file from which the specified module was loaded. The function copies the null-terminated filename into the buffer pointed to by the lpFilename parameter.
Routine Description:
hModule - Identifies the module whose executable file name is being requested. A value of NULL references the module handle associated with the image file that was used to create the process.
lpFilename - Points to the buffer that is to receive the filename.
nSize - Specifies the maximum number of characters to copy. If the filename is longer than the maximum number of characters specified by the nSize parameter, it is truncated.
Return Value:
The return value specifies the actual length of the string copied to the buffer. A return value of zero indicates an error and extended error status is available using the GetLastError function.
Arguments:
--*/
{ NT4_LDR_DATA_TABLE_ENTRY LdrEntryData; DWORD cb;
if (!Nt4FindModule(hProcess, hModule, &LdrEntryData)) { return(0); }
nSize *= sizeof(WCHAR);
cb = LdrEntryData.FullDllName.MaximumLength; if ( nSize < cb ) { cb = nSize; }
if (!ReadProcessMemory(hProcess, LdrEntryData.FullDllName.Buffer, lpFilename, cb, NULL)) { return(0); }
if (cb == LdrEntryData.FullDllName.MaximumLength) { cb -= sizeof(WCHAR); }
return(cb / sizeof(WCHAR)); }
|