Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to use a custom class loader to prevent code from being decompiled

2025-02-27 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article focuses on "how to use a custom class loader to prevent code from being decompiled and cracked". Interested friends may wish to take a look. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn how to use custom class loaders to prevent code from being decompiled.

Code anti-compilation overall routine 1, write encryption tool class @ 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 () Encrypt 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. Decompilation verification of encrypted code

Open the decompiler jd-gui and drag the encrypted code into jd-gui

Can not be opened, at least it means that jd-gui can not be used to decompile encrypted code.

We open the normal compiled class file, and its content looks like this. We can probably see something from the content, such as the package name. And open the encrypted file, its content is as follows, just like the book of heaven.

Ponder one: if the code is encrypted, how does jvm identify it?

Answer: since there is encryption, it can be used through decryption. So where does this decryption have to be stored for decryption?

If you have some knowledge of class loading, you will know that java's class file loads class into jvm memory through a class loader, so we can consider putting decryption in the class loader. Commonly used classes are loaded with startup class loaders, extended class loaders, and system class loaders. The classes under our normal classpath path are loaded through the system class loader. Unfortunately, the loaders provided by these three jdk can not meet our needs. So we have to implement our classloader ourselves. The custom loader code is as follows

@ Slf4jpublic class CustomClassLoader extends ClassLoader {/ * authorization code * / private String secretKey; private String SECRETKEY_PREFIX = "lyb-geek"; / * root directory of the class file * / 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); / / query whether this class has been loaded first. If it is already loaded, the loaded class is returned directly. If not, the new class is loaded. 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, 0classData.length);} return clz } private Class getaClass (String name, Class clz, ClassLoader parent) {try {/ / delegate the parent class to load 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; / / decrypt 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 (isometric null) {is.close ();}} catch (IOException e) {log.error ("encrypt fail:" + e.getMessage (), e) } try {if (basics null) {bas.close ();}} catch (IOException e) {e.printStackTrace ();}

Call is made as follows

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 ()) }} thinking 2: how to integrate classes loaded by custom loaders for spring?

Answer: ioc container injection through extension points provided by spring

1. Write the bean definition and register the bean definition

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 ()) } / * if > spring-boot-devtools is introduced into the project, the default loader is org.springframework.boot.devtools.restart.classloader.RestartClassLoader * if you use a custom loader, you need to change the bean classloader to 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. If it is an interface injection, you still need to change the crown prince through the FactoryBean.

Data@AllArgsConstructor@NoArgsConstructorpublic class ServiceFactoryBean implements 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. Verify whether the integration is successful

Verify the sample code

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

It can output normally, which means the integration is successful.

At this point, I believe you have a deeper understanding of "how to use a custom class loader to prevent code from being decompiled". You might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report