[{"content":"What is AndroidManifest.xml? So, the AndroidManifest.xml file is a file configuration which is crusial in an application, why? cz it provides the comprehensive overview of the app\u0026rsquo;s structure, permissions and security features even before its source code has been analysed in depth.\nHow to Get the File? If you want to get the file, you can simply unzip it; but to read the file from an application, we can\u0026rsquo;t just unzip it because the format is still proprietary binary. We must use a tool like APK Tool with command apktool d [filename].apk to decode the file into XML format which can be read by humans.\nNotes: apktool command is just an alias of java -jar apktool_x.x.x.jar\nHere is a comparison between unzipping and using APK Tool.\nImportant Informations Inside AndroidManifest.xml This is the file must be looks like\nSDK Version \u0026amp; Security Features Let\u0026rsquo;s start with line two because the line one isnt that important. 1... 2\u0026lt;manifest xmlns:android=\u0026#34;http://schemas.android.com/apk/res/android\u0026#34; android:compileSdkVersion=\u0026#34;30\u0026#34; android:compileSdkVersionCodename=\u0026#34;11\u0026#34; package=\u0026#34;com.apptesting.privacy\u0026#34; platformBuildVersionCode=\u0026#34;30\u0026#34; platformBuildVersionName=\u0026#34;11\u0026#34;\u0026gt; 3... So what do we have?\nWe\u0026rsquo;ve got Android compile SDK version 30 and we\u0026rsquo;ve got Android compile SDK version code name if we take a look at the code below. 1... 2\u0026lt;manifest ... android:compileSdkVersion=\u0026#34;30\u0026#34; android:compileSdkVersionCodename=\u0026#34;11\u0026#34; ... \u0026gt; 3... This means the developer has used the compiler settings for Android version 11 and API level of Android version 11 is API level 30.\nWhy is this important? cz it means every security feature till Android 11 is included in the application. For example, in Android 7 (API 24), there was a huge change regarding the trust relationship of certificates, so user-installed certificates are no longer trusted by default.\nhttps://android-developers.googleblog.com/2016/07/changes-to-trusted-certificate.html\nPackage Name Still on line two, this is the package name, take a look at the code below. 1... 2\u0026lt;manifest ... package=\u0026#34;com.apptesting.privacy\u0026#34; ... \u0026gt; 3... That is the unique identifier for the application, but dont let a familiar name fool you cz it doesnt prove the application is legit. For example, anyone could develop a fake application and give it the package name com.instagram.android (Instagram\u0026rsquo;s package name). If you dont have the real one installed, the fake application will install and look totally normal.\nIf you try to install the real one later, you will get an error because your phone maybe like \u0026quot; I already have one application with this ID and the signing certificates dont match, hmm.. Sorry sir\u0026quot;.\nSo you cant have two applications with the same name running on your device.\nPermissions Take a look at these three lines below. 2... 3 \u0026lt;uses-permission android:name=\u0026#34;android.permission.READ_CONTACTS\u0026#34;/\u0026gt; 4 \u0026lt;uses-permission android:name=\u0026#34;android.permission.INTERNET\u0026#34;/\u0026gt; 5 \u0026lt;uses-permission android:name=\u0026#34;android.permission.READ_EXTERNAL_STORAGE\u0026#34;/\u0026gt; 6... We\u0026rsquo;ve got users permission and then we\u0026rsquo;ve got Android permission for read contacts, internet, and read external storage.\nSo those are the permissions this application can use (for this example). It doesnt mean that they are being used, but the application has the ability to use them if the user grants those permissions.\nSo every time the application wants to perform certain tasks like using your microphone, camera, or accessing your photos and stuff like that, those permissions need to be included in the AndroidManifest.xml right in the code.\nCustom Permissions Take a look at the code below. 5... 6 \u0026lt;permission android:label=\u0026#34;Allows reading user information\u0026#34; android:name=\u0026#34;com.apptesting.privacy.USER_INFO\u0026#34; android:protectionLevel=\u0026#34;dangerous\u0026#34;/\u0026gt; 7... As we remember, the three permissions before were predefined permissions, which are being used by this application, but this one is now defining its own permission. So the application can also define its own permission.\nStill on the same line, look below. 5... 6 \u0026lt;permission ... android:name=\u0026#34;com.apptesting.privacy.USER_INFO\u0026#34; ... /\u0026gt; 7... So we\u0026rsquo;ve got the name if you want to perform some sensitive task but want to share the task with other applications, they can ask for requesting this one, when you grant that permissions, then they can exchange data with each other.\nQueries This is an Android security feature that manages how applications share data, take a look at the code below. 6... 7 \u0026lt;queries\u0026gt; 8 \u0026lt;package android:name=\u0026#34;com.example.abcd/\u0026gt; 9 \u0026lt;/queries\u0026gt; 10... For an application to get information from another application, it must be visible first.\nSo, if the application wants to get data from the other application, for example \u0026lsquo;abcd\u0026rsquo; app, the application needs to introduce itself so the other application knows it exists on the phone. Once visible, the other application can recognize the request and send the data back.\nApplication Tags Inside the \u0026lt;application\u0026gt; tag, we can see some interesting stuff, take a look at the code below. 9... 10 \u0026lt;application android:allowBackup=\u0026#34;true\u0026#34; ... \u0026gt; 11... android:allowBackup=\u0026quot;true\u0026quot; means we can perform a backup, for example, by the ADB shell and the data of the application will be included. It doesn\u0026rsquo;t mean that they are sensitive information included in the backup like credentials or tokens or things like that. It just means that some data will be backup.\nNext, look below. 9... 10 \u0026lt;application ... android:debuggable=\u0026#34;true\u0026#34; ... \u0026gt; 11... We\u0026rsquo;ve got android:debuggable=\u0026quot;true\u0026quot;, means that having this feature enabled, we are allowed to attach to this process of this application. So we are allowed to debug it.\nIt\u0026rsquo;s not really often included, but even if it\u0026rsquo;s not being included in the AndroidManifest.xml, this file can be used to enable it. So the AndroidManifest.xml can be also used to enable certain features, for example debug features.\nNext, this is really important, look below. 9... 10 \u0026lt;application ... android:networkSecurityConfig=\u0026#34;@xml/network_security_config\u0026#34; ... \u0026gt; 11... We\u0026rsquo;ve got android:networkSecurityConfig=\u0026quot;@xml/network_security_config\u0026quot;, which points to an network_security_config.xml file that controls the app\u0026rsquo;s network trust policy.\nWhat is this one doing? It\u0026rsquo;s regarding to certificate pinning, so this file is pretty important when you are dealing with certificate pinning.\nNext, we have the four key components of an Android application which are activity, service, receiver, and provider. 10... 11 \u0026lt;provider android:authorities=\u0026#34;user\u0026#34; android:enabled=\u0026#34;true\u0026#34; android:exported=\u0026#34;true\u0026#34; android:name=\u0026#34;com.apptesting.privacy.UserDatabase\u0026#34;\u0026gt; 12 \u0026lt;path-permission android:path=\u0026#34;/User\u0026#34; android:readPermission=\u0026#34;com.apptesting.privacy.USER_INFO\u0026#34;/\u0026gt; 13 \u0026lt;/provider\u0026gt; 14 \u0026lt;receiver android:enabled=\u0026#34;true\u0026#34; android:exported=\u0026#34;true\u0026#34; android:name=\u0026#34;com.apptesting.privacy.WeatherNotification\u0026#34;/\u0026gt; 15 \u0026lt;service android:enabled=\u0026#34;true\u0026#34; android:exported=\u0026#34;true\u0026#34; android:name=\u0026#34;com.apptesting.privacy.MyService\u0026#34;/\u0026gt; 16 \u0026lt;activity android:name=\u0026#34;com.apptesting.privacy.Profile\u0026#34;/\u0026gt; 17 \u0026lt;activity android:name=\u0026#34;com.apptesting.privacy.MainActivity\u0026#34;\u0026gt; 18 \u0026lt;intent-filter\u0026gt; 19 \u0026lt;action android:name=\u0026#34;android.intent.action.MAIN\u0026#34;/\u0026gt; 20 \u0026lt;category android:name=\u0026#34;android.intent.category.LAUNCHER\u0026#34;/\u0026gt; 21 \u0026lt;/intent-filter\u0026gt; 22 \u0026lt;/activity\u0026gt; 23... Start with activity, take a look at the code below. 15... 16 \u0026lt;activity android:name=\u0026#34;com.apptesting.privacy.Profile\u0026#34;/\u0026gt; 17 \u0026lt;activity android:name=\u0026#34;com.apptesting.privacy.MainActivity\u0026#34;\u0026gt; 18 \u0026lt;intent-filter\u0026gt; 19 \u0026lt;action android:name=\u0026#34;android.intent.action.MAIN\u0026#34;/\u0026gt; 20 \u0026lt;category android:name=\u0026#34;android.intent.category.LAUNCHER\u0026#34;/\u0026gt; 21 \u0026lt;/intent-filter\u0026gt; 22 \u0026lt;/activity\u0026gt; 23... activity is basically the part of an Android application that you see and interact with. Each screen in an application is usually handled by an activity, like a home page or a profile page. It takes care of displaying the interface and responding to your actions such as tapping buttons or entering text.\nNext, service, take a look at the code below. 14... 15 \u0026lt;service android:enabled=\u0026#34;true\u0026#34; android:exported=\u0026#34;true\u0026#34; android:name=\u0026#34;com.apptesting.privacy.MyService\u0026#34;/\u0026gt; 16... service is a component that runs in the background without a user interface. Basically this is a background task. So this help the application keep responsive by offloading work from the main thread.\nNext, reciever, look at the code below. 13... 14 \u0026lt;receiver android:enabled=\u0026#34;true\u0026#34; android:exported=\u0026#34;true\u0026#34; android:name=\u0026#34;com.apptesting.privacy.WeatherNotification\u0026#34;/\u0026gt; 15... reciever is simply just an information for applications. For example, let\u0026rsquo;s say we are receiving an SMS, then we\u0026rsquo;ve got the notification, the audio notification, and also the pop up on the screen that we have received new SMS, and also applications will be informed about that SMS has been received. So this is simply just messaging system.\nNext, provider, take a look at the code below. 10... 11 \u0026lt;provider android:authorities=\u0026#34;user\u0026#34; android:enabled=\u0026#34;true\u0026#34; android:exported=\u0026#34;true\u0026#34; android:name=\u0026#34;com.apptesting.privacy.UserDatabase\u0026#34;\u0026gt; 12 \u0026lt;path-permission android:path=\u0026#34;/User\u0026#34; android:readPermission=\u0026#34;com.apptesting.privacy.USER_INFO\u0026#34;/\u0026gt; 13 \u0026lt;/provider\u0026gt; 14... provider is simply just the form of interacting or providing content. Most of the time this is regarding to database accesses. So the application might use a database where it store some information.\nIf a pathPermission is enabled, external applications might be able to read the database if they have the right permission.\nSummary I wanna take a nap rn\u0026hellip; goodbye, i’ll correct it later if there’s any incorrect information T_T\n","date":"2026-04-05T00:00:00Z","permalink":"/p/androidmanifestxml/","title":"AndroidManifest.xml"},{"content":"Reverse Engineering What is Reverse Engineering? Reverse engineering (RE) in computer science is the process of analyzing a compiled, binary application to understand its inner workings, logic, and structure without access to the original source code. In Capture The Flag (CTF) competitions, it involves breaking down software to uncover hidden flags, bypass licensing, or analyze malware, typically using tools like debuggers and disassemblers.\nSega Saturn In this challenge, as we can see on the main page that there is a text and the flag which is actually a fake flag, the text is telling that \u0026ldquo;Sega Saturn should be able to Solve this\u0026rdquo;\nAfter I checked the source code, I discovered an algorithm which is the implementation of LCG standard (Linear Congruential Generator). 17... 18function RNG(seed) { 19 return function() { 20 seed = (seed * 48271) % 2147483647; 21 return seed; 22 }; 23} 24...\nAnd I also discovered an array named seq contains series of integers. 27... 28 const seq = [697438994, 112812148, 1601952528, 848567091, 1409540622, 719284623, 4183535244, 2852213902, 2109397207, 3611470734, 604567242, 1692610300, 2414225221, 1979551723, 3174382114, 425190723, 1060279654, 4283219352, 1099139615, 3427871953, 2056419824, 103242998, 2789231820, 97749902, 3832000502, 2437931514, 337329827, 1784389836, 1971115025, 2430188600, 420768160, 2890064672, 3927353914, 2033350795, 372941141, 2974609317, 1442092933, 2838369745, 3198352587, 230640255, 2641503210, 1721308159, 3764390994]; 29...\nAs we remember on the main page there is a hint, namely \u0026ldquo;Sega Saturn\u0026rdquo; which is indicated 32-bit architechture.\nThe Sega Saturn (セガサターン, Sega Satān) is a 32-bit video game console first released by Sega on November 22, 1994 in Japan, May 11, 1995 in North America, and July 8, 1995 in Europe. It was discontinued in 1998 in North America, Europe, and Australia, and in 2000 in Japan.\nSource: Wikipedia\nIn computer science, signed 32-bit integer has range of data up to $2^{31} - 1$. we know that we need to find each elements of array seq for 32-bit data structure. In the source code before, I saw 1 line which is a little bit crucial. 38... 39 const big = (x \u0026lt;\u0026lt; 24) | (rng() \u0026amp; 0xFFFFFF); 40...\nfrom this one line, I discovered:\nBit 31-24 (MSB) x \u0026laquo; 24 shifting encrypted characters to the leftmost 8-bit. Bit 23-0 (LSB) rng() \u0026amp; 0xFFFFFF will have an output from LCG, then conduct AND operation with 0xFFFFFF (equals to 24-bit), then placed in the rightmost 24-bit. Bitwise (|) then the two segments before are combined. I have known that the creator of this challenge leaks the raw internal state in the lowest 24-bit (right side). From here i have an access to $S_{n+1}$ from 24-bit which has been leaked, then i need to find the $S_{n}$ (initial seed).\nThe LCG worked in 31-bit space before, but there is 24-bit leaked, it means 7-bit is missing (MSB from RNG state). So, i just need to do recovery state as many as 128 iterations.\nHow? so we need the reverse operation of modular multiplication, which is modular multiplicative inverse.\nIf $S_{n+1} \\equiv (S_n \\cdot a) \\pmod{m}$, so $S_n \\equiv (S_{n+1} \\cdot a^{-1}) \\pmod{m}$ which $a^{-1}$ is modular invers from 48271 to 2147483647.\nWith Python, we can calculate $a^{-1}$ using the following Python script: 10... 11MODULUS = 2147483647 12MULTIPLIER = 48271 13 14INVERSE_MULTIPLIER = pow(MULTIPLIER, -1, MODULUS) 15...\nTo determine the initial seed, I\u0026rsquo;m using the following Python script: 1seq = [ 2 697438994, 112812148, 1601952528, 848567091, 1409540622, 719284623, 4183535244, 3 2852213902, 2109397207, 3611470734, 604567242, 1692610300, 2414225221, 1979551723, 4 3174382114, 425190723, 1060279654, 4283219352, 1099139615, 3427871953, 2056419824, 5 103242998, 2789231820, 97749902, 3832000502, 2437931514, 337329827, 1784389836, 6 1971115025, 2430188600, 420768160, 2890064672, 3927353914, 2033350795, 372941141, 7 2974609317, 1442092933, 2838369745, 3198352587, 230640255, 2641503210, 1721308159, 8 3764390994 9] 10 11MODULUS = 2147483647 12MULTIPLIER = 48271 13 14INVERSE_MULTIPLIER = pow(MULTIPLIER, -1, MODULUS) 15 16leak_lsb = seq[0] \u0026amp; 0xFFFFFF 17recovered_seed = None 18 19for high_bits in range(128): 20 potential_state_curr = (high_bits \u0026lt;\u0026lt; 24) | leak_lsb 21 if potential_state_curr \u0026gt;= MODULUS: 22 continue 23 24 s_prev_1 = (potential_state_curr * INVERSE_MULTIPLIER) % MODULUS 25 s_prev_2 = (s_prev_1 * INVERSE_MULTIPLIER) % MODULUS 26 seed_candidate = (s_prev_2 * INVERSE_MULTIPLIER) % MODULUS 27 28 test_state = seed_candidate 29 for _ in range(6): 30 test_state = (test_state * MULTIPLIER) % MODULUS 31 32 if (test_state \u0026amp; 0xFFFFFF) == (seq[1] \u0026amp; 0xFFFFFF): 33 recovered_seed = seed_candidate 34 break 35...\nAfter the seed has discovered (313374141), i conduct the decryption process using the following Python script: 35... 36def nibble_swap(byte_input): 37 return ((byte_input \u0026amp; 0x0F) \u0026lt;\u0026lt; 4) | ((byte_input \u0026amp; 0xF0) \u0026gt;\u0026gt; 4) 38 39plaintext = \u0026#34;\u0026#34; 40current_rng_state = recovered_seed 41 42for packed_int in seq: 43 r1 = (current_rng_state * MULTIPLIER) % MODULUS 44 r2 = (r1 * MULTIPLIER) % MODULUS 45 r3 = (r2 * MULTIPLIER) % MODULUS 46 current_rng_state = r3 47 48 encrypted_byte = (packed_int \u0026gt;\u0026gt; 24) \u0026amp; 0xFF 49 encrypted_byte ^= (r2 \u0026amp; 0xFF) 50 encrypted_byte = nibble_swap(encrypted_byte) 51 52 adjustment = (r1 % 93) + 33 53 decrypted_char_code = (encrypted_byte - adjustment) % 256 54 plaintext += chr(decrypted_char_code) 55 56print(plaintext)\ncela@hugo:~$ python3 segasaturn.py\ncyberwave{c4n_yoU_5olV3_th1s_l1f3_eQu4t10n}\nGrogol In this challenge I was asked to enter the right input.\ncela@hugo:~$ nc 129.226.145.210 317\nInput \u0026gt; abcdefg\nabcdefg\nYour input is inc0rr3ct!\nAfter decompiling the main function (FUN_000103aa), I found that the program limits input to no more than 21 characters. 34... 35lVar6 = FUN_000120f6(auStack_1078,0x1000,PTR_DAT_00088590); 36if (lVar6 != 0) { 37 uVar7 = FUN_0001cc2a(auStack_1078); 38 if (uVar7 \u0026lt; 0x16) { 39...\nThen the program does not process the input as a whole, but breaks it down into a word (let\u0026rsquo;s say token) separated by space. the program takes the first token and stores it in an array pointer, then takes the next token. 37... 38 if (uVar7 \u0026lt; 0x16) { 39 pbVar8 = (byte *)FUN_0001d348(auStack_1078,\u0026amp;DAT_00057e98); 40 if (pbVar8 == (byte *)0x0) { 41 lVar6 = 0; 42 } 43 else { 44 ppbVar17 = local_3078; 45 lVar6 = 0; 46 do { 47 *ppbVar17 = pbVar8; 48 lVar6 = (long)((int)lVar6 + 1); 49 pbVar8 = (byte *)FUN_0001d348(0,\u0026amp;DAT_00057e98); 50 if (pbVar8 == (byte *)0x0) break; 51 ppbVar17 = ppbVar17 + 1; 52 } while (lVar6 != 0x3ff); 53 } 54...\nEach token found is calculated for its checksum value. so the program here initialises hash = 1, then performs XOR and Bit-Shift. 66... 67 if (*local_3078[0] != 0) { 68 uVar7 = 1; 69 pbVar8 = local_3078[0]; 70 do { 71 pbVar19 = pbVar8 + (1 - (long)local_3078[0]); 72 *puVar16 = (long)uVar7 \u0026gt;\u0026gt; 1; 73 *(byte **)(gp + -0x7b8) = pbVar19; 74 bVar1 = *pbVar8; 75 pbVar8 = pbVar8 + 1; 76 uVar7 = (ulong)bVar1 ^ (long)uVar7 \u0026gt;\u0026gt; 1; 77 *puVar16 = uVar7; 78 } while (*pbVar8 != 0); 79...\nThen there is the checksum formula. 78... 79 if (((long)(int)(((uint)*local_3078[0] ^ (uint)pbVar19) \u0026lt;\u0026lt; 4) \u0026amp; 0xffU | uVar7 \u0026amp; 0xf) = = 80 0x10) { 81...\nHere I used Gemini (im too lazy ehe) to map the checksum and found the final target, which was 31337.\nConditions (Hex) Ghidra Code Operation 0x11 lVar10 = lVar10 + 3 Add 3 0xf2 lVar10 = lVar10 * 100 Multiply by 100 0xce lVar10 = lVar10 + 13 Add 13 0x27 lVar10 = lVar10 + 30 Add 30 0x6a lVar10 = lVar10 + 7 Add 7 0x7a69 if (stack == 0x7a69) Final Target (31337) Our goal is to reach the number 31337. Here, we use the following logical calculation:\n$((3 \\times 100) + 13) \\times 100 + 30 + 7 = 31337$\nThen I used python to bruteforce the ASCII character to find some sort strings (1-2 chr) that matched the target checksum. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import string def calculate_checksum(s): length = len(s) first_char = ord(s[0]) h = 1 for char in s: h = ord(char) ^ (h \u0026gt;\u0026gt; 1) res = (((first_char ^ length) \u0026lt;\u0026lt; 4) \u0026amp; 0xFF) | (h \u0026amp; 0xF) return res targets = { 0x11: \u0026#34;add_3\u0026#34;, 0xf2: \u0026#34;mul_100\u0026#34;, 0xce: \u0026#34;add_13\u0026#34;, 0x27: \u0026#34;add_30\u0026#34;, 0x6a: \u0026#34;add_7\u0026#34; } chars = string.ascii_letters + string.digits print(f\u0026#34;{\u0026#39;Token\u0026#39;:\u0026lt;8} | {\u0026#39;Hex\u0026#39;:\u0026lt;6} | {\u0026#39;Operation\u0026#39;}\u0026#34;) for c1 in chars: for c2 in chars: word = c1 + c2 chk = calculate_checksum(word) if chk in targets: print(f\u0026#34;{word:\u0026lt;8} | {hex(chk):\u0026lt;6} | {targets[chk]}\u0026#34;) del targets[chk] So here we get the output:\nToken Hex Operation cp 0x11 add_3 dh 0x6a add_7 md 0xf2 mul_100 ni 0xce add_13 po 0x27 add_30 Here we get the tokens that we have to input:\n$((cp \\times md) + ni) \\times md + po + dh = 31337$\ncela@hugo:~$ nc 129.226.145.210 317\nInput \u0026gt; cp md ni md po dh\ncp md ni md po dh\ncyberwave{belajar_rev_di_google_aja}\nKeygenMe In this challenge I was asked to enter username and license key.\ncela@hugo:~$ ./cyberwave_keygenme\nUsername: test\nLicense Key: test\nAccess Denied!\nAfter decompiling the main function (FUN_00101080), I found the variable local_128 for username input and the variable local_a8 for license key input. 28... 29printf(\u0026#34;Username: \u0026#34;); 30pcVar7 = fgets((char *)local_128,0x80,stdin); 31... 32 printf(\u0026#34;License key: \u0026#34;); 33 pcVar7 = fgets(local_a8,0x80,stdin); 34...\nAnd it was also found that the local_a8 input must be 19 characters long with the prefix \u0026ldquo;CW25\u0026rdquo; and a dash (-) check at a specific index, indicating that the format for the license key is:\nCW25-xxxx-xxxx-xxxx\n37... 38 if ((((((sVar8 - 1 \u0026lt; 0x20) \u0026amp;\u0026amp; (sVar9 = strlen(local_a8), 39 sVar9 == 0x13 40 )) \u0026amp;\u0026amp; (local_a4 == \u0026#39;-\u0026#39;)) \u0026amp;\u0026amp; ((local_a3[4] == \u0026#39;-\u0026#39; \u0026amp;\u0026amp; (local_a3[9] == \u0026#39;-\u0026#39;)))) \u0026amp;\u0026amp; (( 41 local_a8[0] == \u0026#39;C\u0026#39; 42 \u0026amp;\u0026amp; (( 43 local_a8[1] == \u0026#39;W\u0026#39; 44 \u0026amp;\u0026amp; ( 45 local_a8[2] == \u0026#39;2\u0026#39; 46 )))))) \u0026amp;\u0026amp; ( 47 local_a8[3] == \u0026#39;5\u0026#39; 48 )) { 49 uVar10 = 5; 50...\nThen, each of the three ‘XXXX’ is split into three parts and stored in their respective variables. 55... 56 local_162 = 0; 57 local_160 = (code *)((ulong)local_160 \u0026amp; 0xffffffffffff0000); 58 local_158[0] = 0; 59...\nThe program here performs the first loop at local_128. The loop runs by reading each byte from local_128 (username). 62... 63 uVar6 = 0x31415926; 64 pbVar14 = local_128; 65 while( true ) { 66 bVar2 = *pbVar14; 67 pbVar14 = pbVar14 + 1; 68 if (bVar2 == 0) break; 69 uVar6 = (uint)bVar2 + uVar6 * 0x21; 70 uVar6 = (uVar6 * 0x80 | uVar6 \u0026gt;\u0026gt; 0x19) ^ uVar6; 71 } 72...\nIn order for the program to print \u0026ldquo;Access Granted\u0026rdquo;, the input on local_a8 (license key) which is split into local_162, local_160, local_158 must meet the following conditions. 88... 89 if (((local_162 == (ushort)((ushort)uVar6 ^ (ushort)uVar11)) \u0026amp;\u0026amp; 90 ((ushort)local_160 == 91 (ushort)(((ushort)(uVar6 \u0026lt;\u0026lt; 0xb) | (ushort)(uVar6 \u0026gt;\u0026gt; 0x15)) ^ (ushort)(uVar11 \u0026gt;\u0026gt; 5) 92 ^ 0xbeef))) \u0026amp;\u0026amp; 93 (local_158[0] == (ushort)((ushort)uVar6 * 3 + (short)(uVar11 \u0026gt;\u0026gt; 9) ^ 0xc0de))) { 94 puts(\u0026#34;Access Granted!\u0026#34;); 95...\nThen I used this Python script to solve this challenge. 1def generate_key(username): 2 name_bytes = username.encode(\u0026#39;ascii\u0026#39;) 3 length = len(name_bytes) 4 5 uVar6_initial = 0x31415926 6 for b in name_bytes: 7 uVar6_initial = (b + uVar6_initial * 0x21) \u0026amp; 0xFFFFFFFF 8 uVar6_initial = ((uVar6_initial \u0026lt;\u0026lt; 7 | uVar6_initial \u0026gt;\u0026gt; 25) \u0026amp; 0xFFFFFFFF) ^ uVar6_initial 9 10 uVar11 = 0xa53c9e17 11 uVar6 = 0xc0ffee25 12 13 for b in name_bytes: 14 uVar6 = (uVar6 * 0x101 + b) \u0026amp; 0xFFFFFFFF 15 uVar6 = ((uVar6 \u0026lt;\u0026lt; 5 | uVar6 \u0026gt;\u0026gt; 27) \u0026amp; 0xFFFFFFFF) ^ 0xa5c3d2e1 16 uVar11 = (((uVar6 \u0026gt;\u0026gt; 3 ^ (b * 0x1f + uVar11) \u0026amp; 0xFFFFFFFF) * 0x11) + 0x3d) \u0026amp; 0xFFFFFFFF 17 18 uVar6 = ((length * 0x27d4eb2d) ^ uVar6) \u0026amp; 0xFFFFFFFF 19 uVar11 = ((uVar6 \u0026lt;\u0026lt; 13 | uVar6 \u0026gt;\u0026gt; 19) \u0026amp; 0xFFFFFFFF) ^ uVar11 20 21 part1 = (uVar6 ^ uVar11) \u0026amp; 0xFFFF 22 23 rot_uVar6 = (uVar6 \u0026lt;\u0026lt; 11 | uVar6 \u0026gt;\u0026gt; 21) \u0026amp; 0xFFFF 24 part2 = (rot_uVar6 ^ (uVar11 \u0026gt;\u0026gt; 5) ^ 0xbeef) \u0026amp; 0xFFFF 25 26 part3 = ((uVar6 * 3 + (uVar11 \u0026gt;\u0026gt; 9)) ^ 0xc0de) \u0026amp; 0xFFFF 27 28 return f\u0026#34;CW25-{part1:04X}-{part2:04X}-{part3:04X}\u0026#34; 29 30user = input(\u0026#34;Enter Username: \u0026#34;) 31key = generate_key(user) 32print(f\u0026#34;License Key: {key}\u0026#34;)\nSo here we get the output:\ncela@hugo:~$ python3 keygenme.py\nEnter Username: cela\nLicense Key: CW25-4FA0-A1AA-8D7A\nThen I tried entering the same username and license key.\ncela@hugo:~$ ./cyberwave_keygenme\nEnter Username: cela\nLicense Key: CW25-4FA0-A1AA-8D7A\nAccess Granted!\ncyberwave{keygenme_easy_medium_2025}\n","date":"2026-01-11T00:00:00Z","permalink":"/p/cyberwave2025/","title":"CyberWave 2025!"}]