顺利毕业 发表于 2019-4-5 14:48

分析混淆软件,尝试解密被加密的文件

本帖最后由 顺利毕业 于 2019-4-6 14:19 编辑

样本简介:
代码混淆过,不太好分析。
生成随机秘钥来加密用户文件,从而实施勒索行为。
本贴的内容包括:
1、介绍勒索软件加密用户文件的流程;
2、对这个混淆软件进行静态分析、动态调试分析;
3、修改这个软件,尝试复原被加密的文件;
(整理的初衷是尽可能详细地把全过程交代清楚,导致帖子比较长。先跟大家说声抱歉。
如果不想全部看完的话,可以选择自己感兴趣的部分来看~)

帖子的大致目录:
一,本贴涉及的工具与文件
二,介绍勒索软件加密用户文件的流程
三,静态分析
      1、软件初印象
      2、静态分析操作的思路
      3、开始分析。
四,动态分析
      1、感谢丑小鸭大佬的学习贴
      2、目的
      3、操作思路
      4、动态分析
五、勒索软件的卸载
六、尝试恢复被加密的用户文件
      1、操作思路
      2、尝试复原的准备工作
      3、尝试复原
      4、查找加密结果不一致的原因
      5、从尝试到放弃
七、总结

      1、为什么仅加密头1024个字节
      2、为什么解密文件失败


一,本贴涉及的工具与文件

JEB:可查看恶意软件的smali代码与对应的java代码,用于静态分析;

Apktool:可对恶意软件进行反编译,从而获得smali代码;

文件编辑器:对smali代码进行修改。不用怀疑,就是每个系统里自带的文件编辑器;

Android Device Monitor:可用于查看模拟器的运行状况,从而定位恶意软件的运行进程等信息;

Android Studio:可对smali代码进行debug;

mumu模拟器:安装恶意软件;

signapk.jar:用于签名软件。

testKey.pk8文件与testKey.x509.pem文件:用于对重打包后的软件进行签名,不签名就没法安装运行了。




二,勒索软件加密用户文件的流程(以加密/sdcard目录为例)

1、申请权限

申请对外存(/sdcard目录)的“写权限”,即在AndroidManifest.xml文件中申请“android.permission.WRITE_EXTERNAL_STORAGE”权限,并在代码中判断/sdcard目录是否“可写”;

2、遍历文件

遍历/sdcard目录下的所有文件,根据黑白名单选择即将要加密的用户文件。

2.1 若采用白名单模式,即勒索软件指定自己要加密的文件类型(如doc,docx,jpeg,png等),若/sdcard目录下文件的后缀名在这些文件类型范围内,则被勒索软件列入“将要加密的文件列表”中;

2.2 若采用黑名单模式,即勒索软件指定自己不可以加密的文件类型,若/sdcard目录下文件的后缀名在这些文件类型范围内,则勒索软件将跳过该文件,将其它文件列入“将要加密的文件列表”中;

3、加密用户文件

采用官方API来加密或自定义方法来加密。

4、删除原文件

否则它的加密有何意义。有些情况下不需要删除原文件,因为原文件被加密内容直接覆盖。

5、进行勒索行为

告知用户“你的文件被我加密啦,给钱就帮你恢复”。勒索行为的实现方式大多以文字的形式出现在手机界面,也可能出现在被加密文件内,又或是以音频的形式来进行勒索。

6、解密文件

用户提交赎金后,勒索软件对文件进行解密。稍微有良心一点的勒索软件,才会进行到这步。有些勒索软件,根本就不提供解密的操作,“拿钱不办事”。



三,静态分析

1、软件初印象

要分析一个软件,总得先看看它长啥样吧。是帅小伙,还是邻家小姐姐,不扔到JEB怎么看得出来呢。那么,扔!

打开JEB,直接把软件拖进来,或者用“打开文件”也一样:



(图片1)




(图片2.png)

从上面两张图可以认定,混淆得挺彻底的,暗暗搓手:是个学动态调试的好机会啦。直接上手动态调试?上是要上的,但不是现在,得先进行一波静态分析,否则动态调试时debug都不知道断点该打在哪里了。

所以初印象是啥,就是混淆过了呗,没啥。


2、静态分析操作的思路

加密文件型的勒索软件跟其他类型的恶意软件不同,它的特征更明显。
分析其他类型的恶意软件时,最好是从入口Activity一步一步往下分析(如图片1中被圈出的activity,同时有LAUNCHER和MAIN的)。
但此类恶意软件不用,因为它的恶意行为非常突出,加密+勒索,至于其他行为就不在这个帖子的考虑范畴内了。
在(二)中,我有提到,该类型勒索软件会遍历文件夹,从而找到想要加密的文件。
遍历文件夹,一般用的是File->listFiles()方法(参数及类型我就不写了),而该方法是不会被混淆的,找到listFiles()方法后,就可找到该软件攻击的目录,往下继续分析可找到加密文件、解密文件的部分。
找到解密文件的部分后,修改该软件的smali代码,尝试在未提交赎金的情况下调用“解密文件”的功能,从而达到复原文件的目的。


3、那么,开始分析啦。我先分析为敬。

3.1、用JEB打开该软件,直接在Bytecode里全局搜“listFile”:



(图片3.png)

查看listFiles()被调用处的前后方法,加解密方法离得不远呀。
   



(图片4、5、6)

到这有两个疑问:(1)可疑字符串e.a的值是什么,做什么用的;(2)e.e的作用是什么,以及在哪被使用。


结合该类型恶意软件的行为,我们不难猜测,此处的行为应该是:遍历目录下所有文件,对每个文件进行判断,文件名是否包含可疑字符串1或可疑字符串2,将符合某一条件的文件名保存到e.e 中。可以合理地猜测,后续将会对e.e保存的文件进行加密或解密。


为方便查找,将e.a重命名为“可疑字符串EA”,但以本人现在的能力无法静态还原出e.a的值,故打算在后续动态调试时查看e.a的值。


3.2、追查e.e在哪被调用。为了方便在搜索,先重命名为“可疑文件列表”,然后在整个bytecode里全局搜索:



(图片7.png)
   


(图片8.png,图片9.png)

从图片8中可看出,v0_4是某一文件的具体文件名,且在图片9中对v0_4做了些坏事。那我就直接把图片9中相关的方法进行重命名反混淆,方便你们看,直接把相关的方法也贴出来,并做了些解释(图片10-14是相关方法的具体实现,图片15是图片9反混淆后的结果):



(图片10、11、12、13、14)

其中:

图片12是用官方API进行加密操作。

图片13中看到,最多仅加密头1024个字节。

图片14中的Arrays.copyOfRange(arg6,arg7,arg6.length)是对arg6进行复制,从arg7(如arg7等于0)的位置开始复制,直到复制完arg6结束。

图片14中的System.arraycopy(arg5,0,v0,0,arg5.length)是将arg5整个复制到v0中。


将图片9反混淆后的结果如下:



(图片15.png)

反混淆后,整个代码结构更符合“找文件---加密---解密”了呢,关键的操作流程已经找到了呢,高兴得搓手手。

等等,是不是高兴得有点早了,这个f.m是个啥呀?那,动态调试吧?静态分析到这,可以先告一段落呢。



四、动态分析

1、感谢一下

丑小鸭大佬的学习贴:https://www.52pojie.cn/thread-658865-1-1.html。感谢前辈~


2、目的

1.1、确定恶意软件的攻击目标的特性,也就是打算加密哪些类型的文件,doc、txt之类的?即,确定e.a(可疑字符串EA)的值。

1.2、确定加密时所使用的密钥,从图12中可以看到与f.m有关。


3、操作思路

获取该软件的smali代码,放到Android Studio里,在e.a和f.m被赋值地方的smali代码处打断点,在模拟器上运行该软件,到Android Studio里开启debug模式,记录下这两个值。


4、动态起来~

4.1、获取smali代码。在终端中使用命令“apktool d Ransom.apk”,其中Ransom.apk在这里是这个软件的名称79e6…a71f.apk,d表示反编译(decode)。故这里的操作是对该软件进行反编译操作:



(图片16.png)

反编译后,可在该软件所在目录下发现一个同名的文件夹:



(图片17、18)

看到smali文件夹了嘛,smali代码来得如此容易~美滋滋


4.2将smali代码放到Android Studio里。

具体操作:

4.2.1、在其他任意地方新建一个文件夹,并把图片18中的smali文件夹拷贝过去,并重命名为src:
   


(图片19、20)

4.2.2、运行Android Studio ,在首页选择“Open an existing Android Studio project”,选中图片20中的test文件夹,打开后记得选择为Project:
   


(图片21、22)

4.2.3、安装smaliIdea插件,插件文件可以去丑小鸭大神的帖子里拿,记得给他一份感谢呀~



(图片23)

4.3、打开Android Device Monitor。在Android Studio3.1.3里没有Android Device Monitor的,可以去自己的sdk目录下看。怎么找自己的sdk目录呢,学习贴:https://blog.csdn.net/littlefishvc/article/details/80521058。也就是在Android Studio里打开preferences:



(图片24.png)

上图中的/x/y/z/Android/sdk目录就是啦,至于x,y,z是啥,就自行带入自己的啦。不知道就问你的Android Studio去~

在终端进入sdk目录,进入tools目录,找到monitor,就是它,Android Device Monitor就是它,盘它!噢不,bash 它!



(图片25.png)

4.4、模拟器上场啦。该软件实在是不建议真机运行。祭上mumu模拟器~

4.4.1、运行模拟器,并把该软件拖进模拟器中进行安装,又或是用命令adb install Ransom.apk也行~安装后,别着急运行,别~



(图片26.png)

4.4.2、调用软件的入口组件。入口组件为“软件包名/入口activity”。适用命令“adb shell am start –D –n PackageName/MainActivity”,这里am start即“启动”的意思,-D表示进入debug模式,-n表示组件,PackageName就是包名啦,需要用真实的包名代入,MainActivity就是入口Activity,也需要用真实的值代入噢,这里只是形参啦。这是可以看到,模拟器已经进入debug模式了,击掌~



(图片27.png)

4.5、这个时候,回到Android Device Monitor,找到该软件,记住圈圈中的两个值呀,马上就要用到了。

4.6、在终端中输入“adb forward tcp:2035 jdwp:8700”,这样电脑跟模拟器就可以通信并且连接到该恶意软件的进程啦(虽然模拟器安装在电脑上,但我们要把它当作一个独立个体来看,不妨就把它当作真机,本身模拟器就是真机的替身)。

4.7、但是,Android Studio还没准备好通信呢,来,设置一下。在Android Studio里选择:Run---Edit Configurations----“+”,选择“remote”,修改名字为“testRemote”或是其他你喜欢的名字,以及port值为8700:



(图片28、29)

4.8 等不及要debug啦,但是我们还没打断点呢。我们这次动态分析,想要确定的是f.m与e.a的值,那么就得在Android Studio的赋值部分的smali代码处打断点。直接在smali代码中找会让人头大。让我们回到JEB,找到f.m被赋值的地方:



(图片30.png)

并可直接在Bytecode里找到对应的smali代码:



(图片31.png)

回到Android Studio,打开f.1.smali文件,在其中找到与图片31对应的地方,打断点:



(图片32.png)

同理e.a也是一样的操作:



(图片33、34、35)

4.9 开始debug啦。在Android Studio : Run---Debug testRemote(如果你刚刚起名不是testRemote的话,那就是Debug yourName啦)。这是该恶意软件还未运行到我们打断点的地方,因为它需要用户的一些授权,所以Android Studio还在等待用户操作。所以,我们现在回到模拟器上去,不就是要加密我们的文件嘛?满足它!
   


(图片36、37、38)

4.10、这时候,Android Studio已经运行到我们打断点的地方了,来,赶紧记录值了。这个时候,e.a和f.m的值就不是迷了。



(图片39、40)

4.11、结合一下静态分析的几个图,把e.a的值与f.m的值带进去,我们重新梳理一下:

图片5、6:若v0文件可被“写”,且v0的文件名不包含“cryeye”(即e.a的值)且不包含“.apk”(即e.a的值),则将v0添加到e.e中。(例:/sdcard目录下的testManifest.txt可被写,且文件名不包含“cryeye”与“.apk”,故将testManifest.txt添加到e.e中)

图片7、8、9中的v0_4就是上面的v0。(例:v0_4的其中一个值为testManifest.txt)

图片10:对于arg5这个文件,是否存在以“.cryeye”为后缀的文件存在。(例,对于testManifest.txt文件,判断是否同时存在testManifest.txt.cryeye文件。)

图片12:Cipher v1=Cipher.getInstance(“AES/ECB/NoPadding”) ,创建cipher对象v1用于加解密。其中算法为AES,模式为ECB,填充方式为NoPadding。这边就先不多解释啦。放到总结的地方再聊聊?

图片15:
(1)当this.i为true时,进行加密行为。这里直接用testManifest.txt这个例子来说了,假设该文件有5555个字节。读取testManifest.txt的头1024个字节到v1中,若testManifest.txt.cryeye文件不存在,对v1进行加密。读取testManifest.txt的全部内容,并用v1覆盖该内容的头1024个字节,并将新的内容赋值给v1。也就是说,v1现在的头1024个字节是被加密的,剩下的字节是testManifest.txt的原始内容。(此处还未将v1写入文件)This.h=this.h+”/sdcard/testManifest.txt”+”…[“+“5555”+“bytes]”+“\n”,即this.h=this.h+”/sdcard/testManifest.txt…\n” 。
(2)当this.i为false时,进行解密行为。这里依旧用testManifest.txt来说。若testManifest.txt.cryeye文件存在,读取testManifest.txt文件的头1024个字节进行解密,同时读取testManifest.txt的全部内容,将解密后的1024个字节重新放回头部并赋值给v1 。也就是说,v1此时应该保存着testManifest.txt的全部原始内容。(此处还未将v1写入文件)。This.h就不写啦,跟上面的操作差不多。

这样,是不是对这个恶意软件有些了解了呢?那我们就来看看它坏事做得怎么样了,是不是如它代码里说的那样~


4.12、这个时候,看模拟器上,勒索软件告诉我们,它已经加密6个文件啦。



(图片41.png)

那,看下被加密前后的对比?打开终端,利用adb shell进入查看模拟器的信息,利用cd sdcard进入sdcard目录,从下图的对比可以看出3个文件只被加密了2个,ShunLiBiYe.txt没被加密是因为它不到1024个字节所以这个勒索软件直接跳过,不屑于去加密啦。



(图片42.png)

从图片42中看到出现了两个带.cryeye的文件,这难道就是被加密后的文件?但是,原文件还在,这是什么操作?用“du –sh *”命令,该命令用于查看当前目录下所有文件与文件夹的大小。在这里可以看出来.cryeye文件都是空文件!



(图片43.png)

那么,加密的内容就应该是放在原文件里吧?利用cat命令查看一下,如我们所愿:



(图片44.png)

为什么这个软件只加密头1024个字节呢?这里先不告诉你,等你看完了就找到答案啦,嘿嘿嘿。

一切都这么顺利,勾起了想要解密的欲望~解密前,得先卸载这个勒索软件吧。


五、勒索软件的卸载

1、停止恶意软件

该软件没法手动退出,那就只能对它不客气啦,用“adb shell am force-stop PackageName”来强制停止运行,记得把PackageName换成具体的包名呀。


2、取消授权
由于前期给这个软件授权了设备管理,所以现在还没法直接卸载,得先取消设备管理,点击“设备”—“安全”—“设备管理器”—“取消勾选”---“取消激活”:

   


(图片45、46、47、48、49)
3、卸载:



(图片50.png)
4、卸载完成~记得现在不要删除刚刚被加密的文件噢,要留着后面解密用呢。




六、尝试恢复被加密的用户文件

1、操作思路:

当然是想办法调用“解密文件”的操作啦。在图51中我们可以看到当this.i为false时执行加密操作。那么,目前就有两个想法:将if(this.i)修改为if(!this.i),或者将this.i被赋值为true的地方改为赋值为false,。



(图片51.png)


2、尝试复原的准备工作:

先将this.i重命名一下,方便一会在JEB的bytecode里查找。(但在此处的重命名操作不会影响到smali文件,所以smali文件里它依旧是this.i)。



图片52.png


3、尝试复原的方法一“将if(this.i)修改为if(!this.i)”

3.1、在JEB的bytecode里找到图片51中if(this.i)对应的地方:



(图片53)

3.2、在图片18所示的smali文件夹里,找到对应的smali文件,即f.1.smali,并用系统自带的文件编辑打开它:



(图片54)

3.3 、在f.1.smali文件中,找到与图片53相对应的地方:



(图片55)

3.4、将if(this.i)修改为if(!this.i),即修改smali代码中的if-eqz为if-nez(if-eqz,即if value equal zore,若值等于零;if-nez,即if value not equzl zero,若值不等于零):



(图片56)

3.5、保存修改后的f.1.smali文件,在终端进入图片17所示的地方,此时文件夹79..71f内的smali文件夹就保存着我们刚刚修改的f.1.smali文件。对文件夹79..71f进行编译,即进行重打包操作,



(图片57)

3.6、此时,文件夹79..71f会生成build文件夹和dist文件夹,重打包后的apk就藏在dist文件夹下啦:



(图片58、59)

3.7对新生成apk进行签名。首先把signapk.jar、testKey.pk8、testKey.x509.pem都放到这个目录下,并在终端进入该目录,使用命令“java –jar signapk.jar testkey.x509.pem testkey.pk8 Ransom.apk decrypted.apk”命令进行签名。其中,Ransom.apk要用具体软件名带入,decrypted.apk就是你自己命名的啦,也就是签名过后生成的最终apk文件。



(图片60、61、62)

3.8、安装运行decrypted.apk文件,发现文件并未被复原,且头1024个字节被改动,已经与图片44不一样了,说明两种情况:要么我们没修改成功,if(this.i)依旧跳转到加密的部分,文件又被加密了一次。要么,if(this.i)经我们修改后确实运行到解密部分了,但解密部分的代码并无法真正完成解密操作。不管是哪一种情况,现在/sdcard/testManifest.txt现在已经被加密两回了,不能要了。



(图片63)

3.9、那么,回到文件刚刚被加密的状态吧。怎么回呢:卸载decrypted.apk,删除模拟器中/sdcard/testManifest.txt文件与/sdcard/testManifest.txt.cryeye文件,重新将电脑里的testManifest.txt复制到/sdcard/目录下。安装运行恶意软件,让它加密testManifest.txt文件。这些操作,都在上面可以找到,在这里就不赘述了。
但是!!!查看这次被加密后的testManifest.txt,跟第一次被加密时(图片44)不一样呀!也就是,同一款恶意软件,对同一个testManifest.txt进行加密时,出现了不一样的加密结果:



(图片64)


4、查找加密结果不一致的原因

4.1、回到加密与解密的代码中



(图片65、66)

其中,f.m与f.m的值都是“AES/ECB/NoPadding”。V1.init参数中的1和2对应的是“加密”和“解密”模式,所以,焦点就放在arg5和this.k中了。

