(1) 以二进制模式打开源文件;
(2) 从源文件第I位读取一个字节,假设为字母“A”,得到“A”的ASCII值为65;
(3) 将65转换成八位二进制串为“01000001”;
(4) 将“01000001”按字节逐位倒排序得另一个八位二进制串“10000010”;
(5) 将“10000010”转换成十进制再写回源文件第I位置,完成一个字节的加密;
(6) 重复(2)、(3)、(4)和(5),直到所有字节加密结束。
为了使程序模块化,我们用函数过程ByteToBin完成将字节型数据转换成二进制串(其实质就是将十进制数转换成八位二进制串);用函数过程BinToByte将二进制串转换成字节型数据(实质是将八位二进制串转换成十进制数):用函数过程Reverse将八位二进制串逐位倒排序。具体程序如下:
Function ByteToBin(m As Byte) As String ' 将字节型数据转换成八位二进制字符串
Dim c$
c$ = ""
Do While m 0
r = m Mod 2
m = m \ 2
c$ = r &c$
Loop
c$ = Right("00000000" &c$, 8)
ByteToBin = c$
End Function
Function Reverse(m As String) As String ' 将八位二进制字符串颠倒顺序
Dim i%, x$
x = ""
For i = 1 To 8
x = Mid(m, i, 1) &x
Next i
Reverse = x
End Function
Function BinToByte(m As String) As Byte ' 将八位二进制串转换成十进制
Dim x As String * 1, y%, z%
z = 0
For i = 1 To 8
x = Mid(m, i, 1)
y = x * 2 ^ (8 - i)
z = z + y
Next i
BinToByte = z
End Function
Private Sub Command1_Click()
Dim x As Byte, i%, fname$
fname = InputBox("请输入要加密的文件名!注意加上路径名:")
If Dir(fname) = "" Then
MsgBox "文件不存在!"
Exit Sub
End If
Open fname For Binary As #1 ' 以二进制访问模式打开待加密文件
For i = 1 To LOF(1) ' LOF函数是求文件长度的内部函数
Get #1, i, x ' 取出第i个字节
x = BinToByte(Reverse(ByteToBin(x))) ' 这里调用了三个自定义函数
Put #1, i, x ' 将加密后的这个字节写回到文件原位置
Next i
Close
MsgBox "任务完成!"
End Sub
本例可以完成对任意文件的加密与解密,对同一文件作第一次处理为加密,第二次处理为解密。要调试本程序,可用记事本在C盘根目录下任意建立一个文本文件(假设为文件名为aaa.txt),其中的内容任意(可以包括字母、汉字、数字、回车符、换行符等)。运行本程序后,在输入文件名的对话框中输入文件名(如:“C:\aaa.txt”)后回车,即可完成对文件的加密。文件加密后,可以在记事本中打开该文件查看加密效果。如果想解密,可再次运行该程序并输入相同文件名。
这个累加载器(EncryptedClassLoader)有两个基本的 *** 作 在给定的类路径下加密一系列Class文件并且运行一个先前加密的程序 加密后的文件很简单 有一些极讨厌的各个字节的位组成 (当然 XOR运算符不可能被加密 这只是一个范例 请多多包涵 ) 通过EncryptedClassLoader来加载类需要注意一些问题 我实现的是继承自 URLClassLoader并且重载了loadClass()和defineClass()两个方法来实现自己的两个功能 一个是专心于JAVA 类加载器的委托规则并且在系统类加载器做之前先加载一个经加密过的类二是在执行defineClass()之前立即调用crypt()方法 否则会执行URLClassLoader findClass() 执行下面的语句 >javac d bin src/* java src/my/secret/code/* java 我把Main class和MySecretClass class进行了 加密 >java cp bin EncryptedClassLoader encrypt bin Main my de MySecretClassencrypted [Main class]encrypted [my\secret\code\MySecretClass class] 现在原先编译的class文件已经被加密后的文件所替代了 如果我想运行原始类文件 需要使用EncryptedClassLoader来 *** 作 >java cp bin MainException in thread main java lang ClassFormatError: Main (Illegal constant pool type) at java lang ClassLoader defineClass (Native Method) at java lang ClassLoader defineClass(ClassLoader java: ) at java security SecureClassLoader defineClass (SecureClassLoader java: ) at URLClassLoader defineClass(URLClassLoader java: ) at URLClassLoader access$ (URLClassLoader java: ) at URLClassLoader$ run(URLClassLoader java: ) at java security AccessController doPrivileged(Native Method) at URLClassLoader findClass(URLClassLoader java: ) at java lang ClassLoader loadClass(ClassLoader java: ) at sun misc Launcher$AppClassLoader loadClass(Launcher java: ) at java lang ClassLoader loadClass(ClassLoader java: ) at java lang ClassLoader loadClassInternal(ClassLoader java: )>java cp bin EncryptedClassLoader run bin Maindecrypted [Main]decrypted [de MySecretClass]secret result = 现在可以确信 采用任何反编译工具对加密后的Class文件都不会起作用的 现在添加一个可靠的密码保护机制 把它打包成本地可执行文件 并且使其对外收费 这样子可以吗?当然不能这样了 ClassLoader defineClass():必然经过的接口 所有的类加载器必须经过明确地API把类定义传递到JVM里 这就需要java lang ClassLoader defineClass()方法了 类加载器的API有多个这个方法的重载 但是所有的方法都会调用defineClass(String byte[] int int ProtectionDomain) 这是一个在经过一些简单验证后放入到JVM里的最终的方法 如果你想建立一个新的Class文件的话 这对于理解每个类加载器都会不可避免的调用该方法是很重要的 你只能在方法defineClass()里把一些单调的字节数组生成Class对象 并且我们猜测这些字节数组文件会包含一些文档格式化(查看class文件格式规范well document.d format)的未加密的class定义 通过拦截对该方法的所有调用可以很简单的破坏这种加密模式 并且很方便的反编译你感兴趣的Class文件 做这种拦截并不困难 实际上破坏自己建立的保护模式比用工具更加迅速的 首先 我取得基于J SDK的java lang ClassLoader源文件 并修改defineClass(String byte[] int int ProtectionDomain)方法 在里面加入其他的类 正如下面 c = defineClass (name b off len protectionDomain)//Intercept classes defined by the system loader and its children:if (isAncestor (getSystemClassLoader () getParent ())) { // Choose your own dump location here [use an absolute pathname]: final File parentDir = new File ( c:/TEMP/classes/ )File dump = new File (parentDir name replace ( File separatorChar) + [ + getClass () getName () + @ +Long toHexString (System identityHashCode (this)) + ] class ) dump getParentFile () mkdirs () FileOutputStream out = nulltry { out = new FileOutputStream (dump) out write (b off len)} catch (IOException ioe) { ioe printStackTrace (System out)} finally { if (out != null) try { out close ()} catch (Exception ignore) {} } } 注意if里的语句可以过滤系统类加载器及其子类加载器 同样在defineClass()方法可以正常工作的情况下才能载入类 很难以相信不只有一个类加载器实例加载一个类 可通过在文件名堆里面加入类加载器标志我还是最终把这一问题给解决了 ) 最后一步是用包含java lang ClassLoader类的可执行文件临时替换由JRE使用的文件rt jar 你也可以使用 Xbootclasspath/p选项 我再一次运行加密的程序 并恢复了所有的未加密的文件 这么说可以很容易的把 class文件正确的反编译 我先声明我并没有用EncryptedClassLoader类的内部机制来完成此壮举的 在这里注意一点 假如我没去使用一个系统类 我可以使用别的方法 比如自定义一个JVMPI代理来处理JVMPI_EVENT_CLASS_LOAD_HOOK事件 学习小结 我希望你能对本文有所兴趣 你必须认识到得很重要的一点是在购买市面上任何反编译工具前要三思而行 除非JVM体系结构进行改革以支持class字节码在本地能进行译码转换 你才会更好的从传统的困惑中走出来 上演一场字节码的改革浪潮!当然也有其他的更有效的方法 对类加载进行调试 尽可能地得到类加载的轨迹是很有价值的 特别是在类加载时你去捕获异常情况下使用 因此 JAVA的诞生可能纯粹是为了开源项目 当然 其他一些体系结构(如 NET)也正在倾向于反编译 目前我就说说这种思想了 lishixinzhi/Article/program/Java/gj/201311/27493问 如果我把我的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 classpackage deimport java util Randompublic 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文件并在运行期解密来隐藏de MySecretClass的执行 用下面这个工具可以达到效果(你可以到这里下载Resources) public class EncryptedClassLoader extends URLClassLoader{public static void main (final String [] args)throws Exception{if ( run equals (args [ ]) &&(args length >= )){// Create a custom loader that will use the current loader as// delegation parent:final ClassLoader appLoader =new EncryptedClassLoader (EncryptedClassLoader class getClassLoader () new File (args [ ]))// Thread context loader must be adjusted as well:Thread currentThread () setContextClassLoader (appLoader)final Class app = appLoader loadClass (args [ ])final Method appmain = app getMethod ( main new Class [] {String [] class})final String [] appargs = new String [args length ]System arraycopy (args appargs appargs length)appmain invoke (null new Object [] {appargs})}else if ( encrypt equals (args [ ]) &&(args length >= )){ encrypt specified classes }elsethrow new IllegalArgumentException (USAGE)}/** * Overrides java lang ClassLoader loadClass() to change the usual parent child * delegation rules just enough to be able to snatch application classes * from 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 = nulltry{// This is slightly unorthodox: do a trial load via the// parent loader and note whether the parent delegated or not// what this acplishes 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 altogethereither 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 = nulltry{in = classURL openStream ()final byte [] classBytes = readFully (in)lishixinzhi/Article/program/Java/hx/201311/25555
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)