2012-02-18 10 views
3

asm_execve.s:sys_execveシステムコール

 
.section .data 
file_to_run: 
.ascii  "/bin/sh" 

.section .text 
.globl main 

main: 
    pushl %ebp 
    movl %esp, %ebp 
    subl $0x8, %esp   # array of two pointers. array[0] = file_to_run array[1] = 0 

    movl file_to_run, %edi 
    movl %edi, -0x4(%ebp) 
    movl $0, -0x8(%ebp) 

    movl $11, %eax      # sys_execve 
    movl file_to_run, %ebx    # file to execute  
    leal -4(%ebp), %ecx     # command line parameters 
    movl $0, %edx      # environment block 
    int $0x80    

    leave 
    ret 

メイク:

 
NAME = asm_execve 
$(NAME) : $(NAME).s 
    gcc -o $(NAME) $(NAME).s 

プログラムが実行されますが、sys_execveと呼ばれていません。

 
[email protected]:~/project$ make 
gcc -o asm_execve asm_execve.s 
[email protected]:~/project$ ./asm_execve 
[email protected]:~/project$ 

期待出力は次のとおりです。

 
[email protected]:~/project$ ./asm_execve 
$ exit 
[email protected]:~/project$ 

このアセンブリプログラムは、次のCコードのように動作することになっている:システムコールのパラメータで間違っ

 
char *data[2]; 
data[0] = "/bin/sh"; 
data[1] = NULL; 
execve(data[0], data, NULL); 

何か?

+0

'strace -e execve'を使ってあなたのプログラム*が実際に作るexecve呼び出しをトレースします。 –

答えて

8

execveシステムコールは、と呼ばれていますが、実際には悪いパラメータを渡しています。

(あなたは straceを使用して、実行可能ファイルを実行することで、これを見ることができます。)三つの問題があります

  1. .asciiは、文字列を0、終了しません。 (この例の.dataセクションにはそれに続くものはないので、運が良かったかもしれませんが、保証されません...)0を追加するか、代わりに.asciz(または.string)を使用してください。

  2. movl file_to_run, %edi%edifile_to_runシンボルによってが指す値は、文字列(0x6e69622f)の、すなわち最初の4つのバイトを移動させます。文字列のアドレスはシンボル自体の値にすぎないので、movl $file_to_run, %ediの文字列には$の接頭辞を使用する必要があります。同様に、あなたはmovl $file_to_run, %ebxと言います。 (これはAT & T構文とIntel構文との混同の共通のソースです!)

  3. パラメータが間違った順序でスタックに配置されている:-0x8(%ebp)-0x4(%ebp)よりも下位アドレスです。したがって、コマンド文字列のアドレスは-0x8(%ebp)に、0は-0x4(%ebp)に、leal命令はleal -8(%ebp), %ecxにそれぞれ書き込まれます。


固定コード:

.section .data 
file_to_run: 
.asciz  "/bin/sh" 

.section .text 
.globl main 

main: 
    pushl %ebp 
    movl %esp, %ebp 
    subl $0x8, %esp   # array of two pointers. array[0] = file_to_run array[1] = 0 

    movl $file_to_run, %edi 
    movl %edi, -0x8(%ebp) 
    movl $0, -0x4(%ebp) 

    movl $11, %eax      # sys_execve 
    movl $file_to_run, %ebx    # file to execute  
    leal -8(%ebp), %ecx     # command line parameters 
    movl $0, %edx      # environment block 
    int $0x80    

    leave 
    ret 
+0

ポータブルではない拡張機能として、Linuxでは 'argv'や' envp'を実際に* NULLにすることができます(あなたがenvpのようにしています)ので、 'xor%ecx、%ecx'; 'xor%edx、%edx'です。スタック上に 'argv []'を作るもっと簡単な方法は 'mov $ file_to_run、%ebx'です。 'push $ 0'(またはゼロ化されたreg); 'push%ebx'; 'mov%esp、%ecx'です。 –

1

あなたが実際に他の引数に何をロードする必要はありません。あなたは、x86でこれをやっている場合は、次の単純なコードも動作します:

.global _main 
.section .text 

.data 
file_to_run: 
.asciz "/bin/sh" 

.section .text 
.globl main 

_main: 
pushl %ebp 
movl %esp, %ebp 

movl $11, %eax      # sys_execve 
movl $file_to_run, %ebx    # file to execute  
movl $0, %ecx      # Null value will work too 
movl $0, %edx      # Null will works too 
int $0x80    

leave 
ret 

これは本質的にシステムコールを呼び出した後、シェルターミナルを開きます。

+0

レジスタをゼロにするには 'xor%ecx、%ecx'を使うべきです。ゼロ以外のゴミを渡すことは確実ですか? '0'(または有効なポインタ)以外のものはシステムコールを' -EFAULT'に戻さなければなりません。 'argv'と' envp'のNULLポインタはLinux固有の動作(http://man7.org/linux/man-pages/man2/execve.2.html)として特別に文書化されており、*ポインタを渡すのと同じです* NULLポインタ。しかし、それは他の悪いポインターが "うまくいく"ことを意味するものではありません。これは実際には実装にバグがあり、0以外の悪いポインタで '-EFAULT'を返す代わりに何かを実行した場合 –

+0

はい正しいです。そのことについて謝ります。私は基本的には、あなたが端末を開こうとするならば、あなたは特定の議論をする必要はなく、あなたがヌル値を与えてもそれは動作することを意味します。 – Shank

+1

これは本当にテストしましたか? '$ file_to_run'が必要です。それ以外の場合は、文字列の最初の4バイトをロードしてポインタとして渡しているだけです。また、 'ebp'を保存/復元しますが、コードは' ebx'をクローバーします。 'execve'がexecの代わりにエラーを返すときにクラッシュするのではなく、安全に戻りたいなら、スタックフレームを作るのではなく、ebxを' push/pop'する必要があります。 (おそらく、CRBコードはebxを壊しても問題ありません)オプションの改良:あなたの文字列は '.rodata'に入るので、' .data'セクションは必要ありません。 '.asciiz'を使ってゼロ終端文字列を得ることができます。 –

関連する問題