前言
Enmmm,还记得之前看反编译之后的结果,对于 Smali 文件,简直懵的要死。
今天,一起好好回顾下。
首先来个小 Demo
效果如下:
将生成的 Apk 文件使用 ApkTool 进行解包,之后在 Sublime Text 3 中打开,下面附上下载链接:
链接: https://pan.baidu.com/s/1EbZsk106YLV22TgoVkbhbw 密码:f5v1
打开如下格式:
而接下来,我们重点关注 Smali 目录下的文件:
Smali 解析代码文件
Enmmm,这里还需要借助工具:Dalvik虚拟机操作码,进行辅助。
链接: https://pan.baidu.com/s/14I63tafdQRcBkSm6UO1qaQ 密码:2w7h
首先,我们先来看前三句:
.class public Lcom/hlq/apktooldemo/MainActivity;
.super Landroid/support/v7/app/AppCompatActivity;
.source "MainActivity.java"
首先,我们来依次解析下所代表含义:
那么依旧这些内容,转化为 Java 代码如下:
public class MainActivity extends AppCompatActivity {
}
接着,往下继续看:
# instance fields
.field private mCheckID:Landroid/widget/Button;
.field private mUserLicenseID:Landroid/widget/EditText;
.field private mUserNameID:Landroid/widget/EditText;
Enmmm,显而易见,这里定义了三个全局变量,并且我们解析下这几行行所代表的含义:
那么针对这些,逆推 Java 代码如下:
private Button mCheckID;
private EditText mUserLicenseID;
private EditText mUserNameID;
而接下来,我们来看下 onCreate() 方法又被转化成了什么鬼?
# virtual methods
.method protected onCreate(Landroid/os/Bundle;)V
.locals 1
.param p1, "savedInstanceState" # Landroid/os/Bundle;
.line 21
invoke-super {p0, p1}, Landroid/support/v7/app/AppCompatActivity;->onCreate(Landroid/os/Bundle;)V
.line 22
const v0, 0x7f09001b
invoke-virtual {p0, v0}, Lcom/hlq/apktooldemo/MainActivity;->setContentView(I)V
.line 23
invoke-direct {p0}, Lcom/hlq/apktooldemo/MainActivity;->initView()V
.line 24
invoke-direct {p0}, Lcom/hlq/apktooldemo/MainActivity;->initEvent()V
.line 25
return-void
.end method
显而易见,有一个名为 onCreate 并且有一个参数为 Bundle 类型,参数名为 savedInstanceState。
而其下则调用了 super,而 {p0, p1} 所代表的含义如下:
而 const v0, 0x7f09001b 则对应的具体类型,经过 LZ 搜索如下:
下面的 invoke-virtual {p0, v0}, Lcom/hlq/apktooldemo/MainActivity; ->setContentView(I)V 解析如下:
.line 23
invoke-direct {p0}, Lcom/hlq/apktooldemo/MainActivity;->initView()V
.line 24
invoke-direct {p0}, Lcom/hlq/apktooldemo/MainActivity;->initEvent()V
而这俩行,则是定义了俩个方法,分别为:
So,结合起来,onCreate Smali 文件转换 Java 文件如下:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initEvent();
}
而下面,继续查看 initView 方法:
// void 类型 方法名为 initView
.method private initView()V
.locals 2
// 对应 id 类型为:<public type="id" name="tv_user_name" id="0x7f070085" />
.line 28
const v0, 0x7f070085
// invoke-virtual 调用带参数的虚拟方法。
// 这里便是实例化此控件 findViewById
invoke-virtual {p0, v0}, Lcom/hlq/apktooldemo/MainActivity;->findViewById(I)Landroid/view/View;
// move-result-object v0 移动上一次方法调用的对象引用返回值到 v0
move-result-object v0
// 参数类型 EditText
// check-cast 检查 vx 寄存器中的对象引用是否可以转换成类型 ID 对应类型的实例
check-cast v0, Landroid/widget/EditText;
// 参数名 mUserNameID
// iput-object vx, vy, 字段 ID根据字段 ID 将 vx 寄存器的值存入实例的对象引用字段, vy 寄存器中是该实例的引用。
iput-object v0, p0, Lcom/hlq/apktooldemo/MainActivity;->mUserNameID:Landroid/widget/EditText;
// 对应 id 类型为:<public type="id" name="tv_license" id="0x7f070084" />
.line 29
const v0, 0x7f070084
// invoke-virtual 调用带参数的虚拟方法。
// 这里便是实例化此控件 findViewById
invoke-virtual {p0, v0}, Lcom/hlq/apktooldemo/MainActivity;->findViewById(I)Landroid/view/View;
// move-result-object v0 移动上一次方法调用的对象引用返回值到 v0
move-result-object v0
// 参数类型 EditText
check-cast v0, Landroid/widget/EditText;
// 参数名 mUserLicenseID
iput-object v0, p0, Lcom/hlq/apktooldemo/MainActivity;->mUserLicenseID:Landroid/widget/EditText;
// 对应 id 类型为:<public type="id" name="btn_check" id="0x7f070022" />
// 获取到 id
.line 30
const v0, 0x7f070022
// 拿到 id 对应的类型
invoke-virtual {p0, v0}, Lcom/hlq/apktooldemo/MainActivity;->findViewById(I)Landroid/view/View;
move-result-object v0
check-cast v0, Landroid/widget/Button;
// 赋给 v0 对应 java 代码则是:mCheckID = findViewById(R.id.btn_check);
iput-object v0, p0, Lcom/hlq/apktooldemo/MainActivity;->mCheckID:Landroid/widget/Button;
.line 34
return-void
.end method
而在 initEvent() 方法中,则又是如下:
.method private initEvent()V
.locals 2
// iget-object-quick vx, vy, 偏移量 获取 vy 寄存器中实例指向+偏移位置的数据区的对象引用, 存入 vx
.line 37
iget-object v0, p0, Lcom/hlq/apktooldemo/MainActivity;->mCheckID:Landroid/widget/Button;
// new-instance vx, 类型 ID 根据类型 ID 或类型新建一个对象实例,并将新建的对象的引用存入 vx
new-instance v1, Lcom/hlq/apktooldemo/MainActivity$1;
// invoke-direct {参数}, 方法名 不解析直接调用带参数的方法
invoke-direct {v1, p0}, Lcom/hlq/apktooldemo/MainActivity$1;-><init>(Lcom/hlq/apktooldemo/MainActivity;)V
// invoke-virtual/range {vx..vy}, 方法名 调用以寄存器范围为参数的虚拟方法。 该指令第一个寄存器和寄存器的数量将传递给方法
// 这里调用 setOnClickListener 事件
invoke-virtual {v0, v1}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V
.line 53
return-void
.end method
而其下点击事件中关键内容解析如下:
// 获取 EditText 实例
.method static synthetic access$000(Lcom/hlq/apktooldemo/MainActivity;)Landroid/widget/EditText;
.locals 1
// 类型为 com/hlq/apktooldemo/MainActivity
.param p0, "x0" # Lcom/hlq/apktooldemo/MainActivity;
// 参数名为
.line 14 mUserNameID
iget-object v0, p0, Lcom/hlq/apktooldemo/MainActivity;->mUserNameID:Landroid/widget/EditText;
return-object v0
.end method
// 同下同理
.method static synthetic access$100(Lcom/hlq/apktooldemo/MainActivity;)Landroid/widget/EditText;
.locals 1
.param p0, "x0" # Lcom/hlq/apktooldemo/MainActivity;
.line 14
iget-object v0, p0, Lcom/hlq/apktooldemo/MainActivity;->mUserLicenseID:Landroid/widget/EditText;
return-object v0
.end method
// 同下同理
.method static synthetic access$200(Lcom/hlq/apktooldemo/MainActivity;Ljava/lang/String;Ljava/lang/String;)Z
.locals 1
.param p0, "x0" # Lcom/hlq/apktooldemo/MainActivity;
.param p1, "x1" # Ljava/lang/String;
.param p2, "x2" # Ljava/lang/String;
.line 14
invoke-direct {p0, p1, p2}, Lcom/hlq/apktooldemo/MainActivity;->checkData(Ljava/lang/String;Ljava/lang/String;)Z
move-result v0
return v0
.end method
// checkData 包含俩个 String 类型参数
.method private checkData(Ljava/lang/String;Ljava/lang/String;)Z
.locals 3
// 参数名如下:
.param p1, "userName" # Ljava/lang/String;
.param p2, "userLicense" # Ljava/lang/String;
// 调用 getBytes
.line 56
invoke-virtual {p1}, Ljava/lang/String;->getBytes()[B
// move-result-object v0 移动上一次方法调用的对象引用返回值到 v0
move-result-object v0
// 临时存入变量中
const/4 v1, 0x0
// invoke-static {v0, v1} 调用带参数的静态方法
invoke-static {v0, v1}, Landroid/util/Base64;->encodeToString([BI)Ljava/lang/String;
// move-result-object v0 移动上一次方法调用的对象引用返回值到 v0
move-result-object v0
// const-string vx, 字符串 ID 存入字符串常量引用到 vx,通过字符串 ID 或字符串
const-string v1, "\r|\n"
// 同上
const-string v2, ""
// invoke-virtual{参数}, 方法名调用带参数的虚拟方法
// 这里进行了一个转化 将以上的 “\r|\n” 替换为 “”
invoke-virtual {v0, v1, v2}, Ljava/lang/String;->replaceAll(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
// move-result-object v0 移动上一次方法调用的对象引用返回值到 v0
move-result-object v0
// 而这里则进行一个判断 校验是否相等
invoke-virtual {v0, p2}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
// move-result vx 移动上一次方法调用的返回值到vx。0A00 - move-result v0移动上一次方法调用的返回值到 v
move-result v0
// 将校验结果返回
return v0
.end method
而最后,我们简单看下 onClick 中如何处理:
// 调用 onClick 方法 传如 View
# virtual methods
.method public onClick(Landroid/view/View;)V
.locals 6
// 声明一个 View 类型参数
.param p1, "v" # Landroid/view/View;
.line 40
// iget-object-quick vx, vy, 偏移量 获取 vy 寄存器中实例指向+偏移位置的数据区的对象引用, 存入 vx
iget-object v0, p0, Lcom/hlq/apktooldemo/MainActivity$1;->this$0:Lcom/hlq/apktooldemo/MainActivity;
// invoke-static{参数}, 方法名 调用带参数的静态方法
// 获取 EditText 实例
invoke-static {v0}, Lcom/hlq/apktooldemo/MainActivity;->access$000(Lcom/hlq/apktooldemo/MainActivity;)Landroid/widget/EditText;
// move-result-object vx 移动上一次方法调用的对象引用返回值到 vx
// 将结果赋值 v0
move-result-object v0
// 调用 getText 方法 获取用户输入值
invoke-virtual {v0}, Landroid/widget/EditText;->getText()Landroid/text/Editable;
// 赋值 v0
move-result-object v0
// 调用 toString 方法
invoke-virtual {v0}, Ljava/lang/Object;->toString()Ljava/lang/String;
// 赋值 v0
move-result-object v0
// 定义 String 类型的变量名为 userName 变量
.line 41
.local v0, "userName":Ljava/lang/String;
// iget-object-quick vx, vy, 偏移量 获取 vy 寄存器中实例指向+偏移位置的数据区的对象引用, 存入 vx
// 将最终的结果传入 v1
iget-object v1, p0, Lcom/hlq/apktooldemo/MainActivity$1;->this$0:Lcom/hlq/apktooldemo/MainActivity;
invoke-static {v1}, Lcom/hlq/apktooldemo/MainActivity;->access$100(Lcom/hlq/apktooldemo/MainActivity;)Landroid/widget/EditText;
move-result-object v1
invoke-virtual {v1}, Landroid/widget/EditText;->getText()Landroid/text/Editable;
move-result-object v1
invoke-virtual {v1}, Ljava/lang/Object;->toString()Ljava/lang/String;
// 将值重新赋给 v1
move-result-object v1
// 定义 String 类型的变量名为 userLicense 变量
.line 42
.local v1, "userLicense":Ljava/lang/String;
invoke-static {v0}, Landroid/text/TextUtils;->isEmpty(Ljava/lang/CharSequence;)Z
move-result v2
const/4 v3, 0x0
// if-nez vx, 目标 如果 vx != 0,跳转到目标 cond_2
if-nez v2, :cond_2
// 调用 isEmpty 判断当前是否为空
invoke-static {v1}, Landroid/text/TextUtils;->isEmpty(Ljava/lang/CharSequence;)Z
// move-result vx 移动上一次方法调用的返回值到vx
move-result v2
// if-eqz vx, 目标 如果 vx == 0 ,跳转到目标。 vx 是 int 型值
// 如果当前等于空
if-eqz v2, :cond_0
// goto 目标 通过短偏移量注 2 无条件跳转到目标
goto :goto_1
.line 46
:cond_0
iget-object v2, p0, Lcom/hlq/apktooldemo/MainActivity$1;->this$0:Lcom/hlq/apktooldemo/MainActivity;
invoke-static {v2, v0, v1}, Lcom/hlq/apktooldemo/MainActivity;->access$200(Lcom/hlq/apktooldemo/MainActivity;Ljava/lang/String;Ljava/lang/String;)Z
move-result v2
// 如果等于空 跳转到 cond_1 否则 执行下面 startActivity 方法
if-eqz v2, :cond_1
.line 47
iget-object v2, p0, Lcom/hlq/apktooldemo/MainActivity$1;->this$0:Lcom/hlq/apktooldemo/MainActivity;
new-instance v3, Landroid/content/Intent;
iget-object v4, p0, Lcom/hlq/apktooldemo/MainActivity$1;->this$0:Lcom/hlq/apktooldemo/MainActivity;
const-class v5, Lcom/hlq/apktooldemo/SuccessActivity;
invoke-direct {v3, v4, v5}, Landroid/content/Intent;-><init>(Landroid/content/Context;Ljava/lang/Class;)V
invoke-virtual {v2, v3}, Lcom/hlq/apktooldemo/MainActivity;->startActivity(Landroid/content/Intent;)V
goto :goto_0
.line 49
:cond_1
// 提示异常信息
iget-object v2, p0, Lcom/hlq/apktooldemo/MainActivity$1;->this$0:Lcom/hlq/apktooldemo/MainActivity;
// 转化后结果为:当前校验码有误,请核实~!
// 转化地址:http://tool.oschina.net/encode?type=3
const-string v4, "\u5f53\u524d\u6821\u9a8c\u7801\u6709\u8bef\uff0c\u8bf7\u6838\u5b9e~\uff01"
invoke-static {v2, v4, v3}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
move-result-object v2
invoke-virtual {v2}, Landroid/widget/Toast;->show()V
// 直接执行 return
.line 51
:goto_0
return-void
.line 43
:cond_2
:goto_1
iget-object v2, p0, Lcom/hlq/apktooldemo/MainActivity$1;->this$0:Lcom/hlq/apktooldemo/MainActivity;
// 请输入正确的用户名以及校验码
const-string v4, "\u8bf7\u8f93\u5165\u6b63\u786e\u7684\u7528\u6237\u540d\u4ee5\u53ca\u6821\u9a8c\u7801"
// 调用 makeText 静态方法
invoke-static {v2, v4, v3}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
move-result-object v2
invoke-virtual {v2}, Landroid/widget/Toast;->show()V
.line 44
return-void
.end method
由此推断出,转化为 Java 代码应该如下:
String userName = mUserNameID.getText().toString();
String userLicense = mUserLicenseID.getText().toString();
if (TextUtils.isEmpty(userName) || TextUtils.isEmpty(userLicense)) {
Toast.makeText(MainActivity.this, "请输入正确的用户名以及校验码", Toast.LENGTH_SHORT).show();
return;
}
if (checkData(userName, userLicense)) {
startActivity(new Intent(MainActivity.this, SuccessActivity.class));
} else {
Toast.makeText(MainActivity.this, "当前校验码有误,请核实~!", Toast.LENGTH_SHORT).show();
}
有些生涩,但是好歹翻译出来了。尴尬癌都犯了。。。生涩 ing。。。
修改 Smali 文件,使其达到我们预期效果
从文中提供 Demo 演示图,我们可以看出,当前的小程序主要功能便是,属于用户名以及校验码,验证通过进入欢迎页,否则提示错误异常。
那么,如何在我们不知道验证码的情况下,还能正常进入欢迎页面呢?
结合我们刚刚解析的 Smail 文件,以及转化后的 Java 文件,我们可以得知如下关键内容:
首先,Apk 会对用户输入进行一个非空校验,这个好办,我们随便输入点什么即可绕过;
而关键将通过 Base64 对用户输入进行校验合法性。
那么,我们可以不可以,将这块的逻辑给它逆转一下,比如,我们随便输入,使其程序校验成功,而我们真正录入正确的时候,则认为是失败的。嘿嘿嘿,有点坏哦~
说干就干,一起来修改 Smail 文件。
直接通过搜索定位到 startActivity 方法处:
那么,我们接下来只需要直接将 cond_1 前面的 if - eqz 修改为 if - nez 即可,如下所示:
if-nez v2, :cond_1
.line 47
iget-object v2, p0, Lcom/hlq/apktooldemo/MainActivity$1;->this$0:Lcom/hlq/apktooldemo/MainActivity;
new-instance v3, Landroid/content/Intent;
iget-object v4, p0, Lcom/hlq/apktooldemo/MainActivity$1;->this$0:Lcom/hlq/apktooldemo/MainActivity;
const-class v5, Lcom/hlq/apktooldemo/SuccessActivity;
invoke-direct {v3, v4, v5}, Landroid/content/Intent;-><init>(Landroid/content/Context;Ljava/lang/Class;)V
invoke-virtual {v2, v3}, Lcom/hlq/apktooldemo/MainActivity;->startActivity(Landroid/content/Intent;)V
goto :goto_0
这时候,再次回包:
签个名:
运行查看效果:
6 不 6?
本文到此结束~
大吉大利,晚上吃鸡~~~
欢迎各位老铁关注~不定期发布~见证你我的成长路~!!!
觉得不错,动动小手,转发让更多人看到,3Q,比心~