首页
论坛
课程
招聘
[原创]破解某交(y)友(p)app的VIP&&半自动im机器人
2020-7-28 18:45 5368

[原创]破解某交(y)友(p)app的VIP&&半自动im机器人

2020-7-28 18:45
5368

原贴地址 http://zhaoxincheng.com/index.php/2020/07/27/%e7%a0%b4%e8%a7%a3%e6%9f%90%e4%ba%a4y%e5%8f%8bpapp%e7%9a%84vip/

案例

就不放了,某交(y)友(p)app

致谢

Youpk
环信IM文档
hanbing&&r0ysue

加固简单分析

拿到app就先拿到jadx中分析,发现这是36*加壳。
file
这是时候我们就要祭出脱壳神奇Youpk
Youpk的操作文档具体可以看Youpk的github,再次感谢Youpk。
我们在吧修复好的dex放在jadx中分析。
修复的很给力,也可以看出源代码基本没有混淆,这就更利于我们的分析了。
file

破解VIP

  • 利用Xposed/Frida破解
    我们首先打开这个app,在主页点到一个人->进去,点击私信,发现要开通会员才可以呢。
    file
    这时候就可以 祭出搜索大法。
    打开jadx-全局搜索这个关键词“成为会员”。
    file
    这里可以看到有两个相同的。进入看看看。
    file
    这两处都是,我们分析一下这两处。
  • 第一处

    else if (this.isVip <= 1) {
                          new CommomDialog(this, R.style.dialog, true, "成为会员才能私聊哦!", new CommomDialog.OnCloseListener() {
                              /* class com.**.**.main.user.UserInfoActivity.AnonymousClass6 */
    
                              /* JADX WARN: Type inference failed for: r0v0, types: [android.content.Context, com.**.**.main.user.UserInfoActivity] */
                              @Override // com.**.**.widget.dialog.CommomDialog.OnCloseListener
                              public void onClick(Dialog dialog, boolean z) {
                                  if (z) {
                                      UserInfoActivity.this.startActivity(new Intent((Context) UserInfoActivity.this, MembersActivity.class));
                                      dialog.dismiss();
                                  }
                              }
                          }).setTitle("温馨提示").setPositiveButton("开通会员").show();
                          return;
    

    else if 里面的this.isVip只有小于1才会进入,也就是提示让你开通会员。

  • 第二处

    if (this.isVip > 1) {
                          Intent intent = new Intent((Context) this, (Class<?>) ChatActivity.class);
                          intent.putExtra(UserCacheInfo.COLUMNNAME_USERIDIMID, this.user_id);
                          intent.putExtra("userId", this.user_imid);
                          startActivity(intent);
                          return;
                      }
                      new CommomDialog(this, R.style.dialog, true, "成为会员才能私聊哦!", new CommomDialog.OnCloseListener() {
                          /* class com.**.**.main.user.UserInfoActivity.AnonymousClass8 */
    
                          /* JADX WARN: Type inference failed for: r0v0, types: [android.content.Context, com.**.**.main.user.UserInfoActivity] */
                          @Override // com.u**.**.widget.dialog.CommomDialog.OnCloseListener
                          public void onClick(Dialog dialog, boolean z) {
                              if (z) {
                                  UserInfoActivity.this.startActivity(new Intent((Context) UserInfoActivity.this, MembersActivity.class));
                                  dialog.dismiss();
                              }
                          }
                      }).setTitle("温馨提示").setPositiveButton("开通会员").show();
                      return;
                  }
                  return;
    

    这里可以看到this.isVip 大于1的话就会提示“开通会员了呢”

  • 最后
    其实只要进入到this.isVip大于1那不就,,,,嘿嘿嘿
    继续分析一下这个isVip是在哪里赋值呢。查找用例。。。。。
    file
    找到啦。。我们改下返回值
    file
    我们这里frida改一下。
    献上代码
    这里还会有个小问题,就是这块类没在内存加载的时候会报错,这时候点下某人的主页就好了。

    Java.perform(function () {
      var pre = Java.use("com.***.***.utils.UncleSharedPreferences");
      pre.getInt.overload('android.content.Context', 'java.lang.String').implementation = function (a1, a2) {
          return 2;
      }
    })
    

    看看效果。。。
    file
    发过去了。。。
    但是我们需要一直用的话就要一个xposed的插件。
    这里app采用的36加固,那我们就不能用常规的classloader进行hook,直接用36壳的classloader进行hook。

       XposedHelpers.findAndHookMethod("com.stub.StubApp", loadPackageParam.classLoader, "attachBaseContext", Context.class, new XC_MethodHook() {
                  @Override
                  protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                      super.afterHookedMethod(param);
                      Context context = (Context) param.args[0];
                      ClassLoader classLoader = context.getClassLoader();
                      classLoaders = classLoader;
                      XposedHelpers.findAndHookMethod("com.***.***.utils.UncleSharedPreferences", classLoader, "getInt", Context.class, String.class, new XC_MethodHook() {
                          @Override
                          protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                          //设置返回值为2
                              param.setResult(2);
                          }
                      });
                      XposedHelpers.findAndHookMethod("com.***.***.utils.DateUtil", classLoader, "getDayDiff", Date.class, Date.class, new XC_MethodHook() {
                          @Override
                          protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                              param.setResult(0L);
                          }
                      });
    
                  }
              });
    

    好了完美。。。私聊小姐姐(**)们

  • 暗坑
    最后发现他们有个体验会员,到期就是放弃(退出)
    file
    那还能咋办,继续分析
    搜索大法
    file
    这里的if都是&&,一假则假。前边几个看着不好搞,就dayDiff入手,改他返回值,小于3就行了。
    file
    代码就不放了。
  • 小结
    这个vip的破解还是很简单的那种。。。
    这块其实可以通过拦截请求的方式更改数据包,将vip字段设置一下,没具体分析。

    聊天IM&&半自动im机器人

    根据com.hyphenate.chat.EMMessage可以得到这是环信的im聊天,那就很简单了。
    两种方式实现发消息:
  • 1.使用环信sdk,逆向该app的inti环境的一些配置信息,完成发消息。
  • 2使用app本身的消息发送方法,用frida或者xposed主动调用。
    这里由于没有pythonSdk,所以采用第二种。

    分析消息发送

    这里我们上ddms和环信的文档,分析它的调用情况。
    文档如下
    发送文本消息
    //创建一条文本消息,content为消息文字内容,toChatUsername为对方用户或者群聊的id,后文皆是如此
    EMMessage message = EMMessage.createTxtSendMessage(content, toChatUsername);
    //如果是群聊,设置chattype,默认是单聊
    if (chatType == CHATTYPE_GROUP)
      message.setChatType(ChatType.GroupChat);
    //发送消息
    EMClient.getInstance().chatManager().sendMessage(message);
    
    ddms如下
    file
    打开jadx分析这个类代码,可以看到如下
    file
    发送消息时候,创建了EMMessage.createTxtSendMessage,需要发送文本和对方的id。
    下面的代码是发送文本信息的
              if (this.chatFragmentHelper != null) {
                  this.chatFragmentHelper.onSetMessageAttributes(eMMessage);
              }
              if (this.chatType == 2) {
                  eMMessage.setChatType(EMMessage.ChatType.GroupChat);
              } else if (this.chatType == 3) {
                  eMMessage.setChatType(EMMessage.ChatType.ChatRoom);
              }
              EaseUser userInfo = EaseUserUtils.getUserInfo(eMMessage.getFrom(), UncleSharedPreferences.getString(SZApplication.getContext(), UncleSharedPreferences.SP_UID));
              eMMessage.setAttribute("avatar", userInfo.getAvatar());
              eMMessage.setAttribute("gender", UncleSharedPreferences.getString(SZApplication.getContext(), UncleSharedPreferences.SP_USER_SEX));
              eMMessage.setAttribute("name", userInfo.getNickname());
              eMMessage.setAttribute("token", UncleSharedPreferences.getString(SZApplication.getContext(), UncleSharedPreferences.SP_UID));
              if (UserCacheManager.getImidFromCache(this.toChatUsername) != null) {
                  eMMessage.setAttribute("tokenTo", UserCacheManager.getImidFromCache(this.toChatUsername).getUserId());
              } else {
                  eMMessage.setAttribute("tokenTo", "");
              }
              eMMessage.setAttribute("nameTo", eMMessage.getTo());
              eMMessage.setAttribute("avatarTo", UncleSharedPreferences.getString(SZApplication.getContext(), UncleSharedPreferences.SP_TO_USER_AVATAR));
    EMClient.getInstance().chatManager().saveMessage(eMMessage);
    
    知道上边的我们就可以用frida玩玩。
    var to_user_id = '1000477560';
          var content = '我是一个机器人你信吗';
          var uid = '1000511189';
          var EMMessage = Java.use("com.hyphenate.chat.EMMessage");
          var eMMessage = EMMessage.createTxtSendMessage(content, to_user_id);
          eMMessage.setAttribute("avatar", "http://***/android/pic/1591284964")//头像
          eMMessage.setAttribute("gender", "1")
          eMMessage.setAttribute("name", "看123了看刻录机")
          eMMessage.setAttribute("token", uid)//自己uid
          eMMessage.setAttribute("nameTo", to_user_id)//对方imid
          eMMessage.setAttribute("avatarTo", "")
          eMMessage.setAttribute("tokenTo", to_user_id)
          var EMClient = Java.use("com.hyphenate.chat.EMClient");
    EMClient.getInstance().chatManager().saveMessage(eMMessage)
    
    file
    发送之后,需要点进去聊天界面,才会发送过去,并且如果这个app没有缓存这个用户信息,就会闪退。

    解决闪退

    继续ddms,点击私信。
    file
    搜索startAc,可以看到在UserInfoActivity下
    file
    分析到如下代码,可以很清楚到看到,这里吧用户信息存起来了。然后启动聊天的tActivity。
         UserCacheManager.save(this.user_id, this.user_imid, this.nickname, this.avatar);
                      EaseUser easeUser = new EaseUser(this.user_imid);
                      easeUser.setAvatar(this.avatar);
                      easeUser.setNickname(this.nickname);
                      if (this.isVip > 1) {
                          Intent intent = new Intent((Context) this, (Class<?>) ChatActivity.class);
                          intent.putExtra(UserCacheInfo.COLUMNNAME_USERIDIMID, this.user_id);
                          intent.putExtra("userId", this.user_imid);
                          startActivity(intent);
                          return;
                      }
    
    这次用xposed实现发送消息和启动ui。
     Class EMMessage = XposedHelpers.findClass("com.hyphenate.chat.EMMessage", classLoaders);
          Object eMMessage = XposedHelpers.callStaticMethod(EMMessage, "createTxtSendMessage", content, to_user_id);
          XposedHelpers.callMethod(eMMessage, "setAttribute", "avatar", avatar);
          XposedHelpers.callMethod(eMMessage, "setAttribute", "gender", gender);
          XposedHelpers.callMethod(eMMessage, "setAttribute", "name", name);
          XposedHelpers.callMethod(eMMessage, "setAttribute", "token", token);
          XposedHelpers.callMethod(eMMessage, "setAttribute", "nameTo", nameTo);
          XposedHelpers.callMethod(eMMessage, "setAttribute", "avatarTo", avatarTo);
          XposedHelpers.callMethod(eMMessage, "setAttribute", "tokenTo", tokenTo);
          Class EMClient = XposedHelpers.findClass("com.hyphenate.chat.EMClient", classLoaders);
          Object getInstance = XposedHelpers.callStaticMethod(EMClient, "getInstance");
          Object chatManager = XposedHelpers.callMethod(getInstance, "chatManager");
          XposedHelpers.callMethod(chatManager, "saveMessage", eMMessage);
          Class ChatActivity = XposedHelpers.findClass("com.***.***.main.im.ChatActivity", classLoaders);
          Class UserCacheManager = XposedHelpers.findClass("com.***.***.main.im.cache.UserCacheManager", classLoaders);
          XposedHelpers.callStaticMethod(UserCacheManager, "save", to_user_id, to_user_id, to_user_id, avatar);
          Class EaseUser = XposedHelpers.findClass("com.hyphenate.easeui.domain.EaseUser", classLoaders);
          Object easeUsernewInstance = XposedHelpers.newInstance(EaseUser, to_user_id);
          XposedHelpers.callMethod(easeUsernewInstance, "setNickname", to_user_id);
          XposedHelpers.callMethod(easeUsernewInstance, "setAvatar", avatar);
          Intent intentChat = new Intent(contexts, ChatActivity);
          intentChat.putExtra("userImId", to_user_id);
          intentChat.putExtra("userId", to_user_id);
          contexts.startActivity(intentChat);
    
    这就基本完成了。

    效果展示

    最后借助NanoHTTPD做了web接口。看下效果

    总结

    这个app比较简单,虽然36加壳,但是通过youpk脱壳之后,发现基本没混淆。文中是借助ddms分析调用情况。这个可以继续扩展到,hook接收消息,收到消息之后,自动回复信息。
    接口在com...SZHelper$9.onMessageReceived上,以后有时间再分析写出来。

[公告]《安卓APP加固攻与防》训练营!Android逆向分析技能,干货满满,报名免费赠送一部手机!

最后于 2020-7-29 11:01 被mb_aoooaosd编辑 ,原因:
收藏
点赞2
打赏
分享
最新回复 (16)
雪    币: 625
活跃值: 活跃值 (142)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lianzhan 活跃值 2020-7-28 19:29
2
0
分析出来里面的小姐姐是不是真的没
雪    币: 223
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
python1024 活跃值 2020-7-28 19:49
3
0
我朋友想知道是什么app
雪    币: 3249
活跃值: 活跃值 (144)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
战马 活跃值 2020-7-28 21:17
4
0
里面的小姐姐明显是机器人,就是骗你充钱的
雪    币: 636
活跃值: 活跃值 (701)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
mb_aoooaosd 活跃值 2020-7-28 21:28
5
1
python1024 我朋友想知道是什么app
不 你没朋友
雪    币: 1152
活跃值: 活跃值 (219)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
caolinkai 活跃值 2020-7-29 09:11
6
0
66666
雪    币: 105
活跃值: 活跃值 (95)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
caicaihui 活跃值 2020-7-29 09:57
7
0
咱们这里缺的不是技术,缺的是样本
雪    币: 171
活跃值: 活跃值 (187)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
库尔 活跃值 2020-7-29 11:13
8
0
贴友阴阳怪气的
雪    币: 165
活跃值: 活跃值 (265)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
初学小潘 活跃值 2020-7-29 11:14
9
0
感谢分享
雪    币: 4
活跃值: 活跃值 (164)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
最懒人great 活跃值 2020-7-29 15:02
10
0

