预估稿费:180RMB
投稿方式:发送邮件至linwei#,或登陆网页版在线投稿
前言
最近,我们发现了一个新的Android rootnik恶意软件,它使用开源的Android root 利用工具和来自dashi root工具的MTK root方案来在Android设备上获得root权限。这个恶意软件伪装成一个文件助手,还使用了非常先进的反调试和反HOOK技术,用于防止其被逆向 。它还使用了multidex方案加载辅助的dex文件。 在成功获得设备上的root权限后,rootnik恶意软件可能会执行以下几种恶意行为,包括应用和广告宣传,推送色情内容,在主屏幕上创建快捷方式,静默安装应用程序,推送通知等。在这篇博客中, 我会提供对此恶意软件的深入分析。
恶意软件简介
恶意应用程序看起来像是一个正常合法的文件助手程序,来管理你保存的文件和手机上的其他资源。
图1 恶意软件安装图标
图2 恶意软件的一个界面
我们反编译APK文件,如图3所示。
图3 反编译的恶意软件
包名为com.web.sdfile。首先,我们来看看其AndroidManifest.xml文件。
图4 AndroidManifest.xml
我们在图4中找不到主Activity, com.sd.clip.activity.FileManagerActivity,服务类或广播类。显然,这个文件助手的主要逻辑不在classes.dex中。在分析之后,我们发现恶意软件应用程序使用multidex方案动态加载辅助dex文件并执行。
Rootnik是如何工作的
1.Rootnik的工作流程
以下是android rootnik恶意软件的工作流程。
图5 Android rootnik恶意软件工作流的概述
2.继续深入第一个dex文件
以下是SecAppWrapper类的代码段。
图6:类SecAppWrapper的代码段
执行流程如下所示。
Staticcodeblock->attachBaseContext->onCreate
静态代码块将动态链接库libSecShell.so加载到文件夹资产中,然后程序进入Native层,执行几个反调试操作,解密辅助的dex文件,然后使用multidex方案加载解密的辅助 dex文件,这个DEX文件是应用的主要逻辑 。
然后程序调用DexInstall的安装方法来加载辅助dex文件。调用DexInstall的安装方法在Native层中执行的。
图7 安装辅助DEX文件
在attachBaseContext函数中,程序加载com.sd.clip.base.MyApplication类,它是辅助dex的执行入口。 Helper的方法attach是一个Native层方法。
在onCreate函数中,程序执行com.sd.clip.base.MyApplication 类的onCreate函数 。
这就完了。第一个dex其实相当简单。接下来,我们将对Native层代码进行深入分析,这是非常复杂和棘手的。
3. Native 代码层的范围
如上所述,Native层代码使用一些先进反调试和反HOOK技术,并且还使用若干解密算法来解密一些字节数组以获得纯文本字符串。
以下是libSecShell.so中的导出函数的一部分。由于混淆的函数名称,分析变得相当困难。
图8 libSecShell.so中部分导出函数
所有的反调试代码都位于JNI_Onload函数中。
如上一节所述,Java层中Helper类的attach方法是一个Native方法。 程序在Native层动态注册此方法。 以下是在Native层中注册Native方法的ARM汇编代码片段。
图9 在Native 层中动态注册Native函数
函数RegisterNatives用于注册Native方法。其接口如下所示。
jintRegisterNatives(JNIEnvenv,jclassclazz,constJNINativeMethodmethods,jintnMethods)
JNINativeMethod的定义如下所示。
typedefstruct{
constchar*name;
constchar*signature;
void*fnPtr;
}JNINativeMethod;
ThefirstvariablenameisthemethodnameinJava.Here,it’sthestring“attach”.Thethirdvariable,fnPtr,isafunctionpointerthatpointstoafunctioninCcode.
我们接下来需要找到反调试代码的位置并绕过它,分析如何解密加密的辅助dex文件,并从内存中将dex文件DUMP出来。
让我们看看IDA中的以下代码:
图10 反调试代码片段
根据我们的深入分析,地址0xF832处的指令是跳转到地址loc_F924。 跟踪一些代码后,我们发现了反调试代码。
图11 反调试代码的位置
函数p7E7056598F77DFCC42AE68DF7F0151CA()执行的是反调试的功能。
以下是它的图形执行流程,这是非常复杂的。
图12 反调试代码的图形执行流程
以下是一些在恶意软件中使用到的反调试和反HOOK的方法。
检测一些常用的HOOK框架,如Xposed,substrate,adbi,ddi,dexposed。一旦发现了使用这些流行的HOOK框架, 它会杀死相关的进程。
图13 检测XPOSED框架
图14 发现HOOK特性
然后使用一种多进程ptrace来实现反调试,这就比较棘手了。在这里我们不打算提供一个对反调试实现机制的详细的分析,只是给一些简单的解释。
我们可以看到有两个进程名为com.web.sdfile。
图15 命令为com.web.sdfile的两个进程
以下是多进程反调试代码的代码段。
图16 反调试代码片段
该程序还使用inotify来监视主进程的内存和主进程的映射。它导致内存的DUMP不完整。这两个进程使用管道相互通信。
总之,这些反调试和反HOOK方法为逆向创造了一个巨大的障碍。所以绕过他们是我们的第一个任务。
那么来吧, 让我们试着绕过他们。
如图10所示,偏移位置为0x0000F832处的指令跳转到loc_F924,然后程序开始执行这些反调试代码。我们可以动态修改某些寄存器或某些ARM指令的值,以便在动态调试时改变程序的运行流程。 当程序在偏移位置0xF828处执行指令“SUBS R1,R0,#0”时,我们将寄存器R0的值修改为非零值,这将使“BNE loc_F834”的条件为真,使程序跳转至loc_F834。
图17 如何绕过反调试
接下来,我们就需要动态调试来绕过反调试,然后dump出解密的辅助dex文件。动态调试如下所示。
图18 将寄存器R0的值修改为非0
图19 跳到local_75178834
接下来,跳转到local_751788D8,如下所示。
图20 辅助dex的解密
函数p34D946B85C4E13BE6E95110517F61C41是解密函数。寄存器R0指向存储加密的dex文件的存储器,R1的值是dex文件的大小,即:0x94A3E(608830)。加密的dex文件是apk包中的文件夹中的secData0.jar。以下是文件secData0.jar。
图21 apk包文件夹assets中的 secData0.jar文件
图22 解密后的DEX文件在内存中的内容
我们现在可以将解密文件的内存dump到文件decrypt.dump中。
解密的文件是zip格式的文件,它包含辅助dex文件。解密后,程序将解密的辅助apk解压缩为dex文件。函数p3CBBD6F30D91F38FCD0A378BE7E54877用来解压缩文件。
接下来,函数unk_75176334调用类com.secshell.shellwrapper.DexInstall的java方法来加载解压缩出来的dex文件。
图23 解压apk文件并加载dex文件
图24 通过jni调用安装方法
在这里我们完成对Native层的分析,并获得解密后apk文件,我会将分析这个解密后的apk文件的内容放在这个博客的第二部分。
在Native层中解密secData0.jar的解密函数:
int__fastcallsub_7518394C(intresult,_BYTE*a2,inta3)
{
intv3;//r1@1
intv4;//r3@5
unsignedintv5;//r3@7
intv6;//r6@7
intv7;//r5@7
charv8;//r2@8
intv9;//r4@9
intv10;//r3@9
intv11;//r7@11
_BYTE*v12;//r6@12
intv13;//r4@13
_BYTE*v14;//r1@15
intv15;//[sp+0h][bp-138h]@1
intv16;//[sp+4h][bp-134h]@1
_BYTE*v17;//[sp+8h][bp-130h]@1
intv18;//[sp+10h][bp-128h]@5
charv19[256];//[sp+1Ch][bp-11Ch]@6
intv20;//[sp+11Ch][bp-1Ch]@1
v17=a2;
v16=result;
v20=_stack_chk_guard;
v15=a3;
v3=0;
if(result<=0x1FFFF)
{
v3=0x20000-result;
if(0x20000-result>a3)
v3=a3;
v15=a3-v3;
if(v3>0)
{
v18=dword_751AF650;
v4=0;
do
{
v19[v4]=v4;
++v4;
}
while(v4!=256);
v5=0;
v6=0;
v7=0;
do
{
v6=(*(_BYTE*)(v18+v5)+(unsigned__int8)v19[v7]+v6)&0xFF;
v8=v19[v7];
v5=(v5+1)&-((v5+1<=0xF)+((v5+1)>>31));
v19[v7]=v19[v6];
v19[v6]=v8;
++v7;
}
while(v7!=256);
v9=0;
result=0;
v10=0;
while(v9!=v16)
{
v10=(v10+1)&0xFF;
v11=(unsigned__int8)v19[v10];
++v9;
result=(v11+result)&0xFF;
v19[v10]=v19[result];
v19[result]=v11;
}
v12=v17;
do
{
v10=(v10+1)&0xFF;
v13=(unsigned__int8)v19[v10];
result=(result+v13)&0xFF;
v19[v10]=v19[result];
v19[result]=v13;
*v12++^=v19[(v13+(unsigned__int8)v19[v10])&0xFF];
}
while(v12!=&v17[v3]);
}
}
if(v15>0)
{
v14=&v17[v3];
result=(int)v14;
do
*v14++^=0xACu;
while((signedint)&v14[-result]
}
if(v20!=_stack_chk_guard)
result=((int(*)(void))unk_75173E48)();
returnresult;
}
android 反调试 方案 【木马分析】使用高级反调试与反HOOK的安卓恶意ROOT软件的深度分析(一):NATIVE层的调试...
如果觉得《android 反调试 方案 【木马分析】使用高级反调试与反HOOK的安卓恶意ROOT软件的深》对你有帮助,请点赞、收藏,并留下你的观点哦!