日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

摩托x的逆向分析

發布時間:2024/1/1 编程问答 57 豆豆
生活随笔 收集整理的這篇文章主要介紹了 摩托x的逆向分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

篇幅有限

完整內容及源碼關注公眾號:ReverseCode,發送

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

使用PKiD再次確認

脫殼

環境

安卓8.1+fs128arm64+pyenv local 3.8.2

adb install 摩托邦4.8.0.2021070601.apk

FRIDA-DEXDump

對于完整的 dex,采用暴力搜索 DEX.035 即可找到。而對于抹頭的 dex,通過匹配一些特征來找到。FRIDA-DEXDump純粹的利用特征從內存中檢索已經加載的 DEX 文件,而不需要攔截任何的函數得到一些結構體,并從中獲取 DEX 的內存地址或其他相關信息。

git clone https://github.com/hluwa/FRIDA-DEXDump.git 支持搜索沒有文件頭的 DEX 文件 python main.py 前臺運行需要脫殼的app,將dump下的dex放到jadx-1.2.0中反編譯

FART

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

frida_fart_reflection.js

用反射的方式實現的函數粒度的脫殼,與使用hook方式實現的方法不同,可以使用spawn和attach兩種方式使用

調用dump(classname),傳入要處理的類名,只完成對某一個類下的所有函數的CodeItem完成dump,效率更高,dump下來的類函數的所有CodeItem在含有類名的bin文件中

frida_fart_hook.js

使用hook的方式實現的函數粒度的脫殼,僅僅是對類中的所有函數進行了加載,但依然可以解決絕大多數的抽取保護,需要以spawn方式啟動app,等待app進入Activity界面后,執行fart()函數即可

如果發現某個類中的函數的CodeItem沒有dump下來,可以調用dump(classname),傳入要處理的類名,完成對該類下的所有函數體的dump,dump下來的函數體會追加到bin文件當中

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/ 在使用愛莫助手下載

Youpk

僅限機型pixel 1代,效果最好,脫的褲衩都沒了

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

安裝apk后在Settings-Apps-摩托邦-Permissions啟動存儲權限

adb shell "echo com.motoband >> /data/local/tmp/unpacker.config" 啟動apk等待脫殼,每隔10秒將自動重新脫殼(已完全dump的dex將被忽略), 當日志打印unpack end時脫殼完成 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 調用修復工具 dexfixer.jar, 兩個參數, 第一個為dump文件目錄(必須為有效路徑), 第二個為重組后的DEX目錄(不存在將會創建)adb install wifiadb.apk adb tcpip 5555 免root執行tcpip調試模式 adb connect 172.20.103.254:5555