ddms分析调用情况    ,ddms 中parent 是 xxfromclick()Z  啊,第一个ddms ,你是怎么分析得到EMMessage.createTxtSendMessage的   ?

最后于 2020-7-29 15:05 被最懒人great编辑 ,原因:
雪    币: 636
活跃值: 活跃值 (701)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
mb_aoooaosd 活跃值 2020-7-29 23:01
11
0
最懒人great ddms分析调用情况&nbsp;&nbsp;&nbsp; ,ddms 中parent 是 xxfromclick()Z&nbsp; 啊,第一个ddms ,你是怎么分析得 ...
哥 ddms找到分析的类,createTxtSendMessage 有环信文档的
雪    币: 97
活跃值: 活跃值 (117)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
bbStudent 活跃值 2020-7-30 14:22
12
0
这种软件竟然是本地验证的,我还以为都是服务器鉴权呢
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
five_ayi 活跃值 2020-7-30 17:32
13
0
分析样本发一下,如果里面都是机器人就不用发了!
雪    币: 466
活跃值: 活跃值 (29)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
Gintoki 活跃值 2020-7-31 10:26
14
0
所有交友APP,难逃看雪一手
雪    币: 205
活跃值: 活跃值 (36)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
KnightKing 活跃值 2020-8-4 18:33
15
0
果然这类帖子容易吸引回复,楼猪高明
雪    币: 54
活跃值: 活跃值 (32)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
amazing3k 活跃值 2020-9-1 22:46
16
0
里面的小姐姐肯定都是机器人
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_hapxpitd 活跃值 2020-9-2 17:41
17
0
约到了吗我就想问
游客
登录 | 注册 方可回帖
返回