Advertisement
Guest User

Untitled

a guest
Jun 24th, 2025
31
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 11.10 KB | Source Code | 0 0
  1. #include <string>
  2. #include <thread>
  3. #include <atomic>
  4. #include <cassert>
  5. #include <iostream>
  6. #include <mutex>
  7. #include <windows.h>
  8. #include <io.h>
  9. #include <winternl.h>
  10. #define isatty                       _isatty
  11. #define fileno                       _fileno
  12. #define NtCurrentProcess()           ((HANDLE)(LONG_PTR) - 1)
  13. #define RESIZE_CONHOST_SIGNAL_BUFFER 8
  14. #ifndef PSEUDOCONSOLE_INHERIT_CURSOR
  15. #    define PSEUDOCONSOLE_INHERIT_CURSOR 1
  16. #endif
  17. #define BUFF_SIZE 0x200
  18.  
  19. typedef struct _HPCON_INTERNAL
  20. {
  21.     HANDLE hWritePipe;
  22.     HANDLE hConDrvReference;
  23.     HANDLE hConHostProcess;
  24. } HPCON_INTERNAL;
  25.  
  26. inline NTSTATUS WINAPI CreateHandle(PHANDLE FileHandle, PWSTR Buffer,
  27.                                     ACCESS_MASK DesiredAccess,
  28.                                     HANDLE      RootDirectory,
  29.                                     BOOLEAN     IsInheritable,
  30.                                     ULONG       OpenOptions)
  31. {
  32.     IO_STATUS_BLOCK IoStatusBlock;
  33.     ULONG           Attributes = OBJ_CASE_INSENSITIVE;
  34.     if (IsInheritable)
  35.         Attributes |= OBJ_INHERIT;
  36.  
  37.     UNICODE_STRING ObjectName;
  38.     memset(&ObjectName, 0, sizeof ObjectName);
  39.     RtlInitUnicodeString(&ObjectName, Buffer);
  40.  
  41.     OBJECT_ATTRIBUTES ObjectAttributes;
  42.     memset(&ObjectAttributes, 0, sizeof ObjectAttributes);
  43.     ObjectAttributes.RootDirectory = RootDirectory;
  44.     ObjectAttributes.Length = sizeof ObjectAttributes;
  45.     ObjectAttributes.Attributes = Attributes;
  46.     ObjectAttributes.ObjectName = &ObjectName;
  47.  
  48.     return NtOpenFile(
  49.         FileHandle, DesiredAccess, &ObjectAttributes, &IoStatusBlock,
  50.         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  51.         OpenOptions);
  52. }
  53.  
  54. class Terminal
  55. {
  56.   public:
  57.     HPCON consoleHandle;
  58.  
  59.     HRESULT
  60.     WINAPI
  61.     InitializeConsole(COORD size, HANDLE hInput, HANDLE hOutput,
  62.                       DWORD dwFlags)
  63.     {
  64.         NTSTATUS Status;
  65.         BOOL     bRes;
  66.  
  67.         HANDLE InputHandle, OutputHandle;
  68.         HANDLE hConServer, hConReference;
  69.         HANDLE hProc = NtCurrentProcess();
  70.  
  71.         bRes = DuplicateHandle(hProc, hInput, hProc, &InputHandle, 0,
  72.                                TRUE, DUPLICATE_SAME_ACCESS);
  73.         assert(bRes != 0);
  74.  
  75.         bRes = DuplicateHandle(hProc, hOutput, hProc, &OutputHandle,
  76.                                0, TRUE, DUPLICATE_SAME_ACCESS);
  77.         assert(bRes != 0);
  78.  
  79.         Status = CreateHandle(&hConServer,
  80.                               (LPWSTR)L"\\Device\\ConDrv\\Server",
  81.                               GENERIC_ALL, NULL, TRUE, 0);
  82.  
  83.         std::cout << "Status: " << Status << '\n';
  84.  
  85.         assert(Status == 0);
  86.  
  87.         HANDLE              ReadPipeHandle, WritePipeHandle;
  88.         SECURITY_ATTRIBUTES PipeAttributes = {};
  89.         PipeAttributes.bInheritHandle = TRUE;
  90.         PipeAttributes.lpSecurityDescriptor = NULL;
  91.         PipeAttributes.nLength = sizeof PipeAttributes;
  92.  
  93.         bRes = CreatePipe(&ReadPipeHandle, &WritePipeHandle,
  94.                           &PipeAttributes, 0);
  95.         assert(bRes != 0);
  96.  
  97.         bRes = SetHandleInformation(
  98.             ReadPipeHandle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
  99.         assert(bRes != 0);
  100.  
  101.         PWSTR InheritCursor =
  102.             (LPWSTR)L"--inheritcursor "; /* Requires one space */
  103.         if (!(dwFlags & PSEUDOCONSOLE_INHERIT_CURSOR))
  104.             InheritCursor = (LPWSTR)L"";
  105.  
  106.         wchar_t ConHostCommand[MAX_PATH];
  107.  
  108.         /* ConHost command format strings */
  109. #define COMMAND_FORMAT                                          \
  110.     L"\\\\?\\%s\\system32\\conhost.exe %s--width %hu --height " \
  111.     L"%hu --signal 0x%x --server 0x%x"
  112.  
  113.         wchar_t winDir[MAX_PATH];
  114.         GetWindowsDirectoryW(winDir, MAX_PATH);
  115.         swprintf_s(ConHostCommand, MAX_PATH,
  116.                    L"\"%s\\system32\\conhost.exe\" %s--width %hu "
  117.                    L"--height %hu --signal 0x%x --server 0x%x",
  118.                    winDir, InheritCursor, size.X, size.Y,
  119.                    HandleToULong(ReadPipeHandle),
  120.                    HandleToULong(hConServer));
  121.  
  122.         /* Initialize thread attribute list */
  123.         HANDLE Values[4] = {hConServer, InputHandle, OutputHandle,
  124.                             ReadPipeHandle};
  125.         size_t AttrSize;
  126.         LPPROC_THREAD_ATTRIBUTE_LIST AttrList = NULL;
  127.         InitializeProcThreadAttributeList(NULL, 1, 0, &AttrSize);
  128.         AttrList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(
  129.             GetProcessHeap(), 0, AttrSize);
  130.         InitializeProcThreadAttributeList(AttrList, 1, 0, &AttrSize);
  131.         bRes = UpdateProcThreadAttribute(
  132.             AttrList, 0,
  133.             PROC_THREAD_ATTRIBUTE_HANDLE_LIST, /* 0x20002u */
  134.             Values, sizeof Values, NULL, NULL);
  135.         assert(bRes != 0);
  136.  
  137.         /* Assign members of STARTUPINFOEXW */
  138.         PROCESS_INFORMATION ProcInfo;
  139.         memset(&ProcInfo, 0, sizeof ProcInfo);
  140.         STARTUPINFOEXW SInfoEx;
  141.         memset(&SInfoEx, 0, sizeof SInfoEx);
  142.         SInfoEx.StartupInfo.cb = sizeof SInfoEx;
  143.         SInfoEx.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
  144.         SInfoEx.StartupInfo.hStdInput = InputHandle;
  145.         SInfoEx.StartupInfo.hStdOutput = OutputHandle;
  146.         SInfoEx.StartupInfo.hStdError = OutputHandle;
  147.         SInfoEx.lpAttributeList = AttrList;
  148.  
  149.         bRes = CreateProcessW(
  150.             NULL, ConHostCommand, NULL, NULL, TRUE,
  151.             EXTENDED_STARTUPINFO_PRESENT, NULL, NULL,
  152.             &SInfoEx.StartupInfo, &ProcInfo);
  153.         assert(bRes != 0);
  154.  
  155.         Status = CreateHandle(
  156.             &hConReference, (LPWSTR)L"\\Reference",
  157.             GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, hConServer,
  158.             FALSE, FILE_SYNCHRONOUS_IO_NONALERT);
  159.         assert(Status == 0);
  160.  
  161.         /* Return handles to caller */
  162.         HPCON_INTERNAL* consoleHandleInt = (HPCON_INTERNAL*)HeapAlloc(
  163.             GetProcessHeap(), 0, sizeof(*consoleHandleInt));
  164.         consoleHandleInt->hWritePipe = WritePipeHandle;
  165.         consoleHandleInt->hConDrvReference = hConReference;
  166.         consoleHandleInt->hConHostProcess = ProcInfo.hProcess;
  167.  
  168.         consoleHandle = consoleHandleInt;
  169.  
  170.         /* Cleanup */
  171.         HeapFree(GetProcessHeap(), 0, AttrList);
  172.         CloseHandle(InputHandle);
  173.         CloseHandle(OutputHandle);
  174.         CloseHandle(hConServer);
  175.         CloseHandle(ProcInfo.hThread);
  176.         CloseHandle(ProcInfo.hProcess);
  177.  
  178.         return 0;
  179.     }
  180. };
  181.  
  182. HANDLE hPipeIn = NULL, hPipeOut;
  183. HANDLE hPipePTYIn, hPipePTYOut;
  184. Terminal terminal;
  185.  
  186. void PipeListener()
  187. {
  188.     HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
  189.     char   szBuffer[BUFF_SIZE];
  190.     DWORD  dwBytesWritten, dwBytesRead, dwAvailable;
  191.  
  192.     int loopCount = 0;
  193.     while (true)
  194.     {
  195.         loopCount++;
  196.  
  197.         // Check if data is available to read
  198.         if (PeekNamedPipe(hPipeIn, NULL, 0, NULL, &dwAvailable, NULL))
  199.         {
  200.             if (loopCount % 100 == 0)
  201.             {
  202.                 printf("Loop %d: PeekNamedPipe succeeded, "
  203.                        "dwAvailable: %lu\n",
  204.                        loopCount, dwAvailable);              
  205.             }
  206.  
  207.             if (dwAvailable > 0)
  208.             {
  209.                 if (ReadFile(hPipeIn, szBuffer, BUFF_SIZE - 1,
  210.                              &dwBytesRead, NULL))
  211.                 {
  212.                     if (dwBytesRead == 0)
  213.                         break;
  214.  
  215.                     szBuffer[dwBytesRead] =
  216.                         '\0';
  217.                    
  218.                     WriteFile(hConsole, szBuffer, dwBytesRead,
  219.                               &dwBytesWritten, NULL);
  220.                 }
  221.                 else
  222.                 {
  223.                     // ReadFile failed
  224.                     DWORD error = GetLastError();
  225.                     if (error == ERROR_BROKEN_PIPE ||
  226.                         error == ERROR_PIPE_NOT_CONNECTED)
  227.                         break;
  228.                 }
  229.             }
  230.             else
  231.             {
  232.                 // No data available, sleep briefly to avoid busy
  233.                 // waiting
  234.                 Sleep(10);
  235.             }
  236.         }
  237.         else
  238.         {
  239.             printf("ERROR: DATA IS UNAVAILABLE TO READ FROM PIPE.");
  240.            
  241.  
  242.             DWORD error = GetLastError();
  243.             if (error == ERROR_BROKEN_PIPE ||
  244.                 error == ERROR_PIPE_NOT_CONNECTED)
  245.             {
  246.                 printf("FATAL ERROR: BROKEN PIPE OR PIPE NOT "
  247.                        "CONNECTED. SHUTTING DOWN LISTENERS. PREPARE "
  248.                        "FOR MELTDOWN.\n");
  249.                
  250.                 break;
  251.             }
  252.  
  253.             Sleep(10);
  254.         }
  255.     }
  256. }
  257.  
  258. int main(int argc, char** argv)
  259. {
  260.     BOOL bRes;
  261.  
  262.     std::thread listenerThread(PipeListener);
  263.    
  264.     SECURITY_ATTRIBUTES attributes = {};
  265.     attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
  266.     attributes.lpSecurityDescriptor = NULL;
  267.     attributes.bInheritHandle = TRUE;
  268.  
  269.     /* Create the pipes to which the ConPTY will connect */
  270.     if (CreatePipe(&hPipePTYIn, &hPipeOut, &attributes, 0) &&
  271.         CreatePipe(&hPipeIn, &hPipePTYOut, &attributes, 0))
  272.     {
  273.         /* Create the Pseudo Console attached to the PTY-end of the
  274.          * pipes */
  275.         COORD                      consoleSize = {0};
  276.         CONSOLE_SCREEN_BUFFER_INFO csbi = {0};
  277.         if (GetConsoleScreenBufferInfo(
  278.                 GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
  279.         {
  280.             consoleSize.X =
  281.                 csbi.srWindow.Right - csbi.srWindow.Left + 1;
  282.             consoleSize.Y =
  283.                 csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
  284.         }
  285.  
  286.         terminal.InitializeConsole(consoleSize, hPipePTYIn,
  287.                                    hPipePTYOut, 0);
  288.  
  289.     }
  290.  
  291.     /* Initialize thread attribute */
  292.     size_t                       AttrSize;
  293.     LPPROC_THREAD_ATTRIBUTE_LIST AttrList = NULL;
  294.     InitializeProcThreadAttributeList(NULL, 1, 0, &AttrSize);
  295.     AttrList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(
  296.         GetProcessHeap(), HEAP_ZERO_MEMORY, AttrSize);
  297.  
  298.     InitializeProcThreadAttributeList(AttrList, 1, 0, &AttrSize);
  299.  
  300.     bRes = UpdateProcThreadAttribute(
  301.         AttrList, 0,
  302.         PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, /* 0x20016u */
  303.         terminal.consoleHandle, sizeof terminal.consoleHandle, NULL,
  304.         NULL);
  305.     assert(bRes != 0);
  306.  
  307.     /* Initialize startup info struct */
  308.     PROCESS_INFORMATION ProcInfo;
  309.     memset(&ProcInfo, 0, sizeof ProcInfo);
  310.     STARTUPINFOEXW SInfoEx;
  311.     memset(&SInfoEx, 0, sizeof SInfoEx);
  312.     SInfoEx.StartupInfo.cb = sizeof SInfoEx;
  313.     SInfoEx.lpAttributeList = AttrList;
  314.  
  315.     wchar_t Command[] = L"cmd /c echo Hello World";
  316.  
  317.     bRes = CreateProcessW(NULL, Command, NULL, NULL, TRUE,
  318.                           EXTENDED_STARTUPINFO_PRESENT, NULL, NULL,
  319.                           &SInfoEx.StartupInfo, &ProcInfo);
  320.     assert(bRes != 0);
  321.  
  322.     while (1) {}
  323.  
  324.     /* Cleanup */
  325.     CloseHandle(ProcInfo.hThread);
  326.     CloseHandle(ProcInfo.hProcess);
  327.     HeapFree(GetProcessHeap(), 0, AttrList);
  328.     CloseHandle(hPipeOut);
  329.     CloseHandle(hPipeIn);
  330.     CloseHandle(hPipePTYOut);
  331.     CloseHandle(hPipePTYIn);
  332.     listenerThread.join();
  333.  
  334.     return 0;
  335. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement