다음 어셈블리 코드를 한줄씩 살펴보고 C코드를 추측해본다.
1.
- push ebp, mov ebp, esp : 이 부분은 Prolog 영역으로 스택프레임을 생성하는 부분이다.
- sub esp, 0x14 : esp가 가리키는 주소를 0x14 만큼 뺌으로써 스택 사용을 준비한다.
- mov DWORD PTR [ebp-0x4], 0xa : ebp가 가리키는 주소로부터 0x4만큼 떨어진 곳에 0xa를 저장
- mov DWORD PTR [ebp-0x8], 0x14 : ebp가 가리키는 주소로부터 0x8만큼 떨어진 곳에 0x14를 저장
- mov DWORD PTR [ebp-0xc], 0x0 : ebp가 가리키는 주소로부터 0xc만큼 떨어진 곳에 0x0을 저장
- mov eax, DWORD PTR [ebp-0x8] : eax레지스터에 ebp-0x8 주소에 저장된 데이터를 복사
- mov edx, DWORD PTR [ebp-0x4] : edx레지스터에 ebp-0x4 주소에 저장된 데이터를 복사
- add eax, edx : eax레지스터에 eax에 저장된 데이터와 edx에 저장된 데이터의 합을 저장
- mov DWORD PTR [ebp-oxc], eax : eax에 저장된 데이터를 ebp-oxc 주소에 복사
- mov eax, DWORD PTR [ebp-0xc] : ebp-0xc 주소에 저장된 데이터를 eax에 복사
- mov DWORD PTR [esp+0x4], eax : esp+0x4 주소에 eax에 저장된 데이터를 복사
- mov DWORD PTR [esp], 0x80484f0 : esp가 가리키는 주소에 0x80484f0을 복사
- call 0x80482f0 <printf@plt> : 0x80482f0 주소를 호출하며 해당 주소는 printf 함수이다.
- leave : leave는 move esp, ebp; pop ebp의 두 명령어를 하나의 어셈블리어로 합친 것이다.
- ret : ret는 pop eip 를 수행하며 이전의 함수로 돌아간다.
위 어셈블리 코드를 보면 4바이트 데이터 3개를 스택에 저장(<+6>, <+13>, <+20>)하며 printf 함수를 호출(<+52>)하는 것을 알 수 있다.
이를 바탕으로 C코드를 추측해 보면 다음과 같다.
int main()
{
int a = 10, b = 20, c;
c = a + b;
printf("%d", c);
return 0;
}
2.
- and esp, 0xfffffff0 : esp레지스터를 최적화 하는 코드
- sub esp, 0x20 : esp가 가리키는 주소를 0x20만큼 빼 스택을 준비한다.
- mov DWORD PTR [esp+0x1c], 0x0 : esp+0x1c 주소에 0을 저장
- jmp 0x8048450 <main+51> : 0x8048450 주소로 점프
- cmp DWORD PTR [esp+0x1c], 0x2 : esp+0x1c 주소에 저장된 데이터와 0x2와 비교
- jne 0x804844b <main+46> : esp+0x1c 주소에 저장된 데이터와 0x2가 같지 않으면 0x804844b 주소로 점프
- mov eax, DWORD PTR [esp+0x1c] : eax레지스터에 esp+0x1c 주소에 저장된 데이터를 복사
- mov DWORD PTR [esp+0x4], eax : esp+0x4 주소에 eax레지스터에 저장된 데이터를 복사
- mov DWORD PTR [esp], 0x80484f0 : esp레즈서터가 가리키는 주소에 0x80484f0를 복사
- call 0x80482f0 <printf@plt> : 0x80482f0 주소를 호출하며 해당 주소는 printf()함수의 주소이다.
- add DWORD PTR [esp+0x1c], 0x1 : esp+0x1c 주소에 저장된 데이터에 1을 더함
- cmp DWORD PTR [esp+0x1c], 0x4 : esp+0x1c 주소에 저장된 데이터와 0x4를 비교
- jle 0x8048430 <main+19> : 비교 결과 esp+0x1c가 0x4보다 작거나 같으면 0x8048430 주소로 점프
- mov eax, 0x0 : eax 레지스터 초기화
위 어셈블리 코드를 보면 데이터를 비교하여 되돌아가는(<+51> <+56>) 부분이 반복되는 것을 알 수 있으며 데이터를 비교하여 처리하는(<+19> <+24) 부분이 있는 것을 알 수 있다.
이를 바탕으로 C코드를 추측해 보면 다음과 같다.
int main()
{
int i;
for( i = 0; i < 5; i++ )
{
if( i == 2 )
printf("%d", i);
}
return 0;
}
3.
- sub esp, 0x20 : esp가 가리카는 주소를 0x20만큼 빼 스택을 준비
- mov DWORD PTR [esp+0x18], 0xa : esp+0x18 주소에 0xa를 저장
- mov DWORD PTR [esp+0x1c], 0x14 : esp+0x1c 주소에 0x14를 저장
- mov eax, DWORD PTR [esp+0x1c] : eax에 esp+0x1c에 저장된 데이터를 복사
- DWORD PTR [esp+0x4], eax : esp+0x4 주소에 eax에 저장된 데이터를 복사
- mov eax, DWORD PTR [esp+0x18] : eax에 esp+0x18에 저장된 데이터를 복사
- mov DWORD PTR [esp], eax : esp가 가리키는 주소에 eax 데이터를 저장
- call 0x804841d <addVal> : 0x804841d 주소를 호출하며 addVal() 함수의 주소이다.
- mov DWORD PTR [esp+0x4], eax : addVal() 함수의 리턴값을 가진 eax의 데이터를 esp+0x4 주소에 복사
- mov DWORD PTR [esp], 0x8048500 : esp가 가리키는 주소에 0x8048500을 저장
- call 0x80482f0 <print@plt> : 0x80482f0 주소를 호출하며 printf() 함수의 주소이다.
- mov eax, DWORD PTR [ebp+0xc] : eax 레지스터에 ebp+0xc에 저장된 데이터를 복사( 첫번째 인자)
- mov edx, DWORD PTR [ebp+0x8] : edx 레지스터에 ebp+0x8에 저장된 데이터를 복사( 두번째 인자)
- add eax, edx : eax에 저장된 값과 edx에 저장된 값을 더해 eax에 저장
- pop ebp : 함수 종료
위 2개의 어셈블리 코드를 바탕으로 C코드를 추측해보면 다음과 같다.
#include <stdio.h>
int addVal(int a, int b);
int main()
{
int a = 10, b = 20, c = 0;
c = addVal(a, b);
printf("%d", c);
return 0;
}
int addVal(int a, int b)
{
return a + b;
}
'NCS보안3기 > 프로그래밍 기초' 카테고리의 다른 글
[Programming] 네트워크 (0) | 2017.03.20 |
---|---|
[Programming] 파이썬에 대해서 (0) | 2017.03.18 |
[Programming] 어셈블리 언어 (0) | 2017.03.16 |
[Programming] 레지스터 & 스택 (0) | 2017.03.15 |
[Programming] 변수와 함수 (0) | 2017.03.15 |