声明:仅供Java逆向学习参考!
解决方案
下载参考链接1提供的JEB。在power shell运行.\jeb_wincon.bat
启动JEB。
进入界面后,如果让你提供license key,就运行下文的python代码(可以自行先修改成py3),输入license data,算出license key。
如果patch失败的话,也可以采用替代方案:在提供了license key以后,用RunAsDate软件来运行JEB(可行大概是因为这版本JEB并没有去服务器请求时间?)。
分析
参考链接1提供的JEB下载链接,实际上已经包含了前人的破解成果:动态patch。即修改了jeb_wincon.bat等shell脚本,在运行jeb官方的bin/app/jeb.jar
之前,先运行同一文件夹下的patch.jar
。
所以直接在power shell运行.\jeb_wincon.bat
启动JEB即可实现动态patch。
去看app文件夹,它比原有的多出两个jar,一个是patch.jar
,另一个是它的依赖:javassist.jar
。
patch.jar
反编译出的Java代码,仅供学习参考(两个文件,每个文件一个public class):
package com.patch.jeb;
import java.lang.instrument.Instrumentation;
public class PatchAgent {
public static void premain(String agentArgs, Instrumentation inst) {
inst.addTransformer(new PatchTransformer());
}
}
package com.patch.jeb;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;
public class PatchTransformer implements ClassFileTransformer {
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
if (!className.equals("com/pnfsoftware/jeb/client/Licensing"))
return null;
String clsName = className.replace("/", ".");
CtClass cls = null;
try {
cls = ClassPool.getDefault().get(clsName);
CtMethod mth = cls.getDeclaredMethod("getExpirationTimestamp");
mth.setBody("{return real_license_ts + (864000 * license_validity);}");
System.out.println("patch success++");
return cls.toBytecode();
} catch (NotFoundException|javassist.CannotCompileException|java.io.IOException e) {
e.printStackTrace();
return null;
}
}
}
简单来说,就是运行时修改Licensing.class
的getExpirationTimestamp
方法,让过期时间从1年延长到10年。
但这是建立在已经有license key的基础上的,参考链接1的JEB并不能直接用,它会问你要license key。我们还需要知道JEB求license key的算法。我自己逆向只分析了start方法,没找到license key生成逻辑。但幸好我找到了参考链接2,@xixicoco实现了license key生成的算法(python2.7)。他打包的exe在参考链接3。
import os, sys, struct, time, binascii, hashlib
RC4_Key2= 'Eg\xa2\x99_\x83\xf1\x10'
def rc4(Key, inData):
Buf = ""
S = range(256)
K = (map(lambda x:ord(x), Key) * (256 / len(Key) + 1))[:256]
j = 0
for i in range(256):
j = (S[i] + K[i] + j) % 256
S[i], S[j] = S[j], S[i]
i, j = 0, 0
for x in range(len(inData)):
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
Buf += chr(S[(S[j] + S[i]) % 256] ^ ord(inData[x]))
return Buf
def Long2Int(longdata):
lo = longdata & 0xFFFFFFFF
hi = (longdata >> 32) & 0x7FFFFFFF
return hi, lo
def KeygenSN(LicenseSerial, MachineID):
mhi, mlo = Long2Int(MachineID)
lhi, llo = Long2Int(LicenseSerial)
hi_Key = (mhi - lhi + 0x55667788) & 0x7FFFFFFF
lo_Key = (mlo + llo + 0x11223344) & 0xFFFFFFFF
Z0, = struct.unpack('<Q', struct.pack('<LL', lo_Key, hi_Key))
Z1 = int(time.time()) ^ 0x56739ACD
s = sum(map(lambda x:int(x, 16), "%x" % Z1)) % 10
return "%dZ%d%d" % (Z0, Z1, s)
def ParsePost(buf):
Info = struct.unpack('<3L2Q4LQ3L', buf[:0x40])
flag, CRC, UserSerial, LicenseSerial, MachineID, build_type, \
Ver_Major, Ver_Minor, Ver_Buildid, Ver_Timestamp, \
TimeOffset, Kclass, Random2 = Info
SysInfoData = buf[0x40:]
assert CRC == binascii.crc32(buf[8:]) & 0xFFFFFFFF
return Info, SysInfoData
def DecodeRc4Str(buf):
buf = buf.decode('hex')
i, s = ParsePost(rc4(buf[:8] + RC4_Key2, buf[8:]))
return i, s
def GetJebLicenseKey():
licdata = raw_input("Input License Data:\n")
if licdata:
i, MachineID = DecodeRc4Str(licdata)
SN = KeygenSN(i[3], i[4])
print "JEB License Key:", SN
return SN
GetJebLicenseKey()
raw_input("Enter to Exit...")
以上注册机的exe逆向(py2.7逆向)
这里我们将参考链接3的exe逆向出来,看看是不是和上面的一样。
python pyinstxtractor.py <filename>
生成一个文件夹,找到里面的jebKeygen.pyc
。已知以上的代码是py2.7,但我们查看文件头可发现magic number不是03 f3 0d 0a
(py2.7的magic number)。并且直接运行反编译命令会失败。
那就把magic number改一下,再试试
uncompyle6 -o jebKeygen.py jebKeygen.pyc
成功。代码与上面基本一致。
参考
- https://cuiqingcai.com/31082.html
- https://www.52pojie.cn/thread-1191557-1-1.html
- JEBKeyGen的exe:https://www.52pojie.cn/thread-1192412-1-1.html