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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android逆向-实战sign分析-某某合伙人_v4.0.9

發布時間:2024/1/1 Android 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android逆向-实战sign分析-某某合伙人_v4.0.9 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1.基礎分析

1.1.基礎分析

工作中經常會對一些app進行安全審計,一般在拿到應用后可以使用APK Helper工具對應用做個簡單分析,了解目標的包名,版本號,名稱等基礎信息,之后再安裝到手機上熟悉下應用的業務,該應用屬于哪類app,之后就是思考業務上可能存在的攻擊點。
本次目標是一個電商應用,簡單使用后可知應用存在登錄,購買,支付等眾多攻擊點,這里我們就從登錄入手。
登錄邏輯的常見審計思路有:

1.審計客戶端與服務端交互時是否直接將用戶名密碼進行明文傳輸。 2.客戶端是否將用戶登錄的錯誤分開提醒如單獨提示密碼錯誤、單獨提示賬號錯誤。 3.服務端沒對客戶的登錄次數進行限制導致用戶名/密碼可被爆破。 4.是否對用戶的token做了校驗,不存在校驗可能導致任意用戶登錄等。 5.是否對驗證碼的輸入次數做了限制,如果驗證碼為4,6位的純數字則可以被爆破。 6.服務端是否驗證注冊手機和提交的驗證碼是否對應。 7.驗證碼獲取的次數、頻率是否有限制。

有了審計思路后就可以進行更深入的分析,在分析之前還需要確定該app是否有保護機制,比如應用是否加固,是否存在反抓包機制。如果存在的保護機制的話還需要把這些保護機制給過掉。

1.2.抓包

第一步,抓包,在實際的測試過程中發現該應用做了反抓包策略,只要我們一掛上代理或開啟VPN就會在請求服務器時提示以下的錯誤。

這時候有兩種選擇

  • 1.分析apk代碼,找到證書檢查的位置,hook繞過
  • 2.采取通用方案:Xposed+JustTrustMe插件+SSLUnpinning2.0插件

這里為了方便就選擇第二種了,首先需要在手機上安裝Xposed環境,Xposed是一個hook框架,它支持安裝別的模塊,每個模塊都是基于hook實現的小工具。比如這里用于繞過SSL證書校驗的模塊JustTrustMe和SSLUnpinning2.0,將Xposed和模塊安裝完成后需要重啟一下系統,這是因為Xposed 的原理是對zygote進程進行劫持,每個apk啟動都是由zygote進程fork出來的,所以每次新加一個模塊都需要重啟下系統使得zygote進程重啟進而加載我們新添加的模塊。
這里再補充說下這兩個插件的原理,都是對APK中可能用到的校驗SSL證書的API進行hook,從而繞過證書檢查這么一步的。
等待系統啟動完成后再次進行抓包,可以發現再次請求時就沒有了之前的錯誤提示,并且fiddler也順利抓到了數據包。

POST https://www.100hhr.com/App/Login/phoneCode HTTP/1.1 Content-Type: application/x-www-form-urlencoded Content-Length: 217 Host: www.100hhr.com Connection: Keep-Alive Accept-Encoding: gzip User-Agent: okhttp/3.9.1data=%7B%22type%22%3A%2220%22%2C%22phone%22%3A%2213711111111%22%2C%22countries_code%22%3A%22%2B86%22%2C%22p%22%3A%22android%22%2C%22v%22%3A%2271%22%2C%22time%22%3A1622530633%7D&apisign=a6874abaa4ff4bc156563b07589d93fe

能夠順利捕獲數據包后,我們可以在抓包工具中對請求的數據進行修改,之后點擊發送來檢查應用是否做了數據包完整性的校驗,如果不存在完整性校驗那就可以利用數據包重放攻擊來對服務端進行測試,這里是重放測試是失敗了的,所以確定服務端是檢查了數據包的完整性。
其實除了修改數據包來確定,還可以分析發送的數據包來確定,數據包中有個apisign字段,每次請求這個apisign值都會變化,一般sign字段表示簽名值,通過計算除sign之外的其他字段算出來的,這叫做參數簽名。
所以如果要實現模擬請求那就需要分析這個apisign值的生成,下面開始分析apisign值的生成。

1.3.脫殼

將應用丟到反編譯工具中進行反編譯時發現應用做了加固,有經驗的小伙伴一眼應該就能看出這個哪家的殼子

不清楚的小伙伴也沒關系,可以使用查殼工具(PKID)來檢測。

工具檢測出使用了360加固,知道使用的哪家加固后脫殼就可以有針對性的進行,不過這里找了幾款通用的脫殼工具進行脫殼。

1.3.1.內存搜索法脫殼

第一款Frida-dexdump,是基于Frida的一款脫殼工具,它的原理是在內存中暴力搜索dex開頭的標志性字符(dex035/dex036/dex037),如果找到了就會將這個dex文件給dump下來,對于將頭部抹掉的dex還支持dex文件的模糊查找。使用時是默認對頂層activity所在進程的內存進行搜索。

E:\FRIDA-DEXDump\FRIDA-DEXDump\frida_dexdump λ python main.py -n com.ljhhr.mobile 05-31/10:32:32 INFO [DEXDump]: found target [6717] com.ljhhr.mobile [DEXDump]: DexSize=0x7324, DexMd5=d4f38621321e74cf8b44a79549af028e, SavePath=E:\FRIDA-DEXDump\FRIDA-DEXDump\frida_dexdump/com.ljhhr.mobile/0xca69c000.dex [DEXDump]: DexSize=0x647424, DexMd5=a56baf750eecd3d744feb795fe3f71b2, SavePath=E:\FRIDA-DEXDump\FRIDA-DEXDump\frida_dexdump/com.ljhhr.mobile/0xcb490000.dex [DEXDump]: DexSize=0x2399f0, DexMd5=6b784fda24a96e6e415a503c4cbbb418, SavePath=E:\FRIDA-DEXDump\FRIDA-DEXDump\frida_dexdump/com.ljhhr.mobile/0xcc0bf000.dex [DEXDump]: Skip duplicate dex 0xcc880000<d4f38621321e74cf8b44a79549af028e> [DEXDump]: DexSize=0x11c, DexMd5=f1771b68f5f9b168b79ff59ae2daabe4, SavePath=E:\FRIDA-DEXDump\FRIDA-DEXDump\frida_dexdump/com.ljhhr.mobile/0xcd0498b0.dex [DEXDump]: Skip duplicate dex 0xcd38701c<d4f38621321e74cf8b44a79549af028e> /...skip.../ E:\FRIDA-DEXDump\FRIDA-DEXDump\frida_dexdump

使用后一共dump出了4個dex,簡單看了下0xcb490000.dex文件比較大,使用反編譯工具可以看到確實存在ljhhr相關代碼,其中還有一些sdk的代碼。

那么該如何確認代碼是否完整呢?
打開登錄頁面拿到頂層activity,看這個dex中是否存在這個activity的處理代碼。

λ adb shell bullhead:/ $ dumpsys activity top | grep ACTIVITYACTIVITY com.google.android.googlequicksearchbox/com.google.android.launcher.GEL cb0b9c6 pid=3519ACTIVITY com.ljhhr.mobile/.ui.login.register.RegisterActivity b215e63 pid=4469

當前頂層activity"com.ljhhr.mobile/.ui.login.register.RegisterActivity",那我們去找下看能找到這個activity的java邏輯不
尷尬 ̄□ ̄||并沒有,說明dump出來的不完整,換個脫殼工具。

1.3.2.關鍵函數hook法脫殼

第二款Frida-Apk-Unpack,該工具也是基于Frida實現的,原理則是對libart.so中的一些關鍵函數進行hook,比如OpenMemory和OpenCommon函數,通過這些函數可以拿到內存中的dex地址,之后就可以計算出dex文件大小并從內存中對dex進行導出。話不多說,奧利給,直接淦

E:\Frida-Apk-Unpack\Frida-Apk-Unpack λ frida -U -f com.ljhhr.mobile -l dexDump.js Spawning `com.ljhhr.mobile`... [04:06:36:441] Android Version: 9 [04:06:36:455] index 3406 function name: _ZN3art16ArtDexFileLoader10OpenCommonEPKhjS2_jRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPKNS_10OatDexFileEbbPS9_NS3_10unique_ptrINS_16DexFileContainerENS3_14default_deleteISH_EEEEPNS_13DexFileLoader12VerifyResultE [04:06:36:460] processName com.ljhhr.mobile [04:06:36:460] Android Version: 9 [04:06:36:460] hookFunction: 0xeec28765 Spawned `com.ljhhr.mobile`. Use %resume to let the main thread start executing! [AOSP on walleye::com.ljhhr.mobile]-> %resume [04:06:42:263] hookFunction onEnter [04:06:42:263] hookFunction onLeave [04:06:42:266] hookFunction onEnter [04:06:42:266] magic : dex /...skip.../ 035 [04:06:42:580] dex_size :6160852 [04:06:42:596] dump dex success, saved path: /data/data/com.ljhhr.mobile/6160852.dex [04:06:42:596] hookFunction onLeave [04:06:42:598] hookFunction onEnter [04:06:42:598] magic : dex /...skip.../ [04:06:42:614] dump dex success, saved path: /data/data/com.ljhhr.mobile/284.dex [04:06:42:614] hookFunction onLeave

它的速度很快,共生成了5個dex文件。我們將這5個dex文件dump出來分別使用jeb工具進行反編譯,看是否有我們需要的代碼。

OK,這次能夠成功找到我們想要的代碼,說明脫殼成功。

2.關鍵代碼定位

現在能看到apk的源碼了,接下來就是對sign生成代碼的定位,我們對核心邏輯定位用的比較多的方法有這幾個,從簡單到復雜依次是關鍵字定位法、相關函數定位法、業務邏輯定位法。
首先是關鍵字定位,就是看數據包中的字段名稱,然后去apk代碼中去搜索相應的字符串,搜到有相關字符后再結合上下文進行確定。這種方法的問題就是可能搜索出來的關鍵字比較多,所以在搜索時可以使用一些技巧比如字符串加分號等,之后遇到再講。還可能關鍵字搜不到那么就需要換方法。
其次是相關函數定位,首先猜測需要定位的邏輯可能會使用到哪些函數,比如常用的加解密函數,獲取用戶輸入的函數等,之后對這類函數進行hook,當觸發hook后輸出當時的調用堆棧,這樣通過調用堆棧基本就能定位到核心邏輯,這樣的好處是在hook對了函數的情況下可以精準快速的定位到關鍵的邏輯。
最后是業務邏輯定位法,這種相對前面兩個就比較麻煩,通過UI信息定位到大概的位置,之后去分析具體的業務邏輯進行定位,比如可以先定位登錄Activity的邏輯,再深入分析具體的處理邏輯。
這里只是舉幾個比較常用的,定位的方法還有很多。
回到主題,這里先使用關鍵字定位看能否定位到sign生成代碼。

POST https://www.100hhr.com/App/Login/phoneCode HTTP/1.1 Content-Type: application/x-www-form-urlencoded Content-Length: 217 Host: www.100hhr.com Connection: Keep-Alive Accept-Encoding: gzip User-Agent: okhttp/3.9.1data=%7B%22type%22%3A%2220%22%2C%22phone%22%3A%2213711111111%22%2C%22countries_code%22%3A%22%2B86%22%2C%22p%22%3A%22android%22%2C%22v%22%3A%2271%22%2C%22time%22%3A1622530753%7D&apisign=7394b88416122929db54df1363fa715c

再抓個數據包開始分析,直接對數據包中的apisign字段進行搜索,掏出另一個反編譯工具jadx,載入前面dump出來的dex文件,使用jadx的無敵搜索功能對關鍵字進行搜索。

