Android代碼混淆 探索

聲明

這篇文章更多的是做一個(gè)整理,內(nèi)容來(lái)自于ProGuard官方文檔以及各種博客等,相關(guān)文章的鏈接在參考目錄里,感興趣的可以去看看。

本人關(guān)于學(xué)習(xí)代碼混淆的建議

了解基本的混淆概念和目的概念 -> 做一下簡(jiǎn)單的代碼混淆實(shí)踐 -> 詳細(xì)了解混淆規(guī)則

目錄:

  • 一:代碼混淆是什么?
  • 二:為什么要進(jìn)行代碼混淆?
  • 三:代碼混淆能保證代碼的絕對(duì)安全嗎?
  • 四:怎么進(jìn)行代碼混淆?
  • 五:什么是 ProGuard
  • 六:Proguard 的作用?
  • 七:Android Studio 中怎么使用 ProGuard 進(jìn)行代碼混淆
  • 八:為什么要了解混淆規(guī)則
  • 九:ProGuard 常用語(yǔ)法(包括 保留、壓縮、優(yōu)化、混淆)
  • 十:混淆注意事項(xiàng)
  • 十一:ProGuard 的輸出文件說(shuō)明
  • 十二:參考

分這么多的目錄是為了 能夠全面而且循序漸進(jìn)得 將 ProGuard 講清楚,同時(shí)適應(yīng)于不同水平的開(kāi)發(fā)者,因?yàn)楹芏鄤側(cè)腴T(mén)的小白對(duì)一些比較基本的概念也是不清楚的,這些也是當(dāng)初我剛接觸 Proguard 時(shí)困惑我的點(diǎn),所以寫(xiě)得比較多,你可以有選擇性得看。

一、代碼混淆是什么?

刪除無(wú)用代碼,將代碼中的各種元素,如包名、類(lèi)名、函數(shù)名、變量名等改成無(wú)意義的符號(hào),使得反編譯你apk的人無(wú)法根據(jù)名字猜測(cè)代碼的用途,這是一種加密手段

二、為什么要進(jìn)行代碼混淆?

如果代碼沒(méi)經(jīng)過(guò)混淆,發(fā)布出去后,別人只需要反編譯即可查看你的源碼,這是一種知識(shí)產(chǎn)權(quán)的保護(hù)手段

三、代碼混淆能保證代碼的絕對(duì)安全嗎?

混淆的目的是為了加大反編譯的成本,但是并不能徹底防止反編譯

四、怎么進(jìn)行代碼混淆?

使用Android Studio創(chuàng)建項(xiàng)目時(shí)會(huì)在項(xiàng)目根目錄下生成一個(gè)proguard-rules.pro文件,該文件便是指定項(xiàng)目混淆規(guī)則的文件,使用的時(shí)候只需要在里面加入相應(yīng)的混淆規(guī)則即可。也就是說(shuō),你在這個(gè)文件里面指定 哪些代碼需要混淆,哪些不需要

至于什么是混淆規(guī)則、混淆規(guī)則的語(yǔ)法、哪些需要或不需要混淆,在下面會(huì)詳細(xì)講到。

五、什么是ProGuard

ProGuard是一個(gè)開(kāi)源的Java 代碼混淆器。它能且只能混淆Android項(xiàng)目里面的java代碼,對(duì)于Native代碼,資源文件Drawable、Xml等無(wú)法進(jìn)行混淆。

  • 官方對(duì)Proguard的解釋是:

Proguard是一個(gè)集合了 文件壓縮、優(yōu)化、混淆和校驗(yàn) 等功能的工具。
它通過(guò)將類(lèi)名、變量名、方法名重命名為無(wú)意義的名稱實(shí)現(xiàn)混淆效果;
它檢測(cè)并刪除無(wú)用的類(lèi),變量,方法和屬性;
它優(yōu)化字節(jié)碼并刪除無(wú)用的指令;
最后它還校驗(yàn)處理后的代碼。

進(jìn)入app下的build.gradle,可以看到:

