Pythonでネイティブコード(x86バイトコードなど)を実行する方法のメモ。
ctypesモジュールをインポートし、次のような関数を定義すればよい。
import ctypes
def native_func(bytecode):
libc = ctypes.CDLL('libc.so.6')
libc.mmap.restype = ctypes.c_void_p
buf = libc.mmap(None, len(bytecode), 7, 0x22, -1, 0)
libc.memcpy(ctypes.c_void_p(buf), ctypes.c_char_p(bytecode), len(bytecode))
return ctypes.CFUNCTYPE(ctypes.c_void_p)(buf)
rdrand = native_func('\x48\x0f\xc7\xf0\xc3') # rdrand rax; ret
print hex(rdrand())
上のコードでは、例としてハードウェア乱数を生成するRDRAND命令を実行し、その結果を返す関数を定義している。
実際に実行すると、実行ごとにランダムな値が返っていることが確認できる。
$ python native_func.py 0xd8e5dd17b96e3b07L $ python native_func.py 0xdfbac12088c27055L
追記(2016-06-06)
上ではネイティブコードの例としてRDRAND命令を実行したが、単にセキュアな乱数が必要な場合はos.urandom()を用いればよい。
# urandom.py
import os
import struct
randvalue = struct.unpack('<Q', os.urandom(8))[0]
print hex(randvalue)
$ python urandom.py 0xd67b1aeabffab050L $ python urandom.py 0x784919deb3fa692
さらに安全性を求める場合は/dev/randomを利用することになるが、このデバイスは十分なエントロピーが確保されるまでブロックされることに注意する必要がある。