使用Python执行汇编代码

37

我想在Python脚本中执行汇编代码。这可能吗?

在C编程中,可以像这样实现

static inline getesp(){
        __asm__("mov %esp, %eax");
}

但是用Python如何实现呢?可能吗?


1
通过你的示例,你只会得到解释器的堆栈指针,这在你的程序上下文中是没有意义的。所以你想做的事情可能无法实现。 - Gunther Piez
2
不,那只是一个在另一种语言内执行的小例子。我并不是真的想要获取堆栈指针地址... - Yuda Prawira
该函数不能作为内联函数使用。实际上,您需要在其上使用__attribute__((noinline))或其他类似的东西。否则,它将只是在内联的任何地方插入一个mov %esp,%eax,而编译器可能正在使用EAX进行其他操作。您应该使用asm("mov %esp, %0" : "=rm"(retval));。此外,在声明中依赖C89隐式返回类型(int)也是不好的。另外,从Python中获取ESP是一个非常糟糕的示例。也许可以展示如何使用BMI2指令,例如pext - Peter Cordes
不要。请不要。 - leap123
7个回答

23

21

您可以编写Python的(C)扩展来实现此目的。您可以查看此文档以了解详细信息。

另一种开发基于C的Python扩展的方法是使用ctypes模块直接与外部库进行接口。

无论哪种情况,您都需要将一些C代码编译为库或扩展,并从Python中调用它。显然,对于您想要实现的内容来说,这可能不是最佳选择,但实际上仅需公开几个函数即可。


8
需要指出的是,由于Python支持C扩展,因此您可以使用纯汇编语言编写整个扩展,只要您在代码中遵循C关于参数传递、返回值、寄存器使用等方面的调用约定即可。 - martineau

21

以下是一个具体的例子,介绍如何调用一个函数,该函数将获取一个整数并返回增加1后的结果。

要获取带有可执行标志的内存,使用mmap模块。

要调用该函数,使用ctypes模块。

为了将机器码放入内存中,需要硬编码x86-64机器码的字节字符串。

该代码将输出43。

在实践中,我会在C共享对象库中编写代码,并在C中使用内联汇编语言。然后,我将使用cffi来加载和运行库。此示例的优点是它是自包含的,并且仅需要标准Python库。

import ctypes
import mmap

buf = mmap.mmap(-1, mmap.PAGESIZE, prot=mmap.PROT_READ | mmap.PROT_WRITE | mmap.PROT_EXEC)

ftype = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int)
fpointer = ctypes.c_void_p.from_buffer(buf)

f = ftype(ctypes.addressof(fpointer))

buf.write(
    b'\x8b\xc7'  # mov eax, edi
    b'\x83\xc0\x01'  # add eax, 1
    b'\xc3'  # ret
)

r = f(42)
print(r)

del fpointer
buf.close()

6

抱歉回复较晚,但我认为你可以使用汇编语言编写自己的DLL,并从Python中调用其函数。


1
我现在正在学习汇编语言,同时思考如何使用可爱的Python和超级英雄般的汇编语言。你是否已经找到了这个想法所需的解决方案?也许你可以将它们分享作为对自己问题的回答?非常感谢你提出这个重要的问题 :) - Крайст
在这里鼓励回复“死亡帖子”,请参见Necromancer徽章。 - user7610

1

Python不支持这种低级硬件交互。


3
你需要走出常规的Python“代码”范畴,但是Python可以通过ctypes和/或C扩展与低级硬件进行交互。 - John Montgomery
3
我理解我需要从语言角度而非像Cython这样的实现来看待这个问题。 - bradley.ayers

1

理论上,您可以:

  1. 在C中编写一个简单的函数来调用汇编
  2. 使用CythonPyrex从Python调用该函数

我必须承认我没有使用过Pyrex或Cython,但它们可能能够满足您的需求,而无需费力地编写完整的C扩展。


0

很有可能我用Python编写了一个小的汇编器,使用了一些可能支持Ctypes的库,但我使用的是纯Python。大多数语言实际上在低级别接口。我们只是使用高级语言功能,没有适当地关注代码是如何被处理的。我还编写了一个小的POC图像编辑应用程序,在Visual Basic中使用了ASM x86代码。 我实际上不确定如何将其编辑为我想说的内容。也许可以使用函数来读取汇编代码,并在脚本内部工作。我相信我的想法被指出是错误的。可以通过读取代码区域并编译它们的脚本函数来执行ASM代码。就好像是内置的即时汇编器一样。我试图帮助不太擅长讲话的人(或者在这种情况下是写作者),这里的页面可能能更好地解释我想说的话 http://code.activestate.com/recipes/579037-how-to-execute-x86-64-bit-assembly-code-directly-f/


1
OP想在Python程序中运行asm中指定的机器码,而不是编写Python程序将asm源代码汇编成机器码。 - Peter Cordes
请前往codewars.com查找__TomFoolery__,那是我的用户名,请查看我用Python编写的汇编程序。要编写汇编程序,您必须具备低级功能的访问权限,因此我不同意您的说法 :) - TomFoolery
重点是,你可以这样做,但你必须编写函数。有点毫无意义,但确实可行。 - TomFoolery
汇编器只需要读取文本文件并写入二进制文件。无论您是否将其称为“低级”,它与在Python程序中执行自定义asm /机器代码无关。也就是说,用Python编写的汇编器可以在ARM系统上运行时将x86 asm汇编成x86机器代码。在汇编时评估浮点表达式的方式与目标相同可能需要一些“低级”的调整,但仍不必执行目标机器代码。(如果我没记错,NASM在交叉汇编时不支持x87 10字节常量) - Peter Cordes
没错,那就是我想说的。可能有点翻译不准 :) - TomFoolery
那么你应该编辑你的回答,因为能够在Python中编写汇编程序根本不能帮助回答这个问题。也就是说,你的第一句话离题了。其他一些东西可能是相关的,但你没有解释它们如何相关。 - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接