I run binary in windows using:
process = subprocess.Popen(cmd, stderr = subprocess.PIPE, stdin = subprocess.PIPE, stdout = ch.input) ch.input comes from: ch = InputStreamChunker('\n') ch.daemon = True ch.start()
which was a cool, non-blocking way of reading from stdout. This was the accepted answer to this question: How can I read all available data from the .Popen.stdout subprocess (without blocking)?
This is the main part of my script that is trying to run / control the process:
import subprocess import time from e import * import msvcrt ch = InputStreamChunker('\n') ch.daemon = True ch.start() cmd = "C:\TEST.EXE" process = subprocess.Popen(cmd, stderr = subprocess.PIPE, stdin = subprocess.PIPE, stdout = ch.input) i = process.stdin answers = [] waitforresults(ch, answers, expect = 5) an = 1 for i in answers: print "ANSWER # " + str(an) + ":" + i.read() an= an+1 answers = [] time.sleep(5) msvcrt.ungetch('s') ch.flush() waitforresults(ch, answers, expect = 1) for a in answers: print a.getvalue() process.terminate() ch.stop() del process, ch print "DONE"
In any case, I can read from the process using this method. When I try to record a process using:
i = process.stdin i.write ("s \ n") or i.write ("s")
The output is displayed in the console window, but is not written in binary. I looked at the binary in IDA Pro and found that it uses a non-standard method of capturing user input while it is running.
This process is an interactive cli tool waiting for S, R, P or Q (status, resume, pause, exit) ***, and it captures the input power of a user falling into *** r. This is achieved using getche (). I threw the binary in IDA Pro to confirm:
v7 = getche(); if ( (unsigned int)dword_41F060 > 1 ) sub_4030A0(&unk_41C111, v5); WaitForSingleObject((HANDLE)dword_41F040, 0xFFFFFFFFu); if ( v7 == 113 ) { if ( dword_41F060 != 1 ) { if ( dword_41F060 ) dword_41F060 = 6; } } else { if ( v7 <= 113 ) { if ( v7 == 112 ) { if ( dword_41F060 == 2 ) QueryPerformanceCounter((LARGE_INTEGER *)&qword_41F128); dword_41F060 = 3; sub_4030A0("Paused", v5); } } else { if ( v7 == 114 ) { if ( dword_41F060 == 3 ) { QueryPerformanceFrequency((LARGE_INTEGER *)&v9); QueryPerformanceCounter((LARGE_INTEGER *)&v8); v3 = (double)(v8 - qword_41F128); LODWORD(v4) = sub_413FF0(v9, v10, 1000, 0); dbl_41F138 = v3 / (double)v4 + dbl_41F138; } dword_41F060 = 2; sub_4030A0("Resumed", v5); } else { if ( v7 == 115 ) sub_40AFC0(); } } }
Does anyone know how to trigger this event? This looked promising: http://docs.python.org/library/msvcrt.html and I tried using:
msvcrt.ungetch ("s") "The reason for the char character to be dropped into the console buffer is the next character read by getch () or getche ()."
which DID pressed the letter "s" on the console but did not call my breakpoint on getche (). Pressing the letter S manually does the job and causes IDA pro to hit the breakpoint.
halp? :)
EDIT:
I created two small console applications for Windows to demonstrate what works, what doesn't, and ensure that my python is normal.
This is the first with which I cannot recognize input by writing stdin, the second I can.
#include "stdafx.h" #include <conio.h> int _tmain(int argc, _TCHAR* argv[]) { char response; printf("Enter \"s\":\n"); response = _getch(); printf("You entered %c\n", response); return 0; }
can write the following:
#include "stdafx.h" #include <conio.h> int _tmain(int argc, _TCHAR* argv[]) { char response [2]; printf("Enter \"s\":\n"); gets(response); printf("You entered %s", response); return 0; }
EDIT 2 I also tried: import subprocess import time from e import * import msvcrt
ch = InputStreamChunker('\n') ch.daemon = True ch.start() cmd = ["test-getch.exe"] process = subprocess.Popen(cmd, stderr = subprocess.PIPE, stdin = subprocess.PIPE, stdout = ch.input) i = process.stdin answers = [] msvcrt.putch('s') ch.flush waitforresults(ch, answers, expect = 1) for answer in answers: print answer.getvalue() i.close() time.sleep(3) #process.terminate() ch.stop() del process, ch print "DONE"