시스템 콜 실습 ( mymkdir, mycat, myshell )에 대해서 정리한다.
[실습]
1. mymkdir ( mkdir 명령 )
- 프로그램 실행 결과
#> ./mymkdir
path: mydir
success mkdir
#> ./mymkdir
path: mydir
fail mkdir
- system call: read, write, mkdir
* 프로그램 작성시 고려해야 하는 부분
! read 시스템 콜은 뉴라인까지 입력을 받는다.
! read 시스템 콜은 읽어들인 문자열의 길이를 반환한다.
! 메모리는 지역변수만 사용
! 다른 C 표준 함수는 사용하지 않는다.
[ C언어 코드 ]
int main()
{
char path[1024];
int len = 0;
int ret = 0;
write( 1, "path: ", 6 );
len = read( 0, path, 1024 );
path[len-1] = 0;
ret = mkdir( path, 0755 );
if( ret != 0 ) {
write( 1, "failed\n", 8 );
}else {
write( 1, "success\n", 8 );
}
return 0;
}
[ 어셈블리 코드 ]
section .data
path db 'path: ', 00
print_success db 'success', 10, 00
print_failed db 'failed', 10, 00
section .text
global _start
_start:
push ebp
mov ebp, esp ; prologue
sub esp, 1032
mov dword [ebp-1028], 0 ; int len = 0;
mov dword [ebp-1032], 0 ; int ret = 0;
; write system call
mov eax, 4
mov ebx, 1
mov ecx, path
mov edx, 6
int 80h
; read system call
mov eax, 3
mov ebx, 0
lea ecx, [ebp-1024]
mov edx, 1024
int 80h
mov dword [ebp-1024+eax-1], 0 ; path[len-1] = 0;
; mkdir system call
mov eax, 39
lea ebx, [ebp-1024]
mov ecx, 0755q
int 80h
cmp eax, 0
jz success
; print failed
mov eax, 4
mov ebx, 1
mov ecx, print_failed
mov edx, 7
int 80h
jmp end
success:
; print success
mov eax, 4
mov ebx, 1
mov ecx, print_success
mov edx, 8
int 80h
end:
; exit system call
mov eax, 1
mov ebx, 0
int 80h
( mymkdir 프로그램을 실행해서 디렉터리를 생성해보면 정상적으로 생성이 되고
디렉터리 이름이 중복 되었을 경우에는 failed가 출력 되면서 생성이 되지 않는걸 확인할 수 있다 )
( 실행 권한 또한 mkdir system call 인자에서 0755로 주었기 때문에 rwxr-xr-x의 권한으로 디렉터리가 생성이 되었다 )
2. mycat ( cat 명령 )
- 프로그램 실행 결과
#> ./mycat
file: /etc/passwd
...
- system call: open,read, write
* 프로그램 작성시 고려해야 하는 부분
!! read의 3번째 인자만큼 파일의 내용을 읽어오게 된다.
!! buffer보다 적게 읽어오면 마지막라인
!! open 시스템 콜에서 세번째 인자에 O_RDONLY는 번호로 0을 사용한다.
( 해당 인자를 입력 받을때 자료형이 int이다 )
!! 어셈블리에서 메모리 초기화는 rep stosd 명령어를 이용한다.
[ C언어 코드 ]
int main()
{
char path[1024] = {0,};
char buffer[1024] = {0,};
int len = 0;
int ret = 0;
int fd = 0;
write(1, "file path: ", 11);
len = read(0, path, 1024);
path[len-1] = 0;
fd = open( path, 0 );
while( (ret = read( fd, buffer, 400 )) != 0) {
write( 1, buffer, 1024 );
memset( buffer, 0, 1024 );
}
return 0;
}
[ 어셈블리 코드 ]
section .data
file db 'file: ', 00
sectin .text
global _start
_start:
push ebp
mov ebp, esp
sub esp, 2060
mov dword [ebp-2052], 0 ; int len = 0;
mov dword [ebp-2056], 0 ; int ret = 0;
mov dword [ebp-2060], 0 ; int fd = 0;
; write system call
mov eax, 4
mov ebx, 1
mov ecx, file
mov edx, 6
int 80h
; read system call
mov eax, 3
mov ebx, 0
lea ecx, [ebp-1024]
mov edx, 1024
int 80h
mov dword [ebp-2052], eax ; len = read(0, path, 1024);
mov ebx, dword [ebp-2052]
mov dword [ebp-1024+ebx-1] ; path[len-1] = 0;
; open system call
mov eax, 5
lea ebx, [ebp-1024]
mov ecx, 0 ; O_RDONLY( 0 )
int 80h
mov dword [ebp-2060], eax ; fd = open( path, 0 );
while:
mov ecx, 256
mov eax, 0
lea edi, [ebp-2048]
rep stosd ; initialize the array
;read system call
mov eax, 3
mov ebx, dword [ebp-2060]
lea ecx, [ebp-2048]
mov edx, 400
int 80h
cmp eax, 0
jz while_end
; write system call
mov eax, 4
mov ebx, 1
lea ecx, [ebp-2048]
mov edx, 400
int 80h
jmp while
while_end:
; exit system call
mov eax, 1
mov eax, 0
int 80h
rep stosd 코드 ( 배열 초기화 예시 코드 )
- 해당 코드를 실행 해보면 rep stosd를 어떻게 사용이 되는지 이해하기 쉽다.
section .data
file db 'file: ', 00
section .text
global _start
_start:
push ebp
mov ebp, esp
sub esp, 1024
mov ecx, 256
mov eax, 41414141h
lea edi, [ebp-1024]
rep stosd
mov eax, 4
mov ebx, 1
lea ecx, [ebp-1024]
mov edx, 1024
int 80h
( mycat 프로그램을 실행하게 되면 cat 명령을 실행할 경로를 절대경로로 입력 받게 된다.
여기서는 사용자 정보가 들어있는 /etc/passwd를 입력했다. )
( 출력된 결과가 많아서 한 화면에 다 나오지 않았지만 마지막 사용자인 squid까지 모두 출력이 되었다. )
3. myshell ( shell 만들기 )
- 프로그램 실행 결과
#> ./myshell
cmd: /bin/ls
...
- system call: read, write, execve
[예시 코드]
int main()
{
char *shell[2] = {0,};
shell[0] = "/bin/ls";
shell[1] = 0;
execve( shell[0], shell, 0 );
return 0;
}
[C언어 코드]
int main()
{
char cmd[1024] = {0,};
char *shell[2] = {0,};
int len = 0;
int ret = 0;
write(1, "cmd: ", 5);
len = read(0, cmd, 1024);
cmd[len-1] = 0;
shell[0] = cmd;
shell[1] = 0;
execve( shell[0], shell, 0 );
return 0;
}
[ 어셈블리 코드 ]
section .data
print_cmd db 'cmd: ', 00
section .text
global _start
_start:
push ebp
mov ebp, esp ; prologue
sub esp, 1040
mov ecx, 256
mov eax, 0
lea edi, [ebp-1024] ; char cmd[1024] = {0,};
rep stosd
mov dword [ebp-1028], 0
mov dword [ebp-1032], 0 ; char *shell[2] = {0,};
mov dword [ebp-1036], 0 ; int len = 0;
mov dword [ebp-1040], 0 ; int ret = 0;
; write system call
mov eax, 4
mov ebx, 1
mov ecx, print_cmd
mov edx, 5
int 80h
; read system call
mov eax, 3
mov ebx, 0
lea ecx, [ebp-1024]
mov edx, 1024
int 80h
mov dword [ebp-1036], eax ; len = read(0, path, 1024);
mov ebx, dword [ebp-1036]
lea eax, [ebp-1024+ebx-1]
mov byte [eax] , 0 ; path[len-1] = 0;
lea eax, [ebp-1024]
mov dword [ebp-1032], eax ; shell[0] = cmd;
mov dword [ebp-1028], 0 ; shell[1] = 0;
; execve system call
mov eax, 11
mov ebx [ebp-1032]
lea ecx, [ebp-1032]
mov edx, 0
int 80h
; exit system call
mov eax, 1
mov ebx, 0
int 80h
( myshell 프로그램을 실행하면 명령어 절대 경로를 입력 받게 되고 /bin/ls를 입력한 결과
해당 디렉터리에서 ls 명령어가 실행되 파일과 디렉터리 목록이 보이게 된다 )
!! execve는 path를 확인하지 않기 때문에 명령어를 실행하려면 절대경로를 입력해줘야 한다.
'프로그래밍 > SYSTEM HACKING' 카테고리의 다른 글
[SYSTEM HACKING] GDB를 이용한 바이너리 분석 실습 (0) | 2017.11.13 |
---|---|
[SYSTEM HACKING] 디버거(DeBugger) 사용법( GDB ) / 바이트 오더( byte order ) (0) | 2017.11.13 |
[SYSTEM HACKING] main 함수의 인자 / 시스템 프로그래밍( 시스템 콜 ) (0) | 2017.11.01 |
[SYSTEM HACKING] 어셈블리 call & jmp 명령의 차이 / 스택 메모리를 이용한 인자 전달 / reverse.asm 지역변수 사용해서 표현하는 실습 (2) | 2017.11.01 |
[SYSTEM HACKING] 실행중인 프로세스의 전체 메모리 구조 / 스택에서 사용되는 레지스터 / 어셈블리에서 함수 (0) | 2017.10.26 |
댓글