从X86-64组件(NASM)执行系统命令一般结构? [英] General structure for executing system commands from x86-64 assembly (NASM)?

查看:174
本文介绍了从X86-64组件(NASM)执行系统命令一般结构?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图做一些基本的系统组装调用(X86-64在NASM在OSX),但至今没有成功。

我看到在网络上的唯一例子,到目前为止是从标准输入读取或写入到stdout,像这样的:

 全球主要
.text段主要:
  调用write写:
  MOV RAX,0x2000004
  MOV RDI,1
  MOV RSI,消息
  MOV RDX,长度
  系统调用段.data
消息:DB'!你好,世界为0xA
长度:EQU $ - 消息

然而,当我尝试使用相同的模式,使其他系统调用,这是行不通的(它说总线错误:10

 全球主要
.text段主要:
  打电话的mkdirMKDIR:
  MOV RAX,0x2000136; MKDIR系统命令数
  MOV RDI,RAX;点目标系统的命令
  MOV RSI,目录;第一个参数
  MOV RDX,755;第二个参数
  系统调用段.data
目录:DBTMP,为0xA

什么是总体结构调用系统命令(在OSX在NASM理想情况下)?

基本上它似乎像你应该做的是找到你想要的系统调用在此处的http://www.opensource.apple.com/source/xnu/xnu-1504.3.12/bsd/kern/syscalls.master.所以,写一个看起来是这样的:

  4 AUE_NULL ALL {user_ssize_t写(INT FD,user_addr_t CBUF,user_size_t nbyte); }

这是在说:


  • 系统调用号:4

  • 参数的数目:3(文件描述符,内存地址串/缓冲区,缓冲区的长度)

于是,我开始认为的一般模式是这样的:

  RAX:系统调用号
RDI:可能?点系统调用(目标索引),但在写的例子,为什么`1`?
RSI:第一个参数的系统调用(源索引,在这种情况下,字符串)
RDX:第二个参数的系统调用
RCX:第三个参数(如果有必要的,但不是在系统写的情况下)

于是它就像你可以做任何的系统命令的直接映射。因此,的mkdir

  136 AUE_MKDIR ALL {INT的mkdir(user_addr_t路径,INT模式); }

将被转换为

  RAX:0x20000136; 136 + 20000000
RDI:我不知道,也许`rax`?
RSI:目录(第一个参数)
RDX:755(模式,第二个参数)

但是,是的,那是行不通的。

我是什么做错了吗?什么是如何做到这一点,所以我可以测试它在任何的 syscalls.master中?你能描述一下这里太不同的寄存器中发挥的作用?这将有助于澄清了很多,我认为。


解决方案

您已经得到它几乎是正确:您需要均为0x88(十进制136)的系统调用号。在syscall.master的系统调用是小数。你最后调用GETSID(这是系统调用310)。

有关参数,因为这让你内核的角度来看这是倾斜一点点(当它涉及到参数名),不要使用syscalls.master中。您应该使用/usr/include/unistd.h为原型,并为数字USR / inclunde / SYS / syscall.h。 syscalls.master中派上用场只在系统调用不会导出到这些文件的情况下,和那些情况下,主文件说NO_SYSCALL_STUB。

对于ABI,这是相同的System V的AMD64 ABI。 http://people.freebsd.org/~obrien/amd64-elf-abi .PDF

您可以看到系统调用libSystem中做他们:

  otool -TV /usr/lib/system/libsystem_kernel.dylib |更多
#力求/ ^ _的mkdir:
_mkdir:
0000000000012dfc MOVL $ 0x2000088,EAX%
0000000000012e01 MOVQ%RCX,R10%
0000000000012e04系统调用
0000000000012e06宰0x12e0d
0000000000012e08 jmpq cerror_nocancel
0000000000012e0d RET
0000000000012e0e NOP
0000000000012e0f NOP

所有的系统调用本质上具有以下结构:


  1. 由这点争论一直摆在RDI,RSI,......按照上述
    ABI

  2. 系统调用#加载到EAX。该0X2意味着POSIX
    系统调用。为0x1将是马赫陷阱,0x3中 - 拱具体,为0x4 -
    诊断系统调用

  3. RCX保存到R10

  4. 系统调用被执行

    <<发生内核部分,其中,通过执行陷阱进入内核模式,
            并用于ⅰ)EAX的值到达系统调用表,和ii)支纠正
            系统调用>>


  5. 内核模式返回到用户模式,过去的系统调用指令

  6. EAX现在拥有的系统调用的返回值,所以
    认为宰的意思,如果系统调用返回值> = 0 - 即确定 -
    继续该RET,并返回到用户

  7. 如果没有,跳到
    cerror_nocancel它加载errno的值,并返回-1
    该用户。


