没有样品
提供!
准备工具:
1、反编译工具
2、java2smali
3、绿叶
本教程不适合小白。软件样品为当前最新版8.1.0,随时可能失效。软件有签名校验,就不再分析了,用工具一键hook即可。软件免费会员只有24小时,时间不算长,用来救急还是不错的选择。软件有广告,观看广告或者签到之后可以获取一定时长的会员。
像一些抓包或者事前准备就不说了,略过,直接讲重点。先看一下app界面。
1.png (60.49 KB, 下载次数: 4)
下载附件
2020-12-8 21:14 上传
这个加速器新用户送24小时的黄金会员,而且是自动注册的,安装注册后再卸载重装并没有重置会员状态,那么考虑是获取了设备id进行了一个验证。
我试过对vip进行赋值,即使显示绿金会员还是提示了“会员到期”,所以这款app是服务器验证的,那入手点就从免费送24小时会员那里切入。
首先我想到的思路是让这个app获取一个随机ID,以此来逃避用户检查。当然方法很多,比如用xp框架改、抓包或者在虚拟机里面运行都是可以办到的。但是这样只是改了和app无关的东西,有点差强人意。所以我直接硬杠app。
实际上大部分app进行设备封号基本上都会获取id,至于还获取了什么这就要看开发者了,但是设备id不会缺席,每次都有它。
反编译后直接搜索字符串【deviceId】,有几个结果,进入到SplashActivity。如下图:
1.png (78.19 KB, 下载次数: 6)
下载附件
2020-12-8 21:30 上传
public static String j(Context context) {
SharedPreferences a = e.a(context);
String string = a.getString("pref_local_device_id", "");
if (!string.equals("")) {
return string;
}
String string2 = Settings.Secure.getString(context.getContentResolver(), "android_id");
if (f.j(string2) || "9774d56d682e549c".equals(string2)) {
string2 = UUID.randomUUID().toString();
}
a.edit().putString("pref_local_device_id", string2).commit();
return string2;
}
然后跳转跟进j,原本的Java如上。这个方法有个明显的randomUUID,还有一个字符串9774d56d682e549c,这个字符串是什么可以百度看一下。所以的话它的老巢就是这里,启动的时候app从这个方法获取了设备id,然后上传到服务器进行注册,如果是新id就是新用户了,所以你卸载重装是没有用的。
根据它的id格式9774d56d682e549c,我现在要让这个方法产生一个随机16位的字符串,并包含小写字母和数字,看看能不能欺骗服务器。
先写一段Java给他安排上:
public class Utils {
public static String j(int length) {
int a = 16;
String KeyString = "123456789abcdef";
int len = KeyString.length();
StringBuffer sb = new StringBuffer();
for(int i=0;i
因为这个写法是万用的,所以在一些场景中是非常有效的改法。
其中代码中的16是字符串的长度,可以根据需求随便改,如果你想产生8位随机数就写8。然后123456789abcdef就是字库,从里面抽取进行排列,你想抽什么就放什么。因为16进制没有那么多的字母,所以只保留到f,又因为开头我感觉应该不会是0,所以0也去掉了。
然后把这段Java转换成smali,就得到了下面这个:
.class public LUtils;
.super Ljava/lang/Object;
.source "Utils.java"
# direct methods
.method public constructor ()V
.registers 1
.prologue
.line 1
invoke-direct {p0}, Ljava/lang/Object;->()V
return-void
.end method
.method public static j(I)Ljava/lang/String;
.registers 11
.prologue
.line 5
const/16 v1, 0x10
.line 6
const-string v2, "123456789abcdef"
.line 7
invoke-virtual {v2}, Ljava/lang/String;->length()I
move-result v3
.line 8
new-instance v4, Ljava/lang/StringBuffer;
invoke-direct {v4}, Ljava/lang/StringBuffer;->()V
.line 9
const/4 v0, 0x0
:goto_e
if-ge v0, v1, :cond_27
.line 10
invoke-static {}, Ljava/lang/Math;->random()D
move-result-wide v6
add-int/lit8 v5, v3, -0x1
int-to-double v8, v5
mul-double/2addr v6, v8
invoke-static {v6, v7}, Ljava/lang/Math;->round(D)J
move-result-wide v6
long-to-int v5, v6
invoke-virtual {v2, v5}, Ljava/lang/String;->charAt(I)C
move-result v5
invoke-virtual {v4, v5}, Ljava/lang/StringBuffer;->append(C)Ljava/lang/StringBuffer;
.line 9
add-int/lit8 v0, v0, 0x1
goto :goto_e
.line 12
:cond_27
invoke-virtual {v4}, Ljava/lang/StringBuffer;->toString()Ljava/lang/String;
move-result-object v0
return-object v0
.end method
我们只需要提取方法中的代码就可以了,其它不用理。
把这段代码覆盖到原来的方法里面去,然后回编译试一下。
1.png (81.38 KB, 下载次数: 3)
下载附件
2020-12-8 21:58 上传
结果还是……
好吧这样行不通。虽然产生了一个随机的设备id,但还是无法进行新用户注册。观察到这个app多次获取了id,开发者可能也想到了这个,如果出现变动那么肯定有问题。
那现在继续换另一种思路,直接写死id。
1.png (57.5 KB, 下载次数: 0)
下载附件
2020-12-8 22:04 上传
这个随便填,然后回编译测试一下。启动时先清除app所有数据,防止本地数据不一致,然后再打开。
1.png (97.96 KB, 下载次数: 0)
下载附件
2020-12-8 22:08 上传
成功!
1.jpg (5.11 KB, 下载次数: 0)
下载附件
2020-12-9 10:20 上传
过期的时候改一下id无限续命。
当然,如果你想随机抽取固定字符串的话,还可以这样设计,举例:
public class Test
{
public Test()
{
}
public static String num(String s)
{
int i = (int)(Math.random() * 5D);
return (new String[] {
"3452788", "8689967857", "8765785", "885755", "879785475"
});
}
}
代码中的数字就是要抽取的字符串,5D就是在5个之中抽取。
转换成smali代码就是:
.class public LTest;
.super Ljava/lang/Object;
.source "Test.java"
# direct methods
.method public constructor ()V
.registers 1
.prologue
.line 6
invoke-direct {p0}, Ljava/lang/Object;->()V
.line 7
return-void
.end method
.method public static num(Ljava/lang/String;)Ljava/lang/String;
.registers 5
.prologue
.line 11
invoke-static {}, Ljava/lang/Math;->random()D
move-result-wide v0
const-wide/high16 v2, 0x4014000000000000L # 5.0
mul-double/2addr v0, v2
double-to-int v0, v0
.line 12
const/4 v1, 0x5
new-array v1, v1, [Ljava/lang/String;
const/4 v2, 0x0
const-string v3, "3452788"
aput-object v3, v1, v2
const/4 v2, 0x1
const-string v3, "8689967857"
aput-object v3, v1, v2
const/4 v2, 0x2
const-string v3, "8765785"
aput-object v3, v1, v2
const/4 v2, 0x3
const-string v3, "885755"
aput-object v3, v1, v2
const/4 v2, 0x4
const-string v3, "879785475"
aput-object v3, v1, v2
aget-object v0, v1, v0
return-object v0
.end method