Execute binary code

Chris Mellon arkanes at gmail.com
Tue Jan 9 17:02:06 CET 2007


On 9 Jan 2007 07:04:11 -0800, sturlamolden <sturlamolden at yahoo.no> wrote:
>
> Jorgen Grahn wrote:
>
> > For what it's worth[1], under Unix it /is/ impossible. The only way to bring in
> > new code (short of dynamic libraries) is to call exec(2) or its variations,
> > and all need a file system object to load the code from.
>
> The x86 processor cannot tell the difference between code segments and
> data segments. If the executable code is stored in string, all you need
> is a pointer to the string holding the code. You can cast the string
> address to a function pointer (possibly through a void* if the compiler
> complains), then dereference (call) the function pointer.
>
> Trojans, viruses and JIT compilers do this all the time. Here is an
> (untested) example:
>
> static PyObject*
> call_code_in_string(PyObject *self, PyObject *args)
> {
>     char *s;
>     int size;
>     int arg1, arg2, arg3;
>     typedef int (*func_t)(int,int,int);
>     func_t pfunc;
>     if(!PyArg_ParseTuple(args, "s#(iii)", &s, &size, &arg1, &arg2,
> &arg3)) return NULL;
>     pfunc = (func_t)((void *)s); /* if it fails, try
> memcpy(&pfunc,&s,sizeof(void*)) instead */
>     return PyInt_FromLong((long)pfunc(arg1, arg2, arg3));
> }
>
> Another possibility would be to just return the string address, and
> then make the call possibly using ctypes.
>
> static PyObject*
> get_string_addr(PyObject *self, PyObject *args)
> {
>     char *s;
>     int size;
>     if(!PyArg_ParseTuple(args, "s#", &s, &size)) return NULL;
>     return PyInt_FromLong((long)((void*)s));
> }
>

This works fine if the binary data is "pure" asm, but the impresssion
the OP gave is that it's a compiled binary, which you can't just "jump
into" this way.



More information about the Python-list mailing list