摩托x的逆向分析

篇幅有限

完整內(nèi)容及源碼關(guān)注公眾號(hào):ReverseCode俐银,發(fā)送

apk放入jadx-1.2.0中很明顯被奇虎360加固了

image-20210727192532494

使用PKiD再次確認(rèn)

image-20210727192630567

脫殼

環(huán)境

安卓8.1+fs128arm64+pyenv local 3.8.2

adb install 摩托邦4.8.0.2021070601.apk

FRIDA-DEXDump

對(duì)于完整的 dex,采用暴力搜索 DEX.035 即可找到。而對(duì)于抹頭的 dex,通過匹配一些特征來找到。FRIDA-DEXDump純粹的利用特征從內(nèi)存中檢索已經(jīng)加載的 DEX 文件携狭,而不需要攔截任何的函數(shù)得到一些結(jié)構(gòu)體,并從中獲取 DEX 的內(nèi)存地址或其他相關(guān)信息回俐。

git clone https://github.com/hluwa/FRIDA-DEXDump.git  支持搜索沒有文件頭的 DEX 文件
python main.py  前臺(tái)運(yùn)行需要脫殼的app逛腿,將dump下的dex放到j(luò)adx-1.2.0中反編譯
image-20210727192238333

FART

在設(shè)置中找到需要脫殼的應(yīng)用配置sdcard存儲(chǔ)空間權(quán)限,否則只能存到var savepath = "/data/data/com.motoband";首先拷貝fart.so和fart64.so到/data/app目錄下(權(quán)限不足就先放到/data/local/tmp再轉(zhuǎn)移目錄)仅颇,并使用chmod 777 設(shè)置好權(quán)限

frida_fart_reflection.js

用反射的方式實(shí)現(xiàn)的函數(shù)粒度的脫殼单默,與使用hook方式實(shí)現(xiàn)的方法不同,可以使用spawn和attach兩種方式使用

調(diào)用dump(classname),傳入要處理的類名,只完成對(duì)某一個(gè)類下的所有函數(shù)的CodeItem完成dump忘瓦,效率更高搁廓,dump下來的類函數(shù)的所有CodeItem在含有類名的bin文件中

frida_fart_hook.js

使用hook的方式實(shí)現(xiàn)的函數(shù)粒度的脫殼,僅僅是對(duì)類中的所有函數(shù)進(jìn)行了加載耕皮,但依然可以解決絕大多數(shù)的抽取保護(hù),需要以spawn方式啟動(dòng)app境蜕,等待app進(jìn)入Activity界面后,執(zhí)行fart()函數(shù)即可

如果發(fā)現(xiàn)某個(gè)類中的函數(shù)的CodeItem沒有dump下來凌停,可以調(diào)用dump(classname),傳入要處理的類名粱年,完成對(duì)該類下的所有函數(shù)體的dump,dump下來的函數(shù)體會(huì)追加到bin文件當(dāng)中

git clone https://github.com/hanbinglengyue/FART.git
frida -UF -l frida_fart_reflection.js
frida -U -f com.motoband -l frida_fart_reflection.js --no-pause
frida -U -f com.motoband -l frida_fart_hook.js --no-pause
mv dex /sdcard/com.motoband/   在使用愛莫助手下載
image-20210727195632734

Youpk

僅限機(jī)型pixel 1代,效果最好罚拟,脫的褲衩都沒了

7z x Youpk_sailfish.zip 
adb reboot bootloader
cd sailfish-nzh54d && sh flash-all.sh

安裝apk后在Settings-Apps-摩托邦-Permissions啟動(dòng)存儲(chǔ)權(quán)限

adb shell "echo com.motoband >> /data/local/tmp/unpacker.config"  啟動(dòng)apk等待脫殼,每隔10秒將自動(dòng)重新脫殼(已完全dump的dex將被忽略), 當(dāng)日志打印unpack end時(shí)脫殼完成
adb pull /data/data/com.motoband/unpacker  pull出dump文件, dump文件路徑為 /data/data/包名/unpacker
java -jar dexfixer.jar /data/data/com.motoband/unpacker /data/data/com.motoband/output   調(diào)用修復(fù)工具 dexfixer.jar, 兩個(gè)參數(shù), 第一個(gè)為dump文件目錄(必須為有效路徑), 第二個(gè)為重組后的DEX目錄(不存在將會(huì)創(chuàng)建)

adb install wifiadb.apk
adb tcpip 5555   免root執(zhí)行tcpip調(diào)試模式
adb connect 172.20.103.254:5555

適用場景

  1. 整體加固
  2. 抽取:
    • nop占坑型(類似某加密)
    • naitve化, 在<clinit>中解密(類似早期阿里)
    • goto解密型(類似新版某加密?najia)

AUPK

抓包

charles+postern

image-20210728113500752

SSL handshake with client failed: An unknown issue occurred processing the certificate (certificate_unknown)看起來做了證書綁定台诗,使用r0capture開啟dump證書也未dump下來,無法正常抓包

./fs1280arm64 啟動(dòng)frida舟舒,netstat -tnlp|grep 27042 查看占用端口

frida_ssl_logger

核心原理就是對(duì)SSL_readSSL_write進(jìn)行hook拉庶,得到其收發(fā)包的明文數(shù)據(jù)

python ssl_logger.py -U -f com.motoband
python ssl_logger.py -U -f com.motoband -p motoband.pcap  生成的pcap通過wireshark打開
image-20210728101147025

OkHttpLogger-Frida

由于所有使用的okhttp框架的App發(fā)出的請(qǐng)求都是通過RealCall.java發(fā)出的,那么我們可以hook此類拿到request和response,也可以緩存下來每一個(gè)請(qǐng)求的call對(duì)象秃励,進(jìn)行再次請(qǐng)求氏仗,所以選擇了此處進(jìn)行hook

adb push okhttpfind.dex /data/local/tmp
frida -U -l okhttp_poker.js -f com.motoband --no-pause  可追加 -o [output filepath]保存到文件

判斷是否混淆,如果混淆需要修改okhttp_poker.js中的混淆后的變量

image-20210728102421848

開啟抓包

image-20210728102752197

r0capture

./fs14216arm64
pyenv local 3.9.0

adb shell dumpsys activity activities  查看前臺(tái)app包名
python r0capture.py -U -f  com.motoband -v
python r0capture.py -U -f  com.motoband -v -p motoband.pcap
python r0capture.py -U -f com.motoband -v >>motoband.txt
frida -U -f com.motoband -l script.js --no-pause -o motoband.txt

ctrl+shift+o獲取請(qǐng)求與請(qǐng)求頭

image-20210728111350099

ctrl+shift+o獲取請(qǐng)求參數(shù)

image-20210728111453906

拼裝到postman中

image-20210728111914921
image-20210728111831220

分析

通過Youpk脫下的dex一起放到j(luò)dax-1.2.0中,搜索seriesinfo

@POST("car/seriesinfo")
Observable<ResponseBody> motoInfo(@Body RequestBody requestBody);

查找用例位于com.motoband.core.manager.ChooseCarManager

public Observable<MotorbikeSeriesModel> requestMotorInfo(String str, int i) {
    HashMap hashMap = new HashMap();
    hashMap.put(IntentConstants.MODELID, str);
    hashMap.put("source", Integer.valueOf(i));
    return RetrofitHelper.getObjectObservable(((ChooseCarService) RetrofitHelper.getRetrofit().create(ChooseCarService.class)).motoInfo(RetrofitHelper.getRequestBody(hashMap)), MotorbikeSeriesModel.class).observeOn(AndroidSchedulers.mainThread()).doOnNext($$Lambda$ChooseCarManager$XcbjKQVeNSK4TPlk0mzi1vIv6Z0.INSTANCE);
}

顯然getRequestBody就是生成眾多加密參數(shù)的方法皆尔,位于com.motoband.core.http.RetrofitHelper

public static RequestBody getRequestBody(Map<String, Object> map) {
    if (map == null) {
        map = new HashMap<>();
    }
    long currentTimeMillis = System.currentTimeMillis();
    map.put("token", UserInfo.getInstance().getToken());
    map.put(MBRequestConstants.REQUEST_REQUESTID, CommonUtil.getRequestId(currentTimeMillis));
    map.put(MBRequestConstants.REQUEST_CTYPE, "2");
    map.put(MBRequestConstants.REQUEST_CVERSION, AppUtils.getAppVersionName());
    map.put("citycode", UserInfo.getInstance().getCitycode());
    if (!map.containsKey("userid")) {
        map.put("userid", UserInfo.getInstance().getUserid());
    }
    if (!map.containsKey(MBRequestConstants.REQUEST_LONLAT)) {
        map.put(MBRequestConstants.REQUEST_LONLAT, UserInfo.getInstance().getLonlatStr());
    }
    map.put(MBRequestConstants.REQUEST_PUSH_ID, JPushInterface.getRegistrationID(MBUtil.getContext()));
    ArrayList<String> arrayList = new ArrayList();
    for (String str : map.keySet()) {
        if (map.get(str) == null) {
            arrayList.add(str);
        }
    }
    for (String str2 : arrayList) {
        map.remove(str2);
    }
    String str3 = null;
    try {
        str3 = RSAUtil.rsaSign(EncryptUtils.encryptMD5ToString(RSAUtil.getSignContent(map)).toLowerCase(), Constants.CLIENT_PRIVATE_KEY);
    } catch (Exception e) {
        e.printStackTrace();
        System.out.println(MBResponseCode.RSA_SIGN_ERROR);
    }
    map.put("sign", str3);
    return RequestBody.create(MediaType.parse(HttpConstants.MediaType_Json), JSON.toJSONString(map));
}

多進(jìn)程保護(hù)

由于摩托邦存在多進(jìn)程保護(hù)呐舔,基于信號(hào)的發(fā)送和接收,實(shí)現(xiàn)相互的保護(hù)防止被動(dòng)態(tài)攻擊慷蠕。簡單的雙進(jìn)程保護(hù)就是從原進(jìn)程再fork一個(gè)空進(jìn)程出來,讓逆向分析的時(shí)候附加到空進(jìn)程中導(dǎo)致hook不上珊拼。

雙進(jìn)程進(jìn)程保護(hù)主要功能: 1、保護(hù)父進(jìn)程流炕,ptrace所有線程澎现,防止被附加、調(diào)試每辟、暫停剑辫; 2、保護(hù)子進(jìn)程渠欺,防止被暫停妹蔽、異常退出;

objection附加雙進(jìn)程保護(hù)的app的時(shí)候報(bào)錯(cuò),一般雙進(jìn)程保護(hù),先把a(bǔ)pp關(guān)掉直接用spwan模式就能附加上挠将。

查看frida源碼和objection源碼:

frida附加的順序:spawn->resume->attach
objection附加的順序:spawn->attach->resume

vim /root/.pyenv/versions/3.8.2/lib/python3.8/site-packages/objection/utils/agent.py   添加如下代碼
        debug_print('Resuming PID test `{pid}`'.format(pid=self.spawned_pid))
        self.device.resume(self.spawned_pid)
image-20210728160806491
注釋如下代碼
        #if not self.exports().ping():
        #    click.secho('Failed to ping the agent', fg='red')
        #    raise Exception('Failed to communicate with agent')
image-20210728160856891

實(shí)際就是把resume放到步驟的中間,如果不行的話適當(dāng)加個(gè)sleep就能附加上了

內(nèi)存漫游

objection -g com.motoband explore -P ~/.objection/plugins
android hooking search classes com.motoband.core.manager.ChooseCarManager  搜索類
android hooking list class_methods com.motoband.core.manager.ChooseCarManager  列出類方法
image-20210728150824474
plugin wallbreaker classdump com.motoband.core.http.RetrofitHelper  根據(jù)指定類dump類結(jié)構(gòu)
plugin wallbreaker objectdump --fullname 0x3576  查看類的值
image-20210728165336743
plugin wallbreaker classsearch com.motoband.core.http.RetrofitHelper   搜索所有相關(guān)類
plugin wallbreaker objectsearch com.motoband.core.http.RetrofitHelper$1$1  搜索內(nèi)存中指定類返回地址
plugin wallbreaker objectdump --fullname 0x2d9a   根據(jù)地址dump類所有方法
image-20210728164831881
android hooking watch class_method com.motoband.core.manager.ChooseCarManager.requestMotorInfo --dump-backtrace --dump-args --dump-return   hook指定方法requestMotorInfo胳岂,打印參數(shù)返回值調(diào)用棧
image-20210728152259851

以上hook說明在requestMotorInfo中傳入品牌型號(hào)3334后進(jìn)入getRequestBody函數(shù)

jobs list  查看進(jìn)程中的任務(wù)
jobs kill id  殺死hook任務(wù)
image-20210728152113382

參數(shù)分析

根據(jù)以上Jadx中的分析,App在請(qǐng)求car/seriesinfo時(shí)調(diào)用了RetrofitHelper.getRequestBody(hashMap))舔稀,在函數(shù)getRequestBody中對(duì)不同參數(shù)包括token,sign等進(jìn)行了加密乳丰,并RequestBody.create(MediaType.parse(HttpConstants.MediaType_Json), JSON.toJSONString(map));最終將請(qǐng)求參數(shù)的HashMap轉(zhuǎn)成JSONString作為create傳遞參數(shù)。

那么即可通過主動(dòng)調(diào)用getRequestBody的同時(shí)hook函數(shù)RequestBody.create拿到第二個(gè)參數(shù)作為請(qǐng)求參數(shù)镶蹋,由于headers中數(shù)據(jù)一致成艘,加上請(qǐng)求url即可完成數(shù)據(jù)抓取。

function hook_RequestBody_create(){
    Java.perform(function(){
        Java.use("okhttp3.RequestBody").create.overload('okhttp3.MediaType', 'java.lang.String').implementation = function(mediaType,str){
            var result = this.create(mediaType,str)
            console.log("params====",str)
            return result;
        }
    })
}
function Initiative_getRequestBody(){
    Java.perform(function(){
        var map = Java.use('java.util.HashMap').$new();
        var StringClass = Java.use("java.lang.String");
        map.put("modelid", StringClass.$new("3334"));
        var RetrofitHelper = Java.use("com.motoband.core.http.RetrofitHelper");
        RetrofitHelper.getRequestBody(map);
    })
}
function main(){
    console.log("Main")
    hook_RequestBody_create(); 
}
setImmediate(main)
image-20210728175304412

以上完成繞過so層通過主動(dòng)調(diào)用和hook的方式獲取請(qǐng)求參數(shù)贺归,接下來就是完成爬蟲的具體邏輯。

抓包

通過python r0capture.py -U com.motoband -v -p moto.pcap抓包分析各個(gè)頁面請(qǐng)求并使用python實(shí)現(xiàn)断箫,headers可以通過請(qǐng)求頭加引號(hào).py自動(dòng)生成

選車列表

headers = {
    'Source': 'source',
    'Date': 'Wed, 28 Jul 2021 10:42:37 GMT',
    'Authorization': 'hmac id="AKIDKpo6me25b14nzcNefQeoqR95syh2ayx97s0g", algorithm="hmac-sha1", headers="date source", signature="LueIYYQhihnHza8ZIzzH3X1J6xM="',
    'Content-Type': 'application/json; charset=utf-8',
    'Content-Length': '396',
    'Host': 'api.motuobang.com',
    'Connection': 'Keep-Alive',
    'Accept-Encoding': 'gzip',
    'User-Agent': 'okhttp/3.14.9'
}
param_str = '{"jpushregistrationid":"18071adc03d4364a59f","ctype":"2","citycode":"0512","requestid":"10120210728184237309B6FABE44946F25C3","brandid":0,"sign":"Un9ld6EYErQmE2ab0CgGP4pbqGKz8taTYlT2d4vgJlR1e6N3vp2Ld/YHpZVHLAYQgdYxmHDPDmdPiapY/Irewg==","type":0,"cversion":"4.8.0.2021070601","userid":"53AEB07289854E91A74DA4718D86617F","token":"6A057F7AB0654DEBA3A9BAFE51A17D62","lonlat":"[120.670592,31.295319]"}'

data = requests.post('http://api.motuobang.com/release/car/brandinfo', data=param_str,
                     headers=headers).json()["data"]
brandlist = json.loads(data)["brandlist"]

品牌列表

headers = {
    'Source': 'source',
    'Date': 'Wed, 28 Jul 2021 11:02:48 GMT',
    'Authorization': 'hmac id="AKIDKpo6me25b14nzcNefQeoqR95syh2ayx97s0g", algorithm="hmac-sha1", headers="date source", signature="xUe79aim7V1Nur4J8DfN9KSDU0Q="',
    'Content-Type': 'application/json; charset=utf-8',
    'Content-Length': '396',
    'Host': 'api.motuobang.com',
    'Connection': 'Keep-Alive',
    'Accept-Encoding': 'gzip',
    'User-Agent': 'okhttp/3.14.9'
}
param_str = '{"jpushregistrationid":"18071adc03d4364a59f","searchcar":"{\\"brandids\\":[28],\\"haveabs\\":0,\\"maxcc\\":0.0,\\"maxmaxpower\\":0.0,\\"maxprice\\":0,\\"maxsitheight\\":0,\\"maxxuhanglicheng\\":0,\\"maxzuigaochesu\\":0,\\"mincc\\":0.0,\\"minmaxpower\\":0.0,\\"minprice\\":0,\\"minsitheight\\":0,\\"minxuhanglicheng\\":0,\\"minzuigaochesu\\":0,\\"modelid\\":-1,\\"month\\":0,\\"pagenum\\":0,\\"pagesize\\":200,\\"searchtype\\":0,\\"source\\":0,\\"store\\":0,\\"year\\":0}","ctype":"2","citycode":"0512","requestid":"10120210728190247800B530F6E7211E0724","sign":"BeHwJ+uZ0BK7bR9z6Q4XifFqp0crBtwDouA3BxYYU7br2XQvwehJPrkfnn9MV/PezYqMawUZI6zEDiplwJ49ug==","cversion":"4.8.0.2021070601","userid":"53AEB07289854E91A74DA4718D86617F","token":"5100BF109300497C83A51614C58314FD","lonlat":"[120.67073,31.295348]"}'

data = requests.post('http://api.motuobang.com/release/car/searchv2', data=param_str,
                     headers=headers).json()["data"]
print(json.loads(data)["serieslist"])

品牌詳情

headers = {
    'Source': 'source',
    'Date': 'Mon, 26 Jul 2021 05:47:06 GMT',
    'Authorization': 'hmac id="AKIDKpo6me25b14nzcNefQeoqR95syh2ayx97s0g", algorithm="hmac-sha1", headers="date source", signature="jmwgtLvjj06A/M/TNcCqL72GRsk="',
    'Content-Type': 'application/json; charset=utf-8 ',
    'Content-Length': '403',
    'Host': 'api.motuobang.com',
    'Connection': 'Keep-Alive',
    'Accept-Encoding': 'gzip',
    'User-Agent': 'okhttp/3.14.'
}
param_str = '{"jpushregistrationid":"1104a89792736fd015f","lonlat":"[120.670593,31.295318]","ctype":"2","sign":"SJxFIJSEi7BwlnPLC/6j3RfyxsR2EEEC2uWGpfC3/MQl/8gSCS5GcqSbre/S3Jrrws+/LYQzGE08T+Gv+tIIAg==","source":0,"token":"89DFF7721007455D806E282F8195B0EF","requestid":"10120210726134706717A11599A619EBCF39","citycode":"0512","cversion":"4.8.0.2021070601","userid":"53AEB07289854E91A74DA4718D86617F","modelid":"3387"}'

data = requests.post('http://api.motuobang.com/release/car/seriesinfo', data=param_str,
                     headers=headers).json()["data"]
print(json.loads(data)["seriesinfo"])

frida rpc 數(shù)據(jù)傳遞

hook RequestBody.create

由于RequestBody.create(MediaType.parse(HttpConstants.MediaType_Json), JSON.toJSONString(map));拂酣,hook create即可拿到入?yún)?請(qǐng)求頭加密參數(shù)。

function hook_body_create(){
    Java.perform(function(){
        Java.use("okhttp3.RequestBody").create.overload('okhttp3.MediaType', 'java.lang.String').implementation = function(mediaType,str){
            var result = this.create(mediaType,str)
            send(str)
            return result;
        }
    })
}
function main(){
    console.log("Main")
    hook_body_create(); 
}
setImmediate(main)

主動(dòng)調(diào)用searchv2

查看選車列表時(shí)仲义,搜索brandinfo

@POST("car/brandinfo")
Observable<ResponseBody> refreshBrandInfo(@Body RequestBody requestBody);

查找用例com.motoband.core.manager.MotoBrandManager

android hooking watch class com.motoband.core.manager.MotoBrandManager --dump-args --dump-backtrace --dump-return   將整個(gè)類hook婶熬,點(diǎn)擊觸發(fā)類實(shí)現(xiàn)
android hooking watch class_method com.motoband.core.manager.MotoBrandManager.requestBrandDetail --dump-args --dump-backtrace --dump-return  hook觸發(fā)的類方法并拿到參數(shù)為brandid
image-20210728211005543

查看品牌列表時(shí),搜索searchv2

@POST("car/searchv2")
Observable<ResponseBody> searchNewMotoModelsV2(@Body RequestBody requestBody);
image-20210729084834395

查找用例時(shí)有多個(gè)方法中調(diào)用埃撵,不過只有兩個(gè)類赵颅,接下來通過objection hook上這兩個(gè)類中的所有方法,點(diǎn)擊指定品牌暂刘,觸發(fā)car/searchv2

android hooking watch class com.motoband.core.manager.ChooseCarManager --dump-args --dump-backtrace --dump-return
android hooking watch class_method com.motoband.core.manager.ChooseCarManager.brandSeries --dump-args --dump-backtrace --dump-return
image-20210729085320595

以上分析得知觸發(fā)了com.motoband.core.manager.ChooseCarManager.brandSeries方法饺谬,傳遞第一個(gè)參數(shù)為brandid,結(jié)合jadx分析

public Observable<CarFilterSearchModel> brandSeries(String str, boolean z) {
    HashMap hashMap = new HashMap();
    hashMap.put("searchcar", SearchMotoFilterModel.toBrandSeriesJson(Integer.parseInt(str), z));
    return RetrofitHelper.getObjectObservable(((ChooseCarService) RetrofitHelper.getRetrofit().create(ChooseCarService.class)).searchNewMotoModelsV2(RetrofitHelper.getRequestBody(hashMap)), CarFilterSearchModel.class).observeOn(AndroidSchedulers.mainThread());
}

拼接searchcar到map中谣拣,通過getRequestBody獲取加密請(qǐng)求參數(shù)募寨。接下來嘗試hook SearchMotoFilterModel.toBrandSeriesJson 拿到入?yún)⒆逭梗胒rida實(shí)現(xiàn)主動(dòng)調(diào)用。

function hook_searchv2(id){
    Java.perform(function(){
        var search_map = Java.use('java.util.HashMap').$new();
        var StringClass = Java.use("java.lang.String");
        var IntegerClass = Java.use("java.lang.Integer");
        var BooleanClass = Java.use("java.lang.Boolean");
        var SearchMotoFilterModel = Java.use('com.motoband.core.model.SearchMotoFilterModel').$new();
        // for brandinfo
        // search_map.put("type", IntegerClass.$new(1));
        // search_map.put("brandid", StringClass.$new(id));
        search_map.put("searchcar",SearchMotoFilterModel.toBrandSeriesJson(id,false));
        var RetrofitHelper = Java.use("com.motoband.core.http.RetrofitHelper");
        RetrofitHelper.getRequestBody(search_map);
    })
}

主動(dòng)調(diào)用serials_info

查看品牌詳情時(shí)拔鹰,搜索seriesinfo

@POST("car/seriesinfo")
Observable<ResponseBody> motoInfo(@Body RequestBody requestBody);

查找用例

public Observable<MotorbikeSeriesModel> requestMotorInfo(String str, int i) {
    HashMap hashMap = new HashMap();
    hashMap.put(IntentConstants.MODELID, str);
    hashMap.put("source", Integer.valueOf(i));
    return RetrofitHelper.getObjectObservable(((ChooseCarService) RetrofitHelper.getRetrofit().create(ChooseCarService.class)).motoInfo(RetrofitHelper.getRequestBody(hashMap)), MotorbikeSeriesModel.class).observeOn(AndroidSchedulers.mainThread()).doOnNext($$Lambda$ChooseCarManager$XcbjKQVeNSK4TPlk0mzi1vIv6Z0.INSTANCE);
}

hook實(shí)現(xiàn)

function hook_seriesinfo(id){
    Java.perform(function(){
        var map = Java.use('java.util.HashMap').$new();
        var StringClass = Java.use("java.lang.String");
        map.put("modelid", StringClass.$new(id));
        var RetrofitHelper = Java.use("com.motoband.core.http.RetrofitHelper");
        RetrofitHelper.getRequestBody(map);
    })
}

rpc調(diào)用

frida主動(dòng)調(diào)用各個(gè)方法時(shí)仪缸,同時(shí)間hook RequestBody.create方法,拿到關(guān)鍵加密參數(shù)列肢,rpc發(fā)送給python恰画,完成爬蟲數(shù)據(jù)拼裝,實(shí)現(xiàn)數(shù)據(jù)抓取瓷马。

js

rpc.exports = {
    hookseriesinfo: hook_seriesinfo,
    hooksearchv2: hook_searchv2,
    hookbodybreate: hook_body_create
}

python


device = frida.get_usb_device()
# pid = device.spawn(["com.motoband"])
# device.resume(pid)
# time.sleep(10)
session = device.attach("com.motoband")
with open("motoband.js") as f:
    script = session.create_script(f.read())
script.on("message", my_message_handler) 
script.load()

# request for brandinfo 
headers = {
    'Source': 'source',
    'Date': 'Wed, 28 Jul 2021 10:42:37 GMT',
    'Authorization': 'hmac id="AKIDKpo6me25b14nzcNefQeoqR95syh2ayx97s0g", algorithm="hmac-sha1", headers="date source", signature="LueIYYQhihnHza8ZIzzH3X1J6xM="',
    'Content-Type': 'application/json;*/jg charset=utf-8',
    'Content-Length': '396',
    'Host': 'api.motuobang.com',
    'Connection': 'Keep-Alive',
    'Accept-Encoding': 'gzip',
    'User-Agent': 'okhttp/3.14.9'
}
param_str = '{"jpushregistrationid":"18071adc03d4364a59f","ctype":"2","citycode":"0512","requestid":"10120210728184237309B6FABE44946F25C3","brandid":0,"sign":"Un9ld6EYErQmE2ab0CgGP4pbqGKz8taTYlT2d4vgJlR1e6N3vp2Ld/YHpZVHLAYQgdYxmHDPDmdPiapY/Irewg==","type":0,"cversion":"4.8.0.2021070601","userid":"53AEB07289854E91A74DA4718D86617F","token":"6A057F7AB0654DEBA3A9BAFE51A17D62","lonlat":"[120.670592,31.295319]"}'
data = requests.post('http://api.motuobang.com/release/car/brandinfo', data=param_str,headers=headers).json()["data"]
brandlist = json.loads(data)["brandlist"]

for brand in brandlist:
    brandname = brand["name"]
    brandid = str(brand["brandid"])
    # 1.創(chuàng)建文件夾
    # 2.request for searchv2
    script.exports.hooksearchv2(brandid)
    # print(name_model_dict)
    # 3.request for seriesinfo
    for (key,value) in name_model_dict.items():
        # print(key+":"+str(value))
        script.exports.hookseriesinfo(str(value))
    # input()    
image-20210729111227782

本文由博客群發(fā)一文多發(fā)等運(yùn)營工具平臺(tái) OpenWrite 發(fā)布

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末锣尉,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子决采,更是在濱河造成了極大的恐慌自沧,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件树瞭,死亡現(xiàn)場離奇詭異拇厢,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)晒喷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門孝偎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人凉敲,你說我怎么就攤上這事衣盾。” “怎么了爷抓?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵势决,是天一觀的道長。 經(jīng)常有香客問我蓝撇,道長果复,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任渤昌,我火速辦了婚禮虽抄,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘独柑。我一直安慰自己迈窟,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布忌栅。 她就那樣靜靜地躺著车酣,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上骇径,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天躯肌,我揣著相機(jī)與錄音,去河邊找鬼破衔。 笑死清女,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的晰筛。 我是一名探鬼主播嫡丙,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼读第!你這毒婦竟也來了曙博?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤怜瞒,失蹤者是張志新(化名)和其女友劉穎父泳,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體吴汪,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡惠窄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了漾橙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片杆融。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖霜运,靈堂內(nèi)的尸體忽然破棺而出脾歇,到底是詐尸還是另有隱情,我是刑警寧澤淘捡,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布藕各,位于F島的核電站,受9級(jí)特大地震影響案淋,放射性物質(zhì)發(fā)生泄漏座韵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一踢京、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧宦棺,春花似錦瓣距、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春逻杖,著一層夾襖步出監(jiān)牢的瞬間奋岁,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工荸百, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留闻伶,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓够话,卻偏偏與公主長得像蓝翰,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子女嘲,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容