Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can global variables' addresses be randomized if they're hardcoded inside the ELF?

Tags:

c

elf

aslr

dwarf

I've read in a few places that ASLR is supposed to load the .data section at random addresses each time a program is run, which means the addresses of global variables should be different. However, if I have the following code:

int global_var = 42;

int main()
{
    global_var = 10;
    return 0;
}

and I compile it with gcc -fpie -o global global.c, objdump -d -M intel shows the following:

  4004ed:   55                      push   rbp
  4004ee:   48 89 e5                mov    rbp,rsp
  4004f1:   c7 05 3d 0b 20 00 0a    mov    DWORD PTR [rip+0x200b3d],0xa        # 601038 <global_var>

It appears that global_var will always be placed at 601038. Indeed, if I compile with debugging symbols, global_var's DIE has that address hardcoded:

$ gcc -ggdb3 -fpie -o global global.c
$ objdump --dwarf=info global
...
<1><55>: Abbrev Number: 4 (DW_TAG_variable)
   <56>   DW_AT_name        : (indirect string, offset: 0x30c): global_var  
   <5a>   DW_AT_decl_file   : 1 
   <5b>   DW_AT_decl_line   : 1 
   <5c>   DW_AT_type        : <0x4e>    
   <60>   DW_AT_external    : 1 
   <60>   DW_AT_location    : 9 byte block: 3 38 10 60 0 0 0 0 0    (DW_OP_addr: 601038)

How does ASLR work in these cases?

like image 317
Martin Avatar asked Dec 24 '22 06:12

Martin


1 Answers

The instruction output from the disassembly is giving you 601038 as a convenience relative to an arbitrary base (0x400000), but read the actual instruction; it's writing to DWORD PTR [rip+0x200b3d]. rip is the instruction pointer. The code and data is at a fixed offset relative to each other; randomizing the base address doesn't change that. By loading using the instruction pointer, it's using an address that incorporates the ASLR relocation already.

The convenience mapping in the description to 601038 is because the fixed offsets from rip scattered throughout the code are all dependent on where the instruction is located, so they're not comparable without making an adjustment for the instruction location; the disassembler knows the instruction offset though, so it can subtract that instruction offset for you to get globally comparable addresses for the common 0x400000 base.

like image 185
ShadowRanger Avatar answered Dec 26 '22 19:12

ShadowRanger