本篇內(nèi)容主要講解“怎么使用自定義類(lèi)加載器防止代碼被反編譯破解”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“怎么使用自定義類(lèi)加載器防止代碼被反編譯破解”吧!
成都創(chuàng)新互聯(lián)專(zhuān)注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于成都網(wǎng)站制作、網(wǎng)站建設(shè)、桐柏網(wǎng)絡(luò)推廣、小程序開(kāi)發(fā)、桐柏網(wǎng)絡(luò)營(yíng)銷(xiāo)、桐柏企業(yè)策劃、桐柏品牌公關(guān)、搜索引擎seo、人物專(zhuān)訪、企業(yè)宣傳片、企業(yè)代運(yùn)營(yíng)等,從售前售中售后,我們都將竭誠(chéng)為您服務(wù),您的肯定,是我們最大的嘉獎(jiǎng);成都創(chuàng)新互聯(lián)為所有大學(xué)生創(chuàng)業(yè)者提供桐柏建站搭建服務(wù),24小時(shí)服務(wù)熱線:028-86922220,官方網(wǎng)址:muchs.cn
@Slf4j public 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(); } } } } }
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); }
打開(kāi)反編譯工具jd-gui,把加密的代碼拖入jd-gui
打不開(kāi),至少說(shuō)明不能用jd-gui來(lái)反編譯加密過(guò)的代碼。
我們打開(kāi)正常的編譯的class文件,其內(nèi)容形如下 從內(nèi)容我們大概還是能看出一些東西,比如包名啥的。而打開(kāi)加密后的文件,其內(nèi)容如下 內(nèi)容宛若天書(shū)
答案:既然有加密,自然可以通過(guò)解密來(lái)使用。那這個(gè)解密得存放在什么地方進(jìn)行解密?
如果對(duì)類(lèi)加載有一定了解的朋友,就會(huì)知道java的class文件是通過(guò)類(lèi)加載器把class加載入jvm內(nèi)存中,因此我們可以考慮把解密放在類(lèi)加載器中。常用的類(lèi)加載有啟動(dòng)類(lèi)加載器、擴(kuò)展類(lèi)加載器、系統(tǒng)類(lèi)加載。我們正常classpath路徑下的類(lèi)都是通過(guò)系統(tǒng)類(lèi)加載器進(jìn)行加載。而不巧這三個(gè)jdk提供的加載器沒(méi)法滿足我們的需求。因此我們只能自己實(shí)現(xiàn)我們的類(lèi)加載器。其自定義加載器代碼如下
@Slf4j public class CustomClassLoader extends ClassLoader{ /** * 授權(quán)碼 */ 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); //先查詢有沒(méi)有加載過(guò)這個(gè)類(lèi)。如果已經(jīng)加載,則直接返回加載好的類(lèi)。如果沒(méi)有,則加載新的類(lèi)。 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 { //委派給父類(lèi)加載 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(); } } } }
通過(guò)如下方式進(jìn)行調(diào)用
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()); } }
答案:通過(guò)spring提供的擴(kuò)展點(diǎn)進(jìn)行ioc容器注入
1、編寫(xiě)bean定義,并注冊(cè)注冊(cè)bean定義
@Component public 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()); } /** * 如果項(xiàng)目中引入了>spring-boot-devtools,則默認(rèn)加載器為org.springframework.boot.devtools.restart.classloader.RestartClassLoader * 此時(shí)如果使用自定加載器,則需把bean的類(lèi)加載器變更為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、如果是接口注入,還需通過(guò)FactoryBean進(jìn)行貍貓換太子
@Data @AllArgsConstructor @NoArgsConstructor public class ServiceFactoryBean <T> implements FactoryBean<T> , ApplicationContextAware, InitializingBean { private ApplicationContext applicationContext; private Class<T> 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、驗(yàn)證是否整合成功
驗(yàn)證示例代碼
@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; } }
能夠正常輸出,說(shuō)明整合成功
到此,相信大家對(duì)“怎么使用自定義類(lèi)加載器防止代碼被反編譯破解”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
分享標(biāo)題:怎么使用自定義類(lèi)加載器防止代碼被反編譯破解
文章源于:http://muchs.cn/article18/pjjegp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站制作、App開(kāi)發(fā)、營(yíng)銷(xiāo)型網(wǎng)站建設(shè)、微信公眾號(hào)、做網(wǎng)站、商城網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)