buildTypes {
    release {
        //buildConfigField "boolean", "LEO_DEBUG", "true" 在編譯時(shí)定義新的屬性及屬性值到BuildConfig.java中
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}

其中proguardFiles getDefaultProguardFile就是制定 混淆規(guī)則 的文件,分兩部分:

(1)前一部分proguard-android.txt代表系統(tǒng)默認(rèn)的android程序的混淆文件,該文件已經(jīng)包含了基本的混淆聲明(例如對(duì)枚舉、注解、Activity等的過(guò)濾),幫我們省去了很多事,這個(gè)文件在SDK/tools/proguard/proguard-android.txt下;

(2)后一部分是我們項(xiàng)目里的自定義的混淆文件,目錄在 app/proguard-rules.pro下,在這個(gè)文件里我們可以聲明一些我們所需要的定制的混淆規(guī)則,主要在這里處理的有 對(duì)第三方庫(kù)的混淆聲明、對(duì)實(shí)體類(lèi)的混淆聲明等。

六、Proguard的作用?

壓縮(Shrink):檢測(cè)并移除代碼中無(wú)用的類(lèi)、字段、方法和特性(Attribute)。
優(yōu)化(Optimize):對(duì)字節(jié)碼進(jìn)行優(yōu)化,移除無(wú)用的指令。
混淆(Obfuscate):使用a,b,c,d這樣簡(jiǎn)短而無(wú)意義的名稱,對(duì)類(lèi)、字段和方法進(jìn)行重命名。
預(yù)檢(Preveirfy):在Java平臺(tái)上對(duì)處理后的代碼進(jìn)行預(yù)檢,確保加載的class文件是可執(zhí)行的。

七、Android Studio中怎么使用ProGuard進(jìn)行代碼混淆

很簡(jiǎn)單,只需要 修改build.grade 配置文件,將 buildTypes代碼塊中的 minifyEnabled false 改為 minifyEnabled true 即可。

注:接下來(lái)在以release模式下打包apk時(shí)便會(huì)自動(dòng)運(yùn)行ProGuard,此時(shí)即使你不添加自己的混淆規(guī)則,也會(huì)進(jìn)行代碼混淆。

可以看看google默認(rèn)的混淆文件,在 \sdk\tools\proguard\proguard-android.txt

接下來(lái)介紹混淆規(guī)則

八、為什么要了解混淆規(guī)則

其實(shí)google已經(jīng)給我們提供了很好的打包規(guī)則, 即如果我們將minifyEnabled set為true后,即使我們?cè)趐roguard-rules.pro 里啥也不寫(xiě), 我們打出來(lái)的release包也是混淆好的

但是!如果我們不添加混淆規(guī)則,一般程序在build的過(guò)程中會(huì)因?yàn)槌霈F(xiàn)問(wèn)題而中斷。

如果加入一些自己的混淆規(guī)則 只需要在 proguard-rules.pro 中文件加入自己的混淆規(guī)則即可,

九、ProGuard常用語(yǔ)法(包括 保留、壓縮、優(yōu)化、混淆)

詳見(jiàn)官方文檔:https://www.guardsquare.com/en/proguard/manual/usage#classspecification

保留

libraryjars

使用該語(yǔ)句把你項(xiàng)目所有用到的jar包都聲明進(jìn)來(lái)

1.libraryjars class_path 應(yīng)用的依賴包,如android-support-v4  
例如:  -libraryjars libs/universal-image-loader-1.9.0.jar

keep相關(guān)語(yǔ)法

表明要保留哪些 Java元素不進(jìn)行混淆 (前3條指定 類(lèi)或成員,后3條指定 類(lèi)或成員 的名稱)

1.keep [,modifier,...] class_specification 不混淆指定的類(lèi)文件和類(lèi)的成員 
例如:
(1).保留某個(gè)包下面的類(lèi)以及子包 -keep public class com.droidyue.com.widget.**
(2).-keep class com.czy.**//不混淆所有com.czy包下的類(lèi),** 換成具體的類(lèi)名則表示不混淆某個(gè)具體的類(lèi)
(3).-keep class com.clock.**{*;}//不混淆所有com.clock包下的類(lèi)和類(lèi)中的所有成員變量,**可以換成具體類(lèi)名,*可以換成具體的字段,可參照Serialzable的混淆 

2.keepclassmembers [,modifier,...] class_specification 不混淆指定類(lèi)的成員,如果此類(lèi)受到保護(hù)他們會(huì)被保護(hù)得更好
例如:
(1).保留所有類(lèi)中使用otto的public方法:
-keepclassmembers class ** {
@com.squareup.otto.Subscribe public *;
@com.squareup.otto.Produce public *;
}
(2).保留Contants類(lèi)的BOOK_NAME屬性:
-keepclassmembers class com.example.admin.proguardsample.Constants {
 public static java.lang.String BOOK_NAME;
}

