Rating:

# Local News
Android

## Challenge

Be sure to check your local news broadcast for the latest updates!

Difficulty: medium-hard

## Solution

### Understand the source code

Decompile APK package

dex2jar app.apk
apktool d app.apk

MainActivity.class

package com.tamu.ctf.hidden;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import io.michaelrocks.paranoid.Deobfuscator.app.Debug;

public class MainActivity extends AppCompatActivity {
protected void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
setContentView(2131296282);
paramBundle = new BroadcastReceiver() {
public void onReceive(Context paramAnonymousContext, Intent paramAnonymousIntent) {
Log.d(MainActivity.this.getString(2131427360), Deobfuscator.app.Debug.getString(0));
}
};
IntentFilter localIntentFilter = new IntentFilter();
localIntentFilter.addAction(getString(2131427361));
LocalBroadcastManager.getInstance(this).registerReceiver(paramBundle, localIntentFilter);
}
}

We know from the constants inside R.class that these resources are used.

public static final int activity_main = 2131296282;
public static final int flag = 2131427360;
public static final int hidden_action = 2131427361;

// <string name="flag">Flag:</string>
// <string name="hidden_action">com.tamu.ctf.hidden.START</string>

### Working operation

So now how the app works is quite simple

1. Register a (Local) BroadcastReceiver of the action `com.tamu.ctf.hidden.START`
2. Deobfuscates the flag using [`Deobfuscator`](https://github.com/MichaelRocks/paranoid)
3. Prints `Flag: <result>` in logcat

### Issue

I initially thought that the fastest way will be to install on my phone and use ADB to control the broadcasting.

I tried this but for some reason I cannot get it to print the flag.

$ adb shell am broadcast -a com.tamu.ctf.hidden.START

Reason is because the app uses [LocalBroadcastManager which means only the app itself can send the broadcast.](https://stackoverflow.com/questions/24981014/how-to-send-a-localbroadcast-from-adb-shell).

We confirm this by checking the receivers.

$ adb shell cmd package query-receivers --brief -a com.tamu.ctf.START
No receivers found

### Modify APK Smali Code

So I thought of modifying the APK code.

We see this in MainActivity.smali

.line 32
invoke-static {p0}, Landroid/support/v4/content/LocalBroadcastManager;->getInstance(Landroid/content/Context;)Landroid/support/v4/content/LocalBroadcastManager;

move-result-object v2

invoke-virtual {v2, v1, v0}, Landroid/support/v4/content/LocalBroadcastManager;->registerReceiver(Landroid/content/BroadcastReceiver;Landroid/content/IntentFilter;)V

.line 34

It corresponds to this Java code.

v2 = LocalBroadcastManager.getInstance(this)
// invoke-static {p0 = this}

v2.registerReceiver // invoke-virtual {v2}
(paramBundle, localIntentFilter); {v1, v0}

---

#### Attempt #1 (Failed)

I assumed I could simply change `LocalBroadcastManager.getInstance(this).registerReceiver()` into `Context.registerReceiver()`, so that it will be globally registered

// I change this:
invoke-virtual {v2, v1, v0}, Landroid/support/v4/content/LocalBroadcastManager;->registerReceiver(Landroid/content/BroadcastReceiver;Landroid/content/IntentFilter;)V

// into this:
invoke-virtual {p0, v1, v0}, Landroid/content/Context;->registerReceiver(Landroid/content/BroadcastReceiver;Landroid/content/IntentFilter;)V

However, it caused a force-close upon opening the app.

---

#### Attempt #2 (Working)

I decided to simply call the `Log.d()` function to print the flag upon opening the app

From MainActivity$1.smali, I extracted the code between line 26 and 27

.line 26
iget-object v0, p0, Lcom/tamu/ctf/hidden/MainActivity$1;->this$0:Lcom/tamu/ctf/hidden/MainActivity;

const v1, 0x7f0b0020

invoke-virtual {v0, v1}, Lcom/tamu/ctf/hidden/MainActivity;->getString(I)Ljava/lang/String;

move-result-object v0

const/4 v1, 0x0

invoke-static {v1}, Lio/michaelrocks/paranoid/Deobfuscator$app$Debug;->getString(I)Ljava/lang/String;

move-result-object v1

invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I

.line 27

Which corresponds to this Java code

v0 = MainActivity.this.getString(2131427360) // Resource string "Flag:"
v1 = Deobfuscator.app.Debug.getString(0)
Log.d(v0, v1);

---

In order to simplify my life, se can form a simpler smali code by omitting the resource string

const/4 v1, 0x0

invoke-static {v1}, Lio/michaelrocks/paranoid/Deobfuscator$app$Debug;->getString(I)Ljava/lang/String;

move-result-object v1

invoke-static {v1, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I

And it corresponds to

v1 = Deobfuscator.app.Debug.getString(0) // flag
Log.d(v1, v1)

Now I simply insert it before the return statement in the onCreate() function.

---

### Building the APK

Now we have the [new smali](MainActivity-new.smali).

Build the new APK and it (will be found inside `app/dist/app.apk`).
Then we [need to sign it](https://stackoverflow.com/questions/18589694/i-have-never-set-any-passwords-to-my-keystore-and-alias-so-how-are-they-created) & install it

$ apktool b app

$ jarsigner -keystore ~/.android/debug.keystore -storepass android app/dist/app.apk androiddebugkey

# adb uninstall com.tamu.ctf.hidden

$ adb install app/dist/app.apk

# adb logcat

### Solving

Now run the app and we see the flag

02-23 16:02:16.472 18046 18046 D gigem{hidden_81aeb013bea}: gigem{hidden_81aeb013bea}

## Flag

gigem{hidden_81aeb013bea}

Original writeup (https://github.com/zst123/tamuctf-2019-writeups/tree/master/Solved/Local_News).