# Smali - デコンパイル/[修正]/コンパイル {{#include ../../banners/hacktricks-training.md}} 時には、隠された情報(おそらくよく難読化されたパスワードやフラグ)にアクセスするためにアプリケーションコードを修正することが興味深い場合があります。そのため、apkをデコンパイルし、コードを修正して再コンパイルすることが興味深いかもしれません。 **オペコードリファレンス:** [http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html](http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html) ## 簡単な方法 **Visual Studio Code**と[APKLab](https://github.com/APKLab/APKLab)拡張機能を使用すると、コマンドを実行することなく、アプリケーションを**自動的にデコンパイル**、修正、**再コンパイル**、署名&インストールできます。 この作業を大いに簡素化する**スクリプト**は[**https://github.com/ax/apk.sh**](https://github.com/ax/apk.sh)です。 ## APKをデコンパイルする APKToolを使用すると、**smaliコードとリソース**にアクセスできます: ```bash apktool d APP.apk ``` もし**apktool**がエラーを出した場合は、[**最新バージョン**](https://ibotpeaches.github.io/Apktool/install/)をインストールしてみてください。 あなたが見るべき**興味深いファイルは**次の通りです: - _res/values/strings.xml_(およびres/values/\*内のすべてのxml) - _AndroidManifest.xml_ - 拡張子が_.sqlite_または_.db_のファイル もし`apktool`が**アプリケーションのデコードに問題がある**場合は、[https://ibotpeaches.github.io/Apktool/documentation/#framework-files](https://ibotpeaches.github.io/Apktool/documentation/#framework-files)を確認するか、**`-r`**(リソースをデコードしない)という引数を使用してみてください。その後、問題がリソースにあり、ソースコードにない場合は、問題が発生しません(リソースもデコンパイルされません)。 ## Smaliコードの変更 あなたは**命令を変更**したり、いくつかの変数の**値を変更**したり、新しい命令を**追加**することができます。私は[**VS Code**](https://code.visualstudio.com)を使用してSmaliコードを変更します。その後、**smalise拡張機能**をインストールすると、エディタが**命令が不正確である**かどうかを教えてくれます。\ いくつかの**例**はここにあります: - [Smali変更の例](smali-changes.md) - [Google CTF 2018 - Shall We Play a Game?](google-ctf-2018-shall-we-play-a-game.md) または、[**以下のSmali変更の説明を確認することができます**](smali-changes.md#modifying-smali)。 ## APKの再コンパイル コードを修正した後、次のコマンドを使用して**再コンパイル**できます: ```bash apktool b . #In the folder generated when you decompiled the application ``` 新しいAPKは_**dist**_フォルダーの**内部**で**コンパイル**されます。 もし**apktool**が**エラー**を投げた場合は、[**最新バージョン**をインストール](https://ibotpeaches.github.io/Apktool/install/)してみてください。 ### **新しいAPKに署名する** 次に、**キーを生成**する必要があります(パスワードといくつかの情報をランダムに入力するよう求められます): ```bash keytool -genkey -v -keystore key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias ``` 最後に、新しいAPKに**署名**します: ```bash jarsigner -keystore key.jks path/to/dist/* ``` ### 新しいアプリケーションの最適化 **zipalign** は、Android アプリケーション (APK) ファイルに重要な最適化を提供するアーカイブ整列ツールです。[More information here](https://developer.android.com/studio/command-line/zipalign). ```bash zipalign [-f] [-v] infile.apk outfile.apk zipalign -v 4 infile.apk ``` ### **新しいAPKに署名する(再度?)** もしあなたが**apksigner**を使用することを**好む**場合、**最適化を適用した後にapkに署名する必要があります**。ただし、**アプリケーションには一度だけ署名する必要があることに注意してください**。jarsigner(zipalignの前)またはaspsigner(zipalignの後)で署名してください。 ```bash apksigner sign --ks key.jks ./dist/mycompiled.apk ``` ## Smaliの変更 次のHello World Javaコードについて: ```java public static void printHelloWorld() { System.out.println("Hello World") } ``` Smaliコードは次のようになります: ```java .method public static printHelloWorld()V .registers 2 sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream; const-string v1, "Hello World" invoke-virtual {v0,v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V return-void .end method ``` The Smali instruction set is available [here](https://source.android.com/devices/tech/dalvik/dalvik-bytecode#instructions). ### Light Changes ### 関数内の変数の初期値を変更する いくつかの変数は、オペコード _const_ を使用して関数の最初に定義されており、その値を変更することができます。または、新しい値を定義することもできます: ```bash #Number const v9, 0xf4240 const/4 v8, 0x1 #Strings const-string v5, "wins" ``` ### 基本操作 ```bash #Math add-int/lit8 v0, v2, 0x1 #v2 + 0x1 and save it in v0 mul-int v0,v2,0x2 #v2*0x2 and save in v0 #Move the value of one object into another move v1,v2 #Condtions if-ge #Greater or equals if-le #Less or equals if-eq #Equals #Get/Save attributes of an object iget v0, p0, Lcom/google/ctf/shallweplayagame/GameActivity;->o:I #Save this.o inside v0 iput v0, p0, Lcom/google/ctf/shallweplayagame/GameActivity;->o:I #Save v0 inside this.o #goto :goto_6 #Declare this where you want to start a loop if-ne v0, v9, :goto_6 #If not equals, go to: :goto_6 goto :goto_6 #Always go to: :goto_6 ``` ### より大きな変更 ### ロギング ```bash #Log win: iget v5, p0, Lcom/google/ctf/shallweplayagame/GameActivity;->o:I #Get this.o inside v5 invoke-static {v5}, Ljava/lang/String;->valueOf(I)Ljava/lang/String; #Transform number to String move-result-object v1 #Move to v1 const-string v5, "wins" #Save "win" inside v5 invoke-static {v5, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I #Logging "Wins: " ``` 推奨事項: - 関数内で宣言された変数(v0、v1、v2...)を使用する場合は、これらの行を _.local \_ と変数の宣言 (_const v0, 0x1_) の間に置いてください。 - 関数のコードの中間にログ記録コードを挿入したい場合: - 宣言された変数の数に2を加えます:例:_.locals 10_ から _.locals 12_ へ - 新しい変数は、すでに宣言された変数の次の番号である必要があります(この例では _v10_ と _v11_ で、v0から始まることを忘れないでください)。 - ログ記録関数のコードを変更し、_v5_ と _v1_ の代わりに _v10_ と _v11_ を使用します。 ### トースティング 関数の最初に _.locals_ の数に3を加えることを忘れないでください。 このコードは **関数の中間に挿入する** ために準備されています(**必要に応じて** **変数** の **番号** を変更してください)。これは **this.o** の **値** を取得し、**String** に **変換** し、その値で **トースト** を **作成** します。 ```bash const/4 v10, 0x1 const/4 v11, 0x1 const/4 v12, 0x1 iget v10, p0, Lcom/google/ctf/shallweplayagame/GameActivity;->o:I invoke-static {v10}, Ljava/lang/String;->valueOf(I)Ljava/lang/String; move-result-object v11 invoke-static {p0, v11, v12}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast; move-result-object v12 invoke-virtual {v12}, Landroid/widget/Toast;->show()V ``` {{#include ../../banners/hacktricks-training.md}}