/*++ 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; }