几种创建进程函数的不同

文章目录
  1. 1. WinExec
  2. 2. ShellExecute和ShellExecuteEx
  3. 3. CreateProcess

参考资料:
1.ShellExecute,ShellExecuteEx, WinExec ,CreateProcess区别
2.ShellExecute, WinExec, CreateProcess区别
3.MSDN

Windows系统提供了好几种创建进程的方式,对于普通的打开一个exe创建进程这几种方式都可以胜任。那这几种创建进程的方式究竟有什么不同呢?
大体上的东西和使用方式可以查看参考资料1、2

WinExec

1
2
3
4
5
6
7
8
9
10
11
UINT WINAPI WinExec(
_In_ LPCSTR lpCmdLine, 将要执行的应用程序路径或则命令行
_In_ UINT uCmdShow 应用程序显示方式
)
;


ChildEBP RetAddr Args to Child
005ff680 74c48618 005ff9f4 005ff99c 02000000 ntdll!NtCreateUserProcess (FPO: [11,0,0])
005ffc48 74c49e4b 00000000 00000000 0076aca8 KERNELBASE!CreateProcessInternalW+0x8d8 (FPO: [SEH])
005ffd30 74c6f8fc 00000000 00000000 005ffedc KERNELBASE!CreateProcessInternalA+0x11b (FPO: [Non-Fpo])
005ffd68 74d7a8ad 00000000 005ffedc 00000000 KERNELBASE!CreateProcessA+0x2c (FPO: [Non-Fpo])
005ffe30 013c1061 005ffedc 00000005 013c337c KERNEL32!WinExec+0xdd (FPO: [2,35,4])

WinExec是为了兼容16位系统而遗留下来的,所以也就只支持ansi码,优点是使用简单只有两个参数,缺点也是太简单没有太多功能。如果执行成功返回值大于31,否则失败,且WinExec是阻塞操作,只有子进程调用了GetMessage或超时才返回,其他几个都会直接返回。
还有一点就是如果写成这样WinExec(“C:\Program Files\MyApp”, …)而且存在 C:\Program.exe这个文件的话就会直接执行这个而不是MyApp.exe,会空格截断。正确写法WinExec(“\”C:\Program Files\MyApp.exe\” -L -S”, …)
所以为了少出问题还是尽量不用WinExec。
从上面堆栈可以看出WInExec底层调用CreateProcess。

ShellExecute和ShellExecuteEx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
ShellExecute
HINSTANCE ShellExecute(
_In_opt_ HWND hwnd, 父进程句柄可设置为NULL
_In_opt_ LPCTSTR lpOperation, 操作类型
_In_ LPCTSTR lpFile, 操作文件路径
_In_opt_ LPCTSTR lpParameters, 参数
_In_opt_ LPCTSTR lpDirectory, 执行当前文件夹
_In_ INT nShowCmd 显示方式
)
;

ShellExecute(handle, "explore", <fully_qualified_path_to_folder>, NULL, NULL, SW_SHOWNORMAL);

ChildEBP RetAddr Args to Child
005ff4a8 74c48618 005ff81c 005ff7c4 02000000 ntdll!NtCreateUserProcess (FPO: [11,0,0])
005ffa70 74c70d7c 00000000 007989d4 007a2480 KERNELBASE!CreateProcessInternalW+0x8d8 (FPO: [SEH])
005ffaa8 747f43a2 007989d4 007a2480 00000000 KERNELBASE!CreateProcessW+0x2c (FPO: [Non-Fpo])
005ffb1c 747f4287 000f0256 00797658 00000001 windows_storage!CInvokeCreateProcessVerb::_CallCreateProcess+0xc5 (FPO: [0,13,4])
005ffb4c 747f3f86 00000001 00797658 00000001 windows_storage!CInvokeCreateProcessVerb::_PrepareAndCallCreateProcess+0x189 (FPO: [Non-Fpo])
005ffb5c 747f4fc4 00797660 00797660 00789dd0 windows_storage!CInvokeCreateProcessVerb::_TryCreateProcess+0x21 (FPO: [0,0,4])
005ffb80 747f3dd1 00797660 747f3da0 005ffbb8 windows_storage!CInvokeCreateProcessVerb::_DoApplication+0xac (FPO: [Non-Fpo])
005ffb90 747f5a7e 00797660 00797658 00789dd0 windows_storage!CInvokeCreateProcessVerb::Execute+0x31 (FPO: [Non-Fpo])
005ffbb8 747f5f95 00797660 0076df6c 00000000 windows_storage!CBindAndInvokeStaticVerb::_DoCommand+0xe4 (FPO: [Non-Fpo])
005ffbdc 747f5ca3 00000000 00000000 747f5b70 windows_storage!CBindAndInvokeStaticVerb::_TryCreateProcessDdeHandler+0x34 (FPO: [Non-Fpo])
005ffcdc 7556998c 00789dd8 007702b8 007702b8 windows_storage!CBindAndInvokeStaticVerb::Execute+0x133 (FPO: [1,57,4])
005ffd0c 7556984c 007824d0 007702b8 005ffd88 SHELL32!CShellExecute::_ExecuteAssoc+0xb7 (FPO: [Non-Fpo])
005ffd30 75569647 005ffd88 007702b8 00000000 SHELL32!CShellExecute::_DoExecute+0x84 (FPO: [Non-Fpo])
005ffd44 755f4d64 005ffd88 00000001 005ffd88 SHELL32!CShellExecute::ExecuteNormal+0x9e (FPO: [Non-Fpo])
005ffd58 755f4cd6 00000001 005ffde4 00000000 SHELL32!ShellExecuteNormal+0x47 (FPO: [0,0,4])
005ffd74 756c21ec 005ffd88 005ffe20 00001500 SHELL32!ShellExecuteExW+0x26 (FPO: [1,1,4])
005ffdd0 756c2175 005ffde4 6df020c1 6defe55e SHELL32!ShellExecuteExA+0x5c (FPO: [Non-Fpo])
005ffe20 013c108b 00000000 013c2178 005ffedc SHELL32!ShellExecuteA+0x65 (FPO: [Non-Fpo])



ShellExecuteEx
BOOL ShellExecuteEx(
_Inout_ SHELLEXECUTEINFO *pExecInfo
)
;

typedef struct _SHELLEXECUTEINFO {
DWORD cbSize; 结构体大小
ULONG fMask;
HWND hwnd;
LPCTSTR lpVerb;
LPCTSTR lpFile;
LPCTSTR lpParameters;
LPCTSTR lpDirectory;
int nShow;
HINSTANCE hInstApp; 返回的进程句柄供waitforsingleobject之类操作
LPVOID lpIDList;
LPCTSTR lpClass;
HKEY hkeyClass;
DWORD dwHotKey;
union {
HANDLE hIcon;
HANDLE hMonitor;
} DUMMYUNIONNAME;
HANDLE hProcess;
} SHELLEXECUTEINFO, *LPSHELLEXECUTEINFO;

ChildEBP RetAddr Args to Child
02c7f5e8 74c48618 02c7f95c 02c7f904 02000000 ntdll!NtCreateUserProcess (FPO: [11,0,0])
02c7fbb0 74c70d7c 00000000 00de9324 00dec680 KERNELBASE!CreateProcessInternalW+0x8d8 (FPO: [SEH])
02c7fbe8 747f43a2 00de9324 00dec680 00000000 KERNELBASE!CreateProcessW+0x2c (FPO: [Non-Fpo])
02c7fc5c 747f4287 000c03dc 00de7fa8 00000001 windows_storage!CInvokeCreateProcessVerb::_CallCreateProcess+0xc5 (FPO: [0,13,4])
02c7fc8c 747f3f86 00000001 00de7fa8 00000001 windows_storage!CInvokeCreateProcessVerb::_PrepareAndCallCreateProcess+0x189 (FPO: [Non-Fpo])
02c7fc9c 747f4fc4 00de7fb0 00de7fb0 00dd7498 windows_storage!CInvokeCreateProcessVerb::_TryCreateProcess+0x21 (FPO: [0,0,4])
02c7fcc0 747f3dd1 00de7fb0 747f3da0 02c7fcf8 windows_storage!CInvokeCreateProcessVerb::_DoApplication+0xac (FPO: [Non-Fpo])
02c7fcd0 747f5a7e 00de7fb0 00de7fa8 00dd7498 windows_storage!CInvokeCreateProcessVerb::Execute+0x31 (FPO: [Non-Fpo])
02c7fcf8 747f5f95 00de7fb0 00daed3c 00000000 windows_storage!CBindAndInvokeStaticVerb::_DoCommand+0xe4 (FPO: [Non-Fpo])
02c7fd1c 747f5ca3 00000000 00000000 747f5b70 windows_storage!CBindAndInvokeStaticVerb::_TryCreateProcessDdeHandler+0x34 (FPO: [Non-Fpo])
02c7fe1c 7556998c 00dd74a0 01105880 00db02b8 windows_storage!CBindAndInvokeStaticVerb::Execute+0x133 (FPO: [1,57,4])
02c7fe4c 7556984c 00dd08b0 01105880 00000000 SHELL32!CShellExecute::_ExecuteAssoc+0xb7 (FPO: [Non-Fpo])
02c7fe70 755f0ada 02c7ff00 771e3bea 00db02b8 SHELL32!CShellExecute::_DoExecute+0x84 (FPO: [Non-Fpo])
02c7fe78 771e3bea 00db02b8 771e3b20 771e3b20 SHELL32!MarshalToGIT+0xa1 (FPO: [Non-Fpo])
02c7ff00 74d4dea4 00c9fcf4 74d4de80 b730151b shcore!CTSimpleArray<Microsoft::WRL::ComPtr<IWindowMonitorChangeListener>,4294967294,CTPolicyCoTaskMem<Microsoft::WRL::ComPtr<IWindowMonitorChangeListener> >,CSimpleArrayStandardCompareHelper<Microsoft::WRL::ComPtr<IWindowMonitorChangeListener> >,CSimpleArrayStandardMergeHelper<Microsoft::WRL::ComPtr<IWindowMonitorChangeListener> > >::_Add<Microsoft::WRL::ComPtr<IWindowMonitorChangeListener> const &>+0x120 (FPO: [Non-Fpo])
02c7ff14 772805ae 00c9fcf4 e2a6d8a3 00000000 KERNEL32!BaseThreadInitThunk+0x24 (FPO: [Non-Fpo])
02c7ff5c 7728057d ffffffff 772c6ea2 00000000 ntdll!__RtlUserThreadStart+0x2b (FPO: [Non-Fpo])
02c7ff6c 00000000 771e3b20 00c9fcf4 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])


//explorer.exe
ChildEBP RetAddr Args to Child
0adbeb98 74c48618 0adbef0c 0adbeeb4 02000000 ntdll!NtCreateUserProcess (FPO: [11,0,0])
0adbf160 74c70d7c 00000000 0c191c0c 0cd503a0 KERNELBASE!CreateProcessInternalW+0x8d8 (FPO: [SEH])
0adbf198 747f43a2 0c191c0c 0cd503a0 00000000 KERNELBASE!CreateProcessW+0x2c (FPO: [Non-Fpo])
0adbf20c 747f4287 0001016c 0c190890 00000001 windows_storage!CInvokeCreateProcessVerb::_CallCreateProcess+0xc5 (FPO: [0,13,4])
0adbf23c 747f3f86 00000001 0c190890 00000001 windows_storage!CInvokeCreateProcessVerb::_PrepareAndCallCreateProcess+0x189 (FPO: [Non-Fpo])
0adbf24c 747f4fc4 0c190898 0c190898 0ae82468 windows_storage!CInvokeCreateProcessVerb::_TryCreateProcess+0x21 (FPO: [0,0,4])
0adbf270 747f3dd1 0c190898 747f3da0 0adbf2a8 windows_storage!CInvokeCreateProcessVerb::_DoApplication+0xac (FPO: [Non-Fpo])
0adbf280 747f5a7e 0c190898 0c190890 0ae82468 windows_storage!CInvokeCreateProcessVerb::Execute+0x31 (FPO: [Non-Fpo])
0adbf2a8 747f5f95 0c190898 0c100e4c 00000000 windows_storage!CBindAndInvokeStaticVerb::_DoCommand+0xe4 (FPO: [Non-Fpo])
0adbf2cc 747f5ca3 00000000 0adbf480 747f5b70 windows_storage!CBindAndInvokeStaticVerb::_TryCreateProcessDdeHandler+0x34 (FPO: [Non-Fpo])
0adbf3c4 7485bbed 0adbf3f0 748001b9 0ae82470 windows_storage!CBindAndInvokeStaticVerb::Execute+0x133 (FPO: [1,57,4])
0adbf3f0 747fff57 0adbf480 0c100e4c 747fff80 windows_storage!_InitCommandExec+0x8a (FPO: [Non-Fpo])
0adbf418 747fff98 0adbf480 0c100e4c 00000000 windows_storage!CRegDataDrivenCommand::_Invoke+0xcb (FPO: [Non-Fpo])
0adbf42c 75581238 0bfd741c 0adbf480 0c100e4c windows_storage!CRegDataDrivenCommand::InvokeFromContextMenu+0x18 (FPO: [Non-Fpo])
0adbf458 7557d9b5 0adbf480 00000000 0adbf7a0 SHELL32!CRegistryVerbsContextMenu::_Execute+0x7d (FPO: [Non-Fpo])
0adbf6d0 755e1d88 0c07724c 0adbf700 0cd5c2a0 SHELL32!CRegistryVerbsContextMenu::InvokeCommand+0x95 (FPO: [2,151,4])
0adbf750 755a7e9f 0adbf7a0 0adbf7a4 0cd5c2a0 SHELL32!HDXA_LetHandlerProcessCommandEx+0xd2 (FPO: [Non-Fpo])
0adbfa3c 75924fbc 0cd5c2a0 0adbfa58 0c0944e8 SHELL32!CDefFolderMenu::InvokeCommand+0xff (FPO: [2,179,4])
0adbfbb8 759248c2 0cd5c2a0 04000100 00000801 SHELL32!SHInvokeCommandOnContextMenu2+0x1bf (FPO: [Non-Fpo])
0adbfbf8 771e3bea 0c0944e8 771e3b20 771e3b20 SHELL32!s_DoInvokeVerb+0xa2 (FPO: [Non-Fpo])
0adbfc80 74d4dea4 00f2e014 74d4de80 e8fe584e shcore!CTSimpleArray<Microsoft::WRL::ComPtr<IWindowMonitorChangeListener>,4294967294,CTPolicyCoTaskMem<Microsoft::WRL::ComPtr<IWindowMonitorChangeListener> >,CSimpleArrayStandardCompareHelper<Microsoft::WRL::ComPtr<IWindowMonitorChangeListener> >,CSimpleArrayStandardMergeHelper<Microsoft::WRL::ComPtr<IWindowMonitorChangeListener> > >::_Add<Microsoft::WRL::ComPtr<IWindowMonitorChangeListener> const &>+0x120 (FPO: [Non-Fpo])
0adbfc94 772805ae 00f2e014 efb9975f 00000000 KERNEL32!BaseThreadInitThunk+0x24 (FPO: [Non-Fpo])
0adbfcdc 7728057d ffffffff 772c6e94 00000000 ntdll!__RtlUserThreadStart+0x2b (FPO: [Non-Fpo])
0adbfcec 00000000 771e3b20 00f2e014 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])

这两个函数均由SHELL32.dll导出,且执行结果可以和COM程序交互(不知道这么理解对不对)这种情况下就需要先初始化com CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE) 对于不需要这种交互的可以不执行com初始化。
且这两个api可以通过设置操作类型“open”利用注册表关联文件的默认打开方式,简单的说就是你能通过鼠标双击或则右键打开的 应该都可以通过这两个api实现,比如说打印文件、打开文件夹、以管理员权限运行之类的。通过上面的堆栈信息也可以看出我们通过explorer.exe即双击执行的应该就是ShellExecuteEx这个api实现的。
还有最重要的一点是在dllmain中使用这两个函数会造成死锁,MSDN原文是When DLLs are loaded into your process, you acquire a lock known as a loader lock. The DllMain function always executes under the loader lock. It is important that you do not call ShellExecuteEx while you hold a loader lock. Because ShellExecuteEx is extensible, you could load code that does not function properly in the presence of a loader lock, risking a deadlock and therefore an unresponsive thread.
虽然只是ShellExecuteEx有说明但两个都可能会出现。

CreateProcess

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
BOOL CreateProcess(
LPCTSTR lpApplicationName, // name of executable module
LPTSTR lpCommandLine, // command line string
LPSECURITY_ATTRIBUTES lpProcessAttributes, // SD
LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD
BOOL bInheritHandles, // handle inheritance option
DWORD dwCreationFlags, // creation flags
LPVOID lpEnvironment, // new environment block
LPCTSTR lpCurrentDirectory, // current directory name
LPSTARTUPINFO lpStartupInfo, // startup information
LPPROCESS_INFORMATION lpProcessInformation // process information);
ChildEBP RetAddr Args to Child
005ff728 74c48618 005ffa9c 005ffa44 02000000 ntdll!NtCreateUserProcess (FPO: [11,0,0])
005ffcf0 74c49e4b 00000000 007a01c0 00000000 KERNELBASE!CreateProcessInternalW+0x8d8 (FPO: [SEH])
005ffdd8 74c6f8fc 00000000 005ffedc 00000000 KERNELBASE!CreateProcessInternalA+0x11b (FPO: [Non-Fpo])
005ffe10 013c112d 005ffedc 00000000 00000000 KERNELBASE!CreateProcessA+0x2c (FPO: [Non-Fpo])

CreateProcessAsUser
CreateProcessWithLogonW
CreateProcessWithTokenW

CreateProcess参数略多使用较复杂,但是是最通用一个,比如说上面在dllmain中使用ShellExecuteEx会造成死锁就可以直接用这个函数替换。并且其他几个函数最终都会调用CreateProcess。
当启动一个带参数启动的应用程序时候正确的的写法CreateProcess的命令行参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
TCHAR szPath[MAX_PATH] = {L"C:\\Windows\\System32\\rundll32.exe"};
TCHAR szCmdLine[MAX_PATH] = {
L"C:\\Windows\\System32\\rundll32.exe"
L" D:\\Test.dll,TestFunc" // 注意前面的空格
};
STARTUPINFO si = {sizeof(si)};
PROCESS_INFORMATION pi = {0};
BOOL bRet = FALSE;

bRet = CreateProcess(
szPath,
szCmdLine,
NULL,
NULL,
FALSE,
CREATE_NEW_CONSOLE,
NULL,
NULL,
&si,
&pi);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);

还有另外一种就是szPath设置为NULL,想过和这种写法一样。

上一篇: Http协议初学
下一篇: 读书计划