首页
论坛
专栏
课程

[原创]过所有主流杀软查杀的“免杀壳”编写揭秘

2019-7-23 01:43 5692

[原创]过所有主流杀软查杀的“免杀壳”编写揭秘

2019-7-23 01:43
5692

目 录

1

2 基本原理

2.1 前置知识

2.2 免杀方法

3 免杀壳开发(BY: AYZRXX)

3.1   免杀壳核心思想-伪装

3.2 免杀壳的编写框架说明

3.3 加壳后程序的执行流程图

3.4 写壳的注意事项

4 主要技术

4.1 壳代码纯SHELLCODE开发

4.2 API字符串隐藏

4.3 SHELLCODE传参方式

4.4 SHELLCODE动态获取外部参数

4.5 简单图片隐写技术(最大化的压缩体积)

4.6 入口点模糊技术

4.7 反沙箱分析

4.8 内存加载PE&支持壳上壳

4.9 兼容性较好的修复IAT表方法

4.10 代码混淆

5 总结

6 参考资料

1    序

    市面上常见的压缩壳(UPX)、VM壳(VMP)已经非常完善,笔者认为重写这类壳没有太大的实用价值,不如有限的时间投入到更有价值的地方。便萌发了编写一款 FUD 免杀壳的念头。还有笔者没有反病毒引擎开发经验,对反病毒引擎的检测方法都是通过查阅相关资料、实践分析后猜测得出,无法保证真实性。描述有误的请大家在评论区指出。


写壳目标:

1、"FUD"。“FUD” 代表恶意软件完全不可被检测到”的意思。

2、希望通过攻击者的角度来研究病毒查杀技术。

2    基本原理

2.1   前置知识

    由于编写该壳需要的前置知识较多,如果一一摊开解读每个知识点,就需要写一系列文章解释。因为笔者时间比较紧张的原因,此篇文章写得比较粗犷和偏方法论。想深入学习的同学可以论坛查找前辈们写的优秀文章,文章尾部也给了一些参考资料。

    基础知识:

1、编程语言:C/C++、ASM、Shellcode编程;

2、PE相关:熟悉PE结构(PE头、区段、IAT表、重定位表);

3、其他: PE加载原理。

2.2   免杀方法

Ø  针对传统的特征码匹配引擎、启发式引擎,常用的免杀方式如下:

²  特征码免杀法:最基本的免杀技术,不解释

²  通用免杀法:替换资源、增加签名、加冷门壳、加多重壳

²  源码免杀法:当前主流免杀技术,需要有源代码才能操作。通过修改病毒的特征字符串、动态API调用、修改编译环境、套程序外壳(MFC、SDK、QT)等

²  输入表(IAT)免杀法:启发式引擎会扫描目标程序的输入表中是否包含指定的函数特征序列(函数调用特征码)。

解决方案:(本段摘自未知作者)

1、 输入表函数移位法:输入这是最早也是比较简单的输人表免杀方法了,虽然效果已经不像当年那么好了,但却是学习免杀过程必须要掌握的基础知识。我们使用C32打开一个EXE文件,找到输入表段,找到我们定位出的特征输入表,比如ShellExecuteA就是,我们将其使用OO填充,然后在附近找到一片空白区域,将刚才找到的代码再粘贴到空白区域中,并记下新函数的地址,ShellExecuteA字符串最前面的那个“S”的地址减2,即00078925,这样就实现了转移,但是要想让程序知道我们转移的函数,我们还得告诉输入表,刚才那个地址是文件偏移地址,但不是内存地址,我们需要利用OC计算出新的输入表函数ShellExecuteA的内存位置,并在LoadPE中修改才行。

2、 输入表函数对调法:这个方法的原理就是将输入表函数名长度相同的函数在C32中进行对调,只有长度一样才不会出错,然后在LoadPE中做相应的修改即可。比如被查杀的函数是OpenFileA,存在于A.dll文件中,我们在b.dll中找到了一个GetATimeA函数,这两个函数名称长度一样,我们在C32中做了静态对换之后,还要将它们的RVA进行对换,操作很简单的,我就不演示了。

3、 手工重建输入表:关于输入表的重建,我想大家都非常熟悉了吧,这算是比较复杂的一种方法了,不过免杀效果非常好,这也是必须要掌握的方法哦!这个方法其实就是添加一个新区段,再把原来的输入表移到我们新建的区段上,重建主要是针对杀毒软件定位到大片输入表函数。

4、 输入表隐藏法:将输入表加密隐藏,然后内存解密修复输入表。属于保护壳常用的技术。

