[SP] Procedure call in Assembly Language and short introduction of ELF format
System Programming 2013. 11. 6. 00:32※ 질문/내용오류/공유할 내용이 있다면 jinkilee73@gmail.com으로 메일 주세요 :-)
아 요즘 참 공부 복잡하다. 슬럼프인가..? 무슨 공부를 해야하는지 너무 고민되고 하다가 Exploit을 공부하기로 했다. 얼마전에 Exploit 공부하면서 너무 재밌어서 Maybe에서 하자고 했다. 기존에 공부하던 커널은 어쩌고? 우선 잠시 미루자. 제 커널 포스팅을 기다리고 계셨던 독자님들 죄송합니다ㅠㅠ 그래도 공부하면서 조금씩 커널에 관한 이야기는 올라올 겁니다. 사실 올릴 이야기도 많이 있고요.
그래도 Maybe에서 Exploit을 공부하기로 했으니 Assembly를 다시 복습할 수 밖에 없었다. 기본적인 것은 이해하고 있으나 조금 더 구체적으로 공부를 다시 해보고 싶었다. 그래서 Procedure Call을 다시 복습했고 그 외의 명령어들에 대한 복습도 조금씩 했다.
Procedure Call에 대해서는 아래의 링크에서 아주 자세하게 설명해놨다.
http://operatingsystems.tistory.com/entry/SP-Procedure-Call
위의 내용과 관련하여 추가적으로 정리하고 싶은 것은 전체적인 스택의 구조이다. 위의 링크에서는 각각의 메모리가 어떤식으로 값이 저장되는지 어떤식으로 다시 이전의 프레임으로 돌아오는지에 대한 이야기는 구체적으로 잘 적혀있지만 전체적인 그림은 없다. 그 전체적인 그림이 아래의 그림과 같다.
친절하게 같은 그림을 두 개 그려서 실제로 어떤 식으로 값이 들어가 있는지 오른쪽 그림에서 볼 수 있다. sum함수의 stack frame과 main 함수의 stack frame 그 경계에 어떤 값이 있으며 그 양쪽으로 어떤 값이 늘어서는지 잘 보고 그 구조를 이해한 후 외워야 한다.
위의 그림을 보면 두 함수의 경계에서 caller함수인 main함수 쪽에는 eip값이 들어가 있고 callee함수인 sum함수 쪽에는 main함수 stack frame의 가장 bottom address인 main의 %ebp가 들어있다. 그리고 eip값 이전에는 sum함수를 호출하기 위해 쓰일 argument들이 쌓여있다. 마지막으로 main의 %ebp 다음에는 sum함수에서 쓰일 변수들이 쌓여있다.
저 구조를 머리 속에 외워두면 실제 어셈블리 코드를 작성할 수도 있다. 정말이냐고? 정말이다. 그래서 간단한 프로그램을 직접 어셈블리 언어로 작성해봤다. 간단하게 hello world를 10번 출력하는 프로그램이다.
첫번째 이렇게 코딩을 해서 실행을 시켜보니까 아래와 같은 에러가 발생했다.
위의 에러가 발새하는 이유를 읽어보면 main에 대한 reference가 정의되지 않았다고 하는데...
나는 사실 여기서 생각했다. 조금더 알기 위해서는 elf 파일 포멧에 대해서 공부를 해야되겠다고. 이것을 보자마자 예전에 시스템 프로그래밍 공부했을 때 봤던 책을 펴서 elf 파일 포멧에 대해서 공부했다.
여기서는 ELF 포멧이 어떤 것이며 어떠한 정보를 포함하고 있는지만 간략적으로 언급하고 넘어가겠다. (ELF 포멧에 대한 자세한 포스팅은 조만간 올라올 예정이다. 그러니까 조금만 기다려주라.)
컴퓨터를 전공하는 사람이라면 PE 파일 포멧이라는 말을 들어봤을 것이다. 이는 windows의 실행파일 포멧을 의미한다. windows의 실행파일 포멧 대표적으로 exe가 있고 dll이 있다. 그 외의 windows의 실행파일 포멧은 .cpl .ocx .sys .scr .drv .efi 등등이 있다. 이 파일들이 실제 reverse engineering 이나 다른 부분에서 얼마나 자주 쓰이는 지는 잘 모르겠다. 아무튼 PE파일 포멧은 이러한 확장자를 가진 파일에 대한 파일 구조이다.
windows에서 PE파일 포멧을 사용한다면 linux에서는 어떤 파일 포멧을 사용할까? 그것이 ELF파일 포멧이다. ELF파일은 Executable and Linking Format의 약자로, wikipedia에서 아래와 같이 설명되어있다.
In computing, the Executable and Linkable Format (ELF, formerly called Extensible Linking Format) is a common standard file format for executables, object code, shared libraries, and core dumps. First published in the System V Application Binary Interfacespecification,[1] and later in the Tool Interface Standard,[2] it was quickly accepted among different vendors of Unix systems. In 1999 it was chosen as the standard binary file format for Unix and Unix-like systems on x86 by the 86open project.
ELF is flexible and extensible by design, and it is not bound to any particular processor or architecture. This has allowed it to be adopted by many different operating systems on many different platforms.
Filename extension | none, .o, .so, .elf, .prx,.puff, .bin |
---|---|
Magic number | 0x7F 'E' 'L' 'F' |
Developed by | Unix System Laboratories |
Type of format | Binary, executable, object,shared libraries, core dump |
Container for | Many executable binary formats |
출처 : http://en.wikipedia.org/wiki/Executable_and_Linkable_Format
위의 표에서 보이다 시피 ELF 포멧은 .none .o .so .elf .prx .puff .bin 파일에 대한 포멧이다. 여기서 잠깐 자꾸 포멧 포멧 하는데 도데체 포멧이 무엇이냐 라고 질문하는 사람이 있을 것이다. 여기서 말하는 포멧이란 파일의 구조를 말하는 것이다. 가령 100byte짜리 프로그램이 있다면 처음 7byte까지는 header가 있고 그 다음부터 20byte까지는 section table이 있고 등등 이런 식이다.(단순 예를 들기 위한 예시일 뿐이다. 실제로는 header 다음에 section table이 오지 않는다.)
위의 그림을 다시 한번 보자.
여기에는 오로지 코드밖에 없다. assembly language는 코드만 가지고는 동작하지 않는다. 반드시 아래와 같이 추가적인 정보가 head와 tail에 붙여져야 한다.
사실 .c파일을 컴파일러로 컴파일을 하면 나오는 .s파일은 위의 정보보다 더욱 많은 정보를 포함하고 있다. 실제로 컴파일을 해보면 .cfi_startproc .cfi_endproc 등등과 같은 여러 가지 내용이 각 함수의 procedure마다 추가되어있다. 그 내용들에 대해서는 다음 포스팅에서 설명할 생각이다. 위의 그림에서 head에 나온 내용을 설명해보면 다음과 같다.
위의 정보들을 보면 대충 무엇에 대한 정보가 들어있는지 추측할 수 있다. Hello World\nHello World처럼 main 함수에서 print할 문자열도 있다. main이 global 하다는 것도 알려주며 그것이 함수라는 것도 알려준다. 대략 이런 정보들이 있다.
도대체 이게 뭘까 아직도 궁금한 사람이 있다면 다음 포스팅을 기다려라. 다음 포스팅을 보기 전에 아래의 그림을 봐주길 바란다. 봐도 뭔지 모르겠지만 그냥 봐서 익숙해지자. section은 뭐고 symbol은 뭐고 section table은 무엇이며 아놔 모르겠다. 라고 말하셔도 된다. 그럴 수 밖에 없다. 그렇지만 다음에 배울 내용에 대한 예습 맛보기 라고 생각하고 보자. 아래의 그림은 readelf 라는 명령어로 elf 파일 포멧을 읽은 것이다.
============================================================================
root@xxxxx-MS-7592:/# readelf -a func
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x80482f0
Start of program headers: 52 (bytes into file)
Start of section headers: 5284 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 9
Size of section headers: 40 (bytes)
Number of section headers: 36
Section header string table index: 33
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 08048154 000154 000013 00 A 0 0 1
[ 2] .note.ABI-tag NOTE 08048168 000168 000020 00 A 0 0 4
[ 3] .note.gnu.build-i NOTE 08048188 000188 000024 00 A 0 0 4
[ 4] .gnu.hash GNU_HASH 080481ac 0001ac 000020 04 A 5 0 4
[ 5] .dynsym DYNSYM 080481cc 0001cc 000040 10 A 6 1 4
[ 6] .dynstr STRTAB 0804820c 00020c 000045 00 A 0 0 1
[ 7] .gnu.version VERSYM 08048252 000252 000008 02 A 5 0 2
[ 8] .gnu.version_r VERNEED 0804825c 00025c 000020 00 A 6 1 4
[ 9] .rel.dyn REL 0804827c 00027c 000008 08 A 5 0 4
[10] .rel.plt REL 08048284 000284 000010 08 A 5 12 4
[11] .init PROGBITS 08048294 000294 000023 00 AX 0 0 4
[12] .plt PROGBITS 080482c0 0002c0 000030 04 AX 0 0 16
[13] .text PROGBITS 080482f0 0002f0 0001c4 00 AX 0 0 16
[14] .fini PROGBITS 080484b4 0004b4 000014 00 AX 0 0 4
[15] .rodata PROGBITS 080484c8 0004c8 000008 00 A 0 0 4
[16] .eh_frame_hdr PROGBITS 080484d0 0004d0 000034 00 A 0 0 4
[17] .eh_frame PROGBITS 08048504 000504 0000d0 00 A 0 0 4
[18] .init_array INIT_ARRAY 08049f08 000f08 000004 00 WA 0 0 4
[19] .fini_array FINI_ARRAY 08049f0c 000f0c 000004 00 WA 0 0 4
[20] .jcr PROGBITS 08049f10 000f10 000004 00 WA 0 0 4
[21] .dynamic DYNAMIC 08049f14 000f14 0000e8 08 WA 6 0 4
[22] .got PROGBITS 08049ffc 000ffc 000004 04 WA 0 0 4
[23] .got.plt PROGBITS 0804a000 001000 000014 04 WA 0 0 4
[24] .data PROGBITS 0804a014 001014 000008 00 WA 0 0 4
[25] .bss NOBITS 0804a01c 00101c 000008 00 WA 0 0 4
[26] .comment PROGBITS 00000000 00101c 00002a 01 MS 0 0 1
[27] .debug_aranges PROGBITS 00000000 001046 000020 00 0 0 1
[28] .debug_info PROGBITS 00000000 001066 0000fb 00 0 0 1
[29] .debug_abbrev PROGBITS 00000000 001161 00009e 00 0 0 1
[30] .debug_line PROGBITS 00000000 0011ff 00004e 00 0 0 1
[31] .debug_str PROGBITS 00000000 00124d 000096 01 MS 0 0 1
[32] .debug_loc PROGBITS 00000000 0012e3 000070 00 0 0 1
[33] .shstrtab STRTAB 00000000 001353 000151 00 0 0 1
[34] .symtab SYMTAB 00000000 001a44 0004a0 10 35 51 4
[35] .strtab STRTAB 00000000 001ee4 000249 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
There are no section groups in this file.
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000034 0x08048034 0x08048034 0x00120 0x00120 R E 0x4
INTERP 0x000154 0x08048154 0x08048154 0x00013 0x00013 R 0x1
[Requesting program interpreter: /lib/ld-linux.so.2]
LOAD 0x000000 0x08048000 0x08048000 0x005d4 0x005d4 R E 0x1000
LOAD 0x000f08 0x08049f08 0x08049f08 0x00114 0x0011c RW 0x1000
DYNAMIC 0x000f14 0x08049f14 0x08049f14 0x000e8 0x000e8 RW 0x4
NOTE 0x000168 0x08048168 0x08048168 0x00044 0x00044 R 0x4
GNU_EH_FRAME 0x0004d0 0x080484d0 0x080484d0 0x00034 0x00034 R 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4
GNU_RELRO 0x000f08 0x08049f08 0x08049f08 0x000f8 0x000f8 R 0x1
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame
03 .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss
04 .dynamic
05 .note.ABI-tag .note.gnu.build-id
06 .eh_frame_hdr
07
08 .init_array .fini_array .jcr .dynamic .got
Dynamic section at offset 0xf14 contains 24 entries:
Tag Type Name/Value
0x00000001 (NEEDED) Shared library: [libc.so.6]
0x0000000c (INIT) 0x8048294
0x0000000d (FINI) 0x80484b4
0x00000019 (INIT_ARRAY) 0x8049f08
0x0000001b (INIT_ARRAYSZ) 4 (bytes)
0x0000001a (FINI_ARRAY) 0x8049f0c
0x0000001c (FINI_ARRAYSZ) 4 (bytes)
0x6ffffef5 (GNU_HASH) 0x80481ac
0x00000005 (STRTAB) 0x804820c
0x00000006 (SYMTAB) 0x80481cc
0x0000000a (STRSZ) 69 (bytes)
0x0000000b (SYMENT) 16 (bytes)
0x00000015 (DEBUG) 0x0
0x00000003 (PLTGOT) 0x804a000
0x00000002 (PLTRELSZ) 16 (bytes)
0x00000014 (PLTREL) REL
0x00000017 (JMPREL) 0x8048284
0x00000011 (REL) 0x804827c
0x00000012 (RELSZ) 8 (bytes)
0x00000013 (RELENT) 8 (bytes)
0x6ffffffe (VERNEED) 0x804825c
0x6fffffff (VERNEEDNUM) 1
0x6ffffff0 (VERSYM) 0x8048252
0x00000000 (NULL) 0x0
Relocation section '.rel.dyn' at offset 0x27c contains 1 entries:
Offset Info Type Sym.Value Sym. Name
08049ffc 00000106 R_386_GLOB_DAT 00000000 __gmon_start__
Relocation section '.rel.plt' at offset 0x284 contains 2 entries:
Offset Info Type Sym.Value Sym. Name
0804a00c 00000107 R_386_JUMP_SLOT 00000000 __gmon_start__
0804a010 00000207 R_386_JUMP_SLOT 00000000 __libc_start_main
The decoding of unwind sections for machine type Intel 80386 is not currently supported.
Symbol table '.dynsym' contains 4 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
2: 00000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.0 (2)
3: 080484cc 4 OBJECT GLOBAL DEFAULT 15 _IO_stdin_used
Symbol table '.symtab' contains 74 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 08048154 0 SECTION LOCAL DEFAULT 1
2: 08048168 0 SECTION LOCAL DEFAULT 2
3: 08048188 0 SECTION LOCAL DEFAULT 3
4: 080481ac 0 SECTION LOCAL DEFAULT 4
5: 080481cc 0 SECTION LOCAL DEFAULT 5
6: 0804820c 0 SECTION LOCAL DEFAULT 6
7: 08048252 0 SECTION LOCAL DEFAULT 7
8: 0804825c 0 SECTION LOCAL DEFAULT 8
9: 0804827c 0 SECTION LOCAL DEFAULT 9
10: 08048284 0 SECTION LOCAL DEFAULT 10
11: 08048294 0 SECTION LOCAL DEFAULT 11
12: 080482c0 0 SECTION LOCAL DEFAULT 12
13: 080482f0 0 SECTION LOCAL DEFAULT 13
14: 080484b4 0 SECTION LOCAL DEFAULT 14
15: 080484c8 0 SECTION LOCAL DEFAULT 15
16: 080484d0 0 SECTION LOCAL DEFAULT 16
17: 08048504 0 SECTION LOCAL DEFAULT 17
18: 08049f08 0 SECTION LOCAL DEFAULT 18
19: 08049f0c 0 SECTION LOCAL DEFAULT 19
20: 08049f10 0 SECTION LOCAL DEFAULT 20
21: 08049f14 0 SECTION LOCAL DEFAULT 21
22: 08049ffc 0 SECTION LOCAL DEFAULT 22
23: 0804a000 0 SECTION LOCAL DEFAULT 23
24: 0804a014 0 SECTION LOCAL DEFAULT 24
25: 0804a01c 0 SECTION LOCAL DEFAULT 25
26: 00000000 0 SECTION LOCAL DEFAULT 26
27: 00000000 0 SECTION LOCAL DEFAULT 27
28: 00000000 0 SECTION LOCAL DEFAULT 28
29: 00000000 0 SECTION LOCAL DEFAULT 29
30: 00000000 0 SECTION LOCAL DEFAULT 30
31: 00000000 0 SECTION LOCAL DEFAULT 31
32: 00000000 0 SECTION LOCAL DEFAULT 32
34: 08049f10 0 OBJECT LOCAL DEFAULT 20 __JCR_LIST__
38: 0804a01c 1 OBJECT LOCAL DEFAULT 25 completed.6339
39: 08049f0c 0 OBJECT LOCAL DEFAULT 19 __do_global_dtors_aux_fin
41: 08049f08 0 OBJECT LOCAL DEFAULT 18 __frame_dummy_init_array_
44: 080485d0 0 OBJECT LOCAL DEFAULT 17 __FRAME_END__
45: 08049f10 0 OBJECT LOCAL DEFAULT 20 __JCR_END__
48: 08049f14 0 OBJECT LOCAL DEFAULT 21 _DYNAMIC
50: 0804a000 0 OBJECT LOCAL DEFAULT 23 _GLOBAL_OFFSET_TABLE_
59: 0804a018 0 OBJECT GLOBAL HIDDEN 24 __dso_handle
60: 080484cc 4 OBJECT GLOBAL DEFAULT 15 _IO_stdin_used
66: 080484c8 4 OBJECT GLOBAL DEFAULT 15 _fp_hw
70: 0804a020 4 OBJECT GLOBAL DEFAULT 25 glov
71: 0804a01c 0 OBJECT GLOBAL HIDDEN 24 __TMC_END__
## no procedure has lower address than _start besides _init
61: 00000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@@GLIBC_
73: 08048294 0 FUNC GLOBAL DEFAULT 11 _init
65: 080482f0 0 FUNC GLOBAL DEFAULT 13 _start
53: 08048320 4 FUNC GLOBAL HIDDEN 13 __x86.get_pc_thunk.bx
35: 08048330 0 FUNC LOCAL DEFAULT 13 deregister_tm_clones
36: 08048360 0 FUNC LOCAL DEFAULT 13 register_tm_clones
37: 080483a0 0 FUNC LOCAL DEFAULT 13 __do_global_dtors_aux
40: 080483c0 0 FUNC LOCAL DEFAULT 13 frame_dummy
62: 080483ec 49 FUNC GLOBAL DEFAULT 13 func
68: 0804841d 35 FUNC GLOBAL DEFAULT 13 main
63: 08048440 97 FUNC GLOBAL DEFAULT 13 __libc_csu_init
51: 080484b0 2 FUNC GLOBAL DEFAULT 13 __libc_csu_fini
56: 080484b4 0 FUNC GLOBAL DEFAULT 14 _fini
## ABS is the file that should not be relocated
33: 00000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
42: 00000000 0 FILE LOCAL DEFAULT ABS test.c
43: 00000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
46: 00000000 0 FILE LOCAL DEFAULT ABS
47: 08049f0c 0 NOTYPE LOCAL DEFAULT 18 __init_array_end
49: 08049f08 0 NOTYPE LOCAL DEFAULT 18 __init_array_start
52: 00000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab
54: 0804a014 0 NOTYPE WEAK DEFAULT 24 data_start
55: 0804a01c 0 NOTYPE GLOBAL DEFAULT 24 _edata
57: 0804a014 0 NOTYPE GLOBAL DEFAULT 24 __data_start
58: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
64: 0804a024 0 NOTYPE GLOBAL DEFAULT 25 _end
67: 0804a01c 0 NOTYPE GLOBAL DEFAULT 25 __bss_start
69: 00000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
72: 00000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
Histogram for `.gnu.hash' bucket list length (total of 2 buckets):
Length Number % of total Coverage
0 1 ( 50.0%)
1 1 ( 50.0%) 100.0%
Version symbols section '.gnu.version' contains 4 entries:
Addr: 0000000008048252 Offset: 0x000252 Link: 5 (.dynsym)
000: 0 (*local*) 0 (*local*) 2 (GLIBC_2.0) 1 (*global*)
Version needs section '.gnu.version_r' contains 1 entries:
Addr: 0x000000000804825c Offset: 0x00025c Link: 6 (.dynstr)
000000: Version: 1 File: libc.so.6 Cnt: 1
0x0010: Name: GLIBC_2.0 Flags: none Version: 2
Notes at offset 0x00000168 with length 0x00000020:
Owner Data size Description
GNU 0x00000010 NT_GNU_ABI_TAG (ABI version tag)
OS: Linux, ABI: 2.6.24
Notes at offset 0x00000188 with length 0x00000024:
Owner Data size Description
GNU 0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring)
Build ID: 15ba02e08f2be0aa3352d7cca6e07c77773b2c2f
위의 내용에 대해서 차근 차근 설명할 것이니 조금만 기다려라. section이 뭔지 symbol은 또 뭔지 전부 다 설명할거다. 나도 공부를 해야 블로깅을 할 수 있다.ㅠㅠ
'System Programming' 카테고리의 다른 글
[SP] Relocatable Object File (0) | 2014.02.19 |
---|---|
[SP] ELF File (0) | 2014.02.17 |
[SP] Optimizing a Program with a hardware dependent perspective (0) | 2013.05.23 |
[SP] Optimizing a program with a hardware independent perspective (1) | 2013.05.21 |
[SP] Conditional Jump (1) | 2013.05.14 |