I am working on a terminal emulator project in WPF and C#, utilizing WinPTY in an existing console emulator. The aim is to automate the collection of command results, including intermediate outputs, in scenarios where a command requires further input during execution.
The significant hurdle in this project is determining when a console process is ready for input to confirm the completion of its output. To address this, I have delved into various methods such as Thread State Analysis, Performance Counters, Process Stack Inspection, and Windows API Hooking. Particularly, I've tried injecting a DLL to intercept ReadConsoleA calls. Despite successful injection indicated by the initiation of the IsInstalled method, the targeted MyReadConsoleA method fails to activate. This area, new to me, has been navigated with guidance from the UnknownCheats tutorial.
As my understanding deepens, it seems less likely to find a method that definitively identifies when a process awaits user input. However, detecting actions like ConsoleWriteA could suffice for my test cases. I've examined and ruled out numerous methods, twice as many as mentioned, all falling short in reliability or feasibility. I am very open to simpler, more reliable solutions if anyone can offer insight or alternative approaches.
Here is a piece of code from my repository that differs from the one in the guide, which is probably where the error lies.
[DllImport("KernelBase.dll", CharSet = CharSet.Ansi, SetLastError = true)]
static extern bool ReadConsoleA( IntPtr hConsoleInput, StringBuilder lpBuffer, uint nNumberOfCharsToRead, out uint lpNumberOfCharsRead, IntPtr lpReserved);
static bool MyReadConsoleA(IntPtr hConsoleInput, StringBuilder lpBuffer, uint nNumberOfCharsToRead, out uint lpNumberOfCharsRead, IntPtr lpReserved)
{
LogToFile("MyReadConsoleA called");
try
{
((InjectionEntryPoint)HookRuntimeInfo.Callback).Interface.ReadCalled();
}
catch (Exception ex)
{
((InjectionEntryPoint)HookRuntimeInfo.Callback).Interface.HandleError(ex);
}
return ReadConsoleA(hConsoleInput, lpBuffer, nNumberOfCharsToRead, out lpNumberOfCharsRead, lpReserved);
}
namespace Delegates
{
[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi, SetLastError = true)]
public delegate bool ReadConsoleA(IntPtr hConsoleInput, StringBuilder lpBuffer, uint nNumberOfCharsToRead, out uint lpNumberOfCharsRead, IntPtr lpReserved);
}
Full DLL code - ConsoleReadObserver/InjectionEntryPoint.cs
Injection point - src/tterm/Ansi/WinPty.cs - StartObserving()
Class for message passing between dll and emulator - src/tterm/Remote/RemoteControl.cs