标题: 浅析旧版burp-loader-keygen.jar 创建: 2019-09-27 15:17 更新: 2019-10-15 17:42 链接: https://scz.617.cn/misc/201909271517.txt 在"吾爱破解"上看到两个贴子: -------------------------------------------------------------------------- 1.7.37版 https://www.52pojie.cn/thread-691448-1-1.html 2.0.11版 https://www.52pojie.cn/thread-909706-1-1.html -------------------------------------------------------------------------- 注册机是surferxyz提供的。按Hmily当时的说法,通杀1.6.x到最新的1.7.31版本。 后来实际通杀到2.0.11beta。 burp-loader-keygen.jar没有混淆,另有一个版本的破解方案使用了混淆。在网上看 到过很多人质疑后者的可靠性,我没有逆向分析过后者,此处不评价。前者提供了非 常清晰的Burp注册算法。Burp的注册界面会面对三组数据: License ActivationRequest ActivationResponse 这三组数据的原始内容均经过DES加密,再以BASE64编码后的形式出现在GUI中。 用户输入License,Burp反馈ActivationRequest,注册机根据ActivationRequest生 成ActivationResponse,用户将ActivationResponse输入到Burp中完成激活。 正常情况下License由Burp的销售提供给购买过Burp的用户,用户在打开Burp时根据 提示输入License,得到ActivationRequest,用户去Burp的网站在线激活,得到网站 反馈的ActivationResponse。注册机则自己提供License、ActivationResponse。 随便用什么反编译器都成,重点看burp-loader-keygen.jar这几个函数: -------------------------------------------------------------------------- /* * enjoy.reversing.me.KeygenDialog.class */ private String generateLicense ( String licenseName ) { String[] licenseArray = { getRandomString(), "license", licenseName, String.valueOf(new Date().getTime() + 315569521000L), "1", "full", "tdq...=" }; return( prepareArray( licenseArray ) ); } /* end of generateLicense */ -------------------------------------------------------------------------- private String generateActivation ( String activationRequest ) { ArrayList request = decodeActivationRequest( activationRequest ); String[] responseArray = { "0.4315672535134567", (String)request.get(0), "activation", (String)request.get(1), "True", "", (String)request.get(2), (String)request.get(3), "xMo...==", "tdq...=" }; return( prepareArray( responseArray ) ); } /* end of generateActivation */ -------------------------------------------------------------------------- licenseName由用户提供,activationRequest来自手工注册GUI的反馈。 prepareArray()对数据进行DES加密、BASE64编码,得到GUI可接受的形式。 decodeActivationRequest()对数据进行BASE64解码、DES解密,还原出原始字节流。 注册机最NB的地方是给了一个DES密钥,"burpr0x!"。我不知道作者是怎么得到这个 字符串的。为了对抗逆向工程,Burp注册算法中没有使用原始的字符串形式的key, 而是使用所谓的"working key",后者是原始key经标准算法打散后得到的。已知 "working key"能否逆推出原始key?对这块不熟。假设不能逆推,还可以暴力穷举原 始key,也可能早期版本Burp中用的就是原始key。 315569521000大约10年: 86400L * 365 * 10 * 1000 = 315360000000 它产生的License有效期从当前时间开始往后推10年。License数据中真正有用的就是 过期时间,注册用户名没有参与太多License检查,主要供GUI显示。 "0.4315672535134567"这个字符串也挺神密,不知注册机作者从哪儿得到这个字符串 的。一个合理猜测,其来自某个曾经有效的官方反馈的ActivationResponse。不过, 这个字符串没有真正参与ActivationResponse检查,可以指定任意内容。 "tdq...="实际是一个SHA1签名。由于没有私钥(n1,d1),注册机根本不可能生成有效 SHA1签名,作者在这里填写了一个固定值的BASE64编码。 "xMo...=="是另一个SHA256签名。由于没有私钥(n2,d2),注册机根本不可能生成有 效SHA256签名,作者在这里填写了另一个固定值的BASE64编码。 为了让几次签名校验得以通过,作者修改了java.math.BigInteger.compareTo(): -------------------------------------------------------------------------- /* * java.math.BigInteger.class */ public int compareTo ( BigInteger paramBigInteger ) { /* * 插了两个判断,如果是这两种特殊情况,直接返回0,表示相等 */ if ( paramBigInteger.toString().equals( "4188...3311" ) ) { return( 0 ); } if ( paramBigInteger.toString().startsWith( "21397203..." ) ) { return( 0 ); } /* * 后面是原来的代码 */ ... } /* end of compareTo */ -------------------------------------------------------------------------- 这两个神密常数是怎么来的呢? $ echo "tdq...=" | openssl enc -base64 -d | xxd -p b5dabdf50048dc3b67410eeb4492d1d2e01d3974faf5251f001ffc3b6ce2 d25b24e3f6d790ce7c4cfe9cba13b3798cab55426b335d48b09856aeff12 8a89b327faea95e765c7e3f51b90773311557e330bf71433d287198b737e edd1cc8dff7f8cfb853bb2a619fc2359d53822d5d21c59dea8605c7020c7 132e1b8572ae42b0 第一个冒充SHA1签名的大数是: 0xb5da...42b0 $ echo "xMo...==" | openssl enc -base64 -d | xxd -p c4ca18c5f7b0249de3c3f66baa086ad67307248b1912d64bbbd929e0f670 fa41adfb0893b6852351f1f24edfe5b91dc18f35548f646ddad4f1576ae3 59cb95ecc970b1b16b2cea93546aacb48600d69b123ffbaca45924845c21 322d0224d4477717bec4f6275ce6f38bfc7a1b87b4c07de26796e760f45f 9fb207895d53573b2542eaff291e49f011bc08ddc1f57692f3e1c9f741e7 e2ccbcd5f5b4358465356f26e64e2b30337008bbc3ce9d7510dfffc31604 76bb8d2aab7112fbfa55eb2214e83bd7563a83ff4d7fdd42e5d15e74d121 3efda4d9f61be2b27ecf59823814a6588ce31a54b5af6c4ecc84ebaeb324 afe8a5044dd514f3db112e0ab1187f7f 第二个冒充SHA256签名的大数是: 0xc4ca...7f7f Burp注册算法用到了两个n,其10进制表示是: 124738629534480032973221216538446528303324575633925115212696 965608841776943873720505095613202508269959066436906898784998 205530829923162983974106352433716894871489982902326093509712 908876797725225107031946484660556100953152081279303345068843 665216479965336584403210268895718334124563877785956530028295 178054013 256600133821860245539953074083061376234010696292251325913730 541735939262744869444096229430403147720416901320125583118101 690775982374754361221732599973882657089503516296619181313410 228383254653134971381522064709109598749411231306391705035437 297291329436622494650835329738285386410790720166489986976007 428005347428123900789430657659107646463559624960580751927179 906313493474918631338297878280702462242181604216792605178804 793399621095615619560452824650602235680723932855891201813746 556106842518013072204269802452536295152268446724173176619016 801263188695944423188364177107490393919973214507379413156323 53785580197447661 这两个n都用了同一个e(65537)。 在Python里执行: c1=0xb5da...42b0 e1=65537 n1=124738...4013 "%#u" % pow(c1,e1,n1) c2=0xc4ca...7f7f e2=65537 n2=256600...7661 "%#u" % pow(c2,e2,n2) 得到: 418870575296708924170996751849888235621894460719313465903734 013863821870107577767895302611076422414817655735643993720266 355314342776897138930772383421401886975998155182859851739869 949245292483305624380260193706915584017084402692025504542781 921071321079632420245983234848465783753053248333932900984779 15413311 213972034722530999335196412559543368118258976898713185369940 465712371134996632886263381434125677646742086061713229019757 005370433285159396406175868873406983189438362032661312533943 859396482716759853105705292996897150201903972333402485518241 156996465309073171519772337003336004239658552080787136102129 787344012722184627391350213331938460773961160272659684759343 807618539354358269270488041459323584037468818914392308879650 327514456368763127833917109019458359387710436044034909991482 074841024492089747495034053025831565100991974744944295164151 247515859705194835299957928005322357232810608702799367406249 20742282695855232 这就是compareTo()中神密常量的来龙去脉。 License和ActivationResponse中用两个常量冒充RSA签名,修改compareTo(),一旦 发现在检查这两个c的pow(c,e,n)值,就返回0,表示相等。至于compareTo()中用 equals()还是startsWith(),无关紧要,随便。某种意义上相当于替换了两组n。 为了让这个针对compareTo()的修改生效,注册机提供的方案是: java -Xbootclasspath/p:burp-loader-keygen.jar -jar burpsuite_pro_.jar "-Xbootclasspath/p:"将修改过的BigInteger.class置于缺省引导类搜索路径之前, 简单点说,先到的生效,后到的吃灰。据说Java 9不支持这个用法了,那就八仙过海 各想他招吧。 2019-10-15 17:42 后续进展如下: 《新版burp-loader-keygen-2.jar》 https://scz.617.cn/misc/201910151519.txt