Smali - Decompiling/[Modifying]/Compiling

Reading time: 8 minutes

tip

AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE) Azure 해킹 배우기 및 연습하기: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기

때로는 애플리케이션 코드를 수정하여 숨겨진 정보를 얻는 것이 흥미로울 수 있습니다(예: 잘 난독화된 비밀번호나 플래그). 그런 경우 apk를 decompile하고 코드를 modify한 뒤 recompile하는 것이 유용할 수 있습니다.

Opcodes reference: http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html

빠른 방법

Visual Studio CodeAPKLab 확장(extension)을 사용하면 명령을 실행하지 않고도 애플리케이션을 automatically decompile, modify, recompile, sign & install할 수 있습니다.

또 다른 이 작업을 크게 편리하게 해주는 scripthttps://github.com/ax/apk.sh입니다.

Decompile the APK

APKTool을 사용하면 smali code and resources에 접근할 수 있습니다:

bash
apktool d APP.apk

If apktool gives you any error, installing the latest version을 시도해보세요

Some interesting files you should look are:

  • res/values/strings.xml (및 res/values/* 내부의 모든 xml 파일)
  • AndroidManifest.xml
  • Any file with extension .sqlite or .db

If apktool has problems decoding the application take a look to https://ibotpeaches.github.io/Apktool/documentation/#framework-files or try using the argument -r (Do not decode resources). Then, if the problem was in a resource and not in the source code, you won't have the problem (you won't also decompile the resources).

Change smali code

명령을 변경하거나 일부 변수의 값을 바꾸거나 새 명령을 추가할 수 있습니다. 저는 Smali 코드를 VS Code에서 편집합니다. 그 후 smalise extension을 설치하면 에디터가 잘못된 instruction이 있는지 알려줍니다.
Some examples can be found here:

Or you can check below some Smali changes explained.

Recompile the APK

코드를 수정한 후 다음 명령으로 APK를 다시 컴파일할 수 있습니다:

bash
apktool b . #In the folder generated when you decompiled the application

새 APK는 dist 폴더 내부에서 컴파일됩니다.

만약 apktool오류를 발생시키면, installing the latest version을 시도해보세요

새 APK에 서명하기

그런 다음, 키를 생성해야 합니다 (비밀번호와 무작위로 입력해도 되는 몇 가지 정보를 요구합니다):

bash
keytool -genkey -v -keystore key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias <your-alias>

마지막으로 새 APK에 서명하세요:

bash
jarsigner -keystore key.jks path/to/dist/* <your-alias>

새 애플리케이션 최적화

zipalign은 Android 애플리케이션(APK) 파일에 중요한 최적화를 제공하는 아카이브 정렬 도구입니다. More information here.

bash
zipalign [-f] [-v] <alignment> infile.apk outfile.apk
zipalign -v 4 infile.apk

새 APK에 서명 (다시?)

jarsigner 대신 apksigner선호한다면, zipalign으로 최적화를 적용한 후 APK에 서명해야 합니다. 하지만 주의: 애플리케이션은 jarsigner(이전에 zipalign)으로 또는 apksigner(이후에 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

Smali 명령어 집합은 here에서 확인할 수 있습니다.

가벼운 변경

함수 내부 변수의 초기값 수정

몇몇 변수들은 함수 시작 부분에서 opcode _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

더 큰 변경사항

Logging

bash
#Log win: <number>
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: <num>"

권장 사항:

  • 만약 함수 내부에서 선언된 변수를 사용할 예정이라면(선언된 v0,v1,v2...) 이 줄들을 _.local _과 변수 선언들(const v0, 0x1) 사이에 넣으세요
  • 함수 코드의 중간에 logging 코드를 넣고 싶다면:
    • 선언된 변수 수에 2를 더하세요: 예: _.locals 10_에서 .locals 12
    • 새 변수들은 이미 선언된 변수의 다음 번호여야 합니다(이 예제에서는 _v10_과 _v11_이어야 합니다, v0부터 시작한다는 것을 기억하세요).
    • logging 함수의 코드를 변경하여 _v10_과 _v11_을 _v5_와 v1 대신 사용하세요.

토스트 표시

함수 시작 부분의 .locals 수에 3을 더해야 합니다.

이 코드는 함수의 중간에 삽입되도록 준비되어 있습니다 (필요에 따라 변수의 수를 변경하세요). 이 코드는 this.o의 값을 가져와 String으로 변환한 다음 해당 값으로 toast를 생성합니다.

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

시작 시 네이티브 라이브러리 로드 (System.loadLibrary)

때때로 다른 JNI 라이브러리보다 먼저 초기화되도록 네이티브 라이브러리를 사전 로드해야 할 때가 있습니다 (예: 프로세스 로컬 텔레메트리/로깅을 활성화하기 위해). 정적 초기화자나 Application.onCreate() 초기에 System.loadLibrary() 호출을 주입할 수 있습니다. 정적 클래스 초기화자 ()에 대한 smali 예:

smali
.class public Lcom/example/App;
.super Landroid/app/Application;

.method static constructor <clinit>()V
.registers 1
const-string v0, "sotap"         # library name without lib...so prefix
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
return-void
.end method

또는 동일한 두 지시문을 Application.onCreate()의 시작 부분에 배치하여 라이브러리가 가능한 한 빨리 로드되도록 하세요:

smali
.method public onCreate()V
.locals 1

const-string v0, "sotap"
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V

invoke-super {p0}, Landroid/app/Application;->onCreate()V
return-void
.end method

참고:

  • 라이브러리의 올바른 ABI 변종이 lib// (예: arm64-v8a/armeabi-v7a) 아래에 존재하는지 확인하여 UnsatisfiedLinkError를 방지하세요.
  • 매우 초기에 로드하면 (class static initializer) native logger가 이후 JNI activity를 관찰할 수 있습니다.

참고 자료

tip

AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE) Azure 해킹 배우기 및 연습하기: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기