官网下载地址:Aspose Repository Browser /repo/com/aspose/aspose-slides/22.5/
一、分析
1、官方验证部分为:
InputStream is = new FileInputStream("license.xml");
License license = new License();
license.setLicense(is);
以下为一个过期的证书:license.xml
<License>
<Data>
<Products>
<Product>Aspose.Total for Java</Product>
<Product>Aspose.Words for Java</Product>
</Products>
<EditionType>Enterprise</EditionType>
<SubscriptionExpiry>20991231</SubscriptionExpiry>
<LicenseExpiry>20991231</LicenseExpiry>
<SerialNumber>8bfe198c-7f0c-4ef8-8ff0-acc3237bf0d7</SerialNumber>
</Data>
<Signature>
sNLLKGMUdF0r8O1kKilWAGdgfs2BvJb/2Xp8p5iuDVfZXmhppo+d0Ran1P9TKdjV4ABwAgKXxJ3jcQTqE/2IRfqwnPf8itN8aFZlV3TJPYeD3yWE7IT55Gz6EijUpC7aKeoohTb4w2fpox58wWoF3SNp6sK6jDfiAUGEHYJ9pjU=
</Signature>
</License>
2、分析License类的setLicense方法找到关键代码
使用jd-gui反编译jar包,搜索 License
分析setLicense
方法,设置许可证,完成许可的验证,有2个一个是文件路径,一个是io流,但是最终都是走的io流那个方法。
public final void setLicense(InputStream stream) throws AsposeLicenseException {
try {
ByteArrayInputStream byteArrayInputStream = null;
if (stream != null) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] arrayOfByte = new byte[1024];
int i;
while ((i = stream.read(arrayOfByte)) > 0)
byteArrayOutputStream.write(arrayOfByte, 0, i);
byteArrayOutputStream.flush();
byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
}
return return = new return();
return.do(byteArrayInputStream);
} catch (IOException iOException) {
throw new InvalidOperationException("License stream is not available for reading");
}
}
return return = new return();
return.do(byteArrayInputStream);
在 com.aspose.slides.internal.oh 包下
public final void do(InputStream paramInputStream) {
if (paramInputStream != null) {
if(paramInputStream);
for(this.for);
for(this.do);
do(this.int);
if(this.new);
try = this;
public.do(try);
} else {
try = null;
public.do(try);
}
}
定位到RSA验证签名,签名错误抛出异常。把这个方法体清空不抛异常就可以了。
private static void do(Node paramNode1, Node paramNode2, String[] paramArrayOfString) {
try {
String str1 = (paramNode1 != null) ? do(paramNode1) : "";
byte[] arrayOfByte1 = str1.getBytes("UTF-16LE");
String str2 = (paramNode2 != null) ? paramNode2.getFirstChild().getNodeValue() : "";
byte[] arrayOfByte2 = try.do(str2);
PublicKey publicKey = null;
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPublicKeySpec rSAPublicKeySpec = this.do(if(paramArrayOfString), arrayOfByte2);
publicKey = keyFactory.generatePublic(rSAPublicKeySpec);
} catch (Exception exception) {
(new final() {
}).do((new boolean() {
}, ).if, exception);
}
if (arrayOfByte2.length == 128) {
Signature signature = Signature.getInstance("SHA1withRSA");
signature.initVerify(publicKey);
signature.update(arrayOfByte1);
do(signature, arrayOfByte2);
} else {
try {
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initVerify(publicKey);
signature.update(arrayOfByte1);
do(signature, arrayOfByte2);
} catch (InvalidOperationException invalidOperationException) {
try {
String str3;
if (if(paramArrayOfString)) {
str3 = long.if(arrayOfByte2);
} else {
str3 = long.do(arrayOfByte2);
}
String str4 = "AQAB";
byte[] arrayOfByte3 = try.do(str3);
byte[] arrayOfByte4 = try.do(str4);
if (!instanceof.do(arrayOfByte1, arrayOfByte2, arrayOfByte3, arrayOfByte4))
(new final() {
}).do((new boolean() {
}, ).int, (Exception)invalidOperationException);
} catch (Exception exception) {
(new final() {
}).do((new boolean() {
}, ).int, (Exception)invalidOperationException);
}
}
}
} catch (Exception exception) {
(new final() {
}).do((new boolean() {
}, ).int, exception);
}
}
3、分析结果
清空方法 void do(Node paramNode1, Node paramNode2, String[] paramArrayOfString)
private static void do(Node paramNode1, Node paramNode2, String[] paramArrayOfString) {
}
二、修改方式
1、添加Javassist修改class字节码文件
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.29.0-GA</version>
</dependency>
2、修改方法
package test;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
public class Demo6 {
public static void main(String[] args) {
try {
ClassPool pool = ClassPool.getDefault();
//取得需要反编译的jar文件,设定路径
pool.insertClassPath("F:/aspose-slides-22.5-jdk16.jar");
CtClass ctClass = pool.get("com.aspose.slides.internal.oh.return");
CtMethod[] methods = ctClass.getDeclaredMethods("do");
for (CtMethod method : methods) {
CtClass[] ps = method.getParameterTypes();
//参数个数为3个
if (ps.length == 3 && method.getName().equals("do")) {
method.setBody("{}");//重新设置方法体的内容
}
}
ctClass.writeFile("F:/");
} catch (Exception e) {
e.printStackTrace();
}
}
}
3、替换class文件
重命名 aspose-slides-22.5-jdk16.jar 为 aspose-slides-22.5-jdk16.jar.zip 解压
MANIFEST.MF只保留以下部分
Manifest-Version: 1.0
Application-Name: Aspose.Slides for Java
Implementation-Title: Aspose.Slides for Java
Copyright: Copyright 2004-2022 Aspose Pty Ltd
Bundle-SymbolicName: com.aspose.slides
Implementation-Version: 22.5
Release-Date: 2022.05.31
Specification-Vendor: Aspose Pty Ltd
Bundle-ManifestVersion: 2
Specification-Title: Aspose.Slides for Java
Bundle-Vendor: Aspose Pty Ltd
Application-Library-Allowable-Codebase: *
Import-Package: javax.xml.parsers;resolution:=optional,javax.imageio;r
esolution:=optional,org.xml.sax;resolution:=optional
Implementation-Vendor: Aspose Pty Ltd
Ant-Version: Apache Ant 1.9.7
Export-Package: com.aspose.slides;version=22.5,com.aspose.slides.Colle
ctions;version=22.5,com.aspose.slides.exceptions;version=22.5
Bundle-Version: 22.5
Bundle-Name: Aspose.Slides for Java
Caller-Allowable-Codebase: *
Permissions: all-permissions
Created-By: 1.8.0_162-b12 (Oracle Corporation)
Specification-Version: 22.5
替换class文件:直接将生成的com文件夹覆盖到解压包的com文件夹
将压缩成的zip重新命名为jar包