首页
社区
课程
招聘
[原创]海莲花之Denes后门踩坑记录
发表于: 2020-7-3 09:55 5610

[原创]海莲花之Denes后门踩坑记录

2020-7-3 09:55
5610

图片描述
前两天看了某公众号发布的最新的海莲花分析报告,于是乎跟着学习一波,遂有了本文之后要提及的故事了。
图片描述
在文章的结尾,出现了一个名为Denes家族的后门样本,由于没有搞过,想着自己跟着文章的步骤搞一搞,结果一搞就一发不可收拾,遇到这种问题,各种坑,我是被坑哭了,不知道各位大佬可曾遇到过这样的问题。
图片描述

参考链接 样本来源

来来来,开始我的分析过程,首先是跟着文章发表者的分析过程,快速的找到Denes后门所在的内存区域,给它来个dump。
这个记录已经是我分析完之后才发写的所以,我为了展现出我所踩过的坑,又踩了一遍给大家演示,我太难了。
第一次分析,使用的是OllyICE,不带strongod的插件,异常设置如下所示,可能有读者会问我为啥要设置,当然是因为调试的时候发现会触发某些异常导致调试的问题,才会去设置异常。
图片描述
为了快速到达内存dump,我经过多次测试发现了一些好办法,首先是要等待恶意dll的加载,bp LoadLibraryW,让程序跑起来,看加载的位置。
图片描述
这时,取消LoadLibraryW,下VirtualAlloc断点,来看加载的SoftwareUpdateFiles.locale内容所在的内存区域。
图片描述
返回到用户层之后,发现了这段内存的地址,一般API返回地址通常在EAX中,内存窗口 等待写入过程。
图片描述
紧接着就有一个ReadFileAPI调用,估摸着就是准备加载SoftwareUpdateFiles.locale的内容了。
图片描述
此时内存中已经被写入了相关数据。
图片描述
这里还需要另外一个API来完成数据的解密写写入过程,RtlMoveMemory,这个API也是在分析文章中提到的,这里为了更快抵达战场,而进行的快速定位,bp RtlMoveMemory 之后,取消其他的断点,执行。
图片描述
这里的地址就是Denes文件的一部分了,在数据窗口,翻到头就可以发现,看到了熟悉的Dos头部。
图片描述
最后通过一串特征码定位,通过od的ctrl+s搜索命令序列来完成,记得勾选整个块,这串特征码是根据文章中提及的进入PE文件执行之前的最后一个调用call来确定的。
图片描述
可以看到这里od给了我们找到的结果,在call eax加断点,取消之前所有的断点执行到这里来。
图片描述
这时候整个Denes文件已经解码完成了,该收获成果了,从内存中dump出来看一看。本以为分析就此结束了,不曾想遇到个应急,没办法先放下了Denes的分析工作,先去把应急处理了。
处理完应急回来继续分析时,已经是第二天了。将dump文件一看,我有点懵,啥情况难道昨天dump的文件不对劲?
图片描述
Entry Point为0?,难道没有入口点?估计要第二次分析了,ε=(´ο`*)))唉,准备开始第二次分析吧。
第二次分析,因为之前的应急刚处理完,忘记了之前用的不是吾爱版的od,调试了之后发现程序莫名其妙的就崩溃了,我内心是崩溃的(之前调试不是好好的嘛,咋就崩溃了?)
图片描述
这错误也是尼玛的很奇怪,异常代码c0000005一般就是内存访问异常,但是给我的异常偏移为0?难道程序用到了0内存?一般情况下,访问0内存是会出现问题的,但是我记得昨天调试的时候,好像没有这个毛病啊?
就这样,第二次调试以失败告终,还特意在群里问了问各位大佬,依旧是没有得到什么有用的信息。没办法就这样开启了第三次调试。
第三次调试,不过这次用的x64dbg,此次调试很顺利,不过x64dbg有个比较麻烦的问题是API断下后,不像OD一样将参数集中在一起而是这样显示的。
图片描述
成功的从内存中dump出来了Denes样本,但是还是有很多疑问,对比看雪的一篇文章 https://bbs.pediy.com/thread-259596.htm。
图片描述
我发现个问题,为啥这个Denes资源不可见呢?这种问题几乎没遇到过,通过搜索引擎也得不到什么有效信息。
图片描述
想着要不就这么放弃了吧,反正也不差这么一点,但是之后自己做的和心里想的就表里不一了,继续从刚才的文章中寻找相关的信息。果然想的什么都是扯淡,动手搞一搞比啥都强,最后还是本着一颗追求到底的心,又开始第四次的调试过程。
第四次调试,还是用回了之前的OllyICE继续调试,跳过之前定位到Denes的过程,来到最后的call eax这里。由于要加载资源函数所有就下了相关的API断点,FindResource将A系列和W系列都打上断点,还有LoadResource断点,运行看是个什么情况。
图片描述
嗯?什么东西,这个hModule这个地址咋这么熟悉呢?数据窗口一跟随,卧槽咧,这不就是Denes嘛,果然在资源上做了一些手段,导致资源编辑工具无法直接查看,但是程序功能成功的定位,就表示内容还是存在的。
图片描述
通过查询API发现,LoadResource返回的地址,就是资源所在的内存地址。
图片描述
果不其然,在内存中找到了这段资源文件。
图片描述
将整个资源文件从内存中dump出来放着,以防像之前一样重头再来,然后我就像个傻逼一样的盯着这段资源端,一直知道程序跑起来都没看到解码的过程,心想着啥情况,不是说会进行解密嘛,我咋没看到这数据有啥变化呢???
图片描述
不过在这个过程中我发现出现了域名的解析,但是没有转向内存,因为一心傻逼的盯着了资源数据的变化。没得搞了程序已经跑飞了,只有第五次调试了。
第五次调试,在弄好之前的种种问题之后,缓慢仔细的调试着这段花指令代码,找到之前出现域名解析的call调用,应该就可以找到整段解密的过程了。现在的问题就是如何确定第二段代码需要的内存从哪里来?
再一次调试来到了Call eax这里,查看内存的情况,可以看到目前第二段内存并没有出现。
图片描述
现在步过call eax,其中触发了一次HeapCreate分配,不过大小只有1024,分配好的地址如下图所示。
图片描述
图片描述
卧槽咧,难道真的是用的HeapCreate来创建,并扩充了这个heap的大小?为什么这么说,来看一下内存的布局情况,已经无限接近于之前出现的第二段内存的情况了。
当从call eax返回之时,可以发现内存之前的1000大小变成了3000。
图片描述
正当我以为这就是第二段内存是,VirtualAlloc的出现让我觉得,heap应该不是第二段的内存了,这时候再来看看内存布局的情况。
图片描述
这时查看内存时发现,到头来一场空,代码似乎已经解码完毕了。
图片描述
不要以为我真的只是调试了5次,只是省略了很多很多重复的步骤,从刚才的测试中也知道了解密过程是在call eax中完成的,所以必须要跟进call eax进一步查看具体是什么回事。
第六次调试,也是我最后一次调试了,大多数已经弄明白了,就是最后的解密过程和内存分配问题了,已经找到了复制已解密的函数代码,但是依旧没有找到分配内存的API。
图片描述
第一次调用复制后的代码情况如下图所示。
图片描述
第二次调用复制后的代码情况如下图所示。
图片描述
自此整个解密的内存就找到了,只需要来一个dump即可拿出其中被解密出来的两个内置的dll文件了。

push ebx
push 1
push esi
add eax,esi
call eax
这一段特征码的作用是定位到解密完成的Denes的位置,通过eax的值,可以找到Denes的Dos位置。


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2020-9-20 16:02 被Risks编辑 ,原因: 将语言书面化
收藏
免费 5
支持
分享
最新回复 (2)
雪    币: 1
活跃值: (52)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
其实这两个问题也好解决,楼主要是有兴趣的话可以跟一下加载Denis后门的shellcode解密过程,手动提取出一个完整的没被破坏的PE文件(这个过程比较烦),再放到IDA里看就能容易不少。Denis后门混淆比较严重,过去的Denis后门是调用了一个封装了new[]和memcpy函数,直接New出一段内存然后拷贝数据。解密过程是在sub_10052830里,可以耐心跟一下就能找到。或者搜一下字节码:
00 88 00 01 00 00 0f b6 b0 00 01 00 00 0f b6 14 06
2020-7-17 15:37
0
雪    币: 300
活跃值: (2447)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
mark
2020-7-18 10:01
0
游客
登录 | 注册 方可回帖
返回
//