某app生成xsign的方案


对于某app生成xsign的方案

【方案一】脱机模拟执行生成xsign

  • 优点:生成效率高,无需真机
  • 缺点:绕过风控能力较弱

【方案二】基于真机改机和群控的RPC调用方式

  • 优点:行为更拟人,绕过风控能力更强,也是之前给其他团队提供的Tiktok抓取商品的方案
  • 缺点:需维护真机,稳定性稍弱

方案一

脱机模拟执行生成xsign调研xsign

具体表现为请求中的header字段x-sign,通过JNICLibrary#doCommandNative(70102,…)返回,输入参数例如

YtjwSHtVyiYDAL4DmOeGaaAI&&&23867946&08028451c53cb47dda9d3641248ec098&%s&mtop.lazada.detail.getdetailinfo&2.0&&600000@lazada_android_6.51.0&&&&&27&&&&&&&

各字段通过&分割,分别为utdid&&&appKey&x-t&api&appver&x-ttid&x-devid&x-features&

而且xsign的输入参数就是协议请求的参数,除了x-sign之外,有效的协议请求还包括了其他x系列header,其中需要动态计算的主要为x-umt/x-sgext/x-mini-wua/x-t,x-CID和x-c-traceid含义尚未明确,但不在优先考虑范围内。

x-t为秒级时间戳,会参与x-sign的计算,因此需要与输入参数中的x-t字段一致。

x-umt/x-sgext/x-mini-wua则为doCommandNative(70102,…)与xsign一起返回。

可以分三步:

  • x-sign/x-mini-wua/x-umt/x-sgext模拟执行生成
  • x-mini-wua参数构造
  • x-umt参数构造

unidbg模拟执行生成xsign

x-sign主要为hmac和aes白盒的hash签名,目前已基于unidbg生成可用的xsign等header

image-20221125153759307

在构造模拟执行环境过程中发现x-umt与x-mini-wua需要从外界com/alibaba/one/android/sdk/OneMain->play获取信息才能生成,OneMain#play方法又会进入到另一个JNI方法中。

image-20221125153819974

重放测试发现,x-umt可固定不变,但x-mini-wua需要每次计算,同时若723456不设置正确的值或置空,则会生成短的x-mini-wua,会导致请求失败。

API入口:com.taobao.seccurity.LazadaXSign#generateXSign

具体调用方式可参考com.taobao.seccurity.LazadaXSign#main方法

x-mini-wua

