本帖最后由 2316361 于 2020-2-27 13:17 编辑
请问一下论坛里面研究FR的大神,有没有发现这款软件有什么暗装呢?发出来一起交流一下呗。
前些天看了论坛一位大神的帖子https://www.52pojie.cn/thread-1012601-1-1.html,试着弄了一下,真的被FR10的加密给弄崩溃了
于是想到了一个新思路,是否可以在它加载完关键类之后,从jvm里面取出字节码修改后再替换回去呢?
分享一下我的思路吧
启动FR,使用HSDB工具拿到三个类:
1、com.fr.license.selector.EncryptedLicenseSelector
2、com.fr.license.security.LicFileRegistry
3、com.fr.license.entity.FineLicense
需要修改以下几个关键的地方:
1、com.fr.license.selector.EncryptedLicenseSelector的decrypt方法:
[Java] 纯文本查看 复制代码 public abstract class EncryptedLicenseSelector extends AbstractLicenseSelector {
byte[] getBytes() {
byte[] var1 = this.readRawBytes();
return this.decrypt(var1);
}
private byte[] decrypt(byte[] var1) { // 修改为 return var1;
try {
System.getProperties().setProperty("com.ibm.crypto.provider.DoRSATypeChecking", "false");
return (new CommonDecryptChain()).decrypt(var1);
} catch (Throwable var3) {
this.decryptFailed(var3);
return new byte[0];
}
}
protected void decryptFailed(Throwable var1) {
FineLoggerFactory.getLogger().error("Read license failed." + var1.getMessage(), var1);
}
abstract byte[] readRawBytes();
}
其实修改这一个地方就够了,另外两处修改可用于方便懒人。
2、com.fr.license.security.LicFileRegistry的check方法:
[Java] 纯文本查看 复制代码 public class LicFileRegistry {
private static Map<Integer, LicFileChecker> _2c75dfba_fdee_47fa_8cf4_74897f6d7e9a = new ConcurrentHashMap(5);
private LicFileRegistry() {
}
static {
register(new LicFileCheckerImpl());
}
public static void register(LicFileChecker var0) {
_2c75dfba_fdee_47fa_8cf4_74897f6d7e9a.put(var0.getTypeCode(), var0);
}
public static boolean check(InputStream var0, Integer var1) { // 修改为 return true;
LicFileChecker var2 = _2c75dfba_fdee_47fa_8cf4_74897f6d7e9a.get(var1);
return var2 != null && var2.check(var0);
}
}
修改这里主要是破解lic上传注册。
3、com.fr.license.entity.FineLicense的两个support方法:
[Java] 纯文本查看 复制代码 public class FineLicense extends AbstractLicense {
public FineLicense(JSONObject var1) {
super(var1);
}
public String getString(String var1, String var2) {
return super.getInnerString(var1, var2);
}
public boolean support(PluginMarker var1) { // 修改为 return true;
if (var1 == null) {
return false;
} else {
try {
JSONObject var2 = this.getJSONObject();
if (var2.has(LicenseItem.Plugin.getKey())) {
JSONArray var3 = var2.getJSONArray(LicenseItem.Plugin.getKey());
for(int var5 = 0; var5 < var3.length(); ++var5) {
String[] var4 = var3.getString(var5).split(",");
if (var4.length >= 2 && var1.getPluginID().equals(var4[0])) {
return true;
}
}
}
} catch (Exception var6) {
FineLoggerFactory.getLogger().error(var6.getMessage(), var6);
}
return false;
}
}
public boolean support(FunctionPoint var1) { // 修改为 return true;
String var2 = this.getString(LicenseItem.Function.getKey(), "");
if (StringUtils.isNotBlank(var2)) {
BigInteger var3 = new BigInteger(String.valueOf(var2));
return var3.and(BigInteger.ONE.shiftLeft(var1.getMarker())).compareTo(BigInteger.ZERO) == 1;
} else {
return true;
}
}
主要用于破解收费插件。
修改之后的代码可自行编译为class字节码,使用javaagent替换,不过不推荐。因为每次小更新部分类的成员变量名都会随机变化,使得破解失效,
因此建议拿到加载后的字节码自行进行修改并使用javaagent替换,以第一个关键类为例,代码如下:
[Java] 纯文本查看 复制代码 public class FxxxAgent {
public static void agentmain(String args, Instrumentation inst) throws Exception {
Class<?>[] classes = inst.getAllLoadedClasses();
for (Class<?> clazz : classes) {
if (clazz.getName().equals("com.fr.license.selector.EncryptedLicenseSelector")) {
inst.addTransformer((loader, className, classBeingRedefined, protectionDomain, classfileBuffer) -> {
if (className.equals("com/fr/license/selector/EncryptedLicenseSelector")) {
try {
DataInputStream inputStream = new DataInputStream(new ByteArrayInputStream(classfileBuffer));
ClassFile classFile = new ClassFile(inputStream);
inputStream.close();
ConstPool constPool = classFile.getConstPool();
MethodInfo methodInfo = classFile.getMethod("decrypt");
CodeAttribute codeAttribute = new CodeAttribute(constPool, 1, 2, new byte[]{43, -80},
new ExceptionTable(constPool));
methodInfo.setCodeAttribute(codeAttribute);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
DataOutputStream outputStream = new DataOutputStream(byteArrayOutputStream);
classFile.write(outputStream);
outputStream.close();
byte[] result = byteArrayOutputStream.toByteArray();
byteArrayOutputStream.close();
return result;
} catch (Exception e) {
e.printStackTrace();
return classfileBuffer;
}
} else {
return classfileBuffer;
}
});
inst.retransformClasses(clazz);
}
}
}
}
在manifest.sf文件中加上一行:Agent-Class: 刚刚编辑的类名,打包成jar文件备用。
为了使这些代码可以运行起来,需要找个地方写上一些自己的代码,我找的是fine-core-10.0.jar下的com.fr.runtime.FineRuntime这个类,
在initEncryptedBridge方法的最下面加上了自己的代码:
[Java] 纯文本查看 复制代码 private static void initEncryptedBridge() throws Exception {
ClassLoader var0 = (ClassLoader) Class.forName(START_LOADER_FACTORY_NAME).newInstance();
Class.forName("com.fr.plugin.bridge.FinePluginBridge", true, var0);
String name = ManagementFactory.getRuntimeMXBean().getName();
String pid = name.substring(0, name.indexOf('@'));
VirtualMachine virtualMachine = VirtualMachine.attach(pid);
virtualMachine.loadAgent("D:/agent.jar", null); // 这里的路径即为刚刚打的jar包路径
virtualMachine.detach();
}
用winrar打开fr-core-10.0.jar,将编译好的FineRuntime.class替换,或者单独打成jar包,保证文件名能排在fr-core-10.0.jar的前面,放在WEB-INF\lib目录里
用如下内容的注册文件注册即可
[XML] 纯文本查看 复制代码 {"VERSION":"10.0","DEADLINE":"253402271999000","CONCURRENCY":"0"}
最后把自己的代码分享给大家吧。
https://github.com/2316361/FineCrack |