转载

破解某小说App(一)

想实现一个支持多渠道的小说App,因此对该小说App进行分析获取它的接口调用方式 该App详情页截图:

破解某小说App(一)

抓包

Charles抓取飞卢详情页面的接口

破解某小说App(一)

该小说App的域名是一个固定IP(试过几次退出登陆发现每次IP不一样,猜测是客户端写死的或者服务端下发,应该是防止域名被劫持吧)

上传的参数是一堆乱码,token也是乱码,

破解某小说App(一)

一般末尾是‘=’,应该是base64编码, 解密失败

破解某小说App(一)

返回内容居然是XML,author_name居然也是乱码,猜测是base64编码,使用站长工具Base64解密

破解某小说App(一)

感觉该App对数据加密做的很严谨,怪不得市场没有破解版

现在模拟它的请求只要破解它的token和参数就可以了

反编译

使用Android Studio打开该App,看到tencent_stub,应该是做个乐固加固了。

破解某小说App(一)

开始反编译

Mac上使用 Android CrackTool 进行反编译处理

破解某小说App(一)

反编译结果的确是乐固加固

破解某小说App(一)

加固包反编译

那开始对这个加固包进行反编译 参照这个文档 Android APK脱壳--腾讯乐固、360加固一键脱壳

使用脱壳工具FDex2

VirtualXposed:无需root手机即可使用xp框架。

dex进行dex2jar

这个步骤可以用Android Crack Tool上执行,执行成功之后,使用jdgui打开 搜索关键字 Xml4Android_relevantPage ,获取详情页

破解某小说App(一)

刷新详情页发现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;
      }
    }
复制代码

先记录这些,后续有进展在继续

原文  https://juejin.im/post/5c74f930518825622f13049c
正文到此结束
Loading...