MOBISEC
babyrev (10)
Jadx-gui를 이용해서 APK파일을 디스어셈블한다.
MainActivity
분석
다음과 같은 코드를 사용하면 ID를 지정하고 리소스에 매핑된 문자열을 불러올 수 있다.
아래 필드를 따라가보면 ID넘버가 존재하며 이 ID넘버와 매핑되는 값을 strings.xml에서 찾는다.
개발에 대한 자세한 내용은 아래에 정리한 부록1을 참고한다.
final EditText flagWidget = (EditText) findViewById(C0055R.C0057id.flag);
final TextView resultWidget = (TextView) findViewById(C0055R.C0057id.result);
아래의 조건문에 맞는 문자열이 이 문제의 Flag값이라는 것을 알 수 있다.
if (FlagChecker.checkFlag(MainActivity.this, flagWidget.getText().toString())) {
msg = "Valid flag!";
color = -16737536;
} else {
msg = "Invalid flag";
color = SupportMenu.CATEGORY_MASK;
}
Flagchecker의 checkFlag 매소드를 확인해보자
FlagChecker.checkFlag()
크게 조건문의 두가지가 존재하며 False값을 반환하면 올바른 flag가 아니라는 것을 알 수 있다.
조건문 1
첫번째, 조건문을 단계별로 쉽게 풀기 위하여 or연산(||) 단위로 나눠서 분석한다.
1. !flag.startsWith("MOBISEC{") ||
- MOBISEC{
2. new StringBuilder(flag).reverse().toString().charAt(0) != '}' ||
- MOBISEC{ }
3. flag.length() != 35 ||
- 총 문자열의 길이가 35가 되야한다.
4. !flag.toLowerCase().substring(8).startsWith("this_is_") ||
- MOBISEC{this_is_ }
5. !new StringBuilder(flag).reverse().toString().toLowerCase().substring(1).startsWith(ctx.getString(C0055R.string.last_part)) ||
- c0055R.string.last_part의 문자열 값은 "ver_cis"인데 이것을 reverse()한다.
- substrings(1)로 인해 마지막 문자, }가 빠진 나머지 문자열임을 알 수 있다.
- MOBISEC{this_is_ sic_rev}
6. flag.charAt(17) != '_' ||
- MOBISEC{this_is_?_ sic_rev}
- 16번째는 아직 모르기 때문에 ?를 입력하였다.
7. flag.charAt((int) (((double) getY()) * Math.pow((double) getX(), (double) getY()))) != flag.charAt(((int) Math.pow(Math.pow(2.0d, 2.0d), 2.0d)) + 1) ||
- 아래에 있는 메소드가 실행하게 된다. 각 메소드가 반환하는 값을 넣고 계산하면 된다.
- 수식을 정리하면 다음과 같다. flag.charAt(24) != flag.charAt(17)
- 24번째 문자는 '_'이 와야한다.
8. !bam(flag.toUpperCase().substring(getY() * getX() * getY(), (int) (Math.pow((double) getZ(), (double) getX()) - 1.0d))).equals("ERNYYL") ||
- bam 매소드는 굉장히 복잡하기 때문에 이 매소드를 직접 실행해서 결과를 보는 것이 낫다.
- 해당 값을 계산하면 "REALLY"가 된다.
- MOBISEC{this_is_?_REALLY_ sic_rev}
9. flag.toLowerCase().charAt(16) != 'a' ||
- 16번째 문자에 a가 와야한다.
- MOBISEC{this_is_a_REALLY_ sic_rev}
10. flag.charAt(16) != flag.charAt(26) ||
- 16번째와 24번째 문자는 같다.
- MOBISEC{this_is_a_REALLY_?asic_rev}
11. flag.toUpperCase().charAt(25) != flag.toUpperCase().charAt(26) + 1)
- 26번째 문자는 'a'이다. 이것을 대문자로 변경하여 +1을 더하면 B가 된다.
- String 문자열이 아닌 char 타입이라 숫자와 연산이 가능하다.
- MOBISEC{this_is_a_REALLY_Basic_rev}
조건문 2
이 조건문은 간단하지만 집중이 필요하다.
if (!flag.substring(8, flag.length() - 1).matches(getR())) {
return false;
}
public static String getR() {
String r = BuildConfig.FLAVOR;
boolean upper = true;
for (int i = 0; i < 26; i++) {
if (upper) {
r = r + "[A-Z_]";
} else {
r = r + "[a-z_]";
}
upper = !upper;
}
return r;
}
먼저 flag.length()는 35글자이므로 flag.substring(8, 34)를 계산하면
양쪽 대괄호를 제외한 문자열을 추출하는 것을 알 수 있다.
this_is_a_REALLY_Basic_rev.matches(getR()))
getR() 매소드를 테스트 코드로 붙여넣어서 실행하면 다음과 같다.
this_is_a_REALLY_Basic_rev.matches([A-Z_][a-z_][A-Z_][a-z_][A-Z_][a-z_].......)
match 매소드는 정규표현식을 의미하며 임시 클래스를 생성하여 테스트 해보면 대문자,소문자 순으로 매칭이 되어야 한다는 것을 알 수 있다.
위 조건문에 해당하는 문자열로 치환하면 다음과 같다.
ThIs_iS_A_ReAlLy_bAsIc_rEv
하지만 1번 조건문도 동시에 만족해야 하므로 제외됬던 대괄호 밖의 문자열이 같이 존재해야 한다.
Flag: MOBISEC{ThIs_iS_A_ReAlLy_bAsIc_rEv}
부록 1) android - Resource string읽어오기
@strings.xml
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="string_id">This is a sample test</string>
@R.java
public static final class string {
public static final int string_id=0x7f050007;
"This is a smaple test" 라는 string을 resource로부 읽어오기 위해서는 아래와 같은 코드가 가능하다.
1.
getString(string_id), or getResource().getString(string_id);
2.
Context context = this;
context.getString(string_id);
부록 2) 클래스, 매소드 정리
StringBuilder: String 문자열 만드는데 사용하는 클래스
substring(1): 1번째 인덱스부터 시작, 그이전 0번째 인덱스는 포함되지 않는다.
'리버싱CTF > mobisec' 카테고리의 다른 글
[MOBISEC] Pincode (10) (0) | 2020.07.26 |
---|