適用場景

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

    抓包

    charles+postern

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

    ./fs1280arm64 啟動frida,netstat -tnlp|grep 27042 查看占用端口

    frida_ssl_logger

    核心原理就是對SSL_read和SSL_write進行hook,得到其收發包的明文數據

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

    OkHttpLogger-Frida

    由于所有使用的okhttp框架的App發出的請求都是通過RealCall.java發出的,那么我們可以hook此類拿到request和response,也可以緩存下來每一個請求的call對象,進行再次請求,所以選擇了此處進行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中的混淆后的變量

    開啟抓包

    r0capture

    ./fs14216arm64 pyenv local 3.9.0

    adb shell dumpsys activity activities 查看前臺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獲取請求與請求頭

    ctrl+shift+o獲取請求參數

    拼裝到postman中

    分析

    通過Youpk脫下的dex一起放到jdax-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就是生成眾多加密參數的方法,位于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)); }

    多進程保護

    由于摩托邦存在多進程保護,基于信號的發送和接收,實現相互的保護防止被動態攻擊。簡單的雙進程保護就是從原進程再fork一個空進程出來,讓逆向分析的時候附加到空進程中導致hook不上。

    雙進程進程保護主要功能: 1、保護父進程,ptrace所有線程,防止被附加、調試、暫停; 2、保護子進程,防止被暫停、異常退出;

    objection附加雙進程保護的app的時候報錯,一般雙進程保護,先把app關掉直接用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)

    注釋如下代碼#if not self.exports().ping():# click.secho('Failed to ping the agent', fg='red')# raise Exception('Failed to communicate with agent')

    實際就是把resume放到步驟的中間,如果不行的話適當加個sleep就能附加上了

    內存漫游

    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 列出類方法

    plugin wallbreaker classdump com.motoband.core.http.RetrofitHelper 根據指定類dump類結構 plugin wallbreaker objectdump --fullname 0x3576 查看類的值

    plugin wallbreaker classsearch com.motoband.core.http.RetrofitHelper 搜索所有相關類 plugin wallbreaker objectsearch com.motoband.core.http.RetrofitHelper$1$1 搜索內存中指定類返回地址 plugin wallbreaker objectdump --fullname 0x2d9a 根據地址dump類所有方法

    android hooking watch class_method com.motoband.core.manager.ChooseCarManager.requestMotorInfo --dump-backtrace --dump-args --dump-return hook指定方法requestMotorInfo,打印參數返回值調用棧

    以上hook說明在requestMotorInfo中傳入品牌型號3334后進入getRequestBody函數

    jobs list 查看進程中的任務 jobs kill id 殺死hook任務

    參數分析

    根據以上Jadx中的分析,App在請求car/seriesinfo時調用了RetrofitHelper.getRequestBody(hashMap)),在函數getRequestBody中對不同參數包括token,sign等進行了加密,并RequestBody.create(MediaType.parse(HttpConstants.MediaType_Json), JSON.toJSONString(map));最終將請求參數的HashMap轉成JSONString作為create傳遞參數。

    那么即可通過主動調用getRequestBody的同時hook函數RequestBody.create拿到第二個參數作為請求參數,由于headers中數據一致,加上請求url即可完成數據抓取。

    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)

    以上完成繞過so層通過主動調用和hook的方式獲取請求參數,接下來就是完成爬蟲的具體邏輯。

    抓包

    通過python r0capture.py -U com.motoband -v -p moto.pcap抓包分析各個頁面請求并使用python實現,headers可以通過請求頭加引號.py自動生成

    選車列表

    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 數據傳遞

    hook RequestBody.create

    由于RequestBody.create(MediaType.parse(HttpConstants.MediaType_Json), JSON.toJSONString(map));,hook create即可拿到入參=請求頭加密參數。

    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)

    主動調用searchv2

    查看選車列表時,搜索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 將整個類hook,點擊觸發類實現 android hooking watch class_method com.motoband.core.manager.MotoBrandManager.requestBrandDetail --dump-args --dump-backtrace --dump-return hook觸發的類方法并拿到參數為brandid

    查看品牌列表時,搜索searchv2

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

    查找用例時有多個方法中調用,不過只有兩個類,接下來通過objection hook上這兩個類中的所有方法,點擊指定品牌,觸發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

    以上分析得知觸發了com.motoband.core.manager.ChooseCarManager.brandSeries方法,傳遞第一個參數為brandid,結合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獲取加密請求參數。接下來嘗試hook SearchMotoFilterModel.toBrandSeriesJson 拿到入參,利用frida實現主動調用。

    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);}) }

    主動調用serials_info

    查看品牌詳情時,搜索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實現

    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調用

    frida主動調用各個方法時,同時間hook RequestBody.create方法,拿到關鍵加密參數,rpc發送給python,完成爬蟲數據拼裝,實現數據抓取。

    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.創建文件夾# 2.request for searchv2script.exports.hooksearchv2(brandid)# print(name_model_dict)# 3.request for seriesinfofor (key,value) in name_model_dict.items():# print(key+":"+str(value))script.exports.hookseriesinfo(str(value))# input()

    本文由博客群發一文多發等運營工具平臺 OpenWrite 發布

    總結

    以上是生活随笔為你收集整理的摩托x的逆向分析的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。