|
|
本帖最后由 逗比_滑稽 于 2025-2-13 05:40 编辑
Hello ,各位好久不见,自从上班之后没多少兴趣再搞逆向了 ,要不是现在上班太无聊了,想着写篇帖子打发打发时间,正好想到去年9月份有研究过一个软件,废话不多说,Start。
此篇的逆向对象就是
一木记账
关于此应用也是发了很多破解会员的教程,但是大部分都是破解了本地会员功能的,部分会员功能还是无法使用。
例如:语音记账,截图导入。
如果破解了本地会员使用这两个功能都会提示
而本次教程核心内容就是破解这两个服务器验证功能,并不是破解全部服务器功能,其它服务器功能大伙感兴趣可以自行研究 。
————————————————
回归正题,既然这两个功能是服务器功能,那么我们该采取什么方式破解 ?我们不妨先看此图。
这是开通会员权益页面,从这里我们能了解到开发者会给新注册的用户一天的时间体验会员功能,这时有的小伙伴应该就想到了 ,我们可以伪造成新用户,让服务器认为我们是新用户,一直白嫖这两个功能。既然思路有了,说干就干。
我们抓取一下语音记账的网络请求,记住下关键词
等下我们要在dex分析这网络请求。
通过这个网络请求,我们知道请求头有一段数字,而参数会传入账号Token,也就是令牌。而我们的目的就是伪造这两段信息,让服务器认定我们是新用户。
我们回到dex,通过刚刚得到的关键词搜索这个网络请求。
很轻松的就找到了,而且注释已经标明告诉了我们那串数字代表着用户id
这方法的两个参数,String是令牌,int是用户id
通过查找这网络请求方法的调用,我们就得到传入这两参数的核心方法
以此法我们也能得到截图导入的网络请求核心方法(这里就不多解释了)
收集到这么多信息,我们来捋一下。
现在得知了网络请求所会传入的参数
而且找到了这两功能的网络请求核心方法
- 语言记账:getSpeechToken
- 截图导入:getOcrToken
复制代码
以及了解到传入这两参数的具体位置
现在还差最后一步 ,我们需要在返回用户id和用户令牌的地方替换成新用户的id和令牌,从而欺骗服务器,那该怎么得到新用户的id和令牌呢 ?
答:抓取注册账号的网络请求
抓取到了注册账号的请求后,响应中就有我们所需要的令牌和id
到这里就要有代码基础的小伙伴了 ,你可以选择自写一个伪造用户注册账号的网络请求,或者说直接cv注册账号的代码来实现获取新用户id和新用户令牌。
我是直接取软件的代码进行请求的,这里就不展示怎么找了,直接给代码。
代码.zip【download】
- import com.wangc.bill.http.HttpManager;
- import com.wangc.bill.http.HttpService;
- import com.wangc.bill.http.entity.User;
- import com.wangc.bill.http.httpUtils.MyCallback;
- import com.wangc.bill.http.protocol.CommonBaseJson;
- import java.util.Random;
- import retrofit2.Call;
- import retrofit2.Response;
- import android.content.Context;
- import android.content.SharedPreferences;
- import android.content.SharedPreferences.Editor;
- import java.lang.reflect.Method;
- public class Main extends MyCallback {
- private int Ordinal;
- private String Name;
- private static Main Instance;
- private SharedPreferences.Editor Editor;
- private Main(String token, int id) {
- Ordinal = id;
- Name = token;
- }
- private Main(String str) {
- Post(str);
- }
- public static void main(String[] args) {
- init(null);
- new Main(getName(), getValue());
- setUserData(null);
- }
- public static String getName() {
- return Instance.Name;
- }
- public static int getValue() {
- return Instance.Ordinal;
- }
- public static void setUserData(Object obj) {
- if (obj instanceof User) {
- User user = (User) obj;
- user.setVipType(2);
- user.setVipTime(3755260800000L);
- }
- }
- public static void init(Context c) {
- SharedPreferences sp = c.getSharedPreferences("hjData", 0);
- long Time = System.currentTimeMillis();
- long Time2 = sp.getLong("Time", 0);
- if (Time2 == 0 || Time - Time2 > 43200000L) {
- StringBuffer sb = new StringBuffer("1");
- String str = "0123456789";
- Random ran = new Random();
- for (int i = 0; i < 10; i++) {
- sb.append(str.charAt(ran.nextInt(10)));
- }
- Instance = new Main(sb.toString());
- Instance.Editor = sp.edit();
- } else {
- Instance = new Main(sp.getString("Token", ""), sp.getInt("UserId", 0));
- }
- }
- private void Post(String qq) {
- try {
- //网络请求管理器
- HttpManager Http = HttpManager.getInstance();
- //网络请求服务
- Method HttpService = Http.getClass().getDeclaredMethod("getHttpService");
- HttpService.setAccessible(true);
- HttpService Service = (HttpService) HttpService.invoke(Http);
- //User
- String email = qq + "@qq.com";
- //获取实例
- User user = new User(email, "我爱记账", "");
- //设置邮箱
- user.setEmail(email);
- //设置密码
- user.setPassword("6201ED0369A2287B417946EA6CCDE21F");
- //设置apk签名
- user.setSignInfo("92344a8b478ac913b558ba2d040540ae");
- //设置渠道
- user.setChannel("kuan");
- //设置注册时间
- user.setRegisterTime(System.currentTimeMillis());
- //请求
- Call call = Service.addUserInfo(user);
- call.enqueue(this);
- } catch (Exception e) {
-
- }
- }
- @Override
- public void onFailure(Throwable th) {
- }
- @Override
- public void onResponse(Response response) {
- Object obj = response.body();
- if (obj != null) {
- CommonBaseJson Json = (CommonBaseJson) obj;
- if (Json.getCode() == 0) {
- Object obj2 = Json.getResult();
- if (obj2 != null) {
- User result = (User) obj2;
- //id
- Ordinal = result.getId();
- //令牌
- Name = Json.getToken();
- Editor.putString("Token", Name)
- .putInt("UserId", Ordinal)
- .putLong("Time", System.currentTimeMillis())
- .apply();
- }
- }
- }
- }
- }
复制代码
最后展示下如何使用这份代码,该代码除了提供破解服务器功能,以及提供破解本地会员,我一个一个讲。
注意:在修改前记得用mt管理器去除下签名校验哦
1.破解本地会员
搜索
- com.wangc.bill.http.protocol.CommonBaseJson
复制代码
定位getResult方法,在以下插入调用即可破解本地会员。
- invoke-static {v0}, Lcom/doubihuaji/Call;->setUserData(Ljava/lang/Object;)V
复制代码
2.破解服务器功能
因为我代码中采用的是12小时更换一次新用户,所以需要进行初始化,而且代码是有缺陷的,它是以1开头然后随机10位数字➕QQ邮箱,因为去年随便写的,如果本身存在已注册的账号是会出问题的,有精力的大佬可以稍微改进一下 。
搜索类
- com.wangc.bill.activity.MainActivity
复制代码
在onCreate方法插入调用进行初始化
- invoke-static {p0}, Lcom/doubihuaji/Call;->init(Landroid/content/Context;)V
复制代码
1.语音识别
搜索getSpeechToken方法,打开第一个结果在以下方法插入调用
- #新用户令牌
- invoke-static {}, Lcom/doubihuaji/Call;->getName()Ljava/lang/String;
- move-result-object v1
- #新用户id
- invoke-static {}, Lcom/doubihuaji/Call;->getValue()I
- move-result v2
复制代码
截图导入也按此法即可,搜索getOcrToken方法,在第一个结果插调用
最后我们重新打开软件(需要登录账号哦)
能够看到,这两个服务器功能都能正常使用了 ,我们顶着老用户账号id,实则用这两个功能的时候是顶着新用户账号id,下课。 |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
-
查看全部评分
总评分:好评 +27
金币 +30
|