Restoration of APP Encryption and Signature Algorithms

Restoration of APP Encryption and Signature Algorithms

This article is an excellent piece from the KX forum.

KX forum author ID: taobluesky

Recently encountered a shell with quite high intensity, sharing how to debug with the shell, purely a technical exchange, please do not use this article for illegal purposes!
1


Prepare Environment


frida 12.11.18 jeb-3.24 jadx-gui-1.3.3-1 xcube android 7.0 (real machine)
Here’s why you must use a real machine: this shell has an emulator detection, and this app does not compile x86 instructions in its so, so it cannot run on an x86 emulator at all. Let’s get straight to the point.
2


Initial Exploration


Attach the HTTP proxy and try to intercept traffic; the client directly reports an SSL certificate error, clearly indicating some form of SSL pinning validation.jadx loads the apk, manifest parsing fails, then pull in jeb for analysis.
Restoration of APP Encryption and Signature AlgorithmsHas anyone encountered the shell of com.vdog.VDogApplication? If you know, please enlighten me on what this shell is! I took a rough look at the Java part of the shell’s code:Restoration of APP Encryption and Signature Algorithms
The shell restored the ELF file header, which is not novel; just manually restore the first four bytes of the so to .ELF.Restoration of APP Encryption and Signature Algorithms
Then I pulled libvdog-x86.so into IDA for disassembly. The result is that this so is obfuscated quite beautifully; I tried several deobfuscation scripts but to no avail, so I temporarily do not wish to analyze this shell anymore.
So what’s next? I thought of a method to dump the dex first, then use frida for dynamic injection debugging.Restoration of APP Encryption and Signature AlgorithmsThen as expected, there was code to detect frida; once spawn or attach, the app’s process immediately terminates.
[FRD AL00::com.**.*****]-> Process terminated[FRD AL00::com.**.*****]->
Next, I used xcube to load the script and found it feasible. Well, let’s first use FDex2 to dump the dex, a total of 7 dex were dumped.Restoration of APP Encryption and Signature Algorithms
3


Official Start


