yutao531315 发表于 2020-4-1 23:09

xxxx99游戏盒子登录协议分析,附协议登录实现源码

本帖最后由 yutao531315 于 2020-4-1 23:31 编辑

因为疫情关系,在家里失业,()因为闲来无事,我在前几天发了一个帖子,也是关于这个盒子的,但是很凌乱,今天我就一个字,一个字的把流程 ,全部打出来,记录我分析的过程。
知识储备。1 较为熟练java语言,跟着程序逻辑走,寻找关键点
                  2 熟悉samll代码,因为我们跟到关键位置了,得知道传入的准确参数,得动态调试small
                  3ARM汇编,本文不需要你懂汇编,因为我们把他的so 拷贝过来直接调用传参就可以
                  4 瞎折腾,爱折腾,不达到目的饭都吃不下。

需求,做协议登录 第一步要做的就是抓包,



提交网址
POST https://mapi.4399api.net/user/box/android/v1.0/log-in.html

post提交数据
dateline=1585152691&
deviceIdentifier=865166028184599&
info=1&
model=xiaomi+8&
password=lKbiScPzO7%2BARbqYcynHTQ%3D%3D&
sign=0809033c79e0897036c8abef08b67371&
username=yutao531315




从抓包信息里面,我们可以获取很多信息。
1),提交的网址信息
2),可以看出字段
       dateline=1585152691&=865166028184599&
info=1&
model=xiaomi+8&
password=lKbiScPzO7%2BARbqYcynHTQ%3D%3D&
sign=0809033c79e0897036c8abef08b67371&
username=yutao531315
dateline字段   是时间节信息
deviceIdentifier 未知...

通过上面的分析,
Username 账号字段,未加密。
password 密码,字段加密
sig 字段 属于关键字段,需要找到来源
总结
就是找到密码字段,跟sig字段 来源,整个就算ok了。其他我们可以写死。

说干就干,拿出神器 反编译神器。
AndroidKiller反编译。这里我通过网址( v1.0/log-in.html)搜索定位关键单。

找到一个结果,接着搜索类目->方法名
Lcom/m4399/gamecenter/plugin/main/f/ay/ae;->loadData(Lcom/m4399/framework/net/ILoadPageEventListener;)V
看到结果,是tt 方法调用,接着搜索
Lcom/m4399/gamecenter/plugin/main/controllers/user/LoginFragment;->tt()V
定位到 onclick方法,是一个按钮点击事件,这里就是我们点击登录,所调用的逻辑。

看到方法onclick所在的类。
public Lcom/m4399/gamecenter/plugin/main/controllers/user/LoginFragment;

接着我们打开,安卓反编译神器。jadx-gui,把我们的目标程序拖进去反编译。然后找到方法所在的类。

进入。。onclick 查看java代码。



public void onClick(View view) {
      switch (view.getId()) {
            case R.id.btn_clear_text /*2134574883*/:
                if (view.getParent() == this.bat.getParent()) {
                  this.bat.setText("");
                  return;
                } else if (view.getParent() == this.bau.getParent()) {
                  this.bau.setText("");
                  return;
                } else {
                  this.bav.setText("");
                  return;
                }
            case R.id.ib_user_history /*2134574884*/:
                ts();
                if (this.baz.getDataCount() != 0) {
                  if (!this.baz.isShow()) {
                        this.bax.setImageResource(R.mipmap.m4399_png_btn_input_more_up);
                  }
                  this.baz.show();
                } else {
                  ToastUtils.showToast(getActivity(), (int) R.string.auth_user_history_is_null);
                }
                KeyboardUtils.hideKeyboard(getContext(), this.bat);
                return;
            case R.id.btn_look_pwd /*2134574886*/:
                int selectionStart;
                if (this.aQk.isSelected()) {
                  this.aQk.setSelected(false);
                  selectionStart = this.bau.getSelectionStart();
                  this.bau.setInputType(s.LOR);
                  this.bau.setSelection(selectionStart);
                  return;
                }
                this.aQk.setSelected(true);
                if (this.bau != null) {
                  selectionStart = this.bau.getSelectionStart();
                } else {
                  selectionStart = 0;
                }
                this.bau.setInputType(128);
                this.bau.setSelection(selectionStart);
                return;
            case R.id.btn_register /*2134574888*/://
                Bundle bundle = new Bundle();
                Bundle extras = getActivity().getIntent().getExtras();
                if (extras != null) {
                  bundle.putAll(extras);
                }
                bundle.putInt("EXTRA_AUTH_TYPE_KEY", this.baC);
                GameCenterRouterManager.getInstance().openRegister(getActivity(), bundle);
                ba.onEvent("ad_login_register");
                return;
            case R.id.login_button /*2134574889*/://看按钮名称,login_button明显带有登录逻辑
                ba.onEvent("ad_login_login_click");
                tt();//调用了TT方法 ,点击进去查看
                return;
            case R.id.btn_forget_pwd /*2134574890*/:
                Bundle bundle2 = new Bundle();
                bundle2.putString("intent.extra.webview.title", getString(R.string.found_my_pwd));
                bundle2.putString("intent.extra.webview.url", REDIRECT_URI_FIND_PWD + "&_d=" + ((String) Config.getValue(SysConfigKey.UNIQUEID)));
                GameCenterRouterManager.getInstance().openWebViewActivity(getActivity(), bundle2, new int);
                return;
            default:
                super.onClick(view);
                return;
      }
    }

