C-> ASM( 기계어 )


1. 시스템 프로그래밍

 

    - 윈도우즈: win API(Advanced Programing Interface)

    - 리눅스: system call



shell (user)

----------------

커널 

----------------

H/w (Device)

사용자가 커널을 통해 장치에 접근한다

인터페이스는 함수형태로 제공 

세개의 개념을 통틀어서 운영체제



! ltrace Vs. strace

 ltrace: 라이브러리 추적 명령어




 strace: 시스템콜 추적 명령어




리눅스 시스템 콜 같은경우 win api와는 다르게 웹상에 공개되어있어 쉽게 찾아볼 수 있다.

주로 이용하는 시스템 콜 참조 사이트


https://syscalls.kernelgrok.com/


write 함수를 살펴보면




2. write system call


1). C 언어

-systemcall과 동일한 래퍼 함수 제공

-fd: 0,1,2


<파일 디스크립터 번호>

할당되있는 파일디스크립터 번호

0 : 표준입력(키보드)

1 : 표준출력(모니터)

2 : 표준에러

(* 3번부터는 실행파일에 파일핸들을 준다.)


printf 대신 write 를 사용한다

#include <stdio.h>

int main()

{

        write(1,"Hello,world\n",13);

        return 0;

}



2). 어셈블리


- 함수 호출을 통한 시스템콜 함수는 사용하지 않는다.

- 인터럽트를 통한 시스템콜 함수를 사용


-하드웨어 인터럽트 (물리적인 인터럽트)

-소프트웨어 인터럽트 

WRITE 함수



_start:

        mov     eax,    0100b //eax 의 역할은 시스템콜의 번호를 저장한다 wirte 시스템콜이 4번이다. 

        mov     ebx,    1d      // fd =1 표준 출력을 의미한다

        mov     ecx,    string  //const char __user *buf

        mov     edx,    20o    // 최대 길이 

        int     80h //int 가 인터럽트고 80은 시스템콜을 의미한다


        차례 대로 쓰는 인자를 레지스터에 넣고 시스템콜을 한다  급한경우는 edi ,esi 까지 사용이 가능하다

        만약 인자가 3개가 넘어가면 스택을 사용한다.




read 함수



       ;read(0,path,1024);

        mov     eax,    3 ;call number 

        mov     ebx,    0 ;fd 값

        lea     ecx,    [ebp-1024] ;user *buf 사용하고자 하는주소

        mov     edx,    1024 ;최대 길이 

        int     80h





OPEN 함수


     ;open

        mov     eax,    5  ;시스템 콜 번호 

        lea     ebx,    [ebp-1024] ; open할 파일 이름

        mov     ecx,    0  ;flags

        mov     edx,    0 ;int mode

        int     80h



execve 함수



[실습]



1). 디렉터리 생성 :makedir


-read, write, mkdir


#> ./mkdir

path: path

success or fail


C언어로 연습


int main()

{

        char path[1024] = {0,};

        int end=0;


        read(0,path,1024);

        while( path[end] != '\n' ){

                end++;

        }


        path[end]=0;


        printf("%s",path);



        return 0;


}



  - read 는 \n까지 읽어들인다

  - read는 읽어들인 문자열의 길이를 반환

  - 메모리는 지역변수만 사용



C언어 


int main()

{

        char path[1024] = {0,}; // [ebp-1024]

        int end=0; // [ebp-1028]

        int result = 0; // [ebp-1032]


        write(1,"input:",7);

        read(0,path,1024);


        while( path[end] != '\n' ){  //마지막 라인을 찾아준다 

                end++;

        }


        path[end]=0;  // 뉴라인을 삭제 


        result=mkdir(path, 0755); // sys_mkdir 0x27(콜번호) const char __user *pathname int mode(권한)

     

       if (result < 0){

                write(1,"failed\n",7);

        } else {

                write(1, "success\n",8);

        }


        return 0;


}



 어셈블리어                                                                                                                                        

segment .data

fail    db      'failed',10,00

success db      'success',10,00

input   db      'input:',00




segment         .text

global  _start


_start:

        push    ebp  ;프롤로그 

        mov     ebp,    esp

        sub     esp,    1032 ;배열 1024 + 변수 2개 (8)   1032


        mov     ecx,    256  ; 배열 초기화 1024/4 256번 반복한다 

        mov     eax,    0

        lea     edi,    [ebp-1024]

rep     stosb                                   ;path 초기화



        mov     dword [ebp-1028],       0       ;end 초기화

        mov     dword [ebp-1032],       0       ;result 초기화


      

  ;write(1,"input:",7);


        mov     eax,    4 ;call number

        mov     ebx,    1 ; 표준 출력

        mov     ecx,    input ; const char __user *buf

        mov     edx,    7 ; 최대 길이

        int     80h ; 시스템콜 


        ;read(0,path,1024);

        mov     eax,    3 ;call number 

        mov     ebx,    0 ;표준 입력 0

        lea     ecx,    [ebp-1024] ;const char __user *buf

        mov     edx,    1024 ;최대 길이 

        int     80h ; 시스템콜 


while:


   lea     eax,    [ebp-1024] ;path start address

        mov     ebx,    [ebp-1028] ;end memory

        cmp     byte [eax+ebx*1],       10 ;new 라인 인지 비교한다 

        je      end ;뉴 라인이면 end로 jmp 하고

        inc     dword [ebp-1028] ;end 값을 하나 늘려서 while 문을 반복한다

        jmp     while


end:

        ;path[end]=0;

        lea     eax,    [ebp-1024]  ;path 시작 위치를 eax에 두고

        mov     ebx,    [ebp-1028] ; [ebp -1028] end 를 ebx에 저장한다

        mov     byte [eax +ebx *1],     0 [eax+ebx *1] 에 0을 저장한다  


        ;result=mkdir(path, 0755);

        mov     eax,    27h ;mkdir 콜 번호

        lea     ebx,    [ebp-1024] // 시작 위치

        mov     ecx,    0755o // 권한 설정 

        int     80h ; 시스템콜 


        mov     dword [ebp-1032],       eax  ; 값을 1032 result 에 저장한다 



      ;if (result < 0){

                ;write(1,"failed\n",7);

        ;} else {

              ;write(1, "success\n",8);

        ;}


if:

        cmp     dword [ebp-1032],       0 ;result 값을 비교하고 

        jge     .else ;크거나 같으면 .else로 이동한다 


        mov     eax,    4 ;write 시스템 콜 번호

        mov     ebx,    1 ;fd 표준 입출력 

        mov     ecx,    fail ; fail 출력 

        mov     edx,    7 ;최대 길이 

        int     80h ; 시스템콜 

        jmp     .end ;분기문



.else:

        mov     eax,    4

        mov     ebx,    1

        mov     ecx,    success

        mov     edx,    8

        int     80h


.end:

        xor     eax,    eax

        leave

        ret



2). 파일 입/출력: mycat

- open, read, wirte


#> ./mycat

input: /etc/passwd

......

read를 한번 쓸때 마다 얼만큼 썼는지 리턴이 될것이다.

open 할때 flag 0번 

  mode 는 0으로 하면된다


C언어 

int main()


{

  char path[1024] = {0,};

  char buffer[1024] = {0,};

  int size = 0;

  int fd = 0;

  int end = 0;



  write( 1, "input: ", 7 );

  read( 0, path, 1024 );


  while( path[end] != '\n' ) {

    end++;

  }

  

path[end] = 0;


  fd = open( path, 0, 0 );

  size = read( fd, buffer, 1024 );



  while(size == 0) {

    write( 1, buffer, 1024 );

    size = read( fd, buffer, 1024 ); 

}


 어셈블리어 

segment .data

input   db      'input: ', 00


segment .text

global  _start


_start:

        push    ebp                ;프롤로그

        mov     ebp,    esp        

        sub     esp,    2060      ;1024+1024+4+4+4 


        mov     ecx,    512       ;2048 을 한번에 초기화 한다

        mov     eax,    0          ; eax에 0을 넣어주고

        lea       edi,    [ebp-2048] ; 배열 시작 위치 

        rep     stosd ; 반복해서 초기화 한다 


        mov     dword [ebp-2052],       0       ; size

        mov     dword [ebp-2056],       0       ; fd

        mov     dword [ebp-2060],       0       ; end


        ;write

        mov     eax,    4        ;시스템콜 번호    

        mov     ebx,    1        ;파일 출력

        mov     ecx,    input   ; *buf

        mov     edx,    7        ;최대 사이즈

        int     80h                ;시스템콜


        ;read

        mov     eax,    3        ;시스템 콜 번호

        mov     ebx,    0        ;파일 입력

        lea     ecx,    [ebp-1024]     ;path 시작 주소

        mov     edx,    1024        ;최대 길이

   int     80h                   ;시스템 콜


while1:


        lea     eax,    [ebp-1024]        ;path 시작 주소 위치

        mov     ebx,    [ebp-2060]      ;end  값 ebx에 저장 

        cmp     byte [eax + ebx * 1],   10 ; eax+ end *1이 뉴라인 인지 비교한다 

        je      .end ; 뉴라인이면 .end로 이동 

        inc     dword [ebp-2060] ; end값을 1씩 증가 해서 while1 반복문 처리한다

        jmp     while1




.end:

;path[end] = 0;


        lea     eax,    [ebp-1024]  ;path 시작위치 주소를 가지고오고

        mov     ebx,    [ebp-2060]  ; end가 뉴라인인 값을 가지고 오고 ebx에 저장한다  

        mov     byte [eax + ebx *1],    0  ; eax+end가 뉴라인 *1 ,0을 대입해준다 



        ;open

        mov     eax,    5                ;시스템 콜번호

        lea     ebx,    [ebp-1024]    ;open할 파일 이름

        mov     ecx,    0                ;flag

        mov     edx,    0                ;open 0

        int     80h                        ; 시스템콜


        mov     dword [ebp-2056],       eax     eax를 fd에 저장 한다 



    ;size = read( fd, buffer, 1024 );

        mov     eax,    3                 ;시스템 콜 번호

        mov     ebx,    [ebp-2056]    ;위에 저장한 fd 번호 [ebp-2056]

        lea     ecx,    [ebp-2048]      ;시작 위치 주소를 가져온다 buffer의 시작 주소

        mov     edx,    1024            ;최대 길이         

        int     80h                         ; 시스템 콜


        mov     dword [ebp-2052],       eax      ;size 에 대입해준다


while2:


        cmp     dword [ebp-2052],       0    ;;size 가 0 즉 남은 내용이 없으면 end로 끝낸다

        je      end ;에필로그 하고 끝낼려고 


        ;write

        mov     eax,    4                ;만약 size가 남았으면 write 해준다 콜번호

        mov     ebx,    1                ;fd 1

        lea     ecx,    [ebp-2048]     ;시작 위치

        mov     edx,    1024           ; 최대 길이

        int     80h                        ; 시스템 콜


        ;read

        mov     eax,    3

        mov     ebx,    [ebp-2056]  ;fd 번호 

        lea     ecx,    [ebp-2048]

        mov     edx,    1024

        int     80h


        mov     dword [ebp-2052],       eax        ;size에 대입해준다

        jmp     while2


end:


        xor     eax,    eax

        leave

   ret



3). 쉘: myshell

- read, execve

-명령어를 입력-> 실행

-execve, read

int execve (const char *filename, char *const argv [], char *const envp[]);


1. 실행할 명령어의 종류

2. 아규먼트(포인터 배열)

3. 환경 변수에 대한 포인터


#include <stdio.h>

int main()
{


        char *argv[2]= {0,}; //[ebp-8]
        char buffer[1024] ={0,};// [ebp-1032]
        int  end =0; // [ebp-1036]

        write(1, "input:", 7);
        read( 0, buffer, 1024);

        while( buffer[end] != '\n') {
         end ++;
        }

        //while (*(buffer+end) != '\n') {
end ++;
        }


        buffer[end] = 0;

        argv[0] = buffer;   // [ebp-8]
        argv[1] = NULL;    // [ebp-4]

        execve( buffer, argv, NULL);

        return 0;

}


1.변수 초기화

        char *argv[2]= {0,}; //[ebp-8]
        char buffer[1024] ={0,};// [ebp-1032]
        int  end =0; // [ebp-1036]


_start:
        push    ebp     
        mov     ebp,    esp     
        sub     esp,    1036

        mov     dword [ebp-4],  0
        mov     dword [epb-8],  0

        mov     ecx,    256
        xor     eax,    eax
        lea     edi,    [ebp-1032]
rep     stosb

        mov     dword [ebp-1036],       0

        
2. write, read

  write(1, "input:", 7);
        read( 0, buffer, 1024);

  
        mov     eax,    4
        mov     ebx,    1
        mov     ecx,    prompt  
        mov     edx,    7
        int     80h


        mov     eax,    3
        mov     ebx,    0
        lea     ecx,    [ebp-1032]
        mov     edx,    1024
        int     80h


3, 뉴라인 제거 
        while( buffer[end] != '\n') {
         end ++;
        }

        //while (*(buffer+end) != '\n') {
end ++;
        }
   buffer[end] = 0;


loop:   

        lea     eax,    [ebp-1032]      ;buffer
        mov     ebx,    [ebp-1036]      ;end
        cmp     byte [eax + ebx * 1], 10
        je      .end
        inc     dword [ebp-1036]
        jmp     loop
.end:   
        lea     eax,    [ebp-1032]
        mov     ebx,    [ebp-1036]
        mov     byte [eax + ebx *1], 0


4.

lea     eax,    [ebp-1032]
        mov     dword [ebp-8],  eax
        mov     dword [ebp-4],  0

        mov     eax,    11
        lea     ebx,    [ebp-1032]
        lea     ecx,    [ebp-8]
        mov     edx,    0
        int     80h

        xor     eax,    eax

        leave
        ret


+ Recent posts