²  代码混淆、加花:通过对特征代码进行膨胀、乱序来干扰启发式引擎的分析,以及提升人工提取特征码的难度。

²  入口点模糊技术:参考"主要技术"目录下的"入口点模糊技术"

²  内存加载执行PE文件:壳的基本技术,论坛资料很多。


Ø  机器学习引擎(以360QVM为例),绕过方式如下:

    模拟正常程序的PE结构(该免杀壳方案能有效针对该引擎,或许还能污染机器学习引擎的分析结果)

 
 常见QVM引擎报毒原因:

HEUR/Malware.QVM06.Gen   一般情况下加数字签名可过

HEUR/Malware.QVM07.Gen   一般情况下换资源

HEUR/Malware.QVM13.Gen   加壳了

HEUR/Malware.QVM19.Gen   杀壳

HEUR/Malware.QVM20.Gen   改变了入口点

HEUR/Malware.QVM27.Gen   输入表

HEUR/Malware.QVM18.Gen  加花

HEUR/Malware.QVM05.Gen  加资源,改入口点



Ø  沙箱(虚拟机)行为分析引擎,绕过方式如下:

    简介:所谓“沙箱”安全技术,是指以计算机系统为基础对恶意软件的行为与特征进行分析并最终检测出恶意代码的方案。

解决方案:

