2045 lines
57 KiB
C
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;
|
|
}
|