mac App 破解之路六 studio 3t


 

 不想無限使用,直接破解到正版:

 

 

 

輸入郵箱 名字之后 還有licence信息之后,處理函數是:

 

 

 this.text.getText() 很明顯是你輸入的licence.   然后交給父類okPress處理了.      licence字符串存放的變量是 this.r.   獲取這個變量的方法是 am()

 

 查看調用licence信息的地方: 

t3.common.lic.a.d.bb(). :   把用戶輸入用this.aT.a()進行處理.   aT對象的類名是:t3.utils.a

 

展示licence信息的地方: t3.common.lic.j.a():

 

licence信息存儲組織方法 t3.common.lic.a.j.a():。    猜測xVar應該是服務器傳過來的.

 

 

 

 

核心類: 對用戶輸入的licence進行處理

分析:

String x = RegisteredLicenseDocumentFormatter.m886x(str);

License f = this.f711aX.mo903f(x);

if (!f.getStatus().isActive()) {
this.f710aW.mo720O(f.getStatus().getDescription());
return;
}

隨便輸入licence信息得到如下信息.  .f710aW.mo720O 是顯示錯誤的對話框.     

Your license key seems to be corrupted. Make sure you have copied all text between and including the --- markers at the start and end of the license key.

這個信息的顯示意味着走了異常的代碼, 這個異常處有一個打印具體的信息. 等會看這個異常原因.   因為不知道是哪一步異常的.

先找到輸出日志的文件: 

錯誤詳細: 

 

從錯誤信息中可以看到 是  執行License f = this.f711aX.mo903f(x); 這個語句就異常了.   [ at t3.common.lic.a.i.a(ManagerController.java:61)]

 