通过分析,R.id.login_button   此方法是明显的登录逻辑,我们进入tt方法。
private void tt() {
      String obj = this.bat.getText().toString();//获取编辑框账号信息,
      String obj2 = this.bau.getText().toString();//获取编辑框密码信息
      if (UserCenterManager.isLogin().booleanValue() && !TextUtils.isEmpty(obj) && obj.trim().equals(UserCenterManager.getUserName())) {
            ToastUtils.showToast(getContext(), getString(R.string.login_fragment_login_already, obj));
            return;
      }
      CaptchaModel captchaModel = this.mCaptchaDataProvider.getCaptchaModel();
      if (verifyAuthInfo(obj, 1) && verifyAuthInfo(obj2, 0)) {
            final ae aeVar = new ae();
            if (!captchaModel.isEmpty()) {
                if (verifyAuthInfo(this.mCaptchaView.getInputedCaptcha(), 4)) {
                  aeVar.setCaptcha(this.mCaptchaView.getInputedCaptcha());
                  aeVar.setCaptchaId(captchaModel.getCaptchaId());
                } else {
                  return;
                }
            }
            aeVar.setPassword(obj2);//把账号信息,赋值给Password
            aeVar.setUsername(obj);//把密码信息,赋值给Username
            UserCenterManager.setIsAllowNotifyUserPropertyChange(false);
            aeVar.loadData(new ILoadPageEventListener() {//调用一个load 方法,
                public void onBefore() {
                  try {
                        LoginFragment.this.mDialog = new CommonLoadingDialog(LoginFragment.this.getContext());
                        LoginFragment.this.mDialog.show((int) R.string.loading_logining);
                  } catch (Exception e) {
                        e.printStackTrace();
                  }
                }

                public void onSuccess() {
                  UserCenterManager.getInstance().onLoginSuccess(aeVar.getUser());
                }

                public void onFailure(Throwable th, int i, String str, int i2, JSONObject jSONObject) {
                  LoginFragment.this.onLoginFinish(HttpResultTipUtils.getFailureTip(LoginFragment.this.getActivity(), th, i, str));
                }
            });
      }
    }