1、通过检测沙箱(虚拟机)与物理机的差异化(参考:https://bbs.pediy.com/thread-225735.htm),检测到沙箱(虚拟机)则不执行恶意代码。

2、延时180+秒(效果比较好)加载恶意代码,沙箱(虚拟机)的检测结束后无法探测到恶意行为。笔者比较推崇此方法,因为此方法针对的是所有反病毒厂商的沙箱(虚拟机)检测。

3、挖掘开机启动程序的代码执行漏洞,配合白加黑技术来执行敏感行为。


Ø  主动防御:

     简介:主动防御是基于程序行为自主分析判断的实时防护技术,不以病毒的特征码作为判断病毒的依据,而是从最原始的病毒定义出发,直接将程序的行为作为判断病毒的依据。

     360主动防御模块经过做黑灰兄弟们的不懈努力,已经非常完善了,绝大部分常规、非常规的行为绕过方式均已被拦截,并弹出一个默认阻止的小框框。

1、继续挖掘非常规方法绕过主防的拦截,主防未监控到的区域。

2、白程序(包含在杀软白名单库中的程序)加黑程序方式来执行高危行为,写启动项、键盘记录等。(不过要注意的是360白程序判定逻辑,灰程序加载的白程序 = 灰程序,因此需要绕过主防的程序执行链监控)

3    免杀壳开发(by: AYZRxx)

3.1   免杀壳核心思想-伪装

    经过10多年的发展,反病毒引擎已经在误报&查毒粒度之间取了一个比较好的平衡,常规的免杀技术(特征码免杀、源码免杀)处理成本越来越高。不过反病毒引擎天然存在某些"缺陷",例如正常软件会加商业保护壳,导致会受到商业壳的制约,无法将所有壳标记为病毒。

    由于内存执行"被加壳程序"是壳的基础行为,而内存执行PE这个"壳的基础行为"可以很好的将"被加壳程序"的特征码隐藏起来。因此编写一款无特征码壳是一个非常好的反杀软查杀(特征码、启发式)的方案。

1.   模拟正常PE程序结构, 模拟正常PE程序结构, 模拟正常PE程序结构

2.   特征代码最小化,并且被查杀后可通过混淆引擎来混淆壳代码,达到快速变种、快速免杀的效果。

3.   笔者不建议进行任何可能提高程序熵值的操作,尽可能将壳程序的PE格式、数据结构、代码执行顺序与正常程序保持一致。

3.2   免杀壳的编写框架说明

    这个免杀壳的代码主要分为三部分:

加壳器:这部分代码用来将被加壳程序、傀儡程序、壳代码拼装处理,组合生成一个免杀的PE文件。

CodeLoader(壳代码):这部分代码用来反杀毒引擎、内存加载执行PeLoader,需要编译为Shellcode代码。

PeLoader(壳代码):这部分代码用来内存执行Shelled(被加壳程序),需要编译为Shellcode代码。



²  关键词解释

Ø  Shelled:被加壳程序

Ø  Pepput:傀儡程序,用来伪装成正常PE文件,植入壳代码的载体

Ø  CodeLoaderCode:壳代码

Ø  PeLoaderCode:壳代码

Ø  CodeLoader:作用是反调试、反沙箱(虚拟机)、加载执行PeLoader(只有这段代码暴露在杀毒引擎的检测范围之内,只需要对这段代码做混淆即可快速免杀)

Ø  PeLoader:作用是加载执行Shelled(被加壳程序)



Ø  该免杀壳框架的优点:

1、 加壳后只有CodeLoader代码暴露在杀毒引擎(静态)检测范围内,混淆前代码只有1KB左右大小,由于可定位的特征代码少,特征码免杀较为简单。

2、 传统的Shellcode使用自解密的方式来模糊特征,需要代码段内存具有可写属性,该操作会导致启发式引擎报毒。CodeLoader代码则使用了代码混淆技术来达到免于杀毒引擎查杀的效果,代码段内存在PE结构种无需具有可写属性。

3、 并且只需要在CodeLoader代码加入检测沙箱、虚拟机的功能代码,绕过杀毒引擎的行为检测,就做到了基本的无特征码化、无行为化。

4、 无需创建傀儡进程,远程写内存这种高危行为杀毒软件是不允许的。

5、 内存加载PE文件就是老生常谈了,不再做过多的阐述,论坛里面有大量的优秀文章可供参考。

3.3   加壳后程序的执行流程图

    通过在OEP(程序入口点)附近inline HOOK劫持执行流,防止杀毒引擎检测入口点是否被篡改(360会特征匹配OEP代码),跳转到CodeLoader处执行代码,随后内存执行PeLoader,最终加载Shelled(被加壳程序)。

    "加壳后程序" 的具体执行流程:OEP-->壳代码HOOK点--> CodeLoader首部jmp-->壳代码CodeLoaderCode-->内存加载执行PeLoader-->PeLoader首部jmp-->壳代码PeLoaderCode-->内存加载执行Shelled(被加壳程序)

    "加壳后程序" = "傀儡程序" 植入壳代码(CodeLoader) + 伪造资源(PeLoader)


加壳后程序的执行流程

3.4   写壳的注意事项

1.   最核心的就是伪装,完全模拟正常PE程序。

2.   壳代码没有异常行为,不触发杀软的检测规则。

3.   傀儡文件的OEP代码尽量避免影响被加壳程序的正常执行

4.   核心功能为减少暴露面,提高做免杀的速度

5.   通过混淆引擎混淆壳代码,达到混淆后无特征代码。

6.   支持壳上壳,通过加其他VM壳处理内存特征码、反分析。

4    主要技术

4.1   壳代码纯Shellcode开发

将壳代码编译为Shellcode代码,方便移植、混淆、特征码定位。Shellcode开发方法论坛搜索即可,非常多的帖子。

4.2   API字符串隐藏

Shellcode编程的常规编写技巧,将API字符串转为HASH,壳代码通过HASH来获取API地址。此技术主要用于缩短Shellcode体积、干扰分析人员分析。

4.3   ShellCode传参方式

    笔者设计的一个简单的Shellcode传参方式。这种传参方式有一些弊端,将PARAM_CODE_LOADER参数结构体和Shellcode代码植入到傀儡文件的代码段后,由于PARAM_CODE_LOADER参数结构体不是ASM指令,可能会导致杀毒引擎在代码段中扫描到这段畸形数据(PARAM_CODE_LOADER参数结构体)而报毒。

    解决方法:修改参数结构为【mov eax,0x12345678(需要传递的参数)】即可解决该问题,壳代码CodeLoaderCode只需要简单处理下即可使用传递的参数。


图-CodeLoader数据结构

4.4   Shellcode动态获取外部参数

    参考"图-CodeLoader数据结构"可以发现壳代码CodeLoaderCode(EntryPoint函数生成在壳代码CodeLoaderCode的首部)是储存在PARAM_CODE_LOADER结构体的尾部。

    因此只需要动态定位到&EntryPoint函数的内存地址,然后减去sizeof(PARAM_CODE_LOADER)就可以获取到加壳器传递的参数数据了。


4.5   简单图片隐写技术(最大化的压缩体积)

    该技术的作用是为了隐蔽的储存数据,减少暴露在外的特征代码。当前壳的图片隐写代码,只是简单的将PeLoader加密后附加在"图片头"的尾部,修复"图片头"后生成可正常显示的图片,但是此法的生成的图片特征较为明显,不过体积较小。因为真正的图片隐写会增大体积,才采用此法。

    图片隐写技术简单来说,就是根据图片的数据结构,将需要伪装的数据转换为图片像素点数据保存在图片中,生成新的标准结构图片。


4.6   入口点模糊技术

    QVM引擎已经对主流编译器编译的程序,从入口点(OEP)开始提取一段特征代码作为判断依据,因此只要修改入口点代码QVM引擎就会报“HEUR/Malware.QVM20.Gen”。

    杀软检测入口点代码的绕过方法:

1、 使用壳代码完全伪造主流编译器编译的程序的入口点特征

2、 不修改入口点开始处的代码,而是在QVM引擎提取的入口点特征代码的尾部劫持执行流(此壳就是使用的这个方法)


4.7   反沙箱分析

    注:由于沙箱和虚拟机的概念有些混淆和冲突,读者直接将沙箱理解为虚拟机即可。

方法一:安全厂商的沙箱检测超时一般是2-3分钟左右,只需要延时等待沙箱检测超时在执行后续代码,即可绕过沙箱的行为检测。(沙箱过滤了一些常规的延时方法,延时方法读者可以自己研究下)

方法二:当然壳代码中直接内置反沙箱代码来得更直接,常规是通过检测虚拟机痕迹(MAC地址、注册表、文件、进程、服务)或虚拟机漏洞指令(Red Pill、No Pill、str、查询I/O端口)等方法来检测虚拟机,不过大部分常规方法已经被安全厂商的沙箱给反反虚拟机过滤了。此方法不适用于检测所有种类的沙箱。

4.8   内存加载PE&支持壳上壳

    当前使用的内存中加载PE技术,是通过将"被加壳程序"内存展开后,覆盖到当前进程的ImageBase处,随后修复"被加壳程序"的IAT表,设置区段属性,最终调用"被加壳程序"的OEP将执行权限交给"被加壳程序"。这种写壳方式的天生就支持壳上壳功能。

    壳上壳的功能主要是为了躲避内存查杀。可使用VMP、TMD、SE等虚拟化壳的代码虚拟化功能来模糊化被加壳程序的内存特征,当然使用自写的VM、混淆引擎更好,不过写一个稳定、兼容性好的VM、混淆引擎耗时太长。

    加多重壳需要注意关闭内层壳的校验基址,如下图的VMP:


4.9   兼容性较好的修复IAT表方法

    兼容性较好的修复导入表(IAT)方法,优先使用INT表来获取API地址。解决有些编译器编译的程序导入表(IAT)不规范的问题(Delphi)。

	//获取导入表首地址
	IMAGE_DOS_HEADER* pDosHdr = (IMAGE_DOS_HEADER*)pImageBaseAddr;
	IMAGE_NT_HEADERS* pNtHdr = (IMAGE_NT_HEADERS*)(pDosHdr->e_lfanew + (DWORD)pImageBaseAddr);
	IMAGE_DATA_DIRECTORY* pDataDirHdr = (IMAGE_DATA_DIRECTORY*)pNtHdr->OptionalHeader.DataDirectory;
	IMAGE_IMPORT_DESCRIPTOR* pImport = (IMAGE_IMPORT_DESCRIPTOR*)(pDataDirHdr[1].VirtualAddress + (DWORD)pImageBaseAddr);

	while (pImport->OriginalFirstThunk != 0 || pImport->FirstThunk != 0)
	{
		//获得当前DLL名
		char* chName = (char*)(pImport->Name + (DWORD)pImageBaseAddr);

		//加载模块
		HMODULE hModule = My_LoadLibraryExA(chName, 0, 0);

		//如果有INT表则通过INT表来修复IAT表
		DWORD* pReferenceTab = nullptr;
		(pImport->OriginalFirstThunk == 0x0) || (pImport->OriginalFirstThunk == 0xFFFFFFFF) ?
			pReferenceTab = (DWORD*)(pImport->FirstThunk + (DWORD)pImageBaseAddr) :
			pReferenceTab = (DWORD*)(pImport->OriginalFirstThunk + (DWORD)pImageBaseAddr);

		//被修复的IAT表
		DWORD* pIatTab = (DWORD*)(pImport->FirstThunk + (DWORD)pImageBaseAddr);

		DWORD dwIatIndex = 0;
		while (pReferenceTab[dwIatIndex] != 0)
		{
			//判断是什么方式导入 <序号> <名称>
			if ((pReferenceTab[dwIatIndex] & 0x80000000) == 0) //最高为1是序号导入
			{
				IMAGE_IMPORT_BY_NAME* pByName = (IMAGE_IMPORT_BY_NAME*)
					(pReferenceTab[dwIatIndex] + (DWORD)pImageBaseAddr);

				//获取到的API地址
				pIatTab[dwIatIndex] = (DWORD)My_GetProcAddress(hModule, pByName->Name);
			}
			else
			{
				DWORD dwIndex = pReferenceTab[dwIatIndex] & 0x7FFFFFFF;
				//获取到的API地址
				DWORD dwApiAddr = (DWORD)My_GetProcAddress(hModule, (char*)dwIndex);
				pIatTab[dwIatIndex] = (DWORD)dwApiAddr;
			}
			++dwIatIndex;
		}
		//指向下一个结构体
		pImport += 1;
	}

4.10  代码混淆

    主要用于混淆壳代码,躲避特征码查杀。

5    总结

    笔者经过了一些实验和测试,可以确定该方案的免杀效果很好,兼容性也不错。加完壳之后,基本可以无视特征检测、360QVM、启发式检测这类反病毒引擎,效果可以看下面的图。

    "大灰狼远控"(换别的马效果一致,因为壳没被杀)加完壳在稍微处理一下,传到VirusTotal上扫描只有6家不是那么主流的杀软检出,国内全Miss,国外比较强的引擎(Bitdefender、Kaspersky、Symantec、Avast、Avira、McAfee、Microsoft、ESET-NOD32、DrWeb)也都Miss。


    360安全卫士打开全部本地引擎,联网云引擎测试。大灰狼远控直接上线,所有引擎全Miss。


    

    由于免杀壳这种软件放出来会有比较大的危害,也很敏感。笔者把壳的主要编写流程、思路、主要技术已经基本上写得比较清楚了,就不开源和提供测试工具了。还有笔者有时间的话会写一些查杀这种免杀方式的思路,欢迎大家集思广益在评论区发表思路,笔者向大家多学习学习。

    笔者现在主要研究漏洞这块了,有兴趣一起交流技术的小伙伴请加,扣扣群:565158847


免责声明:此文章只在看雪论坛发布,只可用于看雪论坛的朋友交流学习,禁止任何人转载到其他站点,禁止用于任何非法用途。如有任何人凭此做何非法事情,均于笔者无关,特此声明。

笔者不做黑灰,勿扰!


6    参考资料

玩命(网名)-著《软件保护壳专题https://bbs.pediy.com/user-181595-1.htm》系列文章

任晓珲-著《黑客免杀攻防》书

戚利-著《Windows PE权威指南》书

秋伤~~!(网名)-著《一个exe可执行文件的生与死(运行原理)》文章



[公告]安全服务和外包项目请将项目需求发到看雪企服平台:https://qifu.kanxue.com

最后于 2019-7-24 19:05 被暗夜之刃编辑 ,原因:
最新回复 (20)
skyun 3 2019-7-23 08:45
2
0
牛逼。
nevinhappy 2 2019-7-23 08:51
3
0
666,谢谢LZ的分享!
mlgbwoai 1 2019-7-23 09:33
4
0
666 我也写过基本一模一样的壳子,其中内容中的精华我感觉是:长时间执行垃圾指令进行沙箱逃逸
还有一点比较难操作的是:壳本身(单pe文件)   如何给被免的pe文件动态的加花混淆。
MsScotch 2019-7-23 09:38
5
0
github上有类似成品
最后于 2019-7-23 09:38 被MsScotch编辑 ,原因:
妖气17 1 2019-7-23 10:14
6
0
感谢分享
芃杉 2019-7-23 10:26
7
0
mark
Carezy 2019-7-23 10:52
8
0
马克
fengyunabc 1 2019-7-23 10:54
9
0
感谢分享!
lipss 4 2019-7-23 11:37
10
0
赞,写得不错哦
miWusn 2019-7-23 12:33
11
0
学习了
elianmeng 1 2019-7-23 13:10
12
0
给ip修改为外网ip看看,本地连接貌似不专业
暗夜之刃 2 2019-7-23 13:21
13
0
elianmeng 给ip修改为外网ip看看,本地连接貌似不专业
一样的效果,我已经实战测试过了
satadriver 2019-7-23 17:08
14
0
求github地址
一二三六 2019-7-25 17:28
15
0
厉害 学习了
Anskya 20 2019-8-1 18:31
16
0
从2005年NtPacker2诞生已经14年了。。。
yirucandy 4 2019-8-2 10:04
17
0
楼主厉害了!
蓝色淡风 2 2019-8-13 13:23
18
0
还在原单位么?跳槽了没
nqxcwl 2019-8-13 14:10
19
0
楼主溜溜溜
查林 2019-8-20 17:01
20
0
MsScotch github上有类似成品
求一个github链接
小木鱼 2019-8-20 18:22
21
0
楼主是个大牛,爱学习的人有福了!
游客
登录 | 注册 方可回帖
返回