For this challenge, probably we need install some things into our Android 5.1 device with Genymotion.
For example, an ARM Translator.
https://github.com/m9rco/Genymotion_ARM_Translation
Use apktool for decompile the .apk file
apktool d YouCanHideButYouCannotRun.apk
And install the .apk with adb
adb install -r YouCanHideButYouCannotRun.apk
Launching the app we can see that we have a text that talk about encryption and a button. That say Start to Running if we press it.
Let’s load the .apk to jadx for see the source code.
We have the following package:hackchallenge.ahe17.teamsik.org.romanempire
And the AndroidManifest.xml file:
Look the permission
Why this app need write in the storage?
And, notice that in the AndroidManifest.xml file we have a MainActivity with this content:
package hackchallenge.ahe17.teamsik.org.romanempire;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
Button start;
boolean startedflag = false;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initialize();
}
private void initialize() {
this.start = (Button) findViewById(R.id.start);
this.start.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (!MainActivity.this.startedflag) {
MainActivity.this.startedflag = true;
MainActivity.this.start.setText("Running...");
MakeThreads.startWrites(MainActivity.this);
}
}
});
}
}
In the MainActivity, we can see in initialize() method the MakeThreads class.
That have this content:
public class MakeThreads {
private static ArrayList threads;
public static void startWrites(Activity activity) {
File directory = new File(activity.getApplicationInfo().dataDir + "/Rome");
directory.mkdirs();
File scroll = new File(directory, "scroll.txt");
try {
RandomAccessFile raf = new RandomAccessFile(scroll, "rw");
FileOutputStream f = new FileOutputStream(scroll);
new PrintWriter(f);
threads = new ArrayList<>();
threads.add(new X4bc86a15e3dc7ff7dca5240422059c40ca55f084(raf));
[---------]
[---------]
[---------]
[---------]
threads.add(new X1b629eed17073f7c9d6b318b77ab05bb453692f4(raf));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e2) {
e2.printStackTrace();
}
Iterator it = threads.iterator();
while (it.hasNext()) {
Thread t = it.next();
t.start();
}
}
public static void stopWrites(Activity activity) {
Iterator it = threads.iterator();
while (it.hasNext()) {
Thread t = it.next();
t.interrupt();
}
}
}
We can see that imports the classes like
public class X04c3eb5ce6c5e299ad93dac871bbbed16da09e21 extends Thread {
RandomAccessFile a;
long sleepTillTime = 41000;
char c = 'l';
int timetoSleep = 250;
public X04c3eb5ce6c5e299ad93dac871bbbed16da09e21(RandomAccessFile a) {
this.a = a;
}
public void run() {
try {
Thread.sleep(this.sleepTillTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
this.a.seek(0L);
this.a.writeChar(this.c);
this.a.writeChar(10);
} catch (IOException e2) {
e2.printStackTrace();
}
}
}
Which we have the char c variable and sleepTillTime.
This will create the scroll.txt file in/data/data/hackchallenge.ahe17.teamsik.org.romanempire/Rome
But, every char overwrite the previous char.
I try, but without successful
RandomAccessFile raf = new RandomAccessFile(scroll, "rw");
Change via smali code to “rwd” for write as append char by char. But don’t work.
And, the chars are printed and saved Randomly. Then, this don’t make sense, but I mention because this can work (if random isn’t present)
Then, probably we need use frida for hook the function.
Here’s a javascript script that use java.io.RandomAccessFile
Java.perform(function() {
// Initialize an empty array to collect characters written to the file.
var flagArray = [];
// Get a reference to the RandomAccessFile class.
var RandomAccessFile = Java.use('java.io.RandomAccessFile');
// Intercept the seek method of RandomAccessFile.
RandomAccessFile.seek.implementation = function(pos) {
// If the position is 0, set the skip flag to false.
if (pos === 0) {
this.skip = false;
}
// Call the original seek method and return its result.
return this.seek.call(this, pos);
};
// Intercept the writeChar method of RandomAccessFile.
RandomAccessFile.writeChar.implementation = function(c) {
// If the skip flag is true or the character is a newline (10), send the current accumulated flagArray.
if (this.skip || c === 10) {
send("PARTIAL:" + flagArray.join(""));
} else {
// Convert the character code to a character and add it to flagArray.
flagArray.push(String.fromCharCode(c));
// Send the character as a SYM message.
send("SYM:" + String.fromCharCode(c));
}
// Call the original writeChar method and return its result.
return this.writeChar.call(this, c);
};
});
Then, run frida server in your device and get the PID of the app (Button must be in start condition)
With the app running, run in your terminal
frida-ps -Uai
Copy the PID of RomanEmpire app.
Then, attach the script into the app with
frida -U -p -l script.js
Now press the button and when start running, you will see the code intercepting the functions.
Just wait to the end until you see this output
message: {'type': 'send', 'payload': 'PARTIAL:Aol jsvjrdvyr ohz ybzalk Puav h zapmm tvklyu hya zahabl, Whpualk if uhabyl, svhaolk if aol Thzzlz, huk svclk if aol mld. Aol nlhyz zjylht pu h mhpslk ylcpchs: HOL17{IlaalyJyfwaZ4m3vyKpl}!'} data: None
In cleanAol jsvjrdvyr ohz ybzalk Puav h zapmm tvklyu hya zahabl, Whpualk if uhabyl, svhaolk if aol Thzzlz, huk svclk if aol mld. Aol nlhyz zjylht pu h mhpslk ylcpchs: HOL17{IlaalyJyfwaZ4m3vyKpl}!
This is a Caesar’s Cipher text, we can rote this in any online tool.
But here’s a python script
def caesar_cipher(text, shift):
result = []
for char in text:
if char.isalpha():
shift_amount = shift % 26
start = ord('a') if char.islower() else ord('A')
# Crypt
new_char = chr(start + (ord(char) - start + shift_amount) % 26)
result.append(new_char)
else:
# Don't encrypt non-alphabetic chars
result.append(char)
return ''.join(result)
def main():
text = input("Enter the text to encrypt: ")
# ROT TEXT FROM 1 TO 25 TIMES
for shift in range(1, 26):
encrypted_text = caesar_cipher(text, shift)
print(f"\n[+] Shift [{shift}]: {encrypted_text}")
if __name__ == "__main__":
main()
Just paste the text and if you see the 19 ROT, you can found the final string with the flag.
The clockwork has rusted Into a stiff modern art statue, Painted by nature, loathed by the Masses, and loved by the few. The gears scream in a failed revival: AHE17{BetterCryptS4f3orDie}!
Flag: AHE17{BetterCryptS4f3orDie}
I hope you found it useful (:
Leave a Reply