3.keepclasseswithmembers [,modifier,...] class_specification 不混淆指定的類(lèi)和類(lèi)的成員,但條件是所有指定的類(lèi)和類(lèi)成員是要存在。

4.keepnames class_specification 不混淆指定的類(lèi)和類(lèi)的成員的 名稱(如果他們不會(huì)壓縮步驟中刪除)

5.keepclassmembernames class_specification 不混淆指定的類(lèi)的 成員的名稱 (如果他們不會(huì)壓縮步驟中刪除)

6.keepclasseswithmembernames class_specification 不混淆指定的類(lèi)和類(lèi)的成員 的名稱,如果所有指定的類(lèi)成員出席(在壓縮步驟之后)

7.printseeds {filename} 列出類(lèi)和類(lèi)的成員-keep選項(xiàng)的清單,標(biāo)準(zhǔn)輸出到給定的文件

dontwarn

dontwarn是一個(gè)和keep可以說(shuō)是形影不離,尤其是處理引入的library時(shí).
引入的library可能存在一些無(wú)法找到的引用和其他問(wèn)題,在build時(shí)可能會(huì)發(fā)出警告,如果我們不進(jìn)行處理,通常會(huì)導(dǎo)致build中止.因此為了保證build繼續(xù),我們需要使用dontwarn處理這些我們無(wú)法解決的library的警告.

8.dontwarn [class_filter] 不提示warnning  
例如:關(guān)閉Twitter sdk的警告  -dontwarn com.twitter.sdk.**

壓縮

9.dontshrink 不壓縮輸入的類(lèi)文件
10.printusage {filename}
11.whyareyoukeeping {class_specification}

優(yōu)化

12.dontoptimize 不優(yōu)化輸入的類(lèi)文件
13.assumenosideeffects {class_specification} 優(yōu)化時(shí)假設(shè)指定的方法,沒(méi)有任何副作用,即假設(shè)調(diào)用不產(chǎn)生任何影響,在proguard代碼優(yōu)化時(shí)會(huì)將該調(diào)用remove掉。如system.out.println和Log.v等等  
14.allowaccessmodification 優(yōu)化時(shí)允許訪問(wèn)并修改有修飾符的類(lèi)和類(lèi)的成員,

混淆

15.dontobfuscate 不混淆輸入的類(lèi)文件
16.obfuscationdictionary {filename} 使用給定文件中的關(guān)鍵字作為要混淆方法的名稱
17.overloadaggressively 混淆時(shí)應(yīng)用侵入式重載
18.useuniqueclassmembernames 確定統(tǒng)一的混淆類(lèi)的成員名稱來(lái)增加混淆
19.flattenpackagehierarchy {package_name} 重新包裝所有重命名的包并放在給定的單一包中
20.repackageclass {package_name} 重新包裝所有重命名的類(lèi)文件中放在給定的單一包中
21.dontusemixedcaseclassnames 混淆時(shí)不會(huì)產(chǎn)生形形色色的類(lèi)名
22.keepattributes {attribute_name,…} 保護(hù)給定的可選屬性,例如LineNumberTable, LocalVariableTable, SourceFile, Deprecated, Synthetic, Signature, and InnerClasses.
23.renamesourcefileattribute {string} 設(shè)置源文件中給定的字符串常量

通配符匹配規(guī)則

通配符 規(guī)則
匹配單個(gè)字符
* 匹配類(lèi)名中的任何部分,但不包含額外的包名
** 匹配類(lèi)名中的任何部分,并且可以包含額外的包名
% 匹配任何基礎(chǔ)類(lèi)型的類(lèi)型名

詳細(xì)通配符見(jiàn)官方文檔
https://www.guardsquare.com/en/proguard/manual/usage#classspecification

十、混淆注意事項(xiàng)

1.哪些不能混淆

1.反射中使用的元素,如一些ORM框架的使用,需要保證類(lèi)名、方法不變, 不然混淆后, 就反射不了

如果用到了反射需要加入 : 
-keepattributes Signature  
-keepattributes EnclosingMethod  

2.如果想讓一些bean 對(duì)象不混淆, 例如com.czy.bean 包下面的全是 Json框架生成的bean對(duì)象, 那么只需加入:

-keep class czy.**{*;}//不混淆所有的com.czy.bean包下的類(lèi)和這些類(lèi)的所有成員變量 

3.枚舉也不要混淆

4.四大組件不建議混淆,因?yàn)樗拇蠼M件聲明必須在manifest中注冊(cè),而混淆后類(lèi)名會(huì)發(fā)生更改,此時(shí)混淆后的類(lèi)名沒(méi)有在manifest注冊(cè),這是不符合Android組件注冊(cè)機(jī)制的。(AndroidMainfest中的類(lèi)不混淆,四大組件和Application的子類(lèi)和Framework層下所有的類(lèi)默認(rèn)不會(huì)進(jìn)行混淆)

5.注解不能混淆
注解在Android平臺(tái)中使用的越來(lái)越多,常用的有ButterKnife和Otto.很多場(chǎng)景下注解被用作在運(yùn)行時(shí)反射確定一些元素的特征.

為了保證注解正常工作,我們不應(yīng)該對(duì)注解進(jìn)行混淆.Android工程默認(rèn)的混淆配置已經(jīng)包含了下面保留注解的配置

-keepattributes *Annotation*

6.JNI調(diào)用的java方法

7.Java的Native方法

8.JS調(diào)用Java的方法

9.WebView中JavaScript調(diào)用的方法方法不混淆

有用到WEBView的JS調(diào)用接口,需加入如下規(guī)則: 
-keepclassmembers class fqcn.of.javascript.interface.for.webview {  
   public *;  
}  
-keep class com.xxx.xxx.** { *; }//保持WEB接口不被混淆 此處xxx.xxx是自己接口的包名  

10.第三方庫(kù)不建議混淆,使用第三方開(kāi)源庫(kù)或者引用其他第三方的SDK包時(shí),需要在混淆文件中加入對(duì)應(yīng)的混淆規(guī)則(關(guān)于第三方的庫(kù)的, 一般都是看他們的官方文檔)

這里推薦兩個(gè)開(kāi)源項(xiàng)目,里面收集了一些第三方庫(kù)的混淆規(guī)則
android-proguard-snippets
android-proguard-cn

不難理解,混淆之后,類(lèi)名會(huì)變成a,b,c這種,通過(guò)包名+類(lèi)名自然就會(huì)找不到該類(lèi)了,自然就會(huì)出現(xiàn)ClassNotFoundException異常。這里推薦一篇文章:http://www.itnose.net/detail/6043297.html

11.Parcelable的子類(lèi)和Creator靜態(tài)成員變量不混淆,否則會(huì)產(chǎn)生android.os.BadParcelableException異常

12.GSON的序列化與反序列化

使用GSON、fastjson等框架時(shí),所寫(xiě)的JSON對(duì)象類(lèi)不混淆,否則無(wú)法將JSON解析成對(duì)應(yīng)的對(duì)象

13.繼承了Serializable接口的類(lèi),在反序列化的時(shí)候, 需要正確的類(lèi)名等, 在Android 中大多是實(shí)現(xiàn) Parcelable來(lái)序列化的

繼承了Serializable接口的類(lèi),需要加上:

//不混淆Serializable接口的子類(lèi)中指定的某些成員變量和方法  
-keepclassmembers class * implements java.io.Serializable {  
static final long serialVersionUID;  
private static final java.io.ObjectStreamField[] serialPersistentFields;  
private void writeObject(java.io.ObjectOutputStream);  
private void readObject(java.io.ObjectInputStream);  
java.lang.Object writeReplace();  
java.lang.Object readResolve();  
}  

14.Layout文件引用到的自定義View

2.Log處理

我們都知道,使用Log的時(shí)候,需要用到TAG,然而TAG我們一般都會(huì)寫(xiě)成:

private static final String TAG = MainActivity.class.getSimpleName()

這時(shí)候MainActivity如果被混淆的話,log輸出信息就會(huì)變成V/a:xxxxxxx,所以為了讓log輸出信息維持原狀,可以將TAG處理成固定的字符串:

private static final String TAG = "MainActivity"

正好Android Studio里面的 Live Templates 能讓你輕輕松松的聲明TAG !
關(guān)于Log處理,推薦一篇文章:https://www.zybuluo.com/shark0017/note/163330

