远程线程注入

注入就是在第三方进程不知道或者不允许的情况下将模块或者代码写入对方进程空间,并设法执行的技术。

在安全领域,注入是非常重要的技术手段,已知的注入方式:远程线程注入、APC注入、消息钩子注入、注册表注入、导入表注入、输入法注入等。

思路

直接创建远程线程时只能通过反汇编获得对方函数地址。如果想要执行自己想要的代码就需要注入了。

ThreadProc必须有一个DWORD的返回值,和一个LPVOID的参数,只要满足这个条件就可以作为线程函数使用,LoadLibrary和ThreadProc结构是一样的,那么就可以将LoadLibrary当做远程线程来使用。

每个Windows程序都有一个Kernel32.dll模块,并且所有进程的LoadLibrary函数基地址都是一样的,那么通过自己的Kernel32模块可以获取目标进程的LoadLibrary基地址,然后在目标的进程空间申请私有内存写入参数,在通过远程线程将自己的dll附加到目标进程上。


实现远程注入

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
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
/*进程快照相关api头文件*/
#include<tlhelp32.h>

#define PROCNAME "Project1.exe"

BOOL loadDll(DWORD dwProcessID, const CHAR *szDllPathName) {
HANDLE hProcess;
DWORD strLen;
LPVOID lpAllocAddr;
LPVOID lpLoadAddr;
BOOL bRet;
HMODULE hModule;
HANDLE hThread;

CHAR strBuff[100];

/*获取目标进程句柄*/
hProcess = OpenProcess(PROCESS_ALL_ACCESS, NULL, dwProcessID);
if (hProcess == NULL) {
sprintf_s(strBuff, 100, "OpenProcess Error:%d\n", GetLastError());
OutputDebugString(strBuff);
return FALSE;
}

/* 加一字节保存\0*/
strLen = strlen(szDllPathName) + 1;

/*在目标进程分配私有内存*/
lpAllocAddr = VirtualAllocEx(hProcess, NULL, strLen, MEM_COMMIT, PAGE_READWRITE);
if (lpAllocAddr == NULL) {
OutputDebugString("VirtualAllocEx Error\n");
CloseHandle(hProcess);
return FALSE;
}


/*在私有内存写入参数*/
bRet = WriteProcessMemory(hProcess, lpAllocAddr, szDllPathName, strLen, 0);
if (!bRet) {
OutputDebugString("WriteProcessMemory Error\n");
VirtualFreeEx(hProcess, lpAllocAddr, strLen, MEM_RELEASE);
CloseHandle(hProcess);
return FALSE;
}

/*获取模块句柄*/
hModule = GetModuleHandle("Kernel32.dll");

if (hModule == NULL) {
OutputDebugString("GetModuleHandle Error\n");
VirtualFreeEx(hProcess, lpAllocAddr, strLen, MEM_RELEASE);
CloseHandle(hProcess);
return FALSE;
}

/*获得Loadlibrary基地址*/
lpLoadAddr = GetProcAddress(hModule, "LoadLibraryA");

if (lpLoadAddr == NULL) {
OutputDebugString("GetProcAddress Error\n");
VirtualFreeEx(hProcess, lpAllocAddr, strLen, MEM_RELEASE);
CloseHandle(hProcess);
return FALSE;
}

/*创建远程线程,加载dll*/
hThread = CreateRemoteThread(
hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE)lpLoadAddr,
lpAllocAddr,
0,
NULL
);

if (!hThread) {
OutputDebugString("CreateRemoteThread Error\n");
VirtualFreeEx(hProcess, lpAllocAddr, strLen, MEM_RELEASE);
CloseHandle(hProcess);
return FALSE;
}


VirtualFreeEx(hProcess, lpAllocAddr, strLen, MEM_RELEASE);
CloseHandle(hProcess);
CloseHandle(hThread);

return TRUE;
}

DWORD getProcID(CONST CHAR *szProcName) {
PROCESSENTRY32 enter;
HANDLE hSnapshot;

hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);

if (hSnapshot == INVALID_HANDLE_VALUE) {
OutputDebugString("CreateToolhelp32Snapshot Error\n");
return 0;
}

if (Process32First(hSnapshot, &enter) == TRUE) {
do {
/*如果找到进程则返回PID*/
if (strcmp(enter.szExeFile, szProcName) == 0) {
CloseHandle(hSnapshot);
return enter.th32ProcessID;
}
} while (Process32Next(hSnapshot, &enter) == TRUE);
}

OutputDebugString("Not found!\n");
return 0;
}

int main()
{

DWORD procID;
procID = getProcID(PROCNAME);

if (!procID) {
OutputDebugString("getProcID Error\n");
return 0;
}


loadDll(procID, "D:\\absolution\\temporary\\myDll.dll");

getchar();

return 0;
}




模块注入后,可以通过dll的入口函数的调用原因写一个switch,调用自己想执行的代码

dllmain.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
// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
#include<stdio.h>

void myDllFunc() {
while (true) {
printf("执行注入代码。。。");
Sleep(1000);
}
}

BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
myDllFunc();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}