Windows

1.跨进程使用句柄

先创建两个MFC的进程分别为A,B

A:

img

B:

img

使用方式

(1)继承方式

父进程打开的句柄继承给子进程使用

img

父进程的句柄是否继承给子进程使用

img

判断句柄是否可以被继承(安全属性) 第一个为进程句柄 第二个为线程句柄

若安全属性为true 那么当createprocess为true时句柄会传给子进程 为FALSE时句柄不会传给子进程

但若安全属性为false时 无论createprocess为true还是false都不会传给子进程

img

A:

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
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
SECURITY_ATTRIBUTES sa = {};
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;//进程允许被继承

// Start the child process.
if (!CreateProcessW(TEXT("C:\\vs\\B\\x64\\Debug\\B.exe"), // No module name (use command line)
NULL, // Command line
&sa, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi) // Pointer to PROCESS_INFORMATION structure
)
{
AfxMessageBox(_T("CreateProcess failed"));
return;
}

CString strFmt;
strFmt.Format(L"%08X", pi.hProcess);
SetDlgItemText(EDT_BHDANDLE, strFmt);
UpdateWindow();//当A进程创建B进程之后不会立即显示句柄 通过这个API使得创建B进程之后就显示句柄
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);//closehandle 关闭不需要的句柄防止信息泄露(会报错)

B:

1
2
3
4
5
6
7
8
void CBDlg::OnBnClickedButton1()
{
// TODO: 在此添加控件通知处理程序代码
CString str;
GetDlgItemText(EDT_BHANDLE, str);
HANDLE hBProc = (HANDLE)strtoul(str.GetBuffer(), NULL, 16);
TerminateProcess(hBProc, 0);
}

若由A进程启动B进程 B进程关闭A进程 A启动B进程获取的句柄 在B进程启动之前 与B进程无关 B没有继承A的句柄

This is an image

A进程创建两次B进程 B1并没有继承A的句柄 而B2继承了A的句柄 使得B2可以关闭B1(同理B2的进程需要B3来关闭)

(2)拷贝方式

将句柄拷贝到指定进程,无视父子进程

img

参数1、2:原进程被拷贝的句柄

参数3:目标进程的句柄

参数4:拷贝到目标进程后句柄的值

参数5:拷贝到目标进程的句柄的权限

参数6:拷贝出来的新句柄是否被继承

拷贝的句柄所具有的权限 若为same 则与原句柄相同

img

1
2
3
4
5
6
7
8
//将句柄拷贝给B进程
HANDLE hBProc = NULL;
DuplicateHandle(GetCurrentProcess(),pi.hProcess,
pi.hProcess,&hBProc,
0,
FALSE,
DUPLICATE_SAME_ACCESS
);//拷贝出来的句柄,与自己的权限相同

全部代码:

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
void CADlg::OnBnClickedButton1()
{

HANDLE hCurProc = GetCurrentProcess();
HANDLE hCurThread = GetCurrentThread();
//TerminateProcess((HANDLE)-1, 0);
// TODO: 在此添加控件通知处理程序代码
STARTUPINFO si;
PROCESS_INFORMATION pi;

ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
SECURITY_ATTRIBUTES sa = {};
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;//进程允许被继承

// Start the child process.
if (!CreateProcessW(TEXT("C:\\vs\\B\\x64\\Debug\\B.exe"), // No module name (use command line)
NULL, // Command line
&sa, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi) // Pointer to PROCESS_INFORMATION structure
)
{
AfxMessageBox(_T("CreateProcess failed"));
return;
}
//将句柄拷贝给B进程
HANDLE hBProc = NULL;
DuplicateHandle(GetCurrentProcess(),pi.hProcess,
pi.hProcess,&hBProc,
0,
FALSE,
DUPLICATE_SAME_ACCESS
);//拷贝出来的句柄,与自己的权限相同

CString strFmt;
strFmt.Format(L"%08X", pi.hProcess);
SetDlgItemText(EDT_BHDANDLE, strFmt);
UpdateWindow();

WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}


void CADlg::OnEnChangeBhdandle()
{
// TODO: 如果该控件是 RICHEDIT 控件,它将不
// 发送此通知,除非重写 CDialogEx::OnInitDialog()
// 函数并调用 CRichEditCtrl().SetEventMask(),
// 同时将 ENM_CHANGE 标志“或”运算到掩码中。

// TODO: 在此添加控件通知处理程序代码
}

(3)伪句柄

伪句柄仅限作用于当前线程\进程

通过这两个API获取的这两个句柄的值一直都是不变的

1
2
GetCurrentProcess()为-1 0xffffffff
GetCurrentThread()为-2 0xfffffffe

img

不管怎么调用 值都不变

上述两个即为伪句柄

2.跨进程操作内存

img

参数1:句柄

参数2:地址

参数3:数据的缓冲区

参数4:写的数据的大小

参数5:写入的数据的字节数若为NULL则忽略

获取句柄:
img

参数1:权限

img

参数2:安全属性

参数3:进程ID

获取进程ID:

img

但是需要获取窗口句柄

获取窗口句柄:

img

若无窗口句柄 则换成遍历寻找进程名 或者路径 (不同的API)

修改的地址为只读不能写 通过VirtualProtectEx 这个API修改

img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
HWND hWndGame = FindWindow(NULL,"Visual Studio Installer");
if (hWndGame == NULL) {
cout << "获取窗口句柄失败" << endl;
return 0;
}

DWORD dwProId = 0;
DWORD dwThreadId = GetWindowThreadProcessId( hWndGame, &dwProId);

if (dwThreadId == 0)
{
cout << "获取线程ID失败" << endl;
return 0;
}
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProId);
if (hProc == NULL)
{
cout << "获取进程句柄失败" << endl;
return 0;
}

修改内存数据:

1
2
3
4
5
6
7
LPVOID pAddrGod = (LPVOID)0x00227526;
BYTE bt = 0xF5;
DWORD dwOldProc = 0;
BOOL bRet = WriteProcessMemory(hProc, pAddrGod, &bt,sizeof(bt),NULL);
if (!bRet) {
cout << "无敌失败" << endl;
}

img

img

参数4:新修改的属性

参数5:没改之前的属性

Windows内存以分页形式进行管理 在修改内存属性时会影响整个分页 从而使内存大小发生改变

同内存属性的内存是连在一起的 不同属性拆开

1
2
3
4
5
6
7
8
9
10
11
12
13
14
LPVOID pAddrGod = (LPVOID)0x00227526;
BYTE bt = 0xF5;
DWORD dwOldProc = 0;
BOOL bRet = VirtualProtectEx(hProc, pAddrGod, sizeof(bt), PAGE_READWRITE, &dwOldProc);
if (!bRet)
{
cout << "修改内存属性失败" << endl;
return 0;
}
bRet = WriteProcessMemory(hProc, pAddrGod, &bt, sizeof(bt),NULL);
if (!bRet) {
cout << "无敌失败" << endl;
}
VirtualProtectEx(hProc, pAddrGod, sizeof(bt), dwOldProc, &dwOldProc);//将修改的内存属性复原