前言一、Smali简介二、Smali语法简介
1.基本类型2.引用类型3.方法体定义4.关键字5.寄存器类别区分6.条件跳转7.Smali针对函数返回结果的 *** 作8.Smali变量 *** 作权限 三、阅读部分
APK效果打包和反编译阅读 四、实际 *** 作部分总结
前言
本节介绍移动安全相关知识中的Smali语法,并自主动手完成一个小练习
一、Smali简介Smali是Android虚拟机Davlik的寄存器语言,语法上和汇编语言类似. Davlik是基于寄存器的,就是说smali里的所有 *** 作都必须经过寄存器来进行.
简单来说就是高级语言Java和机器语言的一个中间层代码语言,执行效率相比高级语言更加高效,更加贴近底层,通过我们用Apktool反编译APK出来的结果中便会含有Smali文件夹,文件夹下的内容就是Smali语言
本节主要针对基于Java编写的Android应用反编译出的Smali文件进行分析。
2.引用类型B—byte
C—char
D—double
F—float
I—int
S—short
V—void
J—long
Z—boolean
[XXX->X代表类型的数组
例:
[B -->Byte[]
[I -->Int[]Lxx/yyy -->Object对象
例如:
String str–>str Ljava/lang/String;
subobjectName objectName->objectName LpackageaName/objectName
s
u
b
o
b
j
e
c
t
N
a
m
e
注
:
这
里
的
subobjectName 注:这里的
subobjectName注:这里的符号代表内部类,内部类的含义我就不用解释了吧
3.方法体定义
方法体格式:
Func-Name (Para-Type1Para-Type2Para-Type3…)Return-Type 注意: 参数之间没有任何分隔符,返回值在最后
例:
void hello() —> hello()V
boolean hello(int,int,int) —>hello(III)Z
String fun(boolean, int[], int[], String, long)
—>fun(Z[I[ILjava/lang/String,J)Ljava/lang/String
.field private isFlag:z 定义变量.method 方法.parameter 方法参数.prologue 方法开始.line123 此方法开始于123行invoke-super 调用父函数const/high16 v0,0x7fox 把0x7fox的值赋值给v0invoke-direct 调用函数return-void 函数返回void.end method 函数结束new-instance 创建实例iput-object 对象赋值iget-object 调用对象invoke-static 调用静态函数.class public Lcom/disney/WMW/WMWActivty; 类名.super Lcom/XXX/XXX/XXX; 父类名.source “XXX.java” 源文件名.implements Lcom/XXX/XXX/XXX; 实现了接口.annotation 内部类 5.寄存器类别区分
寄存器v,本地寄存器 (local register, 非参寄存器)
常用v开头数字结尾的符号表示 v0,v1,v2…
可以看到这里的locals后面的参数为2,表明使用两个v开头的本地寄存器,若修改数量为1,可以编译通过,但是运行时,会发生错误
寄存器p,参数寄存器 (parameter regisgter)
常用p开头数字结尾的符号来表示 p0,p1,p2,p3…
# direct methods .method public constructor()V .locals 0 .line 18 invoke-direct {p0}, Landroidx/appcompat/app/AppCompatActivity;-> ()V return-void .end method
p0为非静态方法自动创建的寄存器,存储着this,也就是该方法所属类的实例本身,例如这段函数中,一个Activity invoke-direct调用其父类AppCompatActivity的init()方法,传入的参数是这个实例本身的this
6.条件跳转if-eq vA,vB, :cond_** 如果vA等于vB,则跳转到:cond_**if-ne vA,vB, :cond_** 如果vA不等于vB,则跳转到:cond_**if-lt vA,vB, :cond_** 如果vA小于vB,则跳转到:cond_**if-ge vA,vB, :cond_** 如果vA大于等于vB,则跳转到:cond_**if-gt vA,vB, :cond_** 如果vA大于vB,则跳转到:cond_**if-le vA,vB, :cond_** 如果vA小于等于vB,则跳转到:cond_**if-eqz vA, :cond_** 如果vA等于0,则跳转到:cond_**if-nez vA, :cond_** 如果vA不等于0,则跳转到:cond_**if-ltz vA, :cond_** 如果vA小于0,则跳转到:cond_**if-gez vA, :cond_** 如果vA大于等于0,则跳转到:cond_**if-gtz vA, :cond_** 如果vA大于0,则跳转到:cond_**if-lez vA, :cond_** 如果vA小于等于0,则跳转到:cond_** 7.Smali针对函数返回结果的 *** 作
在Java代码中调用函数和返回函数结果可以只用一条语句来表示,如:
A=getPoint();
但在Smali里则需要分开完成,在使用上述指令后,如果调用的函数返回非void, 那么还需要用到move-result(返回基本函数类型)和move-result-object(返回对象指令);
例:
const-string v0,"Eric" invoke-static {v0},Lcmb/pbi;->t(Ljava/lang/String)LJava/lang/String; move-result-object v2
此时v2保存的就是调用t方法得到的String字符串
8.Smali变量 *** 作权限字段 *** 作指令表示对对象字段进行设值和取值 *** 作,就像是你在代码中长些的set和get方法.基本指令是iput-type,iget-type,sput-type,sget-type.type表示数据类型.
普通字段读写 *** 作
前缀是i的iput-type和iget-type指令用于字段的读写 *** 作.
指令 描述
iget-object vAA,vBB,filed_id 读取vAA寄存器中的对象中的filed_id对象的引用值给vBB寄存器iget-boolean vAA,vBB,filed_id 读取vAA寄存器中的对象中的filed_id的值给vBB寄存器iget-wide vAA,vBB,filed_id 读取vAA寄存器中的对象中的filed_id的值给vBB寄存器iget vAA,vBB,filed_id 读取vAA寄存器中的对象中的filed_id的值给vBB寄存器iput-object vAA,vBB,filed_id 把vAA寄存器指向的对象的引用赋值给vBB寄存器中的filed_id对象iput-boolean vAA,vBB,filed_id 把vAA寄存器的值给vBB寄存器中的boolean类型iput-wide vAA,vBB,filed_id 把vAA寄存器的值给vBB寄存器中的wide类型iput vAA,vBB,filed_id 把vAA寄存器的值给vBB寄存器中的int类型
静态字段读写 *** 作
前缀是s的sput-type和sget-type指令用于静态字段的读写 *** 作
指令 描述
sget-object vAA,vBB,filed_id 读取vAA寄存器中的对象中的filed_id对象的引用值给vBB寄存器sget-boolean vAA,vBB,filed_id 读取vAA寄存器中的对象中的filed_id的值给vBB寄存器sget-wide vAA,vBB,filed_id 读取vAA寄存器中的对象中的filed_id的值给vBB寄存器sget vAA,vBB,filed_id 读取vAA寄存器中的对象中的filed_id的值给vBB寄存器sput-object vAA,vBB,filed_id 把vAA寄存器指向的对象的引用赋值给vBB寄存器中的filed_id对象sput-boolean vAA,vBB,filed_id 把vAA寄存器的值给vBB寄存器中的boolean类型sput-wide vAA,vBB,filed_id 把vAA寄存器的值给vBB寄存器中的wide类型sput vAA,vBB,filed_id 把vAA寄存器的值给vBB寄存器中的int类型 三、阅读部分
我们这里采取自己动手打包一个登录验证的APK进行阅读和练习
APK效果登录界面
登陆后的界面
打包用AS一键打包
反编译用APKTool对APK进行反编译出相关Smali代码
点击Smali用VS Code工具进行阅读
MainActivity.smali
.class public Lcom/example/androidsafetest01/MainActivity;//包名+类名 .super Landroidx/appcompat/app/AppCompatActivity;//父类名称 .source "MainActivity.java"//.source 源文件名称 # instance fields .field private btn:Landroid/widget/Button; .field private editText:Landroid/widget/EditText;//实例变量 变量名称:包名 # direct methods .method public constructor()V//方法开始 .locals 0 .line 12//这个方法对应Java代码中的12行 invoke-direct {p0}, Landroidx/appcompat/app/AppCompatActivity;-> ()V//调用父类中的构造函数,返回值为空 return-void .end method//方法结束 .method static synthetic access$000(Lcom/example/androidsafetest01/MainActivity;)Landroid/widget/EditText; .locals 0 .line 12 iget-object p0, p0, Lcom/example/androidsafetest01/MainActivity;->editText:Landroid/widget/EditText;//将MainActivity的id值送给EditText,初步猜测是在给权限 return-object p0 .end method .method private initEvent()V .locals 2//使用了两个寄存器 .line 26 iget-object v0, p0, Lcom/example/androidsafetest01/MainActivity;->btn:Landroid/widget/Button; new-instance v1, Lcom/example/androidsafetest01/MainActivity$1; invoke-direct {v1, p0}, Lcom/example/androidsafetest01/MainActivity$1;-> (Lcom/example/androidsafetest01/MainActivity;)V invoke-virtual {v0, v1}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V//调用实例的虚方法 return-void .end method .method private initView()V .locals 1 const v0, 0x7f08008f .line 44 invoke-virtual {p0, v0}, Lcom/example/androidsafetest01/MainActivity;->findViewById(I)Landroid/view/View; move-result-object v0 check-cast v0, Landroid/widget/EditText; iput-object v0, p0, Lcom/example/androidsafetest01/MainActivity;->editText:Landroid/widget/EditText; const v0, 0x7f080057 .line 45 invoke-virtual {p0, v0}, Lcom/example/androidsafetest01/MainActivity;->findViewById(I)Landroid/view/View; move-result-object v0 check-cast v0, Landroid/widget/Button; iput-object v0, p0, Lcom/example/androidsafetest01/MainActivity;->btn:Landroid/widget/Button; return-void .end method # virtual methods .method protected onCreate(Landroid/os/Bundle;)V .locals 0 .annotation system Ldalvik/annotation/MethodParameters; accessFlags = { 0x0 } names = { "savedInstanceState" } .end annotation .line 19 invoke-super {p0, p1}, Landroidx/appcompat/app/AppCompatActivity;->onCreate(Landroid/os/Bundle;)V const p1, 0x7f0b001d .line 20 invoke-virtual {p0, p1}, Lcom/example/androidsafetest01/MainActivity;->setContentView(I)V .line 21 invoke-direct {p0}, Lcom/example/androidsafetest01/MainActivity;->initView()V .line 22 invoke-direct {p0}, Lcom/example/androidsafetest01/MainActivity;->initEvent()V return-void .end method
MainActivity$1.smali
.class Lcom/example/androidsafetest01/MainActivity$1; .super Ljava/lang/Object; .source "MainActivity.java" # interfaces .implements Landroid/view/View$OnClickListener; # annotations .annotation system Ldalvik/annotation/EnclosingMethod; value = Lcom/example/androidsafetest01/MainActivity;->initEvent()V .end annotation .annotation system Ldalvik/annotation/InnerClass; accessFlags = 0x0 name = null .end annotation # instance fields .field final synthetic this$0:Lcom/example/androidsafetest01/MainActivity; # direct methods .method constructor四、实际 *** 作部分(Lcom/example/androidsafetest01/MainActivity;)V .locals 0 .annotation system Ldalvik/annotation/MethodParameters; accessFlags = { 0x8010 } names = { "this$0" } .end annotation .line 26 iput-object p1, p0, Lcom/example/androidsafetest01/MainActivity$1;->this$0:Lcom/example/androidsafetest01/MainActivity; invoke-direct {p0}, Ljava/lang/Object;-> ()V return-void .end method # virtual methods .method public onClick(Landroid/view/View;)V .locals 2 .annotation system Ldalvik/annotation/MethodParameters; accessFlags = { 0x0 } names = { "view" } .end annotation .line 29 iget-object p1, p0, Lcom/example/androidsafetest01/MainActivity$1;->this$0:Lcom/example/androidsafetest01/MainActivity; invoke-static {p1}, Lcom/example/androidsafetest01/MainActivity;->access$000(Lcom/example/androidsafetest01/MainActivity;)Landroid/widget/EditText; move-result-object p1 invoke-virtual {p1}, Landroid/widget/EditText;->getText()Landroid/text/Editable; move-result-object p1 invoke-virtual {p1}, Ljava/lang/Object;->toString()Ljava/lang/String; move-result-object p1 if-eqz p1, :cond_0 .line 30 invoke-virtual {p1}, Ljava/lang/String;->length()I move-result v0 if-eqz v0, :cond_0 const-string v0, "123456" .line 31 invoke-virtual {p1, v0}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z move-result p1 if-eqz p1, :cond_1 .line 32 new-instance p1, Landroid/content/Intent; iget-object v0, p0, Lcom/example/androidsafetest01/MainActivity$1;->this$0:Lcom/example/androidsafetest01/MainActivity; invoke-virtual {v0}, Lcom/example/androidsafetest01/MainActivity;->getApplicationContext()Landroid/content/Context; move-result-object v0 const-class v1, Lcom/example/androidsafetest01/EndActivity; invoke-direct {p1, v0, v1}, Landroid/content/Intent;-> (Landroid/content/Context;Ljava/lang/Class;)V .line 33 iget-object v0, p0, Lcom/example/androidsafetest01/MainActivity$1;->this$0:Lcom/example/androidsafetest01/MainActivity; invoke-virtual {v0, p1}, Lcom/example/androidsafetest01/MainActivity;->startActivity(Landroid/content/Intent;)V goto :goto_0 .line 36 :cond_0 iget-object p1, p0, Lcom/example/androidsafetest01/MainActivity$1;->this$0:Lcom/example/androidsafetest01/MainActivity; invoke-virtual {p1}, Lcom/example/androidsafetest01/MainActivity;->getApplicationContext()Landroid/content/Context; move-result-object p1 const/4 v0, 0x0 const-string v1, "u8f93u5165u5bc6u7801u6709u8bef"//这里Smali采用的是Unicode编码 invoke-static {p1, v1, v0}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast; move-result-object p1 invoke-virtual {p1}, Landroid/widget/Toast;->show()V :cond_1 :goto_0 return-void .end method
这里通过修改其中的明文密码判定部分,改变其登录逻辑为,密码等于123456789时,进行登录行为
改变后
再次打包APK,进行重签名发送到手机上进行安装
重签名,这里的签名方式采用的是Java中的jarsigner命令,jarsigner命令只可以针对V1的签名方式进行签名,后期应该会进行更改签名方式
jarsigner -verbose -keystore D:2022NamesAndroidSafeSign.jks D:2022移动安全apksreleaseAndroidSafeTest02.apk -signedjar D:2022移动安全apksAfterRenamedAndroidSafeTest01.apk key0
执行效果:
修改过后的视频播放地址
但是这种修改Smali的方法基于静态调试,实际反编译APK过程中基本不会有打静态补丁的机会,这里也是仅供练习使用。
总结以上是Smali语法学习部分,欢迎大家指正
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)