4.2、由于丢失了查找原因过程中的截图,所以只能放上找到的最终原因。最终原因在下面图片67中,该恶意软件使用SecureRandom,也就是说图片67的返回值是随机的,故图片65与图片66中的v0也是随机的。当然,在同一次运行恶意软件的情况下,图片65和图片66中的v0是相同的,所以是可以进行解密行为的。但是,卸载恶意软件后v0也就丢失了,再次安装运行的话v0已经不同了,故无法进行解密操作:



(图片67)


5、从尝试到放弃

现在已经触碰到我的知识盲区了,如果有大佬知道后续该如何操作的话,希望可以交流交流~先献上我的膝盖给大佬们。




七、总结

一开始没想到帖子会这么长,那总结总结吧。(可能会与上文部分内容有所重叠,但是,总结嘛)

1、为什么仅加密头1024个字节:

降低它被杀软检查出来的风险,不少检测方法都是靠计算文件的香农熵。说白点就是,加密一整个文件的话,文件的香农熵会很高,杀软就会判定这个文件被加密了,那么对这个文件进行操作的就是恶意软件了;所以,只加密一部份,甚至是一小部分内容,并不会使文件的香农熵改变太多,那么杀软就无法通过香农熵的方法来检测到这个恶意软件了。虽然只加密了一部分,但对用户来说那伤害已经足够了呀。同样也到达了加密勒索的目的。


2、为什么解密文件失败:


加密时,这个软件所使用的加密秘钥是随机生成的,即随机数由SecureRandom产生,而该类产生随机数时手机了一些随机事件,比如用户点击呀什么的。所以要完全复现出第一次被加密时的情景(即所有随机事件都一样,比如用户在哪个时间点点击屏幕之类的)几乎是不可能的。也就是说,我们拿不到加密时所使用的随机数,因为无法用那个未知的随机数来进行解密。


3、抓住恶意软件的特性进行分析

如果知道了恶意软件的类型,知道它的独特恶意行为,那么直接抓住这个特性作为切入点进行分析,会事半功倍。如分析与这个软件相似的软件时,可参照(三)中的第2步静态分析操作的思路。


4、从尝试到放弃,来得如此容易~


5、写一篇长帖子,真的容易脑阔疼。当然,长帖子看起来也容易脑阔疼。但是只挑重点写吧,我又担心交代不清前因后果,原谅我~







顺利毕业 发表于 2019-4-5 18:27

流言 发表于 2019-4-5 16:21
太长了   脑壳痛

不好意思。但是如果我尝试精简的话,我担心会讲不清楚分析的过程。

涛之雨 发表于 2019-4-14 00:11

顺利毕业 发表于 2019-4-13 14:22
哈哈,看别人写的一般比较难坚持看完,如果是自己手动分析就不会了呢。
可惜我不能分享这个软件,因为危 ...

放在样本区不行吗{:301_1004:}
好吧。。。还是算了吧。。。
作为小白。。
还是换个研究对象吧
话说大佬。最近碰到个问题。
一个软件,重签名后不能在装有框架的手机上运行,一打开就闪退。。
不装框架可以完美运行。。这是什么原理呢?
google的签名二次校验服务吗?
没有翻(过滤)墙的情况下为什也会会闪退呢
是怎么校验的呢。烦请大佬看看{:301_992:}
我跟了半天没明白个所以然来。。。

孤狼微博 发表于 2019-4-5 15:24

我只有膜拜的份了,大神好

流言 发表于 2019-4-5 16:21

太长了   脑壳痛

cn52pojie 发表于 2019-4-5 16:49

谢楼主分享。

wula770202 发表于 2019-4-5 17:52

感谢楼主感谢吾爱破解

sdqyh1985 发表于 2019-4-5 17:52

谢谢分享

swt110120 发表于 2019-4-5 19:50

一脸懵逼的来一脸懵逼的走{:301_998:}

去旅行 发表于 2019-4-5 21:57

感谢分享哦!

羽洛 发表于 2019-4-5 22:34

谢谢分享
页: [1] 2 3 4 5 6 7 8
查看完整版本: 分析混淆软件,尝试解密被加密的文件