Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

java段怎么通过指定agentpath,调用dll,解密class #1

Open
GitHubcaowei opened this issue Mar 21, 2019 · 30 comments
Open

java段怎么通过指定agentpath,调用dll,解密class #1

GitHubcaowei opened this issue Mar 21, 2019 · 30 comments

Comments

@GitHubcaowei
Copy link

我们提供jar供第三方调用,但是不像让第三方看到jar的源码,所以我也采用dll完成此需求,但是我不知道在jar如何集成dll,这样让第三方无感调用jar。

@sea-boat
Copy link
Owner

@wuyingdu
Copy link

你好,我用您的方法,普通的java项目,这样做的确可以做到jar加密,十分感谢,
但是在做springboot项目 jar的加密时,在启动 jar,提示

image

我怀疑是springboot项目和普通java项目的jar结构不一样。

image

image

我也再尝试修改springboot项目的路径, (我是java开发师,c++不是很懂),

尝试着修改JarEncryptor的

image

尝试着修改C++的cpp源文件

image

也不知道是否正确,拜托您帮忙看一下,现在在cmd启动出现第一张图的错误。

我不是很了解c++,怀疑是这里的 if 中的strncmp(name, "BOOT-INF/classes/com/wyd/", 25)这行代码的问题(里面有大小写和符合 - ,与25是否匹配)。拜托您抽空看看。

@sea-boat
Copy link
Owner

你尝试调试一下,把java层和c++层的name和加解密结果都打印出来看看,就知道是哪里的问题了

@wuyingdu
Copy link

wuyingdu commented May 13, 2019

你尝试调试一下,把java层和c++层的name和加解密结果都打印出来看看,就知道是哪里的问题了

您好,我尝试着修改了文件,并打印name。

image

image

image

image

