jar-analyzer / jar-obfuscator

Jar Obfuscator - 一个 JAR/CLASS 字节码混淆工具,支持包名/类名/方法名/字段名/参数名引用分析和重命名混淆方式,支持字符串加密/整型异或混淆/垃圾代码花指令混淆/等方式,支持方法和字段的隐藏,支持 NATIVE 层的 JVMTI 代码加密,配置简单,文档教程齐全,容易上手
MIT License
313 stars 29 forks source link

一些功能完善建议 #14

Closed pcdlrzxx closed 3 months ago

pcdlrzxx commented 4 months ago

测试完了 0.0.8 版本,JDK 17 也能正确使用字节码加密,新增了方法和字段的隐藏功能(点赞),辛苦大佬了,下面反馈一些建议:

1、能够支持多个 jar 包同时混淆和加密呢,现在单个混淆的方式对于大工程来说会有点痛苦(这个其实有点类似之前我提的 MAVEN 插件功能,不过可能这个会更容易实现一些(?))

2、[BUG] 不允许开启 enablePackageName 时使用字节码加密,关于这一点,我今天又想了一下,是否能根据ObfEnv.classNameObfMapping这个 map 里面的内容来加密呢,因为这里面存放的都是需要进行混淆的类,如此便能在enablePackageName: true的情况下进行加密,而且也不会对其他不需要加密的类造成影响

3、字节码解密时,是否会对未加密的 jar 包也进行解密,从而导致解密失败报错(多 jar 包工程)。今天测试时偶然发现这个问题,大致的情况如下:假设一个工程会导出3个 jar 包,分别是A.jar(未混淆,未加密),B.jar(已混淆,已加密),C.jar(未混淆,未加密),其中 A 为启动 jar 包,会调用 B,B 又会调用 C,在使用java -XX:+DisableAttachMechanism -agentpath:...启动 A 后,发现 B 能正确字节码解密,但到 C 时发现也会进行字节码解密,然而由于 C 并未进行字节码加密,从而导致报错,当我将 C 也进行混淆和加密后,整个调用过程就正常了。所以想问问,多 jar 包链路调用时,字节码解密是怎样的工作流程呢

4ra1n commented 4 months ago
  1. 这个我之后看看
  2. 这个地方如果开了包名混淆,会出现一大堆包,本来的com.a.b和com.a.c和com.a.d等我配置com.a即可,但是会变成iii.il和ii1.LL等等,而JNI传递的参数是一个包名例如me.n1ar4然后过滤和加密,如果这个地方传一个java的string[]或者list,在JNI层会很难写,修改的代价有点大
  3. 可能是同包名的问题,JVM的agentlib参数是全局的,不区分具体的JAR包,如果配置解密是com.a那么所有的com.a都会解密,你可以把不加密的包名换掉,避免com.a.x
pcdlrzxx commented 4 months ago

3. 可能是同包名的问题,JVM的agentlib参数是全局的,不区分具体的JAR包,如果配置解密是com.a那么所有的com.a都会解密,你可以把不加密的包名换掉,避免com.a.x

这个确实是同包名的问题,我换成不同的包名后就可以了 .

2. 这个地方如果开了包名混淆,会出现一大堆包,本来的com.a.b和com.a.c和com.a.d等我配置com.a即可,但是会变成iii.il和ii1.LL等等,而JNI传递的参数是一个包名例如me.n1ar4然后过滤和加密,如果这个地方传一个java的string[]或者list,在JNI层会很难写,修改的代价有点大

这里原来考虑的是解密时不好解,我还以为是加密时不好加。我今天看了一下native层的代码(有C、Python和ASM,大佬你一个人写的吗,太牛逼了),原来libdecrypter.dlllibencryptor.dll是预先就生成好的,然后在混淆时将其拷贝到code-encryptor-temp文件夹下,在解密时再把PACKAGE_NAMEKEY传给解密的dll,这样可以说libencryptor.dll其实是一个通用文件,接收不同的参数就能解密不同的jar包,是这样理解吧。 这样我感觉还是有些不方便和不安全的地方,不方便在于每次执行解密时都需要传递PACKAGE_NAMEKEY的值,不安全在于传递的参数值可能会外泄(特别是将应用交给别人去执行时),我不太清楚这个dll反编译的难度如何,假设是比较难的,那有没有可能把这两个参数值写入到libencryptor.dll中,就是在执行加密后动态生成解密的dll,将加密用到的KEY和混淆后的包名类名都保存在这个dll里,相当于把通用的dll变为专用的dll,这样在执行解密时就只需要指定dll的路径即可,不用指定其他参数,而且安全性也得到了保障,不知道这样是否可行呢?

4ra1n commented 4 months ago

DLL/SO 动态生成的技术会很麻烦,方案两个:

  1. 动态编译,在用户运行 JAR OBFUSCATOR 的时候根据用户的输入参数,使用 MSVC/GCC 等方式动态生成一个 DLL./SO 文件,这样不用传参数,是定制的 DLL/SO 文件,自行混淆或者加壳后会比较安全(缺单:需要用户本地有编译环境,不现实)
  2. 编译好一个类似模板的 DLL/SO 文件,用户配置什么就字符串替换修改什么 (缺点:可能需要了解WINDOWS PE结构,这种动态 PATCH 需要考虑一些占位和偏移之类的,应该是有办法,但我还没研究过)

动态编译不现实,只能用第二种实现编译好然后动态替换关键部分,这个我还没研究过唉

pcdlrzxx commented 4 months ago
  1. 动态编译,在用户运行 JAR OBFUSCATOR 的时候根据用户的输入参数,使用 MSVC/GCC 等方式动态生成一个 DLL./SO 文件,这样不用传参数,是定制的 DLL/SO 文件,自行混淆或者加壳后会比较安全(缺单:需要用户本地有编译环境,不现实)

"在用户运行 JAR OBFUSCATOR 的时候"这句话我有点没看懂,是指使用jar-obfuscator对jar包进行混淆的时候吗,那这时候应该还在我们(开发者)的环境下吧,如果是这样的话,我倒觉得动态编译可行诶,因为开发者具备C的编译环境,还是挺正常的,最后就只需要把混淆加密后的jar包和解密dll发给用户就行,也不需要把KEY告诉用户

4ra1n commented 4 months ago

我考虑一下,想想这种办法是可行性(因为环境会比较复杂,需要有 CMAKE/MSVC或GCC环境 可能得用户自行配置MSVC等安装目录,有点过于麻烦了)

pcdlrzxx commented 4 months ago

嗯,麻烦大佬了,如果考虑到通用性和复杂度,要不就提供两种方案自行选择,一种现有的,一种需要C编译环境的,不过这样大佬你的工作量会有点大,辛苦辛苦

4ra1n commented 3 months ago

我考虑了下,还是不打算做了,一方面是这个功能做起来麻烦,另外是否真的更安全:

双因素是更安全的:WHAT YOU HAVE 和 WHAT YOU KNOW

一个黑客如果获得了解密 DLL 只突破了一层 WHAT YOU HAVE

黑客还需要知道你的密码,也就是 WHAT YOU KNOW 才可以成功解密

这样是更安全的

如果是考虑到黑客已经有权限了,可以看命令行传递的参数,这种情况,做不到安全了,可以本地 DUMP JVM 内存拿字节码。也就是说,如果有目标机器的权限,黑客可以有更多比较 HACK 的办法获取,这种情况没必要考虑了

pcdlrzxx commented 3 months ago

OK,其实现在的加密方式已经很安全了,只不过我考虑了需要把程序部署到客户方的情况(相当于把 DLL 和密码都给到对方),不过还是辛苦大佬了