http://www.hackerschool.org/HS_Boards/zboard.php?id=Free_Lectures&no=7906 [º¹»ç]
Intro
This page shows by example the stack layout for an ELF program on the i386 architecture.
Program startup
When a program is started, the first part of the job is done by the kernel, in the code for the execve system call (do_exec(), load_elf_binary()). If there is a .interp section, the interpreter is started. (As in our example case here. The interpreter is /lib/ld-linux.so.2.) Otherwise the object is started directly. In the usual case, the interpreter will fill in the GOT and PLT tables with the appropriate addresses and jump to the objects's _start. There the glibc init code is run, which calls main().
Stack layout
As a first approximation, the stack of a C program on an i386 machine looks like the following (going up from low addresses): ...
local variables of main
saved registers of main
return address of main
argc
argv
envp
stack from startup code
argc
argv pointers
NULL that ends argv[]
environment pointers
NULL that ends envp[]
ELF Auxiliary Table
argv strings
environment strings
program name
NULL
and ends at 0xc0000000. Let us dump a stack, and look. The argv strings and environment strings are character strings, most of the rest are 4-byte integers or pointers, so let us dump things that way.
dumpstack.c
Program dumpstack.c #include <stdio.h>
extern char **environ;
int main(int argc, char **argv) {
unsigned int a, *x;
unsigned char *y;
printf("argv = %08x\n", (unsigned int) argv);
printf("argv[0] = %08x\n", (unsigned int) argv[0]);
printf("environ = %08x\n", (unsigned int) environ);
printf("environ[0] = %08x\n", (unsigned int) environ[0]);
printf("\n\n");
x = (unsigned int *) ((unsigned int) &a & ~0xf);
while ((unsigned int) x < (unsigned int) argv[0]) {
printf("%08x:", (unsigned int) x);
for (a=0; a<4; a++)
printf(" %08x", x[a]);
printf("\n");
x += 4;
}
printf("\n\n");
y = (unsigned char *) ((unsigned int) argv[0] & ~0xf) - 16;
while ((unsigned int) y < 0xc0000000) {
printf("%08x:", (unsigned int) y);
for (a=0; a<16; a++)
printf(" %02x", y[a]);
printf(" ");
for (a=0; a<16; a++)
putchar((y[a] > 32 && y[a] < 127) ? y[a] : '.');
printf("\n");
y += 16;
}
return 0;
}
The dumped stack
Call: % ./dumpstack aap noot mies
Output (all is in hex), with comments interspersed: argv = bffff534
argv[0] = bffff6d0
environ = bffff548
environ[0] = bffff6ea
main()
The local variables x and a of main bffff4a0: bffff4a0 00000001
The saved frame pointer %ebp and the return address of main bffff4a0: bffff508 4004b500
The parameters of main: argc, argv, envp bffff4b0: 00000004 bffff534 bffff548
glibc startup
The following was produced by glibc:sysdeps/generic/libc-start.c:__libc_start_main bffff4b0: 40017970
bffff4c0: 40147bd0 400168c0 08048600 bffff508
bffff4d0: bffff4b0 4004b4c5 00000000 00000000
bffff4e0: 00000000 40016cbc 00000004 08048360
bffff4f0: 00000000 4000ca40 4000d330 40016cbc
bffff500: 00000004 08048360 00000000
The following was produced by glibc:sysdeps/i386/elf/start.S:_start (push the parameters for __libc_start_main and call it)
Return address for the call of __libc_start_main at 0x804837c, points to the final hlt
bffff500: 08048381
Eight values pushed by _start: main, argc, argv, __libc_csu_init, __libc_csu_fini, %edx (rtld_fini), %esp, %eax (padding) bffff510: 0804841c 00000004 bffff534 08048670
bffff520: 08048600 4000d330 bffff52c 00000000
The first seven are the parameters of __libc_start_main().
stack set by kernel
The following was produced by kernel:fs/binfmt_elf.c:create_elf_tables()
argc, followed by the array of argv pointers, followed by NULL:
bffff530: 00000004 bffff6d0 bffff6dc bffff6e0
bffff540: bffff6e5 00000000
The global variable environ has the value 0xbffff548. It points at an array of string pointers, closed by NULL. bffff540: bffff6ea bffff703
bffff550: bffff74d bffff75d bffff78f bffff79e
bffff560: bffff7c5 bffff7ec bffff7f7 bffff802
bffff570: bffff812 bffff823 bffff831 bffff84d
bffff580: bffff85f bffff872 bffff88d bffff896
bffff590: bffffb57 bffffb77 bffffb85 bffffb90
bffff5a0: bffffb9e bffffbb2 bffffbc5 bffffc5e
bffff5b0: bffffc67 bffffc85 bffffc9a bffffcaf
bffff5c0: bffffcc7 bffffcd8 bffffcef bffffd5d
bffff5d0: bffffd74 bffffd7c bffffd8b bffffda9
bffff5e0: bffffdb6 bffffdd5 bffffde8 bffffe03
bffff5f0: bffffe24 bffffe6c bffffe77 bffffe90
bffff600: bffffe9c bffffea8 bffffefd bfffff15
bffff610: bfffff3b bfffff6e bfffff7b bfffff98
bffff620: bfffffad bfffffc5 bfffffd1 bfffffdf
bffff630: 00000000
ELF Auxiliary Table
The ELF Auxiliary Table is a list of (id,value) pairs. AT_SYSINFO=32 VSYSCALL_ENTRY: 0xffffe400
AT_SYSINFO_EHDR=33 VSYSCALL_BASE: 0xffffe000
AT_HWCAP=16 hardware capabilities: 0x0183f9ff
AT_PAGESZ=6 page size: 4096
AT_CLKTCK=17 clock frequency for times(): 100 Hz
AT_PHDR=3 address program headers: 0x08048034
AT_PHENT=4 size of program header: 32
AT_PHNUM=5 number of program headers: 8
AT_BASE=7 base address of interpreter: 0x40000000
AT_FLAGS=8 flags: 0
AT_ENTRY=9 program entry point: 0x08048360
AT_UID=11 uid: 500
AT_EUID=12 effective uid: 500
AT_GID=13 gid: 100
AT_EGID=14 effective gid: 100
AT_SECURE=23 secure mode boolean: 0
AT_PLATFORM=15 address of platform string: 0xbffff6cb
AT_NULL=0 end of table
bffff630: 00000020 ffffe400 00000021
bffff640: ffffe000 00000010 0183f9ff 00000006
bffff650: 00001000 00000011 00000064 00000003
bffff660: 08048034 00000004 00000020 00000005
bffff670: 00000008 00000007 40000000 00000008
bffff680: 00000000 00000009 08048360 0000000b
bffff690: 000001f4 0000000c 000001f4 0000000d
bffff6a0: 00000064 0000000e 00000064 00000017
bffff6b0: 00000000 0000000f bffff6cb 00000000
bffff6c0: 00000000
Padding and platform string bffff6c0: 00000000 69000000 00363836
The kernel part of the stack, starting with argc, is aligned on a 16-byte boundary, while the strings are packed towards the end, so one needs 0-15 bytes of padding in between. Here there is 7 bytes of padding.
The strings
Here we start giving the data in bytes instead of integers.
platform
The ELF_PLATFORM string, defined in <asm/elf.h>. For the i386 architecture it is the output of `uname -m`.
platform: i686
bffff6c0: 69 36 38 36 00 i686.
argv strings
The following was produced by kernel:fs/exec.c:do_execve() and is the same for all types of binary: argv strings, environment strings, program name, NULL.
argv strings: ./dumpstack aap noot mies
bffff6d0: 2e 2f 64 75 6d 70 73 74 61 63 6b 00 61 61 70 00 ./dumpstack.aap.
bffff6e0: 6e 6f 6f 74 00 6d 69 65 73 00 noot.mies.
environment strings
environment strings: LESSKEY=/etc/lesskey.bin MANPATH=... bffff6e0: 4c 45 53 53 4b 45 LESSKE
bffff6f0: 59 3d 2f 65 74 63 2f 6c 65 73 73 6b 65 79 2e 62 Y=/etc/lesskey.b
bffff700: 69 6e 00 4d 41 4e 50 41 54 48 3d 2f 75 73 72 2f in.MANPATH=/usr/
... ... _=./dumpstack OLDPWD=/home/aeb bfffffd0: 00 5f 3d 2e 2f 64 75 6d 70 73 74 61 63 6b 00 4f ._=./dumpstack.O
bfffffe0: 4c 44 50 57 44 3d 2f 68 6f 6d 65 2f 61 65 62 00 LDPWD=/home/aeb.
program name
program name: ./dumpstack bffffff0: 2e 2f 64 75 6d 70 73 74 61 63 6b 00 ./dumpstack.
Final NULL
bffffff0: 00 00 00 00 ....
objdump
Below the output of % objdump -d dumpstack
We see that the entry point 0x08048360 is the label _start. dumpstack: file format elf32-i386
Disassembly of section .init:
08048300 <_init>:
8048300: 55 push %ebp
8048301: 89 e5 mov %esp,%ebp
8048303: 83 ec 08 sub $0x8,%esp
8048306: e8 79 00 00 00 call 8048384 <call_gmon_start>
804830b: e8 e0 00 00 00 call 80483f0 <frame_dummy>
8048310: e8 bb 03 00 00 call 80486d0 <__do_global_ctors_aux>
8048315: c9 leave
8048316: c3 ret
Disassembly of section .plt:
8048318: ff 35 6c 98 04 08 pushl 0x804986c
804831e: ff 25 70 98 04 08 jmp *0x8049870
8048324: 00 00 add %al,(%eax)
8048326: 00 00 add %al,(%eax)
08048328 <putchar@plt>:
8048328: ff 25 74 98 04 08 jmp *0x8049874
804832e: 68 00 00 00 00 push $0x0
8048333: e9 e0 ff ff ff jmp 8048318 <_init+0x18>
08048338 <__libc_start_main@plt>:
8048338: ff 25 78 98 04 08 jmp *0x8049878
804833e: 68 08 00 00 00 push $0x8
8048343: e9 d0 ff ff ff jmp 8048318 <_init+0x18>
08048348 <printf@plt>:
8048348: ff 25 7c 98 04 08 jmp *0x804987c
804834e: 68 10 00 00 00 push $0x10
8048353: e9 c0 ff ff ff jmp 8048318 <_init+0x18>
Disassembly of section .text:
08048360 <_start>:
8048360: 31 ed xor %ebp,%ebp
8048362: 5e pop %esi
8048363: 89 e1 mov %esp,%ecx
8048365: 83 e4 f0 and $0xfffffff0,%esp
8048368: 50 push %eax
8048369: 54 push %esp
804836a: 52 push %edx
804836b: 68 00 86 04 08 push $0x8048600
8048370: 68 70 86 04 08 push $0x8048670
8048375: 51 push %ecx
8048376: 56 push %esi
8048377: 68 1c 84 04 08 push $0x804841c
804837c: e8 b7 ff ff ff call 8048338 <__libc_start_main>
8048381: f4 hlt
8048382: 90 nop
8048383: 90 nop
08048384 <call_gmon_start>:
8048384: 55 push %ebp
8048385: 89 e5 mov %esp,%ebp
8048387: 53 push %ebx
8048388: e8 00 00 00 00 call 804838d <call_gmon_start+0x9>
804838d: 5b pop %ebx
804838e: 81 c3 db 14 00 00 add $0x14db,%ebx
8048394: 52 push %edx
8048395: 8b 83 18 00 00 00 mov 0x18(%ebx),%eax
804839b: 85 c0 test %eax,%eax
804839d: 74 02 je 80483a1 <call_gmon_start+0x1d>
804839f: ff d0 call *%eax
80483a1: 58 pop %eax
80483a2: 5b pop %ebx
80483a3: c9 leave
80483a4: c3 ret
80483a5: 90 nop
80483a6: 90 nop
80483a7: 90 nop
80483a8: 90 nop
80483a9: 90 nop
80483aa: 90 nop
80483ab: 90 nop
80483ac: 90 nop
80483ad: 90 nop
80483ae: 90 nop
80483af: 90 nop
080483b0 <__do_global_dtors_aux>:
80483b0: 55 push %ebp
80483b1: 89 e5 mov %esp,%ebp
80483b3: 50 push %eax
80483b4: 50 push %eax
80483b5: 80 3d 88 98 04 08 00 cmpb $0x0,0x8049888
80483bc: 75 2e jne 80483ec <__do_global_dtors_aux+0x3c>
80483be: a1 84 97 04 08 mov 0x8049784,%eax
80483c3: 8b 10 mov (%eax),%edx
80483c5: 85 d2 test %edx,%edx
80483c7: 74 1c je 80483e5 <__do_global_dtors_aux+0x35>
80483c9: 8d b4 26 00 00 00 00 lea 0x0(%esi),%esi
80483d0: 83 c0 04 add $0x4,%eax
80483d3: a3 84 97 04 08 mov %eax,0x8049784
80483d8: ff d2 call *%edx
80483da: a1 84 97 04 08 mov 0x8049784,%eax
80483df: 8b 10 mov (%eax),%edx
80483e1: 85 d2 test %edx,%edx
80483e3: 75 eb jne 80483d0 <__do_global_dtors_aux+0x20>
80483e5: c6 05 88 98 04 08 01 movb $0x1,0x8049888
80483ec: c9 leave
80483ed: c3 ret
80483ee: 89 f6 mov %esi,%esi
080483f0 <frame_dummy>:
80483f0: 55 push %ebp
80483f1: 89 e5 mov %esp,%ebp
80483f3: 51 push %ecx
80483f4: 51 push %ecx
80483f5: 8b 15 64 98 04 08 mov 0x8049864,%edx
80483fb: 85 d2 test %edx,%edx
80483fd: 74 19 je 8048418 <frame_dummy+0x28>
80483ff: b8 00 00 00 00 mov $0x0,%eax
8048404: 85 c0 test %eax,%eax
8048406: 74 10 je 8048418 <frame_dummy+0x28>
8048408: 83 ec 0c sub $0xc,%esp
804840b: 68 64 98 04 08 push $0x8049864
8048410: e8 eb 7b fb f7 call 0 <_init-0x8048300>
8048415: 83 c4 10 add $0x10,%esp
8048418: c9 leave
8048419: c3 ret
804841a: 90 nop
804841b: 90 nop
0804841c <main>:
804841c: 55 push %ebp
804841d: 89 e5 mov %esp,%ebp
804841f: 83 ec 18 sub $0x18,%esp
8048422: 83 e4 f0 and $0xfffffff0,%esp
8048425: b8 00 00 00 00 mov $0x0,%eax
804842a: 29 c4 sub %eax,%esp
804842c: 83 ec 08 sub $0x8,%esp
804842f: ff 75 0c pushl 0xc(%ebp)
8048432: 68 18 87 04 08 push $0x8048718
8048437: e8 0c ff ff ff call 8048348 <_init+0x48>
804843c: 83 c4 10 add $0x10,%esp
804843f: 83 ec 08 sub $0x8,%esp
8048442: 8b 45 0c mov 0xc(%ebp),%eax
8048445: ff 30 pushl (%eax)
8048447: 68 25 87 04 08 push $0x8048725
804844c: e8 f7 fe ff ff call 8048348 <_init+0x48>
8048451: 83 c4 10 add $0x10,%esp
8048454: 83 ec 08 sub $0x8,%esp
8048457: ff 35 84 98 04 08 pushl 0x8049884
804845d: 68 35 87 04 08 push $0x8048735
8048462: e8 e1 fe ff ff call 8048348 <_init+0x48>
8048467: 83 c4 10 add $0x10,%esp
804846a: 83 ec 08 sub $0x8,%esp
804846d: a1 84 98 04 08 mov 0x8049884,%eax
8048472: ff 30 pushl (%eax)
8048474: 68 47 87 04 08 push $0x8048747
8048479: e8 ca fe ff ff call 8048348 <_init+0x48>
804847e: 83 c4 10 add $0x10,%esp
8048481: 83 ec 0c sub $0xc,%esp
8048484: 68 5c 87 04 08 push $0x804875c
8048489: e8 ba fe ff ff call 8048348 <_init+0x48>
804848e: 83 c4 10 add $0x10,%esp
8048491: 8d 45 fc lea 0xfffffffc(%ebp),%eax
8048494: 83 e0 f0 and $0xfffffff0,%eax
8048497: 89 45 f8 mov %eax,0xfffffff8(%ebp)
804849a: 8b 55 0c mov 0xc(%ebp),%edx
804849d: 8b 45 f8 mov 0xfffffff8(%ebp),%eax
80484a0: 3b 02 cmp (%edx),%eax
80484a2: 72 02 jb 80484a6 <main+0x8a>
80484a4: eb 61 jmp 8048507 <main+0xeb>
80484a6: 83 ec 08 sub $0x8,%esp
80484a9: ff 75 f8 pushl 0xfffffff8(%ebp)
80484ac: 68 5f 87 04 08 push $0x804875f
80484b1: e8 92 fe ff ff call 8048348 <_init+0x48>
80484b6: 83 c4 10 add $0x10,%esp
80484b9: c7 45 fc 00 00 00 00 movl $0x0,0xfffffffc(%ebp)
80484c0: 83 7d fc 03 cmpl $0x3,0xfffffffc(%ebp)
80484c4: 76 02 jbe 80484c8 <main+0xac>
80484c6: eb 27 jmp 80484ef <main+0xd3>
80484c8: 83 ec 08 sub $0x8,%esp
80484cb: 8b 45 fc mov 0xfffffffc(%ebp),%eax
80484ce: 8d 14 85 00 00 00 00 lea 0x0(,%eax,4),%edx
80484d5: 8b 45 f8 mov 0xfffffff8(%ebp),%eax
80484d8: ff 34 10 pushl (%eax,%edx,1)
80484db: 68 67 87 04 08 push $0x8048767
80484e0: e8 63 fe ff ff call 8048348 <_init+0x48>
80484e5: 83 c4 10 add $0x10,%esp
80484e8: 8d 45 fc lea 0xfffffffc(%ebp),%eax
80484eb: ff 00 incl (%eax)
80484ed: eb d1 jmp 80484c0 <main+0xa4>
80484ef: 83 ec 0c sub $0xc,%esp
80484f2: 68 6d 87 04 08 push $0x804876d
80484f7: e8 4c fe ff ff call 8048348 <_init+0x48>
80484fc: 83 c4 10 add $0x10,%esp
80484ff: 8d 45 f8 lea 0xfffffff8(%ebp),%eax
8048502: 83 00 10 addl $0x10,(%eax)
8048505: eb 93 jmp 804849a <main+0x7e>
8048507: 83 ec 0c sub $0xc,%esp
804850a: 68 5c 87 04 08 push $0x804875c
804850f: e8 34 fe ff ff call 8048348 <_init+0x48>
8048514: 83 c4 10 add $0x10,%esp
8048517: 8b 45 0c mov 0xc(%ebp),%eax
804851a: 8b 00 mov (%eax),%eax
804851c: 83 e0 f0 and $0xfffffff0,%eax
804851f: 83 e8 10 sub $0x10,%eax
8048522: 89 45 f4 mov %eax,0xfffffff4(%ebp)
8048525: 81 7d f4 ff ff ff bf cmpl $0xbfffffff,0xfffffff4(%ebp)
804852c: 76 05 jbe 8048533 <main+0x117>
804852e: e9 c5 00 00 00 jmp 80485f8 <main+0x1dc>
8048533: 83 ec 08 sub $0x8,%esp
8048536: ff 75 f4 pushl 0xfffffff4(%ebp)
8048539: 68 5f 87 04 08 push $0x804875f
804853e: e8 05 fe ff ff call 8048348 <_init+0x48>
8048543: 83 c4 10 add $0x10,%esp
8048546: c7 45 fc 00 00 00 00 movl $0x0,0xfffffffc(%ebp)
804854d: 83 7d fc 0f cmpl $0xf,0xfffffffc(%ebp)
8048551: 76 02 jbe 8048555 <main+0x139>
8048553: eb 25 jmp 804857a <main+0x15e>
8048555: 83 ec 08 sub $0x8,%esp
8048558: 8b 45 fc mov 0xfffffffc(%ebp),%eax
804855b: 03 45 f4 add 0xfffffff4(%ebp),%eax
804855e: 8a 00 mov (%eax),%al
8048560: 25 ff 00 00 00 and $0xff,%eax
8048565: 50 push %eax
8048566: 68 6f 87 04 08 push $0x804876f
804856b: e8 d8 fd ff ff call 8048348 <_init+0x48>
8048570: 83 c4 10 add $0x10,%esp
8048573: 8d 45 fc lea 0xfffffffc(%ebp),%eax
8048576: ff 00 incl (%eax)
8048578: eb d3 jmp 804854d <main+0x131>
804857a: 83 ec 0c sub $0xc,%esp
804857d: 68 75 87 04 08 push $0x8048775
8048582: e8 c1 fd ff ff call 8048348 <_init+0x48>
8048587: 83 c4 10 add $0x10,%esp
804858a: c7 45 fc 00 00 00 00 movl $0x0,0xfffffffc(%ebp)
8048591: 83 7d fc 0f cmpl $0xf,0xfffffffc(%ebp)
8048595: 76 02 jbe 8048599 <main+0x17d>
8048597: eb 44 jmp 80485dd <main+0x1c1>
8048599: 83 ec 0c sub $0xc,%esp
804859c: 8b 45 fc mov 0xfffffffc(%ebp),%eax
804859f: 03 45 f4 add 0xfffffff4(%ebp),%eax
80485a2: 80 38 20 cmpb $0x20,(%eax)
80485a5: 76 1d jbe 80485c4 <main+0x1a8>
80485a7: 8b 45 fc mov 0xfffffffc(%ebp),%eax
80485aa: 03 45 f4 add 0xfffffff4(%ebp),%eax
80485ad: 80 38 7e cmpb $0x7e,(%eax)
80485b0: 77 12 ja 80485c4 <main+0x1a8>
80485b2: 8b 45 fc mov 0xfffffffc(%ebp),%eax
80485b5: 03 45 f4 add 0xfffffff4(%ebp),%eax
80485b8: ba 00 00 00 00 mov $0x0,%edx
80485bd: 8a 10 mov (%eax),%dl
80485bf: 89 55 f0 mov %edx,0xfffffff0(%ebp)
80485c2: eb 07 jmp 80485cb <main+0x1af>
80485c4: c7 45 f0 2e 00 00 00 movl $0x2e,0xfffffff0(%ebp)
80485cb: ff 75 f0 pushl 0xfffffff0(%ebp)
80485ce: e8 55 fd ff ff call 8048328 <_init+0x28>
80485d3: 83 c4 10 add $0x10,%esp
80485d6: 8d 45 fc lea 0xfffffffc(%ebp),%eax
80485d9: ff 00 incl (%eax)
80485db: eb b4 jmp 8048591 <main+0x175>
80485dd: 83 ec 0c sub $0xc,%esp
80485e0: 68 6d 87 04 08 push $0x804876d
80485e5: e8 5e fd ff ff call 8048348 <_init+0x48>
80485ea: 83 c4 10 add $0x10,%esp
80485ed: 8d 45 f4 lea 0xfffffff4(%ebp),%eax
80485f0: 83 00 10 addl $0x10,(%eax)
80485f3: e9 2d ff ff ff jmp 804 |
Hit : 12402 Date : 2013/09/13 04:50
|