我們的運氣不錯搜索出的關鍵字只有一處,雙擊進入代碼具體位置看看。

結合上下文基本可以確定就是我們要找的生成sign數據的邏輯,至此sign生成代碼的定位完成,下面開始分析生成邏輯。

3.sign生成邏輯分析

既然已經找到了sign生成邏輯的所在類"com.ljhhr.resourcelib.network.ParameterInterceptor",那么就可以跟jadx說拜拜了,打開我們的jeb工具,三下五除二就在jeb中定位到了"com.ljhhr.resourcelib.network.ParameterInterceptor"類。這里主要是個人習慣,我比較喜歡使用jeb,感覺jeb的代碼看起來要舒服些,jadx一般用來做字符串搜索。
對這個類簡單分析后,知道應用使用的是目前比較流行的網絡通信框架okhttp+Retrofit進行的網絡通信,而"com.ljhhr.resourcelib.network.ParameterInterceptor"這個類是一個自定義攔截器,攔截器是okhttp框架中很重要的一個特性,應用通過將自定義的攔截器添加到okhttp客戶端中,這樣就可以實現對即將發出的請求及響應結果做統一處理,比如添加一些應用需要和服務端交互的信息,這里的apisign就是這時候添加的。
下面來分析這個自定義攔截器中的主要方法makeRequestBody:

