본문 바로가기

High Level Technique/Handray

printf / 변수1

어셈블리어의 구조를 알고 이해를 한 후에 다시 C로 작성하는 것을 handray라고 합니다. 이 연습을 많이하면 gdb를 사용하면서 눈에 금방 들어오게 될거 같아서 연습을 해보려고 합니다.





아주 간단한 C언어 소스입니다. 변수 a에 16이라는 값을 넣고,a에 들어있는 값을 출력해주는 프로그램입니다.


저는 소스 파일을 printf1.c 라는 이름으로 만들고 저장했습니다.


gcc로 컴파일 합니다. 이때 -fno-stack-protector -mpreferred-stack-boundary=2 옵션을 해줍니다.

스택 보호를 풀어주고 쓰레기값을 제거해줍니다.












===================================================================================================================

이제 gdb로 분석을 해보도록 하겠습니다.









===================================================================================================================

0x0804841d <+0>: push   ebp



push ebp로 스택공간을 형성합니다.



main의 첫번째에 breakpoint를 걸고 ni를 해서 실행시킵니다. 그러면 push ebp가 실행됩니다.



info reg로 레지스터를 확인합니다. (i r 로도 됩니다.)



아직 ebp의 값의 상태 변화는 없습니다. 여기서 다음 실행 될 어셈블리어가 mov ebp, esp인것을 알고 있으니 esp의 값인 0xbffff0d8을 기억합니다.








===================================================================================================================

0x0804841e <+1>: mov    ebp,esp




ni를 해서 mov ebp, esp를 실행시킵니다. 

그리고 i r로 레지스터를 확인합니다.


esp와 ebp의 값이 같아진 것을 확인 할 수 있습니다.




위 그림처럼 ebp와 esp의 주소 값이 스택의 시작 주소가 됩니다. 








===================================================================================================================


0x08048420 <+3>: esp, 0xc


ni를 실행시켜서 sub esp, 0xc를 실행시킵니다.

sub esp, 0xc의 의미는 esp에서 0xc 만큼 뺀다 라는 의미입니다.






i r을 실행시켜 레지스터를 확인해보니 esp의 값이 0xbffff0cc가 되었다는 것을 알 수 있습니다.








===================================================================================================================


0x08048423 <+6>: mov DWORD PTR [epb-0x4], 0x10


ebp-0x4 만큼 위치한 곳에 0x10 값을 넣어줍니다.





ebp-4의 주소에 있는 값을 확인해 봅니다.  그러면 10이 들어간 것을 확인 할 수 있습니다.











===================================================================================================================


0x0804842a <+13>: mov eax, DWORD PTR [ebp-0x4]


ebp-0x4의 값을 eax로 이동합니다.



eax의 값에 0x10이 들어간 것을 확인합니다.









===================================================================================================================



0x0804842d <+16>: mov DWORD PTR [esp+0x4], eax


eax의 값을 esp+0x4에 이동합니다.



esp+4의 위치에 0x10 값이 들어있는 것을 확인할 수 있습니다.









===================================================================================================================



0x08048431 <+20>: mov DWORD PTR [esp], 0x80484e0


0x80484e0이라는 값을 esp에 넣어줍니다. 다음 주소에 나오는 call 0x80482f0 <printf@plt>의 첫번째 인자 값입니다.



$esp의 값을 보면 0x080484e0가 있는 것을 알 수 있고, 이 값을 string으로 보게 되면 "%d \n" 인것을 확인할 수 있습니다.

따라서 printf의 첫번재 인자가 %d \n이라고 알 수 있습니다.









===================================================================================================================



0x08048438 <+27>: call 0x80482f0 <printf@plt>


0x80482f0의 주소를 부릅니다. 이것은 함수를 호출하는 것인데 printf 함수를 호출하게 됩니다. 그리고 호출이 완료되면 출력값이 나오게됩니다.




ni을 실행하면 16이라는 값이 출력됩니다.







===================================================================================================================



0x0804843d <+32>: mov eax, 0x0



사용했던 eax의 값을 0으로 초기화 시켜줍니다.



이렇게 분석이 끝나게 됩니다.



1. 변수는 1개가 사용되었고 그 값은 0x10 (16)이라는 것을 알았습니다. 

2. 출력결과를 보면 16이라는 값이 출력되었습니다.

3. printf의 첫번째 인자값을 보고 %d \n 개행까지 있는것을 알았습니다.


이렇게 역분석을 통해서 다시 C로 코딩을 하게 됩니다.