SharifCTF-2016/android-app

From aldeid
Jump to: navigation, search
You are here
srm (50 points)

Description

The file (Sharif_CTF.apk) is an Android application:

MD5 e8f19d21e6fd91fb134bca8bdc5dd3b6
SHA1 5c6005941a32fed7a874836ddd8eca87e48f085a
SHA256 f52c38abf6a52d3d430e5d940e3aab1a8269fa80e409691a2211f7ababcfd40c
File Java archive data (JAR)

Running the application

When run, the application shows a form to enter a serial and a
Login
button. If the serial is invalid, the following message appears:

SharifCTF-2016-android-app-run-app-invalid-serial.png

Analysis

Use dex2jar and JD-GUI

Let's first use dex2jar to convert the *.apk to a *.jar file that we can read with JD-GUI:

$ /data/tools/dex2jar-2.0/d2j-dex2jar.sh Sharif_CTF.apk 
dex2jar Sharif_CTF.apk -> ./Sharif_CTF-dex2jar.jar
Now, we can read
Sharif_CTF-dex2jar.jar
with JD-GUI:
$ $ /data/tools/jd-gui/jd-gui Sharif_CTF-dex2jar.jar

It results in the 2 following files:

MainActivity.class
 1 package com.example.ctf2;
 2 
 3 import android.app.Activity;
 4 import android.os.Build;
 5 import android.os.Bundle;
 6 import android.widget.Button;
 7 import android.widget.EditText;
 8 import android.widget.TextView;
 9 
10 public class MainActivity extends Activity
11 {
12   Button a;
13   EditText b;
14   TextView c;
15   int d = 123;
16   String e = "Code";
17 
18   static
19   {
20     System.loadLibrary("adnjni");
21   }
22 
23   public native int IsCorrect(String paramString);
24 
25   public void onCreate(Bundle paramBundle)
26   {
27     super.onCreate(paramBundle);
28     setContentView(2130903040);
29     this.a = ((Button)findViewById(2131230721));
30     this.b = ((EditText)findViewById(2131230720));
31     this.c = ((TextView)findViewById(2131230722));
32     this.e = Build.SERIAL;
33     this.d = 114366;
34     this.a.setOnClickListener(new a(this));
35   }
36 
37   public native int processObjectArrayFromNative(String paramString);
38 }
  
a.class
 1 package com.example.ctf2;
 2 
 3 import android.text.Editable;
 4 import android.util.Log;
 5 import android.view.View;
 6 import android.view.View.OnClickListener;
 7 import android.widget.EditText;
 8 import android.widget.TextView;
 9 import java.security.MessageDigest;
10 import java.security.NoSuchAlgorithmException;
11 
12 class a
13   implements View.OnClickListener
14 {
15   a(MainActivity paramMainActivity)
16   {
17   }
18 
19   public void onClick(View paramView)
20   {
21     new String(" ");
22     paramView = this.a.b.getText().toString();
23     Log.v("EditText", this.a.b.getText().toString());
24     new String("");
25     int i = this.a.processObjectArrayFromNative(paramView);
26     int j = this.a.IsCorrect(paramView);
27     paramView = this.a.d + i + " ";
28     try
29     {
30       Object localObject = MessageDigest.getInstance("MD5");
31       ((MessageDigest)localObject).update(paramView.getBytes());
32       paramView = ((MessageDigest)localObject).digest();
33       localObject = new StringBuffer();
34       i = 0;
35       while (true)
36       {
37         if (i >= paramView.length)
38         {
39           if ((j == 1) && (this.a.e != "unknown"))
40             this.a.c.setText("Sharif_CTF(" + ((StringBuffer)localObject).toString() + ")");
41           if ((j == 1) && (this.a.e == "unknown"))
42             this.a.c.setText("Just keep Trying :-)");
43           if (j != 0)
44             break;
45           this.a.c.setText("Just keep Trying :-)");
46           return;
47         }
48         ((StringBuffer)localObject).append(Integer.toString((paramView[i] & 0xFF) + 256, 16).substring(1));
49         i += 1;
50       }
51     }
52     catch (NoSuchAlgorithmException paramView)
53     {
54       paramView.printStackTrace();
55     }
56   }
57 }
The
MainActivity.class
file is responsible for the layout. It displays the form and calls the
setOnClickListener
function when the
Login
button is clicked. On line #20, we also see that the
adnjni.so
library is loaded with a call to
System.loadLibrary
. The code for the
Login
button is in the second file (
a.class
). We see that the serial is saved to
paramView
on line #22 and passed to the
IsCorrect
function of the external library on line #26.

Extract files with apktool

Now, let's extract files with apktool:

$ java -jar /data/tools/apktool/apktool_2.0.1.jar d Sharif_CTF.apk 
I: Using Apktool 2.0.1 on Sharif_CTF.apk
I: Loading resource table...
I: Decoding AndroidManifest.xml with resources...
I: Loading resource table from file: /home/unknown/apktool/framework/1.apk
I: Regular manifest package...
I: Decoding file-resources...
I: Decoding values */* XMLs...
I: Baksmaling classes.dex...
I: Copying assets and libs...
I: Copying unknown files...
I: Copying original files...

It will result in the following files:

Sharif_CTF
├── AndroidManifest.xml
├── apktool.yml
├── lib
│   └── armeabi
│       └── libadnjni.so
├── original
│   ├── AndroidManifest.xml
│   └── META-INF
│       ├── CERT.RSA
│       ├── CERT.SF
│       └── MANIFEST.MF
├── res
│   ├── drawable-hdpi-v4
│   │   └── ic_launcher.png
│   ├── drawable-mdpi-v4
│   │   └── ic_launcher.png
│   ├── drawable-xhdpi-v4
│   │   └── ic_launcher.png
│   ├── drawable-xxhdpi-v4
│   │   └── ic_launcher.png
│   ├── layout
│   │   └── activity_main.xml
│   ├── menu
│   │   └── main.xml
│   ├── values
│   │   ├── dimens.xml
│   │   ├── ids.xml
│   │   ├── public.xml
│   │   ├── strings.xml
│   │   └── styles.xml
│   ├── values-v11
│   │   └── styles.xml
│   ├── values-v14
│   │   └── styles.xml
│   └── values-w820dp-v13
│       └── dimens.xml
└── smali
    └── com
        └── example
            └── ctf2
                ├── a.smali
                └── MainActivity.smali

Analysis of libadnjni.so in IDA-Pro

Let's open
libadnjni.so
in IDA-Pro and jump to the
Java_com_example_ctf2_MainActivity_IsCorrect
method. Using the pseudo-code module (
F5
) really helps. It produces the following code:
  1 signed int __fastcall Java_com_example_ctf2_MainActivity_IsCorrect(int a1, int a2, int a3)
  2 {
  3   int v3; // [email protected]
  4   signed int v4; // [email protected]
  5   signed int v5; // [email protected]
  6   signed int v6; // [email protected]
  7   signed int result; // [email protected]
  8   int v8; // [sp+10h] [bp-50h]@1
  9   char *v9; // [sp+14h] [bp-4Ch]@1
 10   int v10; // [sp+1Ch] [bp-44h]@1
 11   signed int v11; // [sp+20h] [bp-40h]@0
 12   char v12; // [sp+24h] [bp-3Ch]@1
 13   char v13; // [sp+25h] [bp-3Bh]@1
 14   char v14; // [sp+26h] [bp-3Ah]@1
 15   char v15; // [sp+27h] [bp-39h]@1
 16   char v16; // [sp+28h] [bp-38h]@1
 17   char v17; // [sp+29h] [bp-37h]@1
 18   char v18; // [sp+2Ah] [bp-36h]@1
 19   char v19; // [sp+2Bh] [bp-35h]@1
 20   char v20; // [sp+2Ch] [bp-34h]@1
 21   char v21; // [sp+2Dh] [bp-33h]@1
 22   char v22; // [sp+2Eh] [bp-32h]@1
 23   char v23; // [sp+2Fh] [bp-31h]@1
 24   char v24; // [sp+30h] [bp-30h]@1
 25   char v25; // [sp+31h] [bp-2Fh]@1
 26   char v26; // [sp+32h] [bp-2Eh]@1
 27   char v27; // [sp+33h] [bp-2Dh]@1
 28   char v28; // [sp+34h] [bp-2Ch]@1
 29   char v29; // [sp+35h] [bp-2Bh]@1
 30   char v30; // [sp+36h] [bp-2Ah]@1
 31   char v31; // [sp+37h] [bp-29h]@1
 32   char v32; // [sp+38h] [bp-28h]@1
 33   char v33; // [sp+39h] [bp-27h]@1
 34   char v34; // [sp+3Ah] [bp-26h]@1
 35   char v35; // [sp+3Bh] [bp-25h]@1
 36   char v36; // [sp+3Ch] [bp-24h]@1
 37   char v37; // [sp+3Dh] [bp-23h]@1
 38   char v38; // [sp+3Eh] [bp-22h]@1
 39   char v39; // [sp+3Fh] [bp-21h]@1
 40   char v40; // [sp+40h] [bp-20h]@1
 41   char v41; // [sp+41h] [bp-1Fh]@1
 42   char v42; // [sp+42h] [bp-1Eh]@1
 43   char v43; // [sp+43h] [bp-1Dh]@1
 44   char v44; // [sp+44h] [bp-1Ch]@1
 45   char v45; // [sp+45h] [bp-1Bh]@1
 46   int v46; // [sp+48h] [bp-18h]@1
 47 
 48   v8 = a3;
 49   v3 = a1;
 50   v46 = _stack_chk_guard;
 51   v9 = (char *)(*(int (**)(void))(*(_DWORD *)a1 + 676))();
 52   v12 = 101;
 53   v13 = 102;
 54   v14 = 53;
 55   v15 = 55;
 56   v16 = 102;
 57   v17 = 51;
 58   v18 = 102;
 59   v19 = 101;
 60   v20 = 51;
 61   v21 = 99;
 62   v22 = 102;
 63   v23 = 54;
 64   v24 = 48;
 65   v25 = 51;
 66   v26 = 99;
 67   v27 = 48;
 68   v28 = 51;
 69   v29 = 56;
 70   v30 = 57;
 71   v31 = 48;
 72   v32 = 101;
 73   v33 = 101;
 74   v34 = 53;
 75   v35 = 56;
 76   v36 = 56;
 77   v37 = 56;
 78   v38 = 55;
 79   v39 = 56;
 80   v40 = 99;
 81   v41 = 48;
 82   v42 = 101;
 83   v43 = 99;
 84   v44 = 0;
 85   v4 = 0;
 86   v45 = 53;
 87   v10 = j_j_strcmp(v9, &v12);
 88   v5 = 1701458332;
 89   while ( 1 )
 90   {
 91     while ( 1 )
 92     {
 93       while ( 1 )
 94       {
 95         v6 = v5;
 96         v5 = 809244963;
 97         if ( v6 <= 1701458331 )
 98           break;
 99         if ( v6 != 1701458332 )
100           goto LABEL_16;
101         v5 = -333293478;
102         if ( v10 )
103           v5 = -158041539;
104       }
105       if ( v6 <= 809244962 )
106         break;
107       if ( v6 != 809244963 )
108         goto LABEL_16;
109       (*(void (__fastcall **)(int, int, char *))(*(_DWORD *)v3 + 680))(v3, v8, v9);
110       v11 = v4;
111       v5 = -326599761;
112     }
113     if ( v6 != -158041539 )
114     {
115       v4 = 1;
116       v5 = -158041539;
117       if ( v6 != -333293478 )
118         break;
119     }
120   }
121   if ( v6 != -326599761 )
122   {
123     while ( 1 )
124 LABEL_16:
125       ;
126   }
127   result = v11;
128   if ( _stack_chk_guard != v46 )
129     j_j___stack_chk_fail(v11);
130   return result;
131 }

We immediately notice the use of variables containing ASCII values that we can use to build a string.

Script and solution

The following script:

#!/usr/bin/env python2
s = [101, 102, 53, 55, 102, 51, 102, 101,
51, 99, 102, 54, 48, 51, 99, 48,
51, 56, 57, 48, 101, 101, 53, 56,
56, 56, 55, 56, 99, 48, 101, 99]
print ''.join([chr(i) for i in s])

...will output:

ef57f3fe3cf603c03890ee588878c0ec

Which is actually the solution to get the flag. If you enter this serial, the following flag is given:

833489ef285e6fa80690099efc5d9c9d

SharifCTF-2016-android-app-valid-serial.png

Comments

blog comments powered by Disqus

Keywords: sharif 2016 challenge reversing