怎么使用自定義類(lèi)加載器防止代碼被反編譯破解

本篇內(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

代碼防編譯整體套路

1、編寫(xiě)加密工具類(lèi)

@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();
                }
            }
        }

    }

}

2、對(duì)需要防止被反編譯代碼加密

 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、對(duì)加密代碼進(jìn)行反編譯驗(yàn)證

打開(kāi)反編譯工具jd-gui,把加密的代碼拖入jd-gui

怎么使用自定義類(lèi)加載器防止代碼被反編譯破解 打不開(kāi),至少說(shuō)明不能用jd-gui來(lái)反編譯加密過(guò)的代碼。

我們打開(kāi)正常的編譯的class文件,其內(nèi)容形如下 怎么使用自定義類(lèi)加載器防止代碼被反編譯破解 從內(nèi)容我們大概還是能看出一些東西,比如包名啥的。而打開(kāi)加密后的文件,其內(nèi)容如下 怎么使用自定義類(lèi)加載器防止代碼被反編譯破解 內(nèi)容宛若天書(shū)

思考一:代碼都被加密了,那jvm如何識(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ò)自定義加載器加載過(guò)的類(lèi)如何整合進(jìn)行spring?

答案:通過(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;
    }
    }

怎么使用自定義類(lèi)加載器防止代碼被反編譯破解 能夠正常輸出,說(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)

成都網(wǎng)站建設(shè)