심플스 - 프로그램과 책 이야기로 가득한 곳, (Simples.Kr)

  


   심플스 배너



 

32Bit 윈도우즈 에서는 4GB 이상에 물리 메모리가 장착되어 있을 때 사용가능한 물리 메모리가 3.25GB 정도로 표시가 됩니다.

( 단, 이 사용가능한 물리메모리는 PC 하드웨어에 따라서 약간 달라질 수 있습니다. )


다음은 32Bit 윈도우즈 에서 4GB이상에 물리 메모리가 장착되어 있고 PAE 옵션이 활성화되어 있다면,

실제 물리 메모리크기를 읽어오는 방법입니다.


MmGetPhysicalMemoryRanges 함수를 이용해서 윈도우즈에서 표시되는 실제 물리메모리 크기를 읽어오며,

그 후에 윈도우즈에서 인식하지 못 하는 물리 메모리크기를 추가로 얻어온 후 이를 합치게 됩니다.


GetPhysicalMemorySize 함수에 리턴값은 실제 물리메모리의 전체크기이며,

인자로 들어가는 uWindowsReservedSize는 윈도우즈에서 인식하지 못 한 메모리 크기입니다.


해당 소스는 커널레벨에서 작동하는 코드이며, 유저레벨에서 사용할 수 없습니다.


#define MEMORY_SCAN_START_ADDRESS ((ULONG64)4 * 1024 * 1024 * 1024)
#define MEMORY_SCAN_BLOCK_SIZE ((ULONG64)1024 * 1024 * 16)

// 이러한 상수는 적용해서는 안됩니다.
// 3.25GB인 경우도 있고 3.5GB인 경우도 있고 PC마다 다르게 맵핑이 되어 있습니다.
//#define MEMORY_3_25GB_4GB_HARDWARE_MAPPED_IO_SIZE ((ULONG64)1024 * 1024 * 768);
//#define MEMORY_HARDWARE_MAPPED_IO_START_ADDRESS ((ULONG64)3328 * 1024 * 1024);


#define MI_CONVERT_PHYSICAL_TO_PFN(Va) (((ULONG)Va << 3) >> 15)

typedef struct _PHYSICAL_MEMORY_RUN
{
    PFN_NUMBER BasePage;
    PFN_NUMBER PageCount;
} PHYSICAL_MEMORY_RUN, *PPHYSICAL_MEMORY_RUN;

typedef struct _PHYSICAL_MEMORY_DESCRIPTOR
{
    ULONG NumberOfRuns;
    PFN_NUMBER NumberOfPages; // NumberOfPages * PAGE_SIZE is physical memory size.
    PHYSICAL_MEMORY_RUN Run[1]; // NumberOfRuns is the total entries.
} PHYSICAL_MEMORY_DESCRIPTOR, *PPHYSICAL_MEMORY_DESCRIPTOR;

ULONG64 GetPhysicalMemorySize(ULONG64 *uWindowsReservedSize);


BOOLEAN IsPAEEnable()
{
    // CR4 레지스터를 체크하는 방법도 있지만 커널내부에서 체크를 해주는 함수가 지원됩니다.
    // 추후에 64비트 포팅을 위해 어셈블리 및 기계어는 사용하지 않는게 좋습니다.
    return (ExIsProcessorFeaturePresent(PF_PAE_ENABLED));
}

ULONG64 GetPhysicalMemorySize(ULONG64 *uWindowsReservedSize)
{
    PPHYSICAL_MEMORY_DESCRIPTOR MmPhysicalMemoryBlock;
    PPHYSICAL_MEMORY_RANGE MmPhysicalMemoryRange;

    PHYSICAL_ADDRESS AboveAddress;

    SIZE_T MemoryBlockSize;
    PFN_NUMBER NumberOfPages;

    ULONG64 uPhysicalMemorySize;
    ULONG64 uPhysicalMemoryBlockCount;

    ULONG NumberOfRuns;
    ULONG Run;

    uPhysicalMemorySize = 0;
    MmPhysicalMemoryRange = MmGetPhysicalMemoryRanges();

    if (MmPhysicalMemoryRange == NULL)
    {
        return 0;
    }

    NumberOfRuns = 0;
    NumberOfPages = 0;

    while ((MmPhysicalMemoryRange[NumberOfRuns].BaseAddress.QuadPart != 0) && (MmPhysicalMemoryRange[NumberOfRuns].NumberOfBytes.QuadPart != 0))
    {
        NumberOfRuns++;
        NumberOfPages += (PFN_NUMBER)BYTES_TO_PAGES(MmPhysicalMemoryRange[NumberOfRuns].NumberOfBytes.QuadPart);
    }

    if (NumberOfRuns == 0)
    {
        return 0;
    }
    MemoryBlockSize = sizeof(ULONG) + sizeof(PFN_NUMBER) + sizeof(PHYSICAL_MEMORY_RUN) * NumberOfRuns;
  
    MmPhysicalMemoryBlock = ExAllocatePoolWithTag(NonPagedPool, MemoryBlockSize, 0);
    MmPhysicalMemoryBlock->NumberOfRuns = NumberOfRuns;
    MmPhysicalMemoryBlock->NumberOfPages = NumberOfPages;
    for (Run = 0; Run < NumberOfRuns; Run++)
    {
        MmPhysicalMemoryBlock->Run[Run].BasePage = (PFN_NUMBER)MI_CONVERT_PHYSICAL_TO_PFN(MmPhysicalMemoryRange[NumberOfRuns].BaseAddress.QuadPart);
        MmPhysicalMemoryBlock->Run[Run].PageCount = (PFN_NUMBER)BYTES_TO_PAGES(MmPhysicalMemoryRange[Run].NumberOfBytes.QuadPart);
    }
    uPhysicalMemorySize = MmPhysicalMemoryBlock->NumberOfPages * PAGE_SIZE;
    ExFreePoolWithTag(MmPhysicalMemoryBlock, 0);

    DbgPrint("Windows Based Memory Size : uPhysicalMemorySize %I64u\n", uPhysicalMemorySize);

    // 4GB 주소부터 메모리를 스캔합니다.
    AboveAddress.QuadPart = MEMORY_SCAN_START_ADDRESS;
    if (IsPAEEnable() == TRUE)
    {
        // 반드시 PAE가 활성화되어 있을 경우에만 접근합니다.
        // 만약 PAE가 비활성화되어 있을 때 접근하게 되면 KMODE_EXCEPTION_NOT_HANDLED 블루스크린이 발생 할 수 있습니다. ( Windows 2000 계열에서 해당 블루 스크린이 발생하여 PAE를 체크하도록 변경한 것입니다. )
        while (TRUE)
        {
            PVOID pVirtualAddress;

            pVirtualAddress = MmMapIoSpace(AboveAddress, MEMORY_SCAN_BLOCK_SIZE, MmNonCached);
            if (pVirtualAddress != NULL)
            {
                PVOID pCheckAddress;
                ULONG uOldData;

                // 참고...
                // MmMapIoSpace 리턴받은 가상주소는 결국에는 물리 메모리주소를 가르키게 됩니다.
                // 여기서 중요한 부분은 만약 물리 메모리주소가 실제 하드웨어에 6GB 메모리가 설치되어 있고 7GB주소에 접근하려고 하여도
                // 에러가 발생하지 않습니다.
                // 이것은 윈도우즈 운영체제에서 관리하는 것이 아니며 CPU에서 발생하는 것입니다.
                // 존재하지 않은 메모리에 접근하였다면 일반적으로 읽어온 데이터는 비트가 모두 1을 가집니다.
                pCheckAddress = (UCHAR *)pVirtualAddress;
                uOldData = *(ULONG *)pCheckAddress;

                // xor 연산을 한 후 값을 씁니다.
                *(ULONG *)pCheckAddress = *(ULONG *)pCheckAddress ^ 0x55AA55AA;
                if (*(ULONG *)pCheckAddress == uOldData)
                {
                    // xor연산을 하여 값을 썼음에도 불구하고 이전 데이터와 동일하다면 이 메모리 주소는 존재하지 않는 메모리주소를 말합니다.
                    MmUnmapIoSpace(pVirtualAddress, MEMORY_SCAN_BLOCK_SIZE);

                    break;
                }
                else
                {
                    // 이 메모리 영역이 존재합니다.
                    MmUnmapIoSpace(pVirtualAddress, MEMORY_SCAN_BLOCK_SIZE);
                }
            }
            else
            {
                break;
            }
            AboveAddress.QuadPart += (ULONG64)((ULONG64)16 * 1024 * 1024);
        }
    }
    if (AboveAddress.QuadPart > MEMORY_SCAN_START_ADDRESS)
    {
        // 4GB이후에 메모리 영역이 존재합니다.
        // 적절한 계산을 통해 메모리 크기를 가져옵니다.
        uPhysicalMemorySize = AboveAddress.QuadPart - MEMORY_SCAN_START_ADDRESS + uPhysicalMemorySize;
    }

    if (uWindowsReservedSize != NULL)
    {
        *uWindowsReservedSize = (AboveAddress.QuadPart - MEMORY_SCAN_START_ADDRESS);
        KdPrint(("PhysicalMemorySize : %I64uMB, ReservedSize : %I64u\n", uPhysicalMemorySize / 1024 / 1024, *uWindowsReservedSize / 1024 / 1024));
    }
    else
    {
        KdPrint(("PhysicalMemorySize : %I64uMB\n", uPhysicalMemorySize / 1024 / 1024));
    }

    return uPhysicalMemorySize;
}

List of Articles
번호 제목 글쓴이 날짜 조회 수
162 Windows Research SCSI Miniport - IOCTL_SCSI_PASS_THROUGH_DIRECT ( ... [레벨:6]lain 2011-06-11 3650
161 Windows Research 커널레벨에서 IAT Hook [레벨:6]lain 2011-06-11 4348
160 Windows Research DEVICE_OBJECT에 대한 보안 디스크립터 변경 [레벨:6]lain 2011-06-11 3167
159 Windows Research IE Cache 경로 변경하기 [레벨:6]lain 2011-06-09 3292
» Windows Research 32Bit 윈도우즈에서 실제 물리메모리크기 얻어오기 [레벨:6]lain 2011-06-09 3431
157 Windows Research VMWare 탐지 기법 우회 - 2 [2] [레벨:6]lain 2011-04-04 8850
156 Linux Tip 우분투에 IRC서버 설치후 닉네임 길이와 동접자 조절. [1] [레벨:0]오랑캐꽃 2010-11-26 5829
155 Linux Tip VirtualBox에 우분투 설치 후에 내부 네트워크 접속 설정하기 file [레벨:8]esniper 2010-09-10 12223
154 Linux Tip VirtualBox에서 오른쪽 CTRL키 사용하기(VitualBox 호스트키) file [2] [레벨:8]esniper 2010-09-10 6057
153 Linux Tip 우분투 설치 후 putty에서 한글 안 깨지도록 설정하기 file [레벨:8]esniper 2010-09-10 6366
152 Linux Tip 우분투 ssh or mysql 서버 접속지연이 있는 경우 해결책 [레벨:8]esniper 2010-09-10 6244
151 문서자료 고품질의 무료 아이콘들 [3] [레벨:8]esniper 2010-09-08 7439
150 Windows Research Sysinternals - Filemon source code file [5] [레벨:6]lain 2010-09-04 5818
149 Windows Research Sysinternals - Regmon source code file [1] [레벨:6]lain 2010-09-04 5492
148 Windows Research PostQueuedCompletionStatus 함수에 실패 여부도 고려해야 할까... [레벨:6]lain 2010-09-04 4678
147 Windows Research SetEvent 함수는 언제 실패할까? [레벨:6]lain 2010-09-04 5491
146 Windows Research 커널모드 드라이버에서 사용하는 시간관련 매크로 [레벨:6]lain 2010-09-04 4443
145 Windows Research 화면캡쳐방지는 어떻게 구현될까? [3] [레벨:6]lain 2010-09-04 8658
144 Windows Research IRP Completion Hook file [레벨:6]lain 2010-09-04 3992
143 Windows Research IRP Hook [레벨:6]lain 2010-09-04 4195

  • 이용약관
  • 개인정보취급방침
  • 사이트맵