DLL注入

概述

DLL远程注入

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
VOID CInjectDllDlg::InjectDll(DWORD dwPid, char *szDllName)
{
if ( dwPid == 0 || lstrlen(szDllName) == 0 )
{
return ;
}
char *pFunName = "LoadLibraryA";
// 打开目标进程
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,
FALSE, dwPid);
if ( hProcess == NULL )
{
return ;
}
// 计算欲注入DLL文件完整路径的长度
int nDllLen = lstrlen(szDllName) + sizeof(char);
// 在目标进程申请一块长度为nDllLen大小的内存空间
PVOID pDllAddr = VirtualAllocEx(hProcess,
NULL, nDllLen,
MEM_COMMIT,
PAGE_READWRITE);
if ( pDllAddr == NULL )
{
CloseHandle(hProcess);
return ;
}
DWORD dwWriteNum = 0;
// 将欲注入DLL文件的完整路径写入在目标进程中申请的空间内
WriteProcessMemory(hProcess, pDllAddr, szDllName,
nDllLen, &dwWriteNum);
// 获得LoadLibraryA()函数的地址
FARPROC pFunAddr = GetProcAddress(GetModuleHandle("kernel32.dll"),
pFunName);
// 创建远程线程
HANDLE hThread = CreateRemoteThread(hProcess,
NULL, 0,
(LPTHREAD_START_ROUTINE)pFunAddr,
pDllAddr, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
CloseHandle(hProcess);
}
void CInjectDllDlg::OnBtnUninject()
{
// TODO: Add your control notification handler code here
char szDllName[MAX_PATH] = { 0 };
char szProcessName[MAXBYTE] = { 0 };
DWORD dwPid = 0;
GetDlgItemText(IDC_EDIT_DLLFILE, szDllName, MAX_PATH);
GetDlgItemText(IDC_EDIT_PROCESSNAME, szProcessName, MAXBYTE);
// 由进程名获得PID
dwPid = GetProcId(szProcessName);
// 注入szDllName到dwPid
UnInjectDll(dwPid, szDllName);
}
VOID CInjectDllDlg::UnInjectDll(DWORD dwPid, char *szDllName)
{
if ( dwPid == 0 || lstrlen(szDllName) == 0 )
{
return ;
}
HANDLE hSnap = CreateToolhelp32Snapshot(
TH32CS_SNAPMODULE,
dwPid);
MODULEENTRY32 me32;
me32.dwSize = sizeof(me32);
// 查找匹配的进程名称
BOOL bRet = Module32First(hSnap, &me32);
while ( bRet )
{
if ( lstrcmp(strupr(me32.szExePath),
strupr(szDllName)) == 0 )
{
break;
}
bRet = Module32Next(hSnap, &me32);
}
CloseHandle(hSnap);
char *pFunName = "FreeLibrary";
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,
FALSE, dwPid);
if ( hProcess == NULL )
{
return ;
}
FARPROC pFunAddr = GetProcAddress(GetModuleHandle("kernel32.dll"),
pFunName);
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE)pFunAddr,
me32.hModule, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
CloseHandle(hProcess);
}

     整个注入与卸载的过程其实就是让远程线程执行一次LoadLibrary()函数或FreeLibrary()函数。

无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
typedef struct _DATA
{
DWORD dwLoadLibrary;
DWORD dwGetProcAddress;
DWORD dwGetModuleHandle;
DWORD dwGetModuleFileName;
char User32Dll[STRLEN];
char MessageBox[STRLEN];
char Str[STRLEN];
}DATA, *PDATA;
DWORD WINAPI RemoteThreadProc(LPVOID lpParam)
{
PDATA pData = (PDATA)lpParam;
// 定义API函数原型
HMODULE (__stdcall *MyLoadLibrary)(LPCTSTR);
FARPROC (__stdcall *MyGetProcAddress)(HMODULE, LPCSTR);
HMODULE (__stdcall *MyGetModuleHandle)(LPCTSTR);
int (__stdcall *MyMessageBox)(HWND, LPCTSTR, LPCTSTR, UINT);
DWORD (__stdcall *MyGetModuleFileName)(HMODULE, LPTSTR, DWORD);
MyLoadLibrary = (HMODULE (__stdcall *)(LPCTSTR))
pData->dwLoadLibrary;
MyGetProcAddress = (FARPROC (__stdcall *)(HMODULE, LPCSTR))
pData->dwGetProcAddress;
MyGetModuleHandle = (HMODULE (__stdcall *)(LPCSTR))
pData->dwGetModuleHandle;
MyGetModuleFileName = (DWORD (__stdcall *)(HMODULE, LPTSTR, DWORD))
pData->dwGetModuleFileName;
HMODULE hModule = MyLoadLibrary(pData->User32Dll);
MyMessageBox = (int (__stdcall *)(HWND, LPCTSTR, LPCTSTR, UINT))
MyGetProcAddress(hModule, pData->MessageBox);
char szModuleFileName[MAX_PATH] = { 0 };
MyGetModuleFileName(NULL, szModuleFileName, MAX_PATH);
MyMessageBox(NULL, pData->Str, szModuleFileName, MB_OK);
return 0;
}
VOID CNoDllInjectDlg::InjectCode(DWORD dwPid)
{
// 打开进程并获取进程句柄
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,
FALSE, dwPid);
if ( hProcess == NULL )
{
return ;
}
DATA Data = { 0 };
// 获取kernel32.dll中相关的导出函数
Data.dwLoadLibrary = (DWORD)GetProcAddress(
GetModuleHandle("kernel32.dll"),
"LoadLibraryA");
Data.dwGetProcAddress = (DWORD)GetProcAddress(
GetModuleHandle("kernel32.dll"),
"GetProcAddress");
Data.dwGetModuleHandle = (DWORD)GetProcAddress(
GetModuleHandle("kernel32.dll"),
"GetModuleHandleA");
Data.dwGetModuleFileName = (DWORD)GetProcAddress(
GetModuleHandle("kernel32.dll"),
"GetModuleFileNameA");
// 需要的其他DLL和导出函数
lstrcpy(Data.User32Dll, "user32.dll");
lstrcpy(Data.MessageBox, "MessageBoxA");
// MessageBoxA()弹出的字符串
lstrcpy(Data.Str, "Inject Code !!!");
// 在目标进程申请空间
LPVOID lpData = VirtualAllocEx(hProcess, NULL, sizeof(Data),
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE);
DWORD dwWriteNum = 0;
WriteProcessMemory(hProcess, lpData, &Data,
sizeof(Data), &dwWriteNum);
// 在目标进程空间申请的用于保存代码的长度
DWORD dwFunSize = 0x1000;
LPVOID lpCode = VirtualAllocEx(hProcess, NULL, dwFunSize,
MEM_COMMIT,
PAGE_EXECUTE_READWRITE);
BOOL bRet = WriteProcessMemory(hProcess, lpCode, &RemoteThreadProc,
dwFunSize, &dwWriteNum);
if ( bRet == FALSE )
{
int n = GetLastError();
}
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE)lpCode,
lpData, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
CloseHandle(hProcess);
}

通过peid可以查看DLL的导出函数

还可以通过vc6自带的dependency Walker以及CFF Explorer

    这种方式是直接把想要使用的API函数以及API函数所在的DLL文件都封装在一个结构体中,直接写入目标进程的空间中,最后调用CreateRemoteThread()函数即可将其运行。

tips

通过windows自带工具运行DLL的两种方法
1.通过regsvr32.exe 调用 例如 regsvr32 /i c:\test.dll
2.通过rundll32.exe 调用 例如 rundll32.exe “c:\test.dll” ,RundllFunc FunParam
3.通过Dependency Walker工具查看应用程序所使用到的动态链接库文件,此外还可以使用dumpbin工具

Reference

神奇的马甲Dll By 海风月影
DLL注入的几种姿势(二):CreateRemoteThread And More