吾愛破解 - LCG - LSG |安卓破解|病毒分析|破解軟件|www.kvamco.live

 找回密碼
 注冊[Register]

QQ登錄

只需一步,快速開始

搜索
查看: 9303|回復: 111
上一主題 下一主題

[原創] Charles 4.5.1逆向工程(2)

  [復制鏈接]
跳轉到指定樓層
樓主
scz 發表于 2019-10-24 17:49 回帖獎勵
本帖最后由 scz 于 2019-10-25 17:53 編輯

標題: Charles 4.5.1逆向工程(2)

創建: 2019-10-24 17:14
更新: 2019-10-25 17:50
鏈接: http://scz.617.cn:8/misc/201910241714.txt
      http://www.kvamco.live/thread-1042815-1-1.html

續前文:

《Charles 4.5.1逆向工程》
http://scz.617.cn:8/misc/201910170937.txt
http://www.kvamco.live/thread-1039171-1-1.html

上次通過定位Register按鈕處理代碼定位與License強相關的YQUd.class,后來看到
另一種定位方案,參看:

《如何逆向破解抓包工具Charles》
https://blog.csdn.net/Kaitiren/article/details/83182108

他的思路是在JD-GUI中搜"This is a 30 day trial version",定位:

com.xk72.charles.gui.SplashWindow.class

--------------------------------------------------------------------------
import com.xk72.charles.YQUd;

public class SplashWindow extends JWindow
{
    public void showSharewareStatus ()
    {
        this.showStatus( "This is a 30 day trial version. If you continue using Charles you must\npurchase a license. Please see the Help menu for details." );
    }

