36

I want to execute assembly code inside a python script. Is that possible?

In C programming would be like this

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

But how to do that with Python? Is it possible?

Russia Must Remove Putin
  • 374,368
  • 89
  • 403
  • 331
Yuda Prawira
  • 12,075
  • 10
  • 46
  • 54
  • 1
    With your example you will only get the stack pointer of the interpreter, which is meaningless in the context of your program. So what you wanted to do will proably not work anyway. – Gunther Piez May 18 '11 at 08:00
  • 2
    no that's asm just little example executing inside another language. i'm not really mean i want to get stack pointer address... – Yuda Prawira May 18 '11 at 08:04
  • That function doesn't work as an inline function. You actually need `__attribute__((noinline))` on it or something. Otherwise it will just insert a `mov %esp, %eax` into wherever it inlines, where the compiler might be using EAX for something else. You should use `asm("mov %esp, %0" : "=rm"(retval));`. Also, you're depending C89 implicit return type (of `int`) in the declaration. Also, getting ESP is a really bad example for something to use from python. Maybe show using a BMI2 instruction like `pext`? – Peter Cordes Sep 07 '16 at 00:50
  • Don't. Please don't. – leap123 Mar 26 '23 at 07:02

7 Answers7

22

You can embed assembly directly inside your Python program:

These work by compiling the assembly and loading it into executable memory at runtime. The first three projects implement x86-64 or x86 assemblers in Python, whereas the last calls out to an external compiler.

Luke
  • 11,374
  • 2
  • 48
  • 61
20

As a specific example, here is how to call a function which will take an int and return it incremented by one.

To obtain memory with the executable flag set, mmap module is used.

To call the function, ctypes module is used.

To put the machine code into memory, there is hardcoded byte string of x86-64 machine code.

The code will print 43.

In practice, I'd write the code in C shared object library and use inline assembly in C. I'd then use cffi to load and run the library. The advantage of this example is that it is self-contained and only needs the standard Python library.

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()
user7610
  • 25,267
  • 15
  • 124
  • 150
20

One way you could do this would be to write a (C) extension for Python. You can take a look at this documentation for full details of how to do that.

Another way of developing C-based Python extensions would be to interface directly with an external library using the ctypes module.

In any case, you'd need some C code compiled into either a library or an extension and a way to call it from Python. Clearly for what you want to achieve this is probably not optimal but actually its not that much work to expose a few functions.

jkp
  • 78,960
  • 28
  • 103
  • 104
  • 8
    It should be pointed out that since Python supports C extensions, you could write your who;e extension in pure assembler provided you code it to follow C's calling conventions w.r.t. parameter passing, returning values, register usage, etc. – martineau May 18 '11 at 09:59
6

Sorry for necroposting but I think that you can write your own DLL using asm and call it's functions from within Python.

Крайст
  • 776
  • 1
  • 9
  • 22
  • 1
    I'm learning asm now and thought about it while thinking about how to use adorable python and superheroable assembler. Have you already found necessary solutions for that idea? May be you can share them as an answer to your own question? And thank you for that important question :) – Крайст Jan 25 '13 at 19:40
  • necroposting answers is encouraged here, see the [Necromancer](https://stackoverflow.com/help/badges/17/necromancer) badge. – user7610 Oct 12 '20 at 14:15
1

In theory, you could:

  1. Write a simple function in C that calls the assembly
  2. Use Cython or Pyrex to call that function from Python

I have to admit that I haven't used either Pyrex or Cython, but they might be able to do what you need without having to go to the trouble of writing a full blown C extension.

detly
  • 29,332
  • 18
  • 93
  • 152
0

It is highly possible I made a small assembler in python, some of the libraries I used may have supported Ctypes, but I used pure Python, Most languages do actually interface at a low level, We are just using the HLL Langage features and not paying appropriate attention to how the code is being processed, I have also written a small POC image editing app in visual basic that used ASM x86 Code I am not actually sure on how to edit this into what I was trying to say. except maybe functions that would read the asm code and work from within the script itself. I do believe my thoughts were pointed out to be wrong. ASM code can be executed through the use of scripted functions that read that area of the code and compile them. almost as if it were a built in on the fly assembler. I try to help not so great a speaker though (or writter in this case as it may be) this page here maybe able to explain better on what I am trying to say http://code.activestate.com/recipes/579037-how-to-execute-x86-64-bit-assembly-code-directly-f/

TomFoolery
  • 11
  • 3
  • 1
    The OP wants to run machine code specified in asm inside a python program, not write a python program to assemble asm source into machine code. – Peter Cordes Sep 07 '16 at 00:55
  • go to codewars.com look for __TomFoolery__ that is me and check out the assembler I wrote in Python. You have to have access to low level functionality to write a assember my good sir so I beg to differ :) – TomFoolery Dec 08 '16 at 19:47
  • Point being. you can. but you have to write the functions, Kind of pointless but it can be done – TomFoolery Dec 08 '16 at 19:48
  • An assembler just has to read text files and write binary files. Whether or not you call that "low level", it has nothing to do with executing custom asm / machine code inside your python program. i.e. there's no reason an assembler written in Python wouldn't be able to assemble x86 asm into x86 machine code while running on an ARM system. Evaluating floating-point expressions at assemble time the same way the target would might take some "low level" fiddling, but you still don't have to execute target machine code. (IIRC NASM doesn't support x87 10-byte constants when cross-assembling) – Peter Cordes Dec 08 '16 at 19:54
  • Right. That is kind of what I was trying to say. little lost in translation there I guess :) – TomFoolery Dec 08 '16 at 20:03
  • Then you should edit your answer, because being able to write an assembler in Python doesn't help answer this question *at all*. i.e. your first sentence is off topic. Some of the other stuff is maybe relevant, but you don't explain how. – Peter Cordes Dec 08 '16 at 20:13
0

Python does not support this type of low level hardware interaction.

bradley.ayers
  • 37,165
  • 14
  • 93
  • 99
  • 3
    You have to step outside of regular Python *code*, but Python can interface with low level hardware via ctypes and/or C extensions. – John Montgomery May 18 '11 at 10:33
  • 3
    I suppose I was looking at this from the language perspective, rather than from an implementation such as Cython – bradley.ayers May 18 '11 at 10:36