in the name of zero

April 12, 2006

elf magic revisited

Filed under: hermetic studies

to do more cool stuffs with ptrace(), elf sorcery is in order. or so i think. i’ve done some basic experiments (1 ,2, 3) with the elf abi some time ago, but that couldn’t prepare me for the things i wish to do recently. so today, i’ll be continuing my elf adventures by learning how the got (global offset table) and plt (procedure linkage table) mechanisms work.

see:
“global offset table and procedure linkage table” - the elf specification

i made a simple program so i can follow this paper too.

void thisfunction()
{
        printf(\"hello world\n\");
}
	
int main(int argc, char **argv)
{
        thisfunction();
        return 0;
}
generated a disassembly dump of all sections too for reference.
steph@heaven ~/git/null/c/ptrace $ gcc -g -o plt-got plt-got.c
steph@heaven ~/git/null/c/ptrace $ objdump -D plt-got > plt-got.dasm

every instruction here, (unless otherwise noted) was done inside gdb. i started by disassembling <_start>. i followed the call function to the .plt section.

0x080482dc <_start +28>: call   0x8048298 <__libc_start_main @plt>
i noticed that is is an absolute procedure linkage table. since it doesn’t use register ebx as offset.

steph@gdb $ disassemble 0x8048298
Dump of assembler code for function __libc_start_main@plt:
0x08048298 <__libc_start_main @plt+0>:   jmp    DWORD PTR ds:0x80495ac
0x0804829e <__libc_start_main @plt+6>:   push   0x0
0x080482a3 <__libc_start_main @plt+11>:  jmp    0x8048288 <_init +24>
note that the first instruction is a jmp which i found quite frustrating since i just came from a call instruction. that instruction by the way instructs us to jmp at the memory address pointed to, by the memory address 0x80495ac. in other words, we get the value of 0x80495ac and jump to that value instead of using the memory address directly.

first, view the contents of memory address 0x80495ac

steph@gdb $ x/x 0x80495ac
0x80495ac <_global_offset_table_ +12>:   0x0804829e
i noticed that the value 0x0804829e is actually just the very next instruction after the jmp. you can see for yourself in the above disassembly!

i quote from the paper i’m following:

“In the beginning, the GOT offsets points on the following push offset
0x804830e : look at the objdump trace above) . At the moment , the GOT
in our process is said to be “empty”, and is going to be filled as long
as the process calls remote functions (one entry is updated each time the
program calls this remote function *for the first time*) .”
in my case, my push instruction is in a different memory address - 0x0804829e.

i followed the jmp instruction next.

steph@gdb $ x/i 0x8048288
0x8048288 <_init +24>:   push   DWORD PTR ds:0x80495a4
again, another pointer. let’s print it’s value shall we?

steph@gdb $ x/d 0x80495a4
0x80495a4 <_global_offset_table_ +4>:    0
ok so now what? well, let’s try looking at the __libc_start_main@plt block.

Disassembly of section .plt:
	
08048288 <__libc_start_main @plt-0x10>:
 8048288:       ff 35 a4 95 04 08       pushl  0x80495a4
 804828e:       ff 25 a8 95 04 08       jmp    *0x80495a8
 8048294:       00 00                   add    %al,(%eax)
we already know that the first pushl instruction pushed “zero” to the stack. now we determine what jmp *0x80495a8 is all about.

steph@gdb $ x/d 0x80495a8
0x80495a8 <_global_offset_table_ +8>:    0
the same.

and with the help of gdb, i constructed the got table

print out the values of every index of the global offset table

steph@gdb $ x 0x80495a0
0x80495a0 <_global_offset_table_>:      0x080494d4
	
steph@gdb $ x 0x80495a0+4
0x80495a4 <_global_offset_table_ +4>:    0x00000000
	
steph@gdb $ x 0x80495a0+8
0x80495a8 <_global_offset_table_ +8>:    0x00000000
	
steph@gdb $ x 0x80495a0+12
0x80495ac <_global_offset_table_ +12>:   0x0804829e
	
steph@gdb $ x 0x80495a0+16
0x80495b0 <_global_offset_table_ +16>:   0x080482ae
and construct the array

_GLOBAL_OFFSET_TABLE_[0] = 0x080494d4 (address of _DYNAMIC)
_GLOBAL_OFFSET_TABLE_[1] = 0x00000000 (NULL)
_GLOBAL_OFFSET_TABLE_[2] = 0x00000000 (NULL)
_GLOBAL_OFFSET_TABLE_[3] = 0x0804829e (offset to push instruction of __libc_start_main@plt)
_GLOBAL_OFFSET_TABLE_[4] = 0x080482ae (offset to push instruction of printf@plt)
based on this array, i quote from the paper i’m reading. it makes sense now doesn’t it?
We can see that the third first entries in the GOT have special values :

- The [0] entry contains the offset for the .dynamic section of
this object, it’s used by the dynamic linker to know some
preferences and some very useful informations . Look at the
ELF reference for further details . Some stuff are also explained
in the dynamic linking related chapter of this tfile .

- The [1] one is the link_map structure offset associated with
this object, it’s an internal structure in ld.so describing
a lot of interresting stuffs, I wont go in depth with it in this
paper .

- The [2] entry contains the runtime process fixup function offset
(pointing in the dynamic linking code zone). This pointer is used by
the first entry of the plt which is called when you want to launch
a remote (undefined) function for the first time .

The 2nd and 3rd entries are set to NULL at the beginning and are filled by
the dynamic linker before the process code segment starting function takes
control . These are filled in elf_machine_runtime_setup() in
sysdeps/i386/dl-machine.h .

these, on the other hand make up the plt (procedure linkage table) entry.

08048298 <__libc_start_main @plt>:
 8048298:       ff 25 ac 95 04 08       jmp    *0x80495ac
 804829e:       68 00 00 00 00          push   $0x0
 80482a3:       e9 e0 ff ff ff          jmp    8048288 <_init +0x18>
	
080482a8 <printf @plt>:
 80482a8:       ff 25 b0 95 04 08       jmp    *0x80495b0
 80482ae:       68 08 00 00 00          push   $0x8
 80482b3:       e9 d0 ff ff ff          jmp    8048288 <_init +0x18>

so as a summary, the got (global descriptor table) deals with address calculations to absolute locations. and the plt (procedure linkage table) “maps” function calls to absolute locations. whatever that means. :D *giggles*

well, that was quite fun! (smirk) it took me many hours of staring at seemingly “garbage” outputs of objdump and gdb. and the paper i’m following didn’t really make much sense at first too. it makes me wonder if i even got the basic concepts correct.

in my next post i’ll try running the program and see if there are changes. in the got/plt section.

Comments »

The URI to TrackBack this entry is: http://gnurbs.blogsome.com/2006/04/12/elf-magic-revisited/trackback/

No comments yet.

RSS feed for comments on this post.

Leave a comment

Line and paragraph breaks automatic, e-mail address never displayed, HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>


Get free blog up and running in minutes with Blogsome | Theme designs available here