class=”markdown_views prism-atom-one-dark”>
One environment
Mobile phone: Pixel 1
System: Android 8.1
Software: IDA 7.5, JADX
Difficulty: Easy
apk resources
Link: https://pan.baidu.com/ s/1iEBK__qeWKQAg9KFVraskA
Extraction code: jn3p
Second analysis process
1. Open and click Freedom and Justice Share, then click Register, you will enter the registration interface
2. Enter 1122334455667, then click Register, click OK to exit the APP (click anywhere outside the dialog box, it will not exit APP)
3. Open JADX, search for “your registration code has been saved”, and then see the key saveSN
4. Viewed three native methods
5. First check that the initSN method is only initialized in onCreate of this class, and search for the place where the MyApp class is initialized in JADX
6. Find the key judgment value MyApp.m (Figure 1), search for references and find no value assignment (Figure 2), then it may be in SO, plus APP initialization to judge, indicating the initSN method of MyApp.m assignment
figure 1
figure 2
7. Open IDA, import SO, open the export table and search for initSN, but find nothing, indicating that it is dynamically registered in JNI_OnLoad
8. View JNI_OnLoad, and import jni.h file, view off_5004
9. Check n1 first, simply read the “/sdcard/reg.dat” file (since the file is stored in the SD card, you need to give the APP storage permission), and read the characters in the file string, and compare it with “EoPAoY62@ElRD”
10. Set the result to MyApp.m through setValue, then find the key key “EoPAoY62@ElRD”
11. View n2 (JAVA layer saveSN) in the dynamic registration, which is divided into three parts:
1. Initialize the string used for encryption;
2. XOR characters;
3. Write /sdcard/reg.dat file
12 Part 1: The string used for initializing encryption is obviously fixed from the pseudo-code, and there is no anti-debugging, so direct IDA, dynamic debugging (the place where the breakpoint is placed is shown in Figure 1)
figure 1
figure 2
13. The second part: the encryption algorithm is very simple, the implemented JAVA code
public static String myEncrpt_CTF(String input){
char[]table={
0x57,0x33,0x5F,0x61,0x72,0x45,0x5F,0x77,0x68,0x4F, 0x5F,0x77,0x65,0x5F,0x41,0x52,0x45,0x00};
char[]result=new char[input .length() ];
int table_index=2016;
char table_item=0;
for (int i = 0; i input.length() ; i++) {
if(i%3==1) {
table_index=(table_index+5)%16 ;
table_item=table[table_index+1];
}else if(i%3== 2){
table_index=(table_index+7)%15 ;
table_item=table[table_index+2];
}else{
table_index=(table_index+3)%13 ;
table_item=table[table_index+3];
}
result[i]= (char) ( input.charAt(i)^table_item);
}
return new String(result);
}
14. Because the generation of table_item has nothing to do with the plaintext, plus the XOR at the end, it shows that the ciphertext is passed in, and the plaintext is returned
System.out.println(myEncrpt_CTF("EoPAoY62@ElRD"));
201608Am!2333
15. Enter the correct flag, re-enter the app, and submit according to the specified format xman{201608Am!2333}! Just submit, but this is a competition app from a long time ago, so it’s fine as a sign of success
class=”token operator”>+2];
}else{
table_index=(table_index+3)%13 ;
table_item=table[table_index+3];
}
result[i]= (char) ( input.charAt(i)^table_item);
}
return new String(result);
}
14. Because the generation of table_item has nothing to do with the plaintext, plus the XOR at the end, it shows that the ciphertext is passed in, and the plaintext is returned
System.out.println(myEncrpt_CTF("EoPAoY62@ElRD"));
201608Am!2333
15. Enter the correct flag, re-enter the app, and submit according to the specified format xman{201608Am!2333}! Just submit, but this is a competition app from a long time ago, so it’s fine as a sign of success