#include <Windows.h>
우선 기본적으로 사용 가능한 리전을 제로 베이스부터 반복으로 읽어오며 끝점까지 불러와야 한다.
그러기 위해서 사용 가능한 최소 메모리 주소 위치와 최대 메모리 주소 위치를 가져와야 한다. Windows.h 함수 중에서 GetSystemInfo 라는 함수가 있는데, 이 함수로부터 소프트웨어에 대한 시스템 인포를 가져올 수 있다.
SYSTEM_INFO *systemInfo = new SYSTEM_INFO();
GetSystemInfo(systemInfo);
GetSystemInfo 는 SYSTEM_INFO 구조체를 포인터 변수로 받아 반영해준다.
VOID *maximumAddress = systemInfo->lpMaximumApplicationAddress;
VOID *minimumAddress = systemInfo->lpMinimumApplicationAddress;
이 구조체를 포인터로 접근해서 maximumAddress 주소와 minimumAddress 주소를 가져올 수 있다. 즉 상기 minimumAddress 주소를 시작으로 리전을 탐색하되 사이즈를 늘려나가며 리전을 모두 찾아오고, maximumAddress 을 초과하면 리전 탐색을 중단하면 된다.
std::cout << "Min Address : " << minimumAddress << std::endl;
std::cout << "Max Address : " << maximumAddress << std::endl;
MEMORY_BASIC_INFORMATION* lpBuffer = new MEMORY_BASIC_INFORMATION();
SIZE_T sizeData = VirtualQuery(nowPosition, lpBuffer, sizeof(MEMORY_BASIC_INFORMATION));
std::cout << "[BASE] " << lpBuffer->BaseAddress << " [SIZE]" << lpBuffer->RegionSize << " [TYPE]" << message << std::endl;
먼저 VirtualQuery 를 요청할 때 첫 인자로는 대상 메모리 시작 위치( 포함 위치 ), lpBuffer 은 MEMORY_BASIC_INFORMATION 의 구조체 포인터를, 그리고 MEMORY_BASIC_INFORMATION 포인터 크기를 기입한다.
그러면 VirtualQuery 는 MEMORY_BASIC_INFORMATION 구조체 안에 각 하나의 리전 정보가 담아서 반환한다.
lpBuffer 에는 BaseAddress, RegionSize와 같은 정보가 포함되는데, 리전 블럭의 정보이다. 리전 블럭은 4KB 의 페이지가 모여서 성질이 같은 페이지를 모아둔 것이다.
nowPosition =(VOID*)((char*)lpBuffer->BaseAddress + lpBuffer->RegionSize);
특히 메모리 상태는 3가지가 존재하는데, 0x1000 는 커밋된 상태, 0x2000는 예약된 상태, 0x10000는 미사용 상태이다. 해당 상태를 구별해서 순회하면서 관여 가능한 메모리 블럭을 모두 조회해보기로 한다.
VOID* nowPosition = (VOID*)minimumAddress;
while(true){
MEMORY_BASIC_INFORMATION* lpBuffer = new MEMORY_BASIC_INFORMATION();
SIZE_T sizeData = VirtualQuery(nowPosition, lpBuffer, sizeof(MEMORY_BASIC_INFORMATION));
const char* message="";
switch (lpBuffer->State) {
case 0x1000:
message = "Memory Commit";
break;
case 0x2000:
message = "Memory Reserved";
break;
case 0x10000:
message = "Memory FREE";
break;
}
std::cout << "[BASE] " << lpBuffer->BaseAddress << " [SIZE]" << lpBuffer->RegionSize << " [TYPE]" << message << std::endl;
nowPosition =(VOID*)((char*)lpBuffer->BaseAddress + lpBuffer->RegionSize);
if (nowPosition >= maximumAddress) {
break;
}
}
nowPosition 는 발견된 리전의 베이스 위치 + 리전 크기를 더해나가면서 다음 위치 블럭을 찾는다. 즉 다음 영역의 메모리 지점을 nowPosition에 담아 VirtualQuery 를 요청하면 다음 지점에 해당하는 리전 블럭을 찾아 반환해준다. 이러한 작업을 반복하며, 끝점까지 도달하는지 확인하는 것이다.