第四章 启动技术
创建进程API
在一个进程中创建并启动一个新进程,最简单的方法无非是直接通过调用WIN32 API函数创建新进程。用户层上,微软提供了WinExec、ShellExecute和CreateProcess等函数来实现进程创建。
WinExec、ShellExecute以及CreateProcess除了可以创建进程外,还能执行CMD命令等功能。
代码实现
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
| #include <SDKDDKVer.h> #include <stdio.h> #include <tchar.h> #include <Windows.h>
BOOL WinExec_Test(char* pszExePath, UINT uiCmdShow) { UINT uiRet = 0; uiRet = ::WinExec(pszExePath, uiCmdShow); if (31 < uiRet) { return TRUE; } return FALSE; }
BOOL ShellExecute_Test(char* pszExePath, UINT uiCmdShow) { HINSTANCE hInstance = 0; hInstance = ::ShellExecute(NULL, NULL, pszExePath, NULL, NULL, uiCmdShow); if (32 < (DWORD)hInstance) { return TRUE; } return FALSE; }
BOOL CreateProcess_Test(char* pszExePath, UINT uiCmdShow) { STARTUPINFO si = { 0 }; PROCESS_INFORMATION pi; BOOL bRet = FALSE; si.cb = sizeof(si); si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = uiCmdShow; bRet = ::CreateProcess(NULL, pszExePath, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi); if (bRet) { ::CloseHandle(pi.hThread); ::CloseHandle(pi.hProcess); return TRUE; } return FALSE; }
int _tmain(int argc, _TCHAR* argv[]) { BOOL bRet = FALSE; bRet = WinExec_Test("C:\\Users\\admin\\Desktop\\C++\\WinExec.exe", SW_SHOWNORMAL); if (bRet) { printf("WinExec.exe Run OK.\n"); } else { printf("WinExec.exe Run ERROR.\n"); } bRet = ShellExecute_Test("C:\\Users\\admin\\Desktop\\C++\\ShellExecute.exe", SW_SHOWNORMAL); if (bRet) { printf("ShellExecute.exe Run OK.\n"); } else { printf("ShellExecute.exe Run ERROR.\n"); } bRet = CreateProcess_Test("C:\\Users\\admin\\Desktop\\C++\\CreateProcess.exe", SW_SHOWNORMAL); if (bRet) { printf("CreateProcess.exe Run OK.\n"); } else { printf("CreateProcess.exe Run ERROR.\n"); }
system("pause"); return 0; }
|
突破SESSION 0隔离创建用户进程(+创建服务)
病毒木马通常会把自已注入系统服务进程或是伪装成系统服务进程,并运行在SESSION 0中。处于SESSION 0中的程序能正常执行普通程序的绝大部分操作,但是个别操作除外。例如,处于SESSION 0中的系统服务进程,无法与普通用户进程通信,不能通过Windows消息机制进行通信,更不能创建普通的用户进程。
从Windows VISTA开始,只有服务可以托管到SESSION 0中,用户应用程序和服务之间会进行隔离。虽然Windows7及以上版本的SESSION 0给服务层和应用层间的通信造成了很大的难度,但这并不代表没有办法实现服务层与应用层间的通信与交互。微软提供了一系列以WTS(Windows Terminal Service,Windows终端服务)开头的函数,从而可以完成服务层与应用层的交互。
实现原理
由于SESSION 0的隔离,使得在系统服务进程内不能直接调用CreateProcess等函数创建进程,而只能通过CreateProcessAsUser函数来创建。这样,创建的进程才会显示UI界面,与用户进行交互。
在SESSION 0中创建用户桌面进程具体的实现流程如下所示:
首先,调用WTSGetActiveConsoleSessionId函数来获取当前程序的会话ID,即Session Id。根据Session Id继续调用WTSQueryUserToken函数来检索用户令牌,并获取对应的用户令牌句柄。在不需要使用用户令牌句柄时,可以调用CloseHandle函数来释放句柄。
其次,使用DuplicateTokenEx函数创建一个新令牌,并复制上面获取的用户令牌。设置新令牌的访问权限为MAXIMUM_ALLOWED,这表示获取所有令牌权限。新访问令牌的模拟级别为SecurityIdentification,而且令牌类型为TokenPrimary,这表示新令牌是可以在CreateProcessAsUser函数中使用的主令牌。
最后,根据新令牌调用CreateEnvironmentBlock函数创建一个环境块,用来传递给CreateProcessAsUser使用。在不需要使用进程环境块时,可以通过调用DestroyEnvironmentBlock函数进行释放。获取环境块后,就可以调用CreateProcessAsUser来创建用户桌面进程。
上述方法创建的用户桌面进程并没有继承服务程序的系统权限,只具有普通权限。要想创建一个有系统权限的子进程,这可以通过设置进程访问令牌的安全描述符来实现。
代码实现
因为程序要实现的是突破SESSION 0隔离,所以,在系统服务程序中创建用户桌面进程程序必须注册成为一个系统服务进程,这样才处于SESSION 0中。
服务程序的入口点与普通程序的人口点不同,需要通过调用函数StartServiceCtrlDispatcher来设置服务人口点函数。
ServiceLoader.exe
ServiceOperate.h
1 2 3 4 5 6 7 8 9
| #ifndef _SERVICE_OPERATE_H_ #define _SERVICE_OPERATE_H_
#include <Windows.h> #include <Shlwapi.h> #pragma comment(lib, "Shlwapi.lib")
BOOL SystemServiceOperate(char* lpszDriverPath, int iOperateType); #endif
|
ServiceLoader.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
|
#include "ServiceOperate.h" #include<stdio.h> #include<tchar.h>
int _tmain(int argc, _TCHAR* argv[]) { BOOL bRet = FALSE; char szExePath[] = "C:\\Users\\admin\\Desktop\\C++\\CreateProcessAsUser.exe";
bRet = SystemServiceOperate(szExePath, 0); if (bRet) { printf("INSTALL OK.\n"); } else { printf("INSTALL ERROR.\n"); } bRet = SystemServiceOperate(szExePath, 1); if (bRet) { printf("START OK.\n"); } else { printf("START ERROR.\n"); }
system("pause");
bRet = SystemServiceOperate(szExePath, 2); if (bRet) { printf("STOP OK.\n"); } else { printf("STOP ERROR.\n"); } bRet = SystemServiceOperate(szExePath, 3); if (bRet) { printf("UNINSTALL OK.\n"); } else { printf("UNINSTALL ERROR.\n"); }
return 0; }
|
ServiceOperate.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
| #include "ServiceOperate.h" #include <stdio.h> #include<tchar.h>
void ShowError(char* lpszText) { char szErr[MAX_PATH] = { 0 }; ::wsprintf(szErr, "%s Error!\nError Code Is:%d\n", lpszText, ::GetLastError()); #ifdef _DEBUG ::MessageBox(NULL, szErr, "ERROR", MB_OK | MB_ICONERROR); #endif }
BOOL SystemServiceOperate(char* lpszExePath, int iOperateType) { BOOL bRet = TRUE; char szName[MAX_PATH] = { 0 };
lstrcpy(szName, lpszExePath); PathStripPath(szName);
SC_HANDLE shOSCM = NULL, shCS = NULL; SERVICE_STATUS ss; DWORD dwErrorCode = 0; BOOL bSuccess = FALSE; shOSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (!shOSCM) { ShowError("OpenSCManager"); return FALSE; }
if (0 != iOperateType) { shCS = OpenService(shOSCM, szName, SERVICE_ALL_ACCESS); if (!shCS) { ShowError("OpenService"); ::CloseServiceHandle(shOSCM); shOSCM = NULL; return FALSE; } }
switch (iOperateType) { case 0: { shCS = ::CreateService(shOSCM, szName, szName, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, lpszExePath, NULL, NULL, NULL, NULL, NULL); if (!shCS) { ShowError("CreateService"); bRet = FALSE; } break; } case 1: { if (!::StartService(shCS, 0, NULL)) { ShowError("StartService"); bRet = FALSE; } break; } case 2: { if (!::ControlService(shCS, SERVICE_CONTROL_STOP, &ss)) { ShowError("ControlService"); bRet = FALSE; } break; } case 3: { if (!::DeleteService(shCS)) { ShowError("DeleteService"); bRet = FALSE; } break; } default: break; } if (shCS) { ::CloseServiceHandle(shCS); shCS = NULL; } if (shOSCM) { ::CloseServiceHandle(shOSCM); shOSCM = NULL; }
return bRet; }
|
CreateProcessAsUser.exe CreateProcessAsUser.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 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
| #include <Windows.h> #include <UserEnv.h> #include <WtsApi32.h> #include <tchar.h> #pragma comment(lib, "UserEnv.lib") #pragma comment(lib, "WtsApi32.lib")
void __stdcall ServiceMain(DWORD dwArgc, char* lpszArgv); void __stdcall ServiceCtrlHandle(DWORD dwOperateCode); void DoTask();
void ShowMessage(TCHAR* lpszMessage, TCHAR* lpszTitle);
BOOL CreateUserProcess(char* lpszFileName);
char g_szServiceName[MAX_PATH] = "002.exe"; SERVICE_STATUS g_ServiceStatus = { 0 }; SERVICE_STATUS_HANDLE g_ServiceStatusHandle = { 0 };
int _tmain(int argc, _TCHAR* argv[]) { SERVICE_TABLE_ENTRY stDispatchTable[] = { { g_szServiceName, (LPSERVICE_MAIN_FUNCTION)ServiceMain }, { NULL, NULL } }; ::StartServiceCtrlDispatcher(stDispatchTable);
return 0; }
void __stdcall ServiceMain(DWORD dwArgc, char* lpszArgv) { g_ServiceStatus.dwServiceType = SERVICE_WIN32; g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING; g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; g_ServiceStatus.dwWin32ExitCode = 0; g_ServiceStatus.dwServiceSpecificExitCode = 0; g_ServiceStatus.dwCheckPoint = 0; g_ServiceStatus.dwWaitHint = 0;
g_ServiceStatusHandle = ::RegisterServiceCtrlHandler(g_szServiceName, ServiceCtrlHandle);
g_ServiceStatus.dwCurrentState = SERVICE_RUNNING; g_ServiceStatus.dwCheckPoint = 0; g_ServiceStatus.dwWaitHint = 0; ::SetServiceStatus(g_ServiceStatusHandle, &g_ServiceStatus);
DoTask(); }
void __stdcall ServiceCtrlHandle(DWORD dwOperateCode) { switch (dwOperateCode) { case SERVICE_CONTROL_PAUSE: { g_ServiceStatus.dwCurrentState = SERVICE_PAUSED; break; } case SERVICE_CONTROL_CONTINUE: { g_ServiceStatus.dwCurrentState = SERVICE_RUNNING; break; } case SERVICE_CONTROL_STOP: { g_ServiceStatus.dwWin32ExitCode = 0; g_ServiceStatus.dwCurrentState = SERVICE_STOPPED; g_ServiceStatus.dwCheckPoint = 0; g_ServiceStatus.dwWaitHint = 0; ::SetServiceStatus(g_ServiceStatusHandle, &g_ServiceStatus); break; } case SERVICE_CONTROL_INTERROGATE: { break; } default: break; } }
void DoTask() { ShowMessage("Hi Demon·Gan\nThis Is From Session 0 Service!\n", "HELLO"); CreateUserProcess("C:\\Users\\admin\\Desktop\\C++\\WinExec.exe"); }
void ShowMessage(TCHAR* lpszMessage, TCHAR* lpszTitle) { DWORD dwSessionId = ::WTSGetActiveConsoleSessionId(); DWORD dwResponse = 0; ::WTSSendMessage(WTS_CURRENT_SERVER_HANDLE, dwSessionId, lpszTitle, (1 + ::lstrlen(lpszTitle)), lpszMessage, (1 + ::lstrlen(lpszMessage)), 0, 0, &dwResponse, FALSE); }
BOOL CreateUserProcess(char* lpszFileName) { BOOL bRet = TRUE; DWORD dwSessionID = 0; HANDLE hToken = NULL; HANDLE hDuplicatedToken = NULL; LPVOID lpEnvironment = NULL; STARTUPINFO si = { 0 }; PROCESS_INFORMATION pi = { 0 }; si.cb = sizeof(si);
do { dwSessionID = ::WTSGetActiveConsoleSessionId();
if (FALSE == ::WTSQueryUserToken(dwSessionID, &hToken)) { ShowMessage("WTSQueryUserToken", "ERROR"); bRet = FALSE; break; }
if (FALSE == ::DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hDuplicatedToken)) { ShowMessage("DuplicateTokenEx", "ERROR"); bRet = FALSE; break; }
if (FALSE == ::CreateEnvironmentBlock(&lpEnvironment, hDuplicatedToken, FALSE)) { ShowMessage("CreateEnvironmentBlock", "ERROR"); bRet = FALSE; break; }
if (FALSE == ::CreateProcessAsUser(hDuplicatedToken, lpszFileName, NULL, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT, lpEnvironment, NULL, &si, &pi)) { ShowMessage("CreateProcessAsUser", "ERROR"); bRet = FALSE; break; }
} while (FALSE); if (lpEnvironment) { ::DestroyEnvironmentBlock(lpEnvironment); } if (hDuplicatedToken) { ::CloseHandle(hDuplicatedToken); } if (hToken) { ::CloseHandle(hToken); } return bRet; }
|
测试
运行ServiceLoader.exe,注册CreateProcessAsUser.exe为服务,并执行CreateProcessAsUser.exe;CreateProcessAsUser.exe处于SESSION 0,实现创建用户桌面进程Winexec.exe(处于SESSION 1)

