lem0nify
lem0nify

Reputation: 793

Explain to me how Windows allocates process virtual memory

I have pretty complex question combined of multiple related questions. Let me give you the preamble.

I wrote a simple Win64 program in assembly language which prints "2 + 3 = 5" using printf and then "Hello World!" using puts:

format PE64
entry start

section '.text' code readable executable

  start:
        sub     rsp,8*5         ; reserve stack for API use and make stack dqword aligned

        mov edx, 3
        mov ecx, 2
        call print_sum

        lea     rcx,[_hw_message]
        call    [puts]

        mov     ecx,0
        call    [ExitProcess]

  print_sum:
        sub rsp, 20h
        mov r9d, ecx
        add r9d, edx
        mov r8d, edx
        mov edx, ecx
        lea ecx, [_format_message]
        call [printf]
        add rsp, 20h
        ret

section '.data' data readable writeable

  _hw_message db 'Hello World!',0
  _format_message db '%d + %d = %d',13,10,0

section '.idata' import data readable writeable

  dd 0,0,0,RVA kernel_name,RVA kernel_table
  dd 0,0,0,RVA msvcrt_name,RVA msvcrt_table

  kernel_table:
    ExitProcess dq RVA _ExitProcess
    dq 0
  msvcrt_table:
    printf dq RVA _printf
    puts dq RVA _puts
    dq 0

  kernel_name db 'KERNEL32.DLL',0
  msvcrt_name db 'msvcrt.dll',0

  _ExitProcess dw 0
    db 'ExitProcess',0
  _printf dw 0
    db 'printf',0
  _puts dw 0
    db 'puts',0

and built it with fasm. Resulting binary size is 2048 bytes.

I've opened it with CFF Explorer to see PE header values. PE64HELLO.EXE headers in CFF Explorer

Image base is 0x400000, entry point is 0x1000, .text section virtual address is 0x1000 too, so, as far as I understand, it should start in virtual memory at offset 0x401000 and it is also its entry point.

Then I've opened it in debugger (I use x64dbg) to confirm my guess: PE64HELLO.EXE in x64dbg Memory map of PE64HELLO.EXE in x64dbg

Looks believable. Also note that stack is located at 0x8A000.

Fine, then I've tried the same with another program – notepad.exe from C:\Windows: notepad.exe in CFF Explorer and x64dbg

Wait, what? 0x140000000 + 0x24050 = 0x140024050, not 0x7FF75FD04050. And I can't find in PE headers such big values starting with 7FF.

In addition, the stack is again located somewhere at the beginning of the process's memory map, but now its address is already much larger: Memory map of notepad.exe in x64dbg

I thought that perhaps this is because notepad.exe is a system program and is tightly tied to the Windows system APIs, and some parts of it (and maybe all the code) are always loaded into RAM while Windows is running. Therefore, I tried to do the same with x64dbg itself, and saw about the same picture:

So the questions are:

I understand that this can be difficult to explain in a nutshell, so I appreciate if, in addition to answering my questions, you can recommend me some reading material that will help me improve my understanding of the Windows virtual memory mapping.

Upvotes: 1

Views: 304

Answers (1)

thedemons
thedemons

Reputation: 1233

What you're seeing is Address space layout randomization, which is enabled by default in MSVC with the linker flag: /DYNAMICBASE.

To enable this, the flag IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE (0x40) must be set in the PE header, at FileHeader -> OptionalHeader -> DllCharacteristics.

When enabled, the OS will select a random address for the base image, stack, and heap. The ImageBase specified in the PE header will be ignored.

Upvotes: 1

Related Questions