APKrypt
2 minutes to read
We are given an APK file (APKrypt.apk
). We need to find a VIP code inside the APK file. Hence, we will use d2j-dex2jar
to get a JAR file:
$ d2j-dex2jar APKrypt.apk
dex2jar APKrypt.apk -> ./APKrypt-dex2jar.jar
Source code analysis
Now we upload the JAR file into www.javadecompilers.com and select Jadx as decompiler.
The main file is at sources/com/example/apkrypt/MainActivity.java
:
package com.example.apkrypt;
import android.app.Activity;
import android.os.Bundle;
import android.util.Base64;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class MainActivity extends Activity {
/* renamed from: b1 */
Button f77b1;
EditText ed1;
public static String decrypt(String str) throws Exception {
Key generateKey = generateKey();
Cipher instance = Cipher.getInstance("AES");
instance.init(2, generateKey);
return new String(instance.doFinal(Base64.decode(str, 0)), "utf-8");
}
public static String encrypt(String str) throws Exception {
Key generateKey = generateKey();
Cipher instance = Cipher.getInstance("AES");
instance.init(1, generateKey);
return Base64.encodeToString(instance.doFinal(str.getBytes("utf-8")), 0);
}
private static Key generateKey() throws Exception {
return new SecretKeySpec("Dgu8Trf6Ge4Ki9Lb".getBytes(), "AES");
}
public static String md5(String str) {
try {
MessageDigest instance = MessageDigest.getInstance("MD5");
instance.update(str.getBytes());
byte[] digest = instance.digest();
StringBuffer stringBuffer = new StringBuffer();
for (byte b : digest) {
stringBuffer.append(Integer.toHexString(b & 255));
}
return stringBuffer.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return "";
}
}
/* access modifiers changed from: protected */
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(C0535R.layout.activity_main);
this.f77b1 = (Button) findViewById(C0535R.C0538id.button);
this.ed1 = (EditText) findViewById(C0535R.C0538id.editTextVipCode);
this.f77b1.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
try {
if (MainActivity.md5(MainActivity.this.ed1.getText().toString()).equals("735c3628699822c4c1c09219f317a8e9")) {
Toast.makeText(MainActivity.this.getApplicationContext(), MainActivity.decrypt("k+RLD5J86JRYnluaZLF3Zs/yJrVdVfGo1CQy5k0+tCZDJZTozBWPn2lExQYDHH1l"), 1).show();
} else {
Toast.makeText(MainActivity.this.getApplicationContext(), "Wrong VIP code!", 0).show();
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
First, it asks for a VIP code in onCreate
and checks its MD5 hash with 735c3628699822c4c1c09219f317a8e9
. If we use crackstation.net we won’t find any match:
Flag
Indeed, we are not interested in the VIP code but in what comes after. If we entered a correct VIP code, then a ciphertext that is encoded in Base64 (k+RLD5J86JRYnluaZLF3Zs/yJrVdVfGo1CQy5k0+tCZDJZTozBWPn2lExQYDHH1l
) would be decrypted. The cipher is AES, and we got the key (Dgu8Trf6Ge4Ki9Lb
). Hence, let’s decrypt it using Python:
$ python3 -q
>>> from base64 import b64decode
>>> from Crypto.Cipher import AES
>>> from Crypto.Util.Padding import unpad
>>> key = b'Dgu8Trf6Ge4Ki9Lb'
>>> ct = b64decode('k+RLD5J86JRYnluaZLF3Zs/yJrVdVfGo1CQy5k0+tCZDJZTozBWPn2lExQYDHH1l')
>>> cipher = AES.new(key, AES.MODE_ECB)
>>> unpad(cipher.decrypt(ct), AES.block_size)
b'HTB{3nj0y_y0ur_v1p_subscr1pt1on}'