原文链接: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;
}