NotepadExec – 使用 notepad.exe 启动 EXE 而无需代码注入

原文链接:https://www.x86matthew.com/view_post?id=notepadexec

此代码演示如何使用窗口消息 ( SendMessage / PostMessage ) 以编程方式从 notepad.exe 中启动另一个可执行文件。我想不出这个工具有什么实际用途——这只是一个有趣的快速概念验证。

此代码演示如何使用窗口消息 ( SendMessage / PostMessage ) 以编程方式从 notepad.exe 中启动另一个可执行文件。我想不出这个工具有什么实际用途——这只是一个有趣的快速概念验证。

其工作原理如下:

1. 使用CreateProcess启动隐藏的notepad.exe进程。2. 使用EnumWindows
找到新的 notepad.exe 进程的主窗口。使用GetWindowThreadProcessId检查窗口是否由新的notepad.exe进程拥有。3. 使用SendMessage 以编程方式启动“打开文件”对话框。

4. 向“打开文件”对话框发送各种消息以导航到目标目录并选择 EXE 文件。将有更简洁的方法来访问未记录的DirectUIHWND窗口类,但我没有花任何时间研究这个。
5、发送WM_CONTEXTMENU消息到“打开文件”对话框,模拟EXE文件的右键单击。
6. 选择右键菜单中的“打开”按钮执行程序。

上述步骤的结果是从notepad.exe进程中创建的子进程。这是因为 Windows 中的“打开文件”对话框是在每个进程中使用 shell API DLL 实现的——这意味着它可以用作“缩减”

我还应该补充一点,这种方法并不是特别可靠。它依赖于一些硬编码的睡眠调用,整个事情很可能会在未来的 Windows 版本上中断。它还需要英文标签,尽管这些标签很容易更改。这仅在 Windows 10 上进行了测试。

完整代码如下:

// NotepadExec.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

//#include <iostream>

#include <stdio.h>
#include <windows.h>

DWORD dwGlobal_HideWindows = 0;
DWORD dwGlobal_NotepadPID = 0;
HWND hGlobal_NotepadWindow = NULL;
HWND hGlobal_OpenFileWindow = NULL;
HWND hGlobal_OpenFileEditControl = NULL;
HWND hGlobal_OpenFileOpenButton = NULL;
HWND hGlobal_OpenFileListControl = NULL;
HWND hGlobal_PopupWindow = NULL;
HANDLE hGlobal_NotepadProcess = NULL;

BOOL CALLBACK FindNotepadWindow(HWND hWnd, LPARAM lParam)
{
	DWORD dwPID = 0;

	// check if this window is within the new notepad process
	GetWindowThreadProcessId(hWnd, &dwPID);
	if (dwPID == dwGlobal_NotepadPID)
	{
		if (GetWindow(hWnd, GW_OWNER) == 0)
		{
			// found main window
			hGlobal_NotepadWindow = hWnd;
			return 0;
		}
	}

	return 1;
}

BOOL CALLBACK FindOpenFileWindow(HWND hWnd, LPARAM lParam)
{
	DWORD dwPID = 0;
	char szClassName[512];

	// check if this window is within the new notepad process
	GetWindowThreadProcessId(hWnd, &dwPID);
	if (dwPID == dwGlobal_NotepadPID)
	{
		memset(szClassName, 0, sizeof(szClassName));
		GetClassName(hWnd, szClassName, sizeof(szClassName) - 1);
		if (strcmp(szClassName, "#32770") == 0)
		{
			// found "open file" window
			hGlobal_OpenFileWindow = hWnd;
			return 0;
		}
	}

	return 1;
}

BOOL CALLBACK FindPopupWindow(HWND hWnd, LPARAM lParam)
{
	DWORD dwPID = 0;
	char szClassName[512];

	// check if this window is within the new notepad process
	GetWindowThreadProcessId(hWnd, &dwPID);
	if (dwPID == dwGlobal_NotepadPID)
	{
		memset(szClassName, 0, sizeof(szClassName));
		GetClassName(hWnd, szClassName, sizeof(szClassName) - 1);
		if (strcmp(szClassName, "#32768") == 0)
		{
			// found context menu
			hGlobal_PopupWindow = hWnd;
			return 0;
		}
	}

	return 1;
}

