私はアセンブリで手動のシステムコールで遊んでいます。以前は正しく起動させることができましたが、nullを削除した後、syscallを実行させることができません/bin/date
。これが私がAT&T構文で書いたコードです。
.global main
main:
jmp two
one:
# zero rax and rdx
xor %rax,%rax
mov %rax,%rdx
# save string location
mov (%rsp),%rbx
# push argv array onto the stack
add $16, %rsp
push %rax
push %rbx
# assign argv pointer
mov %rsp,%rcx
# execve call
mov $0xb, %al
int $0x80
# exit on failure
xor %rax,%rax
xor %rbx,%rbx
movb $0x1,%al
int $0x80
two:
# get address of the string
call one
.string "/bin/date"
私が正しい場合は%rbx
、起動するプログラムを指定する文字列を直接指す必要があります。プログラムのを%rcx
表すnullで終了するポインタの配列を指す必要があり、環境を指すので、ここではnullのままにしておきます。そして、もちろん、syscall番号(この場合)を保持します。argv
%rdx
%rax
0x0b
(gdb) info registers
rax 0xb 11
rbx 0x4000a0 4194464
rcx 0x7fffffffe968 140737488349544
rdx 0x0 0
(gdb) x/s $rbx
0x4000a0: "/bin/date"
(gdb) x/s *$rcx
0x4000a0: "/bin/date"
それにもかかわらず、syscallはプログラムを実行せず、-14を返します。これは、 EFAULT
(segfault)に変換されます。何を見落としているのかわかりません。助けていただければ幸いです。
したがって、知覚的な読者は、上記のコードが64ビットシステムで32ビットのsyscall規則(およびfriendsを使用)を使用していることに気付いたかもしれませ%ebx
んint $0x80
。32ビット規則は32ビットコードの実行を有効にするためにのみサポートされているため、これはエラーでした。64ビットシステム用に記述されたコードでは、syscallは、、、、、、および命令%rdi
を使用します。64ビットシステム(nullfree)の修正されたコードは次のとおりです。%rsi
%rdx
%r10
%r8
%r9
syscall
.global main
main:
jmp two
one:
# zero rax and rdx
xor %rax,%rax
mov %rax,%rdx
# save string location, note that %rdi is used instead of %rbx
pop %rdi
# push argv array onto the stack
add $16, %rsp
push %rax
push %rdi
# assign argv pointer, using %rsi instead of %rcx
mov %rsp,%rsi
# execve call, note that the syscall number is different than in 32bit
mov $0x3b, %al
syscall
two:
# get address of the string
call one
.string "/bin/date"
ただし、32ビットのsyscall規則は64ビットシステムでサポートされており(したがって、32ビットの実行可能ファイルを実行できます)、execve
このシステムで32ビットの呼び出し規則を使用して他のコマンドを正常に実行できました。実際、x86_64システムで調べた「シェルコード」の大部分は32ビット規則を使用していました。それで、私の質問はまだ立っています:なぜ32ビットの呼び出し規約が上記のコードで機能しなかったのですか?