Wywołaj wywołanie systemowe Linux z języka skryptowego

15

Chcę wywołać wywołanie systemowe Linux (lub przynajmniej opakowanie libc) bezpośrednio z języka skryptowego. Nie obchodzi mnie, jaki język skryptowy - ważne jest, aby nie był on kompilowany (powodem jest w zasadzie to, że nie chcę kompilatora na ścieżce zależności, ale nie ma go tu ani tam). Czy są na to języki skryptowe (shell, Python, Ruby itp.)?

W szczególności jest to wywołanie systemowe getrandom.

joshlf
źródło
3
getrandom po prostu pobiera losowe bajty z /dev/urandom. Z pewnością możesz to zrobić ze skryptu powłoki.
Steve
@steve rzeczywiście, chyba że oczywiście /devnie jest jeszcze dostępne. Ale trudno sobie wyobrazić, że Perl byłby!
derobert
Krytycznie chcę, aby to blokowało, dopóki pula entropii nie zostanie zainicjowana, czego nie robi odczyt z / dev / urandom jako pliku.
joshlf
5
Czytać od, /dev/randomaż się odblokuje, a potem czytać /dev/urandom?
biskup
1
„powodem jest zasadniczo to, że nie chcemy kompilatora na ścieżce zależności, ale to nie jest ani tu, ani tam” -> Huh? Jeśli masz na myśli ścieżkę zależności środowiska wykonawczego , w żadnym wypadku nie będziesz. Nie potrzebujesz kompilatora C, aby uruchomić plik binarny skompilowany z C. Jeśli masz na myśli, że nie chcesz polegać na zdolności kompilacji dla docelowej architektury, ponieważ uważasz, że nie będziesz miał takiej możliwości, to jest mało prawdopodobne, abyś mógł uruchomić Python, Bash lub inny prawdziwy język skryptowy na tej platformie.
Kevin

Odpowiedzi:

33

Perl pozwala na to ze swoją syscallfunkcją:

$ 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
⋮

Dokumentacja podaje również przykład wywołania write (2):

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

Nie mogę powiedzieć, że kiedykolwiek korzystałem z tej funkcji. Cóż, przed chwilą, aby potwierdzić, że przykład rzeczywiście działa.

Wygląda na to, że działa z 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..

A jeśli nie masz getrandom w syscall.ph, możesz zamiast tego użyć numeru. Jest 318 na moim pudełku testowym Debiana (amd64). Uważaj, że numery systemowe Linuksa są specyficzne dla architektury.

derobert
źródło
2
Perl - młot planu B!
Thorbjørn Ravn Andersen
28

W Pythonie możesz używać ctypesmodułu do uzyskiwania dostępu do dowolnych funkcji w bibliotekach dynamicznych, w tymsyscall() z 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)

Jeśli twoja biblioteka libc zawiera funkcję getrandom()otoki, możesz ją również wywołać:

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)
cg909
źródło
Czy jest szansa, że ​​możesz dodać przykład wywołania getrandomfunkcji libc bezpośrednio zamiast wywołania systemowego getrandom? Czy to jest możliwe?
joshlf
@joshlf Oczywiście, że to możliwe. Zredagowałem swoją odpowiedź.
cg909
Czy wiesz, czy istnieje sposób, aby dynamicznie sprawdzić poprawną wartość SYS_getrandomwartości w czasie wykonywania (aby uzyskać odpowiedni wynik dla bieżącej platformy)? Np. Parsując /usr/includepliki nagłówkowe?
joshlf
Nie próbowałem tego, ale możesz mieć szczęście z pycparser .
cg909,
17

Ruby ma syscall(num [, args...]) → integer funkcję.

Na przykład:

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

Z 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> 
lgeorget
źródło