首先在这之前我们需要了解DEP和ASLP是什么,DEP 和 ASLR是微软默认的两个缓解措施。

DEP

DEP简单来说就是数据执行防护,可帮助保护你免受从不应启动的位置启动的可执行代码的损害。 DEP 通过将电脑内存的某些区域标记为仅用于数据,将不允许任何可执行代码或应用从这些内存区域运行。

它的工作原理是将指定的内存区域标记为不可执行,从而使攻击者更难以从这些区域执行恶意代码。

在哪里开启?windows默认是开启数据执行防护的,这里可以在Windows安全中心中,选择应用和浏览器控制,点击攻击防护设置。


我们也可以在Process Hacker中查看:

ASLR

ASLR随机排列关键数据区域的位置,例如可执行文件的基址以及进程地址空间中堆栈、堆和库的位置。这种随机化使攻击者更难预测内存布局,从而降低了成功利用内存相关漏洞的可能性。

也可以在安全中心找到:


同样也可以在Process Hacker中看到:

PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY 结构

接下来来看一下这个结构:

struct _PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY {
  union {
    DWORD Flags;
    struct {
      DWORD MicrosoftSignedOnly : 1;
      DWORD StoreSignedOnly : 1;
      DWORD MitigationOptIn : 1;
      DWORD AuditMicrosoftSignedOnly : 1;
      DWORD AuditStoreSignedOnly : 1;
      DWORD ReservedFlags : 27;
    } DUMMYSTRUCTNAME;

这个结构包含用于加载映像的进程缓解策略设置,具体取决于映像的签名。

MicrosoftSignedOnly

设置 (0x1) 以防止进程加载未由 Microsoft 签名的图像;否则保留未设置 (0x0) 。

StoreSignedOnly

设置 (0x1) 以防止进程加载未由 Windows 应用商店签名的图像;否则保留未设置 (0x0) 。

MitigationOptIn

设置 (0x1) 以防止进程加载未由 Microsoft、Windows 应用商店和 Windows 硬件质量实验室 (WHQL) 签名的图像;否则保留未设置 (0x0) 。

测试

所以我们可以通过3种方式来进行禁止EDR给我们的进程注入DLL,除非它是微软签名的DLL。

如下代码开启:

#include <iostream>
#include <Windows.h>
int main()
{
    PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY ply = { 0 };
    ply.StoreSignedOnly = false;
    ply.MicrosoftSignedOnly = true;

    if (SetProcessMitigationPolicy(ProcessSignaturePolicy, &ply, sizeof(ply))) {
            printf("设置成功");
    }
    else {
         printf("设置失败");
    }
    getchar();
}

这里我们使用Process Hacker来观察一下:

我们会发现它多了一项。


我们打开详细来看一下:

这里表示已为此进程启用图像签名限制。只允许使用Microsoft签名。


我们使用Avast Free Antivirus来测试一下:

Avast Free Antivirus会为你启动的应用程序注入一个aswhook.dll来监视你应用程序的一些行为。

但是我们会发现似乎没有起到什么作用。


这是什么原因造成的呢?

我们会发现应用程序是已经启动之后才设置得签名限制,这样的话并不能阻止EDR给我们的程序去注入监控DLL。

我们可以给他启动一个子进程,就比如说我们通过这个程序去拉一个子进程,而这个子进程才是我们真正的loader,或者恶意二进制程序,我们在启动的时候使用策略限制对其进行初始化,那么EDR就不会对其进行挂钩。

除非他有微软签名。

创建子进程如下API函数:
CreateProcessA

BOOL CreateProcessA(
  [in, optional]      LPCSTR                lpApplicationName,
  [in, out, optional] LPSTR                 lpCommandLine,
  [in, optional]      LPSECURITY_ATTRIBUTES lpProcessAttributes,
  [in, optional]      LPSECURITY_ATTRIBUTES lpThreadAttributes,
  [in]                BOOL                  bInheritHandles,
  [in]                DWORD                 dwCreationFlags,
  [in, optional]      LPVOID                lpEnvironment,
  [in, optional]      LPCSTR                lpCurrentDirectory,
  [in]                LPSTARTUPINFOA        lpStartupInfo,
  [out]               LPPROCESS_INFORMATION lpProcessInformation
);

lpApplicationName参数表示执行的模块的名称,这里我们给他设置为NULL就可以了。

lpCommandLine参数表示你要执行的命令行,这里我们设置为你要执行的子进程的名称就可以了。

lpProcessAttributes参数设置为NULL,表示新的进程不会继承进程的句柄。

lpThreadAttributes参数表示新进程的主线程不会继承调用进程主线程的句柄。这里设置为NULL。

bInheritHandles参数表示新进程是否将从调用进程继承句柄,这里设置为TRUE。

dwCreationFlags参数表示指定控制进程创建的附加标志EXTENDED_STARTUPINFO_PRESENT是一个标志,指示扩展结构的存在STARTUPINFO,它允许对新进程的创建进行更多控制。

lpEnvironment参数表示允许您为新进程指定环境块,这里设置为NULL。

lpCurrentDirectory参数表示新进程的当前工作目录。将其设置为NULL表示新进程将以与调用进程相同的当前目录启动。这很重要,因为我们想要执行相同的可执行文件来启动我们的子进程。

lpStartupInfo参数指向一个STARTUPINFO结构的指针。

lpProcessInformation此参数是一个指向结构的指针PROCESS_INFORMATION该结构接收有关新进程的标识信息,例如其进程句柄和线程句柄。

如下代码会创建一个sss.exe的子进程,这里其实可以换成我们的loader。

参考: https://www.ired.team/offensive-security/defense-evasion/preventing-3rd-party-dlls-from-injecting-into-your-processes

void CreateChildProcessWithMitigationOption() {
    PROCESS_INFORMATION pi = {};
    STARTUPINFOEXA si = {};
    SIZE_T attributeSize = 0;
    InitializeProcThreadAttributeList(NULL, 1, 0, &attributeSize);
    PPROC_THREAD_ATTRIBUTE_LIST attributes = (PPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, attributeSize);
    InitializeProcThreadAttributeList(attributes, 1, 0, &attributeSize);
    DWORD64 policy = PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON;

    UpdateProcThreadAttribute(attributes, 0, PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, &policy, sizeof(DWORD64), NULL, NULL);
    si.lpAttributeList = attributes;

    CreateProcessA(NULL, (LPSTR)"sss.exe", NULL, NULL, TRUE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, &si.StartupInfo, &pi);
    HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, attributes);

    return;
}

然后在我们设置禁止微软以外的DLL注入我们的进程之前,创建初始化子进程。

void LocalProcessMitigationOption() {
    PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY poy = { 0 };
    GetProcessMitigationPolicy(GetCurrentProcess(), ProcessSignaturePolicy, &poy, sizeof(poy));
    poy.MicrosoftSignedOnly = true;
    CreateChildProcessWithMitigationOption();
    SetProcessMitigationPolicy(ProcessSignaturePolicy, &poy, sizeof(poy));
}

看一下效果:


如下图可以看到子进程和父进程都成功设置了Mircrosoft only,我们来看下aswhook.dll有没有注入进去。


首先查看父进程会发现aswhook.dll依旧注入进去了。但是我们会发现它的子进程并没有被注入aswhook.dll