Description
Category: Reversing
Source: HDCON 2017 Quals.(Febuary)
Points: 100
Author: Jisoon Park(js00n.park)
Description:
가위바위보에 연속적으로 이겨서 플래그를 획득하시오
Write-up
apk 파일이 주어진 것으로 보아, android 리버싱 문제이다. 코드 분석에 앞서, Android 기기에 파일을 올려서 동작을 확인해 본다.
![](https://github.com/JisoonPark/writeup/raw/master//rock/run.png)
가위바위보를 하는 단순한 게임인데, Gole Score(Goal Score의 오타인듯)가 17916인걸로 봐서, 17916번을 연속으로 이기면 flag를 획득할 수 있는것으로 보인다.
brute force 같은건 생각하지 말고, 코드 분석으로 넘어가자.
apk 파일은 zip 파일과 같은 형태이므로, unzip을 이용해서 압축을 풀고, classes.dex 파일을 jar 파일로 변환한 뒤, jd-gui를 통해 코드 분석을 실시하면 된다.
$ unzip rock.apk
...
$ dj2-dex3jar.sh classes.dex
dex2jar classes.dex -> ./classes-dex2jar.jar
$ jd-gui classes-dex2jar.jar
열심히 뜯어볼 것도 없이, 친절하게 CallMe.class라는 클래스가 있다. 이 클래스가 호출되도록 하면 되는 것 같다. 이 클래스가 하는 일은 onReceive() 메소드에 기록되어 있다.
![](https://github.com/JisoonPark/writeup/raw/master//rock/callme.png)
문자열을 갖고 조합하는 코드인 것 같은데, 한땀한땀 파악하긴 귀찮으니 그냥 그대로 C 코드로 옮긴다. ck라는 함수는 Native API이다. IDA에서 decompile 해서 코드로 옮기면 된다.
![](https://github.com/JisoonPark/writeup/raw/master//rock/ck.png)
마지막으로, paramIntent에서 'mm'이라는 태그를 통해 넘어온 문자열을 찾아야 하는데, 가위바위보를 이겼을 경우 CallMe가 호출될 것이므로, MainActivity에서 이 부분을 찾아보면 Native 함수인 rps_calc() 함수의 반환 값이 전달되는 것을 알 수 있다.
![](https://github.com/JisoonPark/writeup/raw/master//rock/main_activity.png)
rps_calc() 함수를 decompile 해서 살펴보자.
어떤 변수(k)가 이 게임의 목표 점수였던 17916보다 큰 값을 가질때 뭔가를 수행하는 부분을 찾을 수 있다.
![](https://github.com/JisoonPark/writeup/raw/master//rock/rps_calc.png)
이왕 코드로 옮기기로 한 것, 이 부분도 따와서 붙여넣도록 한다.
최종 코드는 아래와 같이 완성된다.
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
signed short CallMe_ck(signed int a3, signed short a4, signed short a5)
{
signed short result; // ax@1
result = a5;
//LOBYTE(result) = a5;
switch ( a3 % 6 )
{
case 0:
result = ((a4 & 0xFFF0u) >> 4) ^ a5;
goto LABEL_8;
case 1:
result = ((a4 & 0xFFE0u) >> 5) ^ a5;
goto LABEL_8;
case 2:
result = ((a4 & 0xFF80u) >> 7) ^ a5;
goto LABEL_8;
case 3:
result = ((a4 & 0xFFC0u) >> 6) ^ a5;
goto LABEL_8;
case 5:
result = a5 ^ 0xF;
goto LABEL_8;
case 4:
LABEL_8:
result = (char)result;
break;
default:
result = 67;
break;
}
return result;
}
void onReceive(char* v10)
{
///CallMe_onReceive///
register int i;
char* paramContext = v10;
char arrayOfChar[] = "SBtbhfle_7tg]Runsj5]io_MBmi";
char paramIntent[100] = {0};
for (i = 0; i < strlen(arrayOfChar); i++)
{
if (i < 16) {
paramIntent[i] = CallMe_ck(i, paramContext[i], arrayOfChar[i]);
} else {
paramIntent[i] = CallMe_ck(i, paramContext[i - 16], arrayOfChar[i]);
}
}
printf("%s\n", paramIntent);
return;
}
int main(void)
{
///rps_1calc///
register size_t v6; // esi@4
signed int v10; // [sp+8h] [bp-354h]@1
signed int v11; // [sp+Ch] [bp-350h]@1
signed int v12; // [sp+10h] [bp-34Ch]@1
signed int v13; // [sp+14h] [bp-348h]@1
char v14;
v14 = 0;
v13 = 658317629;
v12 = 540877373;
v11 = 1581080381;
v10 = 0x533D5458;
printf ("%08x %08x %08x %08x %08x\n", (unsigned int)&v10, (unsigned int)&v11, (unsigned int)&v12, (unsigned int)&v13, (unsigned int)&v14);
if ( strlen((const char *)&v10) )
{
//v9 = 0x10;
v10 = (v10 & (~0xff)) ^ (0x10 ^ 0x58);
if ( strlen((const char *)&v10) >= 2 )
{
v6 = 1;
do
*((unsigned char *)&v10 + v6++) ^= 0x10;
while ( v6 < strlen((const char *)&v10) );
}
}
printf("%s\n", (char*)&v10);
onReceive(&v10);
return 0;
}
위 코드를 컴파일하여 실행하면 flag 값을 얻을 수 있다.
![](https://github.com/JisoonPark/writeup/raw/master//rock/flag.png)
Flag : W@tching_7th_Sunse7_in_B@li
'writeups > Reversing' 카테고리의 다른 글
Local News (0) | 2019.11.25 |
---|---|
KeyGenMe (0) | 2019.11.25 |
pyc decompile (0) | 2019.11.25 |
Easyhaskell (0) | 2019.11.25 |
EASY_CrackMe (0) | 2019.11.25 |