First step is to break through the HTTP packet capture problem, using fiddler to capture packets, seeing the HTTPS handshake request User-Agent: okhttp/4.9.1, confirming that the okhttp library is used.
After trying several SSL unpinning scripts with no results, I analyzed the okhttp/4.9.1 library and found an issue with the script provided online: the second parameter of CertificatePinner.check$okhttp’s overload is incorrect, and since this method is not overloaded, I directly removed the overload. Here’s an SSL unpinning script usable for okhttp 4.9.1:
// okhttp4try {    var CertificatePinner = Java.use('okhttp3.CertificatePinner');     CertificatePinner.check.overload('java.lang.String', 'java.util.List').implementation = function(str) {        writeFile('! Intercepted okhttp4 in [check()]: ' + str);        return;    };     try {//.overload('java.lang.String', 'kotlin.jvm.functions.Function0')        CertificatePinner.check$okhttp.implementation = function(str, _) {            writeFile('! Intercepted okhttp4 in [check$okhttp]: ' + str);            return;        };    } catch (ex) {        writeFile("is this Okhttp3 ?!");    }    writeFile('* Setup okhttp4 pinning')} catch (err) {    writeFile('* Unable to hook into okhttp4 pinner')    writeFile(err);}
After testing, I successfully captured packets; below is the request body for the login interface:Restoration of APP Encryption and Signature AlgorithmsYou can see that the password for the login interface is encrypted, along with the sign field. First, look for the key code for password encryption as follows:Restoration of APP Encryption and Signature AlgorithmsThen follow up:Restoration of APP Encryption and Signature AlgorithmsUsing RSA to encrypt the password, this unnamed method is a brilliant injection point; here’s the script to obtain the public key:
// Password encryption: output RSA's pubkeyvar this3 = Java.use("com.**.*****.encrypt.this3");this3.unname.implementation = function(str, str2){    writeFile('unname is called');    writeFile("pubkey:" + str2);    var ret = this.unname(str, str2);    writeFile('unname ret value is ' + ret);    return ret;};
Using Java to restore the algorithm:
try {    String password = "qed";    String publicKey = "MIGfMA0GCSqGSIb3D********qGWVMv5z6FwIDAQAB";    byte[] decoded = Base64.decode(publicKey, Base64.DEFAULT);    RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));     Cipher instance = Cipher.getInstance("RSA/ECB/PKCS1Padding");    instance.init(ENCRYPT_MODE, pubKey);    String pwdenc = Base64.encodeToString(instance.doFinal(password.getBytes(StandardCharsets.UTF_8)), Base64.DEFAULT);    Log.e(TAG, pwdenc); } catch (Exception e) {    e.printStackTrace();}
Alright, the password encryption algorithm has been sorted out. Next, let’s look at the sign algorithm, searching for sign in the dex to find the key position:Restoration of APP Encryption and Signature AlgorithmsNext, follow into the SignUtil class:Restoration of APP Encryption and Signature AlgorithmsYou can see that the key method handle is in native-lib; by hooking the get method, you can obtain the parameters passed for signature verification and the sign result:
var SignUtil = Java.use("com.**.****.encrypt.SignUtil");SignUtil.get.implementation = function(str, str2, str3, str4){    writeFile('get is called');     writeFile("str:" + str);    writeFile("str2:" + str2);    writeFile("str3:" + str3);    writeFile("str4:" + str4);     var ret = this.get(str, str2, str3, str4);    writeFile('get ret value is ' + ret);    return ret;};
Load libnative-lib.so into IDA for analysis, the analysis result is as follows:Restoration of APP Encryption and Signature AlgorithmsFunction sub_45A40:Restoration of APP Encryption and Signature AlgorithmsThe above figure has annotated the key methods and variables, and the logic is very clear: sign=sha256(_requestData+_requestDataList+_token+_clientTime+salt_key). To verify if the concatenation is correct, you can output temp_str and find a suitable hook point:Restoration of APP Encryption and Signature AlgorithmsThis can be hooked to output; the corresponding asm code is as follows:Restoration of APP Encryption and Signature AlgorithmsNote that the type of temp_str is std::string; to print output, you need to convert it to cstring. We can use the string_to_cstr function analyzed above for conversion:Restoration of APP Encryption and Signature AlgorithmsAfter analysis, let’s write the hook code:
var libnative_addr = Module.findBaseAddress("libnative-lib.so")writeFile("libnative_addr is: " + libnative_addr) // Internal std::string to cstring methodvar str_to_c = new NativeFunction(libnative_addr.add(0x45A85), "pointer", ["pointer"]); // Output signature stringtry{    var addr_45266 = libnative_addr.add(0x45267);    writeFile("addr_45266: " + addr_45266);     Interceptor.attach(addr_45266, {        onEnter: function (args) {            writeFile("ohwawawa");            var ret = str_to_c(this.context.r2);            writeFile("addr_45266 OnEnter sign string:" + Memory.readCString(ret));        },        onLeave: function (retval) {             //console.log("retval is :", retval)        }    });} catch(err) {    writeFile("[!!!!!!!!!!!!] " + err);}
Thus, once the signature function is executed, all parameters of the signature, the concatenated signature string, and the return result can be perfectly output. This algorithm is relatively simple, so I won’t write the code to restore it.
The app itself has quite good protection measures, with many checks in place. Also, the code volume of this vdog shell is quite astonishing, with a lot of complex encryption and decryption operations and checks inside, as well as complex obfuscation. I can study how this guy protects against frida when I have time.
We cleverly used xcube to bypass the shell’s detection of frida’s spawn and attach; another point to note is that you can see that the frida scripts I wrote cannot use console.log to output, they all use file writing methods instead. This is because console.log cannot output any content at all; I suspect this is also a shield made by the shell, very annoying. Additionally, the code volume of this type of app is still quite astonishing, and it is split into many dex files, requiring patience during analysis with various cross-analysis across several dex files. Work done!
The original text has uploaded the libvdog; if anyone can figure out its key logic, please remember to @ me to learn!

Restoration of APP Encryption and Signature Algorithms

KX ID: taobluesky

https://bbs.pediy.com/user-home-65525.htm

*This article is original by KX forum taobluesky, please indicate the source from KX community when reprinting.

Restoration of APP Encryption and Signature Algorithms

# Previous Recommendations

1. CVE-2022-21882 Privilege Escalation Vulnerability Study Notes

2. Wibu Certificate – An Initial Exploration

3. Win10 1909 Reverse Engineering of APIC Interrupts and Experiments

4. Analysis of EAF Mechanism Under EMET and Simulation Implementation

5. SQL Injection Learning Sharing

6. Issues with V8 Array.prototype.concat Function and Their POCs

Restoration of APP Encryption and Signature Algorithms
Restoration of APP Encryption and Signature Algorithms

Share the Ball

Restoration of APP Encryption and Signature Algorithms

Like the Ball

Restoration of APP Encryption and Signature Algorithms

Watch the Ball

Restoration of APP Encryption and Signature Algorithms

Click “Read the Original” for more information!

Leave a Comment