Android 静态分析 smali

一、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$OnClickListener
     7、还可以参考http://blog.csdn.net/lpohvbe/article/details/7981386

           注:invoke-static:调用静态方法,invoke-direct:调用私有或者构造函数,invoke-virtual:调用public或者protected方法。


二、工程源码目录       

         Android 静态分析 smali

       在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;
        }
    }
}

         MainActivity.java对应的反编译过来的smali是以下四个文件,a.smali,b.smali,c.smali,MainActivity.smali

         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

        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 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

        c.smali代码如下:

.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

       MainActivity.smali代码如下:

.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 method

       MyApp.java代码如下:

package 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.java对应的反编译出来的smali文件为MyApp.smali

        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

       c.smali代码如下:

.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 method

Android 静态分析 smali,布布扣,bubuko.com

Android 静态分析 smali

上一篇:Mybatis实战(四)Mapper配置文件


下一篇:JAVA全栈第四天:Mybatis Mapper