免费视频国产一区,欧美综合视频,成人免费视频网址http://www.aygfsteel.com/cooperlee321/知行合一zh-cnTue, 17 Jun 2025 15:38:18 GMTTue, 17 Jun 2025 15:38:18 GMT60Java Plugin Detectorhttp://www.aygfsteel.com/cooperlee321/archive/2010/09/21/332551.html梧桐夜雨梧桐夜雨Mon, 20 Sep 2010 16:16:00 GMThttp://www.aygfsteel.com/cooperlee321/archive/2010/09/21/332551.htmlhttp://www.aygfsteel.com/cooperlee321/comments/332551.htmlhttp://www.aygfsteel.com/cooperlee321/archive/2010/09/21/332551.html#Feedback0http://www.aygfsteel.com/cooperlee321/comments/commentRss/332551.htmlhttp://www.aygfsteel.com/cooperlee321/services/trackbacks/332551.html閱讀全文

梧桐夜雨 2010-09-21 00:16 發表評論
]]>
JWS在使用中遇到的一個bug跟蹤http://www.aygfsteel.com/cooperlee321/archive/2010/08/12/328721.html梧桐夜雨梧桐夜雨Thu, 12 Aug 2010 15:49:00 GMThttp://www.aygfsteel.com/cooperlee321/archive/2010/08/12/328721.htmlhttp://www.aygfsteel.com/cooperlee321/comments/328721.htmlhttp://www.aygfsteel.com/cooperlee321/archive/2010/08/12/328721.html#Feedback0http://www.aygfsteel.com/cooperlee321/comments/commentRss/328721.htmlhttp://www.aygfsteel.com/cooperlee321/services/trackbacks/328721.htmlOur primary use case also has the user switching between online and offline, so these bugs are a big problem.

I threw the full weight of my three bug votes behind bug 6931553 ;)

The fix for bug 6911785 does seem to prevent the endless "hang" on launch (with an active TCP/IP connection but no internet access), but there are still lots of problems:
- launching without internet access can take 20s - 2 minutes!
- launching offline results in the non-sensical "this application has requested to go online" dialog
- the JNLPClassLoader ends up doing DNS lookups which occasionally cause long delays during execution

It's really ugly. We have unhappy customers. I have no idea how to get these bugs fixed. Any suggestions?
http://forums.sun.com/thread.jspa?threadID=5426321&start=0&tstart=0

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6931553


梧桐夜雨 2010-08-12 23:49 發表評論
]]>
使用ant構建c++ 程序http://www.aygfsteel.com/cooperlee321/archive/2010/05/06/320240.html梧桐夜雨梧桐夜雨Thu, 06 May 2010 15:52:00 GMThttp://www.aygfsteel.com/cooperlee321/archive/2010/05/06/320240.htmlhttp://www.aygfsteel.com/cooperlee321/comments/320240.htmlhttp://www.aygfsteel.com/cooperlee321/archive/2010/05/06/320240.html#Feedback0http://www.aygfsteel.com/cooperlee321/comments/commentRss/320240.htmlhttp://www.aygfsteel.com/cooperlee321/services/trackbacks/320240.html閱讀全文

梧桐夜雨 2010-05-06 23:52 發表評論
]]>
ClassLoader 與 JAVA類加密技術http://www.aygfsteel.com/cooperlee321/archive/2010/04/01/317240.html梧桐夜雨梧桐夜雨Thu, 01 Apr 2010 14:52:00 GMThttp://www.aygfsteel.com/cooperlee321/archive/2010/04/01/317240.htmlhttp://www.aygfsteel.com/cooperlee321/comments/317240.htmlhttp://www.aygfsteel.com/cooperlee321/archive/2010/04/01/317240.html#Feedback0http://www.aygfsteel.com/cooperlee321/comments/commentRss/317240.htmlhttp://www.aygfsteel.com/cooperlee321/services/trackbacks/317240.html 1,   什么是 ClassLoader?
    Java 程序并不是一個可執行文件,是需要的時候,才把裝載到 JVM中。ClassLoader 做的工作就是 JVM 中將類裝入內存。 而且,Java ClassLoader 就是用 Java 語言編寫的。這意味著您可以創建自己的 ClassLoader
    ClassLoader 的基本目標是對類的請求提供服務。當 JVM 需要使用類時,它根據名稱向 ClassLoader 請求這個類,然后 ClassLoader 試圖返回一個表示這個類的 Class 對象。 通過覆蓋對應于這個過程不同階段的方法,可以創建定制的 ClassLoader。