x-mini-wua格式为HHnB_加一串base64,生成流程为:

  1. base64_decode(oneMain#play(61501799,723456))
  2. aes_decrypt
  3. xor
  4. aes_encrypt
  5. base64_encode

反混淆

1.类似这种修改PC跳转的,但是无法识别具体跳转到哪儿的可以在unidbg里下断点,查看PC寄存器的值,然后d命令查看:

image-20221125154036230
2.遇到jumpout可以patch 对应的跳转指令为固定地址然后删除重建函数并反编译,IDA可识别部分JUMPOUT地址,若无法识别,需要动态调试获取对应地址。

3.遇到未识别为指令代码段的可以强制C成Code,然后根据堆栈回溯分析函数开始手动创建函数

因此oneMain#play(61501799,723456)的值为x-mini-wua的关键,目前尚未分析得到,不同sgmain版本中该值来源也不同,已知的有为saveWb接口返回值中的ee:

b'{"code":200,"data":{"ee":"M1gAoWrca8vx120N2zysp5nJDxvckXlhiZM2cntm/PuoxNy2svgDmAw1Baalg9ybqtSOngGCbTDIesksAS3CqV1g","trace_ip_addr":"0","rmdata":"eyJybWlkIjoibkI3MEFkYWpKdlIzaktSNHQxdFNsVnFqMmdteEdTWTVRNmxVTVlDWUVnST0iLCJiaW5hcnkiOiIwIiwidmVyc2lvbiI6ImQwNDJmODdhZjI3MzZmNDFlYTRkMjYwNWYxMTUzMTBkIn0=","um_changed":false,"exactid":"AAABgp/16kyqQqINsC3DVlg6Ze1PcpvKh5X5xAIcIHQAAAGC4a4JuWQSULHxYMbjWDpl7X133e6vR9EHtZvUeUs6BQEB","stid":"cM0A/INLPD/ddAOCWIzGIORAOmVPG/c8"},"message":"\xe5\xa4\x84\xe7\x90\x86\xe6\x88\x90\xe5\x8a\x9f","secevent":1101}\x04\x04\x04\x04'

x-umt

经分析,x-umt的取值逻辑与https://acs-m.lazada.sg/gw/mtop.alibaba.cro.umid.reped/1.0/
接口有关,在应用首次启动时,会发起多次reped请求,在该请求发送之前,x-umt值与utdid一致,在请求reped接口之后,x-umt方会改变。

get http request:Request{ url=https://acs-m.lazada.sg/gw/mtop.alibaba.cro.umid.reped/1.0/, method=POST, appKey=23867946, authCode=null, headers={appVersion=2, x-sgext=JAHF7KiWDJ8%2BAnUbh816dg%3D%3D, X-CID=858ff2b55155dc79|44084cfa-0b06-4959-aa1c-a133bb28c69f, x-i18n-regionID=sg, x-sign=azwfNj002xAAIT5n41qQ1fUyxhY%2BcT5hMxTjlxQqQDodUBRph%2FDsJ%2BIuj4O4aObssyXw3u5kw%2BMVAwodblB61Z8ln%2FE%2BcT5hPnE%2BYT, x-nettype=NET_NO, x-pv=6.3, x-nq=NET_NO, adid=, x-features=27, x-i18n-language=en-SG, x-app-conf-v=0, x-mini-wua=HHnB_GWv2mZrcyhfajE8L8b3rsPqWh8nKmV6lGbujqwXWpW0%3D, content-type=application/x-www-form-urlencoded;charset=UTF-8, x-t=1658805961, x-bx-version=6.5.4, f-refer=mtop, utdid=Yt9dzeT09CEDAL4DmOclT2bd, x-ttid=600000%40lazada_android_6.51.0, x-app-ver=6.51.0, x-c-traceid=null16588059612800001130996, x-umt=Yt9dzeT09CEDAL4DmOclT2bd, x-utdid=Yt9dzeT09CEDAL4DmOclT2bd, c-launch-info=0,0,1658805961279,1658805958940,0, x-appkey=23867946, x-umidtoken=Yt9dzeT09CEDAL4DmOclT2bd, user-agent=MTOPSDK%2F3.1.1.7+%28Android%3B10%3BGoogle%3BPixel%29}, body=mtopsdk.network.domain.ParcelableRequestBodyImpl@75e804a, seqNo=MTOP1, connectTimeoutMills=5000, readTimeoutMills=5000, retryTimes=1, bizId=0, env=0, reqContext=null, api=mtop.alibaba.cro.umid.reped}
07-26 11:26:01.411 30996 31138 I lazada  : url:https://acs-m.lazada.sg/gw/mtop.alibaba.cro.umid.reped/1.0/
07-26 11:26:01.411 30996 31138 I lazada  : content-type:application/x-www-form-urlencoded;charset=UTF-8,content:data={"request":"{\"sv\":\"2.0.77\",\"pt\":\"1\",\"os\":\"0\",\"e\":\"1000\",\"pv\":\"6.51.0\",\"lt\":\"1658805961\",\"nv\":\"3.0\",\"body\":\"msAMQG9KGcN0cPwYnHbrvowogcYMceFSU51iB14Uk7EGVdjlZO9WdZA/I2/J1SkXYOnYjX3gvoq4HLU+rZTxHRzPYjyWdfB69mUmpPUGuRW8JIyiY3ZbB4V2a5i5MqG8P4QYzq4NWxJeKHuUImjzWDDNf+MtWmKqPWuyfCtRF+Z+oFmiHUXHvHoDpF8PzLAVVC7D1E8+DEnIFAfJxRYi/dAF0+eqPhAh2m32ChDFWWM26LDQTAUxVWsdVvzARYjUF5xKwww2S/+9vtPCdMNi/dpRjiJLPyKGE/ZhZuiX+c+Z396msL1GFuMAoaqjbQ/bjMTMNuN3Fk5MkRcRw18OH3nJg0tdGUSIGcY9h0BksCauX5TrgBmZXKHyKxZOfNyWctAfhA0PKbj80tieF+XL35gbosInurvB4xnq/qJAl1zkeQiQsqhncVQasDszhW29j5rDxuPy5x0ZRFN50jBupba+9McPDKynUF6JRFruI0UtQv/UAZDqsGlpoQJ+qBk2xcQscmtIWp4nD+cffRhsQth4jmpkkTPW3Z54V/S8Wg+p5cXphZcd7Vjo24L+XeRRKYBj3B/19AoszfFfuFyjuO/s36SbbBLboq938ytU5cmD3IQzH/NXbAJtc37krW1q8ltrdb8OhyO2AwggWhY3v7baumk/p9EzeZlmr3/UV/yg8frGebuTOuJ16oMOD1Jin/oj7TOIE8L68CMLFTKqnFjbacqVZCuqUpXEeE9qSoRsMj2GlVk1SOBhIft9bTlaKktf4nu51tICkdlfHcUAqsngE2OyWRnSXVRWxyNuBJBf5xYpfdMiGPXbIRmYM8deX8bmZKDDJZB5GEUABCkt8AyQOcGiStCKOJUmEfJAibqmxNzEHt6nAK5r1ZnSORdGoZDHZwm5aRciIwfvX0aMnEJ2ljr+2AszeICR+2NvThiIhNOQFBMZBC2y9gGiQUuzrv2Qst7IPCZXFZdja5NJPeKaZO/TkkMpaCyFeloBECi+8JZEAZ8qVhig5WR7K7sjO7+mIGmUESVDfKMVwEn4HOMTuwCp1FtCa+7gbWedq0s3kKu1rQjLdelXMRCp+ooSIVJ5BbH7khe+eM4nqH4xzfdzaLa6RB2SxPPGrgLzQdWhiSfAKA0fKYzW0CUiwqxYyoBfPWraqZ9XyjhUa9nFEZshM7xDZAkT5xRSmeXSWRfbK7ThD/5J2b7MqUDJlVjYtEdX1qW2L0ujzeOSRpxCV49VxKvEQXFSMkNTjvsgXIGB3LAP2h3lln86kUblDJ5Udydow4dyLnuS8pUyIgnMDLmwXjZ1bTSVLQWyIKyb7XsU/nQt4eTWfxjfFAYE45qD69lT2qWkU1HZSDMnO1U6xAvRIbTRhtECr7qg3mlSOQWZtilCSGkVgrYcWGDSHWvgdNf5bULBrl1QX6zowbHMmDYjXT0H8t6mQvjFEavgJBE/uqx6/47fqlBupBJsX5ZAQ83bPqt4sNhTnCkRG5pJEQ==\",\"pn\":\"com.lazada.android\"}"} 07-26 14:18:16.919 16241 16385 I lazada  : java.lang.Throwable
07-26 14:18:16.919 16241 16385 I lazada  :     at com.virjar.ratel.demoapp.crack.hook.LazadaHooker$2.afterHookedMethod(LazadaHooker.java:64)
07-26 14:18:16.919 16241 16385 I lazada  :     at com.virjar.ratel.api.rposed.RC_MethodHook.callAfterHookedMethod(RC_MethodHook.java:70)
07-26 14:18:16.919 16241 16385 I lazada  :     at com.virjar.ratel.hook.sandcompat.hookstub.HookStubManager.hookBridge(HookStubManager.java:319)
07-26 14:18:16.919 16241 16385 I lazada  :     at com.virjar.ratel.hook.sandcompat.hookstub.MethodHookerStubs32.stub_hook_0(MethodHookerStubs32.java:378)
07-26 14:18:16.919 16241 16385 I lazada  :     at mtopsdk.network.impl.ANetworkCallImpl.<init>(SourceFile:36)
07-26 14:18:16.919 16241 16385 I lazada  :     at com.lazada.android.mtop.ANetWorkSecurityCallFactory.newCall(SourceFile:51)
07-26 14:18:16.919 16241 16385 I lazada  :     at mtopsdk.framework.filter.before.ExecuteCallBeforeFilter.doBefore(SourceFile:55)
07-26 14:18:16.919 16241 16385 I lazada  :     at mtopsdk.framework.manager.impl.AbstractFilterManager.start(SourceFile:60)
07-26 14:18:16.919 16241 16385 I lazada  :     at mtopsdk.mtop.intf.MtopBuilder.asyncRequest(SourceFile:810)
07-26 14:18:16.919 16241 16385 I lazada  :     at mtopsdk.mtop.intf.MtopBuilder.syncRequest(SourceFile:726)
07-26 14:18:16.919 16241 16385 I lazada  :     at java.lang.reflect.Method.invoke(Native Method)
07-26 14:18:16.919 16241 16385 I lazada  :     at com.alibaba.one.android.inner.DataReportJniBridge.sendReportBridgeMtop(Unknown Source:186)
 
get http response:{"api":"mtop.alibaba.cro.umid.reped","data":{"ck":"0163bb04f7299dcc768c22cc4f1c09c5","dt":"XoasjheQJiva3aDBGB8QeLm6YJUvIK92WQObJFCas5hkYgOPRLqD1t4zScu3kq9I5mP2kQ5WfkCu+wAobiam1TBtcbB55v5grQ1bH0mIJz60gaqaXpkcVeCh15tKIccdsTDC26IqHSY//5lJHU2vA3pVEK1G7WuYvF3mtBU2n8tRzKDnW2tDFuBF2SgxRmk4QAf/3uYLHf1l37jEL681Kma4qTJENrErolsZFuryg5DaBYRlAGYpsuosJYFJvuL1WiNnbZGq9OgM/QWgVvfNZYrfmO/wfFaRPJVBxVvxZQ1ZAn1kteQenzdL/0X4wT4ZivWbMsjEZG7pz9NR4xdRC7/FqNvAVqn52gK2nxmploCsfimQi0j7r4gffR4gzl425jKYtkrnSsuE8yIUPL48rU6gSrNTkk8eHjqWp3K+lK4=","ec":"200"},"ret":["SUCCESS::调用成功"],"v":"1.0"}

reped请求与响应参数以及调用堆栈如上所示,DataReportJniBridge.sendReportBridgeMtop在so中通过JNI调用,hook对应CallStaticObjectMethod打印堆栈发现在libsgsecuritybodyso.so中,但该so与libsgmain一样,有大量的静态花指令保护,IDA无法正常分析出各函数开始和结束地址,甚至部分函数无法识别是代码段,需要手动识别以及patch跳转,为防止有一些SMC或加固,从运行内存中dump一份so进行分析,同时lazada只有arm32的so,trace也行不通,因此分析起来比较麻烦。

若要继续完整还原x-umt算法,需要还原出reped响应内容,以及后续解析逻辑,同时还需解密请求参数中的body分析各字段含义,并模拟发送该请求交换获取x-umt。

因此xsign系列header并非简单参数签名,如果要走纯协议脱机过风控,还涉及到很多前置初始化请求和加密算法分析。

方案二

基于真机改机和群控的RPC调用方式

基于真机的方案有两种路线,一种是通过直接调用真机上请求方法或者doCommand方法生成xsign等header,该方案的优点在于无需考虑各header逻辑,只需保证设备指纹和代理IP正常即可,但需要和手机同步配合,以及每台手机的消费能力有限。

另一种则是通过真机异步生成上述模拟执行所需的OneMain#play方法的返回值并回传服务端,服务端通过模拟执行生成xsign等header,该方案相比于第一种的优点在于手机端只需生成环境信息,与业务请求解耦,相当于手机端的功能为生成deviceId,若deviceId储备充足,则服务端生成xsign速度较快。

逆向分析&Hook脚本

So层主要分析方式为unidbg trace和frida,通过unidbg分析数据来源和堆栈,结合frida和真机确定参数和返回值是否正确

Java层Hook可参考:

import android.util.Log;
 
import org.json.JSONObject;
 
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
 
import dalvik.system.PathClassLoader;
 
/**
 * @author alienhe
 * @date 2022/6/16
 * @Description lazada 6.51.0 xsign
 */
public class LazadaHooker implements Hooker {
 
    public static final String TAG = "lazada";
 
    @Override
    public boolean willHook(RC_LoadPackage.LoadPackageParam lpparam) {
        return lpparam.packageName.equals("com.lazada.android");
    }
 
    @Override
    public void hook(RC_LoadPackage.LoadPackageParam lpparam) {
        try {
            DemoAppHooker.registerSekiro("lazada");
 
            // 淘宝系抓包强制走Https
            ClassLoadMonitor.findAndHookMethod("mtopsdk.mtop.global.SwitchConfig", "isGlobalSpdySwitchOpen", new RC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    Log.i(TAG, "switch to https!");
                    param.setResult(false);
                }
            });
 
            // or mtopsdk.network.impl.ANetworkCallImpl#request
            // ref: https://blog.csdn.net/haoren_xhf/article/details/90449978
            RposedBridge.hookAllConstructors(RposedHelpers.findClass("mtopsdk.network.AbstractCallImpl", RatelToolKit.hostClassLoader), new RC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    if (param.args.length <= 0) {
                        return;
                    }
                    Object request = param.args[0];
                    Log.i(TAG, "get http request:" + request);
                    String url = RposedHelpers.getObjectField(request, "url");
                    // reped接口返回值中包括了x-umt
                    if (url.contains("mtop.alibaba.cro.umid.reped")) {
                        try {
                            Object requestBody = RposedHelpers.getObjectField(request, "body");
                            Log.i(TAG, "content-type:" + RposedHelpers.getObjectField(requestBody, "contentType") + ",content:" + new String(RposedHelpers.getObjectField(requestBody, "content"), StandardCharsets.UTF_8));
                            Log.i(TAG, "backtrace:", new Throwable());
                        } catch (Throwable e) {
                            Log.i(TAG, "parse request body error:", e);
                        }
                    }
                }
            });
 
            RposedHelpers.findAndHookMethod("mtopsdk.mtop.domain.MtopResponse", RatelToolKit.hostClassLoader, "getBytedata", new RC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    Log.i(TAG, "get http response:" + new String((byte[]) param.getResult(), StandardCharsets.UTF_8));
                }
            });
 
            Log.i(TAG, "http network hook finish");
 
            RposedHelpers.findAndHookMethod("mtopsdk.mtop.intf.MtopBuilder", RatelToolKit.hostClassLoader, "syncRequest", new RC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    try{
                        Object request = RposedHelpers.getObjectField(param.thisObject,"request");
                        Object response = param.getResult();
                        String retCode = (String) RposedHelpers.callMethod(response,"getRetCode");
                        JSONObject dataJsonObject = (JSONObject) RposedHelpers.callMethod(response,"getDataJsonObject");
                        Log.i(TAG, "mtopsdk.mtop.intf.MtopBuilder#syncRequest request:"+ request+ "result:" + retCode + "|" + dataJsonObject);
                    }catch (Throwable e){
                        Log.e(TAG,"mtopsdk.mtop.intf.MtopBuilder#syncRequest error:" ,e);
                    }
                }
            });
 
            //ClassLoadMonitor.hookAllMethod("com.taobao.wireless.security.adapter.datareport.DataReportJniBridge", "sendReportBridgeMtop", new RC_MethodHook() {
            ClassLoadMonitor.hookAllMethod("com.taobao.wireless.security.adapter.common.d", "a", new RC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    try{
                        Log.i(TAG,"mtop DataReportJniBridge send reped request:" + param.args.length);
                        if (param.args != null) {
                            Log.i(TAG, "mtop DataReportJniBridge send reped request:" + Arrays.toString(param.args) + ",result:" + param.getResult());
                            Log.i(TAG, "backtrace:", new Throwable());
                        }
                    }catch(Throwable e){
                        Log.e(TAG,"mtop DataReportJniBridge send reped request error:",e);
                    }
                }
            });
 
            // 不Hook这个方法会出现JNICLibrary引用回收导致找不到JNICLibrary的情况
            RposedBridge.hookAllConstructors(PathClassLoader.class, new RC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    Log.i(TAG, "PathClassLoader create:" + param.thisObject);
                }
            });
 
            ClassLoadMonitor.addClassLoadMonitor(new ClassLoadMonitor.OnClassLoader() {
                @Override
                public void onClassLoad(Class<?> clazz) {
                    if (clazz.getName().equals("com.taobao.wireless.security.adapter.JNICLibrary")) {
                        Log.i(TAG, "find class JNICLibrary clazz:" + clazz + ",classloader:" + clazz.getClassLoader());
                        LazadaHandler.JNICLibraryClassLoader = clazz.getClassLoader();
                    } else if (clazz.getName().equals("com.alibaba.one.android.sdk.OneMain")) {
                        Log.i(TAG, "find class com.alibaba.one.android.sdk.OneMain clazz:" + clazz + ",classloader:" + clazz.getClassLoader());
                    } else if (clazz.getName().equals("com.taobao.wireless.security.adapter.datareport.DataReportJniBridge")) {
                        Log.i(TAG, "find class com.taobao.wireless.security.adapter.datareport.DataReportJniBridge clazz:" + clazz + ",classloader:" + clazz.getClassLoader());
                    }
                }
            });
 
            ClassLoadMonitor.hookAllMethod("com.taobao.dp.DeviceSecuritySDKImpl", "initUMIDNative", new RC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    Log.i(TAG, "com.taobao.dp.DeviceSecuritySDKImpl invoked:" + param.args[0]);
                }
            });
 
            ClassLoadMonitor.findAndHookMethod("com.taobao.wireless.security.adapter.JNICLibrary", "doCommandNative", int.class, Object.class, new RC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    StringBuilder paramString = new StringBuilder();
                    int code = (int) param.args[0];
                    // filter
                    if (code == 12606) {
                        return;
                    }
                    paramString.append(param.args[0]);
                    if (param.args[1] instanceof Object[]) {
                        for (Object p : (Object[]) param.args[1]) {
                            paramString.append(",").append(p);
                        }
                    }
 
                    Log.i(TAG, "JNICLibrary#doCommandNative params: " + paramString + ",result:" + JSON.toJSONString(param.getResult()));
                }
            });
 
            ClassLoadMonitor.findAndHookMethod("com.taobao.wireless.security.adapter.common.SPUtility2", "readFromSPUnified", String.class, String.class, String.class, new RC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    Log.i(TAG, "SPUtility2#readFromSPUnified key:" + param.args[0] + ",value:" + param.getResult());
                }
            });
 
            ClassLoadMonitor.findAndHookMethod("com.taobao.wireless.security.adapter.datacollection.DeviceInfoCapturer", "doCommandForString", int.class, new RC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    Log.i(TAG, "DeviceInfoCapturer#doCommandForString key:" + param.args[0] + ",value:" + param.getResult());
                }
            });
 
            ClassLoadMonitor.findAndHookMethod("com.alibaba.one.android.sdk.OneMain", "play", int.class, int.class, int.class, Object.class, new RC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    Log.i(TAG, "OneMain#play key:" + Arrays.toString(param.args) + ",value:" + param.getResult());
                    try {
                        int i3 = (int) param.args[2];
                        int i4 = (int) param.args[3];
                        // x-umt来源
                        if (i3 == 61501799 && i4 == 136803) {
                            //Log.i(TAG,"backtrace:",new Throwable());
                        }
                    } catch (Throwable e) {
                        Log.d(TAG, "ignore:" + e.getMessage());
                    }
                }
            });
 
            ClassLoadMonitor.findAndHookMethod("com.alibaba.wireless.security.securitybody.SecurityBodyAdapter", "doAdapter", int.class, new RC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    Log.i(TAG, "SecurityBodyAdapter#doAdapter param:" + param.args[0] + ",value:" + param.getResult());
                }
            });
            Log.i(TAG, "lazada hook finish");
        } catch (Throwable e) {
            Log.e(TAG, "lazada hook error:", e);
        }
    }
}

Author: Lic
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint policy. If reproduced, please indicate source Lic !
  TOC