Actual app - analyze and restore the interface algorithm

Keywords: Python Algorithm

Shelling

Because I analyzed the app in advance, I shelled it first.
Run ADB shell dumpsys activities | grep mresumedactivity to obtain a current activity

Then use friddex_ After dump is shelled, it is filtered, and grep -ril "PassWordLoginActivity" gets the dex file we want

Grab bag

Firstly, packet capture analysis is carried out, taking the login interface as an example

Use r0capture to capture packets, run python r0capture.py -U com.caratlover -p kllr.pcap, save it to the pcap file, and open it with wireshark for analysis. You can see that the body of the post is encrypted

analysis

Open it with jadx and search with the fields in headers to see if you find anything.
To GPS_ For city search, there is only one result. Follow up and check. It is basically the field in the headers. It is likely to locate the code location

Go straight to the back to see what this method does and follow up on method cMethod c calls method b again. Obviously, AES encryption, that f87210e0ed3079d8 is the key

After the analysis, we have to prove whether our conjecture is right or not, and use object to hook

Using object

hook the c method just now. You can see that the parameters are the mobile phone number and password filled in, so you do go through this method. Comparing the packets just caught, we can find that the encrypted one is the body

Restore body

Go back to the analysis b method and analyze how it is encrypted

To prove the correctness of the analysis, you can https://chinabaiker.com/cyberchef.htm Conduct operation comparison. You can see that it is the same. The body part is solved, and then analyze the fields in the headers.

Analyze headers

The code is confused. You can probably guess that the a method should add a request header such as addheader. What has been added to a from top to bottom

You can see that these fields are added to the header first. Like the requested fields, the values of the following fields can be basically fixed.

The remaining fields can be analyzed according to the code, or you can guess the general meaning according to its fields

In order to prove the conjecture, base64 is decoded

I'll just show one. The others are the same

Simulation request

The body and headers are almost analyzed. Try simulating the request

import base64
from Crypto.Cipher import AES
import requests
import time

'''
use AES Symmetric encryption algorithm
'''
# If str is not a multiple of 32, make it a multiple of 16
def add_to_32(value):
    while len(value) % 32 != 0:
        value += '\0'
    return str.encode(value)  # Return bytes
 
def add_to_16(value):
    while len(value) % 16 != 0:
        value += '\0'
    return str.encode(value)  # Return bytes
 
#Encryption method
def encrypt_oracle(text):
    # Secret key
    key = 'f87210e0ed3079d8'
    # Text to be encrypted
    # Initialize encryptor
    aes = AES.new(add_to_16(key), AES.MODE_ECB)
    #aes encryption first
    encrypt_aes = aes.encrypt(add_to_16(text))
    #Convert to string form with base64
    encrypted_text = str(base64.encodebytes(encrypt_aes), encoding='utf-8')  # Perform encryption and transcode to return bytes
    # print(encrypted_text)
    return encrypted_text
#Decryption method
def decrypt_oralce(text):
    # Secret key
    key = 'f87210e0ed3079d8'
    # ciphertext
    # Initialize encryptor
    aes = AES.new(add_to_16(key), AES.MODE_ECB)
    #Priority reverse decryption base64 into bytes
    base64_decrypted = base64.decodebytes(text.encode(encoding='utf-8'))
    #Perform decryption and transcoding to return str
    decrypted_text = str(aes.decrypt(base64_decrypted),encoding='utf-8').replace('\0','')
    # print('decrypted_text',decrypted_text)
    return decrypted_text
 
if __name__ == '__main__':

    text = '{"verifyValue":"123456","openInvite":"","phoneNumber":"12345678910","verifyMode":"2","openChannel":""}'
    entrypted_text = encrypt_oracle(text)
 
    url = "http://uc.pairui1.com:8668/auth/login"
    headers = {
        "device_system": "8.1.0",
        "device_name": "aos",
        "device_model": "Nexus 6P",
        "device_brand": "google",
        "package_name": "com.caratlover",
        "imei": "867686020207104",
        "api_version": "4600",
        "client_version": "4600",
        "post_time": str(int(time.time())),
        "app_market": "uc",
        "oaid": "",
        "mac": "A0:8D:16:F3:87:76",
        "gps": "",
        "gps_city": "",
        "gps_province": "",
        "area": "",
        "township": "",
        "number": "",
        "Content-Type": "text/plain; charset=utf-8",
        "Host": "uc.pairui1.com:8668",
        "Connection": "Keep-Alive",
        "Accept-Encoding": "gzip",
        "User-Agent": "okhttp/3.12.0",
    }

    response = requests.post(url, data=entrypted_text, headers=headers)

    # print(response.status_code)
    # print(response.text)

    print(decrypt_oralce(response.text))

You can see that the request has been sent successfully. If you have registered an account, you can test it.

Posted by Roggan on Wed, 01 Sep 2021 18:37:49 -0700