windows-nt/Source/XPSP1/NT/base/win32/client/toolhelp.c
2020-09-26 16:20:57 +08:00

2045 lines
57 KiB
C

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
tlhelp32.c
Abstract:
NT implementation of win95 ToolHelp API's
Author:
John Daly
Environment:
NT Only
Notes:
Version 1.0
structure definitions/documentation in tlhelp32.h
Revision History:
John Daly (johndaly) 5-Apr-1996
initial implementation
--*/
#include "basedll.h"
#pragma hdrstop
#include "tlhelp32.h"
#define BUFFER_SIZE 64*1024
#define ARRAYSIZE(x) (sizeof(x) / sizeof(x[0]))
/*
snapshot structure
This is mapped onto the beginning of the memory we use to hold the information.
*/
typedef struct tagSNAPSHOTSTATE {
/* item list counts */
ULONG HeapListCount;
ULONG ProcessCount;
ULONG ModuleCount;
ULONG ThreadCount;
/* item list head pointers */
PHEAPLIST32 HeapListHead;
PPROCESSENTRY32W ProcessListHead;
PMODULEENTRY32W ModuleListHead;
PTHREADENTRY32 ThreadListHead;
/* item list current indexes */
ULONG HeapListIndex;
ULONG ProcessListIndex;
ULONG ModuleListIndex;
ULONG ThreadListIndex;
/* data begins here... */
UCHAR DataBegin;
}SNAPSHOTSTATE;
typedef SNAPSHOTSTATE * PSNAPSHOTSTATE;
//
// private functions
//
NTSTATUS
ThpCreateRawSnap(
IN ULONG dwFlags,
IN ULONG th32ProcessID,
PUCHAR *RawProcess,
PRTL_DEBUG_INFORMATION *RawModule,
PRTL_DEBUG_INFORMATION *RawDebugInfo);
NTSTATUS
ThpAllocateSnapshotSection(
OUT PHANDLE SnapSection,
IN DWORD dwFlags,
IN DWORD th32ProcessID,
PUCHAR RawProcess,
PRTL_DEBUG_INFORMATION RawModule,
PRTL_DEBUG_INFORMATION RawDebugInfo);
NTSTATUS
ThpProcessToSnap(
IN DWORD dwFlags,
IN DWORD th32ProcessID,
IN HANDLE SnapSection,
PUCHAR RawProcess,
PRTL_DEBUG_INFORMATION RawModule,
PRTL_DEBUG_INFORMATION RawDebugInfo);
HANDLE
WINAPI
CreateToolhelp32Snapshot(
IN DWORD dwFlags,
IN DWORD th32ProcessID)
/*++
Routine Description:
Takes a snapshot of the Win32 processes, heaps, modules, and threads used
by the Win32 processes. Returns an open handle to the specified snapshot if
successful or -1 otherwise.
NOTE that all of the snapshots are global except for the heap and module
lists which are process specific. To enumerate the heap or module state for
all WIN32 processes call with TH32CS_SNAPALL and the current process. Then
for each process in the TH32CS_SNAPPROCESS list that isn't the current
process, do a call with just TH32CS_SNAPHEAPLIST and/or TH32CS_SNAPMODULE.
Use CloseHandle to destroy the snapshot
This function is not multi-thread safe. All of the other functions are.
Arguments:
dwFlags - Supplies switches to specify action as follows:
TH32CS_INHERIT Indicates that the snapshot handle is to be inheritable.
TH32CS_SNAPALL Equivalent to specifying the TH32CS_SNAPHEAPLIST,
TH32CS_SNAPMODULE, TH32CS_SNAPPROCESS, and
TH32CS_SNAPTHREAD values.
TH32CS_SNAPHEAPLIST Includes the heap list of the specified Win32
process in the snapshot.
TH32CS_SNAPMODULE Includes the module list of the specified Win32
process in the snapshot.
TH32CS_SNAPPROCESS Includes the Win32 process list in the snapshot.
TH32CS_SNAPTHREAD Includes the Win32 thread list in the snapshot.
th32ProcessID - Supplies a Win32 process identifier. This parameter can be
zero to indicate the current process. This parameter is used when the
TH32CS_SNAPHEAPLIST or TH32CS_SNAPMODULE value is specified. Otherwise,
it is ignored. The snapshot taken by this function is examined by the
other tool help functions to provide their results. Access to the
snapshot is read only. The snapshot handle acts like a Win32 object
handle and is subject to the same rules regarding which processes and
threads it is valid in.
Return Value:
Returns an open handle to the specified snapshot if successful or -1 if not.
To retrieve an extended error status code generated by this function, use
the GetLastError function.
To destroy the snapshot, use the CloseHandle function.
--*/
{
HANDLE SnapSection;
PUCHAR RawProcess;
PRTL_DEBUG_INFORMATION RawModule;
PRTL_DEBUG_INFORMATION RawDebugInfo;
NTSTATUS Status = 0;
if (th32ProcessID == 0) {
th32ProcessID = GetCurrentProcessId();
}
//
// process the requested data types
//
Status = ThpCreateRawSnap(dwFlags,
th32ProcessID,
&RawProcess,
&RawModule,
&RawDebugInfo);
if (!NT_SUCCESS(Status)) {
BaseSetLastNTError(Status);
return (HANDLE)-1;
}
Status = ThpAllocateSnapshotSection(&SnapSection,
dwFlags,
th32ProcessID,
RawProcess,
RawModule,
RawDebugInfo);
if (!NT_SUCCESS(Status)) {
BaseSetLastNTError(Status);
return (HANDLE)-1;
}
Status = ThpProcessToSnap(dwFlags,
th32ProcessID,
SnapSection,
RawProcess,
RawModule,
RawDebugInfo);
if (!NT_SUCCESS(Status)) {
CloseHandle(SnapSection);
BaseSetLastNTError(Status);
return (HANDLE)-1;
}
return SnapSection;
}
BOOL
WINAPI
Heap32ListFirst(
IN HANDLE SnapSection,
IN OUT LPHEAPLIST32 lphl)
/*++
Routine Description:
Retrieves information about the first heap that has been allocated by a
specified Win32 process.
Arguments:
SnapSection - Supplies the handle of the snapshot returned from a previous
call to the CreateToolhelp32Snapshot function.
lphl - Returns a HEAPLIST32 structure. The calling application must set
the dwSize member of HEAPLIST32 to the size, in bytes, of the structure.
Return Value:
Returns TRUE if the first entry of the heap list has been copied to the buffer
or FALSE otherwise. The ERROR_NO_MORE_FILES error value is returned by the
GetLastError function when no heap list exists or the snapshot does not contain
heap list information.
--*/
{
PSNAPSHOTSTATE SnapshotBase;
LARGE_INTEGER SectionOffset;
SIZE_T ViewSize;
NTSTATUS Status = 0;
BOOL retv = FALSE;
if (!lphl || lphl->dwSize != sizeof(HEAPLIST32)) {
BaseSetLastNTError(STATUS_INFO_LENGTH_MISMATCH);
return FALSE;
}
SectionOffset.LowPart = 0;
SectionOffset.HighPart = 0;
ViewSize = 0;
SnapshotBase = 0;
Status = NtMapViewOfSection(SnapSection,
NtCurrentProcess(),
&SnapshotBase,
0L,
0L,
&SectionOffset,
&ViewSize,
ViewShare,
0L,
PAGE_READWRITE);
if (!NT_SUCCESS(Status)) {
BaseSetLastNTError(Status);
return FALSE;
}
if (SnapshotBase->HeapListCount == 0) {
RtlZeroMemory((PUCHAR)lphl + sizeof(SIZE_T), (lphl->dwSize - sizeof(SIZE_T)));
SetLastError(ERROR_NO_MORE_FILES);
} else {
memcpy(lphl,
(LPHEAPLIST32)((ULONG_PTR)SnapshotBase + (ULONG_PTR)SnapshotBase->HeapListHead),
sizeof(HEAPLIST32));
retv = TRUE;
SnapshotBase->HeapListIndex = 1;
}
NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)SnapshotBase);
return retv;
}
BOOL
WINAPI
Heap32ListNext(
IN HANDLE SnapSection,
IN OUT LPHEAPLIST32 lphl)
/*++
Routine Description:
Retrieves information about the next heap that has been allocated by a
Win32 process.
Arguments:
SnapSection - Supplies the handle of the snapshot returned from a previous
call to the CreateToolhelp32Snapshot function.
lphl - Returns a HEAPLIST32 structure. The calling application must set the
dwSize member of HEAPLIST32 to the size, in bytes, of the structure.
Return Value:
Returns TRUE if the next entry of the heap list has been copied to the buffer or
FALSE otherwise. The ERROR_NO_MORE_FILES error value is returned by the
GetLastError function when no more entries in the heap list exist.
--*/
{
PSNAPSHOTSTATE SnapshotBase;
BOOL retv = FALSE;
LARGE_INTEGER SectionOffset;
SIZE_T ViewSize;
NTSTATUS Status = 0;
if (!lphl || lphl->dwSize != sizeof(HEAPLIST32)) {
BaseSetLastNTError(STATUS_INFO_LENGTH_MISMATCH);
return FALSE;
}
SectionOffset.LowPart = 0;
SectionOffset.HighPart = 0;
ViewSize = 0;
SnapshotBase = 0;
Status = NtMapViewOfSection(SnapSection,
NtCurrentProcess(),
&SnapshotBase,
0L,
0L,
&SectionOffset,
&ViewSize,
ViewShare,
0L,
PAGE_READWRITE);
if (!NT_SUCCESS(Status)) {
BaseSetLastNTError(Status);
return FALSE;
}
if (SnapshotBase->HeapListIndex < SnapshotBase->HeapListCount) {
memcpy(lphl,
(LPHEAPLIST32)((ULONG_PTR)SnapshotBase + (ULONG_PTR)(&SnapshotBase->HeapListHead[SnapshotBase->HeapListIndex++])),
sizeof(HEAPLIST32));
retv = TRUE;
} else {
SetLastError(ERROR_NO_MORE_FILES);
}
NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)SnapshotBase);
return(retv);
}
BOOL
WINAPI
Heap32First(
IN OUT LPHEAPENTRY32 lphe,
IN DWORD th32ProcessID,
IN ULONG_PTR th32HeapID)
/*++
Routine Description:
Retrieves information about the first block of a heap that has been
allocated by a Win32 process. Also, create a snapshot of that heap so
the Heap32Next functions can walk them.
Arguments:
lphe - Returns a HEAPENTRY32 structure. The calling application must set
the dwSize member to the size, in bytes, of the structure.
th32ProcessID - Supplies the identifier of the Win32 process context that
owns the heap.
th32HeapID - Supplies the identifier of the heap to enumerate.
Return Value:
Returns TRUE if information for the first heap block has been copied to the buffer
or FALSE otherwise. The ERROR_NO_MORE_FILES error value is returned by the
GetLastError function if the heap is invalid or empty.
Notes:
since there is no way to save heap snapshots or delete heap snapshots in any way that
makes sense (because this info is not associated with snapshots etc), the information
needs to be generated completely for each call. This is very expensive, it would be
a good idea to redesign this API...
We could try and cheat by preserving snapshots until they are completyely iterated or
until a new one is taken, etc, but we will just end up with a bunch of memory leaks
--*/
{
PRTL_DEBUG_INFORMATION ThRawHeapDebugInfo;
ULONG HeapListCount;
PRTL_HEAP_ENTRY p;
PRTL_HEAP_INFORMATION HeapInfo;
ULONG HeapEntryAddress;
NTSTATUS Status = 0;
BOOL retv = FALSE;
if (!lphe || lphe->dwSize != sizeof(HEAPENTRY32)) {
BaseSetLastNTError(STATUS_INFO_LENGTH_MISMATCH);
return FALSE;
}
//
// take snapshot
//
ThRawHeapDebugInfo = RtlCreateQueryDebugBuffer(0, FALSE);
if(ThRawHeapDebugInfo == 0)
{
return STATUS_UNSUCCESSFUL;
}
Status = RtlQueryProcessDebugInformation((HANDLE)LongToHandle(th32ProcessID),
RTL_QUERY_PROCESS_HEAP_SUMMARY |
RTL_QUERY_PROCESS_HEAP_ENTRIES,
ThRawHeapDebugInfo);
if (!NT_SUCCESS(Status)) {
RtlDestroyQueryDebugBuffer(ThRawHeapDebugInfo);
BaseSetLastNTError(Status);
return FALSE;
}
//
// query snapshot
//
for (HeapListCount = 0;
HeapListCount < ThRawHeapDebugInfo->Heaps->NumberOfHeaps;
HeapListCount++) {
HeapInfo = &ThRawHeapDebugInfo->Heaps->Heaps[HeapListCount];
if ((ULONG_PTR)HeapInfo->BaseAddress == th32HeapID) {
p = HeapInfo->Entries;
lphe->dwResvd = 0;
lphe->dwLockCount = 0;
lphe->th32HeapID = th32HeapID;
lphe->th32ProcessID = th32ProcessID;
lphe->hHandle = (HANDLE)th32HeapID;// try this way
// walk up to first non-segment block (I am assuming there is always one)
// skip segments - can you have 2 in a row?
// is first block always a segment?
// We translate the heap flags to the most appropriate LF32_xxx values
while(RTL_HEAP_SEGMENT & p->Flags) {
lphe->dwAddress = (ULONG_PTR)p->u.s2.FirstBlock + ThRawHeapDebugInfo->Heaps->Heaps[HeapListCount].EntryOverhead; // reset this
++lphe->dwResvd;
++p;
}
//
// munge flags
//
//----------------------------------------------
if ((p->Flags & RTL_HEAP_BUSY) ||
(p->Flags & RTL_HEAP_SETTABLE_VALUE) ||
(p->Flags & RTL_HEAP_SETTABLE_FLAG2) ||
(p->Flags & RTL_HEAP_SETTABLE_FLAG3) ||
(p->Flags & RTL_HEAP_SETTABLE_FLAGS) ||
(p->Flags & RTL_HEAP_PROTECTED_ENTRY)
) {
lphe->dwFlags = LF32_FIXED;
}
else if ( p->Flags & RTL_HEAP_SETTABLE_FLAG1) {
lphe->dwFlags = LF32_MOVEABLE;
}
else if ( p->Flags & RTL_HEAP_UNCOMMITTED_RANGE) {
lphe->dwFlags = LF32_FREE;
}
//----------------------------------------------
lphe->dwBlockSize = p->Size;
retv = TRUE;
break;
}
}
//
// free snapshot
//
RtlDestroyQueryDebugBuffer(ThRawHeapDebugInfo);
return retv;
}
BOOL
WINAPI
Heap32Next(
IN OUT LPHEAPENTRY32 lphe)
/*++
Routine Description:
Retrieves information about the next block of a heap that has been
allocated by a Win32 process.
Arguments:
lphe - Returns a HEAPENTRY32 structure. The calling application must set
the dwSize member to the size, in bytes, of the structure.
Return Value:
Returns TRUE if information about the next block in the heap has been
copied to the buffer or FALSE otherwise. The ERROR_NO_MORE_FILES error
value is returned by the GetLastError function when no more objects in
the heap exist.
note:
this function can be prone to error since the heap can change between
calls to get heaplists, Heap32First, etc. There is no good way to
manage a snapshot using this model, so we just get to live with it.
--*/
{
PRTL_DEBUG_INFORMATION ThRawHeapDebugInfo;
PRTL_HEAP_ENTRY p;
PRTL_HEAP_INFORMATION HeapInfo;
ULONG HeapListCount;
BOOL retv = FALSE;
BOOL hit_seg = FALSE;
NTSTATUS Status = 0;
if (!lphe || lphe->dwSize != sizeof(HEAPENTRY32)) {
BaseSetLastNTError(STATUS_INFO_LENGTH_MISMATCH);
return FALSE;
}
//
// take snapshot
//
ThRawHeapDebugInfo = RtlCreateQueryDebugBuffer(0, FALSE);
if(ThRawHeapDebugInfo == 0)
{
return STATUS_UNSUCCESSFUL;
}
Status = RtlQueryProcessDebugInformation((HANDLE)LongToHandle(lphe->th32ProcessID),
RTL_QUERY_PROCESS_HEAP_SUMMARY |
RTL_QUERY_PROCESS_HEAP_ENTRIES,
ThRawHeapDebugInfo);
if (!NT_SUCCESS(Status)) {
RtlDestroyQueryDebugBuffer(ThRawHeapDebugInfo);
BaseSetLastNTError(Status);
return FALSE;
}
//
// get index to correct heap list heap list - th32HeapID / baseadress
//
for (HeapListCount = 0; HeapListCount < ThRawHeapDebugInfo->Heaps->NumberOfHeaps; ++HeapListCount)
{
if((ULONG_PTR)ThRawHeapDebugInfo->Heaps->Heaps[HeapListCount].BaseAddress == lphe->th32HeapID)
{
break;
}
}
//
// ran out of heaps
//
if(HeapListCount >= ThRawHeapDebugInfo->Heaps->NumberOfHeaps)
{
RtlDestroyQueryDebugBuffer(ThRawHeapDebugInfo);
SetLastError(ERROR_NO_MORE_FILES);
return FALSE;
}
//
// check for last entry
//
++lphe->dwResvd; // point to next one
if(lphe->dwResvd >= ThRawHeapDebugInfo->Heaps->Heaps[HeapListCount].NumberOfEntries)
{
RtlDestroyQueryDebugBuffer(ThRawHeapDebugInfo);
SetLastError(ERROR_NO_MORE_FILES);
return FALSE;
}
//
// point to correct heap entry - index of this is kept in lphe->dwResvd
//
p = (PRTL_HEAP_ENTRY)&ThRawHeapDebugInfo->Heaps->Heaps[HeapListCount].Entries[lphe->dwResvd];
// keep segments in lphe->hHandle
while(RTL_HEAP_SEGMENT & p->Flags) {
lphe->dwAddress = (ULONG_PTR)p->u.s2.FirstBlock + ThRawHeapDebugInfo->Heaps->Heaps[HeapListCount].EntryOverhead;// reset this
if(lphe->dwResvd >= ThRawHeapDebugInfo->Heaps->Heaps[HeapListCount].NumberOfEntries)
{
RtlDestroyQueryDebugBuffer(ThRawHeapDebugInfo);
SetLastError(ERROR_NO_MORE_FILES);
return FALSE;
}
++lphe->dwResvd;
++p;
hit_seg = TRUE;
}
//
// calculate the address
// normally, we could add the size of the previous block to the existing (last) address
// to get the current address, but this is only for blocks that do not follow a segment
// I am assuming that there will always be a segment first
// current address = last address() + last size
// by the time we reach this point, either we have just exited from scannin a segment, or
// p-> is pointing at a non-segment entry.
//
if(hit_seg == FALSE)
{
lphe->dwAddress += lphe->dwBlockSize;
}
lphe->dwBlockSize = p->Size;
//
// munge flags
//
// We translate the heap flags to the most appropriate LF32_xxx values
//----------------------------------------------
if( (p->Flags & RTL_HEAP_BUSY) ||
(p->Flags & RTL_HEAP_SETTABLE_VALUE) ||
(p->Flags & RTL_HEAP_SETTABLE_FLAG2) ||
(p->Flags & RTL_HEAP_SETTABLE_FLAG3) ||
(p->Flags & RTL_HEAP_SETTABLE_FLAGS) ||
(p->Flags & RTL_HEAP_PROTECTED_ENTRY)
) {
lphe->dwFlags = LF32_FIXED;
}
else if( p->Flags & RTL_HEAP_SETTABLE_FLAG1) {
lphe->dwFlags = LF32_MOVEABLE;
}
else if( p->Flags & RTL_HEAP_UNCOMMITTED_RANGE) {
lphe->dwFlags = LF32_FREE;
}
//----------------------------------------------
retv = TRUE;
//
// free snapshot
//
RtlDestroyQueryDebugBuffer(ThRawHeapDebugInfo);
return(retv);
}
BOOL
WINAPI
Toolhelp32ReadProcessMemory(
IN DWORD th32ProcessID,
IN LPCVOID lpBaseAddress,
OUT PUCHAR lpBuffer,
IN SIZE_T cbRead,
OUT SIZE_T *lpNumberOfBytesRead)
/*++
Routine Description:
Copies memory allocated to another process into an application-supplied
buffer. This function is for people who are to lazy to open
the process themselves.
Arguments:
th32ProcessID - Supplies the Identifier of the Win32 process whose memory
is being copied. This parameter can be zero to copy the memory of the
current process.
lpBaseAddress - Supplies the base address in the specified process to read.
Before transferring any data, the system verifies that all data in the
base address and memory of the specified size is accessible for read
access. If this is the case, the function proceeds. Otherwise, the
function fails.
lpBuffer - Returns the requested data
cbRead - Supplies the number of bytes to read from the specified process.
lpNumberOfBytesRead - Returns the number of bytes copied to the buffer. If
this parameter is NULL, it is ignored.
Return Value:
Returns TRUE if successful.
--*/
{
HANDLE hProcess;
BOOL RetVal;
hProcess = OpenProcess(PROCESS_VM_READ, FALSE, th32ProcessID);
if (hProcess == NULL) {
return FALSE;
}
RetVal = ReadProcessMemory(hProcess,
lpBaseAddress,
lpBuffer,
cbRead,
lpNumberOfBytesRead);
CloseHandle(hProcess);
return RetVal;
}
BOOL
WINAPI
Process32FirstW(
IN HANDLE SnapSection,
IN OUT LPPROCESSENTRY32W lppe)
/*++
Routine Description:
Retrieves information about the first Win32 process encountered in a system
snapshot.
Arguments:
SnapSection - Supplies the handle of a snapshot returned from a previous call
to the CreateToolhelp32Snapshot function.
lppe - Returns a PROCESSENTRY32W structure. The caller must set the dwSize
member to the size, in bytes, of the structure.
Return Value:
Returns TRUE if the first entry of the process list has been copied to the buffer
or FALSE otherwise. The ERROR_NO_MORE_FILES error value is returned by the
GetLastError function if no processes exist or the snapshot does not contain
process information.
--*/
{
PSNAPSHOTSTATE SnapshotBase;
LARGE_INTEGER SectionOffset;
SIZE_T ViewSize;
NTSTATUS Status = 0;
BOOL retv = FALSE;
if (!lppe || lppe->dwSize != sizeof(PROCESSENTRY32W)) {
BaseSetLastNTError(STATUS_INFO_LENGTH_MISMATCH);
return FALSE;
}
SectionOffset.LowPart = 0;
SectionOffset.HighPart = 0;
ViewSize = 0;
SnapshotBase = 0;
Status = NtMapViewOfSection(SnapSection,
NtCurrentProcess(),
&SnapshotBase,
0L,
0L,
&SectionOffset,
&ViewSize,
ViewShare,
0L,
PAGE_READWRITE);
if (!NT_SUCCESS(Status)) {
BaseSetLastNTError(Status);
return FALSE;
}
if (SnapshotBase->ProcessCount == 0) {
memset((PUCHAR)lppe + 4, 0, lppe->dwSize - 4);
SetLastError(ERROR_NO_MORE_FILES);
} else {
memcpy(lppe,
(LPPROCESSENTRY32W)((ULONG_PTR)SnapshotBase + (ULONG_PTR)SnapshotBase->ProcessListHead),
sizeof(PROCESSENTRY32W));
SnapshotBase->ProcessListIndex = 1;
retv = TRUE;
}
NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)SnapshotBase);
return retv;
}
BOOL
WINAPI
Process32First(
IN HANDLE SnapSection,
IN OUT LPPROCESSENTRY32 lppe)
/*++
Routine Description:
ANSI version of Process32FirstW.
Retrieves information about the first Win32 process encountered in a system
snapshot.
Arguments:
SnapSection - Supplies the handle of a snapshot returned from a previous call
to the CreateToolhelp32Snapshot function.
lppe - Returns a PROCESSENTRY32 structure. The caller must set the dwSize
member to the size, in bytes, of the structure.
Return Value:
Returns TRUE if the first entry of the process list has been copied to the buffer
or FALSE otherwise. The ERROR_NO_MORE_FILES error value is returned by the
GetLastError function if no processes exist or the snapshot does not contain
process information.
--*/
{
PROCESSENTRY32W pe32w;
BOOL b;
if (lppe == NULL || (lppe->dwSize < sizeof(PROCESSENTRY32))) {
BaseSetLastNTError(STATUS_INFO_LENGTH_MISMATCH);
return FALSE;
}
// Thunk to Process32FirstW
pe32w.dwSize = sizeof(pe32w);
b = Process32FirstW(SnapSection,&pe32w);
WideCharToMultiByte(CP_ACP, 0,
pe32w.szExeFile, -1,
lppe->szExeFile, ARRAYSIZE(lppe->szExeFile),
0, 0);
lppe->cntUsage = pe32w.cntUsage; // meaningless on NT, copy anyway
lppe->th32ProcessID = pe32w.th32ProcessID;
lppe->th32DefaultHeapID = pe32w.th32DefaultHeapID;
lppe->th32ModuleID = pe32w.th32ModuleID;
lppe->cntThreads = pe32w.cntThreads;
lppe->th32ParentProcessID = pe32w.th32ParentProcessID;
lppe->pcPriClassBase = pe32w.pcPriClassBase;
lppe->dwFlags = pe32w.dwFlags;
return b;
}
BOOL
WINAPI
Process32NextW(
IN HANDLE SnapSection,
IN OUT LPPROCESSENTRY32W lppe)
/*++
Routine Description:
Retrieves information about the next Win32 process recorded in a system snapshot.
Arguments:
SnapSection - Supplies the handle of a snapshot returned from a previous call
to the CreateToolhelp32Snapshot function.
lppe - Returns a PROCESSENTRY32W structure. The caller must set the dwSize
member to the size, in bytes, of the structure.
Return Value:
Returns TRUE if the next entry of the process list has been copied to the buffer or
FALSE otherwise. The ERROR_NO_MORE_FILES error value is returned by the GetLastError
function if no processes exist or the snapshot does not contain process information.
--*/
{
PSNAPSHOTSTATE SnapshotBase;
BOOL retv = FALSE;
LARGE_INTEGER SectionOffset;
SIZE_T ViewSize;
NTSTATUS Status = 0;
if (!lppe || lppe->dwSize != sizeof(PROCESSENTRY32W)) {
BaseSetLastNTError(STATUS_INFO_LENGTH_MISMATCH);
return FALSE;
}
SectionOffset.LowPart = 0;
SectionOffset.HighPart = 0;
ViewSize = 0;
SnapshotBase = 0;
Status = NtMapViewOfSection(SnapSection,
NtCurrentProcess(),
&SnapshotBase,
0L,
0L,
&SectionOffset,
&ViewSize,
ViewShare,
0L,
PAGE_READWRITE);
if (!NT_SUCCESS(Status)) {
BaseSetLastNTError(Status);
return FALSE;
}
if (SnapshotBase->ProcessListIndex < SnapshotBase->ProcessCount) {
memcpy(lppe,
(LPPROCESSENTRY32W)((ULONG_PTR)SnapshotBase + (ULONG_PTR)(&SnapshotBase->ProcessListHead[SnapshotBase->ProcessListIndex++])),
sizeof(PROCESSENTRY32W));
retv = TRUE;
} else {
SetLastError(ERROR_NO_MORE_FILES);
}
NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)SnapshotBase);
return retv;
}
BOOL
WINAPI
Process32Next(
IN HANDLE SnapSection,
IN OUT LPPROCESSENTRY32 lppe)
/*++
Routine Description:
ANSI version of Process32NextW
Retrieves information about the next Win32 process recorded in a system snapshot.
Arguments:
SnapSection - Supplies the handle of a snapshot returned from a previous call
to the CreateToolhelp32Snapshot function.
lppe - Returns a PROCESSENTRY32 structure. The caller must set the dwSize
member to the size, in bytes, of the structure.
Return Value:
Returns TRUE if the next entry of the process list has been copied to the buffer or
FALSE otherwise. The ERROR_NO_MORE_FILES error value is returned by the GetLastError
function if no processes exist or the snapshot does not contain process information.
--*/
{
PROCESSENTRY32W pe32w;
BOOL b;
if (lppe == NULL || (lppe->dwSize < sizeof(PROCESSENTRY32))) {
BaseSetLastNTError(STATUS_INFO_LENGTH_MISMATCH);
return FALSE;
}
// Thunk to Process32NextW
pe32w.dwSize = sizeof(pe32w);
b = Process32NextW(SnapSection,&pe32w);
WideCharToMultiByte(CP_ACP, 0,
pe32w.szExeFile, -1,
lppe->szExeFile, ARRAYSIZE(lppe->szExeFile),
0, 0);
lppe->cntUsage = pe32w.cntUsage; // meaningless on NT, copy anyway
lppe->th32ProcessID = pe32w.th32ProcessID;
lppe->th32DefaultHeapID = pe32w.th32DefaultHeapID;
lppe->th32ModuleID = pe32w.th32ModuleID;
lppe->cntThreads = pe32w.cntThreads;
lppe->th32ParentProcessID = pe32w.th32ParentProcessID;
lppe->pcPriClassBase = pe32w.pcPriClassBase;
lppe->dwFlags = pe32w.dwFlags;
return b;
}
BOOL
WINAPI
Thread32First(
IN HANDLE SnapSection,
IN OUT LPTHREADENTRY32 lpte)
/*++
Routine Description:
Retrieves information about the first thread of any Win32 process
encountered in a system snapshot.
Arguments:
SnapSection - Supplies the handle of a snapshot returned from a previous
call to the CreateToolhelp32Snapshot function.
lpte - Returns a THREADENTRY32 structure. The caller must set the dwSize
member to the size, in bytes, of the structure.
Return Value:
Returns TRUE if the first entry of the thread list has been copied to the buffer or
FALSE otherwise. The ERROR_NO_MORE_FILES error value is returned by the GetLastError
function if no threads exist or the snapshot does not contain thread information.
--*/
{
PSNAPSHOTSTATE SnapshotBase;
LARGE_INTEGER SectionOffset;
SIZE_T ViewSize;
NTSTATUS Status = 0;
BOOL retv = FALSE;
if (!lpte || lpte->dwSize != sizeof(THREADENTRY32)) {
BaseSetLastNTError(STATUS_INFO_LENGTH_MISMATCH);
return FALSE;
}
SectionOffset.LowPart = 0;
SectionOffset.HighPart = 0;
ViewSize = 0;
SnapshotBase = 0;
Status = NtMapViewOfSection(SnapSection,
NtCurrentProcess(),
&SnapshotBase,
0L,
0L,
&SectionOffset,
&ViewSize,
ViewShare,
0L,
PAGE_READWRITE);
if (!NT_SUCCESS(Status)) {
BaseSetLastNTError(Status);
return FALSE;
}
if (SnapshotBase->ThreadCount == 0) {
memset((PUCHAR)lpte + 4, 0, lpte->dwSize - 4);
SetLastError(ERROR_NO_MORE_FILES);
} else {
memcpy(lpte,
(LPTHREADENTRY32)((ULONG_PTR)SnapshotBase + (ULONG_PTR)SnapshotBase->ThreadListHead),
sizeof(THREADENTRY32));
SnapshotBase->ThreadListIndex = 1;
retv = TRUE;
}
NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)SnapshotBase);
return(retv);
}
BOOL
WINAPI
Thread32Next(
IN HANDLE SnapSection,
IN OUT LPTHREADENTRY32 lpte)
/*++
Routine Description:
Retrieves information about the next thread of any Win32 process encountered in the
system memory snapshot.
Arguments:
SnapSection - Supplies the handle of a snapshot returned from a previous call
to the CreateToolhelp32Snapshot function.
lpte - Reeturns a THREADENTRY32 structure. The caller must set the dwSize
member to the size, in bytes, of the structure.
Return Value:
Returns TRUE if the next entry of the thread list has been copied to the buffer or
FALSE otherwise. The ERROR_NO_MORE_FILES error value is returned by the GetLastError
function if no threads exist or the snapshot does not contain thread information.
--*/
{
PSNAPSHOTSTATE SnapshotBase;
BOOL retv = FALSE;
LARGE_INTEGER SectionOffset;
SIZE_T ViewSize;
NTSTATUS Status = 0;
if (!lpte || lpte->dwSize != sizeof(THREADENTRY32)) {
BaseSetLastNTError(STATUS_INFO_LENGTH_MISMATCH);
return FALSE;
}
SectionOffset.LowPart = 0;
SectionOffset.HighPart = 0;
ViewSize = 0;
SnapshotBase = 0;
Status = NtMapViewOfSection(SnapSection,
NtCurrentProcess(),
&SnapshotBase,
0L,
0L,
&SectionOffset,
&ViewSize,
ViewShare,
0L,
PAGE_READWRITE);
if (!NT_SUCCESS(Status)) {
BaseSetLastNTError(Status);
return FALSE;
}
if (SnapshotBase->ThreadListIndex < SnapshotBase->ThreadCount) {
memcpy(lpte,
(PTHREADENTRY32)((ULONG_PTR)SnapshotBase + (ULONG_PTR)(&SnapshotBase->ThreadListHead[SnapshotBase->ThreadListIndex++])),
sizeof(THREADENTRY32));
retv = TRUE;
} else {
SetLastError(ERROR_NO_MORE_FILES);
}
NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)SnapshotBase);
return(retv);
}
BOOL
WINAPI
Module32FirstW(
IN HANDLE SnapSection,
IN OUT LPMODULEENTRY32W lpme)
/*++
Routine Description:
Retrieves information about the first module associated with a Win32 process.
Arguments:
SnapSection - Supplies the handle of a snapshot returned from a previous call
to the CreateToolhelp32Snapshot function.
lpme - Returns a buffer containing a MODULEENTRY32W structure. The caller
must set the dwSize member to the size, in bytes, of the structure.
Return Value:
Returns TRUE if the first entry of the module list has been copied to the buffer or
FALSE otherwise. The ERROR_NO_MORE_FILES error value is returned by the GetLastError
function if no modules exist or the snapshot does not contain module information.
--*/
{
PSNAPSHOTSTATE SnapshotBase;
LARGE_INTEGER SectionOffset;
SIZE_T ViewSize;
NTSTATUS Status = 0;
BOOL retv = FALSE;
if (!lpme || lpme->dwSize != sizeof(MODULEENTRY32W)) {
BaseSetLastNTError(STATUS_INFO_LENGTH_MISMATCH);
return FALSE;
}
SectionOffset.LowPart = 0;
SectionOffset.HighPart = 0;
ViewSize = 0;
SnapshotBase = 0;
Status = NtMapViewOfSection(SnapSection,
NtCurrentProcess(),
&SnapshotBase,
0L,
0L,
&SectionOffset,
&ViewSize,
ViewShare,
0L,
PAGE_READWRITE);
if (!NT_SUCCESS(Status)) {
BaseSetLastNTError(Status);
return FALSE;
}
if (SnapshotBase->ModuleCount == 0) {
memset((PUCHAR)lpme + 4, 0, lpme->dwSize - 4);
SetLastError(ERROR_NO_MORE_FILES);
} else {
memcpy(lpme,
(PMODULEENTRY32W)((ULONG_PTR)SnapshotBase + (ULONG_PTR)SnapshotBase->ModuleListHead),
sizeof(MODULEENTRY32W));
SnapshotBase->ModuleListIndex = 1;
retv = TRUE;
}
NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)SnapshotBase);
return retv;
}
BOOL
WINAPI
Module32First(
IN HANDLE SnapSection,
IN OUT LPMODULEENTRY32 lpme)
/*++
Routine Description:
ANSI version of Module32FirstW.
Retrieves information about the first module associated with a Win32 process.
Arguments:
SnapSection - Supplies the handle of the snapshot returned from a previous call
to the CreateToolhelp32Snapshot function.
lpme - Returns a buffer containing a MODULEENTRY32 structure. The caller
must set the dwSize member to the size, in bytes, of the structure.
Return Value:
Returns TRUE if the first entry of the module list has been copied to the buffer or
FALSE otherwise. The ERROR_NO_MORE_FILES error value is returned by the GetLastError
function if no modules exist or the snapshot does not contain module information.
--*/
{
MODULEENTRY32W me32w;
DWORD dwSizeToCopy;
BOOL b;
if (lpme == NULL || (lpme->dwSize < sizeof(MODULEENTRY32))) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
// Thunk to Module32FirstW
me32w.dwSize = sizeof(me32w);
b = Module32FirstW(SnapSection,&me32w);
WideCharToMultiByte(CP_ACP, 0,
me32w.szExePath, -1,
lpme->szExePath, ARRAYSIZE(lpme->szExePath),
0, 0);
WideCharToMultiByte(CP_ACP, 0,
me32w.szModule, -1,
lpme->szModule, ARRAYSIZE(lpme->szModule),
0, 0);
lpme->th32ModuleID = me32w.th32ModuleID;
lpme->th32ProcessID = me32w.th32ProcessID;
lpme->GlblcntUsage = me32w.GlblcntUsage;
lpme->ProccntUsage = me32w.ProccntUsage;
lpme->modBaseAddr = me32w.modBaseAddr;
lpme->modBaseSize = me32w.modBaseSize;
lpme->hModule = me32w.hModule;
return b;
}
BOOL
WINAPI
Module32NextW(
IN HANDLE SnapSection,
IN OUT LPMODULEENTRY32W lpme)
/*++
Routine Description:
Retrieves information about the next module associated with a Win32 process or thread.
Arguments:
SnapSection - Supplies the handle of a snapshot returned from a previous call
to CreateToolhelp32Snapshot.
lpme - Returns a MODULEENTRY32W structure. The calling application must set
the dwSize member to the size, in bytes, of the structure.
Return Value:
Returns TRUE if the next entry of the module list has been copied to the buffer or
FALSE otherwise. The ERROR_NO_MORE_FILES error value is returned by the GetLastError
function if no more modules exist.
--*/
{
PSNAPSHOTSTATE SnapshotBase;
BOOL retv = FALSE;
LARGE_INTEGER SectionOffset;
SIZE_T ViewSize;
NTSTATUS Status = 0;
if (!lpme || lpme->dwSize != sizeof(MODULEENTRY32W)) {
BaseSetLastNTError(STATUS_INFO_LENGTH_MISMATCH);
return FALSE;
}
SectionOffset.LowPart = 0;
SectionOffset.HighPart = 0;
ViewSize = 0;
SnapshotBase = 0;
Status = NtMapViewOfSection(SnapSection,
NtCurrentProcess(),
&SnapshotBase,
0L,
0L,
&SectionOffset,
&ViewSize,
ViewShare,
0L,
PAGE_READWRITE);
if (!NT_SUCCESS(Status)) {
BaseSetLastNTError(Status);
return FALSE;
}
if (SnapshotBase->ModuleListIndex < SnapshotBase->ModuleCount) {
memcpy(lpme,
(LPMODULEENTRY32W)((ULONG_PTR)SnapshotBase + (ULONG_PTR)(&SnapshotBase->ModuleListHead[SnapshotBase->ModuleListIndex++])),
sizeof(MODULEENTRY32W));
retv = TRUE;
} else {
SetLastError(ERROR_NO_MORE_FILES);
}
NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)SnapshotBase);
return(retv);
}
BOOL
WINAPI
Module32Next(
IN HANDLE SnapSection,
IN OUT LPMODULEENTRY32 lpme)
/*++
Routine Description:
ANSI version of Module32NextW.
Retrieves information about the next module associated with a Win32 process or thread.
Arguments:
SnapSection - Supplies the handle of a snapshot returned from a previous call
to CreateToolhelp32Snapshot.
lpme - Returns a MODULEENTRY32 structure. The calling application must set
the dwSize member to the size, in bytes, of the structure.
Return Value:
Returns TRUE if the next entry of the module list has been copied to the buffer or
FALSE otherwise. The ERROR_NO_MORE_FILES error value is returned by the GetLastError
function if no more modules exist.
--*/
{
MODULEENTRY32W me32w;
BOOL b;
if (lpme == NULL || (lpme->dwSize < sizeof(MODULEENTRY32))) {
SetLastError(ERROR_INVALID_DATA);
return FALSE;
}
// Thunk to Module32NextW
me32w.dwSize = sizeof(me32w);
b = Module32NextW(SnapSection,&me32w);
WideCharToMultiByte(CP_ACP, 0,
me32w.szModule, -1,
lpme->szModule, ARRAYSIZE(lpme->szModule),
0, 0);
WideCharToMultiByte(CP_ACP, 0,
me32w.szExePath, -1,
lpme->szExePath, ARRAYSIZE(lpme->szExePath),
0, 0);
lpme->th32ModuleID = me32w.th32ModuleID;
lpme->GlblcntUsage = me32w.GlblcntUsage;
lpme->ProccntUsage = me32w.ProccntUsage;
lpme->modBaseAddr = me32w.modBaseAddr;
lpme->modBaseSize = me32w.modBaseSize;
lpme->hModule = me32w.hModule;
return b;
}
NTSTATUS
ThpCreateRawSnap(
IN DWORD dwFlags,
IN DWORD th32ProcessID,
PUCHAR *RawProcess,
PRTL_DEBUG_INFORMATION *RawModule,
PRTL_DEBUG_INFORMATION *RawDebugInfo)
/*++
Routine Description:
This function gets raw snapshots for the data types specified by dwFlags.
Arguments:
th32ProcessID - Supplies a WIN32 process ID. See CreateToolhelp32Snapshot
for full description.
dwFlags - Supplies switches requesting various data. See
CreateToolhelp32Snapshot for full description
Return Value:
NTSTATUS as appropriate
--*/
{
NTSTATUS Status = 0;
ULONG BufferSize = BUFFER_SIZE;
SIZE_T stBufferSize = BUFFER_SIZE;
//
// get process/thread/module/heap info
//
*RawProcess = NULL;
*RawModule = NULL;
*RawDebugInfo = NULL;
if((dwFlags & TH32CS_SNAPPROCESS) || (dwFlags & TH32CS_SNAPTHREAD)){
do {
try {
stBufferSize = BufferSize;
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
RawProcess,
0,
&stBufferSize,
MEM_COMMIT,
PAGE_READWRITE);
}
except( EXCEPTION_EXECUTE_HANDLER ) {
Status = GetExceptionCode();
}
if (!NT_SUCCESS(Status)) {
break;
}
BufferSize = (ULONG)stBufferSize;
//
// get all of the status information */
//
Status = NtQuerySystemInformation(SystemProcessInformation,
*RawProcess,
BufferSize,
NULL);
if (Status == STATUS_INFO_LENGTH_MISMATCH) {
NtFreeVirtualMemory(NtCurrentProcess(),
RawProcess,
&stBufferSize,
MEM_RELEASE);
*RawProcess = NULL;
BufferSize += 8192;
}
} while(Status == STATUS_INFO_LENGTH_MISMATCH);
}
//
// get module information
//
if((dwFlags & TH32CS_SNAPMODULE) || (dwFlags & TH32CS_SNAPMODULE32))
{
if (NT_SUCCESS(Status)) {
*RawModule = RtlCreateQueryDebugBuffer(0, FALSE);
if (!*RawModule) {
Status = STATUS_UNSUCCESSFUL;
}
}
if (NT_SUCCESS(Status)) {
Status = RtlQueryProcessDebugInformation((HANDLE)LongToHandle(th32ProcessID),
RTL_QUERY_PROCESS_NONINVASIVE |
((dwFlags & TH32CS_SNAPMODULE) ? RTL_QUERY_PROCESS_MODULES : 0) |
((dwFlags & TH32CS_SNAPMODULE32) ? RTL_QUERY_PROCESS_MODULES32 : 0),
*RawModule);
}
}
//
// get the heap summary information for the specified process */
//
if (dwFlags & TH32CS_SNAPHEAPLIST) {
if (NT_SUCCESS(Status)) {
*RawDebugInfo = RtlCreateQueryDebugBuffer(0, FALSE);
if (!*RawDebugInfo) {
Status = STATUS_UNSUCCESSFUL;
}
}
if (NT_SUCCESS(Status)) {
Status = RtlQueryProcessDebugInformation((HANDLE)LongToHandle(th32ProcessID),
RTL_QUERY_PROCESS_HEAP_SUMMARY,
*RawDebugInfo);
}
}
if (!NT_SUCCESS(Status)) {
if (*RawProcess) {
SIZE_T Size = 0;
NtFreeVirtualMemory(NtCurrentProcess(),
RawProcess,
&Size,
MEM_RELEASE);
*RawProcess = NULL;
}
if (*RawModule) {
RtlDestroyQueryDebugBuffer(*RawModule);
*RawModule = NULL;
}
if (*RawDebugInfo) {
RtlDestroyQueryDebugBuffer(*RawDebugInfo);
*RawDebugInfo = NULL;
}
}
return Status;
}
NTSTATUS
ThpAllocateSnapshotSection(
OUT PHANDLE SnapSection,
IN DWORD dwFlags,
IN DWORD th32ProcessID,
PUCHAR RawProcess,
PRTL_DEBUG_INFORMATION RawModule,
PRTL_DEBUG_INFORMATION RawDebugInfo)
/*++
Routine Description:
This function calculates the size of the snapshot and allocates a
file mapping object for it in the pagefile.
Also, initialize snapshot information in the header
Arguments:
th32ProcessID - Supplies a WIN32 process ID. See CreateToolhelp32Snapshot
for full description.
dwFlags - Supplies switches describing requested data. See
CreateToolhelp32Snapshot for full description.
th32ProcessID -
RawProcess -
RawDebugInfo -
Return Value:
Handle to to the mapping object if successful, -1 otherwise
--*/
{
NTSTATUS Status = 0;
PSNAPSHOTSTATE SnapshotBase;
SECURITY_ATTRIBUTES SecurityAttributes;
LPSECURITY_ATTRIBUTES lpSecurityAttributes;
ULONG SnapShotSize;
ULONG Offset1;
PSYSTEM_PROCESS_INFORMATION ProcessInfo;
OBJECT_ATTRIBUTES Obja;
POBJECT_ATTRIBUTES pObja;
LARGE_INTEGER SectionOffset;
LARGE_INTEGER SectionSize;
SIZE_T ViewSize;
SIZE_T Size;
ULONG ProcessCount = 0;
ULONG HeapListCount = 0;
ULONG ModuleCount = 0;
ULONG ThreadCount = 0;
SnapShotSize = sizeof(SNAPSHOTSTATE);
Offset1 = 0;
//
// calculate the required snapshot size
//
if ((dwFlags & TH32CS_SNAPPROCESS) || (dwFlags & TH32CS_SNAPTHREAD)) {
do {
ProcessCount++;
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&RawProcess[Offset1];
Offset1 += ProcessInfo->NextEntryOffset;
ThreadCount += ProcessInfo->NumberOfThreads;
} while (ProcessInfo->NextEntryOffset != 0);
if (dwFlags & TH32CS_SNAPPROCESS) {
SnapShotSize += ProcessCount * sizeof(PROCESSENTRY32W);
}
if (dwFlags & TH32CS_SNAPTHREAD) {
SnapShotSize += ThreadCount * sizeof(THREADENTRY32);
}
}
if (dwFlags & TH32CS_SNAPMODULE) {
SnapShotSize += RawModule->Modules->NumberOfModules * sizeof(MODULEENTRY32W);
ModuleCount = RawModule->Modules->NumberOfModules;
}
if (dwFlags & TH32CS_SNAPHEAPLIST) {
SnapShotSize += RawDebugInfo->Heaps->NumberOfHeaps * sizeof(HEAPLIST32);
HeapListCount = RawDebugInfo->Heaps->NumberOfHeaps;
}
//
// Create a security object if needed
//
if (dwFlags & TH32CS_INHERIT) {
SecurityAttributes.lpSecurityDescriptor = NULL;
SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
SecurityAttributes.bInheritHandle = TRUE;
lpSecurityAttributes = &SecurityAttributes;
} else {
lpSecurityAttributes = NULL;
}
//
// create a pagefile section to contain the snapshot
//
pObja = BaseFormatObjectAttributes(&Obja, lpSecurityAttributes, NULL);
SectionSize.LowPart = SnapShotSize;
SectionSize.HighPart = 0;
Status = NtCreateSection(SnapSection,
STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ | SECTION_MAP_WRITE,
pObja,
&SectionSize,
PAGE_READWRITE,
SEC_COMMIT,
NULL);
if ( !NT_SUCCESS(Status) ) {
return Status;
}
SectionOffset.LowPart = 0;
SectionOffset.HighPart = 0;
ViewSize = 0;
SnapshotBase = 0;
Status = NtMapViewOfSection(*SnapSection,
NtCurrentProcess(),
&SnapshotBase,
0L,
0L,
&SectionOffset,
&ViewSize,
ViewShare,
0L,
PAGE_READWRITE);
//
// free all memory if failure
//
if ( !NT_SUCCESS(Status) ) {
CloseHandle(*SnapSection);
if ((dwFlags & TH32CS_SNAPTHREAD) || (dwFlags & TH32CS_SNAPPROCESS)){
Size = 0;
NtFreeVirtualMemory(NtCurrentProcess(),
&RawProcess,
&Size,
MEM_RELEASE);
}
if (dwFlags & TH32CS_SNAPPROCESS) {
RtlDestroyQueryDebugBuffer(RawModule);
}
if (dwFlags & TH32CS_SNAPHEAPLIST) {
RtlDestroyQueryDebugBuffer(RawDebugInfo);
}
return Status;
}
SnapshotBase->ProcessCount = ProcessCount;
SnapshotBase->HeapListCount = HeapListCount;
SnapshotBase->ModuleCount = ModuleCount;
SnapshotBase->ThreadCount = ThreadCount;
//
// return resources
//
NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)SnapshotBase);
return STATUS_SUCCESS;
}
NTSTATUS
ThpCopyAnsiToUnicode(
PWCHAR Dest,
PUCHAR Src,
USHORT Max)
{
UNICODE_STRING UnicodeString;
ANSI_STRING AnsiString;
UnicodeString.Buffer = Dest;
UnicodeString.MaximumLength = Max;
RtlInitAnsiString(&AnsiString, Src);
return RtlAnsiStringToUnicodeString( &UnicodeString, &AnsiString, FALSE );
}
NTSTATUS
ThpProcessToSnap(
IN DWORD dwFlags,
IN DWORD th32ProcessID,
IN HANDLE SnapSection,
PUCHAR RawProcess,
PRTL_DEBUG_INFORMATION RawModule,
PRTL_DEBUG_INFORMATION RawDebugInfo)
/*++
Routine Description:
This function processes the data in the raw dumps specified by dwFlage into
a mapped file.
Arguments:
dwFlags - Supplies switches describing the data requested. See
CreateToolhelp32Snapshot for full description.
th32ProcessID - Supplies a WIN32 process ID. See CreateToolhelp32Snapshot
for full description.
SnapSection - Supplies handle to section allocated by ThpAllocateSnapshotSection.
RawProcess -
RawDebugInfo -
Return Value:
TRUE if successful, FALSE if there was a problem encountered
--*/
{
PSNAPSHOTSTATE SnapshotBase;
PUCHAR BufferWriteAddr; /* working pointer into out process data - usually points at end */
LARGE_INTEGER SectionOffset;
SIZE_T ViewSize;
NTSTATUS Status = 0;
SIZE_T Size;
SectionOffset.LowPart = 0;
SectionOffset.HighPart = 0;
ViewSize = 0;
SnapshotBase = 0;
Status = NtMapViewOfSection(SnapSection,
NtCurrentProcess(),
&SnapshotBase,
0L,
0L,
&SectionOffset,
&ViewSize,
ViewShare,
0L,
PAGE_READWRITE);
if (!NT_SUCCESS(Status)) {
return Status;
}
BufferWriteAddr = &SnapshotBase->DataBegin;
//
// write heap list to snapshot
// some of this code adapted from dh.c
//
if (dwFlags & TH32CS_SNAPHEAPLIST) {
ULONG HeapListCount = 0;
ULONG HeapEntryCount = 0;
LPHEAPLIST32 pHeapList;
SnapshotBase->HeapListHead = (PHEAPLIST32)(BufferWriteAddr - (PUCHAR)SnapshotBase);
pHeapList = (LPHEAPLIST32)BufferWriteAddr;
// heaplist
for (HeapListCount = 0; HeapListCount < SnapshotBase->HeapListCount; HeapListCount++){
pHeapList->dwSize = sizeof(HEAPLIST32);
pHeapList->th32ProcessID = th32ProcessID;
/* handle = baseaddress = ID we will use internally */
pHeapList->th32HeapID = (ULONG_PTR)RawDebugInfo->Heaps->Heaps[HeapListCount].BaseAddress;
pHeapList->dwFlags = RawDebugInfo->Heaps->Heaps[HeapListCount].Flags;
++pHeapList;
}
// update the pointer to the write area
BufferWriteAddr = (PCHAR)(BufferWriteAddr + HeapListCount * sizeof(HEAPLIST32));
RtlDestroyQueryDebugBuffer(RawDebugInfo);
}
//
// write module list to snapshot
//
if (dwFlags & TH32CS_SNAPMODULE) {
LPMODULEENTRY32W pModule;
ULONG Offset1 = 0;
ULONG mCount = 0;
PRTL_PROCESS_MODULE_INFORMATION ModuleInfo;
SnapshotBase->ModuleListHead = (PMODULEENTRY32W)(BufferWriteAddr - (PUCHAR)SnapshotBase);
//
// get module info from buffer
//
pModule = (LPMODULEENTRY32W)(BufferWriteAddr);
ModuleInfo = &RawModule->Modules->Modules[ 0 ];
for (mCount = 0; mCount < RawModule->Modules->NumberOfModules; mCount++) {
pModule->dwSize = sizeof(MODULEENTRY32W);
pModule->th32ProcessID = th32ProcessID;
//
// base == handle
//
pModule->hModule = ModuleInfo->ImageBase;
//
// Base address of module in th32ProcessID's context
//
pModule->modBaseAddr = ModuleInfo->ImageBase;
//
// Path
//
ThpCopyAnsiToUnicode(pModule->szExePath,
ModuleInfo->FullPathName,
sizeof(pModule->szExePath));
//
// module name
//
ThpCopyAnsiToUnicode(pModule->szModule,
&ModuleInfo->FullPathName[ModuleInfo->OffsetToFileName],
sizeof(pModule->szModule));
//
// Size in bytes of module starting at modBaseAddr
//
pModule->modBaseSize = ModuleInfo->ImageSize;
//
// these are meaningless on NT
// but some apps may care... Gruntz (bugid 327009)
// was failing because th32ModuleID was 0, so
// now we stick in the address of the Module descriptor
//
// However it turns out that a pointer doesn't fit in a DWORD,
// so we stick in the value 1 instead.
//
pModule->th32ModuleID = 1;
pModule->GlblcntUsage = ModuleInfo->LoadCount; // will be 0xffff
pModule->ProccntUsage = ModuleInfo->LoadCount; // will be 0xffff
++ModuleInfo;
++pModule;
}
//
// update the pointer to the write area
//
BufferWriteAddr = (PCHAR)(BufferWriteAddr + mCount * sizeof(MODULEENTRY32W));
RtlDestroyQueryDebugBuffer(RawModule);
}
//
// write process list to snapshot
//
if (dwFlags & TH32CS_SNAPPROCESS) {
PSYSTEM_PROCESS_INFORMATION ProcessInfo;
LPPROCESSENTRY32W pEntry;
ULONG cProcess = 0;
ULONG Offset1 = 0;
SnapshotBase->ProcessListHead = (PPROCESSENTRY32W)(BufferWriteAddr - (PUCHAR)SnapshotBase);
pEntry = (LPPROCESSENTRY32W)(BufferWriteAddr + cProcess * sizeof(PROCESSENTRY32W));
do {
/* get process info from buffer */
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&RawProcess[Offset1];
pEntry->dwSize = sizeof(PROCESSENTRY32W);
pEntry->th32ProcessID = HandleToUlong(ProcessInfo->UniqueProcessId);
pEntry->pcPriClassBase = ProcessInfo->BasePriority;
pEntry->cntThreads = ProcessInfo->NumberOfThreads;
pEntry->th32ParentProcessID = HandleToUlong(ProcessInfo->InheritedFromUniqueProcessId);
pEntry->cntUsage = 0;
pEntry->th32DefaultHeapID = 0;
pEntry->th32ModuleID = 0;
pEntry->dwFlags = 0;
// Path
if (ProcessInfo->ImageName.Buffer == NULL) {
lstrcpyW(pEntry->szExeFile, L"[System Process]");
} else {
if (ProcessInfo->ImageName.Length >= ARRAYSIZE(pEntry->szExeFile)) {
ProcessInfo->ImageName.Length = ARRAYSIZE(pEntry->szExeFile)-1;
}
memcpy(pEntry->szExeFile, ProcessInfo->ImageName.Buffer, ProcessInfo->ImageName.Length);
pEntry->szExeFile[ProcessInfo->ImageName.Length] = TEXT('\0');
}
Offset1 += ProcessInfo->NextEntryOffset;
++cProcess;
++pEntry;
} while (ProcessInfo->NextEntryOffset != 0);
// update the pointer to the write area
BufferWriteAddr = (PCHAR)(BufferWriteAddr + cProcess * sizeof(PROCESSENTRY32W));
}
//
// write thread list to snapshot
//
if (dwFlags & TH32CS_SNAPTHREAD) {
PSYSTEM_PROCESS_INFORMATION ProcessInfo;
PSYSTEM_THREAD_INFORMATION ThreadInfo;
LPTHREADENTRY32 tEntry;
ULONG Offset1 = 0;
ULONG cThread = 0;
SnapshotBase->ThreadListHead = (PTHREADENTRY32)(BufferWriteAddr - (PUCHAR)SnapshotBase);
tEntry = (LPTHREADENTRY32)(BufferWriteAddr + cThread * sizeof(THREADENTRY32));
do {
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&RawProcess[Offset1];
ThreadInfo = (PSYSTEM_THREAD_INFORMATION)(ProcessInfo + 1);
for (cThread = 0; cThread < ProcessInfo->NumberOfThreads; cThread++) {
tEntry->dwSize = sizeof(THREADENTRY32);
tEntry->th32ThreadID = HandleToUlong(ThreadInfo->ClientId.UniqueThread);
tEntry->th32OwnerProcessID = HandleToUlong(ThreadInfo->ClientId.UniqueProcess);
tEntry->tpBasePri = ThreadInfo->BasePriority;
tEntry->tpDeltaPri = 0;
tEntry->cntUsage = 0;
tEntry->dwFlags = 0;
++ThreadInfo;
++tEntry;
}
Offset1 += ProcessInfo->NextEntryOffset;
} while (ProcessInfo->NextEntryOffset != 0);
BufferWriteAddr = (PUCHAR)(BufferWriteAddr + cThread * sizeof(THREADENTRY32)); // update the pointer to the write area
}
if ((dwFlags & TH32CS_SNAPTHREAD) || (dwFlags & TH32CS_SNAPPROCESS)){
Size = 0;
NtFreeVirtualMemory(NtCurrentProcess(),
&RawProcess,
&Size,
MEM_RELEASE);
}
NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)SnapshotBase);
return STATUS_SUCCESS;
}