main startup routine bt
main
의 상위 frame은 \_\_libc\_start\_main
이다.
__libc_start_main
\_\_libc\_start\_main
은 init, fini, stack\_end
등을 인자로 받는데, 첫 번째 인자로 main
의 함수 포인터 를 받는다.
1
2
3
4
5
6
7
8
int \_\_cdecl \_libc\_start\_main(int (\_\_cdecl \*main)(int, char \*\*, char \*\*), int argc, char \*\*ubp\_av,
void (\*init)(void), void (\*fini)(void), void (\*rtld\_fini)(void), void \*stack\_end)
.text:0000000000000A5D lea rdi, main ; main
.text:0000000000000A64 call \_\_libc\_start\_main
\_\_libc\_start\_main
의 상위 frame은 \_start
다.
start ( = Entry point )
OEP(Original Entry Point) = Image Base + Address of Entry Point(RVA)
바이너리에서 코드의 시작 지점은 Image Base + Base of Code
지만, 실제로 프로그램이 맨 처음 실행하게 되는 Instruction은 Entry Point 다. 그리고 OEP에는 start
가 있다.
* Base of Code와 OEP(Address of Entry Point)는 전혀 관련이 없다. Base of Code는 단순히 코드 섹션이 거기서 부터 시작한다는 것을 의미한다. * Base of Code에는 컴파일러가 포함한 스타트업 루틴 등 stub code가 위치하게 되는데, 단순히 위치 상으로 Address of Entry Point 이전에 있는 코드라고 해서 스타트업 루틴으로 간주해서는 안된다. * 스타트업 루틴 등이 위치한 경우 디버거로 봐도 EIP에 들어가는걸 볼 수 없다. 그런 루틴이 끝나야 디버거에 로드되기 때문.
\_start → \_\_libc\_start\_main → main
순으로 호출하고, main
에서 ret
시 \_\_libc\_start\_main
의 끝부분 (+255)로 가게 된다. 여기서 call
instruction을 수행하면서 어딘가로 가게되는데 dl
계열 함수들이나 exit함수를 통해 자원반납이나 종료선행작업을 하는 듯 보인다.
\_\_libc\_start\_main
에서 ret
시 \_start+33
으로 가게 되는데, 여기서 hlt
instruction을 실행하게 된다.
hlt
를 실행하면 CPU는 외부 인터럽트가 들어올 때 까지 대기한다.
Windows
Windows도 크게 다르지 않다. start → [jmp : tmainCRTStartup ... call : main] → main
순으로 호출한다.