破解某小說App(一)

亂碼桑發表於2019-02-26

背景

想實現一個支援多渠道的小說App,因此對該小說App進行分析獲取它的介面呼叫方式 該App詳情頁截圖:

詳情頁截圖

抓包

Charles抓取飛盧詳情頁面的介面

charles抓包

該小說App的域名是一個固定IP(試過幾次退出登陸發現每次IP不一樣,猜測是客戶端寫死的或者服務端下發,應該是防止域名被劫持吧)

上傳的引數是一堆亂碼,token也是亂碼,

token

一般末尾是‘=’,應該是base64編碼,解密失敗

base64解密

返回內容居然是XML,author_name居然也是亂碼,猜測是base64編碼,使用站長工具Base64解密

base64解密

感覺該App對資料加密做的很嚴謹,怪不得市場沒有破解版

現在模擬它的請求只要破解它的token和引數就可以了

反編譯

使用Android Studio開啟該App,看到tencent_stub,應該是做個樂固加固了。

App

開始反編譯

Mac上使用Android CrackTool進行反編譯處理

Android CrackTool
反編譯結果的確是樂固加固
結果

加固包反編譯

那開始對這個加固包進行反編譯 參照這個文件Android APK脫殼--騰訊樂固、360加固一鍵脫殼

使用脫殼工具FDex2

VirtualXposed:無需root手機即可使用xp框架。

dex進行dex2jar

這個步驟可以用Android Crack Tool上執行,執行成功之後,使用jdgui開啟 搜尋關鍵字Xml4Android_relevantPage,獲取詳情頁

詳情頁

重新整理詳情頁發現Logcat中有日誌

破解某小說App(一)
日誌中有contetn 原文進行搜尋,發現token和引數加密都是native實現的RSA加密,

 public <T extends BaseModel> T a(Object paramObject, String paramString1, UserInfoDto paramUserInfoDto, String paramString2, b<T> paramb)
  {
    try
    {
      paramString1 = paramString1.split("\\?");
      String str2 = paramString1[1];
      String str1 = a(paramString1[0]);
      paramString1 = new java/lang/StringBuilder;
      paramString1.<init>();
      paramString1.append(str1);
      paramString1.append("?appversion=");
      paramString1.append(AppUtils.getAppversion());
      paramString1.append("&Type=Android");
      paramString1 = paramString1.toString();
      str1 = paramString1;
      if (!TextUtils.isEmpty(paramString1))
      {
        str1 = paramString1;
        if (paramString1.contains("http://client4ip")) {
          str1 = paramString1.replace("http://client4ip", "https://client4ip");
        }
      }
      if (!TextUtils.isEmpty(paramString2))
      {
        paramString1 = paramb.d(paramString2);
      }
      else
      {
        if (!TextUtils.isEmpty(paramUserInfoDto.getUsername())) {
          paramUserInfoDto.setUsername(paramUserInfoDto.getUsername().toLowerCase());
        }
        if (!TextUtils.isEmpty(paramUserInfoDto.getPassword())) {
          paramUserInfoDto.setPassword(paramUserInfoDto.getPassword().toLowerCase());
        }
        if (!TextUtils.isEmpty(paramUserInfoDto.getVerifyCode())) {
          paramUserInfoDto.setVerifyCode(paramUserInfoDto.getVerifyCode().toLowerCase());
        }
        if (!TextUtils.isEmpty(paramUserInfoDto.getUsername()))
        {
          paramString2 = paramb.a(paramUserInfoDto);
          paramString1 = paramb.d(paramString2);
        }
        else
        {
          paramString1 = new java/lang/StringBuilder;
          paramString1.<init>();
          paramString1.append(System.currentTimeMillis());
          paramString1.append("");
          paramString2 = MD5.MD5(paramString1.toString());
          paramString1 = paramb.d(paramString2);
        }
      }
      paramUserInfoDto = m.a().b("SP_UID");
      if (!TextUtils.isEmpty(m.a().b("username"))) {
        paramUserInfoDto = m.a().b("username");
      }
      Object localObject = paramUserInfoDto;
      if (TextUtils.isEmpty(paramUserInfoDto))
      {
        localObject = j.a();
        m.a().a("SP_UID", (String)localObject);
      }
      paramUserInfoDto = new java/lang/StringBuilder;
      paramUserInfoDto.<init>();
      paramUserInfoDto.append(str2);
      paramUserInfoDto.append("&uuid=");
      paramUserInfoDto.append((String)localObject);
      localObject = paramUserInfoDto.toString();
      paramUserInfoDto = (UserInfoDto)localObject;
      if (!TextUtils.isEmpty((CharSequence)localObject))
      {
        paramUserInfoDto = (UserInfoDto)localObject;
        if (!((String)localObject).contains("time="))
        {
          paramUserInfoDto = new java/lang/StringBuilder;
          paramUserInfoDto.<init>();
          paramUserInfoDto.append((String)localObject);
          paramUserInfoDto.append("&time=");
          paramUserInfoDto.append(URLEncoder.encode(TimeUtils.getNowString(), "gb2312"));
          paramUserInfoDto = paramUserInfoDto.toString();
        }
      }
      localObject = paramUserInfoDto;
      if (!TextUtils.isEmpty(paramUserInfoDto))
      {
        localObject = paramUserInfoDto;
        if (!paramUserInfoDto.contains("appversion="))
        {
          localObject = new java/lang/StringBuilder;
          ((StringBuilder)localObject).<init>();
          ((StringBuilder)localObject).append(paramUserInfoDto);
          ((StringBuilder)localObject).append("&appversion=");
          ((StringBuilder)localObject).append(AppUtils.getAppversion());
          ((StringBuilder)localObject).append("&Type=Android");
          localObject = ((StringBuilder)localObject).toString();
        }
      }
      paramUserInfoDto = new java/lang/StringBuilder;
      paramUserInfoDto.<init>();
      paramUserInfoDto.append("content 原文 ");
      paramUserInfoDto.append((String)localObject);
      g.a(new Object[] { paramUserInfoDto.toString() });
      paramUserInfoDto = paramb.a((String)localObject, paramString2);
      paramString2 = new com/lzy/okgo/model/HttpParams;
      paramString2.<init>();
      paramString2.put("", paramUserInfoDto, new boolean[0]);
      paramObject = ((PostRequest)((PostRequest)((PostRequest)((PostRequest)((PostRequest)com.lzy.okgo.a.b(str1).tag(paramObject)).headers("token", paramString1)).headers("mobileType", "Android")).headers("appversion", AppUtils.getAppversion())).params(paramString2)).execute();
      if (paramObject == null) {
        return null;
      }
      if (((Response)paramObject).isSuccessful())
      {
        paramUserInfoDto = ((Response)paramObject).body().byteStream();
        paramObject = new java/io/BufferedReader;
        paramString1 = new java/io/InputStreamReader;
        paramString1.<init>(paramUserInfoDto, "gb2312");
        ((BufferedReader)paramObject).<init>(paramString1);
        paramUserInfoDto = new java/lang/StringBuffer;
        paramUserInfoDto.<init>();
        for (;;)
        {
          paramString1 = ((BufferedReader)paramObject).readLine();
          if (paramString1 == null) {
            break;
          }
          paramUserInfoDto.append(paramString1);
        }
        paramObject = (BaseModel)paramb.b(paramUserInfoDto.toString());
        return (T)paramObject;
      }
    }
複製程式碼

先記錄這些,後續有進展在繼續

相關文章