Usage Scenario for procmap


Prerequisites

    o Task Manager
    o Command Prompt
    o Microsoft C/C++ compiler
    o GNU C/C++ compiler
    o grep - (optional) - Filters out unneeded lines of output

The following is a program which when compiled by Microsoft C compiler and GCC C
compiler produces programs giving different outputs:

-----------------------------------------------------------------------------------
/* scenario.c */
#include 

static void WaitForKey(void);

int main()
{
    char* p = "Hello, World";
    
    WaitForKey();
    
    printf("p is \"%s\" at points at %p\n", p, p);
    *p = 'X';
    printf("p is \"%s\" at points at %p\n", p, p);
}

void WaitForKey(void)
{
    printf("Press Enter to continue...");
    while(getchar() != '\n');
}

/*  */
-----------------------------------------------------------------------------------

We assume that output produced Microsoft C compiler is scenario.exe, whereas
GCC C compiler produced scenario_gcc.exe.

Open two command prompts (cmd.exe on Win2000/XP), one task manager (taskmgr.exe)
instance. In the first command prompt execute scenario_gcc.exe similar to as shown
below. But please don't press Enter now.

-----------------------------------------------------------------------------------
F:\progs\win32>scenario_gcc.exe
Press any key to continue...
p is "Hello, World" at points at 00401240
-----------------------------------------------------------------------------------

In the "Processes" tab in "Task Manager" window, locate scenario_gcc.exe, note down
its process id. In my case it is 2372. So in the other command prompt, run "procmap"
to print the pagemap of process ID 2372. If you've "grep" you can filter out unneeded
rows. The output as shown below:

-----------------------------------------------------------------------------------
F:\progs\win32>procmap 2372 |grep -i scenario_gcc
00400000-00401000  C  I  R-----      4K  \Device\HarddiskVolume4\progs\win32\scenario_gcc.exe
00401000-00402000  C  I  R-X---      4K  \Device\HarddiskVolume4\progs\win32\scenario_gcc.exe
00402000-00403000  C  I  RW----      4K  \Device\HarddiskVolume4\progs\win32\scenario_gcc.exe
00403000-00404000  C  I  RW-P--      4K  \Device\HarddiskVolume4\progs\win32\scenario_gcc.exe
00404000-00405000  C  I  RW----      4K  \Device\HarddiskVolume4\progs\win32\scenario_gcc.exe
00405000-0040B000  C  I  R-----     24K  \Device\HarddiskVolume4\progs\win32\scenario_gcc.exe
-----------------------------------------------------------------------------------

Now, press Enter in the previous command prompt (where scenario_gcc.exe is running), an access
violation error (error code 0xc0000005)  occurs, while trying to write at location 0x401240
(value of p). Now, locate the interval 0x401240 in above pagemap, it comes in the second interval
which is 00401000-0040200. It is mapped as Read Only/Executable, which this range of pages is write
protected.

Now, in the same command prompt (where scenario_gcc.exe was running), execute scenario.exe.
Don't press Enter now. First note down its process ID from Task Manager. In my case it is 3968.

-----------------------------------------------------------------------------------
F:\progs\win32>scenario
Press any key to continue...
p is "Hello, World" at points at 0040D040
p is "Xello, World" at points at 0040D040
-----------------------------------------------------------------------------------

Dump the pagemap of process 3968 as shown below:

-----------------------------------------------------------------------------------
F:\progs\win32>procmap 3968 |grep -i scenario
00400000-00401000  C  I  R-----      4K  \Device\HarddiskVolume4\progs\win32\scenario.exe
00401000-0040B000  C  I  R-X---     40K  \Device\HarddiskVolume4\progs\win32\scenario.exe
0040B000-0040D000  C  I  R-----      8K  \Device\HarddiskVolume4\progs\win32\scenario.exe
0040D000-00410000  C  I  RW----     12K  \Device\HarddiskVolume4\progs\win32\scenario.exe
-----------------------------------------------------------------------------------

Now, press Enter in the previous command prompt (where scenario.exe is running), no error
occurs. In above case p points to 0x40D040. Locate interval where 0x40D040 comes. It comes in
the last interval, which is mapped Read/Write, which means write access is allowed, hence no
error.

The difference of the outputs of the different versions of the above program is due to the fact
that GCC compiler allocates strings in code section (i.e. with read/execute protection), whereas
Microsoft compiler allocates strings in data section (i.e. with read/write protection). So, PE* loader,
when loads PE file, it maps the pages belonging to data section with read/write protection, whereas
pages belonging to code section with read/execute protection. Hence the different behavior.

But when we change the statement:

    char* p = "Hello, World";

to:

    char  p[] = "Hello, World";
    
there will be no error.

Why ? Because in, this case strings are still allocated in code section, but at the start of the
function code (i.e. in the prologue), it copies the whole string from code section to the stack,
i.e. it allocates the string on stack. And since, stack is committed as read/write, hence no error.
To confirm check the generated assembly language code (-S on GCC, -Fa on Microsoft).

Note: Stack is not mapped from image, so you won't find path name against page map entry.

I've also posted this problem on "comp.lang.asm.x86" Usenet newsgroup with title (not really exactly
"Variable allocation in C").

This is the usage scenario which led to the development of this tool and my research on paging
support in operating systems, executable formats.

Hope u like it.

Thanks,

Ashish Shukla alias Wah Java !!
Wah Java !!

-------------------------------
Footnotes

*PE: Portable Executable

    Source: geocities.com/wah_java_dotnet/procmap

               ( geocities.com/wah_java_dotnet)