2, 一些重要的方法
A)  方法 loadClass
        ClassLoader.loadClass() 是 ClassLoader 的入口點。該方法的定義如下:
        Class loadClass( String name, boolean resolve );
         name  JVM 需要的類的名稱,如 Foo 或 java.lang.Object。
         resolve 參數告訴方法是否需要解析類。在準備執行類之前,應考慮類解析。并不總是需要解析。如果 JVM 只需要知道該類是否存在或找出該類的超類,那么就不需要解析。
    
    cool.gif  方法 defineClass
       defineClass 方法是 ClassLoader 的主要訣竅。該方法接受由原始字節組成的數組并把它轉換成 Class 對象。原始數組包含如從文件系統或網絡裝入的數據。defineClass 管理 JVM 的許多復雜、神秘和倚賴于實現的方面 -- 它把字節碼分析成運行時數據結構、校驗有效性等等。不必擔心,您無需親自編寫它。事實上,即使您想要這么做也不能覆蓋它,因為它已被標記成final的。

    C)  方法 findSystemClass
       findSystemClass 方法從本地文件系統裝入文件。它在本地文件系統中尋找類文件,如果存在,就使用 defineClass 將原始字節轉換成 Class 對象,以將該文件轉換成類。當運行 Java 應用程序時,這是 JVM 正常裝入類的缺省機制。(Java 2 中 ClassLoader 的變動提供了關于 Java 版本 1.2 這個過程變動的詳細信息。) 對于定制的 ClassLoader,只有在嘗試其它方法裝入類之后,再使用 findSystemClass。原因很簡單:ClassLoader 是負責執行裝入類的特殊步驟,不是負責所有類。例如,即使 ClassLoader 從遠程的 Web 站點裝入了某些類,仍然需要在本地機器上裝入大量的基本 Java 庫。而這些類不是我們所關心的,所以要 JVM 以缺省方式裝入它們:從本地文件系統。這就是 findSystemClass 的用途。

     D) 方法 resolveClass
   正如前面所提到的,可以不完全地(不帶解析)裝入類,也可以完全地(帶解析)裝入類。當編寫我們自己的 loadClass 時,可以調用 resolveClass,這取決于 loadClass 的 resolve 參數的值。


   E) 方法 findLoadedClass
      findLoadedClass 充當一個緩存:當請求 loadClass 裝入類時,它調用該方法來查看 ClassLoader 是否已裝入這個類,這樣可以避免重新裝入已存在類所造成的麻煩。應首先調用該方法。

3, 怎么組裝這些方法
  1) 調用 findLoadedClass 來查看是否存在已裝入的類。
  2) 如果沒有,那么采用那種特殊的神奇方式來獲取原始字節。
  3) 如果已有原始字節,調用 defineClass 將它們轉換成 Class 對象。
  4) 如果沒有原始字節,然后調用 findSystemClass 查看是否從本地文件系統獲取類。
  5) 如果 resolve 參數是 true,那么調用 resolveClass 解析 Class 對象。
  6) 如果還沒有類,返回 ClassNotFoundException。

4,Java 2 中 ClassLoader 的變動
1)loadClass 的缺省實現
   定制編寫的 loadClass 方法一般嘗試幾種方式來裝入所請求的類,如果您編寫許多類,會發現一次次地在相同的、很復雜的方法上編寫變量。 在 Java 1.2 中 loadClass 的實現嵌入了大多數查找類的一般方法,并使您通過覆蓋 findClass 方法來定制它,在適當的時候 findClass 會調用 loadClass。 這種方式的好處是您可能不一定要覆蓋 loadClass;只要覆蓋 findClass 就行了,這減少了工作量。

2)新方法:findClass
     loadClass 的缺省實現調用這個新方法。findClass 的用途包含您的 ClassLoader 的所有特殊代碼,而無需要復制其它代碼(例如,當專門的方法失敗時,調用系統 ClassLoader)。

3) 新方法:getSystemClassLoader
     如果覆蓋 findClass 或 loadClass,getSystemClassLoader 使您能以實際 ClassLoader 對象來訪問系統 ClassLoader(而不是固定的從 findSystemClass 調用它)。
 
4) 新方法:getParent 
    為了將類請求委托給父代 ClassLoader,這個新方法允許 ClassLoader 獲取它的父代 ClassLoader。當使用特殊方法,定制的 ClassLoader 不能找到類時,可以使用這種方法。
父代 ClassLoader 被定義成創建該 ClassLoader 所包含代碼的對象的 ClassLoader。
運用加密技術保護Java源代碼
QUOTE
Java程序的源代碼很容易被別人偷看。只要有一個反編譯器,任何人都可以分析別人的代碼。本文討論如何在不修改原有程序的情況下,通過加密技術保護源代碼。
一、為什么要加密?
對 于傳統的C或C++之類的語言來說,要在Web上保護源代碼是很容易的,只要不發布它就可以。遺憾的是,Java程序的源代碼很容易被別人偷看。只要有一 個反編譯器,任何人都可以分析別人的代碼。Java的靈活性使得源代碼很容易被竊取,但與此同時,它也使通過加密保護代碼變得相對容易,我們唯一需要了解 的就是Java的ClassLoader對象。當然,在加密過程中,有關Java Cryptography Extension(JCE)的知識也是必不可少的。

有幾種技術可以“模糊”Java類文件,使得反編譯器處理類文件的效果大打折扣。然而,修改反編譯器使之能夠處理這些經過模糊處理的類文件并不是什么難事,所以不能簡單地依賴模糊技術來保證源代碼的安全。

我們可以用流行的加密工具加密應用,比如PGP(Pretty Good Privacy)或GPG(GNU Privacy Guard)。這時,最終用戶在運行應用之前必須先進行解密。但解密之后,最終用戶就有了一份不加密的類文件,這和事先不進行加密沒有什么差別。

Java 運行時裝入字節碼的機制隱含地意味著可以對字節碼進行修改。JVM每次裝入類文件時都需要一個稱為ClassLoader的對象,這個對象負責把新的類裝 入正在運行的JVM。JVM給ClassLoader一個包含了待裝入類(比如java.lang.Object)名字的字符串,然后由 ClassLoader負責找到類文件,裝入原始數據,并把它轉換成一個Class對象。

我們可以通過定制ClassLoader,在類文件執行之前修改它。這種技術的應用非常廣泛——在這里,它的用途是在類文件裝入之時進行解密,因此可以看成是一種即時解密器。由于解密后的字節碼文件永遠不會保存到文件系統,所以竊密者很難得到解密后的代碼。

由于把原始字節碼轉換成Class對象的過程完全由系統負責,所以創建定制ClassLoader對象其實并不困難,只需先獲得原始數據,接著就可以進行包含解密在內的任何轉換。

Java 2在一定程度上簡化了定制ClassLoader的構建。在Java 2中,loadClass的缺省實現仍舊負責處理所有必需的步驟,但為了顧及各種定制的類裝入過程,它還調用一個新的findClass方法。

這為我們編寫定制的ClassLoader提供了一條捷徑,減少了麻煩:只需覆蓋findClass,而不是覆蓋loadClass。這種方法避免了重復所有裝入器必需執行的公共步驟,因為這一切由loadClass負責。

不 過,本文的定制ClassLoader并不使用這種方法。原因很簡單。如果由默認的ClassLoader先尋找經過加密的類文件,它可以找到;但由于類 文件已經加密,所以它不會認可這個類文件,裝入過程將失敗。因此,我們必須自己實現loadClass,稍微增加了一些工作量。

二、定制類裝入器
每一個運行著的JVM已經擁有一個ClassLoader。這個默認的ClassLoader根據CLASSPATH環境變量的值,在本地文件系統中尋找合適的字節碼文件。

應 用定制ClassLoader要求對這個過程有較為深入的認識。我們首先必須創建一個定制ClassLoader類的實例,然后顯式地要求它裝入另外一個 類。這就強制JVM把該類以及所有它所需要的類關聯到定制的ClassLoader。Listing 1顯示了如何用定制ClassLoader裝入類文件。

【Listing 1:利用定制的ClassLoader裝入類文件】

  // 首先創建一個ClassLoader對象
  ClassLoader myClassLoader = new myClassLoader();

  // 利用定制ClassLoader對象裝入類文件
  // 并把它轉換成Class對象
  Class myClass = myClassLoader.loadClass( "mypackage.MyClass" );

  // 最后,創建該類的一個實例
  Object newInstance = myClass.newInstance();

  // 注意,MyClass所需要的所有其他類,都將通過
  // 定制的ClassLoader自動裝入






如前所述,定制ClassLoader只需先獲取類文件的數據,然后把字節碼傳遞給運行時系統,由后者完成余下的任務。

ClassLoader 有幾個重要的方法。創建定制的ClassLoader時,我們只需覆蓋其中的一個,即loadClass,提供獲取原始類文件數據的代碼。這個方法有兩個 參數:類的名字,以及一個表示JVM是否要求解析類名字的標記(即是否同時裝入有依賴關系的類)。如果這個標記是true,我們只需在返回JVM之前調用 resolveClass。

【Listing 2:ClassLoader.loadClass()的一個簡單實現】

      public Class loadClass( String name, boolean resolve )
      throws ClassNotFoundException {
    try {
      // 我們要創建的Class對象
       Class clasz = null;

      // 必需的步驟1:如果類已經在系統緩沖之中,
      // 我們不必再次裝入它
      clasz = findLoadedClass( name );

      if (clasz != null)
        return clasz;

      // 下面是定制部分
      byte classData[] = /* 通過某種方法獲取字節碼數據 */;
      if (classData != null) {
        // 成功讀取字節碼數據,現在把它轉換成一個Class對象
        clasz = defineClass( name, classData, 0, classData.length );
      }

      // 必需的步驟2:如果上面沒有成功,
      // 我們嘗試用默認的ClassLoader裝入它
      if (clasz == null)
        clasz = findSystemClass( name );

      // 必需的步驟3:如有必要,則裝入相關的類
      if (resolve && clasz != null)
        resolveClass( clasz );

      // 把類返回給調用者
      return clasz;

    } catch( IOException ie ) {
      throw new ClassNotFoundException( ie.toString() );
    } catch( GeneralSecurityException gse ) {
      throw new ClassNotFoundException( gse.toString() );
    }
  }






Listing 2顯示了一個簡單的loadClass實現。代碼中的大部分對所有ClassLoader對象來說都一樣,但有一小部分(已通過注釋標記)是特有的。在處理過程中,ClassLoader對象要用到其他幾個輔助方法:

