Loading

squaretest逆向记录

squaretest逆向记录

单测编写在程序开发实践中至关重要,我想每个写过单测的小伙伴都深有感受。但编写单测费时费力,极大影响研发的工作效率。凭借拿来主义精神,我熟练地打开百度并在互联网中搜寻自动化单元测试生成工具,功夫不负有心人,在众多质量参差不齐的单测生成工具中发现了squareTest,使用过感觉相当不错,能够自动生成Mockito测试用例还能兼容多Module工程,但30天的免费试用就让人不开心了,内外网也没对应开心版本,但毕竟java能够轻松反编译,就尝试pj,并记录下

环境:

系统:macos

工具:idea 2021.3;jclasslib

 

问渠那得清如许,为有源头活水。哪个小伙伴不想知道程序验证的原理呢?那我们就尝试反编译程序看看他是怎么加密的。最佳反编译实践可以看我这篇https://www.cnblogs.com/vycz/p/15624996.html

java -cp "/Applications/IntelliJ IDEA.app/Contents/plugins/java-decompiler/lib/java-decompiler.jar" org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler -dgs=true TestStarter-1.6.4.jar.jar mysrc

反编译可以看出其实代码是有混淆的,但不打紧,关键字符串是没混淆的。咱们可以从ui上的提示文案入手。

校验按钮Validate and Save就是咱们的入手点,简单在代码中全局搜索下

在com.squaretest.c.l下这个按钮被引用了。

这里面包含了3个关键方法createActions() doOKAction() doValidate()

大致我们可以知道一个是创建组建的方法,一个是点击ok时的回调,一个是验证方法

通过DialogWrapper我们能知道doValidate是在doOKAction方法内做校验逻辑的,校验成功调用OkActions,失败返回错误提示。

到此咱们主要关心,一个是doValidate中this.a.b(var1)到底做了啥逻辑

第二是doOKAction做了啥

 

咱们看this.a.b(var1)到底在干啥

 absolutely 就是咱们的验密逻辑,返回var6.verify(var7) 就是var6就是a公钥+var5签名消息进行验密,正确返回true,错误返回false。这个咱们先不急先接下里看

既然doValidate已经完成验密工作,那么我们自然而然会想到是不是要缓存许可证书了!毕竟不能每次启动idea都得重新验证吧

咱们可以看到var1被set了,按照业务开发逻辑,只是一个简单的对象set操作,但实际到代码中咱们看看

实际是实现了一个idea提供的持久化存储接口,所以咱们就懂了,在doValidate通过公钥对文本和签名就行核验,核验通过后太多doActions就行证书的持久化仓储!

到目前为止原理咱们都知道的了,常规咱们能想到2种破解方法

第一种是通过java agent对代码就行增强,增强证书校验方法,令其直接返回true。测试发现在idea中通过custom vm进行java agent进行配置后,idea启动直接崩溃了!后来发现可能是idea的一种启动保护措施,防止进行字节码增强。

 

第二种是直接修改字节码,通过修改字节码常量池中的公钥串,实现生产证书。咱们来实验下!

通过反编译代码我们得知,公钥串位于com.squaretest.c包的r对象下

将class文件通过jclasslib打开

咱们轻松找到了公钥的存放地址,现在问题来了,怎么生产公钥和证书呢

先放生成代码

 

KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DSA");

KeyPair keys = keyPairGenerator.generateKeyPair();

PublicKey publicKey = keys.getPublic();




System.out.printf("pub:"+Base64.getEncoder().encodeToString(publicKey.getEncoded()));

PrivateKey privateKey = keys.getPrivate();




System.out.println("\n");

System.out.println("priv:"+Base64.getEncoder().encodeToString(privateKey.getEncoded()));




Signature sig = Signature.getInstance("SHA256withDSA", "SUN");

sig.initSign(privateKey);

String clearText = "SQT1-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n" +

        "SQT1-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n" +

        "SQT1-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n";

sig.update(clearText.getBytes(StandardCharsets.UTF_8));

byte[] signature = sig.sign();

System.out.println("sign:"+Base64.getEncoder().encodeToString(signature));




sig.initVerify(publicKey);

sig.update(clearText.getBytes(StandardCharsets.UTF_8));

boolean verify = sig.verify(signature);

System.out.println("verify:"+verify);

  

 

posted @ 2022-01-17 23:08  摇橙子  阅读(6684)  评论(32编辑  收藏  举报