@NonNullprivate RequestBody makeRequestBody(Request arg13) {HttpUrl v0 = arg13.url();FormBody.Builder v1 = new FormBody.Builder();JSONObject v2 = new JSONObject();TreeMap v3 = new TreeMap(new MapKeyComparator());long v4 = System.currentTimeMillis() / 1000L; // 獲取秒級時間戳try {if((arg13.body() instanceof FormBody)) { // instanceof(主要作用就是來判斷左邊的對象是否是它右邊對象的實例)L.d(ParameterInterceptor.TAG, "instanceof FormBody");FormBody v13_1 = (FormBody)arg13.body();if(v13_1 != null) {int v6;for(v6 = v13_1.size() - 1; v6 >= 0; --v6) {String v7 = v13_1.name(v6);String v8 = v13_1.value(v6);v2.put(v7, v8);v3.put(v7, v8);}}}else if(!(arg13.body() instanceof MultipartBody)) {String v13_2 = this.bodyToString(arg13.body());if(!TextUtils.isEmpty(v13_2)) {JSONObject v6_1 = new JSONObject(v13_2);Iterator v13_3 = v6_1.keys();while(v13_3.hasNext()) {Object v7_1 = v13_3.next();String v7_2 = (String)v7_1;v2.put(v7_2, v6_1.get(v7_2));v3.put(v7_2, v6_1.get(v7_2));}}}else {L.d(ParameterInterceptor.TAG, "instanceof MultipartBody");}String v13_4 = SP.getUserID();if(!TextUtils.isEmpty(v13_4)) {v2.put("token", SP.getToken());v2.put("user_id", v13_4);v3.put("token", SP.getToken());v3.put("user_id", v13_4);}v2.put("p", "android");v2.put("v", String.valueOf(71));v2.put("time", v4);v3.put("p", "android");v3.put("v", String.valueOf(71));v3.put("time", Long.valueOf(v4));String v13_5 = "";if(v0.url().toString().contains("App/login/getTttId")) { // 判斷url是否包含"App/login/getTttId"v13_5 = "@wf2w&.:kjf2[getTttId]l{flJ8l@sJisff@";}else {TttIdBean v6_2 = (TttIdBean)SPUtil.getSerializableObject(Constants.TttIdBean);if(v6_2 != null && v6_2.getExp_time() > System.currentTimeMillis()) {StringBuilder v13_6 = new StringBuilder();v13_6.append(v6_2.getTimes());v13_6.append(v6_2.getApikey());v13_6.append("@df2*f2l{+fuif2l}=;/sf2gg^kjf%^fk");v13_6.append(v6_2.getTimes());String v13_7 = MD5Util.ToMD5NOKey(v13_6.toString());v13_5 = "@wf2w&.:kjf2[" + v13_7 + "]l{flJ8l@sJisff@";v2.put("tttid", v6_2.getTttid());v3.put("tttid", v6_2.getTttid());}}StringBuilder v6_3 = new StringBuilder();for(Object v8_1: v3.keySet()) { // 將請求的參數轉為大寫并拼接起來String v8_2 = (String)v8_1;v6_3.append(v8_2.toUpperCase());v6_3.append("=");v6_3.append(v3.get(v8_2).toString().toUpperCase());v6_3.append("&");}String v3_1 = StringUtil.subSuffix(v6_3.toString(), "&"); //去除字符串末尾的"&"StringBuilder v6_4 = new StringBuilder();StringBuilder v7_5 = new StringBuilder();v7_5.append(v4); // 當前時間戳v7_5.append(v13_5); // 一串字符v7_5.append(v3_1); // 被轉成大寫的請求數據v6_4.append(MD5Util.ToMD5NOKey(v7_5.toString()));StringBuilder v7_6 = new StringBuilder();v7_6.append(v3_1);v7_6.append(v4);v7_6.append(v13_5);v6_4.append(MD5Util.ToMD5NOKey(v7_6.toString()));String v13_8 = MD5Util.ToMD5NOKey(v6_4.toString());v1.add("data", v2.toString());v1.add("apisign", v13_8);L.d("請求地址RequestUrl=====", v0.url().toString());L.d("請求參數Params=========", v2.toString());L.json(v2.toString());}catch(JSONException v13) {v13.printStackTrace();}return v1.build();}

對函數簡單分析后得到"apisign"的值等于v13_8,而v13_8來源于MD5Util.ToMD5NOKey(v6_4.toString()),通過分析可知ToMD5NOKey方法是計算MD5的方法,所以v13_8等于v6_4的MD5,v6_4又是由v7_6的MD5與v7_5的MD5拼接而成。而v7_6和v7_5都是v4、v13_5、v3_1的拼接,值是一樣的,不一樣的是拼接的順序。
最終得:v13_8 = MD5(MD5(v4+v13_5+v3_1)+MD5(v3_1+v4+v13_5))
其中:
v4等于當前秒級時間戳
v13_5等于一個字符串,如果請求的url中包含"App/login/getTttId",那就是固定的"@wf2w&.:kjf2[getTttId]l{flJ8l@sJisff@",否則就是動態計算出的另一個字符串
v3_1等于請求參數被轉成大寫后的字符串,根據參數個數不一樣,這個值也不一樣

3.2.Frida確定數據格式

靜態對makeRequestBody函數進行分析后總感覺差點什么,對還沒動態分析,因為所有的靜態分析都是猜想最終還是需要結合動態分析來對我們的分析進行一個確認。
這里使用Frida工具來對ToMD5NOKey方法進行hook,來看下運行過程中真實的數據。
這里需要注意的一點是因為應用帶殼,所以需要在目標應用運行起來后通過frida的attach方式進行hook,如果使用spawn方式則會找不到類。關于這兩種啟動有什么不同可以看看之前的文章"Android逆向-Frida入門學習筆記"里面的2.3.frida的兩種注入模式有介紹。
hook代碼如下:

Java.perform(function() {var cls_MD5Util = Java.use("com.softgarden.baselibrary.utils.MD5Util");cls_MD5Util.ToMD5NOKey.overload('java.lang.String').implementation = function(arg){console.log("================ ToMD5NOKey ==============");console.log(arg) console.log("================ ToMD5NOKey ==============");return this.ToMD5NOKey(arg);} });

運行結果如下:

com.softgarden.baselibrary.utils.MD5Util.ToMD5NOKey(java.lang.String): [Nexus 5X::com.ljhhr.mobile]-> ================ ToMD5NOKey ============== 1622531544COUNTRIES_CODE=+86&P=ANDROID&PHONE=13711111111&TIME=1622531544&TYPE=20&V=71 ================ ToMD5NOKey ============================== ToMD5NOKey ============== COUNTRIES_CODE=+86&P=ANDROID&PHONE=13711111111&TIME=1622531544&TYPE=20&V=711622531544 ================ ToMD5NOKey ============================== ToMD5NOKey ============== 9160810470eb8965238e5c1760b2d7e0b1b0f86f13c6bbea81c0ac69ec4e15c7 ================ ToMD5NOKey ==============

在實際測試中發現應該是只有用戶登錄的情況下v13_5這個變量才會被賦值,否則就是默認的空字符串,其余的和我們前面分析的都一樣。因為主要是對登錄邏輯進行分析,所以v13_5不影響我們的結果,下面開始寫模擬登錄請求的代碼。

4.模擬請求

這里對登錄相關的兩個接口進行了模擬請求,POC如下:

# -*- coding: UTF-8 -*- import hashlib import time import requests from requests.api import head from urllib.parse import quote, urlencodedef ToMD5NOKey(arg1, arg2):str = arg1+arg2str_md5 = hashlib.md5()str_md5.update(str.encode("utf-8"))# print(str_md5.hexdigest())return str_md5.hexdigest()def generate_sign(v1, v2, v3):ToMD5NOKey("", v1+v2+v3)ToMD5NOKey("", v1+v2+v3)# v13_8 = MD5(MD5(v4+v13_5+v3_1)+MD5(v3_1+v4+v13_5))res1 = ToMD5NOKey("", v1+v2+v3)# print(res1)res2 = ToMD5NOKey("", v3+v1+v2)# print(res2)result = ToMD5NOKey("", res1+res2)# print(result)return resultdef request_data(type):if "getcode" == type:type = "20"phone = "13711111111"countries_code = "+86"p = "android"app_version = "71"time_stamp = str(int(time.time())) # 秒級時間戳user_info = "{\"type\":\""+type+"\",\"phone\":\""+phone+"\",\"countries_code\":\"" + \countries_code+"\",\"p\":\""+p+"\",\"v\":\"" + \app_version+"\",\"time\":"+time_stamp+"}"print(user_info)sign_info = "COUNTRIES_CODE="+countries_code+"&P="+p+"&PHONE=" + \phone+"&TIME="+time_stamp+"&TYPE="+type+"&V="+app_versionapisign = generate_sign(time_stamp, "", sign_info)data = "data="+quote(user_info)+"&apisign="+apisignprint(data)return dataelif "register" == type:uuid = ""code = "222222"phone = "13711111111"countries_code = "+86"p = "android"app_version = "71"time_stamp = str(int(time.time())) # 秒級時間戳user_info = "{\"uuid\":\""+uuid+"\",\"code\":\""+code+"\",\"phone\":\""+phone+"\",\"countries_code\":\"" + \countries_code+"\",\"p\":\""+p+"\",\"v\":\"" + \app_version+"\",\"time\":"+time_stamp+"}"print(user_info)sign_info = "CODE="+code+"&COUNTRIES_CODE="+countries_code+"&P="+p+"&PHONE=" + \phone+"&TIME="+time_stamp+"&UUID="+uuid+"&V="+app_versionapisign = generate_sign(time_stamp, "", sign_info)data = "data="+quote(user_info)+"&apisign="+apisignprint(data)return dataelse:print("[-] type value error!")headers = {"Content-Type": "application/x-www-form-urlencoded","Host": "www.100hhr.com", "Connection": "Keep-Alive", "Accept-Encoding": "gzip", "User-Agent": "okhttp/3.9.1"}# 獲取驗證碼接口 def ljhhr_get_verify_code():url = "https://www.100hhr.com/App/Login/phoneCode"data = request_data("getcode")response = requests.post(url=url, headers=headers, data=data)response.closeprint(response.text.encode('utf-8').decode('unicode_escape'))# 用戶注冊接口 def ljhhr_register():url = "https://www.100hhr.com/App/Login/register"data = request_data("register")response = requests.post(url=url, headers=headers, data=data)response.closeprint(response.text.encode('utf-8').decode('unicode_escape'))ljhhr_get_verify_code() ljhhr_register()

完整的登錄請求

λ python ljhhr.py {"type":"20","phone":"13700000000","countries_code":"+86","p":"android","v":"71","time":1622548879} data=%7B%22type%22%3A%2220%22%2C%22phone%22%3A%2213700000000%22%2C%22countries_code%22%3A%22%2B86%22%2C%22p%22%3A%22android%22%2C%22v%22%3A%2271%22%2C%22time%22%3A1622548879%7D&apisign=fad1c8bc56eeebc5e22a30fb3efb831c {"_t":"0.6386","status":1,"info":"發送成功","data":{"code":""},"time":1622548881,"errorCode":"0"}λ python ljhhr.py {"uuid":"","code":"833196","phone":"13700000000","countries_code":"+86","p":"android","v":"71","time":1622548911} data=%7B%22uuid%22%3A%22%22%2C%22code%22%3A%22833196%22%2C%22phone%22%3A%2213700000000%22%2C%22countries_code%22%3A%22%2B86%22%2C%22p%22%3A%22android%22%2C%22v%22%3A%2271%22%2C%22time%22%3A1622548911%7D&apisign=fff370bef976602a9610abe0d9c20c99 {"_t":"0.3459","status":1,"info":"","data":{"token":"f3a44c85ae05622073b6e0e8e1a4904X","user_id":"226402","user":{"id":"226402","phone":"13700000000","head":"\/Public\/Mobile\/images\/img\/im95.png","nickname":"13700000000","sex":"0","money":"0.00","score":"0.00","auth":"0","user_id_code":"0210226402","email":"","exam_level":"0","birthday":"","add_time":"1622548912","sign":"","job":"","info":"","province":"25","city":"321","district":"0","now_city":"0","real_name":"","id_card":"","cc":"86","is_set_password":"0","province_name":"上海","city_name":"上海","district_name":"","now_city_name":"","pay_password_exist":0,"is_bind_wechat":0,"is_bind_qq":0,"is_bi nd_weibo":0,"invite":"0210226402","exam_url":"http:\/\/app.askform.cn\/501d9d2a-44bd-4061-a513-ecf4151af30a.aspx?uid=226402&sign=2e5075287215002592df88abb0260d99&callback=https%3A%2F%2Fwww.100hhr.com%2FApp%2FCallBack%2FaskCallback","exam_disable_string":"","sh_auth":0,"sh_id":0,"sh_is_check":0,"level":0,"is_card":0,"bag_id":0,"shop_end_time":0,"shop_apply_step":0,"exam_score":null,"supplier_id":"","supplier_is_check":"","lecturer_id":"","lecturer_is_check":"","coupons":"0"},"price":"1.17","invite_price":0,"invite_phone":null,"weixin_url":"https:\/\/mp.weixin.qq.com\/mp\/profile_ext?action=home&__biz=MzIzMzkzOTk5MQ==&scene=110#wechat_redirect"},"time":1622548912,"errorCode":"0"}

以上便是一次完整的登錄請求,可以看到模擬的驗證碼獲取和注冊請求都得到了對方服務器的正確響應。接下來就可以更進一步的做安全測試了,比如賬號密碼爆破測試,驗證碼爆破測試等。

5.總結

在整個分析過程中可以發現該應用雖然在客戶端、傳輸過程中、服務端都做了相應的防護,但防護的強度并不夠。傳輸過程中使用的sign簽名機制,雖然一定程度上防止了數據被篡改和偽造的風險,但卻使用的是MD5進行sign的計算,需要注意的是MD5并不是加密算法,而是哈希算法,對于sign生成還是使用自定義的簽名算法比較安全。

總結

以上是生活随笔為你收集整理的Android逆向-实战sign分析-某某合伙人_v4.0.9的全部內容,希望文章能夠幫你解決所遇到的問題。

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