mdschool-研究记录

这个mdschool app 我老早就打算研究。本周末的pwnhub的题目好难,而且还是web,我完全不会,所以干脆研究这个好了.

觅动校园 app研究记录

我第一次是从网上直接下载了apk然后进行观察,发现这个apk完全不能用啊,里面都是qihoo的保护内容,而且又是喜闻乐见的动态加载。总不能自己解析这个数据包吧,所以第二次,我就将app直接从手机上传到了电脑上(一开始还root啊各种花式操作,然后发现qq自带这个功能。。。)

首先将文件解压,然后将里面的.dex文件使用dex2jar转换成了jar文件,里面的内容大致如下:

仔细观察,发现这里的类中,只有一个叫做”huidong”的package比较可疑,其他的数据似乎都是辅助。然后我们来看看里面的文件结构:

箭头指向的这个很可能就是我们需要了解的觅动的相关函数,pbl是android app启动的时候用于初始化物理设备,引动系统内核启动的;zxing是实现二维码扫描的;meetwalk里面放置似乎是。。让我们想一想,觅动校园里面的主要功能分为:

  • 大家都不喜欢的打卡
  • 部分同学使用的正常社交功能
    如果说,箭头指向的位置表示的是【觅动】本身的社交功能,那么这个meetwalk可能就是记录行走相关的类。回想一下我们这次研究的最终目的,有一个就是找出打卡的真实过程,那么我们就很有必要好好研究一下这个package:
    这个package内部是这样的:

    GPSStepCountActivity.class

    这个类中记录了【打卡过程】,里面有【当前的打卡状态】,以及【打开的逻辑判定】

    GPSRouteActivity.class

    这个类记录的是【打卡是否完成】,以及提交的方位。
    通过搜索关键字【保存提交】,我们会将提交功能定位到目标函数:
    1
    private void savePoints()

函数的最后有以下内容:

1
GPSRouteActivity.this.http.httpRequest(5307, localHashMap, false, SaveRouteResult.class, true, false);

这个函数将会把我们的跑步数据上传到网上。也就是说,这个过程中有可能能够找到我们平时的数据都上传到了哪里。
接下来我们顺着访问httpRequest函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public void httpRequest(int paramInt, Map paramMap, boolean paramBoolean1, Class paramClass, boolean paramBoolean2, boolean paramBoolean3)
{
Log.e(paramInt + "请求参数", paramMap.toString());
if ((OnClickUtil.isMostPost()) && (lastRequestType == paramInt)) {
// 如果连续点击或者请求失败的话,那么不要传输
return;
}
if ((this.mContext instanceof BaseActivity)) {
if ((paramBoolean2) && (!((BaseActivity)this.mContext).loadingDialog.isShowing())) {
// 显示上传画面
((BaseActivity)this.mContext).loadingDialog.show();
}
}
for (;;)
{
lastRequestType = paramInt;
Log.d("httpRequest", "httpRequest发送");
this.paseUtil = new BasePaserMessageUtil();
//这里进行查找,这里返回的是str1 + "datewalk/createSportTrack.action";
String str = initUrl(paramInt);
this.httpTask = new HttpTask(paramInt, this.mHandler, str, this.mContext, paramMap, paramBoolean1, paramClass, this.paseUtil, paramBoolean3);
HttpTask localHttpTask = this.httpTask;
Executor localExecutor = AsyncTask.THREAD_POOL_EXECUTOR;
RequestMethod[] arrayOfRequestMethod = new RequestMethod[1];
arrayOfRequestMethod[0] = RequestMethod.POST;
localHttpTask.executeOnExecutor(localExecutor, arrayOfRequestMethod);
if (this.controlcurrentThread == null) {
break;
}
this.controlcurrentThread.getControlcurrentThread(this.httpTask);
return;
if (((this.mContext instanceof BaseFragmentActivity)) && (paramBoolean2) && (!((BaseFragmentActivity)this.mContext).loadingDialog.isShowing())) {
((BaseFragmentActivity)this.mContext).loadingDialog.show();
}
}
}
}

从代码看,这里的内容几乎就是发送的过程了。虽然不是太明白,但是大致内容就是发起了一个http请求,这个请求能够将我们的数据存放在服务器上的数据库中。
然后这里应该是将我们的数据上传,然而这个位置的str1的地址是啥呢?感觉这里不弄清楚就没有办法继续下去了。。
想起来比赛时候下载的BeCompare,于是将Constants.class导入,查找BASEURL,发现为
http://58.213.141.235:8080/qmjs_FEP/
那么也就是说,发送的地址就为:
http://58.213.141.235:8080/qmjs_FEP/datewalk/createSportTrack.action
这个地址就会将我们的数据上传上去。然后我们尝试访问
http://58.213.141.235:8080/qmjd_FEP
发现内容为

感觉已经很接近了,我们尝试访问我们的createSportTrack:

访问失败?看起来我们必须伪造一份请求数据(还的是json),然后里面有要求的元素的场合,我们才有可能成功访问。。。
那么我们回到原先的代码,看看都传输了什么数据过去:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
private void savePoints()
{
...
HashMap localHashMap = new HashMap();
// 检查登陆信息
GPSRouteActivity.this.checkLoginInfo();
localHashMap.put("userId", BodyBuildingUtil.mLoginEntity.getLoginEntity().getUserId());
// 注意关键变量gpsPositionModules
String str1;
if ((GPSRouteActivity.this.gpsPositionModules != null) && (GPSRouteActivity.this.gpsPositionModules.size() > 0))
{
// 参数【经度】
localHashMap.put("latitude", ((GPSPositionModule)GPSRouteActivity.this.gpsPositionModules.get(-1 + GPSRouteActivity.this.gpsPositionModules.size())).getLat() + "");
// 参数【维度】
localHashMap.put("longitude", ((GPSPositionModule)GPSRouteActivity.this.gpsPositionModules.get(-1 + GPSRouteActivity.this.gpsPositionModules.size())).getLng() + "");
// 参数【运动持续时间】
localHashMap.put("sportDuration", GPSRouteActivity.this.mTv_sport_time.getText().toString());
// 参数【英里数】
localHashMap.put("mileage", 1000.0D * Double.parseDouble(GPSRouteActivity.this.mTv_sport_km.getText().toString()) + "");
// 参数【运动种类】(?)
localHashMap.put("sportType", GPSRouteActivity.this.sportType);
// 参数【位置】
localHashMap.put("positions", GPSRouteActivity.this.gpsPositionModules);
// 参数【目标(?)】应该是那几个点
if (GPSRouteActivity.this.saveToTraget)
{
localHashMap.put("targetId", ((TargetModel)GPSRouteActivity.this.targets.get(GPSRouteActivity.this.chooseposition)).getTarget_release_id());
localHashMap.put("teamId", ((TargetModel)GPSRouteActivity.this.targets.get(GPSRouteActivity.this.chooseposition)).getTeam_ref_id());
}
// 参数【计步器种类】
localHashMap.put("pedomType", "2");
// 是否完成打卡(?)
if ((GPSRouteActivity.this.isOK == null) || (GPSRouteActivity.this.isOK.equals("0"))) {
// 跳转
break invalidCount;
}
if (!GPSRouteActivity.this.isOK.equals("1")) {
break beginCount;
}
str1 = "0";
label394:
localHashMap.put("isQualify", str1);
if (!GPSRouteActivity.this.isOK.equals("3")) {
break label602;
}
}
int i;
StringBuffer localStringBuffer;
beginCount:
label602:
for (String str2 = "3";; str2 = "1")
{
localHashMap.put("pedomType", str2);
i = 0;
localStringBuffer = new StringBuffer();
// 估计也就三个点
for (int j = 0; j < GPSRouteActivity.this.qmrtb.getTaskPointList().size(); j++)
{
// 检查这个跑步的点完成没有
if (((QueryMornRunTaskBean)GPSRouteActivity.this.qmrtb.getTaskPointList().get(j)).isComplete()) {
i++;
}
// 取出此时的任务id
localStringBuffer.append(((QueryMornRunTaskBean)GPSRouteActivity.this.qmrtb.getTaskPointList().get(j)).getTaskId() + ",");
}
Configuration localConfiguration = new Configuration(GPSRouteActivity.this.getApplicationContext());
// 再次设置经纬度
localHashMap.put("latitude", localConfiguration.getString("geoLat"));
localHashMap.put("longitude", localConfiguration.getString("geoLng"));
break;
str1 = "1";
break label394;
}
// 参数【有效打卡次数】
localHashMap.put("pointCount", "" + i);
// 参数【任务id】,一般为三个id
localHashMap.put("taskIds", localStringBuffer.toString());
invalidCount:
// 参数【无效的打卡个数】
localHashMap.put("invalidCount", "" + GPSRouteActivity.this.invalidCount);
// 重点!将当前参数发送请求
GPSRouteActivity.this.http.httpRequest(5307, localHashMap, false, SaveRouteResult.class, true, false);
return null;
}
protected void onPostExecute(Void paramAnonymousVoid)
{
super.onPostExecute(paramAnonymousVoid);
}
}.execute(new Void[0]);
}

从分析上看,这一段代码主要是在完成我们的跑步路线的设置,而我们的登陆过程显然不是在这里完成的,注意到一个函数:
GPSRouteActivity.this.checkLoginInfo();
这个函数将会检查我们的登陆信息,这个函数内容为

1
2
3
4
5
6
public void checkLoginInfo()
{
if (!StringUtil.isNotEmpty(BodyBuildingUtil.mLoginEntity.getLoginEntity().getUserId())) {
BodyBuildingUtil.mLoginEntity = new DataBaseManager(this).selectUserMessage();
}
}

就是一个简单的检查函数,关键就是这个BodyBuildUtil这个对象,里面似乎会存放我们的【个人登陆信息】。检查过程就不贴出来了。因为数据量太大了。。。想要看出来好像有点麻烦。。。。。。
所以我选择了ask question,结果居然是sun it
卧槽
惊了

以我的水平目前还是做不到的。。。这里就先搁着了。

3.6

学习了一下抓包的技巧,再次记录
首先让手机连接电脑打开的wifi,然后打开burpsuite
找到proxy下的options选项

然后选择add监听更多端口,并且设置如下:

接下来我们进入手机wifi的设置,设置无线的代理配置如下:

就能够通过burpsuite抓取手机上的数据包了!接下来我们查找有关http://58.213.141.235:8080/qmjs_FEP/datewalk/createSportTrack.action url的数据包,结果发现为:

原地爆炸!

这个body是个什么鸡!!!!!!!!!!为什么这么长长长长。。。。。。。。。。。仔细想了一下,header中并没有提到我们的奔跑数据,那么这个位置上的数据,就应该是我们GPS所记录的奔跑数据了。