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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java源程序加密解决方案(基于Classloader解密)

發布時間:2024/4/14 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java源程序加密解决方案(基于Classloader解密) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

源程序加密解決方案

1. 概述:
Java源程序的加密,有如下兩種:
1使用混淆器對源碼進行混淆,降低反編譯工具的作用
2基于classloader的自定義加密、解密運行

1.1. 混淆器加密
1.2. 自定義classloader加密
1.2.1. 原理
原理:java虛擬機的動態加載機制,為classloader加密方案提供了理論基礎。在jvm裝載運行程序,初始的時候,只裝在了必要的類,如java.lang.String等,而應用程序的類并沒有一次性裝入內存。Jvm解釋執行應用程序的過程中,如果發現有未裝載的類,則會調用裝載正在執行的那個類的classloader來裝載,這個過程是一層一層向上,直到頂層的classloader。Jvm啟動的時候會裝入ExtClassloader,而ExtClassloader又會裝載AppClassloader,例如:

Java代碼 ?
  • Class?Hello{??
  • ??
  • ????Public?static?void?main(String[]?args){??
  • ????????System.out.println(“hello”);??
  • ????????HelloMethod.sayHello();??
  • }??
  • }??
  • Class?HelloMethod{??
  • ??
  • ????Public?static?void?sayHello(){??
  • ????????System.out.println(“hello?in?static?HelloMethod”);??
  • ??
  • }??
  • }??
  • Class Hello{Public static void main(String[] args){System.out.println(“hello”);HelloMethod.sayHello(); } } Class HelloMethod{Public static void sayHello(){System.out.println(“hello in static HelloMethod”);} }



    有上面兩個類的定義,在執行Hello類的main方法的時候,首先會委托裝載Hello類的classloader來裝載HelloMethod類,即jvm會委托AppClassloader來裝載,但是在AppClassloader的實現的時候,會首先委托裝載AppClassloader的classloader來裝載,如果上層的classloader無法裝載,才會由AppClassloader來裝載HelloMethod類。這種模式叫做雙親委托模式。在jvm的所有classloader中都是如此,首先由父classloader加載,失敗由自身加載。

    Java虛擬機的這種特性,使得我們可以自定義一個classloader,然后由這個classloader來裝載應用程序的啟動類,然后在啟動應用程序,那么當應用程序中有未裝載的類的時候,java徐機器逐層向上請求classloader裝載新類,那么首先被請求的就是裝在應用程序的classloader,即我們自定義的classloader,我們完全可以首先調用自己的加載方法來加載類,如果加載不成功,可以請求父classloader來加載,因為來請求加載的類是完全有可能是系統的類。







    在我們使用自定義的classloader的時候,裝載自己的程序,那么就可以對裝入的字節碼進行一定的操作,比如解密。在調用自定義的裝載器classloader的時候,首先是要裝入被加密之后的文件,通常情況下仍舊已.class為擴展名,在調用defineClass之前對裝入的數據解密。
    1.2.2. Classloader的兩個重要方法
    protected Class defineClass(String name, byte[] classData, int offset, int length);
    最原子的操作,在調用自定義的classloader加載新類的時候,首先根據自定義規則找到加載的類所存放的位置,然后將數據一byte[]類型讀入,進行解密運算時候,調用該方法,以生成一個Class。這是一個比較核心的方法,這個方法是被抽象的Classloader定義為protected訪問標記的,只有繼承了Classloader這個類才能使用。

    Class loadClass(String name, boolean resolve);
    Java虛擬機,在裝載新類,遞歸向上查找并調用的方法,在自定義classloader中需要重寫,就是判斷是否能夠自己裝載,如果能則自己裝載,否則交由系統裝載。
    2. 源程序加密解決方案

    2.1. 自定義classloader加密
    加密和解密要是對應的,即使用加密之后的數據,經過解密是需要能夠得到原來的數據。

    2.1.1. 加密應用程序
    為了簡單,在這里才用一種簡單的加密方法,把得到的需要加密的數據,以字節取,每一個字節加1,對應的解密就是每一個減1。
    還是以Hello、HelloMethod類為例子,

    Java代碼 ?
  • BufferedInputStream?bis?=?new?BufferedInputStream(new?FileInputSteam(“d:/workbench/ciphertool/bin/com/aatest/Hello.class”));??
  • byte[]?data?=?new?byte[bis.avialable()];??
  • bis.read(data);??
  • bis.close();??
  • for(int?I?=?0;?I?<?data.length;?i++){??
  • ????data[i]?=(byte)(?data[i]?+?1);??
  • }??
  • BufferedOutputStream?bos?=?new?BufferedOutputStream(new?FileOutputStream(“d:/workbench/ciphertool/bin/com/aatest/Hello.class”));??
  • bos.write(data);??
  • bos.close();??
  • BufferedInputStream bis = new BufferedInputStream(new FileInputSteam(“d:/workbench/ciphertool/bin/com/aatest/Hello.class”)); byte[] data = new byte[bis.avialable()]; bis.read(data); bis.close(); for(int I = 0; I < data.length; i++){data[i] =(byte)( data[i] + 1); } BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(“d:/workbench/ciphertool/bin/com/aatest/Hello.class”)); bos.write(data); bos.close();


    將加密對象取出,加密,然后存盤。
    2.1.2. 解密運行應用程序
    在自定義的classloader接收到加載新類請求的時候,首先讀入加密之后的文件,然后解密,最后調用defineClass(name, classData, offset, length)生成類,返回出去。


    攔截新類加載請求

    Java代碼 ?
  • package?com.cjnetwork.ciphertool.core;??
  • ??
  • import?java.io.BufferedInputStream;??
  • import?java.io.File;??
  • import?java.io.FileInputStream;??
  • import?java.lang.reflect.Method;??
  • import?java.util.ArrayList;??
  • import?java.util.HashMap;??
  • import?java.util.List;??
  • import?java.util.Map;??
  • import?java.util.jar.JarEntry;??
  • import?java.util.jar.JarFile;??
  • ??
  • import?com.cjnetwork.ciphertool.util.CipherUtil;??
  • ??
  • public?class?CjClassloader?extends?ClassLoader?{??
  • ??
  • ????String?classpath;??
  • ??????
  • ????Map<String,?Class>?loadedClassPool?=?new?HashMap<String,?Class>();??
  • ??
  • ????public?CjClassloader(String?classpath)?{??
  • ????????this.classpath?=?classpath;??
  • ????}??
  • ??
  • ??????
  • ????@SuppressWarnings("unchecked")??
  • ????@Override??
  • ????public?synchronized?Class<?>?loadClass(String?name,?boolean?resolve)?throws?ClassNotFoundException?{??
  • ????????Class?claz?=?null;??
  • ????????if?(loadedClassPool.containsKey(name))?{??
  • ????????????claz?=?this.loadedClassPool.get(name);??
  • ????????}?else?{??
  • ??
  • ????????????try?{??
  • ????????????????if?(claz?==?null)?{??
  • ????????????????????claz?=?super.loadClass(name,?false);??
  • ????????????????????if?(claz?!=?null)?{??
  • ????????????????????????System.out.println("系統加載成功:"?+?name);??
  • ????????????????????}??
  • ????????????????}??
  • ????????????}?catch?(ClassNotFoundException?e)?{??
  • ????????????????System.out.println("系統無法加載:"?+?name);??
  • ????????????}??
  • ??????????????
  • ????????????try?{??
  • ????????????????if?(claz?==?null)?{??
  • ????????????????????claz?=?loadByCjClassLoader(name);??
  • ????????????????????if?(claz?!=?null)?{??
  • ????????????????????????System.out.println("自定義加載成功:"?+?name);??
  • ????????????????????}??
  • ????????????????}??
  • ????????????}?catch?(Exception?e)?{??
  • ????????????????System.out.println("自定義無法加載:"?+?name);??
  • ????????????}??
  • ??
  • ????????????if?(claz?!=?null)?{??
  • ????????????????this.loadedClassPool.put(name,?claz);??
  • ????????????}??
  • ??
  • ????????}??
  • ????????if?(resolve)?{??
  • ????????????resolveClass(claz);??
  • ????????}??
  • ????????return?claz;??
  • ????}??
  • ??
  • ????/**?
  • ?????*??
  • ?????*?解密加載?
  • ?????*??
  • ?????*??
  • ?????*?@param?name?
  • ?????*?@return?
  • ?????*/??
  • ????@SuppressWarnings("unchecked")??
  • ????private?Class?loadByCjClassLoader(String?name)?{??
  • ????????Class?claz?=?null;??
  • ????????try?{??
  • ????????????byte[]?rawData?=?loadClassData(name);??
  • ????????????if?(rawData?!=?null)?{??
  • ????????????????byte[]?classData?=?decrypt(getReverseCypher(this.cjcipher.getKeycode()),?rawData);??
  • ????????????????classData?=?CipherUtil.filter(classData,?this.cjcipher);??
  • ??????????????????
  • ????????????????claz?=?defineClass(name,?classData,?0,?classData.length);??
  • ????????????}??
  • ????????}?catch?(Exception?e)?{??
  • ????????????claz?=?null;??
  • ????????}??
  • ????????return?claz;??
  • ????}??
  • ??
  • }??
  • package com.cjnetwork.ciphertool.core;import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.jar.JarEntry; import java.util.jar.JarFile;import com.cjnetwork.ciphertool.util.CipherUtil;public class CjClassloader extends ClassLoader {String classpath;Map<String, Class> loadedClassPool = new HashMap<String, Class>();public CjClassloader(String classpath) {this.classpath = classpath;}@SuppressWarnings("unchecked")@Overridepublic synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {Class claz = null;if (loadedClassPool.containsKey(name)) {claz = this.loadedClassPool.get(name);} else {try {if (claz == null) {claz = super.loadClass(name, false);if (claz != null) {System.out.println("系統加載成功:" + name);}}} catch (ClassNotFoundException e) {System.out.println("系統無法加載:" + name);}try {if (claz == null) {claz = loadByCjClassLoader(name);if (claz != null) {System.out.println("自定義加載成功:" + name);}}} catch (Exception e) {System.out.println("自定義無法加載:" + name);}if (claz != null) {this.loadedClassPool.put(name, claz);}}if (resolve) {resolveClass(claz);}return claz;}/*** * 解密加載* * * @param name* @return*/@SuppressWarnings("unchecked")private Class loadByCjClassLoader(String name) {Class claz = null;try {byte[] rawData = loadClassData(name);if (rawData != null) {byte[] classData = decrypt(getReverseCypher(this.cjcipher.getKeycode()), rawData);classData = CipherUtil.filter(classData, this.cjcipher);claz = defineClass(name, classData, 0, classData.length);}} catch (Exception e) {claz = null;}return claz;}}



    最主要的是集成Classloader,并重寫Class loadClass(String name, Boolean resolve)方法,在這個方法中,可以根據需要自己加載需要的文件,并解析生成Class。


    解密并返回Class

    Java代碼 ?
  • BufferedInputStream?bis?=?new?BufferedInputStream(new?FileInputSteam(“d:/workbench/ciphertool/bin/com/aatest/Hello.class”));??
  • byte[]?data?=?new?byte[bis.avialable()];??
  • bis.read(data);??
  • bis.close();??
  • for(int?I?=?0;?I?<?data.length;?i++){??
  • ????data[i]?=(byte)(?data[i]?-?1);??
  • }??
  • Class?claz?=?defineClass(“Hello”,?data,?0,?data.length);??
  • BufferedInputStream bis = new BufferedInputStream(new FileInputSteam(“d:/workbench/ciphertool/bin/com/aatest/Hello.class”)); byte[] data = new byte[bis.avialable()]; bis.read(data); bis.close(); for(int I = 0; I < data.length; i++){data[i] =(byte)( data[i] - 1); } Class claz = defineClass(“Hello”, data, 0, data.length);


    2.2. 加密自定義classloader
    采用以上的方法,就可以將應用程序加密,使得被加密的程序不能被反編譯,因為加密之后的class文件已經不是jvm定義的標準class文件,只能通過解密運行程序解密,才能運行。

    如果只做到這一步,對于java源程序加密還沒有完成。雖然應用程序無法直接反編譯,但是自定義的classloader是沒有被加密的,它自身是可以被反編譯的。理論上,如果得到真正的class文件(即jvm標準的class文件),是可以反編譯的java文件,在這里,假設得到class文件就得到了java文件。
    如果***者將自定義的classloader反編譯,得到源碼,則***者可以再自定義解密運行的同事,將得到的應用程序的字節碼存儲到本地,那么,***者就相當于是跳過了源程序加密解密。例如***者在代碼Class claz = defineClass(name, classData, offset, length);這句代碼前,將classData存儲到本地,即***者可以再解密運行應用程序的同時,將應用程序的字節碼保存,就達到了破解應用程序源代碼的效果。

    為了描述方便,實例化一個 自定義的classloader,叫做CjClassLoader
    這一個漏洞在于,CjClassLoader沒有加密,***者可以在其中嵌入導出應用程序代碼,那么,要解決這個問題,加密CjClassLoader就成了保護應用程序源代碼的關鍵。
    試想,如果加密、解密運行程序中,沒有CjClassLoader.class文件,或是CjClassLoader.class文件本身也是經過加密的,CjClassLoader類的獲得也是通過自己書寫的方法動態獲取,那么***者無法獲取到CjClassLoader.class文件,相當于無法獲取到CjClassLoader.java文件,那么也就無法再其中加入到處應用程序類文件的代碼,那么被加密的應用程序可以認為是安全的。
    假設將CjClassLoader.class加密后生成CjClassLoaderEncryptor0.class,那么CjClassLoader是安全了,但理論上***者還是可以通過反編譯CjClassLoaderEncryptor0來獲取CjClassLoader的源碼,那么保護CjClassLoaderEncryptor0又成了保護應用程序的關鍵,注意在CjClassLoaderEncryptor0中存在解密CjClassLoader的密鑰,即將密鑰硬編碼到CjClassLoaderEncryptor0中,這樣做是為了防止***者直接獲取密鑰,直接破解最里面一層的加密,至于什么是最里面一層,請繼續看后文。
    那么如何CjClassLoaderEncryptor0.class的安全性呢,我們同樣采取加密的方式,即將CjClassLoaderEncryptor0.class加密,生成CjClassLoaderEncryptor1.class,在解密運行的時候首先動態的生成CjClassLoaderEncryptor1.class,在由CjClassLoaderEncryptor1所定義的類動態的裝入CjClassLoaderEncryptor0.class,并且解密生成CjClassLoader,最后使用CjClassLoader裝入應用程序,運行。整體上的思路如下:

    Java代碼 ?
  • CjClassLoader.class?——》?CjClassLoaderEncryptor0.class??
  • CjClassLoaderEncryptor1.class???——》?CjClassLoaderEncryptor1.class??
  • CjClassLoaderEncryptor2.class???——》?CjClassLoaderEncryptor2.class??
  • CjClassLoaderEncryptor3.class???——》?CjClassLoaderEncryptor3.class??
  • 。。。。。。??
  • CjClassLoaderEncryptorN.class???——》?CjClassLoaderEncryptorN.class??
  • CjClassLoader.class ——》 CjClassLoaderEncryptor0.class CjClassLoaderEncryptor1.class ——》 CjClassLoaderEncryptor1.class CjClassLoaderEncryptor2.class ——》 CjClassLoaderEncryptor2.class CjClassLoaderEncryptor3.class ——》 CjClassLoaderEncryptor3.class 。。。。。。 CjClassLoaderEncryptorN.class ——》 CjClassLoaderEncryptorN.class


    這樣的一級一級加密,我們稱CjClassLoaderEncryptorN.class為最外層,成CjClassLoaderEncryptor0.class為最里層。除去最外層沒有加密,里面的每一層都是加密之后的數據,都是不能直接為jvm所識別的字節碼,都是需要通過后一級的解密程序解密之后才能為jvm所識別。

    系統裝在CjClassLoaderEncryptorN.class,生成CjClassLoaderEncryptorN類,使用反射機制,調用CjClassLoaderEncryptorN類中的方法,這個方法可以動態的裝入CjClassLoaderEncryptor(N-1).class,并利用CjClassLoaderEncryptorN中的密鑰,解密CjClassLoaderEncryptor(N – 1),然后生成CjClassLoaderEncryptor( N – 1)類,最后調用CjClassLoaderEncryptor(N – 1)中的方法。而CjClassLoaderEncryptor( N – 1)類中的方法,可以動態裝入CjClassLoaderEncryptor(N- 2).class文件,并利用CjClassLoaderEncryptor(N – 1)中的密鑰,解密CjClassLoaderEncryptor(N – 2),然后生成CjClassLoaderEncryptor(N – 2)類,最后調用方法,被調用的方法可以動態的裝入CjClassLoaderEncryptor(N – 3).class。。。。。。。。

    Java代碼 ?
  • CjClassLoaderEncryptorN??(密鑰N,動態裝入,解密,方法調用)??CjClassLoaderEncryptor(N–1)??
  • CjClassLoaderEncryptor(N-1)?(密鑰N-1,動態裝入,解密,方法調用)?CjClassLoaderEncryptor(N–2)??
  • CjClassLoaderEncryptor(N-2)?(密鑰N-2,動態裝入,解密,方法調用)?CjClassLoaderEncryptor(N-3)??
  • ......??
  • CjClassLoaderEncryptor1??(密鑰1,動態裝入,解密,方法調用)??CjClassLoaderEncryptor0??
  • CjClassLoaderEncryptor0??(密鑰0,動態裝入,解密,方法調用)??CjClassLoader??
  • CjClassLoaderEncryptorN (密鑰N,動態裝入,解密,方法調用) CjClassLoaderEncryptor(N–1) CjClassLoaderEncryptor(N-1) (密鑰N-1,動態裝入,解密,方法調用) CjClassLoaderEncryptor(N–2) CjClassLoaderEncryptor(N-2) (密鑰N-2,動態裝入,解密,方法調用) CjClassLoaderEncryptor(N-3) ...... CjClassLoaderEncryptor1 (密鑰1,動態裝入,解密,方法調用) CjClassLoaderEncryptor0 CjClassLoaderEncryptor0 (密鑰0,動態裝入,解密,方法調用) CjClassLoader


    最后使用CjClassLoader解密裝載應用程序。


    通過這樣一個過程的加密CjClassLoader,可以達到保護加密程序本身的目的,這種保護在理論上是可破,但在實際操作中將會變得困難,因為密鑰是通過硬編碼的方式存儲在下一層的封裝器中,即CjClassLoaderEncryptor(N-1).class的密鑰是放在CjClassLoaderEncryptorN.class中,如果存在CjClassLoaderEncryptor1000.class,那么加密過程將會變得非常復雜。

    當然動態生成CjClassLoaderEncryptorN.class的工作,雖然內置了應編碼(解密CjClassLoaderEncryptor(N-1)的密鑰),但是這樣一個過程,是不需要手動實現,利用程序自動生成即可。目前,這個版本的實現中是采用了動態生成CjClassLoaderEncryptorN.java文件,然后調用javac 命令,編譯生成class文件。

    請記住,這個過程是理論上不安全的,但如果需要加密的應用程序非常的重要,那么可以將加密、解密運行自身的CjClassLoader加密次數增加,以達到更加安全的目的。
    2.3. 隱藏自定義classloader
    通過上述加密CjClassLoader的方案,可以使得CjClassLoader變得相對安全,但似乎還是有一個問題,即解密運行程序本身的main方法中,會動態的裝入CjClassLoaderEncryptorN,然后通過層層調用,最終獲取到CjClassLoader類,然后使用CjClassLoader解密裝載應用程序,這段代碼是沒有加密的,***者可以不考慮CjClassLoaderEncryptorN開始的層層調用,只需要在最終獲取的CjClassLoader解密應用程序之前,將CjClassLoader本地化,即可以獲得未經加密的CjClassLoader,這樣,就不安全了。
    解決這個問題,可以將這段代碼中動態獲取CjClassLoader類,修改為動態獲取CjClassLoader中的Class loadClass(String name, Boolean resovle)方法,然后直接使用獲取到的方法,開始加載應用程序。


    如此,***者就沒有辦法直接獲取到解密之后的CjClassLoader,保護了加密、解密程序。

    2.4. 隱藏加密、解密方法
    在上述的實現中,CjClassLoader中加密、解密應用程序的方法是被放置于CipherUtil.class文件中,而這個文件是沒有被加密的,***者是可以直接獲取到應用程序加密和解密的方法的,這給應用程序帶來了不安全性,是的***者不利用解密程序的繁瑣解密過程,而自定調用CipherUtil.class中的方法,解密應用程序。

    解決這個問題,可以將CipherUtil.class中的加密和解密方法封裝到CjClassloader中,因為CjClassloader是沒有辦法直接得到,所以認為加密解密所用到的方法是安全的。最終在程序中調用的時候不是直接得到CjClassloader類,都是通過CjClassloaderEncrytorN的層層方法調用,而直接獲取到需要使用的方法。例如,我們可以在CjClassloaderEncrytorN類中封裝了一個Method getEncrytMethod(),如此的方法,這個方法會去調用CjClassloaderEncrytor(N-1)中的同名方法,如此一直調用,直到CjClassloaderEncrytor0.class中,在這個類中直接反射獲得CjClassloader中的加密方法,當然這個是比較特殊的,因為在CjClassloaderEncrytor0中時候反射獲取CjClassloader中方法的時候,這個反射是需要帶參數的,但這個帶參數獲取也是簡單的。


    3. bug

    異常堆棧過長
    經過這種一層一層的CjClassLoader解密運行的源程序,其堆棧是很長的,如果應用程序中,出現異常,答應異常或日志記錄將會變得很麻煩,會記錄很多無用的堆棧信息。


    備注:文中提到的應用程序,指需要被加密的程序。

    轉載于:https://blog.51cto.com/guoguoguo/705614

    總結

    以上是生活随笔為你收集整理的java源程序加密解决方案(基于Classloader解密)的全部內容,希望文章能夠幫你解決所遇到的問題。

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

    主站蜘蛛池模板: 无码成人一区二区 | 久久精品国产电影 | 另类激情| 亚洲精品在线中文字幕 | 亚洲乱亚洲乱 | 少妇av一区| 中文二区 | 秋霞成人午夜伦在线观看 | 曰曰操 | 亚洲19p| 欧美男人又粗又长又大 | 青青草视频在线观看 | 欧美黄色一区二区三区 | 欧美日韩免费 | 泰国午夜理伦三级 | 成人黄色片在线观看 | 午夜天堂 | 久久91| 一级视频免费观看 | 亚洲品质自拍视频网站 | 欧美日韩人妻精品一区在线 | v片在线看 | 1000部啪啪未满十八勿入超污 | 国产精品美女久久 | 穿扒开跪着折磨屁股视频 | 开心激情五月婷婷 | 久久网国产 | 午夜黄色小视频 | 好av在线 | 91国产免费视频 | 日批视频| 一级久久久久久久 | 亚洲欧洲日本在线 | 在线激情网 | 中文字幕亚洲色图 | 欧美日韩精品一区 | 国产 欧美 自拍 | 91精品国产自产精品男人的天堂 | 亚洲精品v天堂中文字幕 | 又紧又大又爽精品一区二区 | 国产91一区在线精品 | 亚洲女人av | 香蕉av一区二区三区 | 四虎精品在线观看 | 中文字幕av第一页 | 在线免费视频一区二区 | 中文字幕人乱码中文字 | 特级黄色大片 | 亚洲黄片一区 | 在线aa | 欧美 日韩 精品 | 欧美人与动牲交a欧美精品 欧美三级在线看 | 国产精品久久久久久白浆 | 免费在线观看成人 | 刘亦菲久久免费一区二区 | 日韩三区四区 | 76少妇精品导航 | 日本一区二区三区免费观看 | 久久久久久久久国产精品 | 国产aⅴ精品一区二区三区久久 | 综合久| 波多野结衣在线观看一区二区三区 | 国产av人人夜夜澡人人爽麻豆 | 日本在线视频播放 | 蜜臀av免费一区二区三区水牛 | 女女互磨互喷水高潮les呻吟 | 污的网站 | 久久影视 | 国产精品久久久久久久免费看 | 久久五月综合 | 亚洲第四页| 国产精品日日摸夜夜爽 | 99re这里只有精品在线观看 | 亚洲免费一二三区 | 成人午夜视频网站 | 国产精品欧美一区喷水 | 成年人激情视频 | 日本h视频在线观看 | 色偷偷888欧美精品久久久 | 天天干天天天天 | 免费看黄色一级大片 | 黄色av一区二区三区 | 四虎国产精品免费 | 国产无遮挡又黄又爽 | 欧美极品在线播放 | 五月天男人天堂 | 久久神马 | 亚洲成av人片在www色猫咪 | 精品一区二区三区视频 | 色老头一区二区三区 | 久久99国产精品 | 久久av综合网 | 亚洲av网址在线 | 99在线看| 国产三级91| 亚洲v天堂| 午夜日韩av| 欧美成人一区二区 | 日韩欧美精品一区二区三区 |