远程线程(RemoteThread)注入

回顾线程

程序开始运行时,操作系统就创建了这个程序的进程。一个进程中有多个线程,一个线程就是这个进程正在执行的一个任务。比如main函数就在一个线程中执行。

远程线程注入

首先,这篇文章不是讲远程线程DLL注入(但可以说是为其打基础)。在初学Windows API时,我们学到过函数CreateThread,用来在当前进程中创建一个线程。在这里,又有了一个新的函数——CreateRemoteThread,这两个函数不光名字像,参数列表也很相似(后者只是增加了一个目标进程句柄)。

要进行远程线程注入,我们首先要有一个目标,这里就是inject_me.cpp所生成的程序。该程序在不受外界影响的情况下会无限循环下去。

inject_me.cpp

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

DWORD dwProcessId = 0;
DWORD dwThreadId = 0;

VOID TestFunc()
{
while (true)
{
std::cout << "You injected me." << std::endl;
Sleep(1000 * 5);
}
}

DWORD WINAPI ThreadFunc(LPVOID lpParam)
{
while (true)
{
std::cout << std::hex << ((DWORD *)&TestFunc) << std::endl;
std::cout << "PID: " << dwProcessId << " TID: " << dwThreadId << " inject me." << std::endl;
Sleep(1000 * 5);
}
return 0;
}

int main(int argc, const char *argv[])
{
dwProcessId = GetCurrentProcessId();

HANDLE hThread = CreateThread(
NULL,
0,
(LPTHREAD_START_ROUTINE)ThreadFunc,
NULL,
0,
&dwThreadId);

if (hThread != INVALID_HANDLE_VALUE)
{
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
hThread = INVALID_HANDLE_VALUE;
}

return 0;
}

接下来就是最核心的注入程序了。首先最重要的一点就是:进行远程线程注入时,线程执行的函数或者说线程所执行的机器码应该在目标进程(inject_me.exe)中已存在,本文中线程执行的函数就是TestFunc,而Inject函数的参数(目标进程ID,线程函数TestFunc的地址)需要从inject_me.exe中获取。

inject.cpp

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

VOID Inject(DWORD dwTargetProcessId, DWORD dwFuncAddr)
{
HANDLE hTargetProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwTargetProcessId);

if (hTargetProcess == NULL || hTargetProcess == INVALID_HANDLE_VALUE)
{
std::cout << "OpenProcess failed.\n";
return;
}

DWORD dwThreadId = 0;

HANDLE hRemoteThread = CreateRemoteThread(hTargetProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE)dwFuncAddr,
NULL,
NULL,
&dwThreadId);

if (hRemoteThread == NULL || hRemoteThread == INVALID_HANDLE_VALUE)
{
std::cout << "CreateRemoteThread failed.\n";
CloseHandle(hTargetProcess);
return;
}

WaitForSingleObject(hRemoteThread, INFINITE);
CloseHandle(hRemoteThread);
hRemoteThread = NULL;
}

int main(int argc, const char* argv[])
{
Inject(0x78bc, 0x00234539);
return 0;
}

演示

首先运行inject_me.exe,程序会输出00234539为TestFunc的地址,78bc为PID以及TID7704。当我们开始运行inject.exe开始对目标进程inject_me.exe注入,正常情况下目标进程将会新建一个进程,执行TestFunc函数,并输出:You injected me.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
00234539
PID: 78bc TID: 7704 inject me.
00234539
PID: 78bc TID: 7704 inject me.
00234539
PID: 78bc TID: 7704 inject me.
--------------开始注入------------------
00234539
PID: 78bc TID: 7704 inject me.
You injected me.
00234539
PID: 78bc TID: 7704 inject me.
You injected me.
00234539
PID: 78bc TID: 7704 inject me.
You injected me.