Издание четвертое windows ® для профессионалов создание эффективных Win32-приложений с учетом специфики 64-разрядной версии Windows


Г ЛАВА 14Исследование виртуальной памятиРис. 14-1



Pdf просмотр
страница36/68
Дата28.11.2016
Размер3.57 Mb.
Просмотров12472
Скачиваний0
1   ...   32   33   34   35   36   37   38   39   ...   68
Г ЛАВА 14
Исследование виртуальной памяти
Рис. 14-1.
продолжение
_stprintf(szBuf, TEXT("0x%016I64X"), (__int64) sinf.dwActiveProcessorMask);
SetDlgItemText(hwnd, IDC_ACTIVEPROCMASK, szBuf);
SetDlgItemText(hwnd, IDC_NUMOFPROCS,
BigNumToString(sinf.dwNumberOfProcessors, szBuf));
SetDlgItemText(hwnd, IDC_ALLOCGRAN,
BigNumToString(sinf.dwAllocationGranularity, szBuf));
return(TRUE);
}
///////////////////////////////////////////////////////////////////////////////
void Dlg_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) {
switch (id) {
case IDCANCEL:
EndDialog(hwnd, id);
break;
}
}
///////////////////////////////////////////////////////////////////////////////
INT_PTR WINAPI Dlg_Proc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
chHANDLE_DLGMSG(hDlg, WM_INITDIALOG, Dlg_OnInitDialog);
chHANDLE_DLGMSG(hDlg, WM_COMMAND,
Dlg_OnCommand);
}
return(FALSE);
}
///////////////////////////////////////////////////////////////////////////////
int WINAPI _tWinMain(HINSTANCE hinstExe, HINSTANCE, PTSTR pszCmdLine, int) {
OSVERSIONINFO vi = { sizeof(vi) };
GetVersionEx(&vi);
g_fWin9xIsHost = (vi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
DialogBox(hinstExe, MAKEINTRESOURCE(IDD_SYSINFO), NULL, Dlg_Proc);
return(0);
}
//////////////////////////////// Конец файла //////////////////////////////////
Статус виртуальной памяти
Windows функция
GlobalMemoryStatus позволяет отслеживать текущее состояние памяти
348
Ч АС Т Ь I I I
УПРАВЛЕНИЕ ПАМЯТЬЮ
На мой взгляд, она названа крайне неудачно имя
GlobalMemoryStatus подразумевает, что функция каким то образом связана с глобальными кучами в 16 разрядной. Мне кажется, что лучше было бы назвать функцию
GlobalMemoryStatus по другому — скажем,
VirtualMemoryStatus.
При вызове функции
GlobalMemoryStatus Вы должны передать адрес структуры. Вот эта структура struct _MEMORYSTATUS {
DWORD dwLength;
DWORD dwMemoryLoad;
SIZE_T dwTotalPhys;
SIZE_T dwAvailPhys;
SIZE_T dwTotalPageFile;
SIZE_T dwAvailPageFile;
SIZE_T dwTotalVirtual;
SIZE_T dwAvailVirtual;
} MEMORYSTATUS, Перед вызовом
GlobalMemoryStatus надо записать в элемент dwLength размер структуры в байтах. Такой принцип вызова функции дает возможность Microsoft расширять эту структуру в будущих версиях Windows, не нарушая работу существующих приложений. После вызова
GlobalMemoryStatus инициализирует остальные элементы структуры и возвращает управление. Назначение элементов этой структуры Вы узнаете из следующего разделав котором рассматривается программа пример Если Вы полагаете, что Ваше приложение будет работать на машинах с объемом оперативной памяти более 4 Гб или файлом подкачки более 4 Гб, используйте новую функцию
GlobalMemoryStatusEx:
BOOL GlobalMemoryStatusEx(LPMEMORYSTATUSEX Вы должны передать ей адрес новой структуры MEMORYSTATUSEX:
typedef struct _MEMORYSTATUSEX {
DWORD dwLength;
DWORD dwMemoryLoad;
DWORDLONG ullTotalPhys;
DWORDLONG ullAvailPhys;
DWORDLONG ullTotalPageFile;
DWORDLONG ullAvailPageFile;
DWORDLONG ullTotalVirtual;
DWORDLONG ullAvailVirtual;
DWORDLONG ullAvailExtendedVirtual;
} MEMORYSTATUSEX, Эта структура идентична первоначальной структуре MEMORYSTATUS с одним исключением все ее элементы имеют размер побита, что позволяет оперировать со значениями, превышающими 4 Гб. Последний элемент,
ullAvailExtendedVirtual, указывает размер незарезервированной памяти в самой большой области памяти виртуального адресного пространства вызывающего процесса. Этот элемент имеет смысл только для процессоров определенных архитектур при определенных конфигурациях.
Программа-пример VMStat
Эта программа, «14 VMStat.exe» (см. листинг на рис. 14 2), выводит на экран окно с результатами вызова
GlobalMemoryStatus. Информация в окне обновляется каждую секунду, так что VMStat вполне пригодна для мониторинга памяти в системе. Файлы

349
Г ЛАВА 14
Исследование виртуальной памяти исходного кода и ресурсов этой программы находятся в каталоге 14 VMStat на компакт диске, прилагаемом к книге. Окно этой программы после запуска в Windows на машине с процессором Intel Pentium II и 128 Мб оперативной памяти показано ниже.
Элемент
dwMemoryLoad (показываемый как Memory Load) позволяет оценить, насколько занята подсистема управления памятью. Это число может быть любым в диапазоне от 0 до 100. В Windows 98 и Windows 2000 алгоритмы, используемые для его подсчета, различны. Кроме того, в будущих версиях операционных систем этот алгоритм почти наверняка придется модифицировать. Но, честно говоря, на практике от значения этого элемента толку немного.
Элемент
dwTotalPhys (показываемый как TotalPhys) отражает общий объем физической (оперативной) памяти в байтах. На данной машине си Мб оперативной памяти его значение составляет 133 677 056, что на 540 672 байта меньше Мб. Причина, по которой
GlobalMemoryStatus не сообщает о полных 128 Мб, кроется в том, что система при загрузке резервирует небольшой участок оперативной памяти, недоступный даже ядру. Этот участок никогда не сбрасывается на диск. А элемент (показываемый как AvailPhys) дает число байтов свободной физической памяти.
Элемент
dwTotalPageFile (показываемый как TotalPageFile) сообщает максимальное количество байтов, которое может содержаться в страничном файле (файлах) на жестком диске (дисках. Хотя VMStat показывает, что текущий размер страничного файла составляет 318 574 592 байта, система может варьировать его по своему усмотрению. Элемент
dwAvailPageFile (показываемый как AvailPageFile) подсказывает, что в данный момент 233 046 016 байтов в страничном файле свободно и может быть передано любому процессу.
Элемент
dwTotalVirtual (показываемый как TotalVirtual) отражает общее количество байтов, отведенных под закрытое адресное пространство процесса. Значение 147 352 576 ровно на 128 Кб меньше 2 Гб. Два раздела недоступного адресного пространства от 0x00000000 дои от 0x7FFF0000 до 0x7FFFFFFF — как рази составляют эту разницу в 128 Кб. Запустив VMStat в Windows 98, Вы увидите, что значение этого элемента поменялось на 2 143 289 344 (2 Гб за вычетом 4 Мб). Разница в 4 Мб возникает из за того, что Windows 98 блокирует нижний раздел от до 0x003FFFFF (размером в 4 Мб).
И, наконец,
dwAvailVirtual (показываемый как AvailVirtual) — единственный элемент структуры, специфичный для конкретного процесса, вызывающего
GlobalMemoryStatus
(остальные элементы относятся исключительно к самой системе и не зависят от того,
какой именно процесс вызывает эту функцию. При подсчете значения
dwAvailVirtual
функция суммирует размеры всех свободных регионов в адресном пространстве вызывающего процесса. В данном случае его значение говорит о том, что в распоряжении программы VMStat имеется 2 136 846 336 байтов свободного адресного пространства. Вычтя из значения
dwTotalVirtual величину dwAvailVirtual, Вы получите 10 506 байтов — такой объем памяти VMStat зарезервировала в своем виртуальном адресном

350
Ч АС Т Ь I I I
УПРАВЛЕНИЕ ПАМЯТЬЮ
пространстве. Отдельного элемента, который сообщал бы количество физической памяти, используемой процессом в данный момент, не предусмотрено.
VMStat.cpp
/******************************************************************************
Модуль: Автор Copyright (c) 2000, Джеффри Рихтер (Jeffrey Richter)
******************************************************************************/
#include "..\CmnHdr.h"
/* см. приложение А */
#include
#include
#include
#include "Resource.h"
///////////////////////////////////////////////////////////////////////////////
// идентификатор таймера, отвечающего за обновление информации IDT_UPDATE
1
///////////////////////////////////////////////////////////////////////////////
BOOL Dlg_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam) {
chSETDLGICONS(hwnd, IDI_VMSTAT);
// устанавливаем таймер так, чтобы периодически обновлять информацию, IDT_UPDATE, 1 * 1000, NULL);
// выдаем сообщение таймера для первого обновления, IDT_UPDATE, SendMessage);
return(TRUE);
}
///////////////////////////////////////////////////////////////////////////////
void Dlg_OnTimer(HWND hwnd, UINT id) {
// прежде чем передать структуру функции GlobalMemoryStatus,
// заносим в элемент dwLength ее длину ms = { sizeof(ms) };
GlobalMemoryStatus(&ms);
TCHAR szData[512] = { 0 };
_stprintf(szData, TEXT("%d\n%d\n%I64d\n%I64d\n%I64d\n%I64d\n%I64d"),
ms.dwMemoryLoad, ms.dwTotalPhys,
(__int64) ms.dwAvailPhys,
(__int64) ms.dwTotalPageFile,
(__int64) ms.dwAvailPageFile, (__int64) ms.dwTotalVirtual,
(__int64) ms.dwAvailVirtual);
SetDlgItemText(hwnd, IDC_DATA, szData);
}
Рис. 14-2.
Программа-пример VMStat

351
Г ЛАВА 14
Исследование виртуальной памяти
Рис. 14-2.
продолжение
///////////////////////////////////////////////////////////////////////////////
void Dlg_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) {
switch (id) {
case IDCANCEL:
KillTimer(hwnd, IDT_UPDATE);
EndDialog(hwnd, id);
break;
}
}
///////////////////////////////////////////////////////////////////////////////
INT_PTR WINAPI Dlg_Proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
chHANDLE_DLGMSG(hwnd, WM_INITDIALOG, Dlg_OnInitDialog);
chHANDLE_DLGMSG(hwnd, WM_COMMAND,
Dlg_OnCommand);
chHANDLE_DLGMSG(hwnd, WM_TIMER,
Dlg_OnTimer);
}
return(FALSE);
}
///////////////////////////////////////////////////////////////////////////////
int WINAPI _tWinMain(HINSTANCE hinstExe, HINSTANCE, PTSTR pszCmdLine, int) {
DialogBox(hinstExe, MAKEINTRESOURCE(IDD_VMSTAT), NULL, Dlg_Proc);
return(0);
}
//////////////////////////////// Конец файла //////////////////////////////////
Определение состояния адресного пространства
В Windows имеется функция, позволяющая запрашивать определенную информацию об участке памяти по заданному адресу (в пределах адресного пространства вызывающего процесса размер, тип памяти и атрибуты защиты. В частности, с ее помощью программа VMMap (ее листинг см. на рис. 14 4) выводит карты виртуальной памяти,
с которыми мы познакомились в главе 13. Вот эта функция VirtualQuery(
LPCVOID pvAddress,
PMEMORY_BASIC_INFORMATION pmbi,
DWORD Парная ей функция,
VirtualQueryEx, сообщает туже информацию о памяти, нов другом процессе VirtualQueryEx(
HANDLE hProcess,
LPCVOID pvAddress,
PMEMORY_BASIC_INFORMATION pmbi,
DWORD dwLength);

352
Ч АС Т Ь I I I
УПРАВЛЕНИЕ ПАМЯТЬЮ
Эти функции идентичны стем исключением, что
VirtualQueryEx принимает описатель процесса, об адресном пространстве которого Вы хотите получить информацию. Чаще всего функцией
VirtualQueryEx пользуются отладчики и системные утилиты остальные приложения обращаются к
VirtualQuery. При вызове VirtualQuery(Ex)
параметр
pvAddress должен содержать адрес виртуальной памяти, о которой Вы хотите получить информацию. Параметр
pmbi — это адрес структуры MEMORY_BA
SIC_INFORMATION, которую надо создать перед вызовом функции. Данная структура определена в файле WinNT.h так struct _MEMORY_BASIC_INFORMATION {
PVOID BaseAddress;
PVOID AllocationBase;
DWORD AllocationProtect;
SIZE_T RegionSize;
DWORD State;
DWORD Protect;
DWORD Type;
} MEMORY_BASIC_INFORMATION, Параметр
dwLength задает размер структуры MEMORY_BASIC_INFORMATION. Функция возвращает число байтов, скопированных в буфер.
Используя адрес, указанный Вами в параметре
pvAddress, функция VirtualQuery(Ex)
заполняет структуру информацией о диапазоне смежных страниц, имеющих одинаковые состояние, атрибуты защиты и тип. Описание элементов структуры приведено в таблице ниже.
Элемент
Описание
BaseAddress
Сообщает тоже значение, что и параметр
pvAddress, но округленное до ближайшего меньшего адреса, кратного размеру страницы.
AllocationBase
Идентифицирует базовый адрес региона, включающего в себя адрес,
указанный в параметре
pvAddress.
AllocationProtect
Идентифицирует атрибут защиты, присвоенный региону при его резервировании.
RegionSize
Сообщает суммарный размер (в байтах) группы страниц, которые начинаются с базового адреса
BaseAddress и имеют те же атрибуты защиты, состояние и тип, что и страница, расположенная по адресу, указанному в параметре
pvAddress.
State
Сообщает состояние (MEM_FREE, MEM_RESERVE или всех смежных страниц, которые имеют те же атрибуты защиты, состояние и тип, что и страница, расположенная по адресу, указанному в параметре
pvAddress.
При MEM_FREE элементы
AllocationBase, AllocationProtect, Protect и Type
содержат неопределенные значения, а при MEM_RESERVE неопределенное значение содержит элемент
Protect.
Protect
Идентифицирует атрибут защиты (PAGE_
∗) всех смежных страниц, которые имеют те же атрибуты защиты, состояние и тип, что и страница,
расположенная по адресу, указанному в параметре
pvAddress.
Type
Идентифицирует тип физической памяти (MEM_IMAGE, или MEM_PRIVATE), связанной с группой смежных страниц, которые имеют те же атрибуты защиты, состояние и тип, что и страница, расположенная по адресу, указанному в параметре
pvAddress. В Windows этот элемент всегда дает MEM_PRIVATE.

353
Г ЛАВА 14
Исследование виртуальной памяти
Функция VMQuery
Начиная изучать архитектуру памяти в Windows, я пользовался функцией
VirtualQuery
как поводырем. Если Вычитали первое издание моей книги, то заметите, что программа была гораздо проще ее нынешней версии, представленной в следующем разделе. Прежняя была построена на очень простом цикле, из которого периодически вызывалась функция
VirtualQuery, и для каждого вызова я формировал одну строку, содержавшую элементы структуры MEMORY_BASIC_INFORMATION. Изучая полученные дампы и сверяясь с документацией изв то время весьма неудачной),
я пытался разобраться в архитектуре подсистемы управления памятью. Что ж, с тех поря многому научился и теперь знаю, что функция
VirtualQuery и структура MEMO
RY_BASIC_INFORMATION не дают полной картины.
Проблема в том, что в MEMORY_BASIC_INFORMATION возвращается отнюдь не вся информация, имеющаяся в распоряжении системы. Если Вам нужны простейшие данные о состоянии памяти по конкретному адресу,
VirtualQuery действительно незаменима. Она отлично работает, если Вас интересует, передана ли поэтому адресу физическая память и доступен ли он для операций чтения или записи. Но попробуйте с ее помощью узнать общий размер зарезервированного региона и количество блоков в нем или выяснить, не содержит ли этот регион стек потока, — ничего не выйдет.
Чтобы получать более полную информацию о памяти, я создал собственную функцию и назвал ее
VMQuery:
BOOL VMQuery(
HANDLE hProcess,
PVOID pvAddress,
PVMQUERY По аналогии с
VirtualQueryEx она принимает в hProcess описатель процесса, в
pvAddress — адрес памяти, а в pVMQ — указатель на структуру, заполняемую самой функцией. Структура VMQUERY (тоже определенная мной) представляет собой вот что struct {
// информация о регионе pvRgnBaseAddress;
DWORD dwRgnProtection;
// PAGE_*
SIZE_T RgnSize;
DWORD dwRgnStorage;
// MEM_*: Free, Image, Mapped, Private
DWORD dwRgnBlocks;
DWORD dwRgnGuardBlks;
// если > 0, регион содержит стек потока fRgnIsAStack;
// TRUE, если регион содержит стек потока информация о блоке pvBlkBaseAddress;
DWORD dwBlkProtection;
// PAGE_*
SIZE_T BlkSize;
DWORD dwBlkStorage;
// MEM_*: Free, Reserve, Image, Mapped, Private
} VMQUERY, С первого взгляда заметно, что моя структура VMQUERY содержит куда больше информации, чем MEMORY_BASIC_INFORMATION. Она разбита (условно, конечно) на две части водной информация о регионе, в другой — информация о блоке (адрес которого указан в параметре
pvAddress). Элементы этой структуры описываются в следующей таблице.

354
Ч АС Т Ь I I I
УПРАВЛЕНИЕ ПАМЯТЬЮ
Элемент
Описание
pvRgnBaseAddress Идентифицирует базовый адрес региона виртуального адресного пространства, включающего адрес, указанный в параметре
pvAddress.
dwRgnProtection
Сообщает атрибут защиты, присвоенный региону при его резервиро вании.
RgnSize
Указывает размер (в байтах) зарезервированного региона.
dwRgnStorage
Идентифицирует тип физической памяти, используемой группой блоков данного региона MEM_FREE, MEM_IMAGE, MEM_MAPPED или. Поскольку Windows 98 не различает типы памяти, в этой операционной системе данный элемент содержит либо, либо MEM_PRIVATE.
dwRgnBlocks
Содержит значение — число блоков в указанном регионе.
dwRgnGuardBlks
Указывает число блоков с установленным флагом атрибутов защиты. Обычно это значение либо 0, либо 1. Если оно равно то регион скорее всего зарезервирован под стек потока. В Windows этот элемент всегда равен 0.
fRgnIsAStack
Сообщает, есть ли в данном регионе стек потока. Результат определяется на основе взвешенной оценки, так как невозможно дать стопроцентной гарантии тому, что в регионе содержится стек.
pvBlkBaseAddress
Идентифицирует базовый адрес блока, включающего адрес, указанный в параметре
pvAddress.
dwBlkProtection
Идентифицирует атрибут защиты блока, включающего адрес, указанный в параметре
pvAddress.
BlkSize
Содержит значение — размер блока (в байтах, включающего адрес,
указанный в параметре
pvAddress.
dwBlkStorage
Идентифицирует содержимое блока, включающего адрес, указанный в параметре
pvAddress. Принимает одно из значений MEM_FREE,
MEM_RESERVE, MEM_IMAGE, MEM_MAPPED или MEM_PRIVATE. В 98 этот элемент никогда не содержит значения и Чтобы получить всю эту информацию,
VMQuery, естественно, приходится выполнять гораздо больше операций (в том числе многократно вызывать
VirtualQueryEx), а потому она работает значительно медленнее
VirtualQueryEx. Так что Вы должны все тщательно взвесить, прежде чем остановить свой выбор на одной из этих функций.
Если Вам ненужна дополнительная информация, возвращаемая
VMQuery, используйте или VirtualQueryEx.
Листинг файла VMQuery.cpp (рис. 14 3) показывает, как я получаю и обрабатываю данные, необходимые для инициализации элементов структуры VMQUERY. (Файлы и VMQuery.h содержатся в каталоге 14 VMMap на компакт диске, прилагаемом к книге) Чтобы не объяснять подробности обработки данных на пальцах, я снабдил тексты программ массой комментариев, вольно разбросанных по всему коду.
VMQuery.cpp
/******************************************************************************
Модуль: Автор Copyright (c) 2000, Джеффри Рихтер (Jeffrey Richter)
******************************************************************************/
#include "..\CmnHdr.h"
/* см. приложение А */
Рис. 14-3.
Функция VMQuery

355
Г ЛАВА 14
Исследование виртуальной памяти
Рис. 14-3.
продолжение
#include
#include "VMQuery.h"
///////////////////////////////////////////////////////////////////////////////
// вспомогательная структура typedef struct {
SIZE_T RgnSize;
DWORD dwRgnStorage;
// MEM_*: Free, Image, Mapped, Private
DWORD dwRgnBlocks;
DWORD dwRgnGuardBlks; // если > 0, в регионе содержится стек потока fRgnIsAStack;
// TRUE, если в регионе содержится стек потока VMQUERY_HELP;
// глобальная статическая переменная, содержащая значение — гранулярность выделения памяти на данном типе процессора инициализируется при первом вызове VMQuery static DWORD gs_dwAllocGran = 0;
///////////////////////////////////////////////////////////////////////////////
// эта функция проходит по всем блокам в регионе и инициализирует структуру найденными значениями static BOOL VMQueryHelp(HANDLE hProcess, LPCVOID pvAddress,
VMQUERY_HELP *pVMQHelp) {
// каждый элемент содержит атрибут защиты страницы (например, зарезервирована, PAGE_NOACCESS, PAGE_READWRITE и т. д dwProtectBlock[4] = { 0 };
ZeroMemory(pVMQHelp, sizeof(*pVMQHelp));
// получаем базовый адрес региона, включающего переданный адрес памяти mbi;
BOOL fOk = (VirtualQueryEx(hProcess, pvAddress, &mbi, sizeof(mbi)) == sizeof(mbi));
if (!fOk)
return(fOk); // неверный адрес памяти, сообщаем об ошибке проходим по региону, начиная сего базового адреса (который никогда не изменится pvRgnBaseAddress = mbi.AllocationBase;
// начинаем с первого блока в регионе (соответствующая переменная будет изменяться в цикле pvAddressBlk = pvRgnBaseAddress;
// запоминаем тип физической памяти, переданной данному блоку pVMQHelp >dwRgnStorage = mbi.Type;
for (;;) {
// получаем информацию о текущем блоке
см. след. стр.

356
Ч АС Т Ь I I I
УПРАВЛЕНИЕ ПАМЯТЬЮ
Рис. 14-3.
продолжение
fOk = (VirtualQueryEx(hProcess, pvAddressBlk, &mbi, sizeof(mbi)) == sizeof(mbi));
if (!fOk)
break; // не удалось получить информацию прекращаем цикл проверяем, принадлежит ли текущий блок запрошенному региону if (mbi.AllocationBase != pvRgnBaseAddress)
break; // блок принадлежит следующему региону прекращаем цикл блок принадлежит запрошенному региону следующий оператор if служит для обнаружения стеков в Windows 98; в этой системе стеки размещаются в последних 4 блоках региона "зарезервированный PAGE_NOACCESS, PAGE_READWRITE и еще один "зарезервированный (pVMQHelp >dwRgnBlocks < 4) {
// если это блок 0–3, запоминаем тип защиты блока в массиве dwProtectBlock[pVMQHelp >dwRgnBlocks] =
(mbi.State == MEM_RESERVE) ? 0 : mbi.Protect;
} else {
// мы уже просмотрели 4 блока в этом регионе смещаем вниз элементы массива с атрибутами защиты, &dwProtectBlock[1],
sizeof(dwProtectBlock)
sizeof(DWORD));
// добавляем новые значения атрибутов защиты вконец массива dwProtectBlock[3] = (mbi.State == MEM_RESERVE) ? 0 : mbi.Protect;
}
pVMQHelp >dwRgnBlocks++;
// увеличиваем счетчик блоков в этом регионе на 1
pVMQHelp >RgnSize += mbi.RegionSize; // добавляем размер блока к размеру региона если блок имеет флаг PAGE_GUARD, добавляем 1 к счетчику блоков с этим флагом if ((mbi.Protect & PAGE_GUARD) == PAGE_GUARD)
pVMQHelp >dwRgnGuardBlks++;
// Делаем наиболее вероятное предположение о типе физической памяти переданной данному блоку. Стопроцентной гарантии дать нельзя потому что некоторые блоки могли быть преобразованы изв или изв в любой момент может быть замещен на MEM_IMAGE или MEM_MAPPED.
if (pVMQHelp >dwRgnStorage == MEM_PRIVATE)
pVMQHelp >dwRgnStorage = mbi.Type;
// получаем адрес следующего блока pvAddressBlk = (PVOID) ((PBYTE) pvAddressBlk + mbi.RegionSize);
}
// Обследовав регион, думаем не стекли это Windows 2000: да — если в регионе содержится хотя бы 1 блок с флагом PAGE_GUARD.
// Windows 9x: да — если в регионе содержится хотя бы 4 блока,

357
Г ЛАВА 14
Исследование виртуальной памяти
Рис. 14-3.
продолжение
// и они имеют такие атрибуты 3 й блок от конца зарезервирован 2 й блок от конца PAGE_NOACCESS
// 1 й блок от конца PAGE_READWRITE
// последний блок зарезервирован pVMQHelp >fRgnIsAStack =
(pVMQHelp >dwRgnGuardBlks > 0) ||
((pVMQHelp >dwRgnBlocks >= 4) &&
(dwProtectBlock[0] == 0) &&
(dwProtectBlock[1] == PAGE_NOACCESS) &&
(dwProtectBlock[2] == PAGE_READWRITE) &&
(dwProtectBlock[3] == 0));
return(TRUE);
}
///////////////////////////////////////////////////////////////////////////////
BOOL VMQuery(HANDLE hProcess, LPCVOID pvAddress, PVMQUERY pVMQ) {
if (gs_dwAllocGran == 0) {
// если это первый вызов, надо выяснить гранулярность
// выделения памяти в данной системе sinf;
GetSystemInfo(&sinf);
gs_dwAllocGran = sinf.dwAllocationGranularity;
}
ZeroMemory(pVMQ, sizeof(*pVMQ));
// получаем MEMORY_BASIC_INFORMATION для переданного адреса mbi;
BOOL fOk = (VirtualQueryEx(hProcess, pvAddress, &mbi, sizeof(mbi))
== sizeof(mbi));
if (!fOk)
return(fOk); // неверный адрес памяти, сообщаем об ошибке структура MEMORY_BASIC_INFORMATION содержит действительную информацию — пора заполнить элементы нашей структуры VMQUERY
// во первых, заполним элементы, описывающие состояние блока данные по региону получим позже switch (mbi.State) {
case MEM_FREE:
// свободный блок (незарезервированный)
pVMQ >pvBlkBaseAddress = NULL;
pVMQ >BlkSize = 0;
pVMQ >dwBlkProtection = 0;
pVMQ >dwBlkStorage = MEM_FREE;
break;
case MEM_RESERVE: // зарезервированный блок, которому не передана физическая память pVMQ >pvBlkBaseAddress = mbi.BaseAddress;
см. след. стр.
1   ...   32   33   34   35   36   37   38   39   ...   68


База данных защищена авторским правом ©nethash.ru 2019
обратиться к администрации

войти | регистрация
    Главная страница


загрузить материал