Today's Objective
- Collect product recommendation data from the Dewu app home screen
- Target application version: 4.74.5
Bypassing Forced Updates
# -*- coding: utf-8 -*-
'''
@IDE : PyCharm
@version : 3.9
@Auth : Security Researcher
@time : 2024/2/25 8:01
@Description: Bypass update dialog in Dewu app
'''
import frida
import sys
rdev = frida.get_remote_device()
pid = rdev.spawn(["com.shizhuang.duapp"])
session = rdev.attach(pid)
scr = """
Java.perform(function () {
var AlertDialog = Java.use('androidx.appcompat.app.AlertDialog');
AlertDialog.show.implementation = function(){
console.log("Update dialog intercepted");
// Commenting out the actual call to bypass
//this.show();
}
});
"""
script = session.create_script(scr)
def on_message(message, data):
print(message, data)
script.on("message", on_message)
script.load()
rdev.resume(pid)
sys.stdin.read()
Network Traffic Analysis
The application implements client-side proxy detection, requiring the use of SocksDroid for traffic capture. Before beginning, ensure all previous proxy configurations have been removed from your device.
API Analysis
- Endpoint: https://app.dewu.com/sns-rec/v1/recommend/all/feed
- Method: GET
- Headers: Only X-Auth-Token is required (can be removed from testing)
User-Agent: duapp/4.74.5(android;11)
X-Auth-Token: # Required parameter
- lastId (empty for first page, or 1 for pagination)
- limit (number of items per page, default 20)
- newSign (encrypted signature, must be cracked for full functionality)
- Optional parameters:
- abType: social_brand_strategy_v454
- abValue: 1
- deliveryProjectId: 0
- abVideoCover: 2
- abRectagFengge: 0
- abRecReason: 0
Reverse Engineering Targets
- newSign generation
- X-Auth-Token handling
Cracking newSign Generation
3.1 Application Decompilation
- Drag the Dewu app to JADX for decompilation
- Search for "newSign" in the codebase
- Identify addQueryParameter as the likely method responsible
- Analyze the code: host.addQueryParameter("newSign", RequestUtils.c(hashMap2, currentTimeMillis))
- Confirm RequestUtils.c is called with two parameters
- Create a hook script to verify this method is being called
3.2 Hooking RequestUtils.c Method
# -*- coding: utf-8 -*-
'''
@IDE : PyCharm
@version : 3.9
@Auth : Security Researcher
@time : 2024/2/25 10:01
@Description: Hook RequestUtils.c method to analyze signature generation
'''
import frida
import sys
# Connect to mobile device
rdev = frida.get_remote_device()
session = rdev.attach("com.shizhuang.duapp")
scr = """
Java.perform(function () {
// Package.Class
var RequestUtils = Java.use("com.shizhuang.duapp.common.utils.RequestUtils");
// Hook and replace
RequestUtils.c.implementation = function(map, timestamp){
console.log('--------------------------------')
// Execute original method
console.log('1. Parameter map:', map);
console.log('2. Parameter type:', JSON.stringify(map));
// Standard conversion format
var HashMap = Java.use('java.util.HashMap');
var obj = Java.cast(map, HashMap);
console.log('3. Converted map string:', obj.toString());
console.log("Input timestamp:", timestamp);
var result = this.c(map, timestamp)
console.log("Generated signature:", result);
return result;
}
});
"""
script = session.create_script(scr)
def on_message(message, data):
print(message, data)
script.on("message", on_message)
script.load()
sys.stdin.read()
3.3 Analyzing RequestUtils.c Implementation
The Java source code reveals a five-step process:
public static synchronized String c(Map<String, String> map, long j2) throws UnsupportedEncodingException {
synchronized (RequestUtils.class) {
PatchProxyResult proxy = PatchProxy.proxy(new Object[]{map, new Long(j2)}, null, changeQuickRedirect, true, 6612, new Class[]{Map.class, Long.TYPE}, String.class);
if (proxy.isSupported) {
return (String) proxy.result;
} else if (map == null) {
return "";
} else {
// 1. Add multiple key-value pairs to the map
map.put("uuid", DuHttpConfig.d.getUUID());
map.put("platform", "android");
map.put("v", DuHttpConfig.d.getAppVersion());
map.put("loginToken", DuHttpConfig.d.getLoginToken());
map.put("timestamp", String.valueOf(j2));
// 2. Convert the map to an ArrayList for sorting
ArrayList arrayList = new ArrayList(map.entrySet());