Charles 4.5.1逆向工程/破解

Charles 4.5.1逆向破解

前两天剁了Burp Pro 2.1.04破解版,今天写写如何破解Charles 4.5.1。该文主要以逆向与软件安全为方向编写(作者scz)。你也可参阅Charles破解版/破解工具找到你想要的。

Charles如果未注册,启动时有个10s倒计时,30天试用期,每运行30分钟就自动退出。

Charles缺省是用其自带JDK 11启动的:

C:\Program Files\Charles\jdk\

1 C : \ Program Files \ Charles \ jdk \

正常注册流程是:

启动Charles->Help->Register Charles->输入Registered Name/License Key

1 启动 Charles -> Help -> Register Charles ->输入 Registered Name / License Key

这里会弹一个对话框,有RegisterCancel两个按钮。如何找到Register按钮对应的代码?假设Register按钮用到了JButton,在按钮上显示"Register"这个字符串时会用到javax.swing.AbstractButton.setText(),查看它的调用栈回溯,或许就能定位Register按钮对应的代码。

javax.swing.AbstractButton.setText()设断,命中时:

[1] javax.swing.AbstractButton.setText (AbstractButton.java:297), pc = 0 [2] javax.swing.AbstractButton.init (AbstractButton.java:2,128), pc = 6 [3] javax.swing.JButton.<init> (JButton.java:131), pc = 18 [4] javax.swing.JButton.<init> (JButton.java:104), pc = 3 [5] com.xk72.charles.gui.frames.RegisterFrame.<init> (null), pc = 45 [6] com.xk72.charles.gui.menus.HelpMenu$4.actionPerformed (null), pc = 8 [7] javax.swing.AbstractButton.fireActionPerformed (AbstractButton.java:1,967), pc = 83

1 2 3 4 5 6 7 [ 1 ] javax . swing . AbstractButton . setText ( AbstractButton . java : 297 ) , pc = 0 [ 2 ] javax . swing . AbstractButton . init ( AbstractButton . java : 2 , 128 ) , pc = 6 [ 3 ] javax . swing . JButton . < init > ( JButton . java : 131 ) , pc = 18 [ 4 ] javax . swing . JButton . < init > ( JButton . java : 104 ) , pc = 3 [ 5 ] com . xk72 . charles . gui . frames . RegisterFrame . < init > ( null ) , pc = 45 [ 6 ] com . xk72 . charles . gui . menus . HelpMenu $ 4.actionPerformed ( null ) , pc = 8 [ 7 ] javax . swing . AbstractButton . fireActionPerformed ( AbstractButton . java : 1 , 967 ) , pc = 83

爽到了,关注"com.xk72.charles.gui.frames.RegisterFrame.class"。

比起Burp Pro 2.1.04Charles 4.5.1的混淆程度太弱,说是一马平川不为过。据说Charles早期版本没有混淆过,比如4.0.2,我以前没接触过。

Charles 4.5.1反编译

C:\Program Files\Charles\lib\charles.jar

1 C : \ Program Files \ Charles \ lib \ charles . jar

com.xk72.charles.gui.frames.RegisterFrame.class

