본문 바로가기

[안드로이드] 어플리케이션 디컴파일 및 리컴파일하는 방법

by rudals.kim 2020. 12. 20. 댓글 개
반응형

인터넷을 검색하다가 보니 안드로이드 앱이 디컴파일 및 리컴파일이 된다는 게시글을 보고 한번 해 보기로 했습니다.

( 참고한 사이트 : http://forum.xda-developers.com/showthread.php?t=2195680 )

 

위 사이트에서 필요한 툴을 받아서 압축을 해제합니다.

원본 apktool은 http://ibotpeaches.github.io/Apktool 에서 받을 수 있습니다.

 

우선 androidstudio에서 디버깅시 많이 사용하는 Log API를 사용하여 2개의 로그를 찍는 간단한 안드로이드용 어플리케이션을 아래와 같이 코딩하였습니다.

APK를 생성하면 app-release.apk가 생성되는데 위의 압축을 푼 디렉토리로 copy해 넣습니다.

 

"apktool d app-release.apk" 명령어로 decompile을 합니다.

해당 디렉토리내의 app-release\smali\com\example\logcat\MainActivity.smail 파일을 열어 보면 아래와 같습니다.

아랫 부분의 OnCreate를 보시면 윗 그림에서 Log.e로 출력되는 2개의 부분을 찾을 수 있습니다.

.class public Lcom/example/logcat/MainActivity;
.super Landroidx/appcompat/app/AppCompatActivity;
.source "MainActivity.java"


# instance fields
.field TAG:Ljava/lang/String;


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

    .line 8
    invoke-direct {p0}, Landroidx/appcompat/app/AppCompatActivity;-><init>()V

    const-string v0, "rudalskim.log"

    .line 9
    iput-object v0, p0, Lcom/example/logcat/MainActivity;->TAG:Ljava/lang/String;

    return-void
.end method


# virtual methods
.method protected onCreate(Landroid/os/Bundle;)V
    .locals 2

    .line 13
    invoke-super {p0, p1}, Landroidx/appcompat/app/AppCompatActivity;->onCreate(Landroid/os/Bundle;)V

    const p1, 0x7f0a001c

    .line 14
    invoke-virtual {p0, p1}, Lcom/example/logcat/MainActivity;->setContentView(I)V

    .line 16
    iget-object p1, p0, Lcom/example/logcat/MainActivity;->TAG:Ljava/lang/String;

    const-string v0, "Hello World"

    invoke-static {p1, v0}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I

    .line 18
    iget-object p1, p0, Lcom/example/logcat/MainActivity;->TAG:Ljava/lang/String;

    new-instance v0, Ljava/lang/StringBuilder;

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

    const-string v1, "id="

    invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    const/16 v1, 0x4d2  <-- 1234의 HEX값

    invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;

    invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

    move-result-object v0

    invoke-static {p1, v0}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I

    return-void
.end method

 

또한 이렇게 디컴파일된 소스는 아래와 같이 리컴파일도 가능합니다.

to recompile :

  apktool b app-release

 

to sign :

  java -jar SignApk.jar testkey.x509.pem testkey.pk8 .\app-release\dist\app-release.apk app-release_signed.apk

 

SignApk는 github.com/techexpertize/SignApk를 참고하시기 바랍니다.

 

to zipalign :

  zipalign -fv 4 app-release_signed.apk logcatTestapp-release_signed_zipaligned.apk

 

위의 apktool은 smali 코드를 보여주는데 반하여 JD-GUI(http://jd.benow.ca/)라는 디컴파일러가 있는데, 이 툴은 한 걸음 더 나가 가능한 범위내에서 원본 소스코드를 재구성해서 보여 줍니다. 그러나 아쉽게도 JD-GUI가 더 이상 업데이트가 안되는데다가 오래된 버전이라 최신버전의 apk를 디컴파일하면 코드가 제대로 디컴파일이 안됩니다. 

 

다른분이 JADX(github.com/skylot/jadx)라는 것으로 업그레이드 하였는데, 확실히 더 편리합니다.

기존 JD-GUI는 APK파일의 압축을 해제 후 dex2jar로 jar을 불러와야 했는데, JADX는 APK파일을 지원합니다.

압축 해제 없이 APK파일을 불러오면 자동으로 압축해제 후 디컴파일까지 해 줘서 편리합니다.

이 게시글의 맨 윗쪽 그림의 제가 작성한 원본 소스코드와 위 디컴파일러를 거친 후 재구성된 소스코드를 비교하면 거의 원본 소스코드에 가깝게 코드를 재구성 해 주는것을 볼 수 있습니다.

 

따라서 소스코드를 분석할 때에는 JADX를 사용해서 분석을 하고, 수정은 smali코드를 직접 수정 후 리컴파일을하여 적용하시면 패치된 APK를 사용할 수 있습니다.

반응형

댓글