BOOL CALLBACK FindOpenFileBaseControls(HWND hWnd, LPARAM lParam)
{
	DWORD dwPID = 0;
	char szClassName[512];
	char szButtonText[512];

	// check class name
	memset(szClassName, 0, sizeof(szClassName));
	GetClassName(hWnd, szClassName, sizeof(szClassName) - 1);
	if (strcmp(szClassName, "Edit") == 0)
	{
		if (GetParent(GetParent(GetParent(hWnd))) == hGlobal_OpenFileWindow)
		{
			// found file name edit control
			hGlobal_OpenFileEditControl = hWnd;
		}
	}
	else if (strcmp(szClassName, "Button") == 0)
	{
		memset(szButtonText, 0, sizeof(szButtonText));
		GetWindowText(hWnd, szButtonText, sizeof(szButtonText) - 1);
		if (strcmp(szButtonText, "&Open") == 0)
		{
			// found open button
			hGlobal_OpenFileOpenButton = hWnd;
		}
	}

	return 1;
}

BOOL CALLBACK FindOpenFileListControl(HWND hWnd, LPARAM lParam)
{
	char szClassName[512];

	// check class name
	memset(szClassName, 0, sizeof(szClassName));
	GetClassName(hWnd, szClassName, sizeof(szClassName) - 1);
	if (strcmp(szClassName, "DirectUIHWND") == 0)
	{
		// get parent class name
		memset(szClassName, 0, sizeof(szClassName));
		GetClassName(GetParent(hWnd), szClassName, sizeof(szClassName) - 1);
		if (strcmp(szClassName, "SHELLDLL_DefView") == 0)
		{
			// found file list control
			hGlobal_OpenFileListControl = hWnd;
		}
	}

	return 1;
}

DWORD WINAPI HideOpenFileWindowThread(LPVOID lpArg)
{
	for (;;)
	{
		Sleep(10);

		// check if we have a valid window handle
		if (hGlobal_OpenFileWindow != NULL)
		{
			// hide window
			ShowWindow(hGlobal_OpenFileWindow, SW_HIDE);
		}
	}
}

DWORD CreateNotepadProcess()
{
	PROCESS_INFORMATION ProcessInfo;
	STARTUPINFO StartupInfo;
	char szCmd[1024];

	// initialise startup data
	memset((void*)&StartupInfo, 0, sizeof(StartupInfo));
	StartupInfo.cb = sizeof(StartupInfo);

	// check if the window should be hidden
	if (dwGlobal_HideWindows != 0)
	{
		StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
		StartupInfo.wShowWindow = SW_HIDE;
		StartupInfo.wShowWindow = SW_SHOW;
	}

	strcpy(szCmd, "notepad.exe");
	// create notepad process
	if (CreateProcess(NULL, szCmd, NULL, NULL, 0, 0, NULL, NULL, &StartupInfo, &ProcessInfo) == 0)
	{
		return 1;
	}

	// store process ID and handle
	dwGlobal_NotepadPID = ProcessInfo.dwProcessId;
	hGlobal_NotepadProcess = ProcessInfo.hProcess;

	// close thread handle
	CloseHandle(ProcessInfo.hThread);

	// get main notepad window
	for (;;)
	{
		Sleep(10);

		// search for notepad window
		EnumWindows(FindNotepadWindow, NULL);
		if (hGlobal_NotepadWindow != NULL)
		{
			break;
		}
	}

	return 0;
}

DWORD LaunchTargetProcess(char* pDirectoryPath, char* pTargetExe)
{
	HMENU hMenu = NULL;
	MENUITEMINFO MenuItemInfo;
	char szMenuItemString[512];
	DWORD dwItemCount = 0;
	DWORD dwFoundOpenButton = 0;
	DWORD dwMenuKeyDownCount = 0;
	char szSendString[512];
	DWORD i;

	// open "open file" dialog
	PostMessage(hGlobal_NotepadWindow, WM_COMMAND, 0x10002, 0);

	// find "open file" window
	for (;;)
	{
		Sleep(10);

		// search for window
		EnumWindows(FindOpenFileWindow, NULL);
		if (hGlobal_OpenFileWindow != NULL)
		{
			break;
		}
	}

	// find controls within "open file" window
	for (;;)
	{
		// search for controls
		EnumChildWindows(hGlobal_OpenFileWindow, FindOpenFileBaseControls, NULL);
		if (hGlobal_OpenFileEditControl != NULL && hGlobal_OpenFileOpenButton != NULL)
		{
			break;
		}
		Sleep(10);
	}

	// set directory path
	memset(szSendString, 0, sizeof(szSendString));
	_snprintf(szSendString, sizeof(szSendString) - 1, "%s\\", pDirectoryPath);
	SendMessage(hGlobal_OpenFileEditControl, WM_SETTEXT, strlen(szSendString), (long)szSendString);
	SendMessage(hGlobal_OpenFileOpenButton, BM_CLICK, 0, 0);

	// wait for 1 second
	Sleep(1000);

	// set '*.exe' filter
	memset(szSendString, 0, sizeof(szSendString));
	_snprintf(szSendString, sizeof(szSendString) - 1, "*.exe");
	SendMessage(hGlobal_OpenFileEditControl, WM_SETTEXT, strlen(szSendString), (long)szSendString);
	SendMessage(hGlobal_OpenFileOpenButton, BM_CLICK, 0, 0);

	// wait for 1 second
	Sleep(1000);

	// find directory listing control within "open file" window
	for (;;)
	{
		Sleep(10);

		// find list control
		EnumChildWindows(hGlobal_OpenFileWindow, FindOpenFileListControl, NULL);
		if (hGlobal_OpenFileListControl != NULL)
		{
			break;
		}
	}

	// send tab character to move focus away from the edit control
	PostMessage(hGlobal_OpenFileWindow, WM_KEYDOWN, VK_TAB, 1);
	PostMessage(hGlobal_OpenFileWindow, WM_KEYUP, VK_TAB, 0xc0000001);

	// wait for 1 second
	Sleep(1000);

	// send target file name characters to the directory listing control to select the target file
	for ( i = 0; i < strlen(pTargetExe); i++)
	{
		// send current character
		SendMessage(hGlobal_OpenFileListControl, WM_CHAR, *(char*)(pTargetExe + i), 1);
	}

	// open the context menu for this file
	PostMessage(hGlobal_OpenFileListControl, WM_CONTEXTMENU, (WPARAM)hGlobal_OpenFileListControl, 0xFFFFFFFF);

	// find context menu
	for (;;)
	{
		Sleep(10);

		// search for context menu
		EnumWindows(FindPopupWindow, NULL);
		if (hGlobal_PopupWindow != NULL)
		{
			break;
		}
	}

	// send MN_GETHMENU message
	hMenu = (HMENU)SendMessage(hGlobal_PopupWindow, 0x01E1, 0, 0);
	if (hMenu == NULL)
	{
		return 1;
	}

	// find "Open" entry within the menu
	dwItemCount = GetMenuItemCount(hMenu);
	for (i = 0; i < dwItemCount; i++)
	{
		// get current menu item info
		memset((void*)&MenuItemInfo, 0, sizeof(MenuItemInfo));
		MenuItemInfo.cbSize = sizeof(MenuItemInfo);
		MenuItemInfo.fMask = 0x100;
		GetMenuItemInfo(hMenu, i, 1, &MenuItemInfo);

		// check if this is a separator item
		if (MenuItemInfo.fType & MFT_SEPARATOR)
		{
			// ignore
			continue;
		}

		// increase the number of "key down" presses
		dwMenuKeyDownCount++;

		// check if this is the "Open" button
		memset(szMenuItemString, 0, sizeof(szMenuItemString));
		GetMenuString(hMenu, i, szMenuItemString, sizeof(szMenuItemString) - 1, MF_BYPOSITION);
		if (strcmp(szMenuItemString, "&Open") == 0)
		{
			// found "Open" button
			dwFoundOpenButton = 1;
			break;
		}
	}

	// ensure the "Open" button was found in the context menu
	if (dwFoundOpenButton == 0)
	{
		return 1;
	}

	// send "down" key presses
	for (i = 0; i < dwMenuKeyDownCount; i++)
	{
		PostMessage(hGlobal_PopupWindow, WM_KEYDOWN, VK_DOWN, 0x2A0001);
		PostMessage(hGlobal_PopupWindow, WM_KEYUP, VK_DOWN, 0xD02A0001);
	}

	// send "enter" key to execute the target exe
	PostMessage(hGlobal_PopupWindow, WM_KEYDOWN, VK_RETURN, 0x2A0001);
	PostMessage(hGlobal_PopupWindow, WM_KEYUP, VK_RETURN, 0xD02A0001);

	return 0;
}

