<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    XX客戶端APP簽名分析之算法分析篇

    VSole2021-08-02 19:06:58

    前言

    將脫殼后的dex文件在jadx打開,由于脫殼后會產生多個dex,因此先用腳本合并一下比較方便。當然最新版jadx支持增加文件,也可以直接添加。

    import os, sys
    path = r'xxxx'# 文件夾目錄files = os.listdir(path)  out_path =r'xxxxx'  #路徑s = []for file in files:  # 遍歷文件夾    if file.find("dex") > 0:  ## 查找dex 文件        sh = f'jadx -j 1 -r -d {out_path} {path}\\{file}'        print(sh)        os.system(sh)`
    

    同時使用抓包軟件開始對app進行抓包,對于移動端的app抓包,證書的安裝一直是一個很繁瑣的問題,在這里推薦一款Magisk的模塊Move Certificates,可以很方便的將用戶證書移動到系統層,實現https的抓包。

    這里主要的功能側重點在bbsapi.domo.cn和class.domo.cn上,因為該app主要的功能點就是在這兩個地址下。


    查看一下數據包的內容,可以看到path中是包含sign值的

    /newapi/live/square/live-count?noncestr=84140992&sign=47e714f977952ad75eb6eeb3165083dae93502b3×tamp=1627008983764<
    

    目標就是要找到這個sign值的生成算法。首先到jad中進行代碼定位,為了降低逆向難度,可以選擇從noncestr入手,進行搜索可能會簡單一點,當然這只能是經驗之談,一切還是要以實際分析情況為準。

    可以看一下如果搜索sign,會有多少結果。

    繼續看noncestr,看到搜索到了14個相關代碼,根據類名來看,選擇一個最最有可能的先看一下。



    可以看到是有getSign函數在這個類下面的,采用直接hook這個函數也不是很現實,由于jadx的問題,是無法顯示該函數下的代碼,這個時候,可以采用直接hook該函數的系統加密函數的方法,來查看是否是直接采用了比如MD5,SHA1,Base64等等常規加密的方法,對于此,直接hook后查看輸入和輸出。

    編寫frida腳本進行測試一下。


    update:appSignKey=ac6190d7dfaa77df726f0a82244d3eda68675ccd4e95de802f5042e91d15edc7bae3026d8f0fb2a8287446bb289563970264&noncestr=12520893×tamp=1627023153533digest:e2931f94fdf5cbad61d95bf23b192841a12f1a8c
    

    可以看到上傳數據的構成是appSignKey+noncestr和timestamp構成。多次抓包發現appSignKey是一個固定值(只是class.domo.cn下的固定值,該app不同的網址采用不同的Key值)并且結果跟抓包數據完全一致。這時候主要的問題就是找到使用的默認算法。可以看到第一個調用的函數就是java.security.MessageDigest.digest(Native Method),該類提供了消息摘要算法,如 MD5 或 SHA,的功能。因此可以模擬測試一下,看一下采用的是MD5還是SHA算法。


    測試發現采用的是SHA1算法。noncestr就是隨機8位數字組成,每次可以采用上一次所生成的,或者是自己生成即可。noncestr算法還原。

    Random random=new Random();
    for(int i=0;i<8;i++){    str.append(random.nextInt(10));}
    int num=Integer.parseInt(str.toString());System.out.println(num);
    

    此外,對于bbsapi.domo.cn,它的update是

    appSignKey=Wj8BI3VUZ6BuojAkqzBM3HWHNHv08xdZEtaksbRg6snnuLsvivwa8IvR6PvQ76H0IQQsqkIsa5OKJtg6QcBMfCblMMywgZaA8co&noncestr=63606047×tamp=1627023164959采用了不同的key值來進行拼接。
    

    總結

    該app的簽名算法還原后即為,key+noncestr+timestamp。之后進行SHA1加密,生成sign。最后附上frida hook代碼

        base64DecodeChars = new Array((-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), 62, (-1), (-1), (-1), 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, (-1), (-1), (-1), (-1), (-1), (-1), (-1), 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, (-1), (-1), (-1), (-1), (-1), (-1), 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, (-1), (-1), (-1), (-1), (-1));var stringToBase64 = function (e) {    var r, a, c, h, o, t;    for (c = e.length, a = 0, r = ''; a < c;) {        if (h = 255 & e.charCodeAt(a++), a == c) {            r += base64EncodeChars.charAt(h >> 2),                r += base64EncodeChars.charAt((3 & h) << 4),                r += '==';            break        }        if (o = e.charCodeAt(a++), a == c) {            r += base64EncodeChars.charAt(h >> 2),                r += base64EncodeChars.charAt((3 & h) << 4 | (240 & o) >> 4),                r += base64EncodeChars.charAt((15 & o) << 2),                r += '=';            break        }        t = e.charCodeAt(a++),            r += base64EncodeChars.charAt(h >> 2),            r += base64EncodeChars.charAt((3 & h) << 4 | (240 & o) >> 4),            r += base64EncodeChars.charAt((15 & o) << 2 | (192 & t) >> 6),            r += base64EncodeChars.charAt(63 & t)    }    return r}var base64ToString = function (e) {    var r, a, c, h, o, t, d;    for (t = e.length, o = 0, d = ''; o < t;) {        do            r = base64DecodeChars[255 & e.charCodeAt(o++)];        while (o < t && r == -1);        if (r == -1)            break;        do            a = base64DecodeChars[255 & e.charCodeAt(o++)];        while (o < t && a == -1);        if (a == -1)            break;        d += String.fromCharCode(r << 2 | (48 & a) >> 4);        do {            if (c = 255 & e.charCodeAt(o++), 61 == c)                return d;            c = base64DecodeChars[c]        } while (o < t && c == -1);        if (c == -1)            break;        d += String.fromCharCode((15 & a) << 4 | (60 & c) >> 2);        do {            if (h = 255 & e.charCodeAt(o++), 61 == h)                return d;            h = base64DecodeChars[h]        } while (o < t && h == -1);        if (h == -1)            break;        d += String.fromCharCode((3 & c) << 6 | h)    }    return d}
    
    var hexToBytes = function (str) {    var pos = 0;    var len = str.length;    if (len % 2 != 0) {        return null;    }    len /= 2;    var hexA = new Array();    for (var i = 0; i < len; i++) {        var s = str.substr(pos, 2);        var v = parseInt(s, 16);        hexA.push(v);        pos += 2;    }    return hexA;}var bytesToHex = function (arr) {    var str = '';    var k, j;    for (var i = 0; i < arr.length; i++) {        k = arr[i];        j = k;        if (k < 0) {            j = k + 256;        }        if (j < 16) {            str += "0";        }        str += j.toString(16);    }    return str;}var stringToHex = function (str) {    var val = "";    for (var i = 0; i < str.length; i++) {        if (val == "")            val = str.charCodeAt(i).toString(16);        else            val += str.charCodeAt(i).toString(16);    }    return val}var stringToBytes = function (str) {    var ch, st, re = [];    for (var i = 0; i < str.length; i++) {        ch = str.charCodeAt(i);        st = [];
            do {            st.push(ch & 0xFF);            ch = ch >> 8;        }        while (ch);        re = re.concat(st.reverse());    }    return re;}
    var bytesToString = function (arr) {    var str = '';    arr = new Uint8Array(arr);    for (var i in arr) {        str += String.fromCharCode(arr[i]);    }    return str;}var bytesToBase64 = function (e) {    var r, a, c, h, o, t;    for (c = e.length, a = 0, r = ''; a < c;) {        if (h = 255 & e[a++], a == c) {            r += base64EncodeChars.charAt(h >> 2),                r += base64EncodeChars.charAt((3 & h) << 4),                r += '==';            break        }        if (o = e[a++], a == c) {            r += base64EncodeChars.charAt(h >> 2),                r += base64EncodeChars.charAt((3 & h) << 4 | (240 & o) >> 4),                r += base64EncodeChars.charAt((15 & o) << 2),                r += '=';            break        }        t = e[a++],            r += base64EncodeChars.charAt(h >> 2),            r += base64EncodeChars.charAt((3 & h) << 4 | (240 & o) >> 4),            r += base64EncodeChars.charAt((15 & o) << 2 | (192 & t) >> 6),            r += base64EncodeChars.charAt(63 & t)    }    return r}var base64ToBytes = function (e) {    var r, a, c, h, o, t, d;    for (t = e.length, o = 0, d = []; o < t;) {        do            r = base64DecodeChars[255 & e.charCodeAt(o++)];        while (o < t && r == -1);        if (r == -1)            break;        do            a = base64DecodeChars[255 & e.charCodeAt(o++)];        while (o < t && a == -1);        if (a == -1)            break;        d.push(r << 2 | (48 & a) >> 4);        do {            if (c = 255 & e.charCodeAt(o++), 61 == c)                return d;            c = base64DecodeChars[c]        } while (o < t && c == -1);        if (c == -1)            break;        d.push((15 & a) << 4 | (60 & c) >> 2);        do {            if (h = 255 & e.charCodeAt(o++), 61 == h)                return d;            h = base64DecodeChars[h]        } while (o < t && h == -1);        if (h == -1)            break;        d.push((3 & c) << 6 | h)    }    return d}
    
    Java.perform(function () {
        function showStacks() {        console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()));    }
    
        var secretKeySpec = Java.use('javax.crypto.spec.SecretKeySpec');    secretKeySpec.$init.overload('[B', 'java.lang.String').implementation = function (a, b) {        showStacks();        var result = this.$init(a, b);        console.log("======================================");        console.log("算法名:" + b + "|Dec密鑰:" + bytesToString(a));        console.log("算法名:" + b + "|Hex密鑰:" + bytesToHex(a));        return result;    }
    
        var mac = Java.use('javax.crypto.Mac');    mac.getInstance.overload('java.lang.String').implementation = function (a) {        showStacks();        var result = this.getInstance(a);        console.log("======================================");        console.log("算法名:" + a);        return result;    }    mac.update.overload('[B').implementation = function (a) {        showStacks();        this.update(a);        console.log("======================================");        console.log("update:" + bytesToString(a))    }    mac.update.overload('[B', 'int', 'int').implementation = function (a, b, c) {        showStacks();        this.update(a, b, c)        console.log("======================================");        console.log("update:" + bytesToString(a) + "|" + b + "|" + c);    }    mac.doFinal.overload().implementation = function () {        showStacks();        var result = this.doFinal();        console.log("======================================");        console.log("doFinal結果:" + bytesToHex(result));        console.log("doFinal結果:" + bytesToBase64(result));        return result;    }    mac.doFinal.overload('[B').implementation = function (a) {        showStacks();        var result = this.doFinal(a);        console.log("======================================");        console.log("doFinal參數:" + bytesToString(a));        console.log("doFinal結果:" + bytesToHex(result));        console.log("doFinal結果:" + bytesToBase64(result));        return result;    }
    
        var md = Java.use('java.security.MessageDigest');    md.getInstance.overload('java.lang.String', 'java.lang.String').implementation = function (a, b) {        showStacks();        console.log("======================================");        console.log("算法名:" + a);        return this.getInstance(a, b);    }    md.getInstance.overload('java.lang.String').implementation = function (a) {        showStacks();        console.log("======================================");        console.log("算法名:" + a);        return this.getInstance(a);    }
        md.update.overload('[B').implementation = function (a) {        showStacks();        console.log("======================================");        console.log("update:" + bytesToString(a))        return this.update(a);    }    md.update.overload('[B', 'int', 'int').implementation = function (a, b, c) {        showStacks();        console.log("======================================");        console.log("update:" + bytesToString(a) + "|" + b + "|" + c);        return this.update(a, b, c);    }
        md.digest.overload().implementation = function () {        showStacks();        console.log("======================================");        var result = this.digest();        console.log("digest結果:" + bytesToHex(result));        console.log("digest結果:" + bytesToBase64(result));        return result;    }    md.digest.overload('[B').implementation = function (a) {        showStacks();        console.log("======================================");        console.log("digest參數:" + bytesToString(a));        var result = this.digest(a);        console.log("digest結果:" + bytesToHex(result));        console.log("digest結果:" + bytesToBase64(result));        return result;    }
    
        var ivParameterSpec = Java.use('javax.crypto.spec.IvParameterSpec');    ivParameterSpec.$init.overload('[B').implementation = function (a) {        showStacks();        var result = this.$init(a);        console.log("======================================");        console.log("iv向量:" + bytesToString(a));        console.log("iv向量:" + bytesToHex(a));        return result;    }
    
        var cipher = Java.use('javax.crypto.Cipher');    cipher.getInstance.overload('java.lang.String').implementation = function (a) {        showStacks();        var result = this.getInstance(a);        console.log("======================================");        console.log("模式填充:" + a);        return result;    }    cipher.update.overload('[B').implementation = function (a) {        showStacks();        var result = this.update(a);        console.log("======================================");        console.log("update:" + bytesToString(a));        return result;    }    cipher.update.overload('[B', 'int', 'int').implementation = function (a, b, c) {        showStacks();        var result = this.update(a, b, c);        console.log("======================================");        console.log("update:" + bytesToString(a) + "|" + b + "|" + c);        return result;    }    cipher.doFinal.overload().implementation = function () {        showStacks();        var result = this.doFinal();        console.log("======================================");        console.log("doFinal結果:" + bytesToHex(result));        console.log("doFinal結果:" + bytesToBase64(result));        return result;    }    cipher.doFinal.overload('[B').implementation = function (a) {        showStacks();        var result = this.doFinal(a);        console.log("======================================");        console.log("doFinal參數:" + bytesToString(a));        console.log("doFinal結果:" + bytesToHex(result));        console.log("doFinal結果:" + bytesToBase64(result));        return result;    }
    
        var x509EncodedKeySpec = Java.use('java.security.spec.X509EncodedKeySpec');    x509EncodedKeySpec.$init.overload('[B').implementation = function (a) {        showStacks();        var result = this.$init(a);        console.log("======================================");        console.log("RSA密鑰:" + bytesToBase64(a));        return result;    }
    
        var rSAPublicKeySpec = Java.use('java.security.spec.RSAPublicKeySpec');    rSAPublicKeySpec.$init.overload('java.math.BigInteger', 'java.math.BigInteger').implementation = function (a, b) {        showStacks();        var result = this.$init(a, b);        console.log("======================================");        //console.log("RSA密鑰:" + bytesToBase64(a));        console.log("RSA密鑰N:" + a.toString(16));        console.log("RSA密鑰E:" + b.toString(16));        return result;    }
    });
    

    算法還原之后,下一篇將進行完結,打造bp插件,實現無縫銜接測試。

    var
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    據外媒報道,在檢測到其系統受到網絡攻擊近兩周后,德國電池制造商Varta AG仍未恢復其工廠的生產。該公司生產各種用于家用和工業用途的電池和存儲產品,包括鋰離子小型化電池和移動電源。Varta AG首次檢測到對其系統的網絡攻擊2月12日,其本周發表聲明稱,目前沒有可靠的信息表明處理和解決攻擊需要多長時間,或者所有五個全球生產基地的何時將全面投入運營。然而,工廠的第一批預計將在下周再次啟動。
    第十一屆信息安全漏洞分析與風險評估大會9月16日,2018世界物聯網博覽會信息安全高峰論壇暨第十一屆信息安全漏洞分析與風險評估大會在無錫市濱湖區成功舉辦。來自政府相關主管部門、重要行業、高等院校、研究機構、物聯網產業界、信息安全產業界等近千名中外嘉賓參加了大會。來自政府部門、高等院校、研究機構、信息安全產業界及應用單位的800余名嘉賓參加了大會。
    /usr/目錄usr是user的縮寫,是曾經的HOME目錄,然而現在已經被/home取代了,現在usr被稱為是Unix System Resource,即Unix系統資源的縮寫。默認軟件都會存于該目錄下。用于存儲只讀用戶數據的第二層次;包含絕大多數的用戶工具和應用程序。
    作為世界物聯網博覽會高峰論壇之一的“2021世界物聯網博覽會信息安全高峰論壇暨第十三屆信息安全漏洞分析與風險評估大會”,將于10月22日召開。
    “2021世界物聯網博覽會信息安全高峰論壇暨第十三屆信息安全漏洞分析與風險評估大會”(VARA大會)將于10月22日在江蘇省無錫市召開。
    Python人工智能第11篇文章介紹如何保存神經網絡參數
    動態函數PHP中支持一個功能叫 variable function ,變量函數的意思。//最終是system;當一個變量后邊帶括號,那他就被視作一個函數。編譯器會解析出變量的值,然后會去找當前是否存在名為“system()”的函數并執行它。這里就不給實例了,很多免殺案例中都用到了這個特性。也是被瘋狂查殺的特征。回調函數回調函數,簡單來說就是一個函數不是由我直接調用,而是通過另一個函數去調用它。
    1Docker 遷移存儲目錄默認情況系統會將 Docker 容器存放在 /var/lib/docker 目錄下[問題起因]?今天通過監控系統,發現公司其中一臺服務器的磁盤快慢,隨即上去看了下,發現?由上述原因,我們都知道,在?中存儲的都是相關于容器的存儲,所以也不能隨便的將其刪除掉。設備進行擴容來達到相同的目的。的詳細參數,請點擊查看?但是需要注意的一點就是,盡量不要用軟鏈, 因為一些?容器編排系統不支持這樣做,比如我們所熟知的?發現容器啟動不了了
    在本次2022 RSAC會議中,來自Varonis公司的Matt Radolec分享了議題《Pain in the Apps — Three Attack Scenarios Attackers Are Using to PWN SaaS》,主要介紹了三種針對SaaS平臺的攻擊場景,詳細地說明了每個階段攻擊者的攻擊手法以及對應的檢測思路
    Meta Platforms 近日采取了一系列措施制裁來自意大利、西班牙和阿拉伯等多國的八家間諜軟件公司,分別是 Cy4Gate/ELT Group、RCS Labs、IPS Intelligence、Variston IT、TrueL IT、Protect Electronic Systems、Negg Group 和 Mollitiam Industries。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类