I am trying to make some basic system calls in assembly (x86-64 in NASM on OSX), but have so far been unsuccessful.

The only examples I have seen on the web so far are for reading from stdin or writing to stdout, such as this:

global main
section .text

main:
  call write

write:
  mov rax, 0x2000004
  mov rdi, 1
  mov rsi, message
  mov rdx, length
  syscall

section .data
message: db 'Hello, world!', 0xa
length: equ $ - message

However, when I try to use that same pattern to make another system call, it doesn't work (it's saying Bus error: 10):

global main
section .text

main:
  call mkdir

mkdir:
  mov rax, 0x2000136 ; mkdir system command number
  mov rdi, rax ; point destination to system command
  mov rsi, directory ; first argument
  mov rdx, 755 ; second argument
  syscall

section .data
directory: db 'tmp', 0xa

What is the general structure for calling system commands (on OSX in NASM ideally)?

Basically what it seems like you're supposed to do is find your desired system call in here: http://www.opensource.apple.com/source/xnu/xnu-1504.3.12/bsd/kern/syscalls.master. So the "write" one looks like this:

4   AUE_NULL    ALL { user_ssize_t write(int fd, user_addr_t cbuf, user_size_t nbyte); } 

That is saying:

  • system call number: 4
  • number of arguments: 3 (file descriptor, memory address to string/buffer, length of buffer)

So I was beginning to think the general pattern was this:

rax: system call number
rdi: maybe? point to system call ("destination index"), but why the `1` in the write example?
rsi: first argument to system call ("source index", the string in this case)
rdx: second argument to system call
rcx: third argument (if necessary, but not in the system write case)

So then it's like you could do a direct mapping of any of the system commands. So mkdir:

136 AUE_MKDIR ALL { int mkdir(user_addr_t path, int mode); } 

would be translated to:

rax: 0x20000136 ; 136 + 20000000
rdi: i dunno, maybe `rax`?
rsi: directory (first argument)
rdx: 755 (mode, second argument)

But yeah, that doesn't work.

What am I doing wrong? What is the general pattern of how to do this so I can test it out on any of the other system commands in syscalls.master? Can you describe the role the different registers play here too? That would help clarify a lot I think.

解决方案

You've got it almost right: You need 0x88 (dec 136) for the syscall number. The syscalls in syscall.master are in decimal. You ended up calling getsid (which is syscall 310).

For arguments, don't use syscalls.master since that gives you the kernel perspective which is a tad skewed (when it comes to argument names). You should use /usr/include/unistd.h for the prototypes, and usr/inclunde/sys/syscall.h for the numbers. syscalls.master comes in handy only in cases where the syscalls aren't exported to these files, and those are cases where the master files says NO_SYSCALL_STUB.

As for the ABI, it's the same as System V AMD64 ABI. http://people.freebsd.org/~obrien/amd64-elf-abi.pdf

You can see the system calls as libsystem does them:

otool -tV /usr/lib/system/libsystem_kernel.dylib  | more 
# seek to /^_mkdir:
_mkdir:
0000000000012dfc        movl    $0x2000088, %eax
0000000000012e01        movq    %rcx, %r10
0000000000012e04        syscall
0000000000012e06        jae     0x12e0d
0000000000012e08        jmpq    cerror_nocancel
0000000000012e0d        ret
0000000000012e0e        nop
0000000000012e0f        nop

All the system calls essentially have the structure:

  1. Arguments by this point have been put in RDI,RSI,... as per above ABI
  2. The system call # is loaded into EAX. The 0x2 implies POSIX syscall. 0x1 would be a Mach Trap, 0x3 - arch specific, 0x4 - Diagnostic syscalls
  3. rcx saved into r10
  4. syscall gets executed

    << kernel portion occurs, wherein execution goes into kernel mode through trap, and the value of eax is used to i) get to system call table and ii) branch to correct system call >>

    1. kernel mode returns to user mode, past the syscall instruction
    2. EAX now holds the syscall return value, so that "jae" means if the syscall return value is >=0 - i.e. ok - continue to the "ret" and return to the user
    3. if not, jump to cerror_nocancel which loads the value of errno and returns the -1 to the user.

这篇关于从X86-64组件(NASM)执行系统命令一般结构?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