.method private z(Ljava/lang/String;)Lt3/common/lic/h;
    .registers 9

    .prologue
    const/4 v1, 0x0

    const/4 v3, 0x1

    const/4 v4, 0x0

    .line 154
    .line 156
    :try_start_3
    const-string v0, "X.509"

    invoke-static {v0}, Ljava/security/cert/CertificateFactory;->getInstance(Ljava/lang/String;)Ljava/security/cert/CertificateFactory;

    move-result-object v0

    .line 157
    const-class v2, Lt3/common/lic/ae;

    const-string v5, "/t3/common/lic/licensing_public.cer"

    invoke-virtual {v2, v5}, Ljava/lang/Class;->getResourceAsStream(Ljava/lang/String;)Ljava/io/InputStream;
    :try_end_10
    .catch Ljava/security/cert/CertificateException; {:try_start_3 .. :try_end_10} :catch_49

    move-result-object v2

    .line 160
    if-eqz v2, :cond_aa

    .line 163
    :try_start_13
    invoke-virtual {v0, v2}, Ljava/security/cert/CertificateFactory;->generateCertificate(Ljava/io/InputStream;)Ljava/security/cert/Certificate;

    move-result-object v0

    check-cast v0, Ljava/security/cert/X509Certificate;
    :try_end_19
    .catchall {:try_start_13 .. :try_end_19} :catchall_63

    .line 167
    :try_start_19
    invoke-virtual {v2}, Ljava/io/InputStream;->close()V
    :try_end_1c
    .catch Ljava/io/IOException; {:try_start_19 .. :try_end_1c} :catch_59
    .catch Ljava/security/cert/CertificateException; {:try_start_19 .. :try_end_1c} :catch_49

    .line 177
    :goto_1c
    :try_start_1c
    const-string v2, "SHA-1"

    invoke-static {v2}, Ljava/security/MessageDigest;->getInstance(Ljava/lang/String;)Ljava/security/MessageDigest;

    move-result-object v2

    .line 178
    invoke-virtual {v0}, Ljava/security/cert/X509Certificate;->getEncoded()[B

    move-result-object v5

    invoke-virtual {v2, v5}, Ljava/security/MessageDigest;->update([B)V

    .line 179
    invoke-virtual {v2}, Ljava/security/MessageDigest;->digest()[B
    :try_end_2c
    .catch Ljava/security/cert/CertificateEncodingException; {:try_start_1c .. :try_end_2c} :catch_72
    .catch Ljava/security/NoSuchAlgorithmException; {:try_start_1c .. :try_end_2c} :catch_a8
    .catch Ljava/security/cert/CertificateException; {:try_start_1c .. :try_end_2c} :catch_49

    move-result-object v1

    .line 185
    :goto_2d
    if-nez v1, :cond_7c

    move v2, v3

    :goto_30
    :try_start_30
    sget-object v5, Lt3/common/lic/ae;->am:[B

    invoke-static {v1, v5}, Ljava/util/Arrays;->equals([B[B)Z

    move-result v1

    if-nez v1, :cond_7e

    move v1, v3

    :goto_39
    or-int/2addr v1, v2

    if-eqz v1, :cond_80

    .line 186
    const-string v0, "Failed to verify the integrity of the certificate."

    invoke-static {v0}, Lorg/pmw/tinylog/Logger;->error(Ljava/lang/String;)V

    .line 187
    new-instance v0, Ljava/lang/SecurityException;

    const-string v1, "License verification has failed."

    invoke-direct {v0, v1}, Ljava/lang/SecurityException;-><init>(Ljava/lang/String;)V

    throw v0
    :try_end_49
    .catch Ljava/security/cert/CertificateException; {:try_start_30 .. :try_end_49} :catch_49

    .line 193
    :catch_49
    move-exception v0

    .line 194
    const-string v1, "Failed to access the 3t certificate."

    new-array v2, v4, [Ljava/lang/Object;

    invoke-static {v0, v1, v2}, Lorg/pmw/tinylog/Logger;->error(Ljava/lang/Throwable;Ljava/lang/String;[Ljava/lang/Object;)V

    .line 195
    new-instance v0, Ljava/lang/SecurityException;

    const-string v1, "License verification has failed."

    invoke-direct {v0, v1}, Ljava/lang/SecurityException;-><init>(Ljava/lang/String;)V

    throw v0

    .line 169
    :catch_59
    move-exception v2

    .line 170
    :try_start_5a
    const-string v5, "Failed to find or load 3t certificate."

    const/4 v6, 0x0

    new-array v6, v6, [Ljava/lang/Object;

    invoke-static {v2, v5, v6}, Lorg/pmw/tinylog/Logger;->error(Ljava/lang/Throwable;Ljava/lang/String;[Ljava/lang/Object;)V
    :try_end_62
    .catch Ljava/security/cert/CertificateException; {:try_start_5a .. :try_end_62} :catch_49

    goto :goto_1c

    .line 166
    :catchall_63
    move-exception v0

    .line 167
    :try_start_64
    invoke-virtual {v2}, Ljava/io/InputStream;->close()V
    :try_end_67
    .catch Ljava/io/IOException; {:try_start_64 .. :try_end_67} :catch_68
    .catch Ljava/security/cert/CertificateException; {:try_start_64 .. :try_end_67} :catch_49

    .line 172
    :goto_67
    :try_start_67
    throw v0

    .line 169
    :catch_68
    move-exception v1

    .line 170
    const-string v2, "Failed to find or load 3t certificate."

    const/4 v3, 0x0

    new-array v3, v3, [Ljava/lang/Object;

    invoke-static {v1, v2, v3}, Lorg/pmw/tinylog/Logger;->error(Ljava/lang/Throwable;Ljava/lang/String;[Ljava/lang/Object;)V

    goto :goto_67

    .line 181
    :catch_72
    move-exception v2

    .line 182
    :goto_73
    const-string v5, "Failed to hash the certificate."

    const/4 v6, 0x0

    new-array v6, v6, [Ljava/lang/Object;

    invoke-static {v2, v5, v6}, Lorg/pmw/tinylog/Logger;->error(Ljava/lang/Throwable;Ljava/lang/String;[Ljava/lang/Object;)V

    goto :goto_2d

    :cond_7c
    move v2, v4

    .line 185
    goto :goto_30

    :cond_7e
    move v1, v4

    goto :goto_39

    .line 190
    :cond_80
    invoke-virtual {v0}, Ljava/security/cert/X509Certificate;->getPublicKey()Ljava/security/PublicKey;
    :try_end_83
    .catch Ljava/security/cert/CertificateException; {:try_start_67 .. :try_end_83} :catch_49

    move-result-object v0

    .line 198
    :goto_84
    if-nez v0, :cond_8e

    .line 199
    new-instance v0, Ljava/lang/SecurityException;

    const-string v1, "Failed to load the 3T certificate."

    invoke-direct {v0, v1}, Ljava/lang/SecurityException;-><init>(Ljava/lang/String;)V

    throw v0

    .line 203
    :cond_8e
    new-instance v1, Lt3/common/lic/h;

    invoke-direct {v1}, Lt3/common/lic/h;-><init>()V

    .line 204
    invoke-virtual {v1, p1}, Lt3/common/lic/h;->d(Ljava/lang/String;)V

    .line 205
    invoke-virtual {v1, v0}, Lt3/common/lic/h;->verify(Ljava/security/PublicKey;)Z

    .line 208
    invoke-virtual {v1}, Lt3/common/lic/h;->E()Z

    move-result v0

    if-nez v0, :cond_a7

    .line 209
    new-instance v0, Ljava/lang/SecurityException;

    const-string v1, "License verification failed."

    invoke-direct {v0, v1}, Ljava/lang/SecurityException;-><init>(Ljava/lang/String;)V

    throw v0

    .line 211
    :cond_a7
    return-object v1

    .line 181
    :catch_a8
    move-exception v2

    goto :goto_73

    :cond_aa
    move-object v0, v1

    goto :goto_84
.end method

貼出來的代碼就是校驗用戶輸入的licence關鍵代碼, 可以這個方法反編譯失敗了,有時間再大力研究這段代碼吧.

 把這個jar包放在android studio中 居然完全可以看到源碼, 不可思議

看了一下這個方法,  他的思路是:

獲取licensing_public.cer文件, 然后用sha-1算法驗證這個文件對不對, 如果不對就跑異常.   這樣可以防止有人修改cer文件.

之后創建 t3.common.lic.h 對象,  然后把這個返回.      var1 是用戶輸入.   他是用#在分割.    用戶完全完全可以輸入  xxx#xxxx 這樣的格式數據.

 

破解思路方法就可多了:

方案一:  

自己生成X.509 公私密鑰key.    計算公有key的sha-1

 

用自己生成的公鑰替換licensing_public.cer。 然后替換代碼中 sha-1的值.     就OK了.   

然后用注冊機:

調用 public static af a(String var0, PrivateKey var1)這個方法生成lincese就可以.
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package t3.common.lic;

import com.google.common.io.BaseEncoding;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import org.pmw.tinylog.Logger;

public class af {
    private String aq = null;
    private String content = null;
    private boolean ar = false;

    public String aL() {
        return this.aq;
    }

    public String getContent() {
        return this.content;
    }

    public boolean E() {
        return this.ar;
    }

    private af() {
    }

    public static af a(String var0, PublicKey var1) throws IllegalArgumentException {
        af var2 = new af();
        var2.aq = var0;
        var2.ar = false;
        if (null != var0 && null != var1) {
            String[] var3 = w(var0).split("\\\\");
            if (var3.length != 3) {
                throw new IllegalArgumentException("signedString is not readable.");
            } else {
                byte[] var4;
                byte[] var5;
                byte[] var6;
                BaseEncoding var7;
                IllegalArgumentException var8;
                try {
                    var7 = BaseEncoding.base64();
                    var4 = var7.decode(var3[0]);
                    if (var4.length == 0) {
                        return var2;
                    }

                    var5 = var7.decode(var3[1]);
                    var6 = var7.decode(var3[2]);
                } catch (IllegalArgumentException var10) {
                    var8 = new IllegalArgumentException("signedString is not readable.");
                    var8.initCause(var10);
                    throw var8;
                }

                if (var4[0] != 3) {
                    throw new IllegalArgumentException("signedString is not readable (version mismatch).");
                } else {
                    try {
                        var7 = null;
                        Signature var11 = Signature.getInstance("SHA256withRSA");
                        var11.initVerify(var1);
                        var11.update(var5);
                        if (var11.verify(var6)) {
                            var2.content = new String(var5, "UTF-8");
                            var2.ar = true;
                            return var2;
                        } else {
                            return var2;
                        }
                    } catch (InvalidKeyException | SignatureException | UnsupportedEncodingException | NoSuchAlgorithmException var9) {
                        var8 = new IllegalArgumentException("signedString is not readable.");
                        var8.initCause(var9);
                        throw var8;
                    }
                }
            }
        } else {
            throw new IllegalArgumentException("One of the arguments is null.");
        }
    }

    public static af a(String var0, PrivateKey var1) {
        af var2 = new af();
        var2.content = var0;
        var2.ar = false;
        byte[] var3 = new byte[]{3};

        byte[] var4;
        try {
            var4 = var0.getBytes("UTF-8");
        } catch (UnsupportedEncodingException var12) {
            var12.printStackTrace();
            Logger.error(var12, "Encoding failure", new Object[0]);
            return null;
        }

        Object var5 = null;

        byte[] var13;
        try {
            Signature var6 = Signature.getInstance("SHA256withRSA");
            var6.initSign(var1);
            var6.update(var4);
            var13 = var6.sign();
        } catch (InvalidKeyException | SignatureException | NoSuchAlgorithmException var11) {
            Logger.error(var11, "Encryption failure", new Object[0]);
            return var2;
        }

        BaseEncoding var14 = BaseEncoding.base64();

        try {
            var14.encode(var3);
            var14.encode(var4);
            var14.encode(var13);
        } catch (IllegalArgumentException var10) {
            Logger.error(var10, "Encryption failure", new Object[0]);
            return var2;
        }

        String var7 = String.format("%s\\%s\\%s", var14.encode(var3), var14.encode(var4), var14.encode(var13));
        var2.aq = w(var7);
        var2.ar = true;
        return var2;
    }

    private static String B(String var0) {
        String[] var1 = var0.split("#");
        String var2 = var0;
        if (var1.length > 2) {
            var2 = var1[var1.length - 2];
        } else if (var1.length == 2) {
            var2 = var1[1];
        }

        return var2;
    }

    private static String w(String var0) {
        return var0.replaceAll("[^0-9a-zA-Z/=+\\\\]", "");
    }
}

 

方案二:

直接修改代碼此處代碼, 然后隨便輸入:

 

=========

開始動態調試之旅:

查看安裝時間: 

 

var1 是記錄了安裝時間.  看是什么賦值的?

 

 var1和var2記錄是在本地:  ~/.3T/studio-3t/soduz3vqhnnja46uvu3szq--

 調試得知: ~/.3T/studio-3t/soduz3vqhnnja46uvu3szq--/settings.dat 文件里的內容就是記錄安裝時間的.     只不過加密了.   

理論上刪除這個文件,就可以無限試用了, 但是實際情況不是: 

本人刪除這個文件之后,  又重新生成了一個一摸一樣的數據, 這個setting.data不是最終源頭.  繼續調試之旅,

開始從加密的地方斷點調試.

 

t3.common.lic.b.j 類中是數據源頭, 因為是這個類的 this.bj.get("soduz3vqhnnja46uvu3szq--") 之后得到了數據.

繼續追蹤,發現安裝時間的數據存放在5個類中: 

是一個List 這個 list類的信息分別是: 

如果把這5個地方的安裝數據都刪除,  那就達到無限試用了. 接下來找到5個地方.

第一個地方: t3.common.lic.b.j 

this.bj = Preferences.userRoot().node("/3t/mongochef/" + var2);  var2 = "enterprise"

// Preferences.userRoot() 目錄在: ~/Library/Preferences/com.apple.java.util.prefs.plist

 

第二到五地方分別是:

/Users/dengzhongqiang/.3T/studio-3t/Lwm3TdTxgYJkXBgVk4s3/settings.dat

/Users/dengzhongqiang/.cache/ftuwWNWoJl-STeZhVGHKkQ--/5rpyYIZGkVBXle1pseFY2g

/var/folders/x4/xwpchqcd1m9539py__22l0ww0000gn/T/t3/dataman/mongodb/app/AppRunner/soduz3vqhnnja46uvu3szq--

/var/folders/x4/xwpchqcd1m9539py__22l0ww0000gn/T/ftuwWNWoJl-STeZhVGHKkQ--/5rpyYIZGkVBXle1pseFY2g--.log

 

說明:

第一個地方比較特別 com.apple.java.util.prefs.plist。  這個是所有Java軟件共享的,  直接刪除可能會影響其他應用.   

其他第二到五地方隨意刪.    

寫了一個腳本:

rm -f ~/Library/Preferences/3t.*
rm -rf ~/.3T
rm -rf ~/.cache/ftuwWNWoJl-STeZhVGHKkQ--
rm -rf /var/folders/x4/xwpchqcd1m9539py__22l0ww0000gn/T/t3
rm -rf /var/folders/x4/xwpchqcd1m9539py__22l0ww0000gn/T/ftuwWNWoJl-STeZhVGHKkQ--

發現了一個奇怪現象,執行了之后並沒有效果, 時間沒有重置.  不得不佩服這個軟件安全措施做的很到位.

沒辦法,繼續挖掘. 

 查找到原因了: t3.common.lic.b.j 沒有存放在com.apple.java.util.prefs.plist文件中.  在跟蹤就到JVM虛擬機了.  osx庫在處理這個數據, 具體怎么處理的就不清楚了.

只能寫代碼刪除了.

package com.company.dzqCrack;

import java.util.prefs.Preferences;

public class Main {

    public static void main(String[] args) {
    // write your code here
        Preferences  bt = Preferences.userRoot().node("/3t/mongochef/enterprise");
        bt.remove("soduz3vqhnnja46uvu3szq--");
    }
}

到此之際,破解完成.  又有30天了 

 

 

 

關於動態調試別人的jar包總結:

修改info.plist文件: 圈出來的就是新增的

<string>-Xdebug</string>
<string>-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=50064</string>

 

然后在 idea編輯器中創建一個remote debug

 

 =======================

雖然可以無限試用了,  但是心里有一個結,就是

為什么刪了com.apple.java.util.prefs.plist  3t.mongochef.enterprise.plist 等plist文件,為什么還有存有安裝信息.  跟蹤的時候 發現它是加載了 osx庫.

一定打破砂鍋探到底

進入jre.bundle目錄。 

將osx庫拖入hopper 

可以看到Java層面的東西,最終調用是這些方法. 

 

發現 _getStringsForNode調用了兩次 _toCF:

查了一下蘋果開發文檔:

 

也就是這個_toCF核心是把 c語言的字符串 轉換為 CFString .   

轉換之后,有一個方法被調用了: 

(*(*r15 + 0x530))(r15, r14, rax);  // r15 = arg0.   其實這個就是JNIEnv *env      查看jni.h 中的定義 是struct JNINativeInterface類型

0x530是這個結構體的偏移,  暫且放一放. 

  

通過跟蹤發現: 一切數據來源都是調用 CFPreferencesCopyValue, 

 

 

上面英文的大概意思。

CFPreferences 不能直接轉 NSUserDefault.      是線程安全的.  和應用程序還有用戶ID,host有關.    沒有發現特別之處.  之所以刪除plist文件不生效是因為數據已經加載到內存中了.

 

 至此大完結,   刪除~/Library/Preferences 目錄下 t3* 3t*文件是有用的,  刪除plist文件之后重啟電腦就好了, 也就是上面的shell腳本是OK的.

如果不想重啟電腦, 就執行一段Java代碼, 用Java代碼操作刪除,立馬生效.   

 

====== 

 

 

截止到2020年04月30日,我發現之前的shell腳本對所有studio3T的版本都是有效的,studio3t可以隨意升級版本。

但是之前的shell腳本不具有普適性,只對本人的電腦有效。  鑒於此,為了讓所有人都可以無限試用,我改造了一下之前的腳本。   如果發現以下腳本無法使用,請留言。

#!/bin/sh 

rm -f ~/Library/Preferences/3t.*
rm -rf ~/.3T
rm -rf ~/.cache/ftuwWNWoJl-STeZhVGHKkQ--

ftPath=`find /var/folders -name "ftuwWNWoJl-STeZhVGHKkQ--" -print 2>&1 | fgrep -v "Permission denied" | fgrep -v "Operation not permitted"`
t3Path=`dirname ${ftPath}`/t3

if [ -e ${ftPath} ];then 
    rm -rf ${ftPath}
fi

if [ -e ${t3Path} ];then 
    rm -rf ${t3Path}
fi

echo "刪除文件成功,請立即重啟電腦生效"
echo "如果不想立刻重啟,那么請在重啟電腦前,都不要重新運行studio3T, 否則執行腳本將不起作用"

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM