WindowsAPI编程核心技术-启动技术

创建进程

WinExec

运行指定的应用程序。

1
2
3
4
5
6
UINT WINAPI WinExec(
_In_ LPCTSTR lpCmdLine,
//要执行的应用程序命令行
_In_ UINT uCmdShow
//显示选项 SW_HIDE隐藏窗口 SW_SHOWNORMAL激活
)//成功返回值大于31 失败返回0系统内存资源不足、ERROR_BAD_FORMAT文件无效 ERROR_FILE_NOT_FOUND找不到指定文件 ERROR_PATH_NOT_FOUND找不到指定路径

ShellExecute

运行一个外部程序或打开一个已注册的文件/目录或打印一个文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
HINSTANCE ShellExecute(
_In_opt_ HWND hwnd,
//父窗口句柄
_In_opt_ LPCTSTR lpOperation,
//要执行的操作,sz类型,有edit explore find open print
_In_ LPCTSTR lpFile,
//文件或对象
_In_opt_ LPCTSTR lpParamters,
//lpFile指定为可执行文件时为命令行传参 否则为NULL
_In_opt_ LPCTSTR lpDirectory,
//默认目录 NULL为当前工作目录
_In_ INT nShowCmd
//如何显示 SW_HIDE隐藏 SW_SHOWNORMAL激活
)//成功返回值大于32 失败返回错误值

CreateProcess

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
BOOL WINAPI CreateProcess(
_In_opt_ LPCTSTR lpApplicationName,
//要执行的模块名称
_Inout_opt_ LPCTSTR lpCommandLine,
//要执行的命令行
_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
//是否可以由子进程继承返回的新进程对象的句柄
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
//同上,线程
_In_ BOOL bInheritHandles,
//新进程是否继承调用进程中每个可继承句柄
_In_ DWORD dwCreationFlags,
//控制优先级和创建进程 CREATE_NEW_CONSOLE新进程使用一个新的控制台 CREATE_SUSPENDED主线程以暂停状态来创建
_In_opt LPVOID lpEnvironment,
//新进程的环境块 NULL则使用调用进程的环境
_In_opt LPCTSTR lpCurrentDirectory,
//当前目录完整路径 NULL则新进程具有与调用进程相同的当前驱动器和目录
_In_ LPSTARTUPINFO lpStartupInfo,
//?
_Out_ LPROCESS_INFORMATION lpProcessInformation
//接收有关新进程的标识信息
)//成功返回值非0 失败为0

例子

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
BOOL WinExec_Test(PCHAR pszExePath, UINT uiCmdShow) {
UINT uiRet = 0;
uiRet = ::WinExec(pszExePath, uiCmdShow);
if (32 < uiRet)
return TRUE;
return FALSE;
};
BOOL ShellExecute_Test(PWCHAR pszExePath, UINT uiCmdShow) {
HINSTANCE hInstance = 0;
hInstance = ::ShellExecute(NULL, NULL, pszExePath, NULL, NULL, uiCmdShow);
if (32 < (DWORD)hInstance)
return TRUE;
return FALSE;
};
BOOL CreateProcess_Test(PWCHAR pszExePath, UINT uiCmdShow) {
STARTUPINFO si = { 0 };
PROCESS_INFORMATION pi;
BOOL bRet = FALSE;
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = uiCmdShow;
bRet = ::CreateProcess(NULL, pszExePath, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
if (bRet) {
::CloseHandle(pi.hThread);
::CloseHandle(pi.hProcess);
return TRUE;
};
return FALSE;
};

突破SESSION0隔离创建用户进程

服务创建

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
#include <Shlwapi.h>
BOOL SystemServiceOperate(PWCHAR lpszExePath, INT iOperateType) {
BOOL bRet = TRUE;
WCHAR szName[MAX_PATH] = { 0 };
::lstrcpy(szName, lpszExePath);
// 过滤掉文件目录,获取文件名
::PathStripPath(szName);
SC_HANDLE shOSCM = NULL, shCS = NULL;
SERVICE_STATUS ss;
DWORD dwErrorCode = 0;
BOOL bSuccess = FALSE;
// 打开服务控制管理器数据库
shOSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (!shOSCM)
return FALSE;
if (0 != iOperateType) {
// 打开一个已经存在的服务
shCS = ::OpenService(shOSCM, szName, SERVICE_ALL_ACCESS);
if (!shCS) {
::CloseServiceHandle(shOSCM);
shOSCM = NULL;
return FALSE;
};
};
switch (iOperateType) {
case 0: {
// 创建服务
// SERVICE_AUTO_START 随系统自动启动
// SERVICE_DEMAND_START 手动启动
shCS = ::CreateService(shOSCM, szName, szName, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, lpszExePath, NULL, NULL, NULL, NULL, NULL);
if (!shCS)
bRet = FALSE;
break;
};
case 1: {
// 启动服务
if (!::StartService(shCS, 0, NULL))
bRet = FALSE;
break;
};
case 2: {
//停止服务
if (!::DeleteService(shCS))
bRet = FALSE;
break;
};
default:
break;
};
if (shCS) {
::CloseServiceHandle(shCS);
shCS = NULL;
};
if (shOSCM) {
::CloseServiceHandle(shOSCM);
shOSCM = NULL;
};
return bRet;
};

WTSGetActiveConsoleSessionId

获取当前程序会话ID。

1
2
DWORD WTSGetActiveConsoleSessionId(void)
//成功返回会话标识符 失败返回0xFFFFFFFF

WTSQueryUserToken

检索用户令牌,获取对应用户令牌句柄。

1
2
3
4
5
6
BOOL WTSQueryUserToken(
_In_ ULONG SessionId,
//远程桌面服务会话标识符 在服务上下文中运行的任何程序都为0
_Out_ PHANDLE phToken
//指向登录用户令牌句柄指针
)//成功非0 失败0

DuplicateTokenEx

复制新的访问令牌。

1
2
3
4
5
6
7
8
9
10
11
12
13
BOOL WINAPI DuplicateTokenEx(
_In_ HANDLE hExistingToken,
_In_ DWORD dwDesiredAccess,
//请求权限 最大MAXIMUM_ALLOWED
_In_opt_ LPSECURITY_ATTRIBUTES lpTokenAttributes,
//安全描述符
_In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
//模拟级别
_In_ TOKEN_TYPE TokenType,
//新令牌类型
_Out_ PHANDLE phNewToken
//接收新令牌
)//成功非0 失败0

CreateEnvironmentBlock

检索用户环境变量。

1
2
3
4
5
6
7
8
BOOL WINAPI CreateEnvironmentBlock(
_Out_ LPVOID* lpEnvironment,
//新环境块
_In_opt_ HANDLE hToken,
//令牌
_In_ BOOL hInherit
//是否可继承当前进程环境
)//成功TRUE 失败FALSE

CreateProcessAsUser

在指定令牌用户安全上下文中创建新进程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
BOOL WINAPI CreateProcessAsUser(
_In_opt_ HANDLE hToken,
//用户主令牌
_In_opt_ LPCTSTR lpApplicationName,
//要执行的模块名称
_Inout_opt_ LPTSTR lpCommandLine,
//要执行的命令行
_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
//新进程安全描述符
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
//新线程安全描述符
_In_ BOOL bInheritHandles,
//TRUE每个可继承句柄都被继承 FALSE都不可
_In_ DWORD dwCreationFlags,
//控制优先级和进程创建
_In_opt_ LPVOID lpEnvironment,
//新进程环境快
_In_opt_ LPCTSTR lpCurrentDirectory,
//进程当前目录
_In_ LPSTARTUPINFO lpStartupInfo,
_Out_ LPROCESS_INFORMATION lpProcessInformation
//接收新进程标识信息
)//成功非0 失败0

例子

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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#include <UserEnv.h>
#include <WtsApi32.h>
#include <tchar.h>
#pragma comment(lib, "UserEnv.lib")
#pragma comment(lib, "WtsApi32.lib")
VOID APIENTRY ServiceMain(DWORD dwArgc, PCHAR lpszArgv);
VOID APIENTRY ServiceCtrlHandle(DWORD dwOperateCode);
VOID DoTask(VOID);
// 显示消息对话框
VOID ShowMessage(PTCHAR lpszMessage, PTCHAR lpszTitle);
// 创建用户进程
BOOL CreateUserProcess(PWCHAR lpszFileName);
// 全局变量
WCHAR g_szServiceName[MAX_PATH] = TEXT("CreateProcessAsUser_Test.exe"); // 服务名称
SERVICE_STATUS g_ServiceStatus = { 0 };
SERVICE_STATUS_HANDLE g_ServiceStatusHandle = { 0 };
DWORD _tmain(IN DWORD argc, IN PTCHAR argv[]) {
UNREFERENCED_PARAMETER(argc);
UNREFERENCED_PARAMETER(argv);
// 注册服务入口函数
SERVICE_TABLE_ENTRY stDispatchTable[] = { {g_szServiceName, (LPSERVICE_MAIN_FUNCTION)ServiceMain }, { NULL, NULL } };
::StartServiceCtrlDispatcher(stDispatchTable);
return 0;
};
VOID APIENTRY ServiceMain(DWORD dwArgc, PCHAR lpszArgv) {
g_ServiceStatus.dwServiceType = SERVICE_WIN32;
g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwServiceSpecificExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
g_ServiceStatus.dwWaitHint = 0;
g_ServiceStatusHandle = ::RegisterServiceCtrlHandler(g_szServiceName, ServiceCtrlHandle);
g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
g_ServiceStatus.dwCheckPoint = 0;
g_ServiceStatus.dwWaitHint = 0;
::SetServiceStatus(g_ServiceStatusHandle, &g_ServiceStatus);
// 自己程序实现部分代码放在这里
DoTask();
return;
};
VOID APIENTRY ServiceCtrlHandle(DWORD dwOperateCode) {
switch (dwOperateCode) {
case SERVICE_CONTROL_PAUSE: {
// 暂停
g_ServiceStatus.dwCurrentState = SERVICE_PAUSED;
break;
};
case SERVICE_CONTROL_CONTINUE: {
// 继续
g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
break;
};
case SERVICE_CONTROL_STOP: {
// 停止
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwCheckPoint = 0;
g_ServiceStatus.dwWaitHint = 0;
::SetServiceStatus(g_ServiceStatusHandle, &g_ServiceStatus);
break;
};
case SERVICE_CONTROL_INTERROGATE:
// 询问
break;
default:
break;
};
return;
};
VOID DoTask(VOID) {
// 自己程序实现部分代码放在这里
// 显示对话框
ShowMessage((PTCHAR)"Hi Demon·Gan\nThis Is From Session 0 Service!\n", (PTCHAR)"HELLO");
// 创建用户桌面进程
CreateUserProcess((PTCHAR)"C:\\Users\\DemonGan\\Desktop\\520.exe");
/*
* 上述所用PTCHAR强制类型转换不建议,建议使用以下方法将const PCHAR转PTCHAR:
* DWORD len1=::MultiByteToWideChar(CP_ACP,0,"xxx",-1,NULL,0);
* PTCHAR message=new TCHAR[len1];
* ::MultiByteToWideChar(CP_ACP,0,"xxx",-1,message,len1);
* //...
* delete[] message;
*/
return;
};
VOID ShowMessage(PTCHAR lpszMessage, PTCHAR lpszTitle) {
// 获取当前的Session ID
DWORD dwSessionId = ::WTSGetActiveConsoleSessionId();
// 显示消息对话框
DWORD dwResponse = 0;
::WTSSendMessage(WTS_CURRENT_SERVER_HANDLE, dwSessionId, lpszTitle, (1 + ::lstrlen(lpszTitle)), lpszMessage, (1 + ::lstrlen(lpszMessage)), 0, 0, &dwResponse, FALSE);
return;
};
// 突破SESSION 0隔离创建用户进程
BOOL CreateUserProcess(PWCHAR lpszFileName) {
BOOL bRet = TRUE;
DWORD dwSessionID = 0;
HANDLE hToken = NULL;
HANDLE hDuplicatedToken = NULL;
LPVOID lpEnvironment = NULL;
STARTUPINFO si = { 0 };
PROCESS_INFORMATION pi = { 0 };
si.cb = sizeof(si);
do {
// 获得当前Session ID
dwSessionID = ::WTSGetActiveConsoleSessionId();
// 获得当前Session的用户令牌
if (FALSE == ::WTSQueryUserToken(dwSessionID, &hToken)) {
ShowMessage((PTCHAR)"WTSQueryUserToken", (PTCHAR)"ERROR");
bRet = FALSE;
break;
};
// 复制令牌
if (FALSE == ::DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hDuplicatedToken)) {
ShowMessage((PTCHAR)"DuplicateTokenEx", (PTCHAR)"ERROR");
bRet = FALSE;
break;
};
// 创建用户Session环境
if (FALSE == ::CreateEnvironmentBlock(&lpEnvironment, hDuplicatedToken, FALSE)) {
ShowMessage((PTCHAR)"CreateEnvironmentBlock", (PTCHAR)"ERROR");
bRet = FALSE;
break;
};
// 在复制的用户Session下执行应用程序,创建进程
if (FALSE == ::CreateProcessAsUser(hDuplicatedToken, lpszFileName, NULL, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT, lpEnvironment, NULL, &si, &pi)) {
ShowMessage((PTCHAR)"CreateProcessAsUser", (PTCHAR)"ERROR");
bRet = FALSE;
break;
};
} while (FALSE);
// 关闭句柄, 释放资源
if (lpEnvironment)
::DestroyEnvironmentBlock(lpEnvironment);
if (hDuplicatedToken)
::CloseHandle(hDuplicatedToken);
if (hToken)
::CloseHandle(hToken);
return bRet;
};

内存直接加载运行

略。