티스토리 뷰

! 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 가 불가능한 상황이 있음.


댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함