findLoadedClass:用來進行檢查,以便確認被請求的類當前還不存在。loadClass方法應該首先調用它。
defineClass:獲得原始類文件字節碼數據之后,調用defineClass把它轉換成一個Class對象。任何loadClass實現都必須調用這個方法。
findSystemClass:提供默認ClassLoader的支持。如果用來尋找類的定制方法不能找到指定的類(或者有意地不用定制方法),則可以調用該方法嘗試默認的裝入方式。這是很有用的,特別是從普通的JAR文件裝入標準Java類時。
resolveClass:當JVM想要裝入的不僅包括指定的類,而且還包括該類引用的所有其他類時,它會把loadClass的resolve參數設置成true。這時,我們必須在返回剛剛裝入的Class對象給調用者之前調用resolveClass。



三、加密、解密
Java加密擴展即Java Cryptography Extension,簡稱JCE。它是Sun的加密服務軟件,包含了加密和密匙生成功能。JCE是JCA(Java Cryptography Architecture)的一種擴展。

JCE 沒有規定具體的加密算法,但提供了一個框架,加密算法的具體實現可以作為服務提供者加入。除了JCE框架之外,JCE軟件包還包含了SunJCE服務提供 者,其中包括許多有用的加密算法,比如DES(Data Encryption Standard)和Blowfish。

為簡單計,在本文中我們將用DES算法加密和解密字節碼。下面是用JCE加密和解密數據必須遵循的基本步驟:

步驟1:生成一個安全密匙。在加密或解密任何數據之前需要有一個密匙。密匙是隨同被加密的應用一起發布的一小段數據,Listing 3顯示了如何生成一個密匙。 【Listing 3:生成一個密匙】

  // DES算法要求有一個可信任的隨機數源
  SecureRandom sr = new SecureRandom();

  // 為我們選擇的DES算法生成一個KeyGenerator對象
  KeyGenerator kg = KeyGenerator.getInstance( "DES" );
  kg.init( sr );

  // 生成密匙
  SecretKey key = kg.generateKey();

  // 獲取密匙數據
  byte rawKeyData[] = key.getEncoded();

  /* 接下來就可以用密匙進行加密或解密,或者把它保存
     為文件供以后使用 */
  doSomething( rawKeyData );




步驟2:加密數據。得到密匙之后,接下來就可以用它加密數據。除了解密的ClassLoader之外,一般還要有一個加密待發布應用的獨立程序(見Listing 4)。 【Listing 4:用密匙加密原始數據】

    // DES算法要求有一個可信任的隨機數源
    SecureRandom sr = new SecureRandom();

    byte rawKeyData[] = /* 用某種方法獲得密匙數據 */;

    // 從原始密匙數據創建DESKeySpec對象
    DESKeySpec dks = new DESKeySpec( rawKeyData );

    // 創建一個密匙工廠,然后用它把DESKeySpec轉換成
    // 一個SecretKey對象
    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance( "DES" );
    SecretKey key = keyFactory.generateSecret( dks );

    // Cipher對象實際完成加密操作
    Cipher cipher = Cipher.getInstance( "DES" );

    // 用密匙初始化Cipher對象
    cipher.init( Cipher.ENCRYPT_MODE, key, sr );

    // 現在,獲取數據并加密
    byte data[] = /* 用某種方法獲取數據 */

    // 正式執行加密操作
    byte encryptedData[] = cipher.doFinal( data );

    // 進一步處理加密后的數據
    doSomething( encryptedData );



步驟3:解密數據。運行經過加密的應用時,ClassLoader分析并解密類文件。操作步驟如Listing 5所示。 【Listing 5:用密匙解密數據】

    // DES算法要求有一個可信任的隨機數源
    SecureRandom sr = new SecureRandom();

    byte rawKeyData[] = /* 用某種方法獲取原始密匙數據 */;

    // 從原始密匙數據創建一個DESKeySpec對象
    DESKeySpec dks = new DESKeySpec( rawKeyData );

    // 創建一個密匙工廠,然后用它把DESKeySpec對象轉換成
    // 一個SecretKey對象
    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance( "DES" );
    SecretKey key = keyFactory.generateSecret( dks );

    // Cipher對象實際完成解密操作
    Cipher cipher = Cipher.getInstance( "DES" );

    // 用密匙初始化Cipher對象
    cipher.init( Cipher.DECRYPT_MODE, key, sr );

    // 現在,獲取數據并解密
    byte encryptedData[] = /* 獲得經過加密的數據 */

    // 正式執行解密操作
    byte decryptedData[] = cipher.doFinal( encryptedData );

    // 進一步處理解密后的數據
    doSomething( decryptedData );



四、應用實例
前面介紹了如何加密和解密數據。要部署一個經過加密的應用,步驟如下:

步驟1:創建應用。我們的例子包含一個App主類,兩個輔助類(分別稱為Foo和Bar)。這個應用沒有什么實際功用,但只要我們能夠加密這個應用,加密其他應用也就不在話下。
步驟2:生成一個安全密匙。在命令行,利用GenerateKey工具(參見GenerateKey.java)把密匙寫入一個文件: % java GenerateKey key.data



步驟3:加密應用。在命令行,利用EncryptClasses工具(參見EncryptClasses.java)加密應用的類: % java EncryptClasses key.data App.class Foo.class Bar.class


該命令把每一個.class文件替換成它們各自的加密版本。
步驟4:運行經過加密的應用。用戶通過一個DecryptStart程序運行經過加密的應用。DecryptStart程序如Listing 6所示。 【Listing 6:DecryptStart.java,啟動被加密應用的程序】

import java.io.*;
import java.security.*;
import java.lang.reflect.*;
import javax.crypto.*;
import javax.crypto.spec.*;

public class DecryptStart extends ClassLoader
{
  // 這些對象在構造函數中設置,
  // 以后loadClass()方法將利用它們解密類
  private SecretKey key;
  private Cipher cipher;

  // 構造函數:設置解密所需要的對象
  public DecryptStart( SecretKey key ) throws GeneralSecurityException,
      IOException {
    this.key = key;

    String algorithm = "DES";
    SecureRandom sr = new SecureRandom();
    System.err.println( "[DecryptStart: creating cipher]" );
    cipher = Cipher.getInstance( algorithm );
    cipher.init( Cipher.DECRYPT_MODE, key, sr );
  }

  // main過程:我們要在這里讀入密匙,創建DecryptStart的
  // 實例,它就是我們的定制ClassLoader。
  // 設置好ClassLoader以后,我們用它裝入應用實例,
  // 最后,我們通過Java Reflection API調用應用實例的main方法
  static public void main( String args[] ) throws Exception {
    String keyFilename = args[0];
    String appName = args[1];

     // 這些是傳遞給應用本身的參數
    String realArgs[] = new String[args.length-2];
    System.arraycopy( args, 2, realArgs, 0, args.length-2 );

    // 讀取密匙
    System.err.println( "[DecryptStart: reading key]" );
    byte rawKey[] = Util.readFile( keyFilename );
    DESKeySpec dks = new DESKeySpec( rawKey );
    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance( "DES" );
    SecretKey key = keyFactory.generateSecret( dks );

    // 創建解密的ClassLoader
    DecryptStart dr = new DecryptStart( key );

    // 創建應用主類的一個實例
    // 通過ClassLoader裝入它
    System.err.println( "[DecryptStart: loading "+appName+"]" );
    Class clasz = dr.loadClass( appName );

    // 最后,通過Reflection API調用應用實例
    // 的main()方法

    // 獲取一個對main()的引用
    String proto[] = new String[1];
    Class mainArgs[] = { (new String[1]).getClass() };
    Method main = clasz.getMethod( "main", mainArgs );

    // 創建一個包含main()方法參數的數組
    Object argsArray[] = { realArgs };
    System.err.println( "[DecryptStart: running "+appName+".main()]" );

    // 調用main()
    main.invoke( null, argsArray );
  }

  public Class loadClass( String name, boolean resolve )
      throws ClassNotFoundException {
    try {
      // 我們要創建的Class對象
      Class clasz = null;

      // 必需的步驟1:如果類已經在系統緩沖之中
      // 我們不必再次裝入它
      clasz = findLoadedClass( name );

      if (clasz != null)
        return clasz;

      // 下面是定制部分
      try {
        // 讀取經過加密的類文件
        byte classData[] = Util.readFile( name+".class" );

        if (classData != null) {
          // 解密...
          byte decryptedClassData[] = cipher.doFinal( classData );

          // ... 再把它轉換成一個類
          clasz = defineClass( name, decryptedClassData,
            0, decryptedClassData.length );
          System.err.println( "[DecryptStart: decrypting class "+name+"]" );
        }
      } catch( FileNotFoundException fnfe ) {
      }

      // 必需的步驟2:如果上面沒有成功
      // 我們嘗試用默認的ClassLoader裝入它
      if (clasz == null)
        clasz = findSystemClass( name );

      // 必需的步驟3:如有必要,則裝入相關的類
      if (resolve && clasz != null)
        resolveClass( clasz );

      // 把類返回給調用者
      return clasz;
    } catch( IOException ie ) {
      throw new ClassNotFoundException( ie.toString()
);
    } catch( GeneralSecurityException gse ) {
      throw new ClassNotFoundException( gse.toString()
);
    }
  }
}


對于未經加密的應用,正常執行方式如下: % java App arg0 arg1 arg2


對于經過加密的應用,則相應的運行方式為: % java DecryptStart key.data App arg0 arg1 arg2



DecryptStart 有兩個目的。一個DecryptStart的實例就是一個實施即時解密操作的定制ClassLoader;同時,DecryptStart還包含一個 main過程,它創建解密器實例并用它裝入和運行應用。示例應用App的代碼包含在App.java、Foo.java和Bar.java內。 Util.java是一個文件I/O工具,本文示例多處用到了它。完整的代碼請從本文最后下載。

五、注意事項
我們看到,要在不修改源代碼的情況下加密一個Java應用是很容易的。不過,世上沒有完全安全的系統。本文的加密方式提供了一定程度的源代碼保護,但對某些攻擊來說它是脆弱的。

雖 然應用本身經過了加密,但啟動程序DecryptStart沒有加密。攻擊者可以反編譯啟動程序并修改它,把解密后的類文件保存到磁盤。降低這種風險的辦 法之一是對啟動程序進行高質量的模糊處理。或者,啟動程序也可以采用直接編譯成機器語言的代碼,使得啟動程序具有傳統執行文件格式的安全性。

另外還要記住的是,大多數JVM本身并不安全。狡猾的黑客可能會修改JVM,從ClassLoader之外獲取解密后的代碼并保存到磁盤,從而繞過本文的加密技術。Java沒有為此提供真正有效的補救措施。

不過應該指出的是,所有這些可能的攻擊都有一個前提,這就是攻擊者可以得到密匙。如果沒有密匙,應用的安全性就完全取決于加密算法的安全性。雖然這種保護代碼的方法稱不上十全十美,但它仍不失為一種保護知識產權和敏感用戶數據的有效方案。

參考資源

在運行時刻更新功能模塊。介紹了一個利用類庫加載器ClassLoader 實現在運行時刻更新部分功能模塊的Java程序,并將其與C/C++中實現同樣功能的動態鏈接庫方案進行了比較。
Java 技巧 105:利用 JWhich 掌握類路徑。展示一個簡單的工具,它可以清楚地確定類裝載器從類路徑中載入了什么 Java 類。
要了解更多的 Java 安全信息,請閱讀 java.sun.com的 Java Security API 頁。
如何封鎖您的(或打開別人的) Java 代碼。Java 代碼反編譯和模糊處理的指南。
使您的軟件運行起來:擺弄數字。真正安全的軟件需要精確的隨機數生成器。
下載本文代碼:EncryptedJavaClass_code.zip


關于作者
俞良松,軟件工程師,獨立顧問和自由撰稿人。最初從事PB和Oracle開發,現主要興趣在于Internet開發。您可以通過 javaman@163.net 和我聯系。


梧桐夜雨 2010-04-01 22:52 發表評論
]]>
Java的多進程運行模式分析(轉)http://www.aygfsteel.com/cooperlee321/archive/2010/04/01/317236.html梧桐夜雨梧桐夜雨Thu, 01 Apr 2010 14:29:00 GMThttp://www.aygfsteel.com/cooperlee321/archive/2010/04/01/317236.htmlhttp://www.aygfsteel.com/cooperlee321/comments/317236.htmlhttp://www.aygfsteel.com/cooperlee321/archive/2010/04/01/317236.html#Feedback0http://www.aygfsteel.com/cooperlee321/comments/commentRss/317236.htmlhttp://www.aygfsteel.com/cooperlee321/services/trackbacks/317236.html閱讀全文

梧桐夜雨 2010-04-01 22:29 發表評論
]]>
JUnit 4 http://www.aygfsteel.com/cooperlee321/archive/2010/01/03/308111.html梧桐夜雨梧桐夜雨Sun, 03 Jan 2010 14:25:00 GMThttp://www.aygfsteel.com/cooperlee321/archive/2010/01/03/308111.htmlhttp://www.aygfsteel.com/cooperlee321/comments/308111.htmlhttp://www.aygfsteel.com/cooperlee321/archive/2010/01/03/308111.html#Feedback0http://www.aygfsteel.com/cooperlee321/comments/commentRss/308111.htmlhttp://www.aygfsteel.com/cooperlee321/services/trackbacks/308111.html閱讀全文

梧桐夜雨 2010-01-03 22:25 發表評論
]]>
Java代理模式及動態代理類http://www.aygfsteel.com/cooperlee321/archive/2010/01/03/308109.html梧桐夜雨梧桐夜雨Sun, 03 Jan 2010 14:16:00 GMThttp://www.aygfsteel.com/cooperlee321/archive/2010/01/03/308109.htmlhttp://www.aygfsteel.com/cooperlee321/comments/308109.htmlhttp://www.aygfsteel.com/cooperlee321/archive/2010/01/03/308109.html#Feedback0http://www.aygfsteel.com/cooperlee321/comments/commentRss/308109.htmlhttp://www.aygfsteel.com/cooperlee321/services/trackbacks/308109.html

1.      代理模式

代理模式的作用是:為其他對象提供一種代理以控制對這個對象的訪問。在某些情況下,一個客戶不想或者不能直接引用另一個對象,而代理對象可以在客戶端和目標對象之間起到中介的作用。

代理模式一般涉及到的角色有:

抽象角色:聲明真實對象和代理對象的共同接口;

代理角色:代理對象角色內部含有對真實對象的引用,從而可以操作真實對象,同時代理對象提供與真實對象相同的接口以便在任何時刻都能代替真實對象。同時,代理對象可以在執行真實對象操作時,附加其他的操作,相當于對真實對象進行封裝。

真實角色:代理角色所代表的真實對象,是我們最終要引用的對象。(參見文獻1)

以下以《Java與模式》中的示例為例:

抽象角色:

abstract public class Subject

{

    abstract public void request();

}

真實角色:實現了Subjectrequest()方法。

public class RealSubject extends Subject

{

       public RealSubject()

       {

       }

      

       public void request()

       {

              System.out.println("From real subject.");

       }

}

代理角色:

public class ProxySubject extends Subject

{

    private RealSubject realSubject;  //以真實角色作為代理角色的屬性

      

       public ProxySubject()

       {

       }

 

       public void request()  //該方法封裝了真實對象的request方法

       {

        preRequest(); 

              if( realSubject == null )

        {

                     realSubject = new RealSubject();

              }

        realSubject.request();  //此處執行真實對象的request方法

        postRequest();

       }

 

    private void preRequest()

    {

        //something you want to do before requesting

    }

 

    private void postRequest()

    {

        //something you want to do after requesting

    }

}

客戶端調用:

Subject sub=new ProxySubject();

Sub.request();

       由以上代碼可以看出,客戶實際需要調用的是RealSubject類的request()方法,現在用ProxySubject來代理RealSubject類,同樣達到目的,同時還封裝了其他方法(preRequest(),postRequest()),可以處理一些其他問題。

       另外,如果要按照上述的方法使用代理模式,那么真實角色必須是事先已經存在的,并將其作為代理對象的內部屬性。但是實際使用時,一個真實角色必須對應一個代理角色,如果大量使用會導致類的急劇膨脹;此外,如果事先并不知道真實角色,該如何使用代理呢?這個問題可以通過Java的動態代理類來解決。

 

2.動態代理類

       Java動態代理類位于Java.lang.reflect包下,一般主要涉及到以下兩個類:

(1). Interface InvocationHandler:該接口中僅定義了一個方法Objectinvoke(Object obj,Method method, Object[] args)。在實際使用時,第一個參數obj一般是指代理類,method是被代理的方法,如上例中的request()args為該方法的參數數組。這個抽象方法在代理類中動態實現。


(2).Proxy
:該類即為動態代理類,作用類似于上例中的ProxySubject,其中主要包含以下內容:

Protected Proxy(InvocationHandler h):構造函數,估計用于給內部的h賦值。

Static Class getProxyClass (ClassLoader loader, Class[] interfaces):獲得一個代理類,其中loader是類裝載器,interfaces是真實類所擁有的全部接口的數組。

Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理類的一個實例,返回后的代理類可以當作被代理類使用(可使用被代理類的在Subject接口中聲明過的方法)


      
所謂Dynamic Proxy是這樣一種class:它是在運行時生成的class,在生成它時你必須提供一組interface給它,然后該class就宣稱它實現了這些 interface。你當然可以把該class的實例當作這些interface中的任何一個來用。當然啦,這個Dynamic Proxy其實就是一個Proxy,它不會替你作實質性的工作,在生成它的實例時你必須提供一個handler,由它接管實際的工作。(參見文獻3)

    在使用動態代理類時,我們必須實現InvocationHandler接口,以第一節中的示例為例:

抽象角色(之前是抽象類,此處應改為接口)

public interface Subject

{

    abstract public void request();

}

具體角色RealSubject:同上;

 

代理角色:

import java.lang.reflect.Method;

import java.lang.reflect.InvocationHandler;

 

public class DynamicSubject implements InvocationHandler {

  private Object sub;

 

  public DynamicSubject() {

  }

 

  public DynamicSubject(Object obj) {

    sub = obj;

  }

 

 

  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

    System.out.println("before calling " + method);

 

    method.invoke(sub,args);

 

    System.out.println("after calling " + method);

    return null;

  }

 

}

 

       該代理類的內部屬性為Object類,實際使用時通過該類的構造函數DynamicSubject(Object obj)對其賦值;此外,在該類還實現了invoke方法,該方法中的

method.invoke(sub,args);

其實就是調用被代理對象的將要被執行的方法,方法參數sub是實際的被代理對象,args為執行被代理對象相應操作所需的參數。通過動態代理類,我們可以在調用之前或之后執行一些相關操作。

客戶端

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Proxy;

import java.lang.reflect.Constructor;

import java.lang.reflect.Method;

 

public class Client

{

 

    static public void main(String[] args) throws Throwable

       {

      RealSubject rs = new RealSubject();  //在這里指定被代理類

      InvocationHandler ds = new DynamicSubject(rs);  //初始化代理類

         Class cls = rs.getClass();

      //以下是分解步驟

      /*

      Class c = Proxy.getProxyClass(cls.getClassLoader(),cls.getInterfaces()) ;

      Constructor ct=c.getConstructor(new Class[]{InvocationHandler.class});

      Subject subject =(Subject) ct.newInstance(new Object[]{ds});

     */

     //以下是一次性生成

      Subject subject = (Subject) Proxy.newProxyInstance(cls.getClassLoader(),

                                 cls.getInterfaces(),ds );


      subject.request();

}

       通過這種方式,被代理的對象(RealSubject)可以在運行時動態改變,需要控制的接口(Subject接口)可以在運行時改變,控制的方式(DynamicSubject)也可以動態改變,從而實現了非常靈活的動態代理關系(參見文獻2)

 

 

參考文獻:

1.      閻宏,《Java 與模式》

2.          透明,《動態代理的前世今生》

3.   Forest Hou,《Dynamic Proxy Java RMI 中的應用》



梧桐夜雨 2010-01-03 22:16 發表評論
]]>
Java泛型http://www.aygfsteel.com/cooperlee321/archive/2010/01/03/308108.html梧桐夜雨梧桐夜雨Sun, 03 Jan 2010 14:10:00 GMThttp://www.aygfsteel.com/cooperlee321/archive/2010/01/03/308108.htmlhttp://www.aygfsteel.com/cooperlee321/comments/308108.htmlhttp://www.aygfsteel.com/cooperlee321/archive/2010/01/03/308108.html#Feedback0http://www.aygfsteel.com/cooperlee321/comments/commentRss/308108.htmlhttp://www.aygfsteel.com/cooperlee321/services/trackbacks/308108.html

