By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
425,529 Members | 1,860 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 425,529 IT Pros & Developers. It's quick & easy.

Execute binary code

P: n/a
Is it possible to execute a binary string stored within a python script
as executable code ?

The script is run under Windows, and the binary code (a full executable
file) is stored in a variable in the script.

I know I can use os.system() or os.popen() to run an external file, but
these functions take as argument a string evaluated as command-line.

I also know I could save the binary code as a temporary file, execute
it and delete it afterwards, but this is not an alternative.

Thanks.

Jan 8 '07 #1
Share this Question
Share on Google+
19 Replies


P: n/a
ci*******@yahoo.com wrote:
Is it possible to execute a binary string stored within a python script
as executable code ?

The script is run under Windows, and the binary code (a full executable
file) is stored in a variable in the script.

I know I can use os.system() or os.popen() to run an external file, but
these functions take as argument a string evaluated as command-line.

I also know I could save the binary code as a temporary file, execute
it and delete it afterwards, but this is not an alternative.

Thanks.
What you are asking is a virus/trojan "like" program. There's no reason
you shouldn't be able to write the code to TEMP directory and execute it.

-Larry
Jan 8 '07 #2

P: n/a

ci*******@yahoo.com wrote:
Is it possible to execute a binary string stored within a python script
as executable code ?

The script is run under Windows, and the binary code (a full executable
file) is stored in a variable in the script.

I know I can use os.system() or os.popen() to run an external file, but
these functions take as argument a string evaluated as command-line.

I also know I could save the binary code as a temporary file, execute
it and delete it afterwards, but this is not an alternative.

Thanks.
It's not impossible, that's basically what I did on a smaller scale in
pyasm:

http://mysite.verizon.net/olsongt/

A small C-stub executes arbirary asm that was originally built as a
string. The tough part for you would be loading all of the referenced
..dlls into memory and patching in all the relocations from the source
COFF file. It'll be a pain but not entirely impossible.

Jan 8 '07 #3

P: n/a
Larry Bates wrote:
What you are asking is a virus/trojan "like" program. There's no reason
you shouldn't be able to write the code to TEMP directory and execute it.

-Larry

No, it is not about a trojan, but I guess it's pointless to try to
convince you otherwise.

It's not about being able to write the code to TEMP directory and
execute it, it's about not wanting to do so.

-Cornelius

Jan 8 '07 #4

P: n/a
On 8 Jan 2007 12:45:45 -0800, ci*******@yahoo.com <ci*******@yahoo.comwrote:
Larry Bates wrote:
What you are asking is a virus/trojan "like" program. There's no reason
you shouldn't be able to write the code to TEMP directory and execute it.

-Larry


No, it is not about a trojan, but I guess it's pointless to try to
convince you otherwise.

It's not about being able to write the code to TEMP directory and
execute it, it's about not wanting to do so.

-Cornelius
Writing to a temp file will be at least 3 times as easy and twice as
reliable as any other method you come up with.
<sighRepost. Is there any chance at all that ML could set the
reply-to to the list instead of the sender?
Jan 8 '07 #5

P: n/a

Chris Mellon wrote:
Writing to a temp file will be at least 3 times as easy and twice as
reliable as any other method you come up with.
I'm not disputing that, but I want to keep a piece of code (a parser
for Oracle binary dumps, that I didn't wrote) out of foreign hands, as
much as possible. Using a TEMP directory is not "stealth" enough.

Jan 8 '07 #6

P: n/a
Larry Bates wrote:
What you are asking is a virus/trojan "like" program.
Why? For being a trojan horse it must fake something. For being a
virus it must replicate itself. Writing an executable doesn't imply
the will to replicate itself.

But you could technically achieve this with standard python too
(just write python source and spawn a python process executing it).

Regards,
Björn

--
BOFH excuse #28:

CPU radiator broken

Jan 8 '07 #7

P: n/a

Bjoern Schliessmann wrote:
But you could technically achieve this with standard python too
(just write python source and spawn a python process executing it).
The code I try to execute is Windows specific and it is binary, not
python. Furthermore, it is stored in a variable within the parent
python script, not stored on harddisk as a file.

Jan 8 '07 #8

