JohnGalt
JohnGalt

Reputation: 429

Python Program Output to Named Pipe

I use a program (upx.exe) that compresses and extracts packed executables. When I decompress an executable the only option is to write a file. I dont want the extracted code to touch the hard drive.

So I thought about writing a python wrapper that starts the executable and reads the decompressed code from a named pipe.

I wanted to

  1. create a named pipe in python,
  2. let the external program use that pipe as an output file and
  3. read the content that has been written to that pipe into a string.

I tried the following:

import win32pipe, win32file
import win32file

p = win32pipe.CreateNamedPipe(r'\\.\pipe\upx',
    win32pipe.PIPE_ACCESS_DUPLEX,
    win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_WAIT,
    1, 65536, 65536,300,None)

os.system("upx -d -o\\\\.\\pipe\\upx nbtscan-1.0.35.exe")

win32pipe.ConnectNamedPipe(p, None)

fileHandle = win32file.CreateFile(r'\\.\pipe\upx',
                              win32file.GENERIC_READ | win32file.GENERIC_WRITE,
                              0, None,
                              win32file.OPEN_EXISTING,
                              0, None)


data = win32file.ReadFile(fileHandle, 4096)
print data

This is what happens:

enter image description here

I have no experience with named pipes and feel very desperate right now. Perhaps you have an idea or a tutorial to give me some example. (The MSDN reference did not help me very much)
My code is based on this code, but when I use the "ConnectNamedPipe" function before the "system" call, the program just hangs and waits or some action on that pipe.
Please help.

Upvotes: 0

Views: 1555

Answers (1)

JohnGalt
JohnGalt

Reputation: 429

I solved it this way:

class Decompress(object):

    # Maximum to read from the decompressed stream
    maxsize = 2097152
    data = ""

    def __init__(self, application_path, type, filePath):

        # UPX Decompression
        if type == "UPX":

            print "Checking UPX file %s" % filePath 

            try:   
                p = win32pipe.CreateNamedPipe(r'\\.\pipe\upx', win32pipe.PIPE_ACCESS_DUPLEX, win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_WAIT, 1, 2097152, 2097152, 300, None)

                phandle = p.handle

                success, stdout, stderr = run_popen_with_timeout(application_path + r'tools\upx.exe -d --no-color --no-progress --no-backup -o\\.\pipe\upx ' + filePath, 3, "")
                #print stdout
                #print stderr   

                data = win32file.ReadFile(phandle, self.maxsize)

                p.close()

                #print "Read " + str(len(data[1])) + " bytes from decompressed EXE"

                self.data = data[1]
                #print self.data[:10]

            except Exception, e:
                traceback.print_exc()

def run_popen_with_timeout(command_string, timeout, input_data):
    """
    Run a sub-program in subprocess.Popen, pass it the input_data,
    kill it if the specified timeout has passed.
    returns a tuple of success, stdout, stderr
    """
    kill_check = threading.Event()
    def _kill_process_after_a_timeout(pid):
        os.kill(pid, signal.SIGTERM)
        kill_check.set() # tell the main routine that we had to kill
        # use SIGKILL if hard to kill...
        return
    p = Popen(command_string, stderr=STDOUT, stdout=PIPE)
    #print p.communicate()[0]
    print command_string
    pid = p.pid
    watchdog = threading.Timer(timeout, _kill_process_after_a_timeout, args=(pid, ))
    watchdog.start()
    (stdout, stderr) = p.communicate()
    watchdog.cancel() # if it's still waiting to run
    success = not kill_check.isSet()
    kill_check.clear()
    return (success, stdout, stderr) 

Upvotes: 2

Related Questions