移除一些log代碼:
移除Log類(lèi)打印各個(gè)等級(jí)日志的代碼,打正式包的時(shí)候可以做為禁log使用,這里可以作為禁止log打印的功能使用,另外的一種實(shí)現(xiàn)方案是通過(guò)BuildConfig.DEBUG的變量來(lái)控制

-assumenosideeffects class android.util.Log {  
public static *** v(...);  
public static *** i(...);  
public static *** d(...);  
public static *** w(...);  
public static *** e(...);  
}  

3.Crash信息處理

代碼混淆的時(shí)候記得加上在混淆文件里面記得加上這句:
# keep住源文件以及行號(hào)
-keepattributes SourceFile,LineNumberTable

否則你將看到崩潰信息
這里推薦bugly的一篇文章: http://bugly.qq.com/bbs/forum.php?mod=viewthread&tid=26&extra=page%3D1

十一、ProGuard的輸出文件說(shuō)明

混淆后,會(huì)在/build/proguard/目錄下輸出下面的文件

dump.txt 描述apk文件中所有類(lèi)文件間的內(nèi)部結(jié)構(gòu)。
mapping.txt 列出了原始的類(lèi),方法,和字段名與混淆后代碼之間的映  射。
seeds.txt 列出了未被混淆的類(lèi)和成員
usage.txt 列出了從apk中刪除的代碼 當(dāng)我們需要處理crash log的時(shí)候,就可以通過(guò)mapping.txt的映射關(guān)系找到對(duì)應(yīng)的類(lèi),方法,字段等。方法如下:

sdk\tools\proguard\bin 目錄下有個(gè)retrace工具可以將混淆后的報(bào)錯(cuò)堆棧解碼成正常的類(lèi)名window下為retrace.bat,linux和mac為retrace.sh,

使用方法如下:

1.將crash log保存為yourfilename.txt
2.拿到版本發(fā)布時(shí)生成的mapping.txt
3.執(zhí)行命令retrace.bat -verbose mapping.txt yourfilename.txt

所以我們每次打包版本都需要保存最新的mapping.txt文件。如果要使用到第三方的crash統(tǒng)計(jì)平臺(tái),比如bugly,還需要我們上傳APP版本對(duì)應(yīng)的mapping.txt.每次都要保存最新的mapping文件,那不就很麻煩?放心,gradle會(huì)幫到你,只需要在bulid.gradle加入下面的一句。每次我們編譯的時(shí)候,都會(huì)自動(dòng)幫你保存mapping文件到本地的。

android {
applicationVariants.all { variant ->
    variant.outputs.each { output ->
        if (variant.getBuildType().isMinifyEnabled()) {
            variant.assemble.doLast{
                    copy {
                        from variant.mappingFile
                        into "${projectDir}/mappings"
                        rename { String fileName ->
                            "mapping-${variant.name}.txt"
                        }
                    }
            }
        }
    }
    ......
}
}

實(shí)踐記錄

混淆實(shí)體類(lèi)

實(shí)體類(lèi)不能混淆,需要保留setget方法。對(duì)于boolean類(lèi)型的get方法為isXXX,不能遺漏。在開(kāi)發(fā)的時(shí)候我們可以將所有的實(shí)體類(lèi)放在一個(gè)包內(nèi),這樣我們寫(xiě)一次混淆就行了。

-keep public class com.ljd.example.entity.** {
public void set*(***);
public *** get*();
public *** is*();
}

-keep class com.demo.login.bean.** { *; }
-keep class com.demo.main.bean.** { *; }

反編譯三步走:

1.下載以下三個(gè)工具:

  • apktool
    • 作用:資源文件獲取,可以提取出圖片文件和布局文件進(jìn)行使用查看
  • dex2jar
    • 作用:將apk反編譯成Java源碼(classes.dex轉(zhuǎn)化成jar文件)
  • jd-gui
    • 作用:查看APK中classes.dex轉(zhuǎn)化成出的jar文件,即源碼文件

2.下載上述工具中的apktool,解壓得到3個(gè)文件:aapt.exeapktool.batapktool.jar

將需要反編譯的APK文件放到該目錄下,打開(kāi)命令行界面(運(yùn)行-CMD) ,定位到apktool文件夾,輸入以下命令:

apktool.bat d -f  test.apk  test    

apktool.bat   d  -f    [apk文件 ]   [輸出文件夾])

此時(shí)test文件夾下即包含了所有資源文件

3.下載上述工具中的dex2jarjd-gui ,解壓

將要反編譯的APK后綴名改為.rar或則 .zip,并解壓,得到其中的classes.dex文件(它就是java文件編譯再通過(guò)dx工具打包而成的),將獲取到的classes.dex放到之前解壓出來(lái)的工具dex2jar-0.0.9.15 文件夾內(nèi),
在命令行下定位到dex2jar.bat所在目錄,輸入dex2jar.bat classes.dex

在改目錄下會(huì)生成一個(gè)classes_dex2jar.jar的文件,然后打開(kāi)工具jd-gui文件夾里的jd-gui.exe,之后用該工具打開(kāi)之前生成的classes_dex2jar.jar文件,便可以看到源碼了

4.下面圖文解釋,對(duì)應(yīng)上面流程

進(jìn)入工具`apktool`目錄下,執(zhí)行`apktool.bat d -f app-release.apk`,app-release為你的`apk`名稱
此時(shí)會(huì)生成反編譯`apk`后得到的資源文件`app-release`,你也可以在上面的命令中指定輸出文件的名稱,如`apktool.bat d -f app-release.apk test`,則會(huì)生成一個(gè)文件夾`test`來(lái)存放反編譯得到的資源文件
按照上面步驟將解壓后得到的`classes.dex`文件放到工具`dex2jar`文件夾后,`cmd`進(jìn)入`dex2jar`并執(zhí)行`dex2jar.bat classes.dex`
此時(shí)`dex2jar`工具下出現(xiàn)`classes_dex2jar.jar`
進(jìn)入工具`jd-gui-0.3.5.windows`下運(yùn)行`jd-gui.exe`并用`jd-gui.exe`打開(kāi)上面生成的`classes_dex2jar.jar`文件即可看到反編譯的項(xiàng)目

注:上述反編譯資料來(lái)自http://blog.csdn.net/vipzjyno1/article/details/21039349/

參考

ProGuard手冊(cè)
ProGuard手冊(cè) Version4.7

ProGuard代碼混淆技術(shù)詳解
Android分享:代碼混淆那些事
http://blog.csdn.net/qq_35224673/article/details/52038093
http://blog.csdn.net/chen930724/article/details/49687067
http://blog.csdn.net/ljd2038/article/details/51308768 很詳細(xì)


http://www.tuicool.com/articles/vyEnu2A 含例子
http://www.lxweimin.com/p/be7ec1819d2f 含模板
http://www.lxweimin.com/p/7391f0c554be 含內(nèi)嵌類(lèi)處理
常用第三方庫(kù)的混淆
常用第三方庫(kù)的混淆

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,428評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,024評(píng)論 3 413
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 175,285評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,548評(píng)論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,328評(píng)論 6 404
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 54,878評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,971評(píng)論 3 439
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,098評(píng)論 0 286
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,616評(píng)論 1 331
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,554評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,725評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,243評(píng)論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 43,971評(píng)論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,361評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,613評(píng)論 1 280
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,339評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,695評(píng)論 2 370

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,582評(píng)論 25 707
  • 什么是代碼混淆 代碼混淆就是將代碼中的各種元素,如變量,方法,類(lèi)和包的名字改寫(xiě)成無(wú)意義的名字,增加項(xiàng)目反編譯后被讀...
    蝸牛家族史閱讀 5,186評(píng)論 1 4
  • 混淆(Proguard)用法 最近項(xiàng)目中遇到一些混淆相關(guān)的問(wèn)題,由于之前對(duì)proguard了解不多,所以每次都是面...
    于曉飛93閱讀 56,825評(píng)論 38 230
  • 01 昨天跟家里打電話,我媽又習(xí)慣性地跟我嘮起了家常,什么誰(shuí)家的孩子考上了一本,誰(shuí)家的孩子來(lái)了錄取通知書(shū),誰(shuí)家的孩...
    余少閱讀 3,397評(píng)論 47 31
  • 姊齒秀次造假事件 一宗發(fā)生在日本的建筑舞弊案件。該案于2005年底被揭發(fā),起因于一級(jí)建筑師姊齒秀次基于個(gè)人利益而長(zhǎng)...
    ucudrrad閱讀 196評(píng)論 0 0