[toc]

使用C语言在windows中执行远程线程

1. C语言中的多线程简单使用thrd_create

注意:使用多线程标准库需要C语言C11以上的版本,编译程序时候需选择MTD/MT。

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
#include <stdio.h>
#include <stdlib.h>
#include <threads.h>
#include <windows.h>

// 新线程要执行的代码
int ThreadFunction(void* arg)
{
int thread_id = *((int*)arg);
for (int i = 0; i < 10; i++)
{
Sleep(1000);
printf("线程 %d 打印次数 %d...\n", thread_id,i+1);
}
printf("线程 %d 结束\n", thread_id);
return 0;
}

int main()
{
//创建一个新的进程
thrd_t threads;
int thread_ids = 1;
if (thrd_create(&threads, ThreadFunction, &thread_ids) != thrd_success) {
perror("创建线程失败");
exit(EXIT_FAILURE);
}
for (int i = 0; i < 10; i++)
{
Sleep(1000);
printf("主线程正在运行打印次数 %d...\n", i+1);
}
// 等待线程结束
thrd_join(threads, NULL);
printf("所有线程已结束\n");
return 0;
}

2. windows程序中的多线程CreateThread

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
#include <stdio.h>
#include <windows.h>


DWORD WINAPI print2(LPVOID lpParam) {
for (int i = 0; i < 10; i++) {
printf("线程 1 打印次数 %d...\n", i + 1);
Sleep(1000);
}
return 0;
}

DWORD WINAPI print1(LPVOID lpParam) {
for (int i = 0; i < 10; i++) {
printf("线程 2 打印次数 %d...\n", i + 1);
Sleep(1000);
}
return 0;
}

int main()
{
// 创建两个线程
HANDLE hThread1 = CreateThread(NULL, 0, print1, NULL, 0, NULL);
HANDLE hThread2 = CreateThread(NULL, 0, print2, NULL, 0, NULL);

// 等待两个线程结束
WaitForSingleObject(hThread1, INFINITE);
WaitForSingleObject(hThread2, INFINITE);

// 关闭线程句柄
CloseHandle(hThread1);
CloseHandle(hThread2);

return 0;
}

运行结果符合预期

3.windows中的远程线程使用CreateRemoteThread给自身创建线程

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
#include <stdio.h>
#include <windows.h>


DWORD WINAPI print2(LPVOID lpParam) {
for (int i = 0; i < 10; i++) {
printf("线程 1 打印次数 %d...\n", i + 1);
Sleep(1000);
}
return 0;
}

DWORD WINAPI print1(LPVOID lpParam) {
for (int i = 0; i < 10; i++) {
printf("线程 2 打印次数 %d...\n", i + 1);
Sleep(1000);
}
return 0;
}

int main()
{
DWORD NumberOfByte;
// 创建两个线程
HANDLE hThread1 = CreateRemoteThread(-1, NULL, 0,
(LPTHREAD_START_ROUTINE)print1, NULL, 0,
&NumberOfByte);
HANDLE hThread2 = CreateRemoteThread(-1, NULL, 0,
(LPTHREAD_START_ROUTINE)print1, NULL, 0,
&NumberOfByte);
// 等待两个线程结束
WaitForSingleObject(hThread1, INFINITE);
WaitForSingleObject(hThread2, INFINITE);

// 关闭线程句柄
CloseHandle(hThread1);
CloseHandle(hThread2);

return 0;
}

运行结果与之前使用CreateThread的效果相同

使用C语言在windows中创建新的进程

在windows创建新的进程有以下几种方法

  1. 可以使用鼠标双击运行可执行文件
  2. 在控制台中使用shell命令根据绝对路径运行,Win+R快捷键,任务管理器中的Run New Task.
  3. 使用win32api..

1.使用WinExec创建进程

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
#include <windows.h>


int main()
{
WinExec("calc.exe", SW_SHOW);
return 0;
}

2.使用ShellExecute运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
#include <windows.h>


int main()
{
ShellExecute(
NULL, //指定父窗口句柄
TEXT("open"), //指定动作, 譬如: open、runas、print、edit、explore、find[2]
TEXT("D:\\test\\CC++\\c生万物之windows程序开发\\C+windows\\Debug\\Message.exe"), //指定要打开的文件或程序
NULL, //给要打开的程序指定参数;
NULL, //缺省目录
SW_SHOWDEFAULT //打开选项
);
return 0;
}

3.使用ShellExecuteEx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
#include <windows.h>


int main()
{
SHELLEXECUTEINFO info;
memset(&info, 0, sizeof(info));

info.cbSize = sizeof(info);
info.lpVerb = TEXT("open");
info.lpFile = TEXT("D:\\test\\CC++\\c生万物之windows程序开发\\C+windows\\Debug\\Message.exe");
info.lpParameters = NULL;
info.fMask = SEE_MASK_NOCLOSEPROCESS;
info.nShow = SW_SHOWDEFAULT;
ShellExecuteEx(&info);
return 0;
}

4.使用CreateProcessW

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
#include <windows.h>


int main()
{
PROCESS_INFORMATION pi;
STARTUPINFO si;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
si.wShowWindow = SW_SHOW;
si.dwFlags = STARTF_USESHOWWINDOW;
CreateProcess(TEXT("c://windows//system32//calc.exe"), NULL, NULL, FALSE, NULL, NULL, NULL, NULL,
&si, &pi);
return 0;
}

5.使用CreateProcessWithTokenW来创建新的进程

需要管理员权限运行

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
#include <windows.h>

int main(int argc, char** argv)
{

HANDLE hDpToken = NULL;
HANDLE hCurrentToken = NULL;
//open Token
BOOL getCurrentToken = OpenProcessToken(GetCurrentProcess(),
TOKEN_DUPLICATE |
TOKEN_ASSIGN_PRIMARY |
TOKEN_QUERY, &hCurrentToken);
//copy Token
BOOL dpToken = DuplicateTokenEx(hCurrentToken,
TOKEN_ADJUST_DEFAULT |
TOKEN_ADJUST_SESSIONID |
TOKEN_QUERY |
TOKEN_DUPLICATE |
TOKEN_ASSIGN_PRIMARY,
NULL,
SecurityImpersonation,
TokenPrimary,
&hDpToken
);

STARTUPINFO startupInfo = { 0 };
startupInfo.cb = sizeof(STARTUPINFO);
PROCESS_INFORMATION ProcessInfo = { 0 };
//create process
BOOL Ret = CreateProcessWithTokenW(hDpToken,
LOGON_WITH_PROFILE,
L"C:\\Windows\\System32\\cmd.exe",
NULL, 0, NULL, NULL,
&startupInfo,
&ProcessInfo);


return TRUE;
}



6.使用CreateProcessWithTokenW获取其他进程令牌来创建新的进程(system)

  • 被复制的令牌程序如果有system权限,新创建的程序也会拥有system权限,此处选择winlogon
  1. 设置程序拥有Debug权限
  2. 根据进程名称得到进程PID
  3. 打开其他进程令牌并复制
  4. 使用CreateProcessWithTokenW创建新的进程
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
#include <Lmcons.h>
#include <windows.h>
#include <TlHelp32.h>


BOOL SePrivTokenrivilege(HANDLE hToken, LPCTSTR lpszPrivilege, BOOL bEnablePrivilege);
DWORD FindProcessPID(const wchar_t* ProcessName);
int main(int argc, char** argv) {
HANDLE hDpToken = NULL;

HANDLE hCurrentToken = NULL;
BOOL getCurrentToken = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hCurrentToken);
SePrivTokenrivilege(hCurrentToken, L"SeDebugPrivilege", TRUE);

DWORD PID_TO_IMPERSONATE = FindProcessPID(L"winlogon.exe");
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, TRUE, PID_TO_IMPERSONATE);

HANDLE hToken = NULL;
BOOL TokenRet = OpenProcessToken(hProcess,
TOKEN_DUPLICATE |
TOKEN_ASSIGN_PRIMARY |
TOKEN_QUERY, &hToken);

BOOL impersonateUser = ImpersonateLoggedOnUser(hToken);
if (GetLastError() == NULL)
{
RevertToSelf();
}


BOOL dpToken = DuplicateTokenEx(hToken,
TOKEN_ADJUST_DEFAULT |
TOKEN_ADJUST_SESSIONID |
TOKEN_QUERY |
TOKEN_DUPLICATE |
TOKEN_ASSIGN_PRIMARY,
NULL,
SecurityImpersonation,
TokenPrimary,
&hDpToken
);


STARTUPINFO startupInfo = { 0 };
startupInfo.cb = sizeof(STARTUPINFO);
PROCESS_INFORMATION ProcessInfo = { 0 };

BOOL Ret = CreateProcessWithTokenW(hDpToken,
LOGON_WITH_PROFILE,
L"C:\\Windows\\System32\\cmd.exe",
NULL, 0, NULL, NULL,
&startupInfo,
&ProcessInfo);


return TRUE;
}


BOOL SePrivTokenrivilege(HANDLE hToken,LPCTSTR lpszPrivilege,BOOL bEnablePrivilege)
{
LUID luid;

if (!LookupPrivilegeValue(
NULL,
lpszPrivilege,
&luid))
{
return FALSE;
}

TOKEN_PRIVILEGES PrivToken;
PrivToken.PrivilegeCount = 1;
PrivToken.Privileges[0].Luid = luid;
if (bEnablePrivilege)
PrivToken.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
else
PrivToken.Privileges[0].Attributes = 0;


if (!AdjustTokenPrivileges(
hToken,
FALSE,
&PrivToken,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES)NULL,
(PDWORD)NULL))
{
return FALSE;
}

return TRUE;
}


DWORD FindProcessPID(const wchar_t* ProcessName)
{
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 process = { 0 };
process.dwSize = sizeof(process);

if (Process32First(snapshot, &process)) {
do {
if (!wcscmp((const wchar_t*)process.szExeFile, (const wchar_t*)ProcessName))
break;
} while (Process32Next(snapshot, &process));
}

CloseHandle(snapshot);
return process.th32ProcessID;
}