linux asm x86生产段错误
我正在学习一些linux的汇编程序,我有这个示例程序只是应该调用write syscall并在屏幕上打印'Hello,World!',但它会产生段错误。我在空闲时间学习,而不是作业,我不再去学校!linux asm x86生产段错误
任何人都可以看到这个代码有什么问题吗?
xor eax,eax
xor ebx,ebx
xor ecx,ecx
xor edx,edx
jmp short string
code:
pop ecx
mov bl,1
mov dl,13
mov al,4
int 0x80
dec bl
mov al,1
int 0x80
string:
call code
db 'Hello, World!'
我不是很熟悉Linux组件,但这里有一个猜测:
当调用的API,你必须使用一个特定调用约定。由约定指定的其中一项是通过API调用保留的寄存器列表。在你的情况下,错误是使用dec bl
而不是xor ebx, ebx
。因为bl
被用作输入参数,所以它不太可能被保留。对于mov al, 1
也是一样,写得更安全mov eax, 1
而且我同意@Greg Hewgil,你获得字符串地址的方式很不寻常。用字符串写位置无关代码的常用方法是:
...
call my_print
db 'hello world!', 0
...
my_print:
pop ecx
xor edx, edx
lp:
cmp byte [ecx + edx], 0
inc edx
jne lp
lea eax, [ecx + edx]
push eax // return address
dec edx
mov eax, 4
int 0x80
ret
您的“常用”方式与OP没有特别的不同。你仍然在做数据前的'jmp',然后做一个'call',最后做一个'pop'来获取数据的地址到一个寄存器中。唯一的区别就是在完成之后你如何使用寄存器。 – 2010-12-16 00:03:34
@Evan Teran:区别在于字符串出现在使用它的地方,并且长度是自动计算的。 – ruslik 2010-12-16 00:05:45
我几乎无法调用一个搜索“'\'自动”的循环。 – 2010-12-16 07:04:04
如果编译并在64位内核下运行,此代码可能会崩溃。 64位返回地址不适合32位ecx寄存器,您将不得不弹出rcx。此外,此代码使用32位API,可能在64位内核下不可用。您应该使用64位API,如我的博客文章中所述:x86-64 assembly on Linux。
适合我。这是我做了(注意,我是一个64位的机器上,所以我有一个额外的标志来创建一个32位二进制):
TEST.ASM
_start:
xor eax,eax
xor ebx,ebx
xor ecx,ecx
xor edx,edx
jmp short string
code:
pop ecx
mov bl,1
mov dl,13
mov al,4
int 0x80
dec bl
mov al,1
int 0x80
string:
call code
db 'Hello, World!'
命令:
$ nasm -felf test.asm -o test.o
$ gcc -m32 -nostdlib -nostdinc test.o -o test
哪些产生了警告,但没关系。
/usr/lib/gcc/x86_64-pc-linux-gnu/4.5.1/../../../../x86_64-pc-linux-gnu/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000008048080
然后我跑:
$ ./test
,它确实输出"Hello, World!"
(不换行)。没有段错误。
看起来就是这个问题。 – ruslik 2010-12-16 00:13:17
我必须说,这是一种非常不寻常的将字符串地址加载到'ecx'中的方法。 – 2010-12-15 22:28:55
它是否会产生输出,然后是段错误,还是在分段之前不产生输出? – 2010-12-15 23:29:57
@Greg:同意了,尽管它是编写位置独立shellcode最常用的方法之一...... – 2010-12-15 23:52:16