Record the cracking of a mobile game app data file and game app data cracking
Due to some complicated needs, I also wanted to make some fresh attempts. On the weekend, I spent more than half a day cracking the data files of a mobile game.
The process is better than I expected, mainly because our developers are slack and Keke.
The process is as follows:
- Download the installation package, decompress the package, and find several XXX. db files. The most interesting is a XXX. db with over 50 MB of data.
- You can use UltraEdit to open the XXX. DB file without any clue. Only these files have the same file header.
- Searching for. DB files may be what files, and discovering the Open Source library sqlite is a lightweight database component, which is used by IOS.
- Download the sqlite command line tool and find that the. DB file cannot be opened.
- I saved an sqlite database file for testing and found that it was stored in plaintext.
- It's time to sacrifice IDA pro, disassemble libXXX. so, and find a large number of sqlite3_XXX functions. The. db file should be an sqlite database file.
- Search for information related to sqlite encryption. The official encryption implementation requires authorization, but there is an open source implementation of wxsqlite. I guess the app uses wxsqlite
- Wxsqlite is encrypted by the AES algorithm. The key must be found. Otherwise, it cannot be decrypted.
- Continue to look at the disassembly, find the keySqlite function, and find that the key is written in plain text in the Code. It is a string of 1..., amount
- Download wxsqlite, write several lines of code for testing, and find that it still cannot be opened. I created an encrypted database file and found that it is very different from the db file of the app.
- Read the wxsqlite code and find that the encryption algorithm is called in the sqlite3Codec function. Find sqlite3Codec in the Assembly and find that it calls a My_Encrypt_Func (haha)
- Read the assembly code of My_Encrypt_Func and find that it is reversed by byte (heheh)
- Write a small program to reverse the db file by byte. Use UltraEdit to open the file and view the plain text information.
- This time, the data file can be opened using the sqlite command line. dump the file into a txt file to obtain the table structure and all the data.
- The last is the database file of more than 50 MB. The output table structure shows a string name and a binary object. Write a small program to traverse all table items and save binary objects as png files. Task completed
Gains:
- If wxsqlite is used for encryption and the key is obtained through the network, you must first hook the api to intercept the key at runtime. The difficulty of cracking will increase...
- The arm assembly of the encryption function seems very inefficient... so strange to me. After writing a piece of the same Code, I made it myself and found that the lib is debug. This ....
- The function names related to encryption are very dangerous to be exposed in the dynamic library. When the static and export symbol tables are added to the function declaration, we can only see one address jump.
The de-compiled encryption function is the same as the one written by myself and compiled with debug.
.text:002C46E0 EXPORT My_Encrypt_Func.text:002C46E0 My_Encrypt_Func ; CODE XREF: sqlite3Codec+11Cp.text:002C46E0 ; sqlite3Codec+190p.text:002C46E0.text:002C46E0 var_3C = -0x3C.text:002C46E0 var_38 = -0x38.text:002C46E0 var_34 = -0x34.text:002C46E0 var_30 = -0x30.text:002C46E0 var_28 = -0x28.text:002C46E0 var_20 = -0x20.text:002C46E0 var_4 = -4.text:002C46E0.text:002C46E0 STR R11, [SP,#var_4]!.text:002C46E4 ADD R11, SP, #4+var_4.text:002C46E8 SUB SP, SP, #0x1C.text:002C46EC STR R0, [R11,#0x20+var_30].text:002C46F0 STR R1, [R11,#0x20+var_34].text:002C46F4 STR R2, [R11,#0x20+var_38].text:002C46F8 STR R3, [R11,#0x20+var_3C].text:002C46FC MOV R3, #0.text:002C4700 STR R3, [R11,#0x20+var_28].text:002C4704 B loc_2C473C.text:002C4708 ; ---------------------------------------------------------------------------.text:002C4708.text:002C4708 loc_2C4708 ; CODE XREF: My_Encrypt_Func+68j.text:002C4708 LDR R3, [R11,#-0x10].text:002C470C LDRB R3, [R3].text:002C4710 MVN R3, R3.text:002C4714 STRB R3, [R11,#-9].text:002C4718 LDR R3, [R11,#-0x10].text:002C471C LDRB R2, [R11,#-9].text:002C4720 STRB R2, [R3].text:002C4724 LDR R3, [R11,#-0x10].text:002C4728 ADD R3, R3, #1.text:002C472C STR R3, [R11,#-0x10].text:002C4730 LDR R3, [R11,#-8].text:002C4734 ADD R3, R3, #1.text:002C4738 STR R3, [R11,#-8].text:002C473C.text:002C473C loc_2C473C ; CODE XREF: My_Encrypt_Func+24j.text:002C473C LDR R2, [R11,#-8].text:002C4740 LDR R3, [R11,#-0x14].text:002C4744 CMP R2, R3.text:002C4748 BCC loc_2C4708.text:002C474C MOV R3, #0.text:002C4750 MOV R0, R3.text:002C4754 SUB SP, R11, #0.text:002C4758 LDR R11, [SP+0x20+var_20],#4.text:002C475C BX LR.text:002C475C ; End of function My_Encrypt_Func
With release compilation, the running efficiency is dozens of times lower.
.text:00001D88 ; My_Encrypt_Func(unsigned char *, unsigned int, unsigned char *, unsigned int).text:00001D88 EXPORT _Z15My_Encrypt_FuncPhjS_j.text:00001D88 _Z15My_Encrypt_FuncPhjS_j.text:00001D88 MOVS R3, #0.text:00001D8A B loc_1D94.text:00001D8C ; ---------------------------------------------------------------------------.text:00001D8C.text:00001D8C loc_1D8C ; CODE XREF: My_Encrypt_Func(uchar *,uint,uchar *,uint)+Ej.text:00001D8C LDRB R2, [R0,R3].text:00001D8E MVNS R2, R2.text:00001D90 STRB R2, [R0,R3].text:00001D92 ADDS R3, #1.text:00001D94.text:00001D94 loc_1D94 ; CODE XREF: My_Encrypt_Func(uchar *,uint,uchar *,uint)+2j.text:00001D94 CMP R3, R1.text:00001D96 BNE loc_1D8C.text:00001D98 MOVS R0, #0.text:00001D9A BX LR.text:00001D9A ; End of function My_Encrypt_Func(uchar *,uint,uchar *,uint)