小菜我刚学arm反汇编2个多月,这篇文字的反汇编部分很多地方懵懵懂懂,希望大虾们指点一二。这是一个星期以来对这个木马的一个分析,没有动态调试,老鸟看完指点一下吧。文章中出错的部分也请老鸟们斧正。
对不起,我的排版渣一般。
0x0 粗看
首先反编译了apk,查看AndroidManifest.xml,application里没有修改入口。因为是二次打包的一个文件管理器apk,嵌入了广告类和自己的木马部分以及一个native类。
木马是如何启动自身的?查看Reciever类,可以看到对开机启动的广播进行了接收,回头再看AndroidManifest.xml:
在AndroidManifest.xml中静态注册了3个动作,开机启动、电量变化以及信号变化。接收到这3个广播后:
获取appinfo,为null跳到label17,检查文件permission.xml,不存在也跳label17,存在就删除 ,继续执行label17。Label17里,检查当前的服务,如果没有启动“com.google.update.UpdateService” 就启动它。稍后分析这个服务过程。
再看Native类:
静态加载了libnative.so,
3个native方法,其他两个方法是对其中2个方法的调用,native方法稍后分析。
0x1 启动流程
下面分析木马部分的启动流程,上面分析到当检测到3个广播后,开启服务。服务代码如下,没有onStartCommand,直接看Oncreate:
获取了metadata里的ST_START_DELAY和ST_MY_PID字段:
当前startDelay=180,mIdentifier=”sr001”。
读取SharedPreference里的sstimgstamp,如果字段“start”为0(木马初始值为0),写入当前时间(未格式化的)。如果startDelay大于0,停止服务(这里startDelay=180,会停止当前服务,等待下次启动)。由于广播间隔短(因为信号的电量总会变化的),服务很快会被第二次启动,下次启动时进入else if逻辑,当前时间减去上次保存的时间如果小于180*1000毫秒也就是3分钟,停止服务。直到下一次启动间隔大于3分钟,进入else逻辑:读取SharedPreference里的permission节保存到mPreferences。Utils.isConnected(((Context)this))代码:
判断当前是否联网(WIFI和gprs网络),如果联网,执行doSearchReport(),然后继续执行this.getPermission();this.provideService();其中doSearchReport代码为:
其中updateInfo()方法获得手机的各种参数,包括imei,系统版本,手机型号,网络类型,运营商,内存卡大小等信息。然后构造广告类,获取广告内容等。接下来是往一个url发送信息。Url为new String(Utils.decrypt(StateRes.Servers[v2]))) + "newhi.php"
其中变量servers为一个二维数组
解密方法为public static byte[] decrypt(byte[] encrypted),这个解密方法后面也用到了,二进制的文件解密还原:
用到了一个自定义的密钥:defPassword
3个url地址解密出来为:
现在地址均已失效。
继续看方法getPermission():
首先是checkPermission():
如果存在/system/bin/secbin,就执行cpLegacyRes方法,这个方法解密了assets文件夹里的db.init文件,是个apk,纯木马,非嵌入到正常apk里的。然后执行了TCP.execute方法,此方法通过socket往localhots:11009发送内容为”2 /data/data/package_name/db /system/app/com.google.update.apk”字符串。
回到getPermission,接下来判断了android版本是否为2.2.1,2.3以及3.0,如果是的话或者getPermission1()=true就释放木马程序,设置权限后运行起来,这里有个wifi关闭5秒后打开的过程,难道是为了躲避云查杀?
再接下来执行getPermission3():
这里解密释放了3个bin文件,并设置了权限运行权限。最后开启了工作线程MyThread:
这里通过Utils的runsh方法带参数运行了先前释放的starter,runsh就是对native类里的一个方法的封装。接着判断secbin是否存在,存在就运行,不存在就通过am命令启动服务com.google.update.UpdateService。
最后看provideService()方法,这是开启木马远程控制的核心方法了:
启动了一个TimerTask,每隔60*1000毫秒运行一次UpdateService.this.doTimerTask();
其中mPermState是上面一系列判断而来,它的值可以为(0,1,2,3)。如果mPermState
为0或1,就先检查当前是否联网,如果联网再判断当前自增变量mTickets是否能被60整除,如果整除就重新获取广告,否则获取任务信息。这里的任务是访问的上面解密出来的url加上newtask.php而来的,分析后得出可执行的任务类型有:安装apk、启动apk、卸载apk、打开url、卸载系统apk、升级bin文件。
到此JAVA层的主要代码看完了,流程大概就是:
检查环境--获得广告代码--获取信息--上传信息--释放各种bin--运行bin--获取控制端发的命令后执行。
0x2 静态分析native方法
上面粗看了java代码,清楚了执行流程,下面看看那几个native方法做了些什么。Ida直接载入libNative.so,先看最简单的public static native int runcmd_simple(String paramString);
写成伪c就是:
Int runcmd_simple(JNIEnv * env,jobject obj,char* param_str)
{
Char* str = (*env)->GetStringUTFChars(env,param,0);
Int ret= system(str);
(*env)->ReleaseStringUTFChars(env,param,str,str);
Return ret;
}
再看
public static native int runcmd(Native this, String arg1, String arg2)
在反汇编里我们要明确:R0=JNIEnv,r1=jobject,r2=string_arg1,r3=string_arg2
C代码:
Int runcmd(JNIEnv *env,jobject jobj,string str1,string str2)
{
Char* str__1 = (*env)->GetStringUTFChars(env,str1,0);
Char* str__2 = (*env)->GetStringUTFChars(env,str2,0);
FILE* f = popen(str__1,”w”);
Int ret = 0;
If(f == null)
{
Perror(“eerroor”);
Ret = 1;
}
Else
{
Fputs(str__2,f);
Fwrite(“\nexit\n”,1,6,f);
Pclose(f);
Ret = 0;
}
(*env)->ReleaseStringUTFChars(env,str1,str__1);
Return ret;
}
接下来静态分析starter文件,ida载入一路到main函数:
图截的太乱,大家要看的自行载入附件中的starter.idc。
这一段c代码为:
Int main(int argc,char* argv[],char** env)
{
Char* exec_file;//这块对应的反汇编我看不是太明白,r5里保存了char*地址,但是大小是多少?
Memset(exec_file,0,512);
Char* Path;
If(argc<=1)
{
Char temtpath[0x200];
Path = strdup(getcwd(temtpath,0x200));
}else
Path = argv[1];
[COLOR="red"]Sub_88e0[/COLOR](“myicon”);//这个地方也没看明白,求大侠指点,逻辑太多,脑子不够用
If(geteuid()==0)
{
If(access(“/system/bin/secbin”,0) == 0)
{
exec_file = “/system/bin/secbin”;
}else
{
Snprintf(exec_file,512,”%s/secbino”,Path);
}
Setuid(0);
Setgid(0);
Unlink(“myicon”);
}else
{
Snprintf(exec_file,512,”%s/myicon”,Path);
}
Execve(exec_file[COLOR="Red"],r6???[/COLOR],env); //这里有个r6,值是 r6=sp+0x4,也没整明白
}
好吧,我是个菜鸟,才学反汇编2个多月,很多地方不明白,特别对栈指针的把握不太清楚,还请大牛赐教。其实还有一个木马本体secbin没有分析,小菜有点吃力,但是看导入函数有socket,send,bind,listen等socket通信函数。那个myicon通过解密还是一层加密的,也请有空的大牛出一篇分析文档让我等小菜学习学习吧。还有,动态调试不知道是我参数给的不对还是啥,f7跑着跑着就进了libc。唉。
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!