ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • c언어 -> 어셈블리어 변환 연습
    Rev 2023. 7. 9. 14:39
    //test.c
    
    #include <stdio.h>
    
    int main(int argc, char* argv[]) {
    
        ~~~~
    	....
        ~~~~
    
        return 0;
    }

     

    간단한 c언어 코드이다.

    어셈블리어로 바꾸어 본다면 main함수에 대한 프롤로그, 에필로그가 생성된다.

     

    PUSH rbp
    mov rbp, rsp
    ~~~~
    ....
    ~~~~
    mov eax, 0
    pop rbp
    ret

     

    모든 함수에 대해 프롤로그, 에필로그가 생성이 되고 함수 내 코드에 따라 프롤로그, 에필로그사이에 있는 어셈블리어 코드들도 달라진다.

     

    이렇게 함수의 시작과 끝이 생성이 되면 다음으로는 main 함수 내에 있는 인자 값인 argc, argv에 대한 어셈블리어가 에필로그 다음으로 붙는다.

     

    PUSH rbp
    mov rbp, rsp
    DWORD PTR [rbp-4], edi  //main함수 인자인 int argc
    QWORD PTR [rbp-16], rsi //main함수 인자인 char* argv[]
    ~~~~
    ....
    ~~~~
    mov eax, 0
    pop rbp
    ret

     

    이번에는 위 코드에 간단한 덧셈을 추가해보았다.

     

    #include <stdio.h>
    
    int main(int argc, char* argv[]){
        int a = 1;
        int b = 2;
        printf("a+b = %d", a+b);
        return 0;
    }

     

    main 함수 내에 변수 a와 b가 선언이 되고 a+b값이 출력이 되는 코드이다.

     

    .LC0:
            .string "a+b = %d"
    main:
            push    rbp
            mov     rbp, rsp
            sub     rsp, 32
            mov     DWORD PTR [rbp-20], edi //main함수 인자인 int argc
            mov     QWORD PTR [rbp-32], rsi //main함수 인자인 char* argv[]
            mov     DWORD PTR [rbp-4], 1 //변수 a의 값
            mov     DWORD PTR [rbp-8], 2 //변수 b의 값
            mov     edx, DWORD PTR [rbp-4] // 덧셈을 하기 위해 a의 값을 edx로 이동
            mov     eax, DWORD PTR [rbp-8] // 덧셈을 하기 위해 b의 값을 eax로 이동
            add     eax, edx //a+b
            mov     esi, eax //a+b를 한 값을 esi로 이동
            mov     edi, OFFSET FLAT:.LC0 //printf함수의 첫 인자값
            mov     eax, 0 //eax 레지스터 초기화
            call    printf //printf 함수 call
            mov     eax, 0 //eax 레지스터 초기화
            leave
            ret

     

    어셈블리어로 변환이 되면 이렇다.

    새로운 코드들이 추가가 되었고,  main 함수에 인자 값이었던 argc, argv[]가 저장되는 주솟값이 변화된 것을 볼 수 있다.

     

    rbp-32 //argv[] 8byte
    rbp-20 //argc 4byte
    rbp-8 //b의 값:2
    rbp-4 //a의 값:1
    rbp

     

    스택에는 값이 이렇게 들어가 있을 것이다.

     

     

    +)

    왜 먼저 넣는 argc, argv이 뒤쪽 주소(낮은 값)에 들어가고 a, b 의 값이 앞쪽 주소(높은 값)에 들어가는지 순간 헷갈렸었다.

    어셈블리어 코드에서 sub rsp, 32를 해줬으니 일단은 rbp에서 32크기가 생겼을 것이고, 그 사이에 공간에 스택 쌓이는 순서는 매개변수 > 반환 주소값 > 지역변수 이여서 그런것이라 이해를 했다.

     
    ++)
    공간을 먼저 확보하고 넣어야하는 순서에 맞게 넣는 것이라면 스택에 넣는 값의 크기를 늘려 덮어 쓰는것이 가능한가?

    'Rev' 카테고리의 다른 글

    리버싱 핵심 원리 (인라인 패치)  (0) 2023.07.29
    모르는 어셈블리어 정리 (repne scasb)  (0) 2023.07.19
    모르는 어셈블리어 정리 (cdq)  (0) 2023.07.09
Designed by Tistory.