国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

深入討論JAVA字節碼加密技術(1)

2019-11-18 12:22:30
字體:
來源:轉載
供稿:網友

  假如把的class文件加密,在運行時用指定的類加載器(class loader)裝入并解密它,能防止被反編譯嗎?結論是防止java字節碼反編譯這個問題在java語言雛形期就有了,盡管市面上存在一些反編譯的工具可以利用,但是JAVA程序員還是不斷的努力尋找新的更有效的方法來保護他們的聰明結晶。在此,我將具體給大家解釋這一直來在論壇上有爭議的話題。
  
    Class文件能被很輕松的重構生成JAVA源文件與最初JAVA字節碼的設計目的和商業交易有緊密地聯系。另外,JAVA字節碼被設計成簡潔、平臺獨立性、網絡靈活性,并且易于被字節碼解釋器和JIT (just-in-time)/HotSpot 編譯器所分析。可以清楚地了解程序員的目的, Class文件要比JAVA源文件更易于分析。
  
    假如不能阻止被反編譯的話,至少可以通過一些方法來增加它的困難性。例如: 在一個分步編譯里,你可以打亂Class文件的數據以使其難讀或者難以被反編譯成正確的JAVA源文件,前者可以采用極端函數重載,后者用操作控制流建立控制結構使其難以恢復正常次序。有更多成功的商業困惑者采用這些或其他的技術來保護自己的代碼。
  
    不幸的是,哪種方法都必須改變JVM運行的代碼,并且許多用戶害怕這種轉化會給他們的程序帶來新的Bug。而且,方法和字段重命名會調用反射從而使程序停止工作,改變類和包的名字會破壞其他的JAVA APIS(JNDI, URL PRoviders, etc),除了改變名字,假如字節碼偏移量和源代碼行數之間的關系改變了,在恢復這有異常的堆棧將很困難。于是就有了一些打亂JAVA源代碼的選項,但是這將從本質上導致一系列問題的產生。
  
    加密而不打亂
  
    或許上述可能會使你問,假如我把字節碼加密而不是處理字節碼,并且JVM運行時自動將它解密并裝入類加載器,然后JVM運行解密后的字節碼文件,這樣就不會被反編譯了對嗎?考慮到你是第一個提出這種想法的并且它又能正常運行,我表示遺憾和不幸,這種想法是錯誤的。
  
    下面是一個簡單的類編碼器:為了闡明這種思想,我采用了一個實例和一個很通用的類加載器來運行它,該程序包括兩個類:
  
  public class Main
  {
   public static void main (final String [] args)
   {
   System.out.println ("secret result = " +
   MySecretClass.mySecretAlgorithm ());
   }
  
  } // End of class
  
  
  package my.secret.code;
  import java.util.Random;
  
  public class MySecretClass
  {
   /**
   * Guess what, the secret algorithm just uses
   * a random number generator...
   */
   public static int mySecretAlgorithm ()
   {
   return (int) s_random.nextInt ();
   }
  
   private static final Random s_random = new Random
   (System.currentTimeMillis ());
  
  } // End of class
  
  
  
    我想通過加密相關的class文件并在運行期解密來隱藏my.secret.code.MySecretClass的執行。用下面這個工具可以達到效果(你可以到這里下載Resources):
  
  public class EncryptedClassLoader extends URLClassLoader
  {
   public static void main (final String [] args)
   throws Exception
   {
   if ("-run".equals (args [0]) && (args.length >= 3))
   {
   // Create a custom loader that will use the current
   //loader as delegation parent:
   final ClassLoader appLoader =
   new EncryptedClassLoader (EncryptedClassLoader.
   class.getClassLoader (),
   new File (args [1]));
  
   // Thread context loader must be adjusted as well:
   Thread.currentThread ().setContextClassLoader
   (appLoader);
  
   final Class app = appLoader.loadClass (args [2]);
  
   final Method appmain = app.getMethod ("main",
   new Class [] {String [].class});
   final String [] appargs = new String[args.length -3];
   System.arraycopy (args,3,appargs,0,appargs.length);
  
   appmain.invoke (null, new Object [] {appargs});
   }
   else if ("-encrypt".equals(args[0])&&(args.length>=3))
   {
   ... encrypt specified classes ...
   }
   else
   throw new IllegalArgumentException (USAGE);
   }
  
   /**
   * Overrides java.lang.ClassLoader.loadClass() to change
   * the usual parent-child delegation rules just enough to
   * be able to "snatch" application classesfrom under
   * system classloader's nose.
   */
   public Class loadClass (final String name,
   final boolean resolve)
   throws ClassNotFoundException
   {
   if (TRACE) System.out.println ("loadClass (" + name +
   ", " + resolve + ")");
   Class c = null;
  
   // First, check if this class has already been defined
   // by this classloader instance:
   c = findLoadedClass (name);
  
   if (c == null)
   {
   Class parentsVersion = null;
   try
   {
   // This is slightly unorthodox: do a trial load via the
   // parent loader and note whether the parent delegated or not;
   // what this accomplishes is proper delegation for all core
   // and extension classes without my having to filter
   // on class name:
   parentsVersion = getParent ().loadClass (name);
  
   if(parentsVersion.getClassLoader()!=getParent())
   c = parentsVersion;
   }
   catch (ClassNotFoundException ignore) {}
   catch (ClassFormatError ignore) {}
  
   if (c == null)
   {
   try
   {
   // OK, either 'c' was loaded by the system (not the bootstrap
   // or extension) loader (in which case I want to ignore that
   // definition) or the parent failed altogether; either way I
   // attempt to define my own version:
   c = findClass (name);
   }
   catch (ClassNotFoundException ignore)
   {
   // If that failed, fall back on the parent's version
   // [which could be null at this point]:
   c = parentsVersion;
   }
   }
   }
  
   if (c == null)
   throw new ClassNotFoundException (name);
  
   if (resolve)
   resolveClass (c);
  
   return c;
   }
  
   /**
   * Overrides java.new.URLClassLoader.defineClass() to
   * be able to call crypt() before defining a class.
   */
   protected Class findClass (final String name)
   throws ClassNotFoundException
   {
   if(TRACE) System.out.println("findClass(" + name + ")");
  
   //.class files are not guaranteed to be loadable as resources;
   // but if Sun's code does it, so perhaps can mine...
   final String classResource = name.replace
   ('.', '/') + ".class";
   final URL classURL = getResource (classResource);
  
   if (classURL == null)
   throw new ClassNotFoundException (name);
   else
   {
   InputStream in = null;
   try
   {
   in = classURL.openStream ();
  
   final byte [] classBytes = readFully (in);
  
   // "decrypt":
   crypt (classBytes);
   if (TRACE) System.out.println ("decrypted
   [" +

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 瑞昌市| 江川县| 金阳县| 遂宁市| 固始县| 内江市| 元江| 繁昌县| 梁平县| 南华县| 嘉黎县| 开平市| 新乡市| 金湖县| 安福县| 全州县| 昆山市| 紫云| 临澧县| 公主岭市| 伊通| 涟水县| 金坛市| 佛山市| 和静县| 松原市| 伊川县| 和田市| 拜城县| 龙口市| 伊宁县| 黔江区| 博罗县| 德庆县| 扶余县| 秦安县| 淮南市| 高密市| 石门县| 石首市| 甘谷县|