You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1006 lines
28 KiB
1006 lines
28 KiB
/*++ BUILD Version: 0001 // Increment this if a change has global effects
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
prflibva.c
|
|
|
|
Abstract:
|
|
|
|
Virtual address space counter evaluation routines
|
|
|
|
computes the process and image virtual address space usage for return
|
|
via Perfmon API
|
|
|
|
Author:
|
|
|
|
Stolen from the "internal" PVIEW SDK program and adapted for Perfmon by:
|
|
|
|
a-robw (Bob Watson) 11/29/92
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
//
|
|
// define routine's "personality"
|
|
//
|
|
#define UNICODE 1
|
|
//
|
|
// Include files
|
|
//
|
|
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <memory.h>
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include <winperf.h>
|
|
#define PERF_HEAP hLibHeap
|
|
#include <perfutil.h>
|
|
#include "perfsprc.h"
|
|
|
|
#define DEFAULT_INCR (64*1024)
|
|
#ifdef _WIN64
|
|
#define STOP_AT (PVOID)(0xFFFFFFFF80000000)
|
|
#else
|
|
#define STOP_AT (PVOID)(0x80000000)
|
|
#endif
|
|
|
|
// Function Prototypes
|
|
|
|
PPROCESS_VA_INFO
|
|
GetProcessVaData (
|
|
IN PSYSTEM_PROCESS_INFORMATION
|
|
);
|
|
|
|
PMODINFO
|
|
GetModuleVaData (
|
|
PLDR_DATA_TABLE_ENTRY, // module information structure
|
|
PPROCESS_VA_INFO // process data structure
|
|
);
|
|
|
|
BOOL
|
|
FreeProcessVaData (
|
|
IN PPROCESS_VA_INFO
|
|
);
|
|
|
|
BOOL
|
|
FreeModuleVaData (
|
|
IN PMODINFO
|
|
);
|
|
|
|
|
|
PMODINFO
|
|
LocateModInfo(
|
|
IN PMODINFO,
|
|
IN PVOID,
|
|
IN SIZE_T
|
|
);
|
|
|
|
DWORD
|
|
ProtectionToIndex(
|
|
IN ULONG
|
|
);
|
|
|
|
DWORD dwProcessCount;
|
|
DWORD dwModuleCount;
|
|
|
|
|
|
PPROCESS_VA_INFO
|
|
GetSystemVaData (
|
|
IN PSYSTEM_PROCESS_INFORMATION pFirstProcess
|
|
)
|
|
/*++
|
|
|
|
GetSystemVaData
|
|
|
|
Obtains the Process and Image Virtual Address information for all
|
|
processes running on the system. (note that the routines called by
|
|
this function allocate data structures consequently the corresponding
|
|
FreeSystemVaData must be called to prevent memory "leaks")
|
|
|
|
Arguments
|
|
|
|
IN PSYSTEM_PROCESS_INFORMATION
|
|
pFirstProcess
|
|
Pointer to first process in list of process structures returned
|
|
by NtQuerySystemInformation service
|
|
|
|
Return Value
|
|
|
|
Pointer to first process in list of processes
|
|
or NULL if unable to obtain data
|
|
|
|
--*/
|
|
{
|
|
PSYSTEM_PROCESS_INFORMATION pThisProcess;
|
|
PPROCESS_VA_INFO pReturnValue = NULL;
|
|
PPROCESS_VA_INFO pLastProcess;
|
|
PPROCESS_VA_INFO pNewProcess;
|
|
DWORD dwStartTime;
|
|
BOOL bMoreProcesses;
|
|
|
|
dwProcessCount = 0;
|
|
dwModuleCount = 0;
|
|
|
|
if (pFirstProcess != NULL) {
|
|
|
|
pThisProcess = pFirstProcess;
|
|
pLastProcess = NULL;
|
|
bMoreProcesses = TRUE;
|
|
|
|
while ( bMoreProcesses ) { // loop exit is at bottom of loop
|
|
dwStartTime = GetTickCount ();
|
|
pNewProcess = GetProcessVaData(
|
|
pThisProcess); // pointer to process Info structure
|
|
if (pNewProcess) { // process data found OK
|
|
pNewProcess->LookUpTime = GetTickCount() - dwStartTime;
|
|
dwProcessCount++;
|
|
if (!pLastProcess) { // this is the first process returned
|
|
pReturnValue = pNewProcess; // save return value here
|
|
} else {
|
|
pLastProcess->pNextProcess = pNewProcess;
|
|
}
|
|
pLastProcess = pNewProcess;
|
|
}
|
|
if ( pThisProcess->NextEntryOffset == 0 ) {
|
|
bMoreProcesses = FALSE; // this is the last entry
|
|
} else { // point to the next process info structure
|
|
pThisProcess = (PSYSTEM_PROCESS_INFORMATION)
|
|
((PBYTE)pThisProcess + pThisProcess->NextEntryOffset);
|
|
}
|
|
}
|
|
return pReturnValue; // return pointer to first list entry
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
PPROCESS_VA_INFO
|
|
GetProcessVaData (
|
|
IN PSYSTEM_PROCESS_INFORMATION pProcess
|
|
)
|
|
/*++
|
|
|
|
GetProcessVaData
|
|
|
|
Gets the Virtual Memory usage details for the process passed in the
|
|
argument list. Collects the data for all images in use by the process.
|
|
|
|
Note that this routine allocates data structures that must be freed
|
|
(using the FreeProcessVaData routine) when finished with them.
|
|
|
|
|
|
Arguments
|
|
|
|
IN HANDLE hProcess
|
|
handle to the process to collect data for
|
|
|
|
Return Value
|
|
|
|
Pointer to completed Process VA info structure or
|
|
NULL if unable to collect data
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
HANDLE hProcess;
|
|
PPROCESS_VA_INFO pThisProcess;
|
|
PPEB pPeb;
|
|
PPEB_LDR_DATA Ldr;
|
|
PLIST_ENTRY LdrHead, LdrNext;
|
|
LDR_DATA_TABLE_ENTRY LdrEntryData, *pLdrEntry;
|
|
PMODINFO pNewModule, pLastModule;
|
|
PVOID pBaseAddress;
|
|
MEMORY_BASIC_INFORMATION VaBasicInfo;
|
|
DWORD dwProtection;
|
|
PMODINFO pMod;
|
|
SIZE_T dwRegionSize;
|
|
OBJECT_ATTRIBUTES obProcess;
|
|
CLIENT_ID ClientId;
|
|
PUNICODE_STRING pProcessNameBuffer;
|
|
|
|
// get handle to process
|
|
|
|
ClientId.UniqueThread = (HANDLE)NULL;
|
|
ClientId.UniqueProcess = pProcess->UniqueProcessId;
|
|
|
|
InitializeObjectAttributes(
|
|
&obProcess,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Status = NtOpenProcess(
|
|
&hProcess,
|
|
(ACCESS_MASK)PROCESS_ALL_ACCESS,
|
|
&obProcess,
|
|
&ClientId);
|
|
|
|
if (! NT_SUCCESS(Status)){
|
|
// unable to open the process, but still want to
|
|
// create pThisProcess so we will not mess up
|
|
// the process sequence.
|
|
hProcess = 0;
|
|
// return NULL; // unable to open process
|
|
}
|
|
|
|
// allocate structure
|
|
|
|
pThisProcess = ALLOCMEM (sizeof (PROCESS_VA_INFO));
|
|
|
|
if (pThisProcess) { // allocation successful
|
|
// initialize fields
|
|
|
|
pThisProcess->BasicInfo = ALLOCMEM (sizeof (PROCESS_BASIC_INFORMATION));
|
|
|
|
if (!pThisProcess->BasicInfo) {
|
|
// Bailout if unable to allocate memory
|
|
goto PBailOut;
|
|
}
|
|
|
|
// zero process counters
|
|
pThisProcess->MappedGuard = 0;
|
|
pThisProcess->PrivateGuard = 0;
|
|
pThisProcess->ImageReservedBytes = 0;
|
|
pThisProcess->ImageFreeBytes = 0;
|
|
pThisProcess->ReservedBytes = 0;
|
|
pThisProcess->FreeBytes = 0;
|
|
|
|
// get process short name from Process Info Structure
|
|
|
|
// alloc a new buffer since GetProcessShortName reuses the name
|
|
// buffer
|
|
pThisProcess->pProcessName = ALLOCMEM ((sizeof(UNICODE_STRING) + MAX_PROCESS_NAME_LENGTH));
|
|
|
|
if (pThisProcess->pProcessName != NULL) {
|
|
pThisProcess->pProcessName->Length = 0;
|
|
pThisProcess->pProcessName->MaximumLength = MAX_PROCESS_NAME_LENGTH;
|
|
pThisProcess->pProcessName->Buffer = (PWSTR)(&pThisProcess->pProcessName[1]);
|
|
|
|
pProcessNameBuffer = GetProcessShortName (pProcess);
|
|
RtlCopyUnicodeString (pThisProcess->pProcessName,
|
|
pProcessNameBuffer);
|
|
} else {
|
|
pThisProcess->pProcessName = NULL;
|
|
}
|
|
|
|
pThisProcess->dwProcessId = HandleToUlong(pProcess->UniqueProcessId);
|
|
pThisProcess->hProcess = hProcess;
|
|
|
|
// zero list pointers
|
|
pThisProcess->pMemBlockInfo = NULL;
|
|
pThisProcess->pNextProcess = NULL;
|
|
|
|
if (hProcess) {
|
|
|
|
Status = NtQueryInformationProcess (
|
|
hProcess,
|
|
ProcessBasicInformation,
|
|
pThisProcess->BasicInfo,
|
|
sizeof (PROCESS_BASIC_INFORMATION),
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)){
|
|
// if error reading data, then bail out
|
|
goto SuccessExit;
|
|
}
|
|
|
|
// get pointer to the Process Environment Block
|
|
|
|
pPeb = pThisProcess->BasicInfo->PebBaseAddress;
|
|
|
|
// read address of loader information structure
|
|
|
|
Status = NtReadVirtualMemory (
|
|
hProcess,
|
|
&pPeb->Ldr,
|
|
&Ldr,
|
|
sizeof (Ldr),
|
|
NULL);
|
|
|
|
// bail out if unable to read information
|
|
|
|
if (!NT_SUCCESS(Status)){
|
|
// if error reading data, then bail out
|
|
goto SuccessExit;
|
|
}
|
|
|
|
//
|
|
// get head pointer to linked list of memory modules used by
|
|
// this process
|
|
//
|
|
|
|
LdrHead = &Ldr->InMemoryOrderModuleList;
|
|
|
|
// Get address of next list entry
|
|
|
|
Status = NtReadVirtualMemory (
|
|
hProcess,
|
|
&LdrHead->Flink,
|
|
&LdrNext,
|
|
sizeof (LdrNext),
|
|
NULL);
|
|
|
|
// bail out if unable to read information
|
|
|
|
if (!NT_SUCCESS(Status)){
|
|
// if error reading data, then bail out
|
|
goto SuccessExit;
|
|
}
|
|
|
|
pLastModule = NULL;
|
|
|
|
// walk down the list of modules until back at the top.
|
|
// to list all the images in use by this process
|
|
|
|
while ( LdrNext != LdrHead ) {
|
|
// get record attached to list entry
|
|
pLdrEntry = CONTAINING_RECORD(LdrNext,
|
|
LDR_DATA_TABLE_ENTRY,
|
|
InMemoryOrderLinks);
|
|
|
|
Status = NtReadVirtualMemory(
|
|
hProcess,
|
|
pLdrEntry,
|
|
&LdrEntryData,
|
|
sizeof(LdrEntryData),
|
|
NULL
|
|
);
|
|
// if unable to read memory, then give up rest of search
|
|
// and return what we have already.
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
goto SuccessExit;
|
|
}
|
|
|
|
|
|
pNewModule = GetModuleVaData (
|
|
&LdrEntryData,
|
|
pThisProcess);
|
|
if (pNewModule) { // if structure returned...
|
|
dwModuleCount++;
|
|
if (!pLastModule) { // if this is the first module...
|
|
// then set list head pointer
|
|
pThisProcess->pMemBlockInfo = pNewModule;
|
|
} else {
|
|
// otherwise link to list
|
|
pLastModule->pNextModule = pNewModule;
|
|
}
|
|
pLastModule = pNewModule;
|
|
}
|
|
LdrNext = LdrEntryData.InMemoryOrderLinks.Flink;
|
|
} // end while not at end of list
|
|
|
|
|
|
// now that we have a list of all images, query the process'
|
|
// virtual memory for the list of memory blocks in use by this
|
|
// process and assign them to the appropriate category of memory
|
|
|
|
pBaseAddress = NULL; // start at 0 and go to end of User VA space
|
|
|
|
while (pBaseAddress < STOP_AT) { // truncate to 32-bit if necessary
|
|
|
|
Status = NtQueryVirtualMemory (
|
|
hProcess,
|
|
pBaseAddress,
|
|
MemoryBasicInformation,
|
|
&VaBasicInfo,
|
|
sizeof(VaBasicInfo),
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto SuccessExit;
|
|
} else {
|
|
// get protection type for index into counter array
|
|
dwRegionSize = VaBasicInfo.RegionSize;
|
|
switch (VaBasicInfo.State) {
|
|
case MEM_COMMIT:
|
|
// if the memory is for an IMAGE, then search the image list
|
|
// for the corresponding image to update
|
|
dwProtection = ProtectionToIndex(VaBasicInfo.Protect);
|
|
if (VaBasicInfo.Type == MEM_IMAGE) {
|
|
// update process total
|
|
pThisProcess->MemTotals.CommitVector[dwProtection] += dwRegionSize;
|
|
pMod = LocateModInfo (pThisProcess->pMemBlockInfo, pBaseAddress, dwRegionSize);
|
|
if (pMod) { // if matching image found, then update
|
|
pMod->CommitVector[dwProtection] += dwRegionSize;
|
|
pMod->TotalCommit += dwRegionSize;
|
|
} else { // otherwise update orphan total
|
|
pThisProcess->OrphanTotals.CommitVector[dwProtection] += dwRegionSize;
|
|
}
|
|
} else {
|
|
// if not assigned to an image, then update the process
|
|
// counters
|
|
if (VaBasicInfo.Type == MEM_MAPPED) {
|
|
pThisProcess->MappedCommit[dwProtection] += dwRegionSize;
|
|
} else {
|
|
pThisProcess->PrivateCommit[dwProtection] += dwRegionSize;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MEM_RESERVE:
|
|
if (VaBasicInfo.Type == MEM_IMAGE) {
|
|
pThisProcess->ImageReservedBytes += dwRegionSize;
|
|
} else {
|
|
pThisProcess->ReservedBytes += dwRegionSize;
|
|
}
|
|
break;
|
|
|
|
case MEM_FREE:
|
|
if (VaBasicInfo.Type == MEM_IMAGE) {
|
|
pThisProcess->ImageFreeBytes += dwRegionSize;
|
|
} else {
|
|
pThisProcess->FreeBytes += dwRegionSize;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
} // end switch (VaBasicInfo.State)
|
|
} // endif QueryVM ok
|
|
|
|
// go to next memory block
|
|
|
|
pBaseAddress = (PVOID)((ULONG_PTR)pBaseAddress + dwRegionSize);
|
|
|
|
} // end whil not at the end of memory
|
|
} // endif hProcess not NULL
|
|
} // endif pThisProcess not NULL
|
|
|
|
SuccessExit:
|
|
|
|
if (hProcess) CloseHandle(hProcess);
|
|
|
|
return pThisProcess;
|
|
|
|
//
|
|
// error recovery section, called when the routine is unable to
|
|
// complete successfully to clean up before leaving
|
|
//
|
|
|
|
PBailOut:
|
|
if (pThisProcess->BasicInfo) {
|
|
FREEMEM (pThisProcess->BasicInfo);
|
|
}
|
|
FREEMEM (pThisProcess);
|
|
if (hProcess) CloseHandle(hProcess);
|
|
return NULL;
|
|
}
|
|
|
|
PMODINFO
|
|
GetModuleVaData (
|
|
PLDR_DATA_TABLE_ENTRY ModuleListEntry, // module information structure
|
|
PPROCESS_VA_INFO pProcess // process data structure
|
|
)
|
|
/*++
|
|
|
|
GetModuleVaData
|
|
|
|
Gets the Virtual Memory usage details for the module pointed to by the
|
|
Process Memory Module List Entry argument in the argument list
|
|
|
|
Note that this routine allocates data structures that must be freed
|
|
(using the FreeModuleVaData routine) when finished with them.
|
|
|
|
Arguments
|
|
|
|
IN HANDLE ModuleListEntry
|
|
|
|
Return Value
|
|
|
|
Pointer to completed Module VA info structure or
|
|
NULL if unable to collect data
|
|
|
|
--*/
|
|
{
|
|
PMODINFO pThisModule = NULL; // module structure that is returned
|
|
PUNICODE_STRING pusInstanceName = NULL; // process->image
|
|
PUNICODE_STRING pusLongInstanceName = NULL; // process->fullimagepath
|
|
UNICODE_STRING usImageFileName = {0,0, NULL}; // image file name
|
|
UNICODE_STRING usExeFileName = {0,0, NULL}; // short name
|
|
UNICODE_STRING usNtFileName = {0,0, NULL}; // full Nt File Name
|
|
|
|
PWCHAR p,p1;
|
|
NTSTATUS Status;
|
|
HANDLE hFile;
|
|
HANDLE hMappedFile;
|
|
WORD wStringSize;
|
|
|
|
PVOID MappedAddress;
|
|
PVOID MapBase;
|
|
SIZE_T dwMappedSize;
|
|
|
|
PIMAGE_DOS_HEADER DosHeader;
|
|
PIMAGE_NT_HEADERS FileHeader;
|
|
|
|
LARGE_INTEGER liSectionSize;
|
|
PLARGE_INTEGER pliSectionSize;
|
|
LARGE_INTEGER liSectionOffset;
|
|
OBJECT_ATTRIBUTES obFile;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
BOOL bRetCode;
|
|
USHORT wBufOffset;
|
|
USHORT wDiffSize;
|
|
|
|
// allocate this item's memory
|
|
|
|
pThisModule = ALLOCMEM (sizeof (MODINFO));
|
|
|
|
if (!pThisModule) {
|
|
return NULL;
|
|
}
|
|
|
|
// allocate this items Instance Name Buffer
|
|
|
|
wStringSize = (WORD)(ModuleListEntry->BaseDllName.MaximumLength +
|
|
sizeof (UNICODE_NULL));
|
|
|
|
pusInstanceName = ALLOCMEM (wStringSize + sizeof(UNICODE_STRING)) ;
|
|
|
|
if (!pusInstanceName) {
|
|
goto MBailOut;
|
|
}
|
|
|
|
pusInstanceName->Length = 0;
|
|
pusInstanceName->MaximumLength = wStringSize;
|
|
pusInstanceName->Buffer = (PWCHAR)&pusInstanceName[1];
|
|
|
|
// save instance name using full file path
|
|
|
|
wStringSize = (WORD)(ModuleListEntry->FullDllName.MaximumLength +
|
|
sizeof (UNICODE_NULL));
|
|
|
|
pusLongInstanceName = ALLOCMEM (wStringSize + sizeof (UNICODE_STRING));
|
|
|
|
if (!pusLongInstanceName) {
|
|
goto MBailOut;
|
|
}
|
|
|
|
pusLongInstanceName->Length = 0;
|
|
pusLongInstanceName->MaximumLength = wStringSize;
|
|
pusLongInstanceName->Buffer = (PWCHAR)&pusLongInstanceName[1];
|
|
|
|
// allocate temporary buffer for image name
|
|
|
|
usImageFileName.Length = ModuleListEntry->FullDllName.Length;
|
|
usImageFileName.MaximumLength = ModuleListEntry->FullDllName.MaximumLength;
|
|
usImageFileName.Buffer = ALLOCMEM(usImageFileName.MaximumLength);
|
|
if ( !usImageFileName.Buffer ) {
|
|
goto MBailOut;
|
|
}
|
|
|
|
// allocate temporary buffer for exe name
|
|
|
|
usExeFileName.Length = ModuleListEntry->BaseDllName.Length;
|
|
usExeFileName.MaximumLength = ModuleListEntry->BaseDllName.MaximumLength;
|
|
usExeFileName.Buffer = ALLOCMEM(usExeFileName.MaximumLength);
|
|
if ( !usExeFileName.Buffer ) {
|
|
goto MBailOut;
|
|
}
|
|
usExeFileName.Buffer[0] = UNICODE_NULL;
|
|
|
|
// read base .exe/.dll name of image
|
|
|
|
Status = NtReadVirtualMemory(
|
|
pProcess->hProcess,
|
|
ModuleListEntry->BaseDllName.Buffer,
|
|
usExeFileName.Buffer,
|
|
usExeFileName.MaximumLength,
|
|
NULL
|
|
);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
goto MBailOut;
|
|
}
|
|
|
|
usImageFileName.Buffer[0] = UNICODE_NULL;
|
|
// read full name of image
|
|
Status = NtReadVirtualMemory(
|
|
pProcess->hProcess,
|
|
ModuleListEntry->FullDllName.Buffer,
|
|
usImageFileName.Buffer,
|
|
usImageFileName.MaximumLength,
|
|
NULL
|
|
);
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
goto MBailOut;
|
|
}
|
|
|
|
// make a DOS filename to convert to NT again
|
|
|
|
wDiffSize = wBufOffset = 0;
|
|
p = p1 = usImageFileName.Buffer;
|
|
while (*p != (WCHAR)0){
|
|
if (*p == L':'){
|
|
p1 = p;
|
|
wDiffSize = wBufOffset;
|
|
}
|
|
wBufOffset += sizeof(WCHAR);
|
|
p++;
|
|
}
|
|
if (p1 != usImageFileName.Buffer) {
|
|
// move pointer
|
|
usImageFileName.Buffer = --p1;
|
|
// adjust length fields
|
|
wDiffSize -= (USHORT)(sizeof(WCHAR));
|
|
usImageFileName.Length = usImageFileName.Length - wDiffSize;
|
|
usImageFileName.MaximumLength = usImageFileName.MaximumLength - wDiffSize;
|
|
}
|
|
|
|
// Create/copy a NT filename for Nt file operation
|
|
|
|
bRetCode = RtlDosPathNameToNtPathName_U (
|
|
usImageFileName.Buffer,
|
|
&usNtFileName,
|
|
NULL,
|
|
NULL);
|
|
|
|
if ( !bRetCode ) {
|
|
goto MBailOut;
|
|
}
|
|
|
|
// get handle to file
|
|
|
|
InitializeObjectAttributes(
|
|
&obFile,
|
|
&usNtFileName,
|
|
FILE_ATTRIBUTE_NORMAL | OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Status = NtCreateFile (
|
|
&hFile,
|
|
(ACCESS_MASK)GENERIC_READ | SYNCHRONIZE | FILE_READ_ATTRIBUTES,
|
|
&obFile,
|
|
&IoStatusBlock,
|
|
NULL,
|
|
FILE_ATTRIBUTE_NORMAL & FILE_ATTRIBUTE_VALID_FLAGS,
|
|
FILE_SHARE_READ,
|
|
FILE_OPEN,
|
|
0,
|
|
NULL,
|
|
0);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto MBailOut;
|
|
}
|
|
|
|
pliSectionSize = &liSectionSize;
|
|
liSectionSize.HighPart = 0;
|
|
liSectionSize.LowPart = 0;
|
|
|
|
InitializeObjectAttributes (
|
|
&obFile,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL);
|
|
|
|
Status = NtCreateSection (
|
|
&hMappedFile,
|
|
SECTION_QUERY | SECTION_MAP_READ,
|
|
&obFile,
|
|
pliSectionSize,
|
|
PAGE_READONLY,
|
|
SEC_COMMIT,
|
|
hFile);
|
|
|
|
if ( ! NT_SUCCESS(Status)) {
|
|
CloseHandle(hFile);
|
|
goto MBailOut;
|
|
}
|
|
|
|
// get pointer to mapped memory
|
|
MappedAddress = MapBase = NULL;
|
|
dwMappedSize = 0;
|
|
|
|
liSectionOffset.LowPart = 0;
|
|
liSectionOffset.HighPart = 0;
|
|
|
|
Status = NtMapViewOfSection (
|
|
hMappedFile,
|
|
NtCurrentProcess(),
|
|
&MapBase,
|
|
0L,
|
|
0L,
|
|
&liSectionOffset,
|
|
&dwMappedSize,
|
|
ViewShare,
|
|
0L,
|
|
PAGE_READONLY);
|
|
|
|
CloseHandle(hMappedFile);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
MappedAddress = MapBase;
|
|
} else {
|
|
CloseHandle(hFile);
|
|
goto MBailOut;
|
|
}
|
|
|
|
// check for dos image signature (if a dos file)
|
|
|
|
DosHeader = (PIMAGE_DOS_HEADER)MappedAddress;
|
|
|
|
if ( DosHeader->e_magic != IMAGE_DOS_SIGNATURE ) {
|
|
UnmapViewOfFile(MappedAddress);
|
|
CloseHandle(hFile);
|
|
goto MBailOut;
|
|
}
|
|
|
|
FileHeader = (PIMAGE_NT_HEADERS)((UINT_PTR)DosHeader + DosHeader->e_lfanew);
|
|
|
|
if ( FileHeader->Signature != IMAGE_NT_SIGNATURE ) {
|
|
UnmapViewOfFile(MappedAddress);
|
|
CloseHandle(hFile);
|
|
goto MBailOut;
|
|
}
|
|
|
|
// get base address for this module and save in local data structure
|
|
|
|
pThisModule->BaseAddress = ModuleListEntry->DllBase;
|
|
|
|
// get image name
|
|
|
|
RtlCopyUnicodeString (
|
|
pusInstanceName,
|
|
&usExeFileName);
|
|
|
|
RtlCopyUnicodeString (
|
|
pusLongInstanceName,
|
|
&usImageFileName);
|
|
|
|
pThisModule->InstanceName = pusInstanceName;
|
|
pThisModule->LongInstanceName = pusLongInstanceName;
|
|
pThisModule->pNextModule = NULL;
|
|
pThisModule->TotalCommit = 0;
|
|
|
|
memset (
|
|
&pThisModule->CommitVector[0], 0,
|
|
sizeof (pThisModule->CommitVector));
|
|
|
|
pThisModule->VirtualSize = FileHeader->OptionalHeader.SizeOfImage;
|
|
|
|
// close file handles
|
|
|
|
UnmapViewOfFile(MappedAddress);
|
|
CloseHandle(hFile);
|
|
|
|
// free local memory
|
|
// this is allocated by an RTL function RtlDosPathNameToNtPathName_U.
|
|
RtlFreeHeap(RtlProcessHeap(), 0, usNtFileName.Buffer);
|
|
|
|
// FREEMEM (
|
|
// RelativeName.RelativeName.Buffer);
|
|
|
|
FREEMEM (usExeFileName.Buffer);
|
|
|
|
return (pThisModule); // return pointer to completed module structure
|
|
//
|
|
// Module bail out point, called when the routine is unable to continue
|
|
// for some reason. This cleans up any allocated memory, etc.
|
|
//
|
|
MBailOut:
|
|
|
|
if (pThisModule) {
|
|
FREEMEM (pThisModule);
|
|
}
|
|
|
|
if (usNtFileName.Buffer) {
|
|
// this is allocated by an RTL function RtlDosPathNameToNtPathName_U.
|
|
RtlFreeHeap(RtlProcessHeap(), 0, usNtFileName.Buffer);
|
|
}
|
|
|
|
// if (RelativeName.RelativeName.Buffer) {
|
|
// FREEMEM (
|
|
// RelativeName.RelativeName.Buffer);
|
|
// }
|
|
|
|
if (pusInstanceName) {
|
|
FREEMEM (pusInstanceName);
|
|
|
|
}
|
|
|
|
if (pusLongInstanceName) {
|
|
FREEMEM (pusLongInstanceName);
|
|
|
|
}
|
|
|
|
if (usExeFileName.Buffer){
|
|
FREEMEM (usExeFileName.Buffer);
|
|
}
|
|
|
|
if (usImageFileName.Buffer) {
|
|
FREEMEM(usImageFileName.Buffer);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
PMODINFO
|
|
LocateModInfo(
|
|
IN PMODINFO pFirstMod,
|
|
IN PVOID pAddress,
|
|
IN SIZE_T dwExtent
|
|
)
|
|
/*++
|
|
|
|
LocateModInfo
|
|
|
|
Locates the images associated with the address passed in the argument list
|
|
|
|
Arguments
|
|
|
|
IN PMODINFO pFirstMod,
|
|
first module entry in process list
|
|
|
|
IN PVOID Address
|
|
Address to search for in list
|
|
|
|
Return Value
|
|
|
|
Pointer to matching image or
|
|
NULL if no match found
|
|
|
|
--*/
|
|
{
|
|
PMODINFO pThisMod;
|
|
|
|
pThisMod = pFirstMod;
|
|
|
|
while (pThisMod) { // go to end of list or match is found
|
|
|
|
// match criteria are:
|
|
// address >= Module BaseAddress and
|
|
// address+extent between base and base+image_extent
|
|
|
|
if (pAddress >= pThisMod->BaseAddress) {
|
|
if ((PVOID)((PDWORD)pAddress + dwExtent) <=
|
|
(PVOID)((ULONG_PTR)pThisMod->BaseAddress+pThisMod->VirtualSize)) {
|
|
return (pThisMod);
|
|
}
|
|
}
|
|
|
|
pThisMod = pThisMod->pNextModule;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
DWORD
|
|
ProtectionToIndex(
|
|
IN ULONG Protection
|
|
)
|
|
/*++
|
|
|
|
ProtectionToIndex
|
|
|
|
Determine the memory access protection type and return local code
|
|
|
|
Arguments
|
|
|
|
IN ULONG
|
|
Protection
|
|
|
|
Process memory protection mask
|
|
|
|
Return Value
|
|
|
|
Local value of protection type
|
|
|
|
--*/
|
|
{
|
|
Protection &= (PAGE_NOACCESS |
|
|
PAGE_READONLY |
|
|
PAGE_READWRITE |
|
|
PAGE_WRITECOPY |
|
|
PAGE_EXECUTE |
|
|
PAGE_EXECUTE_READ |
|
|
PAGE_EXECUTE_READWRITE |
|
|
PAGE_EXECUTE_WRITECOPY);
|
|
|
|
switch ( Protection ) {
|
|
|
|
case PAGE_NOACCESS:
|
|
return NOACCESS;
|
|
|
|
case PAGE_READONLY:
|
|
return READONLY;
|
|
|
|
case PAGE_READWRITE:
|
|
return READWRITE;
|
|
|
|
case PAGE_WRITECOPY:
|
|
return WRITECOPY;
|
|
|
|
case PAGE_EXECUTE:
|
|
return EXECUTE;
|
|
|
|
case PAGE_EXECUTE_READ:
|
|
return EXECUTEREAD;
|
|
|
|
case PAGE_EXECUTE_READWRITE:
|
|
return EXECUTEREADWRITE;
|
|
|
|
case PAGE_EXECUTE_WRITECOPY:
|
|
return EXECUTEWRITECOPY;
|
|
default:
|
|
return 0xFFFFFFFF;
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
FreeSystemVaData (
|
|
IN PPROCESS_VA_INFO pFirstProcess
|
|
)
|
|
{
|
|
PPROCESS_VA_INFO pThisProcess, pNextProcess;
|
|
|
|
pThisProcess = pFirstProcess;
|
|
while (pThisProcess) {
|
|
pNextProcess = pThisProcess->pNextProcess; // save pointer to next
|
|
FreeProcessVaData (pThisProcess);
|
|
pThisProcess = pNextProcess; // do next until NULL pointer
|
|
}
|
|
return (FALSE);
|
|
}
|
|
|
|
BOOL
|
|
FreeProcessVaData (
|
|
IN PPROCESS_VA_INFO pProcess
|
|
)
|
|
{
|
|
PMODINFO pThisModule, pNextModule;
|
|
|
|
if (pProcess) {
|
|
if (pProcess->pProcessName) {
|
|
FREEMEM (pProcess->pProcessName);
|
|
pProcess->pProcessName = NULL;
|
|
}
|
|
if (pProcess->BasicInfo) {
|
|
FREEMEM (pProcess->BasicInfo);
|
|
pProcess->BasicInfo = NULL;
|
|
}
|
|
|
|
|
|
pThisModule = pProcess->pMemBlockInfo;
|
|
while (pThisModule) {
|
|
pNextModule = pThisModule->pNextModule;
|
|
FreeModuleVaData (pThisModule);
|
|
pThisModule = pNextModule;
|
|
}
|
|
//
|
|
// and finally throw ourselves away
|
|
//
|
|
FREEMEM (pProcess);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
FreeModuleVaData (
|
|
IN PMODINFO pModule
|
|
)
|
|
{
|
|
if (pModule) {
|
|
if (pModule->InstanceName) {
|
|
FREEMEM(pModule->InstanceName);
|
|
pModule->InstanceName = NULL;
|
|
}
|
|
if (pModule->LongInstanceName) {
|
|
FREEMEM(pModule->LongInstanceName);
|
|
pModule->LongInstanceName = NULL;
|
|
}
|
|
FREEMEM (pModule);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|