ANDROID] Smali

노션으로 옮김·2020년 4월 10일
1

Study

목록 보기
14/33
post-thumbnail

Smali

먼저 안드로이드 아키텍처 구조에 대해 이해해야 한다.

가장 하위에 리눅스 커널이 있고, 그 위에 달빅 가상머신이 있는데 이 달빅 가상머신이 dex 포맷의 바이트코드를 해석하여 안드로이드 어플리케이션을 실행하게 된다.

이 때의 dex 바이트 코드를 사람이 읽을 수 있도록 변환한 것이 바로 Smali이다.(≒어셈블리 언어)

특징

smali 코드를 얻기 위해서는 dex 바이트코드를 baksmali시켜야 하는데, 간단히 apk 파일을 apktool을 이용해 디컴파일시키는 것으로 smali를 확인할 수 있다.

#apktool d test.apk

또한, 이렇게 얻은 smali 코드를 수정하여 apktool로 recompile시켜 apk를 생성할 수 있다.

#apktool b test.apk

참고로 윈도우에서는 버그로 인한 에러가 발생하여 리눅스 환경에서 컴파일해야 한다.

https://github.com/iBotPeaches/Apktool/issues/1623
: 윈도우 apktool 버그
https://ibotpeaches.github.io/Apktool/install/
: 리눅스 apktool 설치

문법

TGHACK2020의 리버싱 문제인 apk파일의 일부를 보면서 몇 가지 문법을 익혀보겠다.

java

this.waves = 1;
...
...
...
      if (this.waves == 1000)
      {

waves라는 변수가 1000인지를 검사하는 if문이다.

smali

    .line 265
    iget p1, p0, Lno/tghack/gaiainvaders/GaiaInvadersView;->waves:I

    const/16 v0, 0x3e8

    if-ne p1, v0, :cond_f

iget 명령으로 waves 변수 값이 p1에 저장되고
const 명령으로 v00x3e8이 저장되며
if-ne가 이 두 가지를 비교하게 된다.
같지 않을 경우 cond_f로 분기한다.

conf_f

 :cond_f
    iget-wide v2, p0, Lno/tghack/gaiainvaders/GaiaInvadersView;->magic:J
    iget p1, p0, Lno/tghack/gaiainvaders/GaiaInvadersView;->waves:I

이제 waves0x3e8이라고 가정하고 if문 안에서 중요한 코드를 살펴보겠다.

java

this.magic = 4919L;
...
...
...
localObject1 = EncryptionKt.decrypt("M6GzLMKMB7TO7qCwYIE6tWjstepv0Fa6B3yyCrRtFbNRb2+VVVCqDuDO6UWY14LEu9Ac3A2sVaKG4Thk1s1j0g==", (Number)Long.valueOf(this.magic), "ClcYYh9brZTGyTFG4kge7w==");
        this.canvas.drawText("Congrats!!!", f1, f2, this.paint);
        this.paint.setTextSize(40.0F);
        this.canvas.drawText(String.valueOf(localObject1), f1, f2 + 100, this.paint);
        getHolder().unlockCanvasAndPost(this.canvas);
        pause();

어떤 암호화된 값을 decrypt한 뒤에 "Contrats!!!"라는 문자열을 출력해주고 pause()를 실행한다.

smali

    iget-wide v6, p0, Lno/tghack/gaiainvaders/GaiaInvadersView;->magic:J

    invoke-static {v6, v7}, Ljava/lang/Long;->valueOf(J)Ljava/lang/Long;

    move-result-object v0

    check-cast v0, Ljava/lang/Number;

magic의 변수값 가져와서 invoke-static에서 valueOf() 메서드를 호출할 때 인자로 전달한다.

결과값을 v0에 가져오고 캐스팅 한다.

    const-string v3, "M6GzLMKMB7TO7qCwYIE6tWjstepv0Fa6B3yyCrRtFbNRb2+VVVCqDuDO6UWY14LEu9Ac3A2sVaKG4Thk1s1j0g=="

    const-string v6, "ClcYYh9brZTGyTFG4kge7w=="

    invoke-static {v3, v0, v6}, Lno/tghack/gaiainvaders/EncryptionKt;->decrypt(Ljava/lang/String;Ljava/lang/Number;Ljava/lang/String;)Ljava/lang/String;

    move-result-object v0

decrypt를 호출하는 부분이다. 결과값이 v0에 저장된다.

    .line 284
    iget-object v3, p0, Lno/tghack/gaiainvaders/GaiaInvadersView;->canvas:Landroid/graphics/Canvas;

    iget-object v6, p0, Lno/tghack/gaiainvaders/GaiaInvadersView;->paint:Landroid/graphics/Paint;

    const-string v7, "Congrats!!!"

    invoke-virtual {v3, v7, p1, v2, v6}, Landroid/graphics/Canvas;->drawText(Ljava/lang/String;FFLandroid/graphics/Paint;)V

drawText()는 인자로 넘어온 문자열('Contrats')을 화면에 출력해준다.

    iget-object v6, p0, Lno/tghack/gaiainvaders/GaiaInvadersView;->paint:Landroid/graphics/Paint;

    invoke-virtual {v3, v0, p1, v2, v6}, Landroid/graphics/Canvas;->drawText(Ljava/lang/String;FFLandroid/graphics/Paint;)V

v0은 아까 decrypt에서 복호화한 플래그 값이었다.
이것을 출력해준다.

    iget-object v0, p0, Lno/tghack/gaiainvaders/GaiaInvadersView;->canvas:Landroid/graphics/Canvas;

    invoke-interface {p1, v0}, Landroid/view/SurfaceHolder;->unlockCanvasAndPost(Landroid/graphics/Canvas;)V

    .line 289
    invoke-virtual {p0}, Lno/tghack/gaiainvaders/GaiaInvadersView;->pause()V

마지막으로 pause()를 호출하며 if문이 끝난다.
unlockCanvasAndPost() 역시 화면에 출력하는 라이브러리 함수이며 일련의 출력을 위한 과정이라고 이해하고 넘어가면 된다.


참조

https://stackoverrun.com/ko/q/8485879
: smali에 대한 이해

https://github.com/JesusFreke/smali/wiki
: smali github wiki

https://source.android.com/devices/tech/dalvik/dalvik-bytecode
: invoke-XXX에 대한 문법

http://www.matcl.com/tip/1137973
: if문

0개의 댓글