Java SE1.5中, 增加了一個新的特性:泛型(日本語中的總稱型)。何謂泛型呢?通俗的說,就是泛泛的指定對象所操作的類型,而不像常規方式一樣使用某種固定的類型去指定。 泛型的本質就是將所操作的數據類型參數化,也就是說,該數據類型被指定為一個參數。這種參數類型可以使用在類、接口以及方法定義中。

 

一、為什么使用泛型呢?

     在以往的J2SE中,沒有泛型的情況下,通常是使用Object類型來進行多種類型數據的操作。這個時候操作最多的就是針對該Object進行數據的強制轉換,而這種轉換是基于開發者對該數據類型明確的情況下進行的(比如將Object型轉換為String型)。倘若類型不一致,編譯器在編譯過程中不會報錯,但在運行時會出錯。

    使用泛型的好處在于,它在編譯的時候進行類型安全檢查,并且在運行時所有的轉換都是強制的,隱式的,大大提高了代碼的重用率。

 

二、  泛型的簡單例子:

首先,我們來看看下面兩個普通的class定義

public class getString {

private String myStr;

 

public String getStr() {

    return myStr;

}

 

public void setStr(str) {

    myStr = str;

}

}

 

public class getDouble {

private Double myDou;

 

public Double getDou() {

    return myDou;

}

 

public void setDou(dou) {

    myDou = dou;

}

          }

 

    這兩個class除了所操作的數據類型不一致,其他機能都是相同的。現在,我們可以使用泛型來將上面兩個class合并為一個,從而提高代碼利用率,減少代碼量。

        public class getObj<T> {

            private T myObj ;

           

            public T getObj() {

                return myObj;

            }

 

            public void setObj<T obj> {

                 myObj = obj;

              }

        }

 

    那么,使用了泛型后,如何生成這個class的實例來進行操作呢?請看下面的代碼:

        getObj<String> strObj = new getObj<String>();

        strObj.setObj(Hello Nissay);

        System.out.println(strObj.getObj());

 

         getObj<Double> douObj = new getObj<Double>();

         douObj.setObj(new Double(116023));

         System.out.println(douObj.getObj());

 

三、例子分析

現在我們來分析上面那段藍色字體的代碼:

1<T>是泛型的標記,當然可以使用別的名字,比如。使用<T>聲明一個泛型的引用,從而可以在class、方法及接口中使用它進行數據定義,參數傳遞。

2<T>在聲明的時候相當于一個有意義的數據類型,編譯過程中不會發生錯誤;在實例化時,將其用一個具體的數據類型進行替代,從而就可以滿足不用需求。

 

四、泛型的規則和限制

通過上述的例子,我們簡單理解了泛型的含義。在使用泛型時,請注意其使用規則和限制,如下:

1、泛型的參數類型只能是類(class)類型,而不能是簡單類型。

      比如,<int>是不可使用的。

2、可以聲明多個泛型參數類型,比如<T, P,Q>,同時還可以嵌套泛型,例如:<List<String>>

3、泛型的參數類型可以使用extends語句,例如<T extends superclass>

4、泛型的參數類型可以使用super語句,例如< T super childclass>

5、泛型還可以使用通配符,例如<? extends ArrayList>

 

五、 擴展

1extends語句

使用extends語句將限制泛型參數的適用范圍。例如:

<T extends collection> ,則表示該泛型參數的使用范圍是所有實現了collection接口的calss。如果傳入一個<String>則程序編譯出錯。

2super語句

super語句的作用與extends一樣,都是限制泛型參數的適用范圍。區別在于,super是限制泛型參數只能是指定該class的上層父類。

例如<T super List>,表示該泛型參數只能是ListList的上層父類。

3、通配符

使用通配符的目的是為了解決泛型參數被限制死了不能動態根據實例來確定的缺點。

舉個例子:public class SampleClass < T extends S> {}

假如ABC,…Z26class都實現了S接口。我們使用時需要使用到這26class類型的泛型參數。那實例化的時候怎么辦呢?依次寫下

SampleClass<A> a = new SampleClass();

SampleClass<B> a = new SampleClass();

SampleClass<Z> a = new SampleClass();

這顯然很冗余,還不如使用Object而不使用泛型,呵呵,是吧?

別著急,咱們使用通配符,就OK了。

SampleClass<? Extends S> sc = new SampleClass();



梧桐夜雨 2010-01-03 22:10 發表評論
]]>
主站蜘蛛池模板: 大埔县| 南投市| 延安市| 罗山县| 潜山县| 泰兴市| 隆回县| 金山区| 陆川县| 南丹县| 临武县| 岳西县| 蒙阴县| 旌德县| 新巴尔虎右旗| 灵石县| 定边县| 罗平县| 阳信县| 曲周县| 邛崃市| 克什克腾旗| 新干县| 睢宁县| 定远县| 南华县| 凤城市| 齐河县| 岐山县| 壶关县| 荣成市| 河源市| 双桥区| 威宁| 仪征市| 商城县| 高安市| 荣成市| 乳山市| 宿松县| 沭阳县|