背景
想实现一个支持多渠道的小说App,因此对该小说App进行分析获取它的接口调用方式 该App详情页截图:
抓包
Charles抓取飞卢详情页面的接口
该小说App的域名是一个固定IP(试过几次退出登陆发现每次IP不一样,猜测是客户端写死的或者服务端下发,应该是防止域名被劫持吧)
上传的参数是一堆乱码,token也是乱码,
一般末尾是‘=’,应该是base64编码,解密失败
返回内容居然是XML,author_name居然也是乱码,猜测是base64编码,使用站长工具Base64解密
感觉该App对数据加密做的很严谨,怪不得市场没有破解版
现在模拟它的请求只要破解它的token和参数就可以了
反编译
使用Android Studio打开该App,看到tencent_stub,应该是做个乐固加固了。
开始反编译
Mac上使用Android CrackTool进行反编译处理
反编译结果的确是乐固加固加固包反编译
那开始对这个加固包进行反编译 参照这个文档Android APK脱壳--腾讯乐固、360加固一键脱壳
使用脱壳工具FDex2
VirtualXposed:无需root手机即可使用xp框架。
dex进行dex2jar
这个步骤可以用Android Crack Tool上执行,执行成功之后,使用jdgui打开 搜索关键字Xml4Android_relevantPage
,获取详情页
刷新详情页发现Logcat中有日志
日志中有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;
}
}
复制代码
先记录这些,后续有进展在继续