관리 메뉴

JHLBLUE

안드로이드 smali 패치하기4 본문

Android

안드로이드 smali 패치하기4

JHLBLUE 2019. 2. 8. 15:14

버튼을 클릭하고 점수를 획득하여 2만점 이상을 획득해야 승리하는 ButtonClicker 앱이며, 실행화면은 아래와 같다.


  



apktool 도구로 디컴파일한 뒤 smali 코드들을 보면 MainActivity$1.smali 등과 같이 MainActivity와 관련된 smali 코드 파일이 여러개가 있는 것을 확인할 수 있다.



이 프로젝트의 경우에는 MainActivity 클래스 내부에서 Inner Class를 사용하고 있기 때문에 Inner Class 코드 부분은 $1, $2. $6$1 등과 같이 별도의 smali 파일로 분리하여 확인할 수 있다.


MainActivity$1.smali 파일을 열어보면 .line 51에서 시작하는 것을 볼 수 있으며, MainActivity.java의 51번째 줄을 확인하면 Handler 객체를 Inner Class로 생성하는 것을 확인할 수 있다.




다음은 게임을 플레이한 뒤 나오는 토스트 메시지를 확인하여 게임에서 승리하기 위한 목표점수가 2만점인 것을 확인하고, 토스트 메시지를 출력하는 부분의 코드를 살펴본다. Toast 관련 코드는 MainActivity.smali 파일 내부에서만 사용하기 때문에 MainActivity.smali 파일을 열어본다.



이전에 "smali 코드 패치로 토스트 메시지 출력하기"를 보면 Toast로 출력하기 위한 String 값은 임의의 레지스터에 고정된 값을 저장한 뒤 이를 사용하는 방식이였지만, 이번에는 getString() 함수를 사용하여 문자열을 불러온 뒤 사용하는 것을 확인할 수 있다.


java에서 getString() 함수는 아래와 같이 사용하며, getString() 함수에 입력하는 인자인 resID는 res\values\strings.xml 파일 내부의 string 리소스 아이디를 참고한다.



하지만 위에서 getString() 함수에 사용하는 값은 "string_id"와 같은 문자열 형태의 값이 아닌 "0x7f0b0023"과 같은 hex 값이며, 이 값에 대한 정보는 디컴파일한 smali 코드 중 R$String.smali 파일에서 확인이 가능하다.


따라서 위의 line153에서 출력하는 토스트 메시지는 0x7f0b0024라는 hex 값을 사용하며, 이는 message_success라는 Resource ID의 값이므로, line153의 코드가 항상 동작하도록 패치해야 한다.


Toast 코드가 포함된, line 152부터 시작되는 checkScore() 함수의 처음 부분을 보면 score라는 이름의 변수를 사용하는 것과 0x4e20 값을 저장하는 것, 그리고 if-le 코드를 사용하는 것을 볼 수 있다.



MainActivity;->score:I는 MainActivity.smali 상단의 .field 부분에서 확인이 가능하며, .field 부분은 자바의 클래스에 정의된 변수를 의미한다.

iget은 iget A, B, C (A : 레지스터, B : 객체 레지스터, C : 인스턴스 필드) 으로 사용하며, B의 인스턴스 필드 C를 가져와서 A 레지스터에 저장한다는 뜻이다.

즉, iget v0, p0, ..../MainActivity;->score:I는 p0(this)의 score 변수의 값을 v0 레지스터에 저장한다는 뜻이며, 이를 아래와 같이 자바코드로 비슷하게 표현이 가능하다.


다음 v2에 저장된 0x4e20은 10진수로 20000을 뜻하기 때문에 게임에 승리하기 위한 기준 점수임을 확인할 수 있으며, 이 값을 적절한 값으로 수정하여 게임을 승리할 수 있을 것으로 추측할 수 있다.


if-le는 if-eq, if-ne, if-lt, if-ge 등의 if-test 코드 종류 중 하나이고, if A, B, C (A, B : 레지스터, C : 분기 오프셋)으로 사용하며, A와 B를 비교하여 명령에 따라서 C로 점프한다는 뜻이다.

if-test의 내용은 아래와 같다.

 if-test 종류

 설명

 if-eq 

 A와 B가 같을 경우 C로 점프한다

 if-ne 

 A와 B가 같지 않을 경우 C로 점프한다

 if-lt

 A가 B보다 작을 경우 C로 점프한다

 if-ge 

 A가 B보다 크거나 같을 경우 C로 점프한다

 if-gt

 A가 B보다 클 경우 C로 점프한다

 if-le 

 A가 B보다 작거나 같을 경우 C로 점프한다


즉, if-le v0, v2, :cond_0은 v0과 v2 레지스터 값을 비교하여 v0의 값이 작거나 같을 경우 cond_0으로 이동한다는 뜻이며, cond_0은 message_failure 메시지를 출력하는 부분이다.


위의 0x4e20 부분을 수정하지 않았다면 if-le를 if-gt나 if-ge 등의 표현식으로 수정하여 반대의 결과를 나타낼 수 있도록 하는 방법도 게임을 승리하는 방법이다.


원본 안드로이드 스튜디오 프로젝트 파일

ButtonClicker.zip


실습 앱

ButtonClicker.apk

Comments