android逆向奇技淫巧二十五:x音另類抓包(十)


  低版本x音client會驗證server的證書,所以把抓包軟件的證書安裝在android系統后就可以冒充server欺騙client抓包了;但是后來的高版本libttboringssl.so中調用了SSL_CTX_set_custom_verify來設置server對client的驗證,這下抓包軟件就抓瞎了,因為不知道client的公鑰,怎么在server面前冒充client了?(當然也可以想辦法在app中找到client的公鑰或證書,然后導入charlse這種抓包軟件,但肯定不輕松)看雪有大佬通過hook或者直接硬編碼把SSL_CTX_set_custom_verify第二個參數改為0,不讓server驗證client;同時把第三個參數回調函數的返回值也改成0來繞開驗證的邏輯,這是非常好的一種思路!我這里根據tls原理、libssl.so或libttboringssl.so源碼從其他角度抓包!

  1、(1)剛打開x音時,client和server要互相驗明正身,由於抓包軟件沒有client的公鑰,是沒法在server面前冒充client的,這里只能罷了!client和server通信首要就是通過handshake協商出雙方對稱加密的key,后續一律通過對稱加密通信!所以handshake階段最重要的就是這個key了!有了這個key,后續一切通信的數據不就能解開了么?這個key怎么獲取了?參考我上一篇文章https://www.cnblogs.com/theseventhson/p/16051195.html 介紹的frida腳本如下:

function startTLSKeyLogger(SSL_CTX_new, SSL_CTX_set_keylog_callback) {
    function keyLogger(ssl, line) {
        console.log(new NativePointer(line).readCString());
    }
    const keyLogCallback = new NativeCallback(keyLogger, 'void', ['pointer', 'pointer']);

    Interceptor.attach(SSL_CTX_new, {
        onLeave: function(retval) {
            const ssl = new NativePointer(retval);
            const SSL_CTX_set_keylog_callbackFn = new NativeFunction(SSL_CTX_set_keylog_callback, 'void', ['pointer', 'pointer']);
            SSL_CTX_set_keylog_callbackFn(ssl, keyLogCallback);
        }
    });
}
startTLSKeyLogger(
    Module.findExportByName('libssl.so', 'SSL_CTX_new'),
    Module.findExportByName('libssl.so', 'SSL_CTX_set_keylog_callback')
)

  我hook的結果是抓了50多個key,部分key如下:

CLIENT_RANDOM 05c10ca9bfb225e24e5fc03fa6dfef05292ce52dab90edd39b20124fd9ce64db 8ea99a617f99e59e1676f26e7266725227d8305fbb48dd36fe91e0e9133b7de4efb28edeacd52d5a06a69d41c4c0d232
CLIENT_RANDOM 75c5363ef6dd0e8ed769bb61dd3b6440d01eb1aa61b52e57be780446281e7b5d c72ba6c9fe54f643d79e330fc83130cd24f88151ea5f2ca9462577cd2585d1a72edd3132010f0bcf675f1aaf9ac5bf94
CLIENT_RANDOM a67744ecb0afb61a70b41604e7e711f56042af51266e02d79d73f28563b2de84 1ab1a45ed5407307e545a47a88a39f2c533c3e5d4effcccdf4a72b12927442fe1b6feaa38063e7ada28a9ca2553e026c
CLIENT_RANDOM 64c75bc38d438669602690369f696df57349e66d5ee784a5e22b66b37f91bff6 f7008fac9daa766edcb636be5ebccc0c3dc3d73c119f39c38f9a7e89d54a508a9da9d96ea30d5b2745639ae275eb8d79
CLIENT_RANDOM b87890d1c9e17f6741985f7e42f96569df9a1153a19c215b107c19a088bec98d 4edec3ac50b381f67125da34014408b70b4c75973db6421fca3e0fde20c859187360e2c68b5efba493ea4efab78fe062
CLIENT_RANDOM bbebae8d1ec928eb785281d56baa50b38f41dd0e6848304af06f4227d1dd1f1c 33c9be07cfd31dbe6a77dfa2f89845f8cf72d1afa196d53bfc9c4bab3757b3b187f631d592e4ac7ec01fb29b87c2a1f5
CLIENT_RANDOM a0a78b7b2a4c100337cd6af637bf40af079ec6bd4f922a3bb1ffbf9f5f4e403b 5c9dd3e00dcac4838fefc498d29d445831e0b92af4480e0dc0815d85552c9f5452bef423a5481252d95066104ef597b1
CLIENT_RANDOM c4ec4ee28686ceb7d68c0c3c1262993848271f809ab3e0824043814e9fa49683 97f2510382981b51bdc3458bda2a0df1994039648ab5b6db9e3d131898952b0574d6772c90461161cc758453ab8e4e10
CLIENT_RANDOM 03572dfae7a9c42406b00d3a17443ed085b42f6094081b6ae951ae5f5a466019 84f2b4c3b08cb3b9335ba087e334fb92f01f0310a9547d220f18604e8e3b3d3780c62d1126ad586707f5fd5e3b6a03e2
CLIENT_RANDOM a190584887037a9deef70ee793ddc8876e379aa196d5c0298216370811c74824 91e661957726600703b2ac7580e0cdce16c135f8627fc1665fa436c4a2a7ea81a10ae55e9754fbc1896e90d4971ba050
CLIENT_RANDOM f379c78bd8efb66d6774cbafa7f7e4953c3d699c24a1cda0e2cfa72e122f9a67 22169928550d7daaf002eeb317de3aae816b2e1dc1b91839fe69f2385e367e39d8723548cfb1dada605c8e6a3d4f6fed
CLIENT_RANDOM 132fd7ae00fa066077d8d99306ee4f248391567fe0cb1edc8859308074361101 4017bee954c38afc02437b472e5c6a175043696cb9587f1680aff3a0c0d5d8d4ec178171e095d4f615a273a445020e0c

  key倒是有了,client和server之間通信的數據又怎么獲取了?

  (2)前面提到了普通的抓包軟件抓不了包,是因為client和server在應用層互相驗證身份,導致charles、fiddler、burpsuit等應用層的抓包軟件立馬抓瞎!換個角度想:所有的數據肯定都是要通過網卡、wifi等硬件設備發送出去的,既然在應用層又驗證無法抓包,為啥不通過“降維打擊”的思路在更底層的傳輸層、ip等、鏈路層等抓包了?這里就要用到wireshark了!由於wireshark是底層抓包,所以完全不用給操作系統裝任何證書,走的也不是“中間人攻擊”的方式抓包,而是直接簡單粗暴地從網卡拿frame數據!現在網絡通信的數據確實拿到了,但應用層是加密的,這時就用到了上面的sslkey了!在wireshark的編輯->首選項->protocols->tls這里把上面hook得到的sslkey上傳,如下:

    

   我這里的抓包結果(我用的是雷電模擬器):這個貌似是個圖片

     

      這里不知道又從x音的cdn拿了啥:

    

   2、上述抓包需要先得到key,再用wireshark解析,各種操作較多,使用並不方便,還有另一種抓包方法:通信雙方不是用tls協議通信么?既然數據是用key加密的,在加密前hook總可以吧? 順着這個思路去hook SSL_write(往外發送數據的)函數和SSL_read(接收外面數據)函數,還真能得到加密前的數據,我hook SSL_write部分結果如下:  

  (1) 這是get方法:

  

  (2)這是post方法:

        

   可以看出確實都是明文的!hook的腳本如下:

function SSL_hook() {
    if (!Java.available) {
        console.error('Java API not available');
        return;
    }
 
    Java.perform(function () {
        console.log('hooked');
        var SSL_write, SSL_read;
        //可查找當前已加載的共享庫的導入與導出方法
        const apiResolver = new ApiResolver('module');
        apiResolver.enumerateMatches('exports:*lib*ssl*!SSL_*').forEach(function (v) {
            if (v.name.indexOf('SSL_write') > 0) {
                SSL_write = v.address;
                console.log('SSL_write:',SSL_write);
            } else if (v.name.indexOf('SSL_read') > 0) {
                SSL_read = v.address;
                console.log('SSL_read:',SSL_read);
            }
        });
 
        if (SSL_write) {
            Interceptor.attach(SSL_write, {
                onEnter: function (args) {
                    this.ssl = args[0].toString();
                    this.buf = ptr(args[1]);
                },
                onLeave: function (retval) {
                    const len = retval.toInt32();
                    if (len > 0) {
                        console.log('SSL_write\n', this.buf.readByteArray(len), '\n', '*'.repeat(120));
                        //send({code: 100,ssl: this.ssl}, this.buf.readByteArray(len));
                        // send({
                            // code: 100,
                            // ssl: this.ssl
                        // }, Memory.readByteArray(this.buf, len));
                    }
                }
            });
        }
 
        if (SSL_read) {
            Interceptor.attach(SSL_read, {
                onEnter: function (args) {
                    this.ssl = args[0].toString();
                    this.buf = ptr(args[1]);
                },
                onLeave: function (retval) {
                    const len = retval.toInt32();
                    if (len > 0) {
                        //console.log('SSL_read\n', this.buf.readByteArray(len), '\n', '*'.repeat(120));
                        //send({code: 200,ssl: this.ssl}, this.buf.readByteArray(len));
                        // send({
                            // code: 200,
                            // ssl: this.ssl
                        // }, Memory.readByteArray(this.buf, len));
                    }
                }
            });
        }
    });
}
 
function main() {
    SSL_hook();
}

setImmediate(main);

   注意:x音不同的版本貌似調用了libssl.so和libttboringssl.so,建議這兩個不同的so都hook一下,看看都發了啥數據!

   3、附上抓包要點的整理和總結如下:

     

 

 

 

參考:

1、http://www.zhuoyue360.com/crack/73.html  android硬核抓包

2、https://bbs.pediy.com/thread-268014.htm 非標准sslpinning抓包

3、https://github.com/google/ssl_logger  ssl_logger

4、https://github.com/BigFaceCat2017/frida_ssl_logger   frida_ssl_logger

5、https://github.com/r0ysue/r0capture


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM