[JAVA] Décompilation de l'application Android ⇒ correction ⇒ recompilation

Que faire

-Décompiler le fichier apk dans le code source au format Java d'origine -Décompiler le fichier apk en un code au format Smalli recompilable -Modifier le code Smalli décompilé et recompiler

Outils à utiliser

・ Apktool https://ibotpeaches.github.io/Apktool/ ・ Dex2jar https://github.com/pxb1988/dex2jar ・ Jad http://www.javadecompilers.com/jad

Application de test de vérification

Si vous entrez le mot de passe correct (possword), le processus de connexion sera exécuté. Utilisez une application simple avec un champ de saisie de mot de passe et un bouton de connexion pour la vérification

Screenshot_20170701-193328.png Screenshot_20170701-193401.png

·Code source

MainActivity.java


package com.example.user.logintest;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {

    private Button mLogInButton;
    private EditText mPasswordEditText;
    private TextView mStatusTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mPasswordEditText = (EditText)findViewById(R.id.editText);
        mStatusTextView = (TextView)findViewById(R.id.textView3);

        mLogInButton = (Button)findViewById(R.id.button);
        mLogInButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (passwordCheck(mPasswordEditText.getText().toString())) {
                    processLogInSuccess();
                } else {
                    processLogInFail();
                }
            }
        });
    }

    private boolean passwordCheck(String password) {
        if (("possword").equals(password)) {
            return true;
        } else {
            return false;
        }
    }

    private void processLogInSuccess() {
        mStatusTextView.setText("Vous êtes maintenant connecté");
        Toast.makeText(MainActivity.this, "Vous êtes maintenant connecté", Toast.LENGTH_LONG).show();
    }

    private void processLogInFail() {
        mStatusTextView.setText("Le mot de passe est différent");
        Toast.makeText(MainActivity.this, "Le mot de passe est différent", Toast.LENGTH_LONG).show();
    }
}

activity_main.xml


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.example.user.logintest.MainActivity">

    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="PASSWORD : "
             />

        <EditText
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:inputType="textPersonName"
            android:text=""
            android:ems="10"
            android:id="@+id/editText"
            android:layout_weight="1" />

    </LinearLayout>

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        >

        <Button
            android:text="S'identifier"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/button"
            android:layout_weight="1" />

        <TextView
            android:text="Pas connecté"
            android:textSize="20sp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/textView3"
            android:layout_weight="1"
            android:paddingTop="10dp"
            android:gravity="center_horizontal"/>
    </LinearLayout>

</LinearLayout>

1. Décompilez le fichier apk dans le code source au format Java d'origine

  1. Changez l'extension du fichier apk en zip et décompressez-le
  2. Convertissez classes.dex dans le dossier décompressé en 1 en jar
> <dex2jar.chemin du dossier bat>\dex2jar.bat <classes.chemin du dossier dex>\classes.dex
  1. Modifiez l'extension de la sortie classes-dex2jar.jar dans 2 pour compresser et décompresser. Convertissez le fichier de classe dans le dossier décompressé en 4.3 en un fichier java
> <chemin du dossier jad>\jad -s java -d src -r classes-dex2jar\**\*.class

La source java est sortie dans le dossier src spécifié par -d.

src\com\example\user\logintest

MainActivity.java


// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) 

package com.example.user.logintest;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.*;

public class MainActivity extends Activity
{

    public MainActivity()
    {
    }

    private boolean passwordCheck(String s)
    {
        return "possword".equals(s);
    }

    private void processLogInFail()
    {
        mStatusTextView.setText("\u30D1\u30B9\u30EF\u30FC\u30C9\u304C\u7570\u306A\u308A\u307E\u3059");
        Toast.makeText(this, "\u30D1\u30B9\u30EF\u30FC\u30C9\u304C\u7570\u306A\u308A\u307E\u3059", 1).show();
    }

    private void processLogInSuccess()
    {
        mStatusTextView.setText("\u30ED\u30B0\u30A4\u30F3\u3057\u307E\u3057\u305F");
        Toast.makeText(this, "\u30ED\u30B0\u30A4\u30F3\u3057\u307E\u3057\u305F", 1).show();
    }

    protected void onCreate(Bundle bundle)
    {
        super.onCreate(bundle);
        setContentView(0x7f04001a);
        mPasswordEditText = (EditText)findViewById(0x7f0b0055);
        mStatusTextView = (TextView)findViewById(0x7f0b0057);
        mLogInButton = (Button)findViewById(0x7f0b0056);
        mLogInButton.setOnClickListener(new android.view.View.OnClickListener() {

            public void onClick(View view)
            {
                if(passwordCheck(mPasswordEditText.getText().toString()))
                {
                    processLogInSuccess();
                    return;
                } else
                {
                    processLogInFail();
                    return;
                }
            }

            final MainActivity this$0;

            
            {
                this$0 = MainActivity.this;
                super();
            }
        }
);
    }

    private Button mLogInButton;
    private EditText mPasswordEditText;
    private TextView mStatusTextView;




}

2. Décompilez le fichier apk en code au format Smalli recompilable

> java -jar <apktoll.Le chemin du dossier où se trouve le fichier jar>/apktool.jar d <LogInTest.Le chemin du dossier où se trouve apk>/LogInTest.apk

Le fichier smali est sorti dans le dossier portant le même nom que le fichier apk.

LogInTest\smali\com\example\user\logintest

MainActivity.smali


.class public Lcom/example/user/logintest/MainActivity;
.super Landroid/app/Activity;
.source "MainActivity.java"


# instance fields
.field private mLogInButton:Landroid/widget/Button;

.field private mPasswordEditText:Landroid/widget/EditText;

.field private mStatusTextView:Landroid/widget/TextView;


# direct methods
.method public constructor <init>()V
    .locals 0

    .prologue
    .line 13
    invoke-direct {p0}, Landroid/app/Activity;-><init>()V

    return-void
.end method

.method static synthetic access$000(Lcom/example/user/logintest/MainActivity;)Landroid/widget/EditText;
    .locals 1
    .param p0, "x0"    # Lcom/example/user/logintest/MainActivity;

    .prologue
    .line 13
    iget-object v0, p0, Lcom/example/user/logintest/MainActivity;->mPasswordEditText:Landroid/widget/EditText;

    return-object v0
.end method

.method static synthetic access$100(Lcom/example/user/logintest/MainActivity;Ljava/lang/String;)Z
    .locals 1
    .param p0, "x0"    # Lcom/example/user/logintest/MainActivity;
    .param p1, "x1"    # Ljava/lang/String;

    .prologue
    .line 13
    invoke-direct {p0, p1}, Lcom/example/user/logintest/MainActivity;->passwordCheck(Ljava/lang/String;)Z

    move-result v0

    return v0
.end method

.method static synthetic access$200(Lcom/example/user/logintest/MainActivity;)V
    .locals 0
    .param p0, "x0"    # Lcom/example/user/logintest/MainActivity;

    .prologue
    .line 13
    invoke-direct {p0}, Lcom/example/user/logintest/MainActivity;->processLogInSuccess()V

    return-void
.end method

.method static synthetic access$300(Lcom/example/user/logintest/MainActivity;)V
    .locals 0
    .param p0, "x0"    # Lcom/example/user/logintest/MainActivity;

    .prologue
    .line 13
    invoke-direct {p0}, Lcom/example/user/logintest/MainActivity;->processLogInFail()V

    return-void
.end method

.method private passwordCheck(Ljava/lang/String;)Z
    .locals 1
    .param p1, "password"    # Ljava/lang/String;

    .prologue
    .line 41
    const-string v0, "possword"

    invoke-virtual {v0, p1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z

    move-result v0

    if-eqz v0, :cond_0

    .line 42
    const/4 v0, 0x1

    .line 44
    :goto_0
    return v0

    :cond_0
    const/4 v0, 0x0

    goto :goto_0
.end method

.method private processLogInFail()V
    .locals 2

    .prologue
    .line 54
    iget-object v0, p0, Lcom/example/user/logintest/MainActivity;->mStatusTextView:Landroid/widget/TextView;

    const-string v1, "\u30d1\u30b9\u30ef\u30fc\u30c9\u304c\u7570\u306a\u308a\u307e\u3059"

    invoke-virtual {v0, v1}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V

    .line 55
    const-string v0, "\u30d1\u30b9\u30ef\u30fc\u30c9\u304c\u7570\u306a\u308a\u307e\u3059"

    const/4 v1, 0x1

    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

    .line 56
    return-void
.end method

.method private processLogInSuccess()V
    .locals 2

    .prologue
    .line 49
    iget-object v0, p0, Lcom/example/user/logintest/MainActivity;->mStatusTextView:Landroid/widget/TextView;

    const-string v1, "\u30ed\u30b0\u30a4\u30f3\u3057\u307e\u3057\u305f"

    invoke-virtual {v0, v1}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V

    .line 50
    const-string v0, "\u30ed\u30b0\u30a4\u30f3\u3057\u307e\u3057\u305f"

    const/4 v1, 0x1

    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

    .line 51
    return-void
.end method


# virtual methods
.method protected onCreate(Landroid/os/Bundle;)V
    .locals 2
    .param p1, "savedInstanceState"    # Landroid/os/Bundle;

    .prologue
    .line 21
    invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V

    .line 22
    const v0, 0x7f04001a

    invoke-virtual {p0, v0}, Lcom/example/user/logintest/MainActivity;->setContentView(I)V

    .line 24
    const v0, 0x7f0b0055

    invoke-virtual {p0, v0}, Lcom/example/user/logintest/MainActivity;->findViewById(I)Landroid/view/View;

    move-result-object v0

    check-cast v0, Landroid/widget/EditText;

    iput-object v0, p0, Lcom/example/user/logintest/MainActivity;->mPasswordEditText:Landroid/widget/EditText;

    .line 25
    const v0, 0x7f0b0057

    invoke-virtual {p0, v0}, Lcom/example/user/logintest/MainActivity;->findViewById(I)Landroid/view/View;

    move-result-object v0

    check-cast v0, Landroid/widget/TextView;

    iput-object v0, p0, Lcom/example/user/logintest/MainActivity;->mStatusTextView:Landroid/widget/TextView;

    .line 27
    const v0, 0x7f0b0056

    invoke-virtual {p0, v0}, Lcom/example/user/logintest/MainActivity;->findViewById(I)Landroid/view/View;

    move-result-object v0

    check-cast v0, Landroid/widget/Button;

    iput-object v0, p0, Lcom/example/user/logintest/MainActivity;->mLogInButton:Landroid/widget/Button;

    .line 28
    iget-object v0, p0, Lcom/example/user/logintest/MainActivity;->mLogInButton:Landroid/widget/Button;

    new-instance v1, Lcom/example/user/logintest/MainActivity$1;

    invoke-direct {v1, p0}, Lcom/example/user/logintest/MainActivity$1;-><init>(Lcom/example/user/logintest/MainActivity;)V

    invoke-virtual {v0, v1}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V

    .line 38
    return-void
.end method

MainActivity$1.smali


.class Lcom/example/user/logintest/MainActivity$1;
.super Ljava/lang/Object;
.source "MainActivity.java"

# interfaces
.implements Landroid/view/View$OnClickListener;


# annotations
.annotation system Ldalvik/annotation/EnclosingMethod;
    value = Lcom/example/user/logintest/MainActivity;->onCreate(Landroid/os/Bundle;)V
.end annotation

.annotation system Ldalvik/annotation/InnerClass;
    accessFlags = 0x0
    name = null
.end annotation


# instance fields
.field final synthetic this$0:Lcom/example/user/logintest/MainActivity;


# direct methods
.method constructor <init>(Lcom/example/user/logintest/MainActivity;)V
    .locals 0
    .param p1, "this$0"    # Lcom/example/user/logintest/MainActivity;

    .prologue
    .line 28
    iput-object p1, p0, Lcom/example/user/logintest/MainActivity$1;->this$0:Lcom/example/user/logintest/MainActivity;

    invoke-direct {p0}, Ljava/lang/Object;-><init>()V

    return-void
.end method


# virtual methods
.method public onClick(Landroid/view/View;)V
    .locals 2
    .param p1, "view"    # Landroid/view/View;

    .prologue
    .line 31
    iget-object v0, p0, Lcom/example/user/logintest/MainActivity$1;->this$0:Lcom/example/user/logintest/MainActivity;

    iget-object v1, p0, Lcom/example/user/logintest/MainActivity$1;->this$0:Lcom/example/user/logintest/MainActivity;

    # getter for: Lcom/example/user/logintest/MainActivity;->mPasswordEditText:Landroid/widget/EditText;
    invoke-static {v1}, Lcom/example/user/logintest/MainActivity;->access$000(Lcom/example/user/logintest/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;

    move-result-object v1

    # invokes: Lcom/example/user/logintest/MainActivity;->passwordCheck(Ljava/lang/String;)Z
    invoke-static {v0, v1}, Lcom/example/user/logintest/MainActivity;->access$100(Lcom/example/user/logintest/MainActivity;Ljava/lang/String;)Z

    move-result v0

    if-eqz v0, :cond_0

    .line 32
    iget-object v0, p0, Lcom/example/user/logintest/MainActivity$1;->this$0:Lcom/example/user/logintest/MainActivity;

    # invokes: Lcom/example/user/logintest/MainActivity;->processLogInSuccess()V
    invoke-static {v0}, Lcom/example/user/logintest/MainActivity;->access$200(Lcom/example/user/logintest/MainActivity;)V

    .line 36
    :goto_0
    return-void

    .line 34
    :cond_0
    iget-object v0, p0, Lcom/example/user/logintest/MainActivity$1;->this$0:Lcom/example/user/logintest/MainActivity;

    # invokes: Lcom/example/user/logintest/MainActivity;->processLogInFail()V
    invoke-static {v0}, Lcom/example/user/logintest/MainActivity;->access$300(Lcom/example/user/logintest/MainActivity;)V

    goto :goto_0
.end method

3. Modifiez le code Smalli décompilé et recompilez

modification du fichier smali

Activité principale

                if (passwordCheck(mPasswordEditText.getText().toString())) {
                    processLogInSuccess();
                } else {
                    processLogInFail();
                }

Parce qu'il vérifie et traite lorsque la connexion réussit ou échoue En éliminant le traitement de jugement if, il sera corrigé pour passer à la voie du traitement réussi.

Si vous suivez la source smali, vous verrez ce qui suit de MainActivity $ 1.smali On a l'impression que c'est un processus de jugement.

    # invokes: Lcom/example/user/logintest/MainActivity;->passwordCheck(Ljava/lang/String;)Z
    ##Exécuter le mot de passe
    invoke-static {v0, v1}, Lcom/example/user/logintest/MainActivity;->access$100(Lcom/example/user/logintest/MainActivity;Ljava/lang/String;)Z

    ##Enregistrer le mot de passeVérifier la valeur de retour dans la v0
    move-result v0

    ##Si la valeur de retour de passwordCheck est 0, cond_0(Traitement en échec)Quoi
    if-eqz v0, :cond_0

    ##Traitement au moment du succès
    .line 32
    iget-object v0, p0, Lcom/example/user/logintest/MainActivity$1;->this$0:Lcom/example/user/logintest/MainActivity;

    # invokes: Lcom/example/user/logintest/MainActivity;->processLogInSuccess()V
    ##Exécutez processLogInSuccess
    invoke-static {v0}, Lcom/example/user/logintest/MainActivity;->access$200(Lcom/example/user/logintest/MainActivity;)V

    .line 36
    ##revenir
    :goto_0
    return-void

    .line 34
    :cond_0
    ##Traitement au moment de l'échec
    iget-object v0, p0, Lcom/example/user/logintest/MainActivity$1;->this$0:Lcom/example/user/logintest/MainActivity;

    # invokes: Lcom/example/user/logintest/MainActivity;->processLogInFail()V
    ##Processus au moment du processusLogInFail
    invoke-static {v0}, Lcom/example/user/logintest/MainActivity;->access$300(Lcom/example/user/logintest/MainActivity;)V

    ##revenir
    goto :goto_0

If-eqz est le processus de jugement, et le processus au moment du succès continue directement sous lui, alors commentez le processus de jugement.

    invoke-static {v0, v1}, Lcom/example/user/logintest/MainActivity;->access$100(Lcom/example/user/logintest/MainActivity;Ljava/lang/String;)Z

    ##Enregistrer le mot de passeVérifier la valeur de retour dans la v0
    move-result v0

    ##Si la valeur de retour de passwordCheck est 0, cond_0(Traitement en échec)Quoi
-    if-eqz v0, :cond_0
+    ## if-eqz v0, :cond_0

    ##Traitement au moment du succès
    .line 32
    iget-object v0, p0, Lcom/example/user/logintest/MainActivity$1;->this$0:Lcom/example/user/logintest/MainActivity;

recompiler vers smali ⇒ apk

>java -jar <apktools.Le chemin du dossier où se trouve le fichier jar>\apktool.jar b .\LogInTest -o .\LogInTestCustom.apk

Signature

> keytool -genkeypair -alias androiddebugkey -keypass android -keyalg RSA -keysize 2048 -sigalg SHA256withRSA -validity 10950 -dname "CN=Android Debug,O=Android,C=US" -keystore debug.keystore -storepass android
> jarsigner -verbose -sigalg SHA256withRSA -digestalg SHA1 -tsa http://timestamp.digicert.com -keystore debug.keystore -storepass android LogInTestCustom.apk androiddebugkey

Installation

>adb install -r LogInTestCustom1.apk

Contrôle de fonctionnement

Screenshot_20170701-201202.png

Recommended Posts

Décompilation de l'application Android ⇒ correction ⇒ recompilation
Application météo Android
Analyseur de spectre d'application Android
À propos des composants de l'application Android
Lancement du développement personnel de l'application Android
Développement d'applications ROS sur Android
Créez une application Android. (Jour 5)
Importer des images d'appareils avec l'application Android
Créez une application Android. (Premier jour)
Remarques sur l'appel du programme d'installation sur l'application Android
J'ai créé une application correspondante (application Android)
[Android] J'ai créé une application de podomètre.