티스토리 뷰
! C++ / GCC
Code
int add(int src, int dest)
{
return src + dest;
}
int main(int argc, char* argv)
{
int i_test = 13;
char c_test = 'c';
char str_test[] = "string"; // 간단한 변수 선언
i_test = add(1, i_test); // 함수 호출
}
Asm
.text:08048448 public main
.text:08048448 main proc near ; DATA XREF: _start+17o
.text:08048448
.text:08048448 var_2C = dword ptr -2Ch
.text:08048448 var_19 = byte ptr -19h
.text:08048448 var_18 = dword ptr -18h
.text:08048448 var_13 = dword ptr -13h
.text:08048448 var_F = word ptr -0Fh
.text:08048448 var_D = byte ptr -0Dh
.text:08048448 var_C = dword ptr -0Ch
.text:08048448 var_4 = dword ptr -4
.text:08048448 argc = dword ptr 0Ch
.text:08048448 argv = dword ptr 10h
.text:08048448 envp = dword ptr 14h
.text:08048448
.text:08048448 000 lea ecx, [esp+4]
.text:0804844C 000 and esp, 0FFFFFFF0h
.text:0804844F 000 push dword ptr [ecx-4]
.text:08048452 000 push ebp
.text:08048453 004 mov ebp, esp
.text:08048455 004 push ecx
.text:08048456 008 sub esp, 34h
.text:08048459 03C mov eax, ecx
.text:0804845B 03C mov eax, [eax+4]
.text:0804845E 03C mov [ebp+var_2C], eax
.text:08048461 03C mov eax, large gs:14h
.text:08048467 03C mov [ebp+var_C], eax
.text:0804846A 03C xor eax, eax
.text:0804846C 03C mov [ebp+var_18], 0Dh
.text:08048473 03C mov [ebp+var_19], 63h
.text:08048477 03C mov [ebp+var_13], 69727473h
.text:0804847E 03C mov [ebp+var_F], 676Eh
.text:08048484 03C mov [ebp+var_D], 0
.text:08048488 03C push [ebp+var_18]
.text:0804848B 040 push 1
.text:0804848D 044 call add
.text:08048492 044 add esp, 8
.text:08048495 03C mov [ebp+var_18], eax
.text:08048498 03C mov edx, [ebp+var_C]
.text:0804849B 03C xor edx, large gs:14h
.text:080484A2 03C jz short loc_80484A9
.text:080484A4 03C call ___stack_chk_fail
.text:080484A9 ; ---------------------------------------------------------------------------
.text:080484A9
.text:080484A9 loc_80484A9: ; CODE XREF: main+5Aj
.text:080484A9 03C mov ecx, [ebp+var_4]
.text:080484AC 03C leave
.text:080484AD 000 lea esp, [ecx-4]
.text:080484B0 000 retn
.text:0804843B public add
.text:0804843B add proc near
.text:0804843B
.text:0804843B arg_0 = dword ptr 8
.text:0804843B arg_4 = dword ptr 0Ch
.text:0804843B
.text:0804843B 000 push ebp
.text:0804843C 004 mov ebp, esp
.text:0804843E 004 mov edx, [ebp+arg_0]
.text:08048441 004 mov eax, [ebp+arg_4]
.text:08048444 004 add eax, edx
.text:08048446 004 pop ebp
.text:08048447 000 retn
.text:08048447 add
Main (0x08048448) 에서 프로그램 시작.
~ .text:08048453 : 함수가 호출되었을 때 스택 프레임을 무시하고 새로 만든다.
~ .text:08048456 : 0x34 만큼 스택 저장공간 할당
~ .text:08048467 : 스택 버퍼오버플로우 방지용 Stack canary 생성. (gs:14h -> stack canary)
~ .text:08048473 : i_test에 13을, c_test에 'c' 할당함.
이 때, i_test는 int 형식이므로 DWORD(4bytes) 0x0000000D를 EBP-0x18 주소에,
c_test는 char 형식이므로 BYTE(1byte) 0x63h를 EBP-0x19 주소에 할당한다.
gdb에서는 어셈블리 코드에 BYTE PTR, WORD PTR와 같이 데이터 크기를 prefix로 알려주며,
IDA에서는 분석한 스택을 기반으로 한 arg_x, var_x 리스트에서 포인터의 크기를 나타내 준다.
~ .text:08048484 : char[] 형식에 문자열 "string"을 대입
C++ 언어에서는 문자열 (char array)를 취급 시, 문자열 맨 마지막에 terminator를 붙여준다.
~ .text:0804848D : 함수 호출. (__cdecl)
마지막 인자를 맨 처음에, 처음 인자를 맨 마지막에 스택에 push한다. (함수 호출 시 맨 처음 argument 가 esp)
예외적으로, push 를 하지 않고 mov esp+??h arg 와 같이 설정하기도 한다.
~ .text:0804843B : 함수 프롤로그 실행 후,
edx, eax 에 인자들을 불러오고, return 값인 eax 에 결과값을 저장한 다음 함수 에필로그를 실행하고(ebp 복구)main 함수로 흐름을 되돌아간다.
~ .text:08048492 : 스택 정리(전달한 인자), 나머지 코드 실행.
stack canary를 검사하고, 이전과 다를 경우 스택이 손상되었음을 알린다.
text:08048473 // char str_test[] = "string"; // 간단한 변수 선언
일반적으로, 함수를 호출할 때 const char (포맷 스트링) 같은 데이터를 넣게 되면, .data 섹션에 문자열을 넣어놓고 offset 을 push해 사용한다.
전역 변수로 const char[] = "STR" 와 같은 구문에서도 종종 이렇게 사용되나,
데이터를 변경할 가능성이 있는 일반 스택 변수에서는 mov 명령을 통해, dword, word, byte 형태로 크기를 나누어 문자열을 하나씩 집어넣는 경우가 있다.
이럴 경우, 종종 바이너리에서 string을 뽑아내는 프로그램이 거의다 검색해내지 못하게 된다. (애초에 int 나 기타 자료형과 굉장히 유사하게 됨)
+ 예제 재 추가 예정 ) Visual C++ 2010에서 컴파일 시 Write 권한이 없는 곳에 문자열을 넣고 포인터를 할당해 write 가 불가능한 상황이 있음.
댓글