GalaxyPilot —— D.S


                  生命不熄,戰(zhàn)斗不止
          數(shù)據(jù)加載中……

          淺談JAVA程序破解

          淺談JAVA程序破解

          作者:舵手
          申明:如轉(zhuǎn)載請(qǐng)保證文章的完整性以及出處

          ????最近對(duì)JAVA程序的破解比較感興趣,拿幾個(gè)行業(yè)軟件練了一下手,略有心得,拿出來(lái)與菜鳥(niǎo)分享!注意只是一點(diǎn)心得,
          本文并不涉及具體軟件的破解。初學(xué)破解,失誤之處在所難免,敬請(qǐng)高手賜教!
          ????直接進(jìn)入正題,對(duì)JAVA的破可從下面幾方面入手:

          一、反編譯
          ????工具很多,建意用GUI工具,命令行下的JAD很容易因?yàn)椴荒芊淳幾g某一個(gè)方法或某一行代碼而終止整個(gè)文件的反
          編譯,但GUI的工具卻能搞定,雖然反編譯后部分代碼較難看懂,但總比看jvm指命要好得多。而且,GUI的工具多數(shù)有
          批量反編譯功能,且能讓反編譯的文件直接以.java為后綴保存,也是方便之處。
          二、方法調(diào)用
          ????安全意識(shí)強(qiáng)的開(kāi)發(fā)者會(huì)把他的程序進(jìn)行高質(zhì)量的混淆,下面就是一個(gè)例子
          public?static?Object?getRemoteEJBHome(String?OOOoOo00oO0O0O0ooOoOO,?Class?OO0oOO0O0o0oO0o00oOoO)
          throws?NamingException
          {
          try
          {
          ????if(OoO0o0o0O0oo0oO00oOO0?==?null)
          ??OoO0o0o0O0oo0oO00oOO0?=?OoOOoOOO0Oo0OO0OooO0o();
          ????Object?OOOOOo00000OoOoO0O000?=?PortableRemoteObject.narrow(OoO0o0o0O0oo0oO00oOO0.lookup(OOOoOo00oO0O0O0ooOoOO),?OO0oOO0O0o0oO0o00oOoO);
          ????Object?obj?=?OOOOOo00000OoOoO0O000;
          ????return?obj;
          }
          catch(NamingException?OO0Ooo0oOO0OO0OOOoOo0)
          {
          ????System.out.println(OO0Ooo0oOO0OO0OOOoOo0.getMessage());
          ????throw?OO0Ooo0oOO0OO0OOOoOo0;
          }
          }
          這是我見(jiàn)過(guò)的最好的混淆效果,變量都是由大小寫(xiě)的O和數(shù)字零組程,要看懂這樣的程序基本上是不可能的,可能有
          人會(huì)想到用有意義的變量進(jìn)行替換,當(dāng)然這也是一個(gè)方法,但如果應(yīng)用所包括的class文件數(shù)以千記,那這個(gè)工作量
          是相當(dāng)大的。B/S結(jié)構(gòu)的授權(quán)方式一般都是文件的形式,當(dāng)然,肯定是經(jīng)過(guò)加密的。像下面的license就是經(jīng)過(guò)了RSA
          非對(duì)稱加密算法,要分析license的構(gòu)成,有明文的license就更方便了,而公鑰是直接被寫(xiě)在class文件中的
          24D568B6A27AEFD683BC7A1CC93D11D074FB6B982A4B6E269712773BE536B40A67F1D345654F659C66D4265F5CE8FE0494B3A
          F33A8299A4F6B0E7500275A27EFF3B6D2E4983F14A9EA38A1AE3394B28A9C6D6924C15027F9B689FD9A3A689A301C4D4EB878
          D75C207F68BAA352F550D8F19876FFA255864FDE8A7E5939202E9F
          那么我們可以用eclipse建一個(gè)JAVA項(xiàng)目,把應(yīng)用的jar加入該項(xiàng)目的庫(kù)搜索路徑,寫(xiě)一個(gè)自己的類調(diào)用解密方法,得到
          明文license再分析。當(dāng)然,也可以調(diào)用其它一些方法,從調(diào)用參數(shù)和最后的返回值我們也可大概猜對(duì)該方法的作用,
          對(duì)付象上面經(jīng)過(guò)高質(zhì)量混淆的代碼也比較管用。當(dāng)然,我這里只是簡(jiǎn)單的舉兩個(gè)例子,其實(shí)“方法調(diào)用”的妙用還很多,
          自己慢慢琢磨吧!
          三、為class添加代碼
          ????反編譯多數(shù)情況下也只能讓我們看看作者的思路,如果想把反編譯出來(lái)的代碼經(jīng)過(guò)修改后再編譯成class,通常
          是行不通了。而且有時(shí)候必須讓程序運(yùn)行在它本身的環(huán)境才能行,否則一些類無(wú)法得到正確的初始化,“方法調(diào)用”
          也就起不了什么作用。搞過(guò)java的人一定知道javassist,這個(gè)庫(kù)提供了足夠多的方法讓你直接修改class文件,而不
          需要你了解字節(jié)碼的相關(guān)知識(shí),我們可以利用這個(gè)庫(kù)解決上述的問(wèn)題。下面是我寫(xiě)的一個(gè)修改字節(jié)碼的類,目前還不
          完善,真正要用時(shí)可能需要根據(jù)情況做一些修改。
          import?java.lang.reflect.*;
          import?javassist.*;
          import?java.io.*;
          /**
          ?*?<p>Title:?JAVA?字節(jié)碼修改類</p>
          ?*?<p>Description:?得到類的相關(guān)信息或修改該類</p>
          ?*?<p>Copyright:?Copyright?()?2005</p>
          ?*?@author?舵手
          ?*?@version?1.0
          ?*/
          public?class?ModifyClass?{
          ??private?static?int?call_method;
          ??private?static?String?_class;
          ??private?static?ClassPool?pool;
          ??private?static?CtClass?cc;
          ??private?static?String[]?clas;
          ??/**
          ???*?修改字節(jié)碼中的方法
          ???*?@param?clas[0]?待修改類的方法名
          ???*?@param?clas[1]?修改位置定義
          ???*?@param?clas[2]?使用insertAt方法插放代碼時(shí)行號(hào)參數(shù)
          ???*?@param?clas[3]?修改內(nèi)容
          ???*?@return
          ???*/
          ????private?static?void?modifyMethod()
          ????{
          ????String?_method;
          ????_method?=?clas[0];
          ????????try
          ????????{
          ??????CtClass[]?param?=?new?CtClass[4]?;????????????????
          ??????//param[0]?=?pool.get("");
          ??????//param[1]?=?pool.get("");
          ??????//param[2]?=?pool.get("java.lang.String");
          ??????//param[3]?=?pool.get("java.lang.String");

          ??????CtMethod?cm?=?cc.getDeclaredMethod(_method);
          ??????if?(clas[1].toLowerCase().equals("a"))
          ??????{
          ????????//方法的尾部加入代碼
          ????????cm.insertAfter(clas[3]);
          ??????}
          ??????if?(clas[1].toLowerCase().equals("b"))
          ??????{
          ????????//方法的首部加入代碼
          ????????cm.insertBefore(clas[3]);
          ??????}
          ??????if?(clas[1].toLowerCase().equals("i"))
          ??????{
          ????????System.out.println(cm.insertAt((Integer.valueOf(clas[2]).intValue()),clas[3]));
          ??????}
          ??????cc.writeFile();
          ????????}
          ????????catch(Exception?e)
          ????????{
          ????????????e.printStackTrace();
          ????????}

          ????}
          ??/**
          ???*?在類中增加方法
          ???*?@param?clas[0]?源方法名稱
          ???*?@param?clas[1]?新方法名稱
          ???*?@param?clas[2]?增加類型
          ???*?@param?clas[3]?方法內(nèi)容
          ???*?@return
          ???*/
          ??private?static?void?addMethod()
          ????{
          ????String?_oldmethod;
          ????String?_newmethod;
          ????_oldmethod?=?clas[0];
          ????_newmethod?=?clas[1];
          ????????try
          ????????{
          ??????StringBuffer?newMethodBody?=?new?StringBuffer();
          ????????????if?(clas[2].toLowerCase().equals("c"))
          ????????????{
          ????????//add?new?Method?(copy)
          ????????CtMethod?oldMethod?=?cc.getDeclaredMethod(_oldmethod);
          ????????CtMethod?newMethod?=?CtNewMethod.copy(oldMethod,?_newmethod,?cc,?null);
          ????????newMethodBody.append(clas[3]);
          ????????newMethod.setBody(newMethodBody.toString());
          ????????cc.addMethod(newMethod);
          ????????????}
          ??????if?(clas[2].toLowerCase().equals("r"))
          ??????{
          ????????//add?new?Method?(create)
          ????????CtMethod?newMethod?=?CtNewMethod.make(clas[3],?cc);
          ????????cc.addMethod(newMethod);
          ??????}
          ??????cc.writeFile();

          ????????}
          ????????catch(Exception?e)
          ????????{
          ????????????e.printStackTrace();
          ????????}

          ????}

          ??private?static?void?getMethods(){
          ????CtMethod[]?cms?=?cc.getDeclaredMethods();
          ????System.out.println();
          ????System.out.println(cc.getName()+"?類的所有方法:");
          ????for?(int?i=0?;?i<cms.length?;?i++?)
          ????{
          ??????System.out.println(cms[i].getName());
          ????}
          ??}

          ??private?static?void?getFields(){
          ????CtField[]?cfs?=?cc.getDeclaredFields();
          ????System.out.println();
          ????System.out.println(cc.getName()+"?類的所有屬性:");
          ????for?(int?i=0?;?i<cfs.length?;?i++?)
          ????{
          ??????System.out.println(cfs[i].getName());
          ????}
          ??}
          ??
          ??private?static?void?delMethod(){
          ????try{
          ??????CtMethod?cm?=?cc.getDeclaredMethod(clas[0]);
          ??????cc.removeMethod(cm);
          ????}catch(Exception?e){
          ??????e.printStackTrace();
          ????}
          ??}
          ????public?static?void?main(String[]?args)?{
          ????StringBuffer?buf?=?new?StringBuffer(500);
          ????int?c;
          ????System.out.print("請(qǐng)輸入操作類名:");
          ????try{
          ??????while?((c?=?System.in.read())?!=?13)?{

          ????????buf.append((char)c);
          ??????}
          ??????_class?=?buf.toString();
          ??????pool?=?ClassPool.getDefault();
          ??????cc?=?pool.get(_class);
          ??????buf.delete(0,buf.length());
          ??????System.out.println("***********************************************************");
          ??????System.out.println("可供調(diào)用的方法有:");
          ??????System.out.println("1-modifyMethod,2-addMethod,3-getMethods,4-getFields,5-removeMethod");
          ??????System.out.println("***********************************************************");
          ??????System.out.print("請(qǐng)選擇調(diào)用方法:");
          ??????while?((c?=?System.in.read())?!=?13)?{
          ????????if?(c?==?10)
          ??????????continue;
          ????????buf.append((char)c);
          ??????}
          ??????call_method?=?Integer.parseInt(buf.toString());
          ??????if?(call_method?==?1)
          ??????{
          ????????System.out.println("***********************************************************");
          ????????System.out.println("調(diào)用?modifyMethod?方法參數(shù):");
          ????????System.out.println("方法名稱,插入位置,行號(hào),內(nèi)容");
          ????????System.out.println("***********************************************************");
          ????????buf.delete(0,buf.length());
          ????????while?((c?=?System.in.read())?!=?13)?{
          ??????????if?(c?==?10)
          ????????????continue;
          ??????????buf.append((char)c);
          ????????}
          ????????clas?=?(buf.toString()).split(",");
          ????????modifyMethod();
          ??????}
          ??????buf.delete(0,buf.length());
          ??????if?(call_method?==?2)
          ??????{
          ????????System.out.println("***********************************************************");
          ????????System.out.println("調(diào)用?addMethod?方法參數(shù):");
          ????????System.out.println("源方法,目標(biāo)方法,建立方式,內(nèi)容");
          ????????System.out.println("***********************************************************");
          ????????buf.delete(0,buf.length());
          ????????while?((c?=?System.in.read())?!=?13)?{
          ??????????if?(c?==?10)
          ????????????continue;
          ??????????buf.append((char)c);
          ????????}
          ????????clas?=?(buf.toString()).split(",");
          ????????addMethod();
          ??????}
          ??????if?(call_method?==?3)
          ??????{
          ????????getMethods();
          ??????}
          ??????if?(call_method?==?4)
          ??????{
          ????????getFields();
          ??????}
          ??????if?(call_method?==?5)
          ??????{
          ????????System.out.println("***********************************************************");
          ????????System.out.println("調(diào)用?removeMethod?方法參數(shù):");
          ????????System.out.println("方法名稱");
          ????????System.out.println("***********************************************************");
          ????????buf.delete(0,buf.length());
          ????????while?((c?=?System.in.read())?!=?13)?{
          ??????????if?(c?==?10)
          ????????????continue;
          ??????????buf.append((char)c);
          ????????}
          ????????clas?=?(buf.toString()).split(",");
          ????????delMethod();
          ??????}

          ????}catch(IOException?ioe)
          ????{
          ??????System.out.println();
          ??????ioe.printStackTrace();
          ??????System.exit(0);
          ????}
          ????catch(NotFoundException?nfe)
          ????{
          ??????System.out.println();
          ??????nfe.printStackTrace();
          ??????System.exit(0);
          ????}
          ????catch(NumberFormatException?nfe)
          ????{
          ??????System.out.println();
          ??????nfe.printStackTrace();
          ??????System.exit(0);
          ????}
          ????}
          }

          ????modifyMethod方法用來(lái)在類的指定方法中插入一行或多行代碼,參數(shù)為a時(shí)表示插在方法現(xiàn)有代碼的最后面,為b時(shí)
          表示插在方法現(xiàn)有代碼的最前面,為i時(shí)表時(shí)插在代碼的指定行的前面,這個(gè)行和原代碼中的行沒(méi)有關(guān)系,插入位置
          要插入一次才能確定,為i時(shí)返回的值代表實(shí)際插入位置,由這個(gè)實(shí)際插入位置你可以計(jì)算i的值。在實(shí)際破解中發(fā)現(xiàn),
          用該方法插入一些代碼后,會(huì)使原來(lái)反編譯的不可讀的代碼變的容易讀懂,當(dāng)然,也有可能使本來(lái)可讀性很強(qiáng)的代碼,
          因?yàn)槟悴迦肓艘恍┱Z(yǔ)句而變得不可讀。我常常在關(guān)鍵方法的代碼中插入一些?System.out.println();這樣的代碼來(lái)跟蹤
          程序,還有一點(diǎn)限制,你不能直接用打印輸出的方法來(lái)輸出方法體內(nèi)的局部變量,但你可以對(duì)全局變量進(jìn)行引用操作。
          如果要操作局部變量,目前我所知的方法只能在該類里重建該方法,如果那位有其它的好辦法,也請(qǐng)指點(diǎn)我一下。
          ????addMethod方法在是類中增加一個(gè)新的方法,增加的方式有兩種,這里就不做具體介紹。
          ????其它方法也就不一一解釋了,有興趣的朋友可以研究一下javassist,相信你會(huì)寫(xiě)出功能更強(qiáng)大的修改class文件的類庫(kù)。
          四、class的修改
          ????在破解過(guò)程中經(jīng)常會(huì)看到rsa非對(duì)稱加密算法,公鑰往往以十六進(jìn)制存放在class文件中,(當(dāng)然,也有對(duì)公鑰加密后存
          放在配置文件中的程序)以便解密已經(jīng)加密過(guò)的信息。前不久破解的一個(gè)J2EE的開(kāi)發(fā)平臺(tái)就是這樣的,license用RSA加密,
          在搞懂了它的算法后,自己構(gòu)件license明文,自己再生成一對(duì)rsa的公私密鑰,用自己的私鑰對(duì)license文明進(jìn)行RSA加密,
          再用十六進(jìn)制編輯器替換程序中所有的公鑰,(當(dāng)然是用你的公鑰替換他的公鑰,不然也沒(méi)法解密)一切就搞定。當(dāng)然,
          我所說(shuō)的只是一個(gè)方面,有時(shí)暴破時(shí)可能還得用到一些JVM的指命,比如你想讓一個(gè)?return?false?的方法?return?ture
          那你就得把相應(yīng)位置的03?AC改為04?AC,位置怎么確定就不用我說(shuō)了吧!
          五、讀JVM指令
          ????沒(méi)有什么可以多說(shuō)的,如果要從jvm指令看懂成程,必須像熟匯編一樣熟悉jvm指令集,還得有一個(gè)工具把class翻譯成
          jvm指令代碼,總不能用十六進(jìn)制編輯器讀代碼嗎?如果真是,那你就太牛了。我這里介紹?bcel?這個(gè)工具,它可以把class
          解釋為jvm指令集并存為html文件,結(jié)果就像下面:
          0??getstatic????????????System.out?Ljava/io/PrintStream;?
          3??ldc??????????????????"is?one"?
          5??invokevirtual????????java.io.PrintStream.println?(Ljava/lang/String;)V(String):void?
          8??getstatic?????????????System.out?Ljava/io/PrintStream;?
          11??ldc??????????????????"is?two"?
          13??invokevirtual????????java.io.PrintStream.println?(Ljava/lang/String;)V(String):void?
          16??getstatic?????????????System.out?Ljava/io/PrintStream;?
          19??ldc??????????????????"is?three"?
          21??invokevirtual????????java.io.PrintStream.println?(Ljava/lang/String;)V(String):void?
          24??getstatic?????????????System.out?Ljava/io/PrintStream;?
          27??ldc??????????????????"is?four"?
          29??invokevirtual????????java.io.PrintStream.println?(Ljava/lang/String;)V(String):void?
          32??return?
          ????這是一個(gè)方法的全部指令,熟悉jvm指令集的話就已經(jīng)能讀懂它在做什么了

          ????發(fā)現(xiàn)有關(guān)JAVA程序破解的文章不是很多,所以本人粗淺的談?wù)摿艘幌翵AVA程序破解時(shí)所用到的一些方法,當(dāng)然,還有很多
          憑經(jīng)驗(yàn)才能找到的靈感,無(wú)法一一列舉,本文質(zhì)在拋磚引玉,望高手能寫(xiě)一些技術(shù)含量更高的文章供我們這些菜鳥(niǎo)學(xué)習(xí)。

          posted on 2006-04-19 10:54 舵手 閱讀(29021) 評(píng)論(4)  編輯  收藏

          評(píng)論

          # re: 淺談JAVA程序破解  回復(fù)  更多評(píng)論   

          多謝指點(diǎn),這篇文章寫(xiě)于剛接觸破解之時(shí),所以部分方法沒(méi)有寫(xiě)到。后來(lái)本打算完善,可人一天比一天變的懶惰,所以就擱置在這里了。
          窮舉私鑰我到?jīng)]有試過(guò),總覺(jué)得太過(guò)渺茫,一般我都是替換公鑰。
          2007-10-19 11:54 | 舵手 QQ:8117892

          # re: 淺談JAVA程序破解  回復(fù)  更多評(píng)論   

          public static Object getRemoteEJBHome(String OOOoOo00oO0O0O0ooOoOO, Class OO0oOO0O0o0oO0o00oOoO)
          throws NamingException
          {

          請(qǐng)問(wèn)這種把包名和變量名稱都替換為OO0oOO0O0o0oO0o00oOoO是使用了什么混淆工具?
          2008-11-10 13:58 | 單飛

          # re: 淺談JAVA程序破解  回復(fù)  更多評(píng)論   

          很崇拜作者

          最近拿到一個(gè)Toefl TPO軟件,Java的,但是Jar被exe4j打包成exe了,運(yùn)行的時(shí)候也不在Temp目錄解壓jar包,不知道該怎么弄了,求助樓主,能否解出Jar或者直接破解

          email:silenceleaf@gmail.com
          2012-09-04 11:11 | silenceleaf

          # re: 淺談JAVA程序破解  回復(fù)  更多評(píng)論   

          我得機(jī)器碼:-bqkfsduaojcgo77nocot13cgjo9d62u0

          不勝感激~
          2012-09-04 11:13 | silenceleaf

          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。

          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 海林市| 买车| 博爱县| 威宁| 惠安县| 任丘市| 阿拉善左旗| 会理县| 图片| 深水埗区| 克东县| 嘉善县| 敦化市| 黑水县| 海丰县| 尉氏县| 通化县| 吴忠市| 什邡市| 伊春市| 青海省| 阳西县| 承德市| 简阳市| 姜堰市| 日土县| 德安县| 镇雄县| 大庆市| 麻城市| 玛沁县| 定远县| 新津县| 镇坪县| 大同县| 米易县| 井研县| 江安县| 南乐县| 枞阳县| 乌拉特中旗|