    public void showRegistrationStatus ()
    {
        /*
         * 為true時表示已注冊
         */
        if ( YQUd.tEdg() )
        {
            /*
             * 形如"Anyting - Site License"
             */
            this.showStatus( "Registered to: " + YQUd.NCuT() );
        }
        else
        {
            this.showSharewareStatus();
        }
    }
--------------------------------------------------------------------------

他這個思路比我的好,更簡捷,不需要動態調試,不需要定位PeRA.class,直接就找
到YQUd.class。不過你可能會碰上一個問題,某些版本JD-GUI不能正確反編譯
SplashWindow.class,搜索字符串失敗。

暴破比較省事,高階選手在可能的情況下提供keygen。我20歲的時候對netguy師兄佩
服得五體投地,他就是那種高階選手。

TEAM MESMERiZE提供了通殺3.x、4.x的keygen,未做混淆,可以清楚地看到如何從注
冊名變換到序列號,參看:

https://www.upload.ee/files/9009 ... -MESMERiZE.rar.html

keygen.jar
MD5     47d911ba0cecfd31c3312cbb3a344981
SHA256  973d364b71140dcf0aa2b181f1920f688a63cfe1bcdf776c0a4d463095fb1541

下面是keygen的主要邏輯,從注冊名到序列號:

kg_charles_web_proxy_analyzer_v4_2.KG_Charles_Web_Proxy_Analyzer_v4_2.class

--------------------------------------------------------------------------
public String calculateSerial ( String name )
{
    /*
     * 這個神密常量并沒有直接出現在Charles代碼中
     */
    int serialCheckSum  = 1418211210;
    /*
     * 這個函數內置了RC5加密操作
     *
     * RC5_SETUP( 1763497072, 2049034577 )
     */
    int nameCheckSum    = calcNameChecksum( name );
    serialCheckSum     ^= nameCheckSum;
    long serial         = serialCheckSum;
    serial    <<= 32;
    serial   >>>= 32;
    serial    <<= 32;
    /*
     * 這個常量包含License類型,用網友的話說,是控制授權級別的。后面講了如
     * 何獲取這兩個常量。
     */
    serial     |= 0x1CAD6BC;

    int     serialLow   = ( int )( serial & 0xFFFFFFFFFFFFFFFF );
    int     serialHigh  = ( int )( serial >>> 32 & 0xFFFFFFFFFFFFFFFF );
    int[]   serialEnc   = new int[2];

    serialEnc[0]    = serialLow;
    serialEnc[1]    = serialHigh;

    int[]   serialDec   = new int[2];

    RC5 serialDecrypter = new RC5();

    serialDecrypter.RC5_SETUP( -334581843, -1259282228 );
    /*
     * 注意,這里是解密操作,不是加密操作
     */
    serialDecrypter.RC5_DECRYPT( serialEnc, serialDec );

    long    serialDecrypted = ( serialDec[1] & 0xFFFFFFFF ) << 32;

    serialDecrypted    |= serialDec[0] & 0xFFFFFFFF;

    int xorCheckSum = calcXorChecksum( serial );

    String  strSerial   = Integer.toHexString( xorCheckSum ) + Long.toHexString( serialDecrypted );

    /*
     * 前2個字符是校驗和
     */
    strSerial   = String.format( "%02X", new Object[] { Integer.valueOf( xorCheckSum ) } ) + String.format( "%016X", new Object[] { Long.valueOf( serialDecrypted ) } );

    this.tfSerial.setText( strSerial );
    return strSerial;
}
--------------------------------------------------------------------------

下面是Charles中校驗序列號的相關代碼:

Y:\自己的技術文檔\misc\破解Charles\4.5.1\YQUd_scz.java

com.xk72.charles.YQUd.class

--------------------------------------------------------------------------
public final class YQUd
{
    /*
     * 返回錯誤提示,用于throw new LicenseException()
     */
    private String tEdg ( int var1 )
    {
        /*
         * RC5_SETUP( 1763497072, 2049034577 );
         */
        this.Rarr( 8800536498351690864L );

        try
        {
            String  var5;
            /*
             * dbSi[]中存放經RC5處理過的錯誤提示,反靜態分析
             */
            byte[]  var2    = new byte[(var5 = dbSi[var1]).length() / 2];

            /*
             * 將hexstr轉成byte[]
             */
            for ( int var3 = 0; var3 < var2.length; ++var3 )
            {
                var2[var3]  = ( byte )Integer.parseInt( var5.substring( var3 << 1, ( var3 << 1 ) + 2 ), 16 );
            }

            byte[]  var6;

            /*
             * RC5_EncryptArray()
             *
             * 注意,這里是加密操作,不是解密操作
             */
            for( var1 = ( var6 = this.NCuT( var2 ) ).length; var6[var1-1] == 0; --var1 )
            {
                ;
            }
            return new String( var6, 0, var1, "UTF-8" );
        }
        catch ( UnsupportedEncodingException var4 )
        {
            return "";
        }
    }

    /*
     * 檢查序列號的第二步。之所以搞得這么復雜,完全是為了對抗靜態分析。
     */
    private boolean tEdg ( long var1 )
    {
        /*
         * calcXorChecksum
         */
        int var3    = TryJ( var1 );
        /*
         * RC5_SETUP(),密鑰與明文是同一組
         */
        this.Rarr( var1 );

        long    var4    = var1;

        for ( int var6 = 0; var6 < var3 + 35; ++var6 )
        {
            /*
             * long RC5_ENCRYPT ( long )
             */
            var4    = this.NCuT( var4 );
        }
        /*
         * 0x520AAC2983719004
         * 0x520AAC29 0x83719004
         * 1376431145 2205257732
         */
        return var4 == 5911726755176091652L;
    }

    /*
     * 檢查序列號的第一步
     */
    private long TryJ ( String name_var1, String serial_var2, int type_var3 )
    {
        /*
         * 序列號18個字符
         */
        if ( serial_var2.length() != 18 )
        {
            /*
             * The license key is not the correct length. Please check your license key and try again.
             */
            throw new LicenseException( this.tEdg( 0 ) );
        }
        /*
         * 檢查序列號黑名單,這些應該是曾經在Internet上貼出來過的
         */
        else if ( !serial_var2.equalsIgnoreCase( "7055ce2f8cb4f9405f" ) ... )
        {
            /*
             * 將序列號切割成3部分,2+8+8
             */
            long    serialDec_var4      = Long.parseLong(serial_var2.substring(2, 10), 16) << 32 | Long.parseLong(serial_var2.substring(10, 18), 16);
            int     xorCheckSum_var12   = Integer.parseInt(serial_var2.substring(0, 2), 16);
            /*
             * 0xB4F0E0CCEC0EAFAD
             * -1259282228 -334581843
             *
             * RC5_SETUP( -334581843, -1259282228 );
             */
            this.Rarr( -5408575981733630035L );
            long    serialEnc_var7;
             /*
              * calcXorChecksum( serial );
              * RC5_ENCRYPT( serialDec, serialEnc );
              *
              * 注意,這里是加密操作,不是解密操作
              *
              * 檢查序列號校驗和
              */
            if ( TryJ( serialEnc_var7 = this.NCuT( serialDec_var4 ) ) != xorCheckSum_var12 )
            {
                /*
                 * 拋出異常,顯示錯誤提示
                 */
                throw new LicenseException( this.tEdg( 1 ) );
            }
            else
            {
                /*
                 * 處理后的序列號的低32位包含License類型,常量0x1CAD6BC會
                 * 出現在這個位置。之前這個地方看錯了,少看了一組邏輯右移
                 * (>>>),錯寫成0x1CAD6BC未被檢查。
                 */
                this.RjRQ   = ( int )( serialEnc_var7 << 32 >>> 32 >>> 24 );
                if ( this.RjRQ == 1 )
                {
                    this.aqrV   = LicenseType.tEdg;
                }
                else
                {
                    if ( this.RjRQ != type_var3 )
                    {
                        if ( this.RjRQ < type_var3 )
                        {
                            /*
                             * 拋出異常,顯示錯誤提示
                             */
                            throw new LicenseException( this.tEdg( 3 ) );
                        }
                        /*
                         * 拋出異常,顯示錯誤提示
                         */
                        throw new LicenseException( this.tEdg( 1 ) );
                    }
                    /*
                     * 處理后的序列號的低32位包含License類型。
                     */
                    switch( ( int )( serialEnc_var7 << 32 >>> 32 >>> 16 & 255L ) )
                    {
                    case 1:
                        this.aqrV   = LicenseType.tEdg;
                        break;
                    case 2:
                        this.aqrV   = LicenseType.TryJ;
                        break;
                    case 3:
                        this.aqrV   = LicenseType.NCuT;
                        break;
                    default:
                        /*
                         * 拋出異常,顯示錯誤提示
                         */
                        throw new LicenseException( this.tEdg( 1 ) );
                    }
                }
                /*
                 * RC5_SETUP( 1763497072, 2049034577 );
                 */
                this.Rarr( 8800536498351690864L );
                try
                {
                    byte[]  var10   = name_var1.getBytes( "UTF-8" );
                    if ( ( type_var3 = ( var12 = var10.length ) + 4 ) % 8 != 0 )
                    {
                        type_var3  += 8 - type_var3 % 8;
                    }
                    byte[]  var14   = new byte[type_var3];
                    System.arraycopy( var10, 0, var14, 4, var12 );
                    var14[0]    = (byte)(var12 >> 24);
                    var14[1]    = (byte)(var12 >> 16);
                    var14[2]    = (byte)(var12 >> 8);
                    var14[3]    = (byte)var12;
                    /*
                     * RC5_EncryptArray();
                     */
                    byte[]  var6    = this.NCuT( var14 );
                    int     var11   = 0;
                    byte[]  var13   = var6;
                    type_var3   = var6.length;
                    /*
                     * calcNameChecksum( name )
                     */
                    for( int var15 = 0; var15 < type_var3; ++var15 )
                    {
                        byte    var5 = var13[var15];
                        /*
                         * nameCheckSum
                         */
                        var11   = ( var11 ^= var5 ) << 3 | var11 >>> 29;
                    }
                    /*
                     * XOR后應該得到"1418211210(0x54882F8A)"
                     */
                    var11  ^= ( int )( serialEnc_var7 >> 32 );
                    /*
                     * 0xA58D19C600000000
                     * 0xA58D19C654882F8A
                     *
                     * 接下來會轉到"檢查序列號的第二步"
                     */
                    return -6517524747541020672L | ( long )var11 << 32 >>> 32;
                }
                catch ( UnsupportedEncodingException var9 )
                {
                    return -1L;
                }
            }
        }
        else
        {
            throw new LicenseException( this.tEdg( 1 ) );
        }
    }

