启程
最近开始学习起了逆向,感觉看了逆向的代码之后对正向开发有不同的见解,当然只是我个人的看法而已,看懂一大堆的逆向代码也是成就感爆棚,一点都不亚于看懂看懂别人的框架代码
(文章仅用于记录学习过程)
工具
我有win和mac端,也在研究win端和mac端哪个更合适于逆向开发,因为正向开发我是习惯用mac,所以逆向的话我应该会更喜欢用mac,但是mac的工具学习成本要高于win端,win端的工具也相对成熟和拥有比较好的可视化界面.
mac
ApkTool,dex2jar,D-GUI,具体可以参考下mac逆向工具教程
win
win端上面的工具就很多了,主要用的是Apktool和AndoridKiller
开始
首先在Android Studio上面编写一个简单的密码登录界面,图形界面就是两个EditText和一个TextView,界面略丑
图形界面
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<EditText
android:id="@+id/edt_account"
android:layout_width="match_parent"
android:layout_height="50dp"
android:hint="请输入账号" />
<EditText
android:id="@+id/edt_passwd"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="30dp"
android:hint="请输入密码" />
<TextView
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="#333333"
android:onClick="onLogin"
android:textColor="#ffffff"
android:layout_marginTop="30dp"
android:gravity="center"
android:text="登录" />
</LinearLayout>
java代码部分
package com.ss.apktool;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private EditText mEdtAccount;
private EditText mEdtPasswd;
private final String ACCOUNT = "123";
private final String PASSWD = "123";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mEdtAccount = findViewById(R.id.edt_account);
mEdtPasswd = findViewById(R.id.edt_passwd);
}
public void onLogin(View view) {
String account = mEdtAccount.getText().toString();
String passwd = mEdtPasswd.getText().toString().trim();
//输入账号密码 如何账号密码不等于123,就提示登录失败,反之提示登录成功
if (!TextUtils.isEmpty(account) && !TextUtils.isEmpty(passwd)) {
if (account.equals(ACCOUNT) && passwd.equals(PASSWD)) {
Toast.makeText(this, "登录成功", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "登录失败", Toast.LENGTH_SHORT).show();
}
}
}
}
我在mac上,使用apktool进行反编译得到smail文件,使用Sublime Text进行查看和修改
.class public Lcom/ss/apktool/MainActivity;
.super Landroidx/appcompat/app/AppCompatActivity;
.source "MainActivity.java" //当前类名称
# instance fields
.field private final ACCOUNT:Ljava/lang/String; //定义一个String类型的变量ACCOUNT
.field private final PASSWD:Ljava/lang/String;//定义一个String类型的变量PASSWD
.field private mEdtAccount:Landroid/widget/EditText;//定义一个EditText
.field private mEdtPasswd:Landroid/widget/EditText;定义一个EditText
//Ljava/lang/String 其中 L代表的是类型 ,java/lang/String就是具体的类型,所以就是String类型 以此类推
# direct methods
.method public constructor <init>()V
.locals 1
.line 11
invoke-direct {p0}, Landroidx/appcompat/app/AppCompatActivity;-><init>()V
const-string v0, "123" //将123赋值给v0寄存器
.line 16
iput-object v0, p0, Lcom/ss/apktool/MainActivity;->ACCOUNT:Ljava/lang/String; //将v0的值付给ACCOUNT
.line 17
iput-object v0, p0, Lcom/ss/apktool/MainActivity;->PASSWD:Ljava/lang/String; //将v0的值付给PASSWD
return-void
.end method
# virtual methods
.method protected onCreate(Landroid/os/Bundle;)V
.locals 0
.line 21
invoke-super {p0, p1}, Landroidx/appcompat/app/AppCompatActivity;->onCreate(Landroid/os/Bundle;)V
const p1, 0x7f0b001c
.line 22
invoke-virtual {p0, p1}, Lcom/ss/apktool/MainActivity;->setContentView(I)V
const p1, 0x7f08006d
.line 23
invoke-virtual {p0, p1}, Lcom/ss/apktool/MainActivity;->findViewById(I)Landroid/view/View;//调用findViewById方法得到一个view地址
move-result-object p1 //将上面的操作结果赋值给p1
check-cast p1, Landroid/widget/EditText; //将寄存器p1转成EditText类型
iput-object p1, p0, Lcom/ss/apktool/MainActivity;->mEdtAccount:Landroid/widget/EditText;
const p1, 0x7f08006e
.line 24
invoke-virtual {p0, p1}, Lcom/ss/apktool/MainActivity;->findViewById(I)Landroid/view/View;
move-result-object p1
check-cast p1, Landroid/widget/EditText;
iput-object p1, p0, Lcom/ss/apktool/MainActivity;->mEdtPasswd:Landroid/widget/EditText;
return-void
.end method
//onLogin方法,参数是View类型
.method public onLogin(Landroid/view/View;)V
.locals 3
.line 29
iget-object p1, p0, Lcom/ss/apktool/MainActivity;->mEdtAccount:Landroid/widget/EditText; //获取mEdtAccount实例
invoke-virtual {p1}, Landroid/widget/EditText;->getText()Landroid/text/Editable;//调用getText方法等到p1
move-result-object p1//将操作结果赋值给p1
invoke-virtual {p1}, Ljava/lang/Object;->toString()Ljava/lang/String;//继续调用toString方法返回一个String类型的p1
move-result-object p1 //将结果赋值给p1
.line 30
iget-object v0, p0, Lcom/ss/apktool/MainActivity;->mEdtPasswd:Landroid/widget/EditText;//获取mEdtPasswd实例
invoke-virtual {v0}, Landroid/widget/EditText;->getText()Landroid/text/Editable;
move-result-object v0
invoke-virtual {v0}, Ljava/lang/Object;->toString()Ljava/lang/String;
move-result-object v0
invoke-virtual {v0}, Ljava/lang/String;->trim()Ljava/lang/String;
move-result-object v0
//经过上面的代码,得到寄存器p1和寄存器v0
.line 32
invoke-static {p1}, Landroid/text/TextUtils;->isEmpty(Ljava/lang/CharSequence;)Z //调用TextUtils的静态方法isEmpty也就是判空处理
move-result v1 //将上面的结果赋值给v1寄存器
if-nez v1, :cond_1 //如果v1的结果不为0,也是是为true
invoke-static {v0}, Landroid/text/TextUtils;->isEmpty(Ljava/lang/CharSequence;)Z//调用TextUtils的静态方法isEmpty也就是判空处理
move-result v1//将上面的结果赋值给v1寄存器
if-nez v1, :cond_1 //如果v1的结果不为0,就跳转
const-string v1, "123" //将字符串123赋值给v1寄存器
.line 33
invoke-virtual {p1, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z //调用equals方法,比较p1和v1寄存器值是否相同
move-result p1 //将操作结果赋值给p1
const/4 v2, 0x0 //定义Toast的时间
// 将这里的if-eqz修改成if-nez(修改这里)
if-eqz p1, :cond_0 //如果p1的值等于0就继续执行(true),不然就跳转到 cond_0
invoke-virtual {v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z //将v0和v1进行比较
move-result p1 //将结果赋值给p1
// 将这里的if-eqz修改成if-nez(修改这里)
if-eqz p1, :cond_0//如果p1的值等于0就继续执行(true) 不然就跳转到 cond_0
const-string p1, "\u767b\u5f55\u6210\u529f" //将字符串赋值给P1
//调用Toast静态方法,这个方法要传入3个参数,p0 是 Landroid/content/Context(上下文这里是MainActivity),p1 是 Ljava/lang/CharSequence(字串符类型),v2 是 I(代表Int类型)
//makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)
.line 34
invoke-static {p0, p1, v2}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
move-result-object p1 //将Toast之后的结果赋值给p1
invoke-virtual {p1}, Landroid/widget/Toast;->show()V //p1调用show方法
goto :goto_0
:cond_0
const-string p1, "\u767b\u5f55\u5931\u8d25" //定义字符串p1
.line 36
//调用Toast静态方法,这个方法要传入3个参数,p0 是 Landroid/content/Context(上下文这里是MainActivity),p1 是 Ljava/lang/CharSequence(字串符类型),v2 是 I(代表Int类型)
//makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)
invoke-static {p0, p1, v2}, 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 //显示toast
:cond_1
:goto_0
return-void
.end method
修改的结果就是将if-eqz修改成if-nez,这样就是修改了逻辑,变成只要账号密码不等于123就可以登录成功
欢迎大家和我进行学习交流,不足的地方请指出,我好及时更正!