public class RegisterFrame extends JDialog { private final JTextField tName; private final JTextField tSerial; /* * Register按钮 */ private final JButton bRegister; /* * Cancel按钮 */ private final JButton bCancel; public RegisterFrame ( Frame paramFrame ) { super( paramFrame, true ); setTitle( "Register Charles" ); this.tName = new JTextField( 20 ); this.tSerial = new JTextField( 20 ); this.bRegister = new JButton( "Register" ); this.bCancel = new JButton( "Cancel" ); Container localContainer; (localContainer = getContentPane()).setLayout( new MigLayout( "wrap,fill", "[label][fill,grow]" ) ); localContainer.add( new JLabel( "Registered Name:" ) ); localContainer.add( this.tName ); localContainer.add( new JLabel( "License Key:" ) ); localContainer.add( this.tSerial ); localContainer.add( this.bCancel, "tag cancel,split 2,span,center" ); localContainer.add( this.bRegister, "tag ok" ); this.bCancel.addActionListener( new gTDF( this ) ); /* * 在此添加Register按钮的处理代码,据此关注 * * com.xk72.charles.gui.frames.PeRA.class */ this.bRegister.addActionListener( new PeRA( this ) ); pack(); if ( paramFrame != null ) { ( paramFrame = new Point( paramFrame.getLocation() ) ).translate( 20, 20 ); setLocation( paramFrame ); } getRootPane().setDefaultButton( this.bRegister ); getRootPane().getInputMap(1).put( KeyStroke.getKeyStroke( "ESCAPE" ), "escape" ); getRootPane().getActionMap().put( "escape", new RegisterFrame.3( this ) ); }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 public class RegisterFrame extends JDialog {      private final JTextField     tName ;      private final JTextField     tSerial ;      /*      * Register按钮      */      private final JButton       bRegister ;      /*      * Cancel按钮      */      private final JButton       bCancel ;        public RegisterFrame ( Frame paramFrame )      {          super ( paramFrame , true ) ;          setTitle ( "Register Charles" ) ;          this . tName        = new JTextField ( 20 ) ;          this . tSerial      = new JTextField ( 20 ) ;          this . bRegister    = new JButton ( "Register" ) ;          this . bCancel      = new JButton ( "Cancel" ) ;            Container   localContainer ;            ( localContainer = getContentPane ( ) ) . setLayout ( new MigLayout ( "wrap,fill" , "[label][fill,grow]" ) ) ;            localContainer . add ( new JLabel ( "Registered Name:" ) ) ;          localContainer . add ( this . tName ) ;          localContainer . add ( new JLabel ( "License Key:" ) ) ;          localContainer . add ( this . tSerial ) ;          localContainer . add ( this . bCancel , "tag cancel,split 2,span,center" ) ;          localContainer . add ( this . bRegister , "tag ok" ) ;          this . bCancel . addActionListener ( new gTDF ( this ) ) ;          /*          * 在此添加Register按钮的处理代码,据此关注          *          * com.xk72.charles.gui.frames.PeRA.class          */          this . bRegister . addActionListener ( new PeRA ( this ) ) ;          pack ( ) ;          if ( paramFrame != null )          {            ( paramFrame = new Point ( paramFrame . getLocation ( ) ) ) . translate ( 20 , 20 ) ;              setLocation ( paramFrame ) ;          }          getRootPane ( ) . setDefaultButton ( this . bRegister ) ;          getRootPane ( ) . getInputMap ( 1 ) . put ( KeyStroke . getKeyStroke ( "ESCAPE" ) , "escape" ) ;          getRootPane ( ) . getActionMap ( ) . put ( "escape" , new RegisterFrame . 3 ( this ) ) ;      }

com.xk72.charles.gui.frames.PeRA.class

import com.xk72.charles.YQUd; final class PeRA implements ActionListener { PeRA( RegisterFrame paramRegisterFrame ) { } public final void actionPerformed ( ActionEvent paramActionEvent ) { paramActionEvent = RegisterFrame.tEdg( this.tEdg ).getText().trim(); String str = RegisterFrame.TryJ( this.tEdg ).getText().trim(); if ( ( paramActionEvent.length() > 0 ) && ( str.length() > 0 ) ) { Object localObject; /* * 为了注册成功,YQUd.tEdg()必须返回null。据此关注 * * com.xk72.charles.YQUd.class */ if ( ( localObject = YQUd.tEdg( paramActionEvent, str ) ) != null ) { /* * 注册失败 */ ExtendedJOptionPane.tEdg( this.tEdg, localObject, "Charles Registration", 2 ); return; } /* * 注册成功,显示注册信息 */ ExtendedJOptionPane.tEdg( this.tEdg, "Thank you for registering. Charles will now close. Please start Charles again to continue.", "Charles Registration", 1 ); ( localObject = CharlesContext.getInstance() ).getConfiguration().getRegistrationConfiguration().setName( paramActionEvent ); ( ( CharlesContext )localObject ).getConfiguration().getRegistrationConfiguration().setKey( str ); ( ( CharlesContext )localObject ).exit( 0, true ); } } }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 import com . xk72 . charles . YQUd ;   final class PeRA implements ActionListener {      PeRA ( RegisterFrame paramRegisterFrame )      {      }        public final void actionPerformed ( ActionEvent paramActionEvent )      {          paramActionEvent      = RegisterFrame . tEdg ( this . tEdg ) . getText ( ) . trim ( ) ;            String    str = RegisterFrame . TryJ ( this . tEdg ) . getText ( ) . trim ( ) ;            if ( ( paramActionEvent . length ( ) > 0 ) && ( str . length ( ) > 0 ) )          {              Object    localObject ;                /*              * 为了注册成功,YQUd.tEdg()必须返回null。据此关注              *              * com.xk72.charles.YQUd.class              */              if ( ( localObject = YQUd . tEdg ( paramActionEvent , str ) ) != null )              {                  /*                  * 注册失败                  */                  ExtendedJOptionPane . tEdg ( this . tEdg , localObject , "Charles Registration" , 2 ) ;                  return ;              }              /*              * 注册成功,显示注册信息              */              ExtendedJOptionPane . tEdg ( this . tEdg , "Thank you for registering. Charles will now close. Please start Charles again to continue." , "Charles Registration" , 1 ) ;              ( localObject = CharlesContext . getInstance ( ) ) . getConfiguration ( ) . getRegistrationConfiguration ( ) . setName ( paramActionEvent ) ;              ( ( CharlesContext ) localObject ) . getConfiguration ( ) . getRegistrationConfiguration ( ) . setKey ( str ) ;              ( ( CharlesContext ) localObject ) . exit ( 0 , true ) ;          }      } }

YQUd.class共有5个public method:

  1. public com.xk72.charles.YQUd();
  2. public static boolean tEdg();
  3. public static void TryJ();
  4. public static java.lang.String NCuT();
  5. public static java.lang.String tEdg(java.lang.String, java.lang.String);

com.xk72.charles.YQUd.class

public final class YQUd { private static YQUd TryJ; /* * 为true时表示已注册 */ private boolean NCuT; public YQUd () { this.NCuT = false; this.Rarr = "Unregistered"; } /* * 为true时表示已注册 */ public static boolean tEdg () { YQUd var0 = TryJ; return TryJ.NCuT; } public static void TryJ () { TryJ = new YQUd(); } /* * 这是要显示到"About Charles"的内容 */ public static String NCuT () { YQUd var0 = TryJ; switch( gTDF.tEdg[var0.aqrV.ordinal()] ) { case 1: return var0.Rarr; case 2: return var0.Rarr + " - Site License"; case 3: return var0.Rarr + " - Multi-Site License"; default: return var0.Rarr; } } /* * 务必让本函数返回null */ public static String tEdg ( String var0, String var1 ) { YQUd var3; try { var3 = new YQUd( var0, var1 ); } catch ( LicenseException var2 ) { return var2.getMessage(); } TryJ = var3; return null; }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 public final class YQUd {      private static YQUd TryJ ;      /*      * 为true时表示已注册      */      private boolean      NCuT ;        public YQUd ( )      {          this . NCuT    = false ;          this . Rarr    = "Unregistered" ;      }        /*      * 为true时表示已注册      */      public static boolean tEdg ( )      {          YQUd     var0      = TryJ ;            return TryJ . NCuT ;      }        public static void TryJ ( )      {          TryJ      = new YQUd ( ) ;      }        /*      * 这是要显示到"About Charles"的内容      */      public static String NCuT ( )      {          YQUd     var0      = TryJ ;            switch ( gTDF . tEdg [ var0 . aqrV . ordinal ( ) ] )          {          case 1 :              return var0 . Rarr ;          case 2 :              return var0 . Rarr + " - Site License" ;          case 3 :              return var0 . Rarr + " - Multi-Site License" ;          default :              return var0 . Rarr ;          }      }        /*      * 务必让本函数返回null      */      public static String tEdg ( String var0 , String var1 )      {          YQUd     var3 ;            try          {              var3      = new YQUd ( var0 , var1 ) ;          }          catch ( LicenseException var2 )          {              return var2 . getMessage ( ) ;          }          TryJ      = var3 ;          return null ;      }

编辑YQUd.java:

package com.xk72.charles; public final class YQUd { /* * 只Patch这5个public method,其他private的扔掉即可 */ public YQUd () { } /* * 为true时表示已注册 */ public static boolean tEdg () { return( true ); } public static void TryJ () { } /* * 这是要显示到"About Charles"的内容,这个内容任意 */ public static String NCuT () { return "Anyting - Site License"; } /* * 务必让本函数返回null */ public static String tEdg ( String var0, String var1 ) { return null; } }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 package com . xk72 . charles ;   public final class YQUd {      /*      * 只Patch这5个public method,其他private的扔掉即可      */        public YQUd ( )      {      }        /*      * 为true时表示已注册      */      public static boolean tEdg ( )      {          return ( true ) ;      }        public static void TryJ ( )      {      }        /*      * 这是要显示到"About Charles"的内容,这个内容任意      */      public static String NCuT ( )      {          return "Anyting - Site License" ;      }        /*      * 务必让本函数返回null      */      public static String tEdg ( String var0 , String var1 )      {          return null ;      } }

编译YQUd.java得到新的YQUd.class,替换charles.jar中的YQUd.class

比起Burp,破解Charles实在是太简单了。要点是定位YQUd.class,每个版本混淆后的名字都不一样,需要重新定位。由于已经讲清楚原理,以后破解都不需要动态调试设断,直接在反编译器中静态定位。

作者:scz

晓白博客网版权所有,原文地址https://www.xbnb.cn/11699
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享