int main(int argc, char* argv[])
{
	DWORD dwThreadID = 0;
	HANDLE hHideOpenFileWindowThread = NULL;
	char szDirectoryPath[512];
	char szTargetExe[512];
	char* pLastSlash = NULL;

	printf("NotepadExec - www.x86matthew.com\n\n");

	if (argc != 2)
	{
		printf("%s <full_exe_path>\n\n", argv[0]);
		return 1;
	}

	// split target exe path
	memset(szDirectoryPath, 0, sizeof(szDirectoryPath));
	strncpy(szDirectoryPath, argv[1], sizeof(szDirectoryPath) - 1);

	// find last slash
	pLastSlash = strrchr(szDirectoryPath, '\\');
	if (pLastSlash == NULL)
	{
		printf("Invalid exe path\n");
		return 1;
	}

	// remove exe name from directory path
	*pLastSlash = '\0';

	// store exe name
	memset(szTargetExe, 0, sizeof(szTargetExe));
	pLastSlash++;
	strncpy(szTargetExe, pLastSlash, sizeof(szTargetExe) - 1);

	// hide windows
	dwGlobal_HideWindows = 1;

	printf("Creating notepad.exe process...\n");

	// create notepad process
	if (CreateNotepadProcess() != 0)
	{
		// error
		printf("Failed to create notepad process\n");
		return 1;
	}

	if (dwGlobal_HideWindows != 0)
	{
		// create background thread to ensure the "open file" window remains hidden.
		// this is because the "open file" window makes itself visible again when performing certain actions.
		hHideOpenFileWindowThread = CreateThread(NULL, 0, HideOpenFileWindowThread, NULL, 0, &dwThreadID);
		if (hHideOpenFileWindowThread == NULL)
		{
			// error
			printf("Failed to create thread\n");

			TerminateProcess(hGlobal_NotepadProcess, 0);
			return 1;
		}
	}

	printf("Sending window messages to notepad...\n");

	// launch target process
	if (LaunchTargetProcess(szDirectoryPath, szTargetExe) != 0)
	{
		// error
		printf("Failed to launch target process\n");

		if (dwGlobal_HideWindows != 0)
		{
			TerminateThread(hHideOpenFileWindowThread, 0);
		}

		TerminateProcess(hGlobal_NotepadProcess, 0);
		return 1;
	}

	printf("Notepad launched %s successfully\n", szTargetExe);

	// wait for 2 seconds
	Sleep(2000);

	// terminate background thread
	if (dwGlobal_HideWindows != 0)
	{
		TerminateThread(hHideOpenFileWindowThread, 0);
	}

	// terminate notepad process
	TerminateProcess(hGlobal_NotepadProcess, 0);

	return 0;
}

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注