FlowerApp
Catgeory: Reversing
Points: 200
Solves: 17
- This is an iOS application built using SwiftUI.
- The Mach-O binary lies in
flowerapp.app/Contents/MacOSdirectory. - On opening the binary in IDA, could notice user-defined functions like loadf , cc , drawFlower
- In Exteral symbols, I could notice references to CCCrypt which is Apple’s CommonCrypto framework.
- Starting with function loadf,
they have loading some base64-encoded data stored in NSUserDefaults with keys “a”, “b” and “c” .
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17v82 = (id)objc_opt_self(&OBJC_CLASS___NSUserDefaults);
v5 = objc_msgSend(v82, "standardUserDefaults");
v6 = objc_retainAutoreleasedReturnValue(v5);
v7 = (void *)String._bridgeToObjectiveC()('a', 0xE100000000000000LL);
v8 = objc_msgSend(v6, "stringForKey:", v7);
v9 = objc_retainAutoreleasedReturnValue(v8);
objc_release(v6);
v10(v7);
if ( !v9 )
BUG();
v11 = static String._unconditionallyBridgeFromObjectiveC(_:)(v9);
v13 = v12;
v14(v9);
v15 = objc_allocWithZone(&OBJC_CLASS___NSData);
swift_bridgeObjectRetain(v13);
v16 = (void *)String._bridgeToObjectiveC()(v11, v13);
v17 = objc_msgSend(v15, "initWithBase64EncodedString:options:", v16, 0LL);They are passing these 3 values to function
cc.Checking the strings section, we get 3 values

These values passes through several intermediate functions before it was finally passed to
closure #1 in closure #1 in closure #1 in cc(a:b:c:)(not sure why the functions are in English sentences lol) , where this function uses CCCrypt package.

We could also see the code,
1
result = CCCrypt(1u, 0, 1u, a3, keyLength, a6, dataIn, dataInLength, (void *)(v16 + 32), v18, dataOutMoved);
- When checking the source code of this framework and comparing the arguments we just got,
- Operation was Decrypt
- Algorithm used is kCCAlgorithmAES
- Uses PKCS7 padding
- Based on the values we have, we could say first string is the key, second is the iv and the third one is the encrypted data.
- On decrypting the data with the above information, we get the flag Flag:
1
2
3
4
5
6
7
8
9
10
11from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
from base64 import b64decode
key = b64decode(b"qQwrmkzuhJv6fzCF2XsxuaB+ZBtMEH+Cd3fpTgJpEM8=")
iv = b64decode(b"FjmNRmlNzMZYK8TbIItuVA==")
ciphertext = b64decode(b"8XvXFKhm8YFfQShtVXcNZh5F8q0zBJMTnfBSh33SEr8r4hMWb/E2VJq20QO2Byef")
cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = cipher.decrypt(ciphertext)
print(plaintext.strip())flag{congrats_on_swiftly_decoding_this}
Protect your API Key
Catgeory: Reversing
Points: 400
Solves: 12
This is a very simple application that has only one activity i.e.
MainActivity.The apk also has an asset file
8.datawhose contents is encrypted.This activity loads a native library
libapp.sothat has two native functionsrunandstringFromJNI.The
runfunction is called withContextand a stringcom.some.real.better.practice.myapplication.RideHailingas arguments.On opening the library in Ghidra, starting with stringFromJNI, it just returns 0 (or some random value).
On checking run function,
- There are numerous string modification steps taking place.
- Methods are being invoked using JNI.
This seems like a pain to reverse with over 5.5k lines of code.
Lets check the application dynamically, starting with the strings created using
env.NewStringUTF()andenv.SetByteArrayRegionusing Medusa.We could see numerous strings used.

As we scroll down through the output, we start to see the juicy part of the challenge like
com.some.better.practice.app.MainActivity.getAssets()Landroid/content/res/AssetManager;,javax.crypto.spec.SecretKeySpec.<init>([BLjava/lang/String;)V,AES/ECB/PKCS5Paddinganddalvik.system.InMemoryDexClassLoader.<init>(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V.In simple, they are decrypting the assets file
8.datausing AES ECB mode with PKCS5Padding and loading the dex file in memory usingInMemoryDexClassLoader.The AES key is gr3443.,g,3-s@[w .
On decrypting the
8.datafile, we get a dex file.

On loading the dex file, we see the class
com.some.real.better.practice.myapplication.RideHailingand a decryption function that provides the flag.
1 | public static String decryptMsg(byte[] cipherText) throws Exception { |
Flag: flag{3fh9.gkf29j.7}