进入
aeVar.loadData(new ILoadPageEventListener() {//进入loadData
看到
public void loadData(ILoadPageEventListener iLoadPageEventListener) {
      super.loadData("user/box/android/v1.0/log-in.html", 2, iLoadPageEventListener);
    }



super关键字
这里我还得说下,我们现在进入的 ae方法,继承自c 方法
class ae extends c {

而super 关键字是调用其父类的方法。就是C方法,呸呸 不要说了!这里很关键也很容易理解错,要是不懂,可以多学习java代码,对你逆向java层每句代码的含有很有作用,因为我也是在学习中我也是编程渣渣。

接着继续进入loadData 方法


再次调用父类的loadData 方法
super.loadData(str, i, new ILoadPageEventListener() {


通过观察LoadData 类 buildRequestParams方法


里面有一个
public abstract void buildRequestParams(String str, ArrayMap arrayMap);

进去看到了是一个抽象方法,抽象方法根据我们的java知识,这个方法一定在其子类有实现
我们在回到ae 方法搜索 buildRequestParams
找到起抽象方法实现的位置。


继续super 调用父类方法,查看到put sig字段,s


sig 字段来源于。。。getServerApi
public String buildSignValue(String str) {
      return AppNativeHelper.getServerApi(str);
    }



而sig 字段来源于,
public static final native String getServerApi(String str);


一个native 修饰的方法,说明其具体逻辑实现是来之so层。
看到传入了一个参数,String,这个就是一个集合 。时间节 (系统获取 )         iemi(手机的iemi数据)       info(写死)    密码加密后的密文()      明文用户名
1585640327865166028184599 1            ytHJhV3wqmT/b5tVr8Qxvw==         yutao531315参与sig字段计算的就全部出来了!
    时间节            IEMI                     info         密码加密后的字段 用户名

哎呀,我去,终于给分析到这里了,真累,我其实目的很简单,就想请版主加一个精 ,大家如果觉得好可以帮我顶上去,谢谢大家了。
还有一个告诉大家,这里字段来源,是动态调试small代码,得到的,

然后呢,sig字段已经给分析出来了,sig字段里面包含的都是一些,上传的基本信息, <用户名><时间节><密码><IEMI>   其实也还好,上传的数据不是很多。


接着就要分析pasword 字段,我们继续看java代码。



同样是一个抽象方法,在其子类 找到其实现的位置。

public void buildSignRequestParams(String str, ArrayMap<String, String> arrayMap) {
      arrayMap.put("username", this.mUsername);
      this.bcd = AppNativeHelper.desCbcEncrypt(this.bcd);//bcd 传入我们输入的密码。调用了一个DesCbcENcrypt,这个方法也是在native 修饰的关键词,逻辑,在so里面
      arrayMap.put("password", this.bcd);//把密码字段put进集合。
      arrayMap.put("deviceIdentifier", (String) Config.getValue(SysConfigKey.UNIQUEID));
      arrayMap.put("captcha", this.mCaptcha);
      arrayMap.put(Captcha.CAPTCHA_ID, this.mCaptchaId);
      arrayMap.put("info", "1");
      arrayMap.put("dateline", "" + (NetworkDataProvider.getNetworkDateline() / 1000));
    }
1 ,到这里了,此apk算是全部分析出来了。哦对了,还要告诉大家,我为了这篇文章,我整整搞了三天,本来最开始想把so层加密字段也给分析出来,奈何分析了一部分,觉得有点累,动态调试so的目的,也是加强我的汇编能力。
分析了一部分,


这个xx99游戏盒子,算是分析完了。

啊,这就算完了,nono 我们还没完,我们要自己编写程序实现登录,也得在自己的程序里面实现啊,

这里我是用的 调用他的so 里面的方法,
java代码实现效果,

然后是其实现效果.......



算是真正的完了!!!!!!写了整整一天,累死了,
后期如果我时间允许,我会在把P多多跟J东的也会写出来,与君共勉。学而不息

骇客之技术 发表于 2020-11-11 11:24

我一般hook打印参数,hook用fridaxposed即可, 楼主没分析关键算法,分析了java层逻辑,可以学习~

yutao531315 发表于 2020-4-1 23:18

18754408308 发表于 2020-4-1 23:17
加油加油

{:1_918:}觉得有用,评分一个

橡鳄君 发表于 2020-4-2 00:06

这不错( ゚∀ ゚)

方圆天下 发表于 2020-4-2 06:58

大神厉害!!!!!!!!

老狼客 发表于 2020-4-2 07:07

厉害,意志顽强!

qaz007 发表于 2020-4-2 08:21

厉害, 加油!

Kxt163 发表于 2020-4-2 08:37

很厉害,写了这么多{:1_921:}

weezyBC 发表于 2020-4-2 08:47

厉害厉害{:1_921:}

Air. 发表于 2020-4-2 10:14

LZ啥专业啊
!学习这个会掉很多头发吗

柒汐 发表于 2020-4-2 10:17

楼主很强~厉害~
页: [1] 2
查看完整版本: xxxx99游戏盒子登录协议分析,附协议登录实现源码