CrySyS SecChallenge 2020: Super battle droids! Take them down!
Take down these super battle droids before the droidekas arrive! Actually, there is only one droid, so this challenge should be easy for you.
I wonder if you are a static or a dynamic person…
Categories
Offensive, Reverse Engineering
Files
Links
Solution
Let’s start off with unpacking all the stuff from the apk with the usual tools:
user@ubuntu:~$ apktool superbattledroids.apk
user@ubuntu:~$ unzip superbattledroids.apk classes.dex
user@ubuntu:~$ d2j-dex2jar classes.dex
user@ubuntu:~$ java -jar cfr-0.148.jar classes-dex2jar.jar --outputdir decompiled
When traversing the newly made directories it’s hard not to notice hu/secchallenge20/superbattledroids/HiddenActivity.java
, and the files in res/raw/
named secret1.png
, secret2.txt
and secret3.txt
. I commented the code of HiddenActivity.java
with the resource names and values for the resource identifiers, by following the number through res/values/public.xml
and res/values/strings.xml
.
/*
* Decompiled with CFR 0.148.
*
* Could not load the following classes:
* android.content.res.Resources
* android.graphics.Bitmap
* android.graphics.BitmapFactory
* android.graphics.BitmapFactory$Options
* android.graphics.Color
* android.os.Bundle
* android.view.View
* android.widget.TextView
*/
package hu.secchallenge20.superbattledroids;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
public class HiddenActivity
extends v {
public static boolean p = false;
/*
* Enabled aggressive block sorting
* Enabled unnecessary exception pruning
* Enabled aggressive exception aggregation
*/
@Override
public void onCreate(Bundle object) {
Bitmap bitmap;
int n10;
Object object2;
int n11;
String[] arrstring;
ArrayList<Integer> arrayList;
block10: {
block9: {
super.onCreate((Bundle)object);
this.setContentView(2131427356);
object = new BitmapFactory.Options();
n11 = 0;
((BitmapFactory.Options)object).inScaled = false;
bitmap = BitmapFactory.decodeResource((Resources)this.getResources(), (int)2131558400, (BitmapFactory.Options)object); // secret1.png
arrstring = this.getResources().openRawResource(2131558401);
object2 = new BufferedReader(new InputStreamReader((InputStream)arrstring));
arrayList = null;
try {
object = ((BufferedReader)object2).readLine();
}
catch (IOException iOException) {
object = null;
break block9;
}
try {
arrstring.close();
((BufferedReader)object2).close();
break block10;
}
catch (IOException iOException) {}
}
((Throwable)object2).printStackTrace();
}
arrstring = ((String)object).replace("[", "").replace("]", "").split(", "); // secret2.txt
InputStream inputStream = this.getResources().openRawResource(2131558402);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
object = arrayList;
try {
object = object2 = bufferedReader.readLine(); // object = secret3.txt
inputStream.close();
object = object2;
bufferedReader.close();
object = object2;
}
catch (IOException iOException) {
iOException.printStackTrace();
}
arrayList = new ArrayList<Integer>();
int n12 = arrstring.length;
int n13 = 0;
for (n10 = 0; n10 < n12; ++n10) {
arrayList.add(Color.red((int)bitmap.getPixel(n13 += Integer.parseInt(arrstring[n10]), 0)));
}
object2 = this.getResources().getString(2131624000); // "start" = "cd20{"
n10 = n11;
do {
n13 = arrayList.size();
object2 = wc.a((String)object2);
if (n10 >= n13) break;
n13 = Integer.parseInt(this.getResources().getString(2131623999)); // "size" = "300"
n11 = (Integer)arrayList.get(n10);
((StringBuilder)object2).append(((String)object).charAt(Integer.parseInt(this.getResources().getString(2131623988 /* "life" = "42" */)) + (n11 + n13 * n10)));
object2 = ((StringBuilder)object2).toString();
++n10;
} while (true);
((StringBuilder)object2).append(this.getResources().getString(2131623982)); // "end" = "}"
object = ((StringBuilder)object2).toString();
object2 = (TextView)this.findViewById(2131230788);
if (!p) {
object = "Calculations are done!";
}
object2.setText((CharSequence)object);
}
}
Time to get the resources into an easier to use format: convert the image with GIMP into C source file and add this convenience function:
unsigned char get_pixel(long idx)
{
return gimp_image.pixel_data[idx * 3];
}
And add the other two text files straight into the program with minor modifications:
int secret2[] = { 12, 122, 247, 231, 51, 65, 102, 178, 102, 127, 10, 55, 82, 36, 7, 76, 101, 156, 126, 225, 90, 73, 151, 117, 168, 241, 179, 113 };
const char secret3[] = R"qqq(<contents of secret3.txt>)qqq";
As a last step, we C++-ify the java code for decryption and run it:
int main()
{
std::vector<int> arrayList;
int n12 = std::size(secret2);
int n13 = 0;
for (int n10 = 0; n10 < n12; ++n10) {
arrayList.push_back(get_pixel(n13 += secret2[n10]));
}
std::string object2 = "cd20{";
int n10 = 0;
do {
n13 = arrayList.size();
//object2 = wc.a((String)object2);
if (n10 >= n13) break;
n13 = 300;
auto n11 = arrayList[n10];
object2 += secret3[(42 + (n11 + n13 * n10))];
++n10;
} while (true);
object2 += "}";
std::cout << object2;
return 0;
}
Output:
cd20{D0_0r_d0_n0t_Th3r3_1s_n0_try}