學習《逆向工程核心原理》,在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("創建進行快照失敗\n"); 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\n", 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\n", 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\n", 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\n", 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. \n"); 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]\n", 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]\n", 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\n", 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\n", 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\n", sz); 269 printf("THREAD_PARAM WriteProcessMemory() fail : err_code = %d\n", GetLastError()); 270 return FALSE; 271 } 272 273 // Allocation for ThreadProc() 寫入代碼 274 dwSize = abs((int)((DWORD)InjectCode - (DWORD)ThreadProc)); 275 276 printf("dwSize:%d\n", 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\n", 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\n", sz); 295 printf("ThreadProc() WriteProcessMemory() fail : err_code = %d\n", GetLastError()); 296 return FALSE; 297 } 298 printf("ThreadProc()寫入大小:%d\n", 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\n", GetLastError()); 308 return FALSE; 309 } 310 311 WaitForSingleObject(hThread, INFINITE); 312 CloseHandle(hThread); 313 CloseHandle(hProcess); 314 printf("code inject end\n"); 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>\n", 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\n"); 336 printf("輸入要注入的進程pid:\n"); 337 scanf_s("%ls", pid, 10); 338 printf("請選擇功能:1.dll注入 2.代碼注入\n"); 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!!!\n", path); 347 else 348 _tprintf(L"InjectDll(\"%s\") failed!!!\n", path); 349 printf("輸入q 卸載dll\n"); 350 while (getchar() != 'q'); 351 TCHAR *p = _tcsrchr(path, '\\'); 352 if(EjectDll((DWORD)_tstol(pid), p+1)) 353 printf("卸載dll成功!\n"); 354 else 355 { 356 printf("卸載失敗!\n"); 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("管理員賬戶,並擁有全部的權限,可以給令牌添加任何特權\n"); 23 return TRUE; 24 } 25 // 4. 如果是其他的, 則需要以管理員身份重新運行本進程. 這樣就能以第三步的方法解決剩下的問題. 26 else if (TokenElevationTypeDefault == tokenType) { 27 printf("默認用戶, 可能是一個普通用戶, 可能是關閉UAC時登錄的管理員用戶\n"); 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("權限被閹割的受限制管理員賬戶, 部分權限被移處理\n"); 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 }