농소

asm 지역변수 배열, main 함수의 인자 int argc, char *argv[ ] 본문

Security/System Hacking

asm 지역변수 배열, main 함수의 인자 int argc, char *argv[ ]

농소 2018. 1. 24. 03:48

asm 지역변수 배열활용


이번에  asm에서 배열을 지역변수로 나타내려면 어떻게 표현해야 하는지 알아보자




스택이 쌓일 수록 메모리주소값은 작아지는데 배열도 마찬가지로

첫주소가 다음주소보다 높다는 생각을 할 수도 있다.

하지만 배열같은경우 c에서 처럼 낮은 주소부높은 주소로 표현된다.

즉, 배열의 시작주소는 지정된 크기중 가장 낮은 주소에 위치한다.



우선 이전에 했던 입력한 문자열을 반대로 출력하는 코드를 지역변수로 변환해서 asm으로 작성해보겠다.


C 언어

int main()

{


  char buffer[1024] = {0,};

  int len =0;


  printf("input: ");

  gets( buffer );


  while(buffer[len] !=0) {

len++

  }

  len--;


  while( len >= 0) {

printf("%c", buffer[len]);

len--;

}

printf("\n");


return 0;

}



ASM

extern printf

extern gets


segment .data

msg     db      'input: ', 00

output  db      '%c', 10, 00

newline db      10, 00


segment .text

global  main


main:

        push    ebp

        mov     ebp,    esp    // prologue

        sub     esp,    1028    // 지역변수 크기 할당


        mov     ecx,    256

        xor     eax,    eax

        lea     edi,    [ebp-1024]  

        rep     stosd                    // 배열에 전부 0으로 초기화


        mov     dword [ebp-1028],       0


        push    msg

        call    printf

        add     esp,    4


        lea     eax,    [ebp-1024]

        push    eax

        call    gets

        add     esp,    4


while1: // 문자열의 길이 확인

        mov     eax,    dword [ebp-1028]

        cmp     byte [ebp - 1024 + eax * 1],    0    // 1바이트씩 읽어서 비교

        je      .end


        inc     dword [ebp-1028]

        jmp     while1


.end:

        dec     dword [ebp-1028]


while2:

        mov     eax,    dword [ebp-1028]

        cmp     eax,    0

        jl      .end


        movzx   ebx,    byte [ebp - 1024 + eax * 1] 

        push    ebx

        push    output

        call    printf     // 1바이트씩 읽어서 출력

        add     esp,    8


        dec     dword [ebp-1028]

        jmp     while2


.end:

        push    newline

        call    printf

        add     esp,    4


        xor     eax,    eax // return 0


   leave

   ret





main 함수의 인자




c 표준 main 인자


int main( );

int main( int argc, char *argv[ ] );


표준이 아닌 void main(void)도 많이 사용하긴 하는데

이 경우 컴파일러가 알아서 해석해서 return 처리를 해준다.


우선 c에서 이 인자들이 어떻게 동작하는지 알아보자.


int main( int argc, char *argv[] )

{

   printf("argc: %d\n", argc);  // 인자의 개수, 최소는 arg1, null 이다


   printf("argv: 0x%08x\n", argv);  // 주소


   printf("*argv: 0x%08x\n", *argv);  // 주소의 메모리 호출 거기에도 주소가 들어있음.


   printf("*argv[]: %c\n", **argv);  // 메모리의 첫번째 문자


   printf("*argv[]: %s\n", argv[0]); // 첫번째 인자의 메모리. 문자열을 출력한다


   printf("%s\n", argv[1]);  // 두번째 인자의 문자열을 호출


   return 0;

}



인자 하나만 넣고 실행 했을때와 두개를 넣었을 때 실행한 결과를 보면




인자가 abc가 추가됨에 따라 arg count가 1증가하였고 argv[1] 이 null에서 abc로 출력되었다.



자 이제 asm에서 메인 함수 인자들이 어떻게 표현되는지 알아본다



argc, *argv[ ]는 스택 메모리 영역중에 메인보다 상위부분 ebp + 8, ebp +12에 위치해 있다.


extern printf


segment .data

prompt_hex      db      'address: 0x%08x', 10, 00

prompt_chr      db      'memory: %c', 10, 00

prompt_int      db      'argc: %d', 10, 00

prompt_str      db      'memory: %s', 10, 00


segment .text

global  main


main:

        push    ebp

        mov     ebp,    esp       // prologue



        push    dword [ebp+8]

        push    prompt_int

        call    printf                 // argc

        add     esp,    8


        lea     eax,    [ebp+12]

        push    eax

        push    prompt_hex      

        call    printf                  // esp address

        add     esp,    8


        mov     eax,    [ebp+12]

        push    eax

        push    prompt_hex

        call    printf                   // *argv[] address

        add     esp,    8


        mov     eax,    [ebp+12]

        mov     ebx,    [eax]

        push    ebx

        push    prompt_hex

        call    printf                    // argv[] address

        add     esp,    8


        mov     eax,    [ebp+12]

        mov     ebx,    [eax]

        mov     ecx,    [ebx]

        push    ecx

        push    prompt_chr

        call    printf                     // argv memory 첫 문자 출력

        add     esp,    8


        mov     eax,    [ebp+12]

        mov     ebx,    [eax]

        push    ebx

        push    prompt_str            // argv[] address 문자열출력

        call    printf

        add     esp,    8


        mov     eax,    [ebp+12]

        mov     ebx,    [eax+4]  // 두번째 인자 위치로 이동

        push    ebx

        push    prompt_str

        call    printf                // 두번째 인자 문자열 출력

        add     esp,    8


        leave            // epilogue

        ret



위와 동일하게 인자 하나만 넣고 실행 했을때와 두개를 넣었을 때 실행한 결과를 보면




인자가 abc가 추가됨에 따라 arg count가 1증가하였고 argv[1] 이 null에서 abc로 출력되었다.




[실습]


  - 두번째 인자값을 출력

  - %s로 출력하지말고 반복문을 이용하여 %c로 출력하시오


extern printf


segment .data

prompt_chr      db      'memory: %c', 10, 00

prompt_int      db      'argc: %d', 10, 00

prompt_str      db      'memory: %s', 10, 00


segment .text

global  main


main:

        push    ebp

        mov     ebp,    esp  // prologue

        sub     esp,    4  // len 지역변수 메모리 확보


        mov     dword [ebp-4],  0



        push    dword [ebp+8]

        push    prompt_int

        call    printf                // argc 출력

        add     esp,    8 


        mov     eax,    [ebp+12]

        mov     ebx,    [eax]

        push    ebx

        push    prompt_str        // 첫번째 인자 문자열 출력

        call    printf

        add     esp,    8


        mov     eax,    [ebp+12]

        mov     ebx,    [eax+4]

        push    ebx

        push    prompt_str   // 두번째인자 문자열 출력

        call    printf

        add     esp,    8


while:

        mov     eax,    dword [ebp-4]

        cmp     eax,    0            // null이 나올때 까지 반복문 진행

        je      .end


        mov     ebx,    [ebp+12]

        mov     ecx,    [ebx+4]

        mov     edx,    [ecx + eax * 1]  // 1바이트씩 읽어들임


        push    edx

        push    prompt_chr        // 1바이트씩 문자 출력

        call    printf

        add     esp,    8


        inc     dword [ebp-4]

        jmp     while


.end:

        leave        // epilogue

        ret




'Security > System Hacking' 카테고리의 다른 글

디버거 GDB 사용법  (0) 2018.01.26
시스템 프로그래밍, 시스템 콜  (0) 2018.01.25
프로세스 메모리 구조, 스택 레지스터, 함수  (0) 2018.01.23
nasm 반복문 연습2  (0) 2018.01.20
nasm 반복문 연습  (0) 2018.01.19