现在有一个注册机,需要输入与用户名对应的注册码(由用户名经过一系列算法得到)才能成功注册。
当点击注册时提示与log日志输出如下
通过一次未经修改时注册的log返回信息,我们无法得到有效信息,因此我们接下来对该APK进行静态分析。通过Android kill对该apk进行反编译,我们查看并分析其MainActivity.smali文件,通过插入log输出代码输出我们需要的寄存器中的值。
.class public Lcom/qianyu/zhuceji/MainActivity;
.super Landroid/app/Activity;
.source "MainActivity.java"
# instance fields
.field private btn:Landroid/widget/Button;
.field private edit_sn:Landroid/widget/EditText;
.field private edit_username:Landroid/widget/EditText;
# direct methods
.method public constructor ()V
.locals 0
.prologue
.line 14
invoke-direct {p0}, Landroid/app/Activity;->()V
return-void
.end method
.method static synthetic access$0(Lcom/qianyu/zhuceji/MainActivity;)Landroid/widget/EditText;
.locals 1
.prologue
.line 16
iget-object v0, p0, Lcom/qianyu/zhuceji/MainActivity;->edit_username:Landroid/widget/EditText;
return-object v0
.end method
.method static synthetic access$1(Lcom/qianyu/zhuceji/MainActivity;)Landroid/widget/EditText;
.locals 1
.prologue
.line 17
iget-object v0, p0, Lcom/qianyu/zhuceji/MainActivity;->edit_sn:Landroid/widget/EditText;
return-object v0
.end method
.method static synthetic access$2(Lcom/qianyu/zhuceji/MainActivity;Ljava/lang/String;Ljava/lang/String;)Z
.locals 1
.prologue
.line 46
invoke-direct {p0, p1, p2}, Lcom/qianyu/zhuceji/MainActivity;->checkSN(Ljava/lang/String;Ljava/lang/String;)Z
move-result v0
return v0
.end method
.method private checkSN(Ljava/lang/String;Ljava/lang/String;)Z
.locals 10
.param p1, "userName" # Ljava/lang/String;
.param p2, "sn" # Ljava/lang/String;
.prologue
const/4 v7, 0x0
.line 48
if-eqz p1, :cond_0
:try_start_0
invoke-virtual {p1}, Ljava/lang/String;->length()I
move-result v8
if-nez v8, :cond_1
.line 72
:cond_0
:goto_0
return v7
.line 51
:cond_1
if-eqz p2, :cond_0
invoke-virtual {p2}, Ljava/lang/String;->length()I
move-result v8
const/16 v9, 0x10
if-ne v8, v9, :cond_0
.line 54
const-string v8, "MD5"
invoke-static {v8}, Ljava/security/MessageDigest;->getInstance(Ljava/lang/String;)Ljava/security/MessageDigest;
move-result-object v1
.line 55
.local v1, "digest":Ljava/security/MessageDigest;
invoke-virtual {v1}, Ljava/security/MessageDigest;->reset()V
.line 56
invoke-virtual {p1}, Ljava/lang/String;->getBytes()[B
move-result-object v8
invoke-virtual {v1, v8}, Ljava/security/MessageDigest;->update([B)V
.line 57
invoke-virtual {v1}, Ljava/security/MessageDigest;->digest()[B
move-result-object v0
.line 58
.local v0, "bytes":[B
const-string v8, ""
invoke-static {v0, v8}, Lcom/qianyu/zhuceji/MainActivity;->toHexString([BLjava/lang/String;)Ljava/lang/String;
move-result-object v3
.line 59
.local v3, "hexstr":Ljava/lang/String;
new-instance v5, Ljava/lang/StringBuilder;
invoke-direct {v5}, Ljava/lang/StringBuilder;->()V
.line 60
.local v5, "sb":Ljava/lang/StringBuilder;
const/4 v4, 0x0
.local v4, "i":I
:goto_1
invoke-virtual {v3}, Ljava/lang/String;->length()I
move-result v8
if-lt v4, v8, :cond_2
.line 63
invoke-virtual {v5}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v6
.line 65
.local v6, "userSN":Ljava/lang/String;
invoke-virtual {v6, p2}, Ljava/lang/String;->equalsIgnoreCase(Ljava/lang/String;)Z
move-result v8
if-eqz v8, :cond_0
.line 72
const/4 v7, 0x1
goto :goto_0
.line 61
.end local v6 # "userSN":Ljava/lang/String;
:cond_2
invoke-virtual {v3, v4}, Ljava/lang/String;->charAt(I)C
move-result v8
invoke-virtual {v5, v8}, Ljava/lang/StringBuilder;->append(C)Ljava/lang/StringBuilder;
:try_end_0
.catch Ljava/security/NoSuchAlgorithmException; {:try_start_0 .. :try_end_0} :catch_0
.line 60
add-int/lit8 v4, v4, 0x2
goto :goto_1
.line 68
.end local v0 # "bytes":[B
.end local v1 # "digest":Ljava/security/MessageDigest;
.end local v3 # "hexstr":Ljava/lang/String;
.end local v4 # "i":I
.end local v5 # "sb":Ljava/lang/StringBuilder;
:catch_0
move-exception v2
.line 69
.local v2, "e":Ljava/security/NoSuchAlgorithmException;
invoke-virtual {v2}, Ljava/security/NoSuchAlgorithmException;->printStackTrace()V
goto :goto_0
.end method
.method private init()V
.locals 1
.prologue
.line 41
const/high16 v0, 0x7f080000
invoke-virtual {p0, v0}, Lcom/qianyu/zhuceji/MainActivity;->findViewById(I)Landroid/view/View;
move-result-object v0
check-cast v0, Landroid/widget/EditText;
iput-object v0, p0, Lcom/qianyu/zhuceji/MainActivity;->edit_username:Landroid/widget/EditText;
.line 42
const v0, 0x7f080001
invoke-virtual {p0, v0}, Lcom/qianyu/zhuceji/MainActivity;->findViewById(I)Landroid/view/View;
move-result-object v0
check-cast v0, Landroid/widget/EditText;
iput-object v0, p0, Lcom/qianyu/zhuceji/MainActivity;->edit_sn:Landroid/widget/EditText;
.line 43
const v0, 0x7f080002
invoke-virtual {p0, v0}, Lcom/qianyu/zhuceji/MainActivity;->findViewById(I)Landroid/view/View;
move-result-object v0
check-cast v0, Landroid/widget/Button;
iput-object v0, p0, Lcom/qianyu/zhuceji/MainActivity;->btn:Landroid/widget/Button;
.line 44
return-void
.end method
.method private static toHexString([BLjava/lang/String;)Ljava/lang/String;
.locals 7
.param p0, "bytes" # [B
.param p1, "separator" # Ljava/lang/String;
.prologue
.line 77
new-instance v2, Ljava/lang/StringBuilder;
invoke-direct {v2}, Ljava/lang/StringBuilder;->()V
.line 78
.local v2, "hexString":Ljava/lang/StringBuilder;
array-length v4, p0
const/4 v3, 0x0
:goto_0
if-lt v3, v4, :cond_0
.line 85
invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v3
return-object v3
.line 78
:cond_0
aget-byte v0, p0, v3
.line 79
.local v0, "b":B
and-int/lit16 v5, v0, 0xff
invoke-static {v5}, Ljava/lang/Integer;->toHexString(I)Ljava/lang/String;
move-result-object v1
.line 80
.local v1, "hex":Ljava/lang/String;
invoke-virtual {v1}, Ljava/lang/String;->length()I
move-result v5
const/4 v6, 0x1
if-ne v5, v6, :cond_1
.line 81
const/16 v5, 0x30
invoke-virtual {v2, v5}, Ljava/lang/StringBuilder;->append(C)Ljava/lang/StringBuilder;
.line 83
:cond_1
invoke-virtual {v2, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v5
invoke-virtual {v5, p1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
.line 78
add-int/lit8 v3, v3, 0x1
goto :goto_0
.end method
# virtual methods
.method protected onCreate(Landroid/os/Bundle;)V
.locals 2
.param p1, "savedInstanceState" # Landroid/os/Bundle;
.prologue
.line 22
invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V
.line 23
const v0, 0x7f050003
invoke-virtual {p0, v0}, Lcom/qianyu/zhuceji/MainActivity;->setTitle(I)V
.line 24
const/high16 v0, 0x7f030000
invoke-virtual {p0, v0}, Lcom/qianyu/zhuceji/MainActivity;->setContentView(I)V
.line 25
invoke-direct {p0}, Lcom/qianyu/zhuceji/MainActivity;->init()V
.line 26
iget-object v0, p0, Lcom/qianyu/zhuceji/MainActivity;->btn:Landroid/widget/Button;
new-instance v1, Lcom/qianyu/zhuceji/MainActivity$1;
invoke-direct {v1, p0}, Lcom/qianyu/zhuceji/MainActivity$1;->(Lcom/qianyu/zhuceji/MainActivity;)V
invoke-virtual {v0, v1}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V
.line 38
return-void
.end method
由于我们只需要绕过对注册码的验证,所以我们直接从checkSN方法直接开始分析
1、分析 .line 51 中的内容我们得知这里对我们输入的注册码进行了是否输入与长度为16的检测,否则结束checkSN的检测。——(因此在之后的注册码中需要输入16位,或者将if-eqz与if-ne判断更改)
2、从 .line56中开始调用p1(及用户名)开始进行一系列的运算,最终在 .line63中得到了变量v6
3、继续往后分析,我们看到了 .line65中的“invoke-virtual {v6, p2}, Ljava/lang/String;->equalsIgnoreCase(Ljava/lang/String;)Z”,他调用了虚方法equalsIgnoreCase(),该方法用于两个字符串的比较,其中p2为我们输入的注册码,由此我们可以猜测出v6及为(2)中计算出的用户名所对应的注册码。我们通过在.line65之前添加log输出代码来输出v6中的值。
log输出代码:invoke-static {v6}, Lcom/android/killer/Log;->LogStr(Ljava/lang/String;)V
将修改后的代码进行编译生成新的APK,并安装输入信息后注册,查看log输出信息
上图中tag属性值为AndroidKiller-string的text属性值中成功输出正确的注册码,通过实验正确注册。