记得把创建的服务删除,sc delete CreateProcessAsUser.exe
其实这一章不太懂,为什么说是突破SESSION 0隔离创建用户进程。创建服务就是从SESSION 1到SESSION 0,这也是突破隔离,还是从由低等级到高等级。
内存直接加载运行
把DLL或者exe等PE文件从内存中直接加载到病毒木马的内存中去执行,不需要通过LoadLibrary等线程的API函数去操作,以此躲过杀毒软件的拦截检测。
假如程序需要动态调用DLL文件,内存加载运行技术可以把这些DLL作为资源插入到自己的程序中。此时直接在内存中加载运行即可,不需要再将DLL释放到本地。
实现原理
内存直接加载运行技术的核心就是模拟PE加载器加载PE文件的过程,也就是对导入表、导出表以及重定位表的操作过程。
从内存中加载运行DLL,具体的实现流程总结如下:
- 在DLL文件中,根据PE结构获取其加载映像的大小SizeOfImage,并根据SizeOfImage在自己的程序中申请可读、可写、可执行的内存,那么这块内存的首地址就是DLL的加载基址。
- 根据DLL中的PE结构获取其映像对齐大小SectionAlignment,然后把DLL文件数据按照SectionAlignment复制到上述申请的可读、可写、可执行的内存中。
- 根据PE结构的重定位表,重新对重定位表进行修正。
- 根据PE结构的导入表,加载所需的DLL,并获取导入函数的地址并写入导入表中。
- 修改DLL的加载基址ImageBase。
- 根据PE结构获取DLL的入口地址,然后构造并调用DllMain函数,实现DLL加载。
而exe文件相对于DLL文件实现原理唯一的区别就在于构造入口函数的差别,exe不需要构造DllMain函数,而是根据PE结构获取exe的入口地址偏移AddressOfEntryPoint并计算出入口地址,然后直接跳转到入口地址处执行即可。
要特别注意的是,对于exe文件来说,重定位表不是必需的,即使没有重定位表,exe也可正常运行。因为对于exe进程来说,进程最早加载的模块是exe模块,所以它可以按照默认的加载基址加载到内存。对于那些没有重定位表的程序,只能把它加载到默认的加载基址上。如果默认加载基址已被占用,则直接内存加载运行会失败。
代码实现
dllload.exe
MmLoadDll.h
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
| #ifndef _MM_LOAD_DLL_H_ #define _MM_LOAD_DLL_H_
#include <Windows.h>
typedef BOOL(__stdcall* typedef_DllMain)(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved);
void ShowError(char* lpszText);
LPVOID MmLoadLibrary(LPVOID lpData, DWORD dwSize);
DWORD GetSizeOfImage(LPVOID lpData);
BOOL MmMapFile(LPVOID lpData, LPVOID lpBaseAddress);
DWORD Align(DWORD dwSize, DWORD dwAlignment);
BOOL DoRelocationTable(LPVOID lpBaseAddress);
BOOL DoImportTable(LPVOID lpBaseAddress);
BOOL SetImageBase(LPVOID lpBaseAddress);
BOOL CallDllMain(LPVOID lpBaseAddress);
LPVOID MmGetProcAddress(LPVOID lpBaseAddress, PCHAR lpszFuncName);
BOOL MmFreeLibrary(LPVOID lpBaseAddress); #endif
|
dllload.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
|
#include<tchar.h> #include<stdio.h> #include "MmLoadDll.h"
int _tmain(int argc, _TCHAR* argv[]) { char szFileName[MAX_PATH] = "TestDll.dll"; HANDLE hFile = CreateFile(szFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL); if (INVALID_HANDLE_VALUE == hFile) { ShowError("CreateFile"); return 1; } DWORD dwFileSize = GetFileSize(hFile, NULL); BYTE* lpData = new BYTE[dwFileSize]; if (NULL == lpData) { ShowError("new"); return 2; } DWORD dwRet = 0; ReadFile(hFile, lpData, dwFileSize, &dwRet, NULL);
LPVOID lpBaseAddress = MmLoadLibrary(lpData, dwFileSize); if (NULL == lpBaseAddress) { ShowError("MmLoadLibrary"); return 3; } printf("DLL加载成功\n");
typedef BOOL(*typedef_ShowMessage)(char* lpszText, char* lpszCaption); typedef_ShowMessage ShowMessage = (typedef_ShowMessage)MmGetProcAddress(lpBaseAddress, "ShowMessage"); if (NULL == ShowMessage) { ShowError("MmGetProcAddress"); return 4; } ShowMessage("I am Demon·Gan\n", "Who Are You");
BOOL bRet = MmFreeLibrary(lpBaseAddress); if (FALSE == bRet) { ShowError("MmFreeLirbary"); }
delete[] lpData; lpData = NULL; CloseHandle(hFile);
system("pause"); return 0; }
|
MmLoadDll.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 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 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
| #include "MmLoadDll.h" #include<windows.h>
void ShowError(char* lpszText) { char szErr[MAX_PATH] = { 0 }; ::wsprintf(szErr, "%s Error!\nError Code Is:%d\n", lpszText, ::GetLastError()); ::MessageBox(NULL, szErr, "ERROR", MB_OK | MB_ICONERROR); }
LPVOID MmLoadLibrary(LPVOID lpData, DWORD dwSize) { LPVOID lpBaseAddress = NULL; DWORD dwSizeOfImage = GetSizeOfImage(lpData); lpBaseAddress = VirtualAlloc(NULL, dwSizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (NULL == lpBaseAddress) { ShowError("VirtualAlloc"); return NULL; } RtlZeroMemory(lpBaseAddress, dwSizeOfImage); if (FALSE == MmMapFile(lpData, lpBaseAddress)) { ShowError("MmMapFile"); return NULL; }
if (FALSE == DoRelocationTable(lpBaseAddress)) { ShowError("DoRelocationTable"); return NULL; }
if (FALSE == DoImportTable(lpBaseAddress)) { ShowError("DoImportTable"); return NULL; }
DWORD dwOldProtect = 0; if (FALSE == ::VirtualProtect(lpBaseAddress, dwSizeOfImage, PAGE_EXECUTE_READWRITE, &dwOldProtect)) { ShowError("VirtualProtect"); return NULL; }
if (FALSE == SetImageBase(lpBaseAddress)) { ShowError("SetImageBase"); return NULL; }
if (FALSE == CallDllMain(lpBaseAddress)) { ShowError("CallDllMain"); return NULL; }
return lpBaseAddress; }
DWORD GetSizeOfImage(LPVOID lpData) { DWORD dwSizeOfImage = 0; PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)lpData; PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((ULONG32)pDosHeader + pDosHeader->e_lfanew); dwSizeOfImage = pNtHeaders->OptionalHeader.SizeOfImage; return dwSizeOfImage; }
BOOL MmMapFile(LPVOID lpData, LPVOID lpBaseAddress) { PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)lpData; PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((ULONG32)pDosHeader + pDosHeader->e_lfanew); DWORD dwSizeOfHeaders = pNtHeaders->OptionalHeader.SizeOfHeaders; WORD wNumberOfSections = pNtHeaders->FileHeader.NumberOfSections; PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pNtHeaders + sizeof(IMAGE_NT_HEADERS)); RtlCopyMemory(lpBaseAddress, lpData, dwSizeOfHeaders); WORD i = 0; LPVOID lpSrcMem = NULL; LPVOID lpDestMem = NULL; DWORD dwSizeOfRawData = 0; for (i = 0; i < wNumberOfSections; i++) { if ((0 == pSectionHeader->VirtualAddress) || (0 == pSectionHeader->SizeOfRawData)) { pSectionHeader++; continue; } lpSrcMem = (LPVOID)((DWORD)lpData + pSectionHeader->PointerToRawData); lpDestMem = (LPVOID)((DWORD)lpBaseAddress + pSectionHeader->VirtualAddress); dwSizeOfRawData = pSectionHeader->SizeOfRawData; ::RtlCopyMemory(lpDestMem, lpSrcMem, dwSizeOfRawData); pSectionHeader++; } return TRUE; }
DWORD Align(DWORD dwSize, DWORD dwAlignment) { DWORD dwRet = 0; DWORD i = 0, j = 0; i = dwSize / dwAlignment; j = dwSize % dwAlignment; if (0 != j) { i++; } dwRet = i * dwAlignment; return dwRet; }
BOOL DoRelocationTable(LPVOID lpBaseAddress) {
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)lpBaseAddress; PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((ULONG32)pDosHeader + pDosHeader->e_lfanew); PIMAGE_BASE_RELOCATION pLoc = (PIMAGE_BASE_RELOCATION)((unsigned long)pDosHeader + pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
if ((PVOID)pLoc == (PVOID)pDosHeader) { return TRUE; }
while ((pLoc->VirtualAddress + pLoc->SizeOfBlock) != 0) { WORD* pLocData = (WORD*)((PBYTE)pLoc + sizeof(IMAGE_BASE_RELOCATION)); int nNumberOfReloc = (pLoc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
for (int i = 0; i < nNumberOfReloc; i++) {
if ((DWORD)(pLocData[i] & 0x0000F000) == 0x00003000) {
DWORD* pAddress = (DWORD*)((PBYTE)pDosHeader + pLoc->VirtualAddress + (pLocData[i] & 0x0FFF)); DWORD dwDelta = (DWORD)pDosHeader - pNtHeaders->OptionalHeader.ImageBase; *pAddress += dwDelta;
} }
pLoc = (PIMAGE_BASE_RELOCATION)((PBYTE)pLoc + pLoc->SizeOfBlock); }
return TRUE; }
BOOL DoImportTable(LPVOID lpBaseAddress) { PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)lpBaseAddress; PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((ULONG32)pDosHeader + pDosHeader->e_lfanew); PIMAGE_IMPORT_DESCRIPTOR pImportTable = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pDosHeader + pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
char* lpDllName = NULL; HMODULE hDll = NULL; PIMAGE_THUNK_DATA lpImportNameArray = NULL; PIMAGE_IMPORT_BY_NAME lpImportByName = NULL; PIMAGE_THUNK_DATA lpImportFuncAddrArray = NULL; FARPROC lpFuncAddress = NULL; DWORD i = 0;
while (TRUE) { if (0 == pImportTable->OriginalFirstThunk) { break; }
lpDllName = (char*)((DWORD)pDosHeader + pImportTable->Name); hDll = ::GetModuleHandle(lpDllName); if (NULL == hDll) { hDll = ::LoadLibrary(lpDllName); if (NULL == hDll) { pImportTable++; continue; } }
i = 0; lpImportNameArray = (PIMAGE_THUNK_DATA)((DWORD)pDosHeader + pImportTable->OriginalFirstThunk); lpImportFuncAddrArray = (PIMAGE_THUNK_DATA)((DWORD)pDosHeader + pImportTable->FirstThunk); while (TRUE) { if (0 == lpImportNameArray[i].u1.AddressOfData) { break; }
lpImportByName = (PIMAGE_IMPORT_BY_NAME)((DWORD)pDosHeader + lpImportNameArray[i].u1.AddressOfData);
if (0x80000000 & lpImportNameArray[i].u1.Ordinal) { lpFuncAddress = ::GetProcAddress(hDll, (LPCSTR)(lpImportNameArray[i].u1.Ordinal & 0x0000FFFF)); } else { lpFuncAddress = ::GetProcAddress(hDll, (LPCSTR)lpImportByName->Name); } lpImportFuncAddrArray[i].u1.Function = (DWORD)lpFuncAddress; i++; }
pImportTable++; }
return TRUE; }
BOOL SetImageBase(LPVOID lpBaseAddress) { PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)lpBaseAddress; PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((ULONG32)pDosHeader + pDosHeader->e_lfanew); pNtHeaders->OptionalHeader.ImageBase = (ULONG32)lpBaseAddress;
return TRUE; }
BOOL CallDllMain(LPVOID lpBaseAddress) { typedef_DllMain DllMain = NULL; PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)lpBaseAddress; PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((ULONG32)pDosHeader + pDosHeader->e_lfanew); DllMain = (typedef_DllMain)((ULONG32)pDosHeader + pNtHeaders->OptionalHeader.AddressOfEntryPoint); BOOL bRet = DllMain((HINSTANCE)lpBaseAddress, DLL_PROCESS_ATTACH, NULL); if (FALSE == bRet) { ShowError("DllMain"); }
return bRet; }
LPVOID MmGetProcAddress(LPVOID lpBaseAddress, PCHAR lpszFuncName) { LPVOID lpFunc = NULL; PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)lpBaseAddress; PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((ULONG32)pDosHeader + pDosHeader->e_lfanew); PIMAGE_EXPORT_DIRECTORY pExportTable = (PIMAGE_EXPORT_DIRECTORY)((DWORD)pDosHeader + pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); PDWORD lpAddressOfNamesArray = (PDWORD)((DWORD)pDosHeader + pExportTable->AddressOfNames); PCHAR lpFuncName = NULL; PWORD lpAddressOfNameOrdinalsArray = (PWORD)((DWORD)pDosHeader + pExportTable->AddressOfNameOrdinals); WORD wHint = 0; PDWORD lpAddressOfFunctionsArray = (PDWORD)((DWORD)pDosHeader + pExportTable->AddressOfFunctions);
DWORD dwNumberOfNames = pExportTable->NumberOfNames; DWORD i = 0; for (i = 0; i < dwNumberOfNames; i++) { lpFuncName = (PCHAR)((DWORD)pDosHeader + lpAddressOfNamesArray[i]); if (0 == ::lstrcmpi(lpFuncName, lpszFuncName)) { wHint = lpAddressOfNameOrdinalsArray[i]; lpFunc = (LPVOID)((DWORD)pDosHeader + lpAddressOfFunctionsArray[wHint]); break; } } return lpFunc; }
BOOL MmFreeLibrary(LPVOID lpBaseAddress) { BOOL bRet = FALSE;
if (NULL == lpBaseAddress) { return bRet; }
bRet = VirtualFree(lpBaseAddress, 0, MEM_RELEASE); lpBaseAddress = NULL;
return bRet; }
|
TestDll.dll(待加载DLL文件)
dllmain.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| #include "framework.h"
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; }
|
TestDll.cpp
1 2 3 4 5 6 7 8
| #include<windows.h>
extern "C" __declspec(dllexport) BOOL ShowMessage(char* lpszText, char* lpszCaption) { MessageBox(NULL, lpszText, lpszCaption, MB_OK);
return TRUE; }
|
测试
