一、smali语言简介
1、宏观的介绍:http://source.android.com/devices/tech/dalvik/instruction-formats.html
2、具体的指令:http://source.android.com/devices/tech/dalvik/dalvik-bytecode.html
3、《Android安全与逆向分析》一书
4、具体指令中的meth@BBBB、filed@BBBB、type@BBBB,方法、字段、类型:https://code.google.com/p/smali/wiki/TypesMethodsAndFields
5、具体指令中的vXXX,寄存器,https://code.google.com/p/smali/wiki/Registers
注:非static函数中,p0代指“this”,p1表示函数的第一个参数,p2代表函数中的第二个参数…而在static函数中p0才对应第一个参数(因为Java的static方法中没有this方法)
6、整体的格式(混淆后的,如果没有混淆结构会更详细)
(1)、类:
.class public Lcom/jltxgcy/crack/MainActivity; .super Landroid/app/Activity;(2)、方法:
# direct methods or vitual methods
.method public constructor <init>()V
.locals 0
invoke-direct {p0}, Landroid/app/Activity;-><init>()V
return-void
.end method 直接方法指构造函数,私有方法,静态方法。虚方法指的是其他的。
(3)、字段
# instance fields or static filelds .field private a:Landroid/widget/Button;(4)、接口
# interfaces .implements Landroid/view/View$OnClickListener7、还可以参考http://blog.csdn.net/lpohvbe/article/details/7981386
注:invoke-static:调用静态方法,invoke-direct:调用私有或者构造函数,invoke-virtual:调用public或者protected方法。
二、工程源码目录
在Android混淆机制这篇文章中,http://blog.csdn.net/jltxgcy/article/details/22670651,对于上面的CrackApk工程,根据不同的proguard-project.txt的不同规则,导出两个混淆后的apk,一个是CrackApk01.apk,一个是CrackApk02.apk。
CrackApk01.apk没有保留内部类isRegistered方法,CrackApk02.apk保留了内部类isRegistered方法。
使用apktool进行反编译两个apk,参考http://blog.csdn.net/jltxgcy/article/details/22690753。最后生成smali语言。
下面我们来对比分析反编译生成的smali和CrackApk工程中对应的java文件。
首先分析CrackApk01.apk。
MainActivity.java代码如下:
package com.jltxgcy.crack;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {
private Button btnAnno;
private Button btnCheckSN;
private EditText edtSN;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnAnno = (Button) findViewById(R.id.btn_annotation);
btnCheckSN = (Button) findViewById(R.id.btn_checksn);
edtSN = (EditText) findViewById(R.id.edt_sn);
btnAnno.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
getAnnotations();
}
});
btnCheckSN.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
SNChecker checker = new SNChecker(edtSN.getText().toString());
String str = checker.isRegistered() ? "注册成功" : "注册失败";
Toast.makeText(MainActivity.this, str, Toast.LENGTH_SHORT).show();
}
});
}
private void getAnnotations() {
try {
Toast.makeText(this, "getAnnotations", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public class SNChecker {
private String sn;
public SNChecker(String sn) {
this.sn = sn;
}
public boolean isRegistered() {
boolean result = false;
char ch = ‘\0‘;
int sum = 0;
if (sn == null || (sn.length() < 8)) return result;
int len = sn.length();
if (len == 8) {
ch = sn.charAt(0);
switch (ch) {
case ‘a‘:
case ‘f‘:
result = true;
break;
default:
result = false;
break;
}
if (result) {
ch = sn.charAt(3);
switch (ch) {
case ‘1‘:
case ‘2‘:
case ‘3‘:
case ‘4‘:
case ‘5‘:
result = true;
break;
default:
result = false;
break;
}
}
} else if (len == 16) {
for (int i = 0; i < len; i++) {
char chPlus = sn.charAt(i);
sum += (int) chPlus;
}
result = ((sum % 6) == 0) ? true : false;
}
return result;
}
}
}a.smali代码如下:
.class final Lcom/jltxgcy/crack/a;
.super Ljava/lang/Object;
# interfaces
.implements Landroid/view/View$OnClickListener;
# instance fields
.field final synthetic a:Lcom/jltxgcy/crack/MainActivity;
# direct methods
.method constructor <init>(Lcom/jltxgcy/crack/MainActivity;)V
.locals 0
iput-object p1, p0, Lcom/jltxgcy/crack/a;->a:Lcom/jltxgcy/crack/MainActivity;
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
# virtual methods
.method public final onClick(Landroid/view/View;)V
.locals 1
iget-object v0, p0, Lcom/jltxgcy/crack/a;->a:Lcom/jltxgcy/crack/MainActivity;
invoke-static {v0}, Lcom/jltxgcy/crack/MainActivity;->a(Lcom/jltxgcy/crack/MainActivity;)V
return-void
.end method.class final Lcom/jltxgcy/crack/b;
.super Ljava/lang/Object;
# interfaces
.implements Landroid/view/View$OnClickListener;
# instance fields
.field final synthetic a:Lcom/jltxgcy/crack/MainActivity;
# direct methods
.method constructor <init>(Lcom/jltxgcy/crack/MainActivity;)V
.locals 0
iput-object p1, p0, Lcom/jltxgcy/crack/b;->a:Lcom/jltxgcy/crack/MainActivity;
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
# virtual methods
.method public final onClick(Landroid/view/View;)V
.locals 7
const/16 v6, 0x8
const/4 v0, 0x1
const/4 v1, 0x0
new-instance v4, Lcom/jltxgcy/crack/c;
iget-object v2, p0, Lcom/jltxgcy/crack/b;->a:Lcom/jltxgcy/crack/MainActivity;
iget-object v3, p0, Lcom/jltxgcy/crack/b;->a:Lcom/jltxgcy/crack/MainActivity;
invoke-static {v3}, Lcom/jltxgcy/crack/MainActivity;->b(Lcom/jltxgcy/crack/MainActivity;)Landroid/widget/EditText;
move-result-object v3
invoke-virtual {v3}, Landroid/widget/EditText;->getText()Landroid/text/Editable;
move-result-object v3
invoke-interface {v3}, Landroid/text/Editable;->toString()Ljava/lang/String;
move-result-object v3
invoke-direct {v4, v2, v3}, Lcom/jltxgcy/crack/c;-><init>(Lcom/jltxgcy/crack/MainActivity;Ljava/lang/String;)V
iget-object v2, v4, Lcom/jltxgcy/crack/c;->a:Ljava/lang/String;
if-eqz v2, :cond_0
iget-object v2, v4, Lcom/jltxgcy/crack/c;->a:Ljava/lang/String;
invoke-virtual {v2}, Ljava/lang/String;->length()I
move-result v2
if-ge v2, v6, :cond_2
:cond_0
move v0, v1
:cond_1
:goto_0
:pswitch_0
if-eqz v0, :cond_5
const-string v0, "\u6ce8\u518c\u6210\u529f"
:goto_1
iget-object v2, p0, Lcom/jltxgcy/crack/b;->a:Lcom/jltxgcy/crack/MainActivity;
invoke-static {v2, v0, v1}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
move-result-object v0
invoke-virtual {v0}, Landroid/widget/Toast;->show()V
return-void
:cond_2
iget-object v2, v4, Lcom/jltxgcy/crack/c;->a:Ljava/lang/String;
invoke-virtual {v2}, Ljava/lang/String;->length()I
move-result v5
if-ne v5, v6, :cond_3
iget-object v2, v4, Lcom/jltxgcy/crack/c;->a:Ljava/lang/String;
invoke-virtual {v2, v1}, Ljava/lang/String;->charAt(I)C
move-result v2
sparse-switch v2, :sswitch_data_0
move v2, v1
:goto_2
if-eqz v2, :cond_7
iget-object v2, v4, Lcom/jltxgcy/crack/c;->a:Ljava/lang/String;
const/4 v3, 0x3
invoke-virtual {v2, v3}, Ljava/lang/String;->charAt(I)C
move-result v2
packed-switch v2, :pswitch_data_0
move v0, v1
goto :goto_0
:sswitch_0
move v2, v0
goto :goto_2
:cond_3
const/16 v2, 0x10
if-ne v5, v2, :cond_6
move v2, v1
move v3, v1
:goto_3
if-lt v3, v5, :cond_4
rem-int/lit8 v2, v2, 0x6
if-eqz v2, :cond_1
move v0, v1
goto :goto_0
:cond_4
iget-object v6, v4, Lcom/jltxgcy/crack/c;->a:Ljava/lang/String;
invoke-virtual {v6, v3}, Ljava/lang/String;->charAt(I)C
move-result v6
add-int/2addr v2, v6
add-int/lit8 v3, v3, 0x1
goto :goto_3
:cond_5
const-string v0, "\u6ce8\u518c\u5931\u8d25"
goto :goto_1
:cond_6
move v0, v1
goto :goto_0
:cond_7
move v0, v2
goto :goto_0
nop
:sswitch_data_0
.sparse-switch
0x61 -> :sswitch_0
0x66 -> :sswitch_0
.end sparse-switch
:pswitch_data_0
.packed-switch 0x31
:pswitch_0
:pswitch_0
:pswitch_0
:pswitch_0
:pswitch_0
.end packed-switch
.end method.class public final Lcom/jltxgcy/crack/c;
.super Ljava/lang/Object;
# instance fields
.field a:Ljava/lang/String;
.field final synthetic b:Lcom/jltxgcy/crack/MainActivity;
# direct methods
.method public constructor <init>(Lcom/jltxgcy/crack/MainActivity;Ljava/lang/String;)V
.locals 0
iput-object p1, p0, Lcom/jltxgcy/crack/c;->b:Lcom/jltxgcy/crack/MainActivity;
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
iput-object p2, p0, Lcom/jltxgcy/crack/c;->a:Ljava/lang/String;
return-void
.end method.class public Lcom/jltxgcy/crack/MainActivity;
.super Landroid/app/Activity;
# instance fields
.field private a:Landroid/widget/Button;
.field private b:Landroid/widget/Button;
.field private c:Landroid/widget/EditText;
# direct methods
.method public constructor <init>()V
.locals 0
invoke-direct {p0}, Landroid/app/Activity;-><init>()V
return-void
.end method
.method static synthetic a(Lcom/jltxgcy/crack/MainActivity;)V
.locals 2
:try_start_0
const-string v0, "getAnnotations"
const/4 v1, 0x0
invoke-static {p0, v0, v1}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
move-result-object v0
invoke-virtual {v0}, Landroid/widget/Toast;->show()V
:try_end_0
.catch Ljava/lang/Exception; {:try_start_0 .. :try_end_0} :catch_0
:goto_0
return-void
:catch_0
move-exception v0
invoke-virtual {v0}, Ljava/lang/Exception;->printStackTrace()V
goto :goto_0
.end method
.method static synthetic b(Lcom/jltxgcy/crack/MainActivity;)Landroid/widget/EditText;
.locals 1
iget-object v0, p0, Lcom/jltxgcy/crack/MainActivity;->c:Landroid/widget/EditText;
return-object v0
.end method
# virtual methods
.method public onCreate(Landroid/os/Bundle;)V
.locals 2
invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V
const/high16 v0, 0x7f03
invoke-virtual {p0, v0}, Lcom/jltxgcy/crack/MainActivity;->setContentView(I)V
const/high16 v0, 0x7f08
invoke-virtual {p0, v0}, Lcom/jltxgcy/crack/MainActivity;->findViewById(I)Landroid/view/View;
move-result-object v0
check-cast v0, Landroid/widget/Button;
iput-object v0, p0, Lcom/jltxgcy/crack/MainActivity;->a:Landroid/widget/Button;
const v0, 0x7f080002
invoke-virtual {p0, v0}, Lcom/jltxgcy/crack/MainActivity;->findViewById(I)Landroid/view/View;
move-result-object v0
check-cast v0, Landroid/widget/Button;
iput-object v0, p0, Lcom/jltxgcy/crack/MainActivity;->b:Landroid/widget/Button;
const v0, 0x7f080001
invoke-virtual {p0, v0}, Lcom/jltxgcy/crack/MainActivity;->findViewById(I)Landroid/view/View;
move-result-object v0
check-cast v0, Landroid/widget/EditText;
iput-object v0, p0, Lcom/jltxgcy/crack/MainActivity;->c:Landroid/widget/EditText;
iget-object v0, p0, Lcom/jltxgcy/crack/MainActivity;->a:Landroid/widget/Button;
new-instance v1, Lcom/jltxgcy/crack/a;
invoke-direct {v1, p0}, Lcom/jltxgcy/crack/a;-><init>(Lcom/jltxgcy/crack/MainActivity;)V
invoke-virtual {v0, v1}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V
iget-object v0, p0, Lcom/jltxgcy/crack/MainActivity;->b:Landroid/widget/Button;
new-instance v1, Lcom/jltxgcy/crack/b;
invoke-direct {v1, p0}, Lcom/jltxgcy/crack/b;-><init>(Lcom/jltxgcy/crack/MainActivity;)V
invoke-virtual {v0, v1}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V
return-void
.end method
.method public onCreateOptionsMenu(Landroid/view/Menu;)Z
.locals 2
invoke-virtual {p0}, Lcom/jltxgcy/crack/MainActivity;->getMenuInflater()Landroid/view/MenuInflater;
move-result-object v0
const/high16 v1, 0x7f07
invoke-virtual {v0, v1, p1}, Landroid/view/MenuInflater;->inflate(ILandroid/view/Menu;)V
const/4 v0, 0x1
return v0
.end methodpackage com.jltxgcy.crack.app;
import android.app.Application;
import android.widget.Toast;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import com.jltxgcy.crack.MainActivity;
public class MyApp extends Application{
@Override
public void onCreate() {
Toast.makeText(this, "app creat", Toast.LENGTH_SHORT).show();
super.onCreate();
}
}
MyApp.smali代码如下:
.class public Lcom/jltxgcy/crack/app/MyApp;
.super Landroid/app/Application;
# direct methods
.method public constructor <init>()V
.locals 0
invoke-direct {p0}, Landroid/app/Application;-><init>()V
return-void
.end method
# virtual methods
.method public onCreate()V
.locals 2
const-string v0, "app creat"
const/4 v1, 0x0
invoke-static {p0, v0, v1}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
move-result-object v0
invoke-virtual {v0}, Landroid/widget/Toast;->show()V
invoke-super {p0}, Landroid/app/Application;->onCreate()V
return-void
.end method然后我们来分析CrackApk02.apk,由于混淆机制保存了内部类isRegister,所以b.smail和c.smail有所不同。
b.smali代码如下:
.class final Lcom/jltxgcy/crack/b;
.super Ljava/lang/Object;
# interfaces
.implements Landroid/view/View$OnClickListener;
# instance fields
.field final synthetic a:Lcom/jltxgcy/crack/MainActivity;
# direct methods
.method constructor <init>(Lcom/jltxgcy/crack/MainActivity;)V
.locals 0
iput-object p1, p0, Lcom/jltxgcy/crack/b;->a:Lcom/jltxgcy/crack/MainActivity;
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
# virtual methods
.method public final onClick(Landroid/view/View;)V
.locals 3
new-instance v0, Lcom/jltxgcy/crack/c;
iget-object v1, p0, Lcom/jltxgcy/crack/b;->a:Lcom/jltxgcy/crack/MainActivity;
iget-object v2, p0, Lcom/jltxgcy/crack/b;->a:Lcom/jltxgcy/crack/MainActivity;
invoke-static {v2}, Lcom/jltxgcy/crack/MainActivity;->b(Lcom/jltxgcy/crack/MainActivity;)Landroid/widget/EditText;
move-result-object v2
invoke-virtual {v2}, Landroid/widget/EditText;->getText()Landroid/text/Editable;
move-result-object v2
invoke-interface {v2}, Landroid/text/Editable;->toString()Ljava/lang/String;
move-result-object v2
invoke-direct {v0, v1, v2}, Lcom/jltxgcy/crack/c;-><init>(Lcom/jltxgcy/crack/MainActivity;Ljava/lang/String;)V
invoke-virtual {v0}, Lcom/jltxgcy/crack/c;->isRegistered()Z
move-result v0
if-eqz v0, :cond_0
const-string v0, "\u6ce8\u518c\u6210\u529f"
:goto_0
iget-object v1, p0, Lcom/jltxgcy/crack/b;->a:Lcom/jltxgcy/crack/MainActivity;
const/4 v2, 0x0
invoke-static {v1, v0, v2}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
move-result-object v0
invoke-virtual {v0}, Landroid/widget/Toast;->show()V
return-void
:cond_0
const-string v0, "\u6ce8\u518c\u5931\u8d25"
goto :goto_0
.end method.class public final Lcom/jltxgcy/crack/c;
.super Ljava/lang/Object;
# instance fields
.field final synthetic a:Lcom/jltxgcy/crack/MainActivity;
.field private b:Ljava/lang/String;
# direct methods
.method public constructor <init>(Lcom/jltxgcy/crack/MainActivity;Ljava/lang/String;)V
.locals 0
iput-object p1, p0, Lcom/jltxgcy/crack/c;->a:Lcom/jltxgcy/crack/MainActivity;
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
iput-object p2, p0, Lcom/jltxgcy/crack/c;->b:Ljava/lang/String;
return-void
.end method
# virtual methods
.method public final isRegistered()Z
.locals 6
const/16 v3, 0x8
const/4 v0, 0x1
const/4 v1, 0x0
iget-object v2, p0, Lcom/jltxgcy/crack/c;->b:Ljava/lang/String;
if-eqz v2, :cond_0
iget-object v2, p0, Lcom/jltxgcy/crack/c;->b:Ljava/lang/String;
invoke-virtual {v2}, Ljava/lang/String;->length()I
move-result v2
if-ge v2, v3, :cond_1
:cond_0
:goto_0
return v1
:cond_1
iget-object v2, p0, Lcom/jltxgcy/crack/c;->b:Ljava/lang/String;
invoke-virtual {v2}, Ljava/lang/String;->length()I
move-result v4
if-ne v4, v3, :cond_3
iget-object v2, p0, Lcom/jltxgcy/crack/c;->b:Ljava/lang/String;
invoke-virtual {v2, v1}, Ljava/lang/String;->charAt(I)C
move-result v2
sparse-switch v2, :sswitch_data_0
move v2, v1
:goto_1
if-eqz v2, :cond_5
iget-object v2, p0, Lcom/jltxgcy/crack/c;->b:Ljava/lang/String;
const/4 v3, 0x3
invoke-virtual {v2, v3}, Ljava/lang/String;->charAt(I)C
move-result v2
packed-switch v2, :pswitch_data_0
move v0, v1
:cond_2
:goto_2
:pswitch_0
move v1, v0
goto :goto_0
:sswitch_0
move v2, v0
goto :goto_1
:cond_3
const/16 v2, 0x10
if-ne v4, v2, :cond_0
move v2, v1
move v3, v1
:goto_3
if-lt v3, v4, :cond_4
rem-int/lit8 v2, v2, 0x6
if-eqz v2, :cond_2
move v0, v1
goto :goto_2
:cond_4
iget-object v5, p0, Lcom/jltxgcy/crack/c;->b:Ljava/lang/String;
invoke-virtual {v5, v3}, Ljava/lang/String;->charAt(I)C
move-result v5
add-int/2addr v2, v5
add-int/lit8 v3, v3, 0x1
goto :goto_3
:cond_5
move v1, v2
goto :goto_0
:sswitch_data_0
.sparse-switch
0x61 -> :sswitch_0
0x66 -> :sswitch_0
.end sparse-switch
:pswitch_data_0
.packed-switch 0x31
:pswitch_0
:pswitch_0
:pswitch_0
:pswitch_0
:pswitch_0
.end packed-switch
.end methodAndroid 静态分析 smali,布布扣,bubuko.com
原文:http://blog.csdn.net/jltxgcy/article/details/22805287