    /*
     * int calcXorChecksum ( long l )
     */
    private static final int TryJ ( long var0 )

    /*
     * RC5_EncryptArray(),進行RC5加密
     */
    private byte[] NCuT ( byte[] var1 )

    /*
     * RC5_ENCRYPT(),進行RC5加密
     *
     * 通過這個函數可以看出r=12
     */
    private long NCuT ( long var1 )

    /*
     * RC5_SETUP(),初始化對稱密鑰(8字節)
     *
     * Charles用的是RC5-32/12/8
     */
    private void Rarr ( long var1 )

    static
    {
        /*
         * 經RC5處理過的錯誤提示
         */
        dbSi    = new String[]{ "b241993e8a1...", ... };
        /*
         * RC5-32/r/b的特征常量P(0xB7E15163),出現在RC5_SETUP()中
         *
         * https://en.wikipedia.org/wiki/RC5
         */
        xgCJ    = -1209970333;
    }
--------------------------------------------------------------------------

TEAM MESMERiZE這伙人很厲害。calculateSerial()中出現的"1418211210"并未直接
出現在Charles代碼中,單靠靜態分析不可能得到這個神密常量。有兩種可能,一種
是他們進行了動態調試,確實可以看到"1418211210";另一種是早期版本中出現過
"1418211210"。另一個常量0x1CAD6BC,我之前看錯了YQUd.class,在某處少看了一
組邏輯右移(>>>),犯了低級錯誤,在注釋中錯寫成校驗序列號時0x1CAD6BC未被檢查,
后來微博上有網友指正了該處錯誤。

為了得到"1418211210",簡單地動態調試就可以,因為它與另一固定常量湊一起后出
現在"檢查序列號的第二步",檢查相應tEdg()的形參,其低32位就是。為了得到
0x1CAD6BC,可以攔截對應calcXorChecksum()的那個TryJ(),形參的低32位就是。這
個調試過程的前提是你有一對現成的"name:serial"。

keygen中的RC5.class值得保存,沒有混淆,實際就是Java源碼。

Charles用的是RC5-32/12/8,有個現成的Java實現可供參考:

https://hewgill.com/rc5/rc5java.zip

最常見的RC5配置是:

w=32
r=12
b=16
P(32)=0xb7e15163 (-0x481eae9d/-1209970333)
Q(32)=0x9e3779b9 (-0x61c88647)

在RC5的具體實現中,有兩種實現方式,一種是使用P、Q動態生成一張表,另一種是
在代碼中直接嵌入這張表。對于RC5-32/r/b來說,搜索P(0xB7E15163),不要搜
Q(0x9E3779B9)。一是Q有可能以負值形式出現,二是從實現上講有兩種實現方式,
stab[t]可能是預生成的,此時有P無Q,搜P可以保證命中。

這是我第二次碰上RC5,第一次碰上還是某次幫組織反APT時,一個極其強大的對手被
我方一個極其聰明的小伙子抓住了一絲尾巴,甚至都談不上對手犯錯,總歸是極具傳
奇色彩地還原了經RC5加密過的數據,待我臨死前再來吹這個牛,如果那時我沒得阿
爾茨海默癥的話。

有了這個keygen,估計很長一段時間都不再需要暴破。早知道有這么個玩意兒,我剁
個毛線啊。在所謂的1024節,我們必須討論一下程序,對吧。

keygen.jar.7z

4.74 KB, 下載次數: 295, 下載積分: 吾愛幣 -1 CB

通殺3.x、4.x,不是我寫的

免費評分

參與人數 25吾愛幣 +23 熱心值 +24 收起 理由
linrunqing521 + 1 熱心回復!
quleilei889 + 1 [email protected]
魚七大大丶 + 1 + 1 用心討論,共獲提升!
oxsho + 1 熱心回復!
scott.jan + 1 + 1 我很贊同!
laohucai + 1 + 1 [email protected]
stat + 1 + 1 我很贊同!
xiong_online + 1 + 1 用心討論,共獲提升!
alien11 + 1 [email protected]
夜塵i + 1 + 1 我很贊同!
zerglurker + 1 + 1 [email protected]
china_wuying + 1 + 1 我很贊同!
daniel7785 + 1 用心討論,共獲提升!
wmsuper + 3 + 1 [email protected]
N0LL + 1 + 1 [email protected]
alsk + 1 + 1 我很贊同!
某些人 + 1 + 1 [email protected]
LOLQAQ + 1 + 1 我很贊同!
cxqdly + 2 + 1 [email protected]
cnshr00t + 1 + 1 我很贊同!
Liu0827 + 1 + 1 熱心回復!
gaosld + 1 + 1 用心討論,共獲提升!
jnez112358 + 1 + 1 [email protected]
xdnice + 1 + 1 用心討論,共獲提升!
monsterbaby521 + 1 熱心回復!

查看全部評分

發帖前要善用論壇搜索功能,那里可能會有你要找的答案或者已經有人發布過相同內容了,請勿重復發帖。

推薦
h080294 發表于 2019-10-24 19:24
注冊的算法就是一個RC5,不過代碼中只有加密的部分,需要自己補一個解密。

細節的部分就是你說的那個常量值,他在正向驗證計算的時候右移了32位,類似這樣。

var11 ^= (int)(var7 >> 32)



因此反推的時候,不能得到全部的信息。但是通過一些現成的key可以發現,那32位long值是固定的。另外那個30070460L的值同樣,也可以得到。
推薦
 樓主| scz 發表于 2019-10-25 11:33 <
本帖最后由 scz 于 2019-10-25 17:54 編輯
h080294 發表于 2019-10-24 19:24
注冊的算法就是一個RC5,不過代碼中只有加密的部分,需要自己補一個解密。

細節的部分就是你說的那個常 ...

有現成的key,動態調試中是可以看到1418211210這些常量。從4.5.1的代碼來看,純靜態反推1418211210是不可能的。
另一個常量0x1CAD6BC,我之前看錯了YQUd.class,在某處少看了一組邏輯右移(>>>),犯了低級錯誤,在注釋中錯寫成校驗序列號時0x1CAD6BC未被檢查。
4#
Monitor 發表于 2019-10-24 17:52
5#
yc19951005 發表于 2019-10-24 17:56
沒看懂說的是啥   
6#
lianxing11 發表于 2019-10-24 18:06
沒看懂是什么東西- -
7#
miaowing 發表于 2019-10-24 19:38
厲害了,大佬
頭像被屏蔽
8#
納米科技 發表于 2019-10-24 22:19
支持  謝謝
9#
孤獨的老大哥 發表于 2019-10-24 22:45
謝謝分享
10#
yike911 發表于 2019-10-25 00:17
牛逼的,謝謝
11#
tmsq 發表于 2019-10-25 02:03
目前看不懂,收藏
您需要登錄后才可以回帖 登錄 | 注冊[Register]

本版積分規則 警告:禁止回復與主題無關內容,違者重罰!

快速回復 收藏帖子 返回列表 搜索

RSS訂閱|小黑屋|聯系我們|吾愛破解 - LCG - LSG ( 京ICP備16042023號 | 京公網安備 11010502030087號 )

GMT+8, 2019-12-14 18:37

Powered by Discuz!

© 2001-2017 Comsenz Inc.

快速回復 返回頂部 返回列表
3d开机号今天