You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
256 lines
8.2 KiB
256 lines
8.2 KiB
2 years ago
|
/*=========================================================================
|
||
|
|
||
|
Program: Visualization Toolkit
|
||
|
Module: $RCSfile: vtkWin32OutputWindowProcess.c,v $
|
||
|
|
||
|
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
|
||
|
All rights reserved.
|
||
|
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
|
||
|
|
||
|
This software is distributed WITHOUT ANY WARRANTY; without even
|
||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||
|
PURPOSE. See the above copyright notice for more information.
|
||
|
|
||
|
=========================================================================*/
|
||
|
#ifdef _MSC_VER
|
||
|
/* Handle MSVC compiler warning messages, etc. */
|
||
|
# pragma warning ( disable : 4115 )
|
||
|
#endif
|
||
|
|
||
|
/* Function to delete executable calling it. */
|
||
|
static int SelfDelete();
|
||
|
|
||
|
#include <windows.h>
|
||
|
|
||
|
#undef _T
|
||
|
#ifdef UNICODE
|
||
|
# define _T(x) L x
|
||
|
#else
|
||
|
# define _T(x) x
|
||
|
#endif
|
||
|
|
||
|
static HWND MainWindow = 0;
|
||
|
static HWND EditWindow = 0;
|
||
|
static LPCTSTR MainWindowClass = _T("vtkOutputWindowProcess");
|
||
|
static LPCTSTR EditWindowClass = _T("EDIT");
|
||
|
static LONG MainWindowStyle = (WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW);
|
||
|
static LONG EditWindowStyle = (ES_MULTILINE | ES_READONLY | WS_CHILD |
|
||
|
ES_AUTOVSCROLL | ES_AUTOHSCROLL | WS_VISIBLE |
|
||
|
WS_VSCROLL | WS_HSCROLL | WS_MAXIMIZE);
|
||
|
|
||
|
static LRESULT APIENTRY MainWindowProc(HWND hWnd, UINT m, WPARAM w, LPARAM l)
|
||
|
{
|
||
|
switch (m)
|
||
|
{
|
||
|
case WM_SIZE:
|
||
|
MoveWindow(EditWindow, 0, 0, LOWORD(l), HIWORD(l), TRUE);
|
||
|
break;
|
||
|
case WM_DESTROY:
|
||
|
PostQuitMessage(0);
|
||
|
break;
|
||
|
}
|
||
|
return DefWindowProc(hWnd, m, w, l);
|
||
|
}
|
||
|
|
||
|
static void RegisterWindowClass()
|
||
|
{
|
||
|
WNDCLASS wndClass;
|
||
|
if(!GetClassInfo(GetModuleHandle(0), MainWindowClass, &wndClass))
|
||
|
{
|
||
|
wndClass.style = CS_HREDRAW | CS_VREDRAW;
|
||
|
wndClass.lpfnWndProc = MainWindowProc;
|
||
|
wndClass.cbClsExtra = 0;
|
||
|
wndClass.hInstance = GetModuleHandle(0);
|
||
|
wndClass.hIcon = LoadIcon(0, IDI_APPLICATION);
|
||
|
wndClass.hCursor = LoadCursor(0, IDC_ARROW);
|
||
|
wndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
|
||
|
wndClass.lpszMenuName = 0;
|
||
|
wndClass.lpszClassName = MainWindowClass;
|
||
|
wndClass.cbWndExtra = 0;
|
||
|
RegisterClass(&wndClass);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static DWORD WINAPI ReadThreadProc(LPVOID p)
|
||
|
{
|
||
|
char buffer[1024];
|
||
|
DWORD nRead = 0;
|
||
|
while(ReadFile(GetStdHandle(STD_INPUT_HANDLE), buffer, 1024, &nRead, 0))
|
||
|
{
|
||
|
buffer[nRead] = 0;
|
||
|
SendMessage(EditWindow, EM_SETSEL, (WPARAM)-1, (LPARAM)-1);
|
||
|
SendMessage(EditWindow, EM_REPLACESEL, (WPARAM)0, (LPARAM)buffer);
|
||
|
}
|
||
|
return (DWORD)p;
|
||
|
}
|
||
|
|
||
|
void MainEventLoop()
|
||
|
{
|
||
|
BOOL b;
|
||
|
MSG msg;
|
||
|
while((b = GetMessage(&msg, 0, 0, 0)) != 0 && b != -1)
|
||
|
{
|
||
|
TranslateMessage(&msg);
|
||
|
DispatchMessage(&msg);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev,
|
||
|
PSTR szCmdLine, int iCmdShow)
|
||
|
{
|
||
|
(void)hInst; (void)hPrev; (void)szCmdLine; (void)iCmdShow;
|
||
|
|
||
|
/* Setup a child process to delete this executable when it exits. */
|
||
|
SelfDelete();
|
||
|
|
||
|
/* Create a simple GUI. */
|
||
|
RegisterWindowClass();
|
||
|
MainWindow = CreateWindow(MainWindowClass, MainWindowClass, MainWindowStyle,
|
||
|
0,0,512,512, 0, 0, GetModuleHandle(0), 0);
|
||
|
EditWindow = CreateWindow(EditWindowClass, "", EditWindowStyle,
|
||
|
0,0,512,512, MainWindow, 0, GetModuleHandle(0), 0);
|
||
|
ShowWindow(MainWindow, SW_SHOW);
|
||
|
UpdateWindow(MainWindow);
|
||
|
|
||
|
/* Create a thread to read from standard input and write to the window. */
|
||
|
{DWORD threadId; CreateThread(0, 1024, ReadThreadProc, 0, 0, &threadId);}
|
||
|
|
||
|
/* Run the event loop until the window is closed. */
|
||
|
MainEventLoop();
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
/* Code to delete executable calling it. Based on code from James
|
||
|
Brown at http://www.catch22.org.uk/tuts/selfdel.asp. */
|
||
|
|
||
|
#pragma pack(push, 1)
|
||
|
|
||
|
#define SELF_DELETE_CODESIZE 0x200
|
||
|
|
||
|
/* Data to inject into remote process. */
|
||
|
typedef struct SelfDeleteRemoteCode_s SelfDeleteRemoteCode;
|
||
|
typedef struct SelfDeleteRemoteCode_s
|
||
|
{
|
||
|
SelfDeleteRemoteCode *Arg0;
|
||
|
BYTE opCodes[SELF_DELETE_CODESIZE];
|
||
|
HANDLE hParent;
|
||
|
|
||
|
DWORD (__stdcall *fnWaitForSingleObject)(HANDLE hHandle, DWORD dwMilliseconds);
|
||
|
BOOL (__stdcall *fnCloseHandle)(HANDLE hObject);
|
||
|
BOOL (__stdcall *fnDeleteFile)(LPCTSTR lpFileName);
|
||
|
void (__stdcall *fnSleep)(DWORD dwMilliseconds);
|
||
|
void (__stdcall *fnExitProcess)(UINT uExitCode);
|
||
|
DWORD (__stdcall *fnGetLastError)(void);
|
||
|
|
||
|
TCHAR szFileName[MAX_PATH];
|
||
|
} SelfDeleteRemoteCode;
|
||
|
|
||
|
#pragma pack(pop)
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
# error "vtkWin32OutputWindowProcess must be compiled Release"
|
||
|
#endif
|
||
|
|
||
|
/* Function to execute in remote process. It may only call windows
|
||
|
kernel functions through pointers in the SelfDeleteRemoteCode
|
||
|
structure. */
|
||
|
static void SelfDeleteRemoteThread(SelfDeleteRemoteCode* remote)
|
||
|
{
|
||
|
/* Block until parent process terminates. */
|
||
|
remote->fnWaitForSingleObject(remote->hParent, INFINITE);
|
||
|
remote->fnCloseHandle(remote->hParent);
|
||
|
|
||
|
/* Delete the executable file. */
|
||
|
while(!remote->fnDeleteFile(remote->szFileName))
|
||
|
{
|
||
|
remote->fnSleep(1000);
|
||
|
}
|
||
|
|
||
|
/* Exit so that we do not execute garbage code. */
|
||
|
remote->fnExitProcess(0);
|
||
|
}
|
||
|
|
||
|
/* Function to setup remote process that waits for this process to
|
||
|
exit and then deletes its executable. */
|
||
|
static int SelfDelete()
|
||
|
{
|
||
|
STARTUPINFO si;
|
||
|
PROCESS_INFORMATION pi;
|
||
|
ZeroMemory(&si, sizeof(si));
|
||
|
si.cb = sizeof(si);
|
||
|
|
||
|
/* Create a process using the explorer executable but suspend it
|
||
|
immediately. */
|
||
|
if(CreateProcess(0, _T("explorer.exe"), 0, 0, 0,
|
||
|
(CREATE_SUSPENDED | IDLE_PRIORITY_CLASS),
|
||
|
0, 0, &si, &pi))
|
||
|
{
|
||
|
/* Structure to store code and data to copy to remote process. */
|
||
|
SelfDeleteRemoteCode code;
|
||
|
|
||
|
DWORD oldProtect;
|
||
|
CONTEXT context;
|
||
|
DWORD entryPoint;
|
||
|
|
||
|
/* Setup pointers to kernel functions for the remote code to call. */
|
||
|
code.fnWaitForSingleObject = WaitForSingleObject;
|
||
|
code.fnCloseHandle = CloseHandle;
|
||
|
code.fnDeleteFile = DeleteFile;
|
||
|
code.fnSleep = Sleep;
|
||
|
code.fnExitProcess = ExitProcess;
|
||
|
code.fnGetLastError = GetLastError;
|
||
|
|
||
|
/* Give the remote process a copy of our own process handle. */
|
||
|
DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
|
||
|
pi.hProcess, &code.hParent, 0, FALSE, 0);
|
||
|
|
||
|
/* Store the file name of this process's executable. */
|
||
|
GetModuleFileName(0, code.szFileName, MAX_PATH);
|
||
|
|
||
|
/* Store the binary code to execute remotely. */
|
||
|
memcpy(code.opCodes, SelfDeleteRemoteThread, SELF_DELETE_CODESIZE);
|
||
|
|
||
|
/* Allocate some space on process's stack and place our
|
||
|
SelfDeleteRemoteCode structure there. Then set the instruction
|
||
|
pointer to this location and let the process resume. */
|
||
|
context.ContextFlags = (CONTEXT_INTEGER | CONTEXT_CONTROL);
|
||
|
GetThreadContext(pi.hThread, &context);
|
||
|
|
||
|
/* Allocate space on stack that is aligned to cache-line boundary. */
|
||
|
entryPoint = (context.Esp - sizeof(SelfDeleteRemoteCode)) & ~0x1F;
|
||
|
|
||
|
/* Place a pointer to the structure at the bottom-of-stack. This
|
||
|
pointer is located in such a way that it becomes the
|
||
|
SelfDeleteRemoteThread's first argument. */
|
||
|
code.Arg0 = (SelfDeleteRemoteCode*)entryPoint;
|
||
|
|
||
|
/* Set dummy return address for remote thread. It will never return. */
|
||
|
context.Esp = entryPoint - 4;
|
||
|
|
||
|
/* Set remote thread to execute the opCodes we copy to the process. */
|
||
|
context.Eip = entryPoint + (((char*)&code.opCodes) - ((char*)&code));
|
||
|
|
||
|
/* Copy the code and data to the remote process entry point. */
|
||
|
VirtualProtectEx(pi.hProcess, (PVOID)entryPoint, sizeof(code),
|
||
|
PAGE_EXECUTE_READWRITE, &oldProtect);
|
||
|
WriteProcessMemory(pi.hProcess, (PVOID)entryPoint, &code, sizeof(code), 0);
|
||
|
|
||
|
/* Make sure the new code will be loaded. */
|
||
|
FlushInstructionCache(pi.hProcess, (PVOID)entryPoint, sizeof(code));
|
||
|
|
||
|
/* Set the remote thread to execute at our entry point. */
|
||
|
SetThreadContext(pi.hThread, &context);
|
||
|
|
||
|
/* Let the remote process continue. It will block until this
|
||
|
process exits. */
|
||
|
ResumeThread(pi.hThread);
|
||
|
CloseHandle(pi.hThread);
|
||
|
CloseHandle(pi.hProcess);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|