当前位置: 首页 > news >正文

APP逆向——某站device-id参数(2)

免责声明

  1. 本博客所涉及的 爬虫技术、逆向分析方法 仅用于 学习、研究和技术交流
  2. 文中所有示例代码、工具和方法,均不得用于以下行为:
    • 未经授权的数据采集
    • 侵犯他人知识产权
    • 干扰或破坏正常业务系统
    • 任何违反国家法律法规的行为
  1. 因读者将本教程内容用于 非法用途 而产生的一切后果,由读者本人承担,本博客作者不承担任何法律及连带责任。
  2. 请在学习和实践过程中 遵守相关法律法规、网站/平台的服务协议及 robots 协议,合理合规地使用所学技术。

device-id

这其实就是设备id,可以直接随机生成就行,这里还是带着看一下

String a4 = com.bilibili.api.e.a();
if (!TextUtils.isEmpty(a4)) {aVar.h("Device-ID", a4);
}

直接看com.bilibili.api.e.a吧:

public class e {private static String a;public static String a() {return a;}public static void b(String str) {a = str;}
}

一样的也是b函数调用,可以用hook也可以直接查找用例,这里就不带大家找了:

public void run() {if (!j.a) {com.bilibili.api.d.b(j.c(this.a));}// 这是加密值com.bilibili.api.e.b(com.bilibili.lib.biliid.utils.f.a.c(this.a));
}

先找this.a:

a(Context context) {this.a = context;
}

context 上下文环境 —— 管理资源

Context 就是应用在 Android 系统中的运行环境,提供了操作资源、启动组件、获取系统服务的能力。

那么这里就不用管,直接看com.bilibili.lib.biliid.utils.f.a.c

public static String c(@Nullable Context context) {// 如果之前已经有缓存的 f13193c,就直接返回,避免重复计算if (!TextUtils.isEmpty(f13193c)) {return f13193c;}// 如果 context 是 null,啥也没法干,直接返回空字符串if (context == null) {return "";}// 从 e.k().f(context) 获取一个值(可能是存储的 ID)String f = c2.f.b0.c.a.e.k().f(context);f13193c = f;// 如果获取到的值非空,就直接返回if (!TextUtils.isEmpty(f)) {return f13193c;}// 如果还是没拿到,就调用 g(context) 生成一个新的 IDf13193c = g(context);// 把新生成的 ID 存起来(持久化到本地,比如 SharedPreferences)c2.f.b0.c.a.e.k().x(f13193c, context);// 返回最终的 IDreturn f13193c;
}// 前面很多都是从之前所说的存储中拿,重点看g函数
static String g(Context context) {// 1. 先调用 f(context) 获取一个基础值(可能是之前存储的 ID 或默认值)String f = f(context);// 2. 如果 f 太短(小于 4 个字符),说明无效,需要生成一个新的if (f.length() < 4) {// a. 获取 Android 系统 ID(每台设备唯一)String androidId = Settings.Secure.getString(context.getContentResolver(), "android_id");// b. 获取设备型号并进行处理(g.g(Build.MODEL))String modelHash = g.g(Build.MODEL);// c. 拼接 Android ID 和设备型号,形成一个新的字符串f = androidId + "@" + modelHash;}// 3. 对最终的字符串做进一步处理(b(f)return b(f);
}// 主要
String androidId = Settings.Secure.getString(context.getContentResolver(), "android_id"); // 之前获取过
// b. 获取设备型号并进行处理(g.g(Build.MODEL) 清除空格)
String modelHash = g.g(Build.MODEL);  // Build.MODEL:设备型号// c. 拼接 Android ID 和设备型号,形成一个新的字符串
f = androidId + "@" + modelHash;// b(f) : 自定义算法
public static String b(String str) {// 1. 将字符串转换成字节数组byte[] bytes = str.getBytes();// 2. 对第一个字节做异或运算,增加混淆性// bytes[0] = bytes[0] ^ (bytes.length & 255)bytes[0] = (byte) (bytes[0] ^ ((byte) (bytes.length & 255)));// 3. 从第二个字节开始,每个字节都和前一个字节异或for (int i = 1; i < bytes.length; i++) {bytes[i] = (byte) ((bytes[i - 1] ^ bytes[i]) & 255);}try {// 4. 将处理后的字节数组进行 Base64 编码(flags = 11)return new String(Base64.encode(bytes, 11));} catch (Exception unused) {// 5. 编码失败时,返回原始字符串return str;}
}

梳理好之后,就可以直接模拟出python代码(经过校验,是一致的):

def obfuscate_string(s: str) -> str:"""型号加密,不补 Base64 '='"""# 1. 将字符串转换成字节数组bytes_arr = bytearray(s.encode('utf-8'))if not bytes_arr:return s# 2. 对第一个字节做异或运算bytes_arr[0] = bytes_arr[0] ^ (len(bytes_arr) & 0xFF)# 3. 从第二个字节开始,每个字节都和前一个字节异或for i in range(1, len(bytes_arr)):bytes_arr[i] = (bytes_arr[i - 1] ^ bytes_arr[i]) & 0xFFtry:# 4. Base64 编码,URL-safe,并去掉结尾 '='encoded = base64.urlsafe_b64encode(bytes_arr)return encoded.decode('utf-8').rstrip('=')except Exception:# 5. 编码失败时返回原始字符串return sdef get_device_id():"""获取device_id"""androidId = '5d01aa95f9aca38c'models = ["Pixel 7", "Redmi K50", "ONEPLUS 9 Pro", "Vivo V23", "MI 12X","SM-G998B", "Xiaomi 11T", "OPPO Reno8", "Pixel 7 Pro", "Lenovo Legion Y90","Realme GT Neo3", "MI 11 Ultra", "Redmi Note 11", "ONEPLUS A6013", "VOG-L29","P50 Pro", "OPPO Find X5", "Vivo X80", "Pixel 6a", "Redmi K40","SM-G991U", "Xiaomi 12S", "Realme GT", "ONEPLUS 8T", "Vivo Y76","OPPO Reno7", "MI 10 Pro", "Pixel 5", "Lenovo K12 Pro", "Redmi Note 10","SM-G990F"]model = random.choice(models)modelHash = model.replace(' ', '').strip()return obfuscate_string(androidId + "@" + modelHash)
http://www.dtcms.com/a/349199.html

相关文章:

  • 56 C++ 现代C++编程艺术5-万能引用
  • Linux内核ELF文件签名验证机制的设计与实现(C/C++代码实现)
  • DeepSeek对采用nginx实现透传以解决OpenShift 4.x 私有数据中心和公有云混合部署一套集群的解答
  • 机床智能健康管理系统:工业母机数字化转型的核心引擎​
  • 在mysql中,modify ,change ,rename to的作用是什么
  • AI使用日志(一)--Cursor和Claude code初体验
  • 用 Python 探索二分查找算法:从基本原理到实战最佳实践
  • 自回归(Auto-Regressive, AR),自回归图像生成过程
  • 【Canvas与旗帜】蓝圈汤加旗
  • 基于蓝牙的stm32智能火灾烟雾报警系统设计
  • 一个高度精简但结构完整的微服务示例
  • 敏感电阻简单介绍
  • Java 创建线程的几种方式
  • Python复数运算完全指南:从基础到工程级应用实践
  • Hyperledger Fabric官方中文教程-改进笔记(十六)-策略(policy)
  • 【Luogu】P4127 [AHOI2009] 同类分布 (数位DP)
  • 【知识杂记】卡尔曼滤波相关知识高频问答
  • Java 中 Set 接口(更新版)
  • 深度学习中的“集体智慧”:Dropout技术详解——不仅是防止过拟合,更是模型集成的革命
  • Java静态代理与动态代理实战解析
  • redis集群模式 -批量操作
  • 智慧工业设备巡检误报率↓81%!陌讯多模态融合算法实战优化与边缘部署
  • 【机器学习】6 Frequentist statistics
  • (计算机网络)JWT三部分及 Signature 作用
  • 车企数据资产管理——解读46页大型车企数据资产数据治理体系解决方案【附全文阅读】
  • 计算机系统 C语言运行时对应内存映射 以及 各个段的数据访问下标越界产生的后果
  • Delphi 12 基于 Indy 的 WebServer 的 https 实现的问题
  • HiRAG:用分层知识图解决复杂推理问题
  • ruoyi框架角色分配用户
  • imx6ull-驱动开发篇38——Linux INPUT 子系统