Execute binary code

Discussion in 'Python' started by citronelu@yahoo.com, Jan 8, 2007.

  1. Guest

    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, 2007
    #1
    1. Advertising

  2. Larry Bates Guest

    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
     
    Larry Bates, Jan 8, 2007
    #2
    1. Advertising

  3. Guest

    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, 2007
    #3
  4. Guest

    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, 2007
    #4
  5. Chris Mellon Guest

    Fwd: Execute binary code

    On 8 Jan 2007 12:45:45 -0800, <> wrote:
    > 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.


    <sigh> Repost. Is there any chance at all that ML could set the
    reply-to to the list instead of the sender?
     
    Chris Mellon, Jan 8, 2007
    #5
  6. Guest

    Re: Fwd: Execute binary code

    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, 2007
    #6
  7. 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
     
    Bjoern Schliessmann, Jan 8, 2007
    #7
  8. Guest

    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, 2007
    #8
  9. 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.
     
    Bjoern Schliessmann, Jan 9, 2007
    #9
  10. Re: Fwd: Execute binary code

    At Monday 8/1/2007 18:01, 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
     
    Gabriel Genellina, Jan 9, 2007
    #10
  11. Chris Mellon Guest

    Re: Fwd: Execute binary code

    On 1/8/07, Gabriel Genellina <> wrote:
    > At Monday 8/1/2007 18:01, 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).
     
    Chris Mellon, Jan 9, 2007
    #11
  12. "Chris Mellon" <> wrote:


    > <sigh> Repost. 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
     
    Hendrik van Rooyen, Jan 9, 2007
    #12
  13. On 8 Jan 2007 15:15:54 -0800, declaimed the
    following in comp.lang.python:


    > 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.


    Oh? Then where is the Python script, itself, stored?

    What would prevent some astute person from feeding said "variable"
    contents to a dis-assembler, then building an actual executable from
    feeding the result to an assembler program?

    --
    Wulfraed Dennis Lee Bieber KD6MOG

    HTTP://wlfraed.home.netcom.com/
    (Bestiaria Support Staff: )
    HTTP://www.bestiaria.com/
     
    Dennis Lee Bieber, Jan 9, 2007
    #13
  14. Jorgen Grahn Guest

    On 8 Jan 2007 12:29:36 -0800, <> wrote:
    >
    > 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!
     
    Jorgen Grahn, Jan 9, 2007
    #14
  15. Guest

    Jorgen Grahn wrote:

    > On 8 Jan 2007 12:29:36 -0800, <> 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.


    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, 2007
    #15
  16. sturlamolden Guest

    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));
    }
     
    sturlamolden, Jan 9, 2007
    #16
  17. Chris Mellon Guest

    On 9 Jan 2007 07:04:11 -0800, sturlamolden <> 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.
     
    Chris Mellon, Jan 9, 2007
    #17
  18. sturlamolden Guest

    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.
     
    sturlamolden, Jan 10, 2007
    #18
  19. Chris Mellon Guest

    On 10 Jan 2007 08:12:41 -0800, sturlamolden <> wrote:
    >
    > 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
    >
     
    Chris Mellon, Jan 10, 2007
    #19
  20. Jorgen Grahn Guest

    On 9 Jan 2007 07:04:11 -0800, sturlamolden <> 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:

    [...]

    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!
     
    Jorgen Grahn, Jan 11, 2007
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Kamal Ahmed
    Replies:
    1
    Views:
    5,212
    =?Utf-8?B?U2VyZ2V5IFBvYmVyZXpvdnNraXk=?=
    Oct 25, 2005
  2. techtonik
    Replies:
    3
    Views:
    399
    Gabriel Genellina
    Feb 11, 2007
  3. P1u70
    Replies:
    2
    Views:
    1,840
    Jacek Dziedzic
    Dec 26, 2006
  4. cf29
    Replies:
    4
    Views:
    1,024
  5. Savas Ates
    Replies:
    1
    Views:
    281
    Patrice
    Aug 17, 2004
Loading...

Share This Page