P: n/a
ci*******@yahoo.com wrote:
The code I try to execute is Windows specific and it is binary,
not python. Furthermore, it is stored in a variable within the
parent python script, not stored on harddisk as a file.
Sure, I just wanted to show that your special application is not
specific for trojan horses oder viruses. One could achieve similar
replication functionality with python by itself.

Regards,
Björn

--
BOFH excuse #217:

The MGs ran out of gas.

Jan 9 '07 #9

P: n/a
At Monday 8/1/2007 18:01, ci*******@yahoo.com wrote:
>Chris Mellon wrote:
Writing to a temp file will be at least 3 times as easy and twice as
reliable as any other method you come up with.

I'm not disputing that, but I want to keep a piece of code (a parser
for Oracle binary dumps, that I didn't wrote) out of foreign hands, as
much as possible. Using a TEMP directory is not "stealth" enough.
This is what I would do (untested of course!) (Mostly using the
Win32 API so you'll have to use pywin32 or ctypes).

Call CreateFile with dwShareMode=0, FILE_ATTRIBUTE_TEMPORARY,
FILE_FLAG_NO_BUFFERING, FILE_FLAG_DELETE_ON_CLOSE.
That means that no other process could open the file, if it fits in
available memory probably it won't even be written to disk, and it
will be deleted as soon as it has no more open handles. File name
does not have to end in .exe.
Copy the desired contents into a buffer obtained from VirtualAlloc;
then call WriteFile; release the buffer (rounding size up to next 4KB multiple)
Then CreateProcess with CREATE_SUSPENDED, and CloseHandle on the
file, and CloseHandle on the two handles returned on
PROCESS_INFORMATION. At this stage, the only open handle to the
temporary file is held by the section object inside the process.
Then ResumeThread(hTread) -process begins running- and
WaitForSingleObject(hProcess) -wait until finishes-.
As soon as it finishes execution, the last handle to the file is
closed and it is deleted.

Another approach would be to go below the Windows API and use the
native API function NtCreateProcess -officially undocumented- which
receives a section handle (which does not have to be disk based). But
this interfase is undocumented and known to change between Windows versions...

Or search for a rootkit...
--
Gabriel Genellina
Softlab SRL


__________________________________________________
Preguntá. Respondé. Descubrí.
Todo lo que querías saber, y lo que ni imaginabas,
está en Yahoo! Respuestas (Beta).
¡Probalo ya!
http://www.yahoo.com.ar/respuestas

Jan 9 '07 #10

P: n/a
On 1/8/07, Gabriel Genellina <ga******@yahoo.com.arwrote:
At Monday 8/1/2007 18:01, ci*******@yahoo.com wrote:
Chris Mellon wrote:
Writing to a temp file will be at least 3 times as easy and twice as
reliable as any other method you come up with.
I'm not disputing that, but I want to keep a piece of code (a parser
for Oracle binary dumps, that I didn't wrote) out of foreign hands, as
much as possible. Using a TEMP directory is not "stealth" enough.

This is what I would do (untested of course!) (Mostly using the
Win32 API so you'll have to use pywin32 or ctypes).

Call CreateFile with dwShareMode=0, FILE_ATTRIBUTE_TEMPORARY,
FILE_FLAG_NO_BUFFERING, FILE_FLAG_DELETE_ON_CLOSE.
That means that no other process could open the file, if it fits in
available memory probably it won't even be written to disk, and it
will be deleted as soon as it has no more open handles. File name
does not have to end in .exe.
Copy the desired contents into a buffer obtained from VirtualAlloc;
then call WriteFile; release the buffer (rounding size up to next 4KB multiple)
Then CreateProcess with CREATE_SUSPENDED, and CloseHandle on the
file, and CloseHandle on the two handles returned on
PROCESS_INFORMATION. At this stage, the only open handle to the
temporary file is held by the section object inside the process.
Then ResumeThread(hTread) -process begins running- and
WaitForSingleObject(hProcess) -wait until finishes-.
As soon as it finishes execution, the last handle to the file is
closed and it is deleted.

Another approach would be to go below the Windows API and use the
native API function NtCreateProcess -officially undocumented- which
receives a section handle (which does not have to be disk based). But
this interfase is undocumented and known to change between Windows versions...

Or search for a rootkit...
--
Gabriel Genellina
Softlab SRL
Thats a lot of work to execute a binary image that can be trivially
recovered from the python source with 2 minutes of work (up to 15 if
you have to install Python and google for how to write to a file
first).
Jan 9 '07 #11

P: n/a

"Chris Mellon" <ar*****@gmail.comwrote:

<sighRepost. Is there any chance at all that ML could set the
reply-to to the list instead of the sender?
+1

- I regularly hit "reply all", delete the OP, and then I get :

"Message has a suspicious header"

- Hendrik
Jan 9 '07 #12

P: n/a
On 8 Jan 2007 12:29:36 -0800, ol*****@verizon.net <ol*****@verizon.netwrote:
>
ci*******@yahoo.com wrote:
>Is it possible to execute a binary string stored within a python script
as executable code ?

The script is run under Windows, and the binary code (a full executable
file) is stored in a variable in the script.

I know I can use os.system() or os.popen() to run an external file, but
these functions take as argument a string evaluated as command-line.

I also know I could save the binary code as a temporary file, execute
it and delete it afterwards, but this is not an alternative.

Thanks.

It's not impossible, that's basically what I did on a smaller scale in
pyasm:
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.

/Jorgen
[1] Not much to the OP, I'd think.

--
// Jorgen Grahn <grahn@ Ph'nglui mglw'nafh Cthulhu
\X/ snipabacken.dyndns.org R'lyeh wgah'nagl fhtagn!
Jan 9 '07 #13

P: n/a

Jorgen Grahn wrote:
On 8 Jan 2007 12:29:36 -0800, ol*****@verizon.net <ol*****@verizon.netwrote:
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.
That's totally untrue, how do you think a JIT compiler works? For
example you can generate x86 assembler on the fly and call it using
pyASM see http://mysite.verizon.net/olsongt/usersGuide.html

Cheers

Rich.

Jan 9 '07 #14

P: n/a

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));
}

Jan 9 '07 #15

P: n/a
On 9 Jan 2007 07:04:11 -0800, sturlamolden <st**********@yahoo.nowrote:
>
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.
Jan 9 '07 #16

P: n/a

Chris Mellon wrote:
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.
You may have to offset the function pointer so the entry point becomes
correct.

Jan 10 '07 #17

P: n/a
On 10 Jan 2007 08:12:41 -0800, sturlamolden <st**********@yahoo.nowrote:
>
Chris Mellon wrote:
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.

You may have to offset the function pointer so the entry point becomes
correct.
That won't be enough. You basically would have to re-implement the OS
loading process, handling relocations and loading any linked
libraries. Possible, in theory, but very non-trivial.
--
http://mail.python.org/mailman/listinfo/python-list
Jan 10 '07 #18

P: n/a
On 9 Jan 2007 07:04:11 -0800, sturlamolden <st**********@yahoo.nowrote:
>
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:
[...]

You probably need to flush the code cache somewhere there, too, don't you?
Or will that resolve itself because that memory area hasn't been executed
before?

I must admit I haven't contemplated this since the MC68000 was state of the
art, before caches became popular.

/Jorgen

--
// Jorgen Grahn <grahn@ Ph'nglui mglw'nafh Cthulhu
\X/ snipabacken.dyndns.org R'lyeh wgah'nagl fhtagn!
Jan 11 '07 #19

P: n/a
On Wed, 10 Jan 2007 10:31:50 -0600, Chris Mellon <ar*****@gmail.comwrote:
On 10 Jan 2007 08:12:41 -0800, sturlamolden <st**********@yahoo.nowrote:
>>
Chris Mellon wrote:
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.

You may have to offset the function pointer so the entry point becomes
correct.

That won't be enough. You basically would have to re-implement the OS
loading process, handling relocations and loading any linked
libraries. Possible, in theory, but very non-trivial.
Yeah, that was implicitly my thinking a bit up in the thread. If all you
have is an executable file (COFF/ELF/...) as a string, and you have no
os.exec(string) or similar, then you're in trouble.

At least if it has to work.

/Jorgen

--
// Jorgen Grahn <grahn@ Ph'nglui mglw'nafh Cthulhu
\X/ snipabacken.dyndns.org R'lyeh wgah'nagl fhtagn!
Jan 11 '07 #20

This discussion thread is closed

Replies have been disabled for this discussion.