能力值:
( LV2,RANK:10 )
|
-
-
26 楼
nevinhappy
你这个是还原的,还是自己写的?
还原的,premain里这样调用就可以了 //第二个参数一定要设置为true
inst.addTransformer(new IdeaTransformer(),true);
try {//addTransformer第二个参数设置为true时生效
inst.retransformClasses(new Class[]{Class.forName("java.lang.String")});
inst.retransformClasses(new Class[]{Class.forName("java.util.Timer")});
inst.retransformClasses(new Class[]{Class.forName("java.util.Base64")});
inst.retransformClasses(new Class[]{Class.forName("java.io.ByteArrayInputStream")});
inst.retransformClasses(new Class[]{Class.forName("java.util.Arrays")});
inst.retransformClasses(new Class[]{Class.forName("java.net.URL")});
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
|
能力值:
( LV2,RANK:10 )
|
-
-
27 楼
nevinhappy
你这个是还原的,还是自己写的?
还原的,premain里这样调用就可以了 //第二个参数一定要设置为true
inst.addTransformer(new IdeaTransformer(),true);
try {//addTransformer第二个参数设置为true时生效
inst.retransformClasses(new Class[]{Class.forName("java.lang.String")});
inst.retransformClasses(new Class[]{Class.forName("java.util.Timer")});
inst.retransformClasses(new Class[]{Class.forName("java.util.Base64")});
inst.retransformClasses(new Class[]{Class.forName("java.io.ByteArrayInputStream")});
inst.retransformClasses(new Class[]{Class.forName("java.util.Arrays")});
inst.retransformClasses(new Class[]{Class.forName("java.net.URL")});
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
|
能力值:
( LV2,RANK:10 )
|
-
-
28 楼
以为没回复成功,没想到在第二页,怎么删除回复。
最后于 2021-4-26 16:37
被guduzhe编辑
,原因:
|
能力值:
( LV9,RANK:181 )
|
-
-
29 楼
guduzhe
还原的,premain里这样调用就可以了//第二个参数一定要设置为true
inst.addTransformer(new IdeaTransformer(),true);
...
怎么还原?我是通过DUMP出来的补丁,自己写出来的。内容和还原的一样。
|
能力值:
( LV2,RANK:10 )
|
-
-
30 楼
nevinhappy
怎么还原?我是通过DUMP出来的补丁,自己写出来的。内容和还原的一样。 ZKM的INVOKEDYNAMIC指令都是一样,比如下面这条
INVOKEDYNAMIC Y (JJ)Z handle[H_INVOKESTATIC fuck_you/b1.a(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;] args[]
INVOKEDYNAMIC后面的Y,都是通过计算来区分调用类型的,比如Field是静态的getter和setter方法还是动态,Method是findVirtual、findStatic还是findSpecial,这些用处不大。
只需要关注这个dynamic指令解析类,这里是fuck_you/b1,找类的(JJ)Ljava/lang/reflect/Field;和(JJ)Ljava/lang/reflect/Method;这两个方法就行,注入输出就可以,根据long数值搜索实际做了什么操作。
java代理参数没有限制,我们在其他代理类之前执行就可以了。
如果有人能解出这些long数值的计算方法,估计就不用输出,直接还原正常代码了。
最后于 2021-4-26 17:36
被guduzhe编辑
,原因:
|
能力值:
( LV9,RANK:181 )
|
-
-
31 楼
guduzhe
nevinhappy
怎么还原?我是通过DUMP出来的补丁,自己写出来的。内容和还原的一样。 ZKM的INVOKEDYNAMIC指令都是一样,比 ...
对这两句没有太理解,有没有啥具体的内容。 ··· 只需要关注这个dynamic指令解析类,这里是fuck_you/b1,找类的(JJ)Ljava/lang/reflect/Field;和(JJ)Ljava/lang/reflect/Method;这两个方法就行,注入输出就可以,根据long数值搜索实际做了什么操作。 ···
|
能力值:
( LV2,RANK:10 )
|
-
-
32 楼
nevinhappy
对这两句没有太理解,有没有啥具体的内容。
···
只需要关注这个dynamic指令解析类,这里是fuck_you/b1,找类的(JJ)Ljava/lang/reflect/Field;和(JJ)L ...
拦截结果 -3802705931672136433:95462646008613:public abstract void java.lang.instrument.Instrumentation.addTransformer(java.lang.instrument.ClassFileTransformer,boolean)
8923367779079012573:73296439639028:public static boolean fuck_you.ao.b
8925782691333146343:73296439639028:public boolean java.lang.String.equals(java.lang.Object)
8925782691333146343:73296439639028:public boolean java.lang.String.equals(java.lang.Object)
8925782691333146343:73296439639028:public boolean java.lang.String.equals(java.lang.Object)
用recaf看字节码就行了,比如这两个long,实际只能看到第一个long,第二个是xor得到的,这个无关紧要,因为一个方法内第二个long都是一致的 8923367779079012573:73296439639028:public static boolean fuck_you.ao.b
这样的局限就是只能显示这个方法内运行流程中调用的方法,没有用到的可以自己修改,比如zkm 15.0,自己改的 public static String a(String mark, long var4, long var6) {
int type = mark.charAt(0) ^ ((int) var6) & 7;
String rtn;
if (type == 106 || type == 107 || type == 105 || type == 109) {//105:i 106:j 107:k 109:m
Field field = aae.c(var4, var6);
if (type == 106) {
rtn = "findGetter";
} else if (type == 107) {
rtn = "findSetter";
} else if (type == 105) {
rtn = "findStaticGetter";
} else {
rtn = "findStaticSetter";
}
rtn = rtn + ":" + field.toString();
} else {
Method method = aae.d(var4, var6);
if (type == 110) {
rtn = "findVirtual";
} else if (type == 113) {
rtn = "findStatic";
} else {
rtn = "findSpecial";
}
rtn = rtn + ":" + method.toString();
}
return rtn;
}
mark就是INVOKEDYNAMIC后面跟的字符,后面两个long就是拦截到的,因为第二个long通用,所以方法内的所有都能解析出来。我一般在arthas里用 ognl '@com.zelix.tool.Tool@a("l",-4720786595021763945L,140189597281954L)'
|
能力值:
( LV9,RANK:181 )
|
-
-
33 楼
guduzhe
拦截结果-3802705931672136433:95462646008613:public abstract void java.lang.in ... 我使用的工具的还原结果如下图,我试着理解一下你的过程,就是通过上面插入指令的输出内容,再通过agent向bv.a()中插入代码,在调用的时候输出具体的调用函数信息对吧 ? 另外,从你的还原结果和源码结构比较接近,对流程和这些打印信息怎么生成那个反混淆结果 ?根据内容整理的还是说能还原出来指令再反编译的 ?
最后于 2021-4-28 16:08
被nevinhappy编辑
,原因:
|
能力值:
( LV2,RANK:10 )
|
-
-
34 楼
nevinhappy
guduzhe
拦截结果-3802705931672136433:95462646008613:public abstract& ...
根据这个值
查拦截的结果 -3802705931672136433:95462646008613:public abstract void java.lang.instrument.Instrumentation.addTransformer(java.lang.instrument.ClassFileTransformer,boolean)
8923367779079012573:73296439639028:public static boolean fuck_you.ao.b
8925782691333146343:73296439639028:public boolean java.lang.String.equals(java.lang.Object)
8925782691333146343:73296439639028:public boolean java.lang.String.equals(java.lang.Object)
8925782691333146343:73296439639028:public boolean java.lang.String.equals(java.lang.Object) 这不就直接知道运行什么方法,做了什么操作了么。这是最简单最笨,同样很繁琐的,每行代码都要去看。
既然知道方法了,这样可以通过recaf来还原指令,用recaf修改都是手工的。
现在尝试用asm去修改java字节码,用程序修改会快很多,现在大体有构想了,还只是能打印单个方法中的字符串,以后慢慢去完善。
下一步就可以修改指令,将这几行字节码用LDC指令替换就可以了。
这个是修改invokedynamic的方法获取字符串,然后再考虑去修invokedynamic调用的方法。
一步步来,现在只能单个方法,但是能省去许多手工执行命令的步骤。
静态分析太难,一些动态的可以交给arthas去做,动静结合,效果会好点。
|
能力值:
( LV2,RANK:10 )
|
-
-
35 楼
guduzhe
nevinhappy
同步更新一个: 现在的破解失效,原来就是密钥被取消了,/etc/hosts屏蔽掉这个地址就可以了127.0.0.1& ...
谢谢分享。
|
能力值:
( LV2,RANK:10 )
|
-
-
36 楼
rover12421的特殊字符给去掉了,可以研究了,应该没有修改坏了jar文件。
最后于 2021-5-1 21:38
被guduzhe编辑
,原因: 去掉jar包里的签名验证
|
能力值:
( LV2,RANK:10 )
|
-
-
37 楼
idea的证书验证有官方代码 4. Add marketplace license verification calls to the plugin code—JetBrains Marketplace 或者
JetBrains/marketplace-makemecoffee-plugin (github.com)
key结构里面也有,减号分割的四部分,第一部分位id,第二部分就是BASE64编码的字符串,也就是证书内容,第三部分是签名,第四部分是证书。 String[] licenseParts = key.split("-");
if (licenseParts.length != 4) {
return false; // invalid format
}
final String licenseId = licenseParts[0];
final String licensePartBase64 = licenseParts[1];
final String signatureBase64 = licenseParts[2];
final String certBase64 = licenseParts[3]; 前两部分随便改,只要可以替换签名和证书就行了,可以自己生成证书进行签名,然后替换掉agent代码中的证书就可以了。至于agent中java/util/Arrays两个比较,分别为Certificate.getEncoded()和Certificate.getPublicKey().getEncoded()的结果经特定算法计算而来的,然后与那两个变量比较,这两个比较的值是硬编码写在idea.jar中的,只不过不是BASE64格式,二是16进制字符串,加密过的,直接搜索不到的。
给一个修改过的agent和key。
D02JT2S8T0-eyJsaWNlbnNlSWQiOiJEMDJKVDJTOFQwIiwibGljZW5zZWVOYW1lIjoi5Lit5Zu954mb6YC8IiwiYXNzaWduZWVOYW1lIjoiIiwiYXNzaWduZWVFbWFpbCI6IiIsImxpY2Vuc2VSZXN0cmljdGlvbiI6IiIsImNoZWNrQ29uY3VycmVudFVzZSI6ZmFsc2UsInByb2R1Y3RzIjpbeyJjb2RlIjoiSUkiLCJwYWlkVXBUbyI6IjIwOTktMTItMzEiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IkFDIiwicGFpZFVwVG8iOiIyMDk5LTEyLTMxIiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJEUE4iLCJwYWlkVXBUbyI6IjIwOTktMTItMzEiLCJleHRlbmRlZCI6dHJ1ZX0seyJjb2RlIjoiUlNDIiwicGFpZFVwVG8iOiIyMDk5LTEyLTMxIiwiZXh0ZW5kZWQiOnRydWV9LHsiY29kZSI6IlBTIiwicGFpZFVwVG8iOiIyMDk5LTEyLTMxIiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJSU0YiLCJwYWlkVXBUbyI6IjIwOTktMTItMzEiLCJleHRlbmRlZCI6dHJ1ZX0seyJjb2RlIjoiR08iLCJwYWlkVXBUbyI6IjIwOTktMTItMzEiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IkRNIiwicGFpZFVwVG8iOiIyMDk5LTEyLTMxIiwiZXh0ZW5kZWQiOnRydWV9LHsiY29kZSI6IkNMIiwicGFpZFVwVG8iOiIyMDk5LTEyLTMxIiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJSUzAiLCJwYWlkVXBUbyI6IjIwOTktMTItMzEiLCJleHRlbmRlZCI6dHJ1ZX0seyJjb2RlIjoiUkMiLCJwYWlkVXBUbyI6IjIwOTktMTItMzEiLCJleHRlbmRlZCI6dHJ1ZX0seyJjb2RlIjoiUkQiLCJwYWlkVXBUbyI6IjIwOTktMTItMzEiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IlBDIiwicGFpZFVwVG8iOiIyMDk5LTEyLTMxIiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJSU1YiLCJwYWlkVXBUbyI6IjIwOTktMTItMzEiLCJleHRlbmRlZCI6dHJ1ZX0seyJjb2RlIjoiUlNVIiwicGFpZFVwVG8iOiIyMDk5LTEyLTMxIiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJSTSIsInBhaWRVcFRvIjoiMjA5OS0xMi0zMSIsImV4dGVuZGVkIjpmYWxzZX0seyJjb2RlIjoiV1MiLCJwYWlkVXBUbyI6IjIwOTktMTItMzEiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IkRCIiwicGFpZFVwVG8iOiIyMDk5LTEyLTMxIiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJEQyIsInBhaWRVcFRvIjoiMjA5OS0xMi0zMSIsImV4dGVuZGVkIjp0cnVlfSx7ImNvZGUiOiJQREIiLCJwYWlkVXBUbyI6IjIwOTktMTItMzEiLCJleHRlbmRlZCI6dHJ1ZX0seyJjb2RlIjoiUFdTIiwicGFpZFVwVG8iOiIyMDk5LTEyLTMxIiwiZXh0ZW5kZWQiOnRydWV9LHsiY29kZSI6IlBHTyIsInBhaWRVcFRvIjoiMjA5OS0xMi0zMSIsImV4dGVuZGVkIjp0cnVlfSx7ImNvZGUiOiJQUFMiLCJwYWlkVXBUbyI6IjIwOTktMTItMzEiLCJleHRlbmRlZCI6dHJ1ZX0seyJjb2RlIjoiUFBDIiwicGFpZFVwVG8iOiIyMDk5LTEyLTMxIiwiZXh0ZW5kZWQiOnRydWV9LHsiY29kZSI6IlBSQiIsInBhaWRVcFRvIjoiMjA5OS0xMi0zMSIsImV4dGVuZGVkIjp0cnVlfSx7ImNvZGUiOiJQU1ciLCJwYWlkVXBUbyI6IjIwOTktMTItMzEiLCJleHRlbmRlZCI6dHJ1ZX0seyJjb2RlIjoiRFAiLCJwYWlkVXBUbyI6IjIwOTktMTItMzEiLCJleHRlbmRlZCI6dHJ1ZX0seyJjb2RlIjoiUlMiLCJwYWlkVXBUbyI6IjIwOTktMTItMzEiLCJleHRlbmRlZCI6dHJ1ZX1dLCJtZXRhZGF0YSI6IjAxMjAyMDA3MjhFUEpBMDA4MDA2IiwiaGFzaCI6IjE1MDIxMzU0LzA6LTEyNTExMTQ3MTciLCJncmFjZVBlcmlvZERheXMiOjAsImF1dG9Qcm9sb25nYXRlZCI6ZmFsc2UsImlzQXV0b1Byb2xvbmdhdGVkIjpmYWxzZX0=-GM19H3TS7ztsQa4n/tzRGnDU3fN2hGC17Zp6Y4l4Lbw4C9YEnby7Xa6sx3mwBOB2wKKhYOxSe/AWfL0og8SlpeD7VjfNfbcVQJsaV12uTHsXnZtCa4HybZq48lcSKHlm4yeewSErSssrDYdw4Zfxgdf37RlV0qznGHW3SJBX+6gegkkgrpUQYOmv3Pxv/H7Hwhp4Gabe9UuGa5wfl1WWyHSMe43WveXhptZE6unDWItCM+ZHZbKyWhV0NBjlQ8nFt2Q7UdIRZgsbqzWxYBViJunDjQGEfyAiQg//9Okm8y0bCuUdjk/He5/ay6N+msQHFkjMxrQhhxiEqIzTddJemg==-MIIDpDCCAoygAwIBAgIBCTANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1KZXRQcm9maWxlIENBMCAXDTE4MTEwMTEyMjA0NloYDzIwOTkwODA5MDIyNjA3WjBoMQswCQYDVQQGEwJDWjEOMAwGA1UECAwFTnVzbGUxDzANBgNVBAcMBlByYWd1ZTEZMBcGA1UECgwQSmV0QnJhaW5zIHMuci5vLjEdMBsGA1UEAwwUcHJvZDN5LWZyb20tMjAxODExMDEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC8zN/3v/FJOYmWXm9NZ9C8kbfji3AC4m6gI6LtF4yneuCT3zPv8XbC083t9LnfMLEnhnkQMJATSaRbbrWhSDtdUrwE00EBc7DTBn9Fhm7VbCX0XRL9hEaHUtyjRCJ1ajtuPg+/BmGF0ecul/rcT3EcXwrMSiRCKjgaRnrUbtYBca1cBqG3iibG6XotwCJo26FaDbMXbkolemRGzYKcMt8QM9qVN8uIftDbmls1KLv92MKfliVJvztyUUF2v6Jz4FiyO97C9gl31wSfkSBoQ6bgWy4mU2wvqHTQW9C0PX23W3dAOmBpFaSQNi3+JArWMVnzyVrmpweZPxBHlQIb9GkDAgMBAAGjgaYwgaMwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQUYSkb2hkZx8swY0GRjtKAeIwaBNwwSAYDVR0jBEEwP4AUo562SGdCEjZBvW3gubSgUouX8bOhHKQaMBgxFjAUBgNVBAMMDUpldFByb2ZpbGUgQ0GCCQDSbLGDsoN54TAJBgNVHRMEAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQCpNbQatJpW3LhNNgu84cuP5jhcMeLqaUmC49Ng3dZd8cSvKnUSGV1TDj0SsR0tbyzdUgDQfscWzt1uqXyJ/5XYJZgUWL8WAU10Wx+ZRgLf8mH9h4/UkNFMu3CeG0TIvhvJ7HPyEgOdS709Za3hqjoER+er8H6t+xyIPp1gfTroUFbvDLgPtRADf/lxDTyv9HqTMW5Pc3hlDvf3veJCPrQP4pfC49zH8dSVSYewVZocER6mTQ3uV9s967XdvoGnGxZOoQimGsHjwwQtJ8CwxeEf2YK+ssYrag7GvDqYk1+GvAbq3oPFLgmhaPBMg8f3rqofbnSQBP/q1gXUrVZB4dqT
最后于 2021-5-14 15:14
被guduzhe编辑
,原因:
|
能力值:
( LV1,RANK:0 )
|
-
-
38 楼
卧槽,各位神仙打架
|
能力值:
( LV1,RANK:0 )
|
-
-
39 楼
大佬,请教一下,这段话中的【至于agent中java/util/Arrays两个比较,分别为Certificate.getEncoded()和Certificate.getPublicKey().getEncoded()的结果经特定算法计算而来的,然后与那两个变量比较】两个变量是什么东西呀?是idea官方内置的字符串吗?
|
能力值:
( LV2,RANK:10 )
|
-
-
40 楼
sf_dream
大佬,请教一下,这段话中的【至于agent中java/util/Arrays两个比较,分别为Certificate.getEncoded()和Certificate.getPublicKey().ge ...
是的,在idea.jar中,用于验证key中证书是不是伪造的。
|
能力值:
( LV1,RANK:0 )
|
-
-
41 楼
guduzhe
是的,在idea.jar中,用于验证key中证书是不是伪造的。
哦,那他既然写死了,肯定是有一定的计算规则生成的这个字符串,我们利用自己生成的证书去比对,能成功吗?特定的算法是什么算法,这块儿能再解惑一下吗,我感觉是不是进入思维误区了
|
能力值:
( LV1,RANK:0 )
|
-
-
42 楼
sf_dream
哦,那他既然写死了,肯定是有一定的计算规则生成的这个字符串,我们利用自己生成的证书去比对,能成功吗?特定的算法是什么算法,这块儿能再解惑一下吗,我感觉是不是进入思维误区了[em_78]
https://github.com/alphazero/Blake2b
|
能力值:
( LV1,RANK:0 )
|
-
-
43 楼
|
能力值:
( LV1,RANK:0 )
|
-
-
44 楼
我怎么感觉像是在看天书呀
|
能力值:
( LV1,RANK:0 )
|
-
-
45 楼
努力吧
我怎么感觉像是在看天书呀[em_12]
刚开始都这样,可以看看《加密与解密》
|
能力值:
( LV2,RANK:10 )
|
-
-
46 楼
|
能力值:
( LV1,RANK:0 )
|
-
-
47 楼
貌似最新的2021.3.2已经修改了license的验证方式,都不管用了
|
能力值:
( LV2,RANK:10 )
|
-
-
48 楼
wcttt
貌似最新的2021.3.2已经修改了license的验证方式,都不管用了
嗯,datagrip有3.2的,不行了,idea还没出新版的
|
能力值:
( LV1,RANK:0 )
|
-
-
49 楼
guduzhe
嗯,datagrip有3.2的,不行了,idea还没出新版的 试着分析了下原因是licenseData里的metadata参数计算不符合原jar中的判断导致的 用网站的key计算出的结果是J,直接修改字节码 成功,但是却依赖于网站的key,自定义的key,验证license的cert方法还有点摸不到头 版本对应的是LATEST-EAP-SNAPSHOT和datagrip2021.3.2应该是一致的
最后于 2021-12-20 19:18
被wcttt编辑
,原因:
|
能力值:
( LV2,RANK:10 )
|
-
-
50 楼
wcttt
guduzhe
嗯,datagrip有3.2的,不行了,idea还没出新版的 试着分析了下原因是licenseData里的metadata参数计 ... 确实,首先证书替换没有限制,和以前一样,只是修改了对证书的验证方式,不用java.util.Arrays.equals()方法了,再就是你的说的metadata验证。
最后于 2021-12-20 20:41
被guduzhe编辑
,原因:
|
|
|