[我是java开发师,对c++一点都不懂,十分抱歉再次打扰到你。

您若是有时间,帮我看看这个。谢谢

问题说明.zip

@sea-boat
Copy link
Owner

没有加载的话直接配一下classpath,将你的目录添加进去即可。

@wuyingdu
Copy link

这个问题已经困扰我好几天了,我实在是看不懂c++的语法,您能帮我写稍微修改一下吗?我愿意请您喝杯咖啡,或者其它,来表示我对您帮助的一点谢意。

@sea-boat
Copy link
Owner

我看了下,问题应该在springboot自己写了类加载器,那个boot-inf是他自己的类加载器加载的,它没有交给jvm的系统类加载器加载。现在如果要简单处理的话你可以把加密的类打包到正常的目录下,而不是boot-inf里面,你是用maven管理的吧,好像是有插件可以做这个事。另外一种方法就是要改springboot的类加载器,比较麻烦。

@sea-boat
Copy link
Owner

还有,记得放到正常目录的类,里面不要用到第三方类,只能用由系统类加载器加载的类,比如java语言自带的类,不然会找不到类,因为不同类加载器加载。

@wuyingdu
Copy link

wuyingdu commented May 13, 2019

image
是这样理解的吗?这样的话,springboot项目因为它独特的类加载器,所以这种加密方式,无法使用。

@sea-boat
Copy link
Owner

你理解的大致没问题,不过不是说无法使用,是因为springboot自定义的类加载器没有使用双亲委派机制,所以不会委派给系统类加载器来加载。需要改动到springboot将类交给系统类加载器加载或者把类放到你图中的java常规目录下。

@wuyingdu
Copy link

通过您提供的思路,今天尝试着将springboot jar 外层的BOOT-INF/classes尝试去除。

参考网上,使用maven的插件 maven-jar-plugin 将依赖包lib和配置文件config与源码进行分离,

成功的将springboot jar 去除外层的BOOT-INF/classes 还原成普通的 jar 项目,就是启动时,需要将lib和config与jar放在一起。

还有一个问题,加密springboot的启动类时,解密失败多次。

image

其余的controller层加解密无异常。

image

毕竟核心业务代码也都是在 controller,所以暂时不加密springboot启动类,换成controller层。这个需求暂时也算是过了。

我还想写篇博客,总结一下这次的经验,方便转载或者摘抄博客吗?会注明出处。

十分感谢您的帮助,方便告诉您的支付宝号或者收款码,请您喝杯咖啡聊表谢意。

如果觉得泄露隐私,可以留邮箱联系您。或者我的邮箱 [email protected]

@sea-boat
Copy link
Owner

博客可以转载,注明出处即可。
多谢打赏。

TIM图片20190514230510

@wuyingdu
Copy link

image

image

加解密的字符位置和之前windows一样。在if判断内的。这是什么原因呢?

@sea-boat
Copy link
Owner

@NotHys
Copy link

NotHys commented May 29, 2019

你好我按情况编写了加密解密springboot 项目 但是 在启动是报错nested exception is org.springframework.core.NestedIOException: ASM ClassReader failed to parse class file - probably due to a new Java class file version that isn't supported yet 而且也没有进去解密的类 我已经将springboot的jar弄成了一般的jar 请问有解决方案吗?非常感谢

@NotHys
Copy link

NotHys commented May 29, 2019

image

image

加解密的字符位置和之前windows一样。在if判断内的。这是什么原因呢?

我在windows下根本加载不了 不进去解密的jvmti写的Agent_OnLoad

@NotHys
Copy link

NotHys commented May 29, 2019

image

image

加解密的字符位置和之前windows一样。在if判断内的。这是什么原因呢?
你成功加密的demo 可以给一个吗 或者加个联系方式QQ 1304320858

@wuyingdu
Copy link

wuyingdu commented May 29, 2019 via email

@NotHys
Copy link

NotHys commented May 30, 2019

可以参考我写的博客:https://blog.csdn.net/weixin_39747279/article/details/90214044 博客仅实现了windows平台的springboot jar包的加密,linux版本的有异常,没有实现。 你刚才的异常,网上搜索了一下,是JDK和spring的版本冲突, jdk7对应的是spring 3.2, jdk8对应的是spring 4.2. 你可以排查一下这方面的。

------------------ 原始邮件 ------------------ 发件人: "yushuihong"[email protected]; 发送时间: 2019年5月29日(星期三) 晚上6:22 收件人: "sea-boat/ByteCodeEncrypt"[email protected]; 抄送: "娃哈哈矿泉水"<[email protected]>;"Comment"<[email protected]>; 主题: Re: [sea-boat/ByteCodeEncrypt] java段怎么通过指定agentpath,调用dll,解密class (#1) 加解密的字符位置和之前windows一样。在if判断内的。这是什么原因呢? 你成功加密的demo 可以给一个吗 或者加个联系方式QQ 1304320858 — You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.

我排除了是JDK和spring的版本冲突的问题的 你试一试把你的加密的那做的复杂一点 比如AES DES 简单的字符str[i] = str[i] + 4 这种 idea 瞬间反编译 其实 可以思考一下 字节码前8个 是魔数 如果魔数不对 是不会加载类的 jdk马上会返回错误,而简单的str[i] = str[i] + 4 还是能识别就证明 这种加密其实没有太大的作用jdk的类加载和springboot的类加载都能识别(我的猜测),需要把字节加密做的复杂而且前8个字节是不能加密的。 当你把字节加密做的复杂的时候 你就会发现springboot的不管是lib和config分离 还是不分离 都运行不起来,(已经做了测试)。总之 在springboot下简单的str[i] = str[i] + 4 能运行(可能是类加载可以处理这种简单的错误code) 复杂的加密运行不了。而且运行复杂的版本的时候 不会进入dll或so的解密算法(假设我的算法有错它也应该会进入解密流程再报错),所以我猜测还是被springboot类加载器加载了,springboot没有双亲委派所以不会进入自定义的jvmti实现中。

基于这个情况我将springboot的类加载器重写进行加密解密,然后将重写springboot类加载器的class通过这个方案加密,因为spring boot 类加载器的加载肯定是会被原始的类加载器加载的,这样算是解决了也正常运行了反编译也看不到了idea同样无法反编译。不知道是不是我弄的没对还是怎么。用你的方案复杂加密算法是无法运行的,你可以尝试一下 如果能运行麻烦告知一下谢谢!

@wuyingdu
Copy link

QQ联系详细聊吧

@xiaoheitalk
Copy link

#1 (comment)

image
image
加解密的字符位置和之前windows一样。在if判断内的。这是什么原因呢?

我在windows下根本加载不了 不进去解密的jvmti写的Agent_OnLoad

最近也在做对jar加密的事情,这边个人感觉是spring自己负责解析class文件,没有交给jvm进行解析(所以也没有进行回调ClassDecryptHook),在spring解析class文件时,由于是密文所以在解析时出现了异常(org.springframework.asm.ClassReader#ClassReader(byte[], int, int));
试过:手动注册被加密后的class类,在BeanDefinitionBuilder.genericBeanDefinition(className) 会调用回调函数,进而解密加载被加密的class文件。
所以个人的判断是:spring项目无法使用jvmti进行加解密后运行。

@WheatMaThink
Copy link

你好我按情况编写了加密解密springboot 项目 但是 在启动是报错nested exception is org.springframework.core.NestedIOException: ASM ClassReader failed to parse class file - probably due to a new Java class file version that isn't supported yet 而且也没有进去解密的类 我已经将springboot的jar弄成了一般的jar 请问有解决方案吗?非常感谢

请问一下这个问题解决了吗?是什么思路,刚刚遇见相同的情况。

@wuyingdu
Copy link

wuyingdu commented Aug 30, 2019 via email

@WheatMaThink
Copy link

WheatMaThink commented Sep 3, 2019

可以参考我写的博客:https://blog.csdn.net/weixin_39747279/article/details/90214044 博客仅实现了windows平台的springboot jar包的加密,linux版本的有异常,没有实现。 你刚才的异常,网上搜索了一下,是JDK和spring的版本冲突, jdk7对应的是spring 3.2, jdk8对应的是spring 4.2. 你可以排查一下这方面的。

------------------ 原始邮件 ------------------ 发件人: "yushuihong"[email protected]; 发送时间: 2019年5月29日(星期三) 晚上6:22 收件人: "sea-boat/ByteCodeEncrypt"[email protected]; 抄送: "娃哈哈矿泉水"<[email protected]>;"Comment"<[email protected]>; 主题: Re: [sea-boat/ByteCodeEncrypt] java段怎么通过指定agentpath,调用dll,解密class (#1) 加解密的字符位置和之前windows一样。在if判断内的。这是什么原因呢? 你成功加密的demo 可以给一个吗 或者加个联系方式QQ 1304320858 — You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.

我排除了是JDK和spring的版本冲突的问题的 你试一试把你的加密的那做的复杂一点 比如AES DES 简单的字符str[i] = str[i] + 4 这种 idea 瞬间反编译 其实 可以思考一下 字节码前8个 是魔数 如果魔数不对 是不会加载类的 jdk马上会返回错误,而简单的str[i] = str[i] + 4 还是能识别就证明 这种加密其实没有太大的作用jdk的类加载和springboot的类加载都能识别(我的猜测),需要把字节加密做的复杂而且前8个字节是不能加密的。 当你把字节加密做的复杂的时候 你就会发现springboot的不管是lib和config分离 还是不分离 都运行不起来,(已经做了测试)。总之 在springboot下简单的str[i] = str[i] + 4 能运行(可能是类加载可以处理这种简单的错误code) 复杂的加密运行不了。而且运行复杂的版本的时候 不会进入dll或so的解密算法(假设我的算法有错它也应该会进入解密流程再报错),所以我猜测还是被springboot类加载器加载了,springboot没有双亲委派所以不会进入自定义的jvmti实现中。

基于这个情况我将springboot的类加载器重写进行加密解密,然后将重写springboot类加载器的class通过这个方案加密,因为spring boot 类加载器的加载肯定是会被原始的类加载器加载的,这样算是解决了也正常运行了反编译也看不到了idea同样无法反编译。不知道是不是我弄的没对还是怎么。用你的方案复杂加密算法是无法运行的,你可以尝试一下 如果能运行麻烦告知一下谢谢!

可以分析出是解析org.springframework.asm.ClassReader#ClassReader(byte[], int, int) 出的问题,

springboot没有双亲委派所以不会进入自定义的jvmti实现中,请教一下这个是怎么实现的?

@wuyingdu
Copy link

wuyingdu commented Sep 3, 2019 via email

@superlee007
Copy link

superlee007 commented Jan 7, 2020

image

image

加解密的字符位置和之前windows一样。在if判断内的。这是什么原因呢?

这个是spring-boot项目加密后启动报数组越界的错误。经排查是由于spring aop注解扫描的时候需要用asm框架去读取字节码数据,去获取注解信息,用于实例化对象,但是由于class文件已经被加密过,SimpleMetadataReader这个类去读取加密字节文件InputStream,然后在将输入流转换为字节数组去构建ClassReader,但是这个字节数组其实已经被c代码修改过了,因此会报数组越界异常。因此需要修改SimpleMetadataReader代码。
详细的原因参考这篇文章
image
由于牵扯到修改源码,有几种方式:
1.直接在项目里,建一个org.springframework.core.type.classreading包,将源码SimpleMetadataReadercopy出来做修改即可。这是最简单直接的方式。

2.第一种方式可能需要每个加密项目都要建相同的包路径和文件,不是很优雅,因此还有一个思路就是修改SimpleMetadataReader类后自己在重新构建spring源码,发布。

3.修改源码,重新构建,打包发布考虑到也比较麻烦,因此就考虑使用jvmti 的class onload回调函数里,拦截SimpleMetadataReader的加载数据,进行替换。
首先也是将SimpleMetadataReader源码copy出来进行相应的字节码解密修改,然后读取SimpleMetadataReader.class文件,转为byte[]数组,然后转为16进制字符串,将16进制字符串进行两位一组分组,分组后每个字符串前加0x前缀(16进制标识),组成四位一组的的字节码数组输出(因为jvmti的ClassFileLoadHook回调函数的unsigned char* class_data就是这种格式)。将输出的字节码数组复制到c代码里,作为一个常量字符数组,然后在ClassFileLoadHook函数里拦截org/springframework/core/type/classreading/SimpleMetadataReader这个类,使用常量替换即可。
注意new_class_data在替换的时候需要申请新的数组空间,否则会出现服务随机无法启动的问题。

@yixianluo
Copy link

image
image
加解密的字符位置和之前windows一样。在if判断内的。这是什么原因呢?

这个是spring-boot项目加密后启动报数组越界的错误。经排查是由于spring aop注解扫描的时候需要用asm框架去读取字节码数据,去获取注解信息,用于实例化对象,但是由于class文件已经被加密过,SimpleMetadataReader这个类去读取加密字节文件InputStream,然后在将输入流转换为字节数组去构建ClassReader,但是这个字节数组其实已经被c代码修改过了,因此会报数组越界异常。因此需要修改SimpleMetadataReader代码。
详细的原因参考这篇文章
image
由于牵扯到修改源码,有几种方式:
1.直接在项目里,建一个org.springframework.core.type.classreading包,将源码SimpleMetadataReadercopy出来做修改即可。这是最简单直接的方式。

2.第一种方式可能需要每个加密项目都要建相同的包路径和文件,不是很优雅,因此还有一个思路就是修改SimpleMetadataReader类后自己在重新构建spring源码,发布。

3.修改源码,重新构建,打包发布考虑到也比较麻烦,因此就考虑使用jvmti 的class onload回调函数里,拦截SimpleMetadataReader的加载数据,进行替换。
首先也是将SimpleMetadataReader源码copy出来进行相应的字节码解密修改,然后读取SimpleMetadataReader.class文件,转为byte[]数组,然后转为16进制字符串,将16进制字符串进行两位一组分组,分组后每个字符串前加0x前缀(16进制标识),组成四位一组的的字节码数组输出(因为jvmti的ClassFileLoadHook回调函数的unsigned char* class_data就是这种格式)。将输出的字节码数组复制到c代码里,作为一个常量字符数组,然后在ClassFileLoadHook函数里拦截org/springframework/core/type/classreading/SimpleMetadataReader这个类,使用常量替换即可。
注意new_class_data在替换的时候需要申请新的数组空间,否则会出现服务随机无法启动的问题。

你好,SimpleMetadataReader要怎么修改,方案3有详细代码吗,方便的话,qq沟通一下:407072737,谢谢

@nobody19527
Copy link

https://bce.gopiqiu.com/ 去这个网站看看,能解决上面提到的所有问题。

@nobody19527
Copy link

通过您提供的思路,今天尝试着将springboot jar 外层的BOOT-INF/classes尝试去除。 参考网上,使用maven的插件 maven-jar-plugin 将依赖包lib和配置文件config与源码进行分离, 成功的将springboot jar 去除外层的BOOT-INF/classes 还原成普通的 jar 项目,就是启动时,需要将lib和config与jar放在一起。 还有一个问题,加密springboot的启动类时,解密失败多次。 image 其余的controller层加解密无异常。 image 毕竟核心业务代码也都是在 controller,所以暂时不加密springboot启动类,换成controller层。这个需求暂时也算是过了。 我还想写篇博客,总结一下这次的经验,方便转载或者摘抄博客吗?会注明出处。 十分感谢您的帮助,方便告诉您的支付宝号或者收款码,请您喝杯咖啡聊表谢意。 如果觉得泄露隐私,可以留邮箱联系您。或者我的邮箱 [email protected]

https://bce.gopiqiu.com/ 去这个网站看看,能解决上面提到的所有问题。

@nobody19527
Copy link

image
image
加解密的字符位置和之前windows一样。在if判断内的。这是什么原因呢?

这个是spring-boot项目加密后启动报数组越界的错误。经排查是由于spring aop注解扫描的时候需要用asm框架去读取字节码数据,去获取注解信息,用于实例化对象,但是由于class文件已经被加密过,SimpleMetadataReader这个类去读取加密字节文件InputStream,然后在将输入流转换为字节数组去构建ClassReader,但是这个字节数组其实已经被c代码修改过了,因此会报数组越界异常。因此需要修改SimpleMetadataReader代码。
详细的原因参考这篇文章
image
由于牵扯到修改源码,有几种方式:
1.直接在项目里,建一个org.springframework.core.type.classreading包,将源码SimpleMetadataReadercopy出来做修改即可。这是最简单直接的方式。
2.第一种方式可能需要每个加密项目都要建相同的包路径和文件,不是很优雅,因此还有一个思路就是修改SimpleMetadataReader类后自己在重新构建spring源码,发布。
3.修改源码,重新构建,打包发布考虑到也比较麻烦,因此就考虑使用jvmti 的class onload回调函数里,拦截SimpleMetadataReader的加载数据,进行替换。
首先也是将SimpleMetadataReader源码copy出来进行相应的字节码解密修改,然后读取SimpleMetadataReader.class文件,转为byte[]数组,然后转为16进制字符串,将16进制字符串进行两位一组分组,分组后每个字符串前加0x前缀(16进制标识),组成四位一组的的字节码数组输出(因为jvmti的ClassFileLoadHook回调函数的unsigned char* class_data就是这种格式)。将输出的字节码数组复制到c代码里,作为一个常量字符数组,然后在ClassFileLoadHook函数里拦截org/springframework/core/type/classreading/SimpleMetadataReader这个类,使用常量替换即可。
注意new_class_data在替换的时候需要申请新的数组空间,否则会出现服务随机无法启动的问题。

你好,SimpleMetadataReader要怎么修改,方案3有详细代码吗,方便的话,qq沟通一下:407072737,谢谢

https://bce.gopiqiu.com/ 去这个网站看看,能解决上面提到的所有问题。

image
image
加解密的字符位置和之前windows一样。在if判断内的。这是什么原因呢?

这个是spring-boot项目加密后启动报数组越界的错误。经排查是由于spring aop注解扫描的时候需要用asm框架去读取字节码数据,去获取注解信息,用于实例化对象,但是由于class文件已经被加密过,SimpleMetadataReader这个类去读取加密字节文件InputStream,然后在将输入流转换为字节数组去构建ClassReader,但是这个字节数组其实已经被c代码修改过了,因此会报数组越界异常。因此需要修改SimpleMetadataReader代码。
详细的原因参考这篇文章
image
由于牵扯到修改源码,有几种方式:
1.直接在项目里,建一个org.springframework.core.type.classreading包,将源码SimpleMetadataReadercopy出来做修改即可。这是最简单直接的方式。
2.第一种方式可能需要每个加密项目都要建相同的包路径和文件,不是很优雅,因此还有一个思路就是修改SimpleMetadataReader类后自己在重新构建spring源码,发布。
3.修改源码,重新构建,打包发布考虑到也比较麻烦,因此就考虑使用jvmti 的class onload回调函数里,拦截SimpleMetadataReader的加载数据,进行替换。
首先也是将SimpleMetadataReader源码copy出来进行相应的字节码解密修改,然后读取SimpleMetadataReader.class文件,转为byte[]数组,然后转为16进制字符串,将16进制字符串进行两位一组分组,分组后每个字符串前加0x前缀(16进制标识),组成四位一组的的字节码数组输出(因为jvmti的ClassFileLoadHook回调函数的unsigned char* class_data就是这种格式)。将输出的字节码数组复制到c代码里,作为一个常量字符数组,然后在ClassFileLoadHook函数里拦截org/springframework/core/type/classreading/SimpleMetadataReader这个类,使用常量替换即可。
注意new_class_data在替换的时候需要申请新的数组空间,否则会出现服务随机无法启动的问题。

你好,SimpleMetadataReader要怎么修改,方案3有详细代码吗,方便的话,qq沟通一下:407072737,谢谢

https://bce.gopiqiu.com/ 去这个网站看看,能解决上面提到的所有问题。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants