怎么使用自定义类加载器防止代码被反编译破解
发表于:2025-11-12 作者:千家信息网编辑
千家信息网最后更新 2025年11月12日,本篇内容主要讲解"怎么使用自定义类加载器防止代码被反编译破解",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"怎么使用自定义类加载器防止代码被反编译破解"吧!
千家信息网最后更新 2025年11月12日怎么使用自定义类加载器防止代码被反编译破解
本篇内容主要讲解"怎么使用自定义类加载器防止代码被反编译破解",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"怎么使用自定义类加载器防止代码被反编译破解"吧!
代码防编译整体套路
1、编写加密工具类
@Slf4jpublic class EncryptUtils { private static String secretKey = "test123456lyb-geek"+System.currentTimeMillis(); private EncryptUtils(){} public static void encrypt(String classFileSrcPath,String classFileDestPath) { System.out.println(secretKey); FileInputStream fis = null; FileOutputStream fos = null; try { fis = new FileInputStream(classFileSrcPath); fos = new FileOutputStream(classFileDestPath); int len; String[] arrs = secretKey.split("lyb-geek"); long key = Long.valueOf(arrs[1]); System.out.println("key:"+key); while((len = fis.read())!=-1){ byte data = (byte)(len + key + secretKey.length()); fos.write(data); } } catch (Exception e) { log.error("encrypt fail:"+e.getMessage(),e); }finally { if(fis != null){ try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } if(fos != null){ try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } } }}2、对需要防止被反编译代码加密
public static void main(String[] args) { String classFileSrcPath = classFileSrcPath("UserServiceImpl"); System.out.println("classFileSrcPath:--->"+classFileSrcPath); String classFileDestDir = ServiceGenerate.class.getClassLoader().getResource("META-INF/services/").getPath(); System.out.println("classFileDestDir:--->"+classFileDestDir); String classFileDestPath = classFileDestDir + "com.github.lybgeek.user.service.impl.UserServiceImpl.lyb"; EncryptUtils.encrypt(classFileSrcPath,classFileDestPath); }3、对加密代码进行反编译验证
打开反编译工具jd-gui,把加密的代码拖入jd-gui
打不开,至少说明不能用jd-gui来反编译加密过的代码。
我们打开正常的编译的class文件,其内容形如下 从内容我们大概还是能看出一些东西,比如包名啥的。而打开加密后的文件,其内容如下 内容宛若天书
思考一:代码都被加密了,那jvm如何识别?
答案:既然有加密,自然可以通过解密来使用。那这个解密得存放在什么地方进行解密?
如果对类加载有一定了解的朋友,就会知道java的class文件是通过类加载器把class加载入jvm内存中,因此我们可以考虑把解密放在类加载器中。常用的类加载有启动类加载器、扩展类加载器、系统类加载。我们正常classpath路径下的类都是通过系统类加载器进行加载。而不巧这三个jdk提供的加载器没法满足我们的需求。因此我们只能自己实现我们的类加载器。其自定义加载器代码如下
@Slf4jpublic class CustomClassLoader extends ClassLoader{ /** * 授权码 */ private String secretKey; private String SECRETKEY_PREFIX = "lyb-geek"; /** * class文件的根目录 */ private String classRootDir = "META-INF/services/"; public CustomClassLoader(String secretKey) { this.secretKey = secretKey; } public String getClassRootDir() { return classRootDir; } public void setClassRootDir(String classRootDir) { this.classRootDir = classRootDir; } @Override protected Class> findClass(String name) throws ClassNotFoundException { Class> clz = findLoadedClass(name); //先查询有没有加载过这个类。如果已经加载,则直接返回加载好的类。如果没有,则加载新的类。 if(clz != null){ return clz; }else{ ClassLoader parent = this.getParent(); clz = getaClass(name, clz, parent); if(clz != null){ return clz; }else{ clz = getaClass(name); } } return clz; } private Class> getaClass(String name) throws ClassNotFoundException { Class> clz; byte[] classData = getClassData(name); if(classData == null){ throw new ClassNotFoundException(); }else{ clz = defineClass(name, classData, 0,classData.length); } return clz; } private Class> getaClass(String name, Class> clz, ClassLoader parent) { try { //委派给父类加载 clz = parent.loadClass(name); } catch (Exception e) { //log.warn("parent load class fail:"+ e.getMessage(),e); } return clz; } private byte[] getClassData(String classname){ if(StringUtils.isEmpty(secretKey) || !secretKey.contains(SECRETKEY_PREFIX) || secretKey.split(SECRETKEY_PREFIX).length != 2){ throw new RuntimeException("secretKey is illegal"); } String path = CustomClassLoader.class.getClassLoader().getResource("META-INF/services/").getPath() +"/"+ classname+".lyb"; InputStream is = null; ByteArrayOutputStream bas = null; try{ is = new FileInputStream(path); bas = new ByteArrayOutputStream(); int len; //解密 String[] arrs = secretKey.split(SECRETKEY_PREFIX); long key = Long.valueOf(arrs[1]); // System.out.println("key:"+key); while((len = is.read())!=-1){ byte data = (byte)(len - key - secretKey.length()); bas.write(data); } return bas.toByteArray(); }catch(Exception e){ e.printStackTrace(); return null; }finally{ try { if(is!=null){ is.close(); } } catch (IOException e) { log.error("encrypt fail:"+e.getMessage(),e); } try { if(bas!=null){ bas.close(); } } catch (IOException e) { e.printStackTrace(); } } }}通过如下方式进行调用
public static void main(String[] args) throws Exception{ CustomClassLoader customClassLoader = new CustomClassLoader("test123456lyb-geek1603895713759"); Class clz = customClassLoader.loadClass("com.github.lybgeek.user.service.impl.UserServiceImpl"); if(clz != null){ Method method = clz.getMethod("list", User.class); method.invoke(clz.newInstance(),new User()); } }思考二:通过自定义加载器加载过的类如何整合进行spring?
答案: 通过spring提供的扩展点进行ioc容器注入
1、编写bean定义,并注册注册bean定义
@Componentpublic class ServiceBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { Object secretKey = YmlUtils.getValue("lyb-geek.secretKey"); if(ObjectUtils.isEmpty(secretKey)){ throw new RuntimeException("secretKey can not be null,you maybe need to config in application.yml with key lyb-geek.secretKey"); } registerBean(beanFactory,secretKey.toString());// setClassLoader(beanFactory,secretKey.toString()); } /** * 如果项目中引入了>spring-boot-devtools,则默认加载器为org.springframework.boot.devtools.restart.classloader.RestartClassLoader * 此时如果使用自定加载器,则需把bean的类加载器变更为AppClassLoader * @param beanFactory */ private void setClassLoader(ConfigurableListableBeanFactory beanFactory,String secretKey) { CustomClassLoader customClassLoader = new CustomClassLoader(secretKey); beanFactory.setBeanClassLoader(customClassLoader.getParent()); } private void registerBean(ConfigurableListableBeanFactory beanFactory,String secretKey){ DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) beanFactory; BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(UserService.class); GenericBeanDefinition definition = (GenericBeanDefinition) builder.getRawBeanDefinition(); definition.getPropertyValues().add("serviceClz",UserService.class); definition.getPropertyValues().add("serviceImplClzName", "com.github.lybgeek.user.service.impl.UserServiceImpl"); definition.getPropertyValues().add("secretKey", secretKey); definition.setBeanClass(ServiceFactoryBean.class); definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE); String beanId = StringUtils.uncapitalize(UserService.class.getSimpleName()); defaultListableBeanFactory.registerBeanDefinition(beanId, definition); }}2、如果是接口注入,还需通过FactoryBean进行狸猫换太子
@Data@AllArgsConstructor@NoArgsConstructorpublic class ServiceFactoryBeanimplements FactoryBean , ApplicationContextAware, InitializingBean { private ApplicationContext applicationContext; private Class serviceClz; private String serviceImplClzName; private String secretKey; private Object targetObj; @Override public T getObject() throws Exception { return (T) targetObj; } @Override public Class> getObjectType() { return serviceClz; } @Override public void afterPropertiesSet() throws Exception { targetObj = ServiceFactory.create(secretKey,serviceImplClzName,applicationContext); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; }}
3、验证是否整合成功
验证示例代码
@RestController@RequestMapping("/user")public class UserController { @Autowired private UserService userService; @PostMapping(value = "/save") public User save(User user){ User newUser = userService.save(user); return newUser; } }能够正常输出,说明整合成功
到此,相信大家对"怎么使用自定义类加载器防止代码被反编译破解"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
代码
编译
加密
内容
文件
整合
验证
成功
工具
朋友
答案
系统
学习
查询
实用
更深
三个
东西
兴趣
内存
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
黑暗之魂3正版不连接服务器
ro 数据库
嵌入式软件开发和前端
石家庄新世网络技术有限公司
服务器被隔离
征途2服务器列表
网络安全法属性不包括
国外ntp服务器
网络技术开发部门职责
江苏省网络安全答题2019
2020网络安全教育内容
软件开发的文件
软件开发需要拼音打字吗
注册软件开发人员证书
要考英语四六级哪个数据库
长春智能网络技术服务口碑推荐
安卓是用什么数据库文件夹里
数据库支持emoji表情
db2数据库表关键字
ldap导入导出数据库
软件开发 前置审批
统计信息网络安全管理制度
电子商务的网络安全性要素
内蒙古网络安全态势感知
区块链和网络技术的区别
软件开发工具2019年真题
H3C服务器bios修改hdm
信创服务器厂家供应
无线网络安全么
企业高级网络技术综合实验