Tuesday, November 16, 2010

translate linear address(virtual address) to physical address

First of all, we need to know the CR3, this register stores the bases address of page directory.

32 bits of linear address are divided into three fields:
directory: most significant 10 bits
table: intermediate 10 bits
offset: least significant 12 bits

there are 1024 (2^10 bytes / 4 bytes)entries in page directory table
there are 1024 (2^10 bytes / 4 bytes)entries in page table table


This link explain the structure of page directory entry and page table entry:
http://valhalla.bofh.pl/~l4mer/WDM/secureread/pde-pte.htm

 I also wrote a program to find all kernel memory in a memory dump: the assumption is I need to know CR3 of kernel mode.
here is the program:


#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define NUMOFARG 3
#define SMALLBUFSIZE 20
#define NUMPDE 1024
#define NUMPTE 1024
#define COUNTER1 1024*1024*256
#define COUNTER2 1024*1024*4
#define COUNTER3 1024*4

int main(int argc, char **argv)
{
    if(argc != NUMOFARG)
    {
    fprintf(stderr, "Usage: %s MemFile RegFile\n", argv[0]);
    exit(1);
    }

    /* Generate new memory file with size of 256 MB
     * which initial to 0 */
    FILE *newMemFile = fopen("newMemDump", "w+");
    if(newMemFile == NULL)
    {
    fprintf(stderr, "Cannot create new memory file\n");
    exit(1);
    }

    int m;
    for(m = 0; m < COUNTER1; m++)
    fputc('\0', newMemFile);
   
    /* Read the CR3 from register file */
    FILE *regFile = fopen(argv[2], "r");
    if(regFile == NULL)
    {
    fprintf(stderr, "Cannot open register file\n");
    exit(1);
    }

    char regName[SMALLBUFSIZE];
    char regEqual[SMALLBUFSIZE];
    unsigned int regAddr;
    int ret;

    int numOf4K = 0;
    int numOf4M = 0;

    while(1)
    {
    ret = fscanf(regFile, "%s\t%s\t%x\n", regName, regEqual, &regAddr);
//    printf("%s\t%s\t%x\n", regName,regEqual, regAddr);
   
    if(strcmp(regName, "CR3") == 0)
        break;
    if(ret == 0 || ferror(regFile) || feof(regFile))
        break;
    }

    fclose(regFile);

    /* Read the memory file */
    FILE *memFile = fopen(argv[1], "r");
    if(memFile == NULL)
    {
    fprintf(stderr, "Cannot open memroy file\n");
    exit(1);
    }

    /* Loop for Each Page Directory Entry
     * There are 2^10 = 1024 entries in PDE
     * We will check the present bit in each PDE
     * */
    int i, j;
    unsigned int CR3 = regAddr;
   
    // Store the content of Page Direcotry Entry
    unsigned int PDEContent;
    unsigned int PTEContent;

    for(i = 0; i < NUMPDE; i++)
    {
    fseek(memFile, CR3+4*i, SEEK_SET);

    if(fread(&PDEContent, 4, 1, memFile) != 1)
    {
        fprintf(stderr, "Read Page Direcotry Entry Error\n");
        exit(1);
    }

    // if the last bit of the PDE entry is 0, this PDE entry is
    // not present. we just jump to next loop
    if(PDEContent%2 == 0)
        continue;

//    printf("%x\n", PDEContent);

    // check if the 4M bit has been setted
    if(PDEContent & 0x00000080 )
    {
        // This PDEContent has the 4M bit set
        numOf4M++;
        // copy the memory file to new memory file
        // 1. seek the original file indicator
        // 2. seek the new meory file indicator
        // 3. copy the content to the new memory file
        PDEContent &= 0xFFFFF000;
        fseek(newMemFile, PDEContent, SEEK_SET);
        fseek(memFile, PDEContent, SEEK_SET);
        for(m = 0; m < COUNTER2; m++)
        fputc(fgetc(memFile), newMemFile);
    }
    else
    {
        // This PDE has 4KB bit set, so we need to go though page
        // table entry.       
        PDEContent &= 0xFFFFF000;
       
        for(j = 0; j < NUMPTE; j++)
        {
        fseek(memFile, PDEContent+4*j, SEEK_SET);

        if(fread(&PTEContent, 4, 1, memFile) != 1)
        {
            fprintf(stderr, "Read Page Table Entry Error\n");
            exit(1);
        }
        // if the present bit is not set in the Page Table Entry
        // we jump to next iteration
        if(PTEContent%2 == 0)
            continue;

        numOf4K++;
        PTEContent &= 0xFFFFF000;
        fseek(newMemFile, PTEContent, SEEK_SET);
            fseek(memFile, PTEContent, SEEK_SET);
            for(m = 0; m < COUNTER3; m++)
            fputc(fgetc(memFile), newMemFile);
        }
    }
    }
    fclose(newMemFile);
    fclose(memFile);

    printf("num of 4M is: %d\n", numOf4M);
    printf("Num of 4K is: %d\n", numOf4K);
    printf("Total kenerl memory size is: %d K\n", numOf4M*4096 + numOf4K);
    return 1;
}

No comments: