从脚本语言调用Linux系统调用


15

我想直接从脚本语言调用Linux syscall(或至少是libc包装器)。我不在乎什么脚本语言-不编译它是很重要的(原因基本上与在依赖路径中不希望使用编译器有关,但这不在这里或那里)。是否有任何脚本语言(shell,Python,Ruby等)允许这样做?

特别是,它是getrandom系统调用。


3
getrandom仅从中提取随机字节/dev/urandom。您当然可以从Shell脚本执行此操作。
史蒂夫(Steve)

@steve确实是这样,除非当然/dev尚不可用。但是很难想象Perl会是!
derobert

至关重要的是,我希望它在初始化熵池之前一直阻塞,而熵池作为文件无法从/ dev / urandom读取。
joshlf

5
从中读取/dev/random直到解除阻止,然后从中读取/dev/urandom
主教

1
“原因基本上与不想在依赖路径中使用编译器有关,但这既不存在也不存在”->嗯?如果您是指运行时依赖项路径,那么无论如何都不会。您不需要C编译器来运行从C编译的二进制文件。如果您表示不想依赖于为目标体系结构编译事物的能力,因为您认为自己没有该能力,那么它就可以了。您不太可能能够在该平台上运行Python,Bash或任何其他实际的脚本语言。
凯文(Kevin)

Answers:


33

Perl允许使用以下syscall功能:

$ perldoc -f syscall
    syscall NUMBER, LIST
            Calls the system call specified as the first element of the list,
            passing the remaining elements as arguments to the system call. If
⋮

该文档还提供了一个调用write(2)的示例:

require 'syscall.ph';        # may need to run h2ph
my $s = "hi there\n";
syscall(SYS_write(), fileno(STDOUT), $s, length $s);

但是不能说我曾经使用过此功能。好吧,在此之前,确认示例确实有效。

这似乎适用于getrandom

$ perl -E 'require "syscall.ph"; $v = " "x8; syscall(SYS_getrandom(), $v, length $v, 0); print $v' | xxd
00000000: 5790 8a6d 714f 8dbe                      W..mqO..

而且,如果您在syscall.ph中没有getrandom,那么您可以使用数字代替。在我的Debian测试(amd64)盒中为318。注意Linux syscall号是特定于体系结构的。


2
Perl-计划B的锤子!
托尔比约恩Ravn的安徒生

28

在Python中,您可以使用该ctypes模块访问动态库中的任意函数,包括syscall()从libc中进行访问:

import ctypes

SYS_getrandom = 318 # You need to check the syscall number for your target architecture

libc = ctypes.CDLL(None)
_getrandom_syscall = libc.syscall
_getrandom_syscall.restypes = ctypes.c_int
_getrandom_syscall.argtypes = ctypes.c_int, ctypes.POINTER(ctypes.c_char), ctypes.c_size_t, ctypes.c_uint

def getrandom(size, flags=0):
    buf = (ctypes.c_char * size)()
    result = _getrandom_syscall(SYS_getrandom, buf, size, flags)
    if result < 0:
        raise OSError(ctypes.get_errno(), 'getrandom() failed')
    return bytes(buf)

如果您的libc包含getrandom()wrapper函数,则也可以调用它:

import ctypes

libc = ctypes.CDLL(None)
_getrandom = libc.getrandom
_getrandom.restypes = ctypes.c_int
_getrandom.argtypes = ctypes.POINTER(ctypes.c_char), ctypes.c_size_t, ctypes.c_uint

def getrandom(size, flags=0):
    buf = (ctypes.c_char * size)()
    result = _getrandom(buf, size, flags)
    if result < 0:
        raise OSError(ctypes.get_errno(), 'getrandom() failed')
    return bytes(buf)

您是否有可能添加getrandom直接调用libc 函数而不是syscall 的示例getrandom?那可能吗?
joshlf

@joshlf当然可以。我编辑了答案。
cg909

您是否知道有没有一种方法可以SYS_getrandom在运行时动态查找正确的值(以便您正确使用当前平台)?例如,通过解析/usr/include头文件?
joshlf

我没有尝试过,但是您可能对pycparser感到幸运。
cg909

17

Ruby具有syscall(num [, args...]) → integer功能。

例如:

irb(main):010:0> syscall 1, 1, "hello\n", 6
hello
=> 6

getrandom()

irb(main):001:0> a = "aaaaaaaa"
=> "aaaaaaaa"
irb(main):002:0> syscall 318,a,8,0
=> 8
irb(main):003:0> a
=> "\x9Cq\xBE\xD6|\x87\u0016\xC6"
irb(main):004:0> 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.