原文始发于matthew:NotepadExec – Using notepad.exe to launch an EXE without code injection
NotepadExec – Using notepad.exe to launch an EXE without code injection
This code demonstrates how to programmatically launch another executable file from within notepad.exe using window messages (SendMessage / PostMessage). I can’t think of any real use for this tool – this is just a quick proof-of-concept for fun.
This works as follows:
1. Use CreateProcess to launch a hidden notepad.exe process.
2. Find the main window of the new notepad.exe process using EnumWindows. Use GetWindowThreadProcessId to check if the window is owned by the new notepad.exe process.
3. Launch the “Open File” dialog programmatically using SendMessage.
4. Send various messages to the “Open File” dialog to navigate to the target directory and select the EXE file. There will be cleaner ways to access the undocumented DirectUIHWND window class, but I didn’t spend any time looking into this.
5. Send the WM_CONTEXTMENU message to the “Open File” dialog to simulate right-clicking on the EXE file.
6. Select the “Open” button on the right-click menu to execute the program.
The result of the steps above is a child process created from within the notepad.exe process. This works because the “Open File” dialog in Windows is implemented within each process using shell API DLLs – this means that it can be used as a “cut-down” version of explorer.exe.
I should also add that this method isn’t particularly reliable. It is dependant on some hard-coded Sleep calls, and the whole thing is likely to break on future Windows versions. It also expects English language labels, although these can easily be changed. This has only been tested on Windows 10.
Full code below:
#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;
// 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;
}
// create notepad process
if(CreateProcess(NULL, "notepad.exe", 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];
// 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(;;)
{
Sleep(10);
// search for controls
EnumChildWindows(hGlobal_OpenFileWindow, FindOpenFileBaseControls, NULL);
if(hGlobal_OpenFileEditControl != NULL && hGlobal_OpenFileOpenButton != NULL)
{
break;
}
}
// 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(DWORD 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;
}
转载请注明:NotepadExec – Using notepad.exe to launch an EXE without code injection | CTF导航