学习《逆向工程核心原理》,在x64下dll注入与代码注入。
dll注入主要用到CreateRemoteThread,
HANDLE WINAPI CreateRemoteThread(
__in HANDLE hProcess,
__in LPSECURITY_ATTRIBUTES lpThreadAttributes,
__in SIZE_T dwStackSize,
__in LPTHREAD_START_ROUTINE lpStartAddress,
__in LPVOID lpParameter,
__in DWORD dwCreationFlags,
__out LPDWORD lpThreadId
);
利用获取到的LoadLibraryW地址作为lpStartAddress,需注入进程中分配保存的dll名称作为lpParameter,实现动态加载dll
代码注入类似,主要用到VirtualAllocEx,WriteProcessMemory,在需注入的进程中开辟空间,写入代码,变量。
1 #include "pch.h" 2 #include <windows.h> 3 #include <tchar.h> 4 #include <tlhelp32.h> 5 #include <stdio.h> 6 #include <shlobj.h> 7 extern void checkAdmin(); 8 9 //遍历输出进程pid 10 int TraversalProcess() { 11 HANDLE hProceessnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 12 if (hProceessnap == INVALID_HANDLE_VALUE) 13 { 14 printf_s("创建进行快照失败 "); 15 return -1; 16 } 17 else 18 { 19 PROCESSENTRY32 pe32; 20 pe32.dwSize = sizeof(pe32); 21 BOOL hProcess = Process32First(hProceessnap, &pe32); 22 while (hProcess) 23 { 24 /*WCHAR * ProcessName =(WCHAR *)L"ProcessID.exe"; 25 if (!wcscmp(pe32.szExeFile, ProcessName)) 26 {*/ 27 printf("进程名:%-10ls ----------------进程ID:%6d ", pe32.szExeFile, pe32.th32ProcessID); 28 /* break; 29 }*/ 30 hProcess = Process32Next(hProceessnap, &pe32); 31 } 32 } 33 CloseHandle(hProceessnap); 34 } 35 36 //设置权限 37 BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege) 38 { 39 TOKEN_PRIVILEGES tp; 40 HANDLE hToken; 41 LUID luid; 42 43 if (!OpenProcessToken(GetCurrentProcess(), 44 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, 45 &hToken)) 46 { 47 _tprintf(L"OpenProcessToken error: %u ", GetLastError()); 48 return FALSE; 49 } 50 51 if (!LookupPrivilegeValue(NULL, // lookup privilege on local system 52 lpszPrivilege, // privilege to lookup 53 &luid)) // receives LUID of privilege 54 { 55 _tprintf(L"LookupPrivilegeValue error: %u ", GetLastError()); 56 return FALSE; 57 } 58 59 tp.PrivilegeCount = 1; 60 tp.Privileges[0].Luid = luid; 61 if (bEnablePrivilege) 62 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 63 else 64 tp.Privileges[0].Attributes = 0; 65 66 // Enable the privilege or disable all privileges. 67 if (!AdjustTokenPrivileges(hToken, 68 FALSE, 69 &tp, 70 sizeof(TOKEN_PRIVILEGES), 71 (PTOKEN_PRIVILEGES)NULL, 72 (PDWORD)NULL)) 73 { 74 _tprintf(L"AdjustTokenPrivileges error: %u ", GetLastError()); 75 return FALSE; 76 } 77 78 if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) 79 { 80 _tprintf(L"The token does not have the specified privilege. "); 81 return FALSE; 82 } 83 84 return TRUE; 85 } 86 87 //dll注入 88 BOOL InjectDll(DWORD dwPID, LPCTSTR szDllPath) 89 { 90 HANDLE hProcess = NULL, hThread = NULL; 91 HMODULE hMod = NULL; 92 LPVOID pRemoteBuf = NULL; 93 DWORD dwBufSize = (DWORD)(_tcslen(szDllPath) + 1) * sizeof(TCHAR); 94 LPTHREAD_START_ROUTINE pThreadProc; 95 96 // #1. 使用dwPID请求对象进程(notepad.exe)的HANDLE。 97 if (!(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID))) 98 { 99 _tprintf(L"OpenProcess(%d) failed!!! [%d] ", dwPID, GetLastError()); 100 return FALSE; 101 } 102 103 // #2. 在目标进程(notepad.exe)内存中分配与szDllName大小相同的内存。 104 pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE); 105 106 // #3. 在分配的内存中使用dll路径 107 WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)szDllPath, dwBufSize, NULL); 108 109 // #4. 请求到LoadLibraryA() API地址。 110 hMod = GetModuleHandle(L"kernel32.dll"); 111 pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hMod, "LoadLibraryW"); 112 113 // #5. 在notepad.exe进程中运行线程 114 hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, pRemoteBuf, 0, NULL); 115 //通过CreateRemoteThread,调用pThreadProc,即LoadLibraryW,参数为在需注入进程中开辟的内存(存储了dll路径) 116 117 WaitForSingleObject(hThread, INFINITE); 118 119 CloseHandle(hThread); 120 CloseHandle(hProcess); 121 122 return TRUE; 123 } 124 //卸载dll 125 BOOL EjectDll(DWORD dwPID, LPCTSTR szDllName) 126 { 127 BOOL bMore = FALSE, bFound = FALSE; 128 HANDLE hSnapshot, hProcess, hThread; 129 HMODULE hModule = NULL; 130 MODULEENTRY32 me = { sizeof(me) }; 131 LPTHREAD_START_ROUTINE pThreadProc; 132 // dwPID = notepad 进程 ID 133 // 使用TH32CS_SNAPMODULE参数获得载入notepad程序的DLL名称 134 hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID); 135 136 bMore = Module32First(hSnapshot, &me); 137 for (; bMore; bMore = Module32Next(hSnapshot, &me)) 138 { 139 if (!_tcsicmp((LPCTSTR)me.szModule, szDllName) || 140 !_tcsicmp((LPCTSTR)me.szExePath, szDllName)) 141 { 142 bFound = TRUE; 143 break; 144 } 145 } 146 147 if (!bFound) 148 { 149 CloseHandle(hSnapshot); 150 return FALSE; 151 } 152 153 if (!(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID))) 154 { 155 _tprintf(L"OpenProcess(%d) failed!!! [%d] ", dwPID, GetLastError()); 156 return FALSE; 157 } 158 159 hModule = GetModuleHandle(L"kernel32.dll"); 160 pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hModule, "FreeLibrary"); 161 hThread = CreateRemoteThread(hProcess, NULL, 0, 162 pThreadProc, me.modBaseAddr, 163 0, NULL); 164 WaitForSingleObject(hThread, INFINITE); 165 166 CloseHandle(hThread); 167 CloseHandle(hProcess); 168 CloseHandle(hSnapshot); 169 170 return TRUE; 171 } 172 173 174 //代码注入所需结构体 175 typedef struct _THREAD_PARAM 176 { 177 FARPROC pFunc[2]; // LoadLibraryA(), GetProcAddress() 178 char szBuf[4][128]; // "user32.dll", "MessageBoxA", "www.reversecore.com", "ReverseCore" 179 } THREAD_PARAM, *PTHREAD_PARAM; 180 181 typedef HMODULE(WINAPI *PFLOADLIBRARYA) 182 ( 183 LPCSTR lpLibFileName 184 ); 185 186 typedef FARPROC(WINAPI *PFGETPROCADDRESS) 187 ( 188 HMODULE hModule, 189 LPCSTR lpProcName 190 ); 191 192 typedef int (WINAPI *PFMESSAGEBOXA) 193 ( 194 HWND hWnd, 195 LPCSTR lpText, 196 LPCSTR lpCaption, 197 UINT uType 198 ); 199 200 //需注入的代码 201 DWORD WINAPI ThreadProc(LPVOID lParam) 202 { 203 PTHREAD_PARAM pParam = (PTHREAD_PARAM)lParam; 204 HMODULE hMod = NULL; 205 FARPROC pFunc = NULL; 206 //调用 LoadLibrary() 加载 "user32.dll" 207 hMod = ((PFLOADLIBRARYA)pParam->pFunc[0])(pParam->szBuf[0]); // "user32.dll" 208 if (!hMod) 209 return 1; 210 211 //调用 GetProcAddress() 获取"MessageBoxA" 212 pFunc = (FARPROC)((PFGETPROCADDRESS)pParam->pFunc[1])(hMod, pParam->szBuf[1]); // "MessageBoxA" 213 if (!pFunc) 214 return 1; 215 216 // 调用MessageBoxA() 217 ((PFMESSAGEBOXA)pFunc)(NULL, pParam->szBuf[2], pParam->szBuf[3], MB_OK); 218 return 0; 219 } 220 221 //实现代码注入 222 BOOL InjectCode(DWORD dwPID) 223 { 224 HMODULE hMod = NULL; 225 THREAD_PARAM param = { 0, }; 226 HANDLE hProcess = NULL; 227 HANDLE hThread = NULL; 228 LPVOID pRemoteBuf[2] = { 0, }; 229 DWORD dwSize = 0; 230 231 hMod = GetModuleHandleA("kernel32.dll"); 232 233 // set THREAD_PARAM 234 param.pFunc[0] = GetProcAddress(hMod, "LoadLibraryA"); 235 param.pFunc[1] = GetProcAddress(hMod, "GetProcAddress"); 236 strcpy_s(param.szBuf[0], "user32.dll"); 237 strcpy_s(param.szBuf[1], "MessageBoxA"); 238 strcpy_s(param.szBuf[2], "这是code inject"); 239 strcpy_s(param.szBuf[3], "好开心!"); 240 241 // Open Process 242 if (!(hProcess = OpenProcess(PROCESS_ALL_ACCESS, // dwDesiredAccess 243 FALSE, // bInheritHandle 244 dwPID))) // dwProcessId 245 { 246 printf("OpenProcess() fail : err_code = %d ", GetLastError()); 247 return FALSE; 248 } 249 250 // Allocation for THREAD_PARAM 写入代码注入所需的data 251 dwSize = sizeof(THREAD_PARAM); 252 if (!(pRemoteBuf[0] = VirtualAllocEx(hProcess, // hProcess 253 NULL, // lpAddress 254 dwSize, // dwSize 255 MEM_COMMIT, // flAllocationType 256 PAGE_READWRITE))) // flProtect 257 { 258 printf("VirtualAllocEx() fail : err_code = %d ", GetLastError()); 259 return FALSE; 260 } 261 SIZE_T sz = 0; 262 if (!WriteProcessMemory(hProcess, // hProcess 263 pRemoteBuf[0], // lpBaseAddress 264 (LPVOID)¶m, // lpBuffer 265 dwSize, // nSize 266 &sz)) // [out] lpNumberOfBytesWritten 267 { 268 printf("写入大小:%d ", sz); 269 printf("THREAD_PARAM WriteProcessMemory() fail : err_code = %d ", GetLastError()); 270 return FALSE; 271 } 272 273 // Allocation for ThreadProc() 写入代码 274 dwSize = abs((int)((DWORD)InjectCode - (DWORD)ThreadProc)); 275 276 printf("dwSize:%d ", dwSize); 277 //dwSize = 1024; 278 if (!(pRemoteBuf[1] = VirtualAllocEx(hProcess, // hProcess 279 NULL, // lpAddress 280 dwSize, // dwSize 281 MEM_COMMIT, // flAllocationType 282 PAGE_EXECUTE_READWRITE))) // flProtect 283 { 284 printf("VirtualAllocEx() fail : err_code = %d ", GetLastError()); 285 return FALSE; 286 } 287 sz = 0; 288 if (!WriteProcessMemory(hProcess, // hProcess 289 pRemoteBuf[1], // lpBaseAddress 290 (LPVOID)ThreadProc, // lpBuffer 291 dwSize, // nSize 292 &sz)) // [out] lpNumberOfBytesWritten 293 { 294 printf("写入大小:%d ", sz); 295 printf("ThreadProc() WriteProcessMemory() fail : err_code = %d ", GetLastError()); 296 return FALSE; 297 } 298 printf("ThreadProc()写入大小:%d ", sz); 299 if (!(hThread = CreateRemoteThread(hProcess, // hProcess 300 NULL, // lpThreadAttributes 301 0, // dwStackSize 302 (LPTHREAD_START_ROUTINE)pRemoteBuf[1], // dwStackSize 303 pRemoteBuf[0], // lpParameter 304 0, // dwCreationFlags 305 NULL))) // lpThreadId 306 { 307 printf("CreateRemoteThread() fail : err_code = %d ", GetLastError()); 308 return FALSE; 309 } 310 311 WaitForSingleObject(hThread, INFINITE); 312 CloseHandle(hThread); 313 CloseHandle(hProcess); 314 printf("code inject end "); 315 return TRUE; 316 } 317 318 319 int _tmain(int argc, TCHAR *argv[]) 320 { 321 /*if (argc != 3) 322 { 323 _tprintf(L"USAGE : %s <pid> <dll_path> ", argv[0]); 324 return 1; 325 }*/ 326 // change privilege 327 // 判断当前进程是否以管理员身份运行 328 checkAdmin(); 329 /*if (!SetPrivilege(SE_DEBUG_NAME, TRUE)) 330 return 1;*/ 331 //TraversalProcess(); 332 TCHAR pid[10]; 333 TCHAR path[MAX_PATH]; 334 system("tasklist"); 335 printf("ok "); 336 printf("输入要注入的进程pid: "); 337 scanf_s("%ls", pid, 10); 338 printf("请选择功能:1.dll注入 2.代码注入 "); 339 int flag = 0; 340 scanf_s("%d", &flag, 1); 341 if (flag == 1) { 342 printf("输入要注入的dll路径:"); 343 scanf_s("%ls", path,MAX_PATH); 344 // inject dll 345 if (InjectDll((DWORD)_tstol(pid), path)) 346 _tprintf(L"InjectDll("%s") success!!! ", path); 347 else 348 _tprintf(L"InjectDll("%s") failed!!! ", path); 349 printf("输入q 卸载dll "); 350 while (getchar() != 'q'); 351 TCHAR *p = _tcsrchr(path, '\'); 352 if(EjectDll((DWORD)_tstol(pid), p+1)) 353 printf("卸载dll成功! "); 354 else 355 { 356 printf("卸载失败! "); 357 } 358 359 system("pause"); 360 return 0; 361 } 362 else if (flag == 2) 363 { 364 InjectCode((DWORD)_tstol(pid)); 365 system("pause"); 366 return 0; 367 } 368 else 369 { 370 system("pause"); 371 return 0; 372 } 373 }
判断当前运行时的权限,以管理员身份运行。
1 BOOL IsAdmin(HANDLE hProcess) 2 { 3 HANDLE hToken = NULL; 4 OpenProcessToken(hProcess, TOKEN_QUERY, &hToken); 5 6 TOKEN_ELEVATION_TYPE tokenType = TokenElevationTypeDefault; // 用于接收令牌类型 7 8 DWORD dwRetSize = 0; // 用于接收函数输出信息的字节数 9 10 // 2. 查询进程令牌中的权限提升值.( 这个值会记录当前的令牌是何种类型( 细节在17_权限管理_令牌的获取.cpp ) ) 11 GetTokenInformation(hToken, 12 TokenElevationType,// 获取令牌的当前提升等级 13 &tokenType, 14 sizeof(tokenType), 15 &dwRetSize // 所需缓冲区的字节数 16 ); 17 18 19 // 根据令牌的类型来输出相应的信息 20 if (TokenElevationTypeFull == tokenType) { 21 // 3. 如果令牌是TokenElevationTypeFull , 则拥有至高无上的能力,可以给令牌添加任何特权 22 printf("管理员账户,并拥有全部的权限,可以给令牌添加任何特权 "); 23 return TRUE; 24 } 25 // 4. 如果是其他的, 则需要以管理员身份重新运行本进程. 这样就能以第三步的方法解决剩下的问题. 26 else if (TokenElevationTypeDefault == tokenType) { 27 printf("默认用户, 可能是一个普通用户, 可能是关闭UAC时登录的管理员用户 "); 28 29 // 调用系统函数IsUserAnAdmin, 进一步确定是普通用户还是管理员用户 30 return IsUserAnAdmin(); 31 } 32 else if (TokenElevationTypeLimited == tokenType) { 33 34 // 判断受限制的用户是管理员 35 // 如果是管理员, 则这个令牌中会保存有管理员的SID 36 37 // 1. 获取系统内键管理员用户的SID 38 SID adminSid; 39 DWORD dwSize = sizeof(adminSid); 40 CreateWellKnownSid(WinBuiltinAdministratorsSid, // 获取SID的类型,这里是系统内键管理员 41 NULL, // 传NULL,获取本地计算机的管理员 42 &adminSid,// 函数输出的管理员SID 43 &dwSize // 输入结构的大小,也作为输出 44 ); 45 46 // 获取本令牌的连接令牌(受限制的令牌都会有一个连接的令牌,受限制的令牌正式由主令牌所创建的. ) 47 TOKEN_LINKED_TOKEN linkToken; 48 GetTokenInformation(hToken, 49 TokenLinkedToken, // 获取连接的令牌句柄 50 &linkToken, 51 sizeof(linkToken), 52 &dwSize 53 ); 54 55 // 在连接的令牌中查找是否具有管理员的SID 56 BOOL bIsContain = FALSE; // 用于保存是否包含. 57 CheckTokenMembership(linkToken.LinkedToken, // 在这个令牌中检查 58 &adminSid, // 检查令牌中是否包含此SID 59 &bIsContain); // 输出TRUE则包含,反之不包含 60 61 62 63 if (bIsContain) { 64 printf("权限被阉割的受限制管理员账户, 部分权限被移处理 "); 65 } 66 67 68 return bIsContain; // 不是以管理员权限运行 69 } 70 71 return FALSE; 72 } 73 74 void checkAdmin() { 75 if (!IsAdmin(GetCurrentProcess())) { 76 77 // 以管理员身份运行本进程 78 // 1 获取本进程的文件路径. 79 TCHAR path[MAX_PATH] = { 0 }; // 需要初始化 80 DWORD dwPathSize = MAX_PATH; 81 QueryFullProcessImageName(GetCurrentProcess(), 0, 82 path, 83 &dwPathSize); 84 85 // 2 调用创建进程的API运行本进程. 86 ShellExecute(NULL, // 窗口句柄,没有则填NULL 87 _T("runas"), // 以管理员身份运行的重要参数 88 path, // 所有运行的程序的路径(这里是本进程) 89 NULL, // 命令行参数 90 NULL, // 新进程的工作目录的路径 91 SW_SHOW // 创建后的显示标志(最小化,最大化, 显示,隐藏等) 92 ); 93 94 // 退出本进程 95 ExitProcess(0); 96 } 97 }