本帖最后由 yutao531315 于 2020-4-1 23:31 编辑
因为疫情关系,在家里失业,()因为闲来无事,我在前几天发了一个帖子,也是关于这个盒子的,但是很凌乱,今天我就一个字,一个字的把流程 ,全部打出来,记录我分析的过程。
知识储备。1 较为熟练java语言,跟着程序逻辑走,寻找关键点
2 熟悉samll代码,因为我们跟到关键位置了,得知道传入的准确参数,得动态调试small
3 ARM汇编,本文不需要你懂汇编,因为我们把他的so 拷贝过来直接调用传参就可以
4 瞎折腾,爱折腾,不达到目的饭都吃不下。
需求 ,做协议登录 第一步要做的就是抓包,
提交网址
[Asm] 纯文本查看 复制代码 POST [url=https://mapi.4399api.net/user/box/android/v1.0/log-in.html]https://mapi.4399api.net/user/box/android/v1.0/log-in.html[/url]
post提交数据
[Asm] 纯文本查看 复制代码 dateline=1585152691&
deviceIdentifier=865166028184599&
info=1&
model=xiaomi+8&
password=lKbiScPzO7%2BARbqYcynHTQ%3D%3D&
sign=0809033c79e0897036c8abef08b67371&
username=yutao531315
从抓包信息里面,我们可以获取很多信息。
1),提交的网址信息
2) ,可以看出字段
[Asm] 纯文本查看 复制代码 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)搜索定位关键单。
找到一个结果,接着搜索 类目->方法名
[Asm] 纯文本查看 复制代码 Lcom/m4399/gamecenter/plugin/main/f/ay/ae;->loadData(Lcom/m4399/framework/net/ILoadPageEventListener;)V
看到结果,是tt 方法调用,接着搜索
[Asm] 纯文本查看 复制代码 Lcom/m4399/gamecenter/plugin/main/controllers/user/LoginFragment;->tt()V
定位到 onclick方法,是一个按钮点击事件,这里就是我们点击登录,所调用的逻辑。
看到方法onclick所在的类。
[Asm] 纯文本查看 复制代码 public Lcom/m4399/gamecenter/plugin/main/controllers/user/LoginFragment;
接着我们打开,安卓反编译神器。jadx-gui,把我们的目标程序拖进去反编译。然后找到方法所在的类。
进入。。onclick 查看java代码。
[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[0]);
return;
default:
super.onClick(view);
return;
}
}
通过分析,R.id.login_button 此方法是明显的登录逻辑,我们进入tt方法。
[Java] 纯文本查看 复制代码 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));
}
});
}
}
进入
[Asm] 纯文本查看 复制代码 aeVar.loadData(new ILoadPageEventListener() {//进入loadData
看到
[Java] 纯文本查看 复制代码 public void loadData(ILoadPageEventListener iLoadPageEventListener) {
super.loadData("user/box/android/v1.0/log-in.html", 2, iLoadPageEventListener);
}
super关键字
这里我还得说下,我们现在进入的 ae方法,继承自c 方法
[Asm] 纯文本查看 复制代码 class ae extends c {
而super 关键字是调用其父类的方法。就是C方法,呸呸 不要说了!这里很关键也很容易理解错,要是不懂,可以多学习java代码,对你逆向java层每句代码的含有很有作用,因为我也是在学习中我也是编程渣渣。
接着继续进入loadData 方法
再次调用父类的loadData 方法
[Asm] 纯文本查看 复制代码 super.loadData(str, i, new ILoadPageEventListener() {
通过观察LoadData 类 buildRequestParams方法
里面有一个
[Asm] 纯文本查看 复制代码 public abstract void buildRequestParams(String str, ArrayMap arrayMap);
进去看到了是一个抽象方法,抽象方法根据我们的java知识,这个方法一定在其子类有实现
我们在回到ae 方法 搜索 buildRequestParams
找到起抽象方法实现的位置。
继续super 调用父类方法,查看到put sig字段,s
sig 字段来源于。。。getServerApi
[Asm] 纯文本查看 复制代码 public String buildSignValue(String str) {
return AppNativeHelper.getServerApi(str);
}
而sig 字段来源于,
[Asm] 纯文本查看 复制代码 public static final native String getServerApi(String str);
一个native 修饰的方法,说明其具体逻辑实现是来之so层。
看到传入了一个参数,String ,这个就是一个集合 。时间节 (系统获取 ) iemi (手机的iemi数据) info(写死) 密码加密后的密文() 明文用户名
[Asm] 纯文本查看 复制代码 1585640327 865166028184599 1 ytHJhV3wqmT/b5tVr8Qxvw== yutao531315 参与sig字段计算的就全部出来了!
时间节 IEMI info 密码加密后的字段 用户名
哎呀,我去,终于给分析到这里了,真累,我其实目的很简单,就想请版主加一个精 ,大家如果觉得好可以帮我顶上去,谢谢大家了。
还有一个告诉大家,这里字段来源,是动态调试small代码,得到的,
然后呢,sig字段已经给分析出来了,sig字段里面包含的都是一些,上传的基本信息, <用户名><时间节><密码><IEMI> 其实也还好,上传的数据不是很多。
接着就要分析pasword 字段,我们继续看java代码。
同样是一个抽象方法,在其子类 找到其实现的位置。
[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游戏盒子,算是分析完了。
啊,这就算完了,no no 我们还没完,我们要自己编写程序实现登录,也得在自己的程序里面实现啊,
这里我是用的 调用他的so 里面的方法,
java代码实现效果,
然后是其实现效果.......
算是真正的完了!!!!!!写了整整一天,累死了,
后期如果我时间允许,我会在把P多多 跟J东的也会写出来,与君共勉。学而不息
|