首页
社区
课程
招聘
[原创]一款木马的简单静态分析
发表于: 2014-9-20 14:16 6296

[原创]一款木马的简单静态分析

2014-9-20 14:16
6296
小菜我刚学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。唉。

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

上传的附件:
收藏
免费 0
支持
分享
最新回复 (2)
雪    币: 34
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
楼主反编译过来的java代码,怎么会如此清晰?好奇。
2014-9-21 15:04
0
雪    币: 108
活跃值: (49)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
3
不错,顶一下!!
2014-9-21 15:54
0
游客
登录 | 注册 方可回帖
返回
//