前言

在分析华为 agps 的位置获取具体实现逻辑时,通过抓包发现有一条发送到高德的数据流;

agps 的原理是手机通过移动网络向基站的 agps 服务器请求得到当前位置的卫星星历信息(包括仰角、轨道等),拿到星历信息后再 进行运算出当前设备的伪距信息,最后将伪距信息传送到 agps 服务器并最终得到手机终端的具体 gps 信息返回到设备。

通过抓包得到的是一条 走 wifi 流量的高德数据;是在返回当前位置的时候开始发送的(onLocationChanged 函数返回);

当前的手机是华为手机,在打算分析华为 rom 的时候,拆解 rom,发现有个 高德位置服务.apk ,遂分析该 apk。

包名是: com.amap.android.ams

结论:

高德位置服务会采集当前设备内很多信息。

抓到的数据流

上报的数据是经过 gzip 的编码处理;

可以将抓包数据转成 byte 流之后,再试用 gzip -d filename 命令解码;

POST /APS/r?ver=4.9&q=0&csid=5ff08bb5-bda6-47fc-38ca-30f5b5d2f33b HTTP/1.1

gzipped: 1

Accept-Encoding: gzip

et: 111

Content-Type: application/octet-stream

User-Agent: Dalvik/2.1.0 (Linux; U; Android 8.0.0; EDI-AL10 Build/HUAWEIEDISON-AL10)

Host: aps.amap.com

Connection: Keep-Alive

Content-Length: 895

HTTP/1.1 200

Date: Thu, 04 Jun 2020 06:18:51 GMT

Content-Type: application/octet-stream;charset=UTF-8

Transfer-Encoding: chunked

Connection: keep-alive

retype: -1

rdesc:

content-encoding: gzip

Server: Tengine/Aserver

EagleEye-TraceId: 0e0fb40115912515318368299efd77

Timing-Allow-Origin: *

gzip 的解码代码

#include

#include

int inflate_read(char *source,int len,char **dest,int gzip) {

LOGTEST("[inflate_read][IN]");

int CHUNK = 2048;

int ret;

unsigned have;

z_stream strm;

unsigned char out[CHUNK];

int totalsize = 0;

/* allocate inflate state */

strm.zalloc = Z_NULL;

strm.zfree = Z_NULL;

strm.opaque = Z_NULL;

strm.avail_in = 0;

strm.next_in = Z_NULL;

LOGTEST("[inflate_read][step 0]");

if (gzip)

ret = inflateInit2(&strm, 47);

else

ret = inflateInit(&strm);

LOGTEST("[inflate_read][step 1 ret %d ]", ret);

if (ret != Z_OK)

return ret;

strm.avail_in = 975;

strm.next_in = (Bytef*)source;

LOGTEST("[inflate_read][step 2]");

/* run inflate() on input until output buffer not full */

strm.avail_out = 2048;

strm.next_out = out;

ret = inflate(&strm, Z_NO_FLUSH);

assert(ret != Z_STREAM_ERROR); /* state not clobbered */

switch (ret) {

//Z_OK

//Z_STREAM_END 1

//Z_NEED_DICT 2

//Z_ERRNO (-1)

//Z_STREAM_ERROR (-2)

//Z_DATA_ERROR (-3)

//Z_MEM_ERROR (-4)

//Z_BUF_ERROR (-5)

//Z_VERSION_ERROR (-6)

case Z_NEED_DICT:

ret = Z_DATA_ERROR; /* and fall through */

case Z_DATA_ERROR:

case Z_MEM_ERROR:

inflateEnd(&strm);

return ret;

}

have = CHUNK - strm.avail_out;

totalsize += have;

char* resu = (char*)malloc(have);

memcpy(resu, out, have);

/* clean up and return */

LOGTEST("[inflate_read][step 4]");

(void)inflateEnd(&strm);

LOGTEST("[inflate_read][out]");

return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;

}

int mini_gz_get_data_offset(const unsigned char *buffer, int bufferlength)

{

int offset;

int result = 0;

if (10 < bufferlength)

{

//buffer + 0; // .gz header

if (buffer[0] == 0x1F && buffer[1] == 0x8B && buffer[2] == 0x08)

{

// auxillary header

offset = 10;

if (buffer[3] & 0x4)

{

//fextra_len = buffer[offset + 1] << 8 | buffer[offset + 0];

offset += 2;

//fextra_ptr = &buffer[offset];

}

if (buffer[3] & 0x8)

{

//fname_ptr = &buffer[offset];

while (buffer[offset++] != '\0')

{

;

}

}

if (buffer[3] & 0x10)

{

//fcomment_ptr = &buffer[offset];

while (buffer[offset++] != '\0')

{

;

}

}

if (buffer[3] & 0x2)

{

//fcrc = *(unsigned short *)&buffer[offset];

offset += 2;

}

result = offset;

}

}

return (result);

}

char* source = "123";

int len = 123;

char **dest;

int gzip = 1;

int miniGz = mini_gz_get_data_offset((const unsigned char *)source, len);

inflate_read(source, len, dest, gzip);

静态分析 apk

他们采集的信息包括:

altitude

speed

bearing

retype

rdesc

citycode

desc

adcode

country

province

city

district

road

street

number

aoiname

poiname

cens

floor

coord

mcell

offpct

provider

lon

lat

accuracy

type

"type"

"mcc"

"mnc"

"lac"

"cid"

"sid"

"nid"

"bid"

"signalStrength"

"latitude"

"longitude"

"cellAge"

"lastUpdateTimeMills"

"registered"

"updateTime"

"cellType"

"networkOperator"

"mainCell"

"mainWifi"

"updateTime"

"curTime"

"ver", "4.9"

"action", 1

"respctrl"

"src"

"license"

"extrakey"

"srvip"

"model"

"os"

"phoneNum"

"appName"

"imei"

"imsi"

"smac"

"sdkVersion"

"collectionVersion"

"utdid"

"adiu"

"nettype"

"inftype"

"gtype"

v1, this.t

"macsAge"

v1, this.v

"poiid"

"context"

"csid

loc"

"request"

截取代码:

.

case 1: {

v0_1.put("altitude", this.e);

v0_1.put("speed", ((double)this.g));

v0_1.put("bearing", ((double)this.h));

v0_1.put("retype", this.k);

v0_1.put("rdesc", this.l);

v0_1.put("citycode", this.m);

v0_1.put("desc", this.n);

v0_1.put("adcode", this.o);

v0_1.put("country", this.p);

v0_1.put("province", this.q);

v0_1.put("city", this.r);

v0_1.put("district", this.s);

v0_1.put("road", this.t);

v0_1.put("street", this.u);

v0_1.put("number", this.v);

v0_1.put("aoiname", this.w);

v0_1.put("poiname", this.x);

v0_1.put("cens", this.y);

v0_1.put("poiid", this.z);

v0_1.put("floor", this.A);

v0_1.put("coord", this.C);

v0_1.put("mcell", this.D);

if(this.E == null) {

goto label_82;

}

if(!v0_1.has("offpct")) {

goto label_82;

}

v0_1.put("offpct", this.E.getString("offpct"));

goto label_82;

}

case 2: {

label_82:

v0_1.put("time", this.i);

goto label_85;

}

case 3: {

label_85:

v0_1.put("provider", this.b);

v0_1.put("lon", this.c);

v0_1.put("lat", this.d);

v0_1.put("accuracy", ((double)this.f));

v0_1.put("type", this.j);

return v0_1;

}

.

.

try {

v1.put("curTime", this.A);

v1.put("ver", "4.9");

v1.put("action", 1);

v1.put("respctrl", this.a);

v1.put("src", this.b);

v1.put("license", this.c);

v1.put("extrakey", this.d);

v1.put("srvip", this.e);

v1.put("model", this.f);

v1.put("os", this.g);

v1.put("phoneNum", this.h);

v1.put("appName", this.i);

v1.put("imei", this.j);

v1.put("imsi", this.k);

v1.put("smac", i.a(this.l));

v1.put("sdkVersion", this.m);

v1.put("collectionVersion", this.n);

v1.put("utdid", this.o);

v1.put("adiu", this.p);

v1.put("nettype", this.q);

v1.put("inftype", this.r);

v1.put("gtype", this.s);

this.a(v1, this.t);

v1.put("macsAge", this.u);

this.a(v1, this.v);

v1.put("poiid", this.w);

v1.put("context", this.x);

}

catch(Exception v0) {

a.a("@_19_4_@", "@_19_4_1_@", v0);

.

.

private JSONObject a(com.amap.location.c.e.b arg5) throws JSONException {

JSONObject v0;

if(arg5 == null) {

v0 = null;

}

else {

v0 = new JSONObject();

v0.put("type", arg5.a);

v0.put("mcc", arg5.b);

v0.put("mnc", arg5.c);

v0.put("lac", arg5.d);

v0.put("cid", arg5.e);

v0.put("sid", arg5.f);

v0.put("nid", arg5.g);

v0.put("bid", arg5.h);

v0.put("signalStrength", arg5.i);

v0.put("latitude", arg5.j);

v0.put("longitude", arg5.k);

v0.put("cellAge", arg5.l);

v0.put("lastUpdateTimeMills", arg5.m);

v0.put("registered", arg5.n);

}

return v0;

}

.

.

private void a(JSONObject arg7, d arg8) throws JSONException {

JSONArray v4;

JSONObject v1 = new JSONObject();

c v2 = arg8.a;

if(v2 != null) {

JSONObject v3 = new JSONObject();

v3.put("updateTime", v2.a);

v3.put("cellType", v2.b);

v3.put("networkOperator", v2.c);

v3.put("mainCell", this.a(v2.d));

if(v2.e != null && v2.e.size() > 0) {

v4 = new JSONArray();

Iterator v5 = v2.e.iterator();

while(v5.hasNext()) {

v4.put(this.a(v5.next()));

}

v3.put("neighbors", v4);

}

v3.put("mainCell2", this.a(v2.f));

if(v2.g != null && v2.g.size() > 0) {

v4 = new JSONArray();

Iterator v2_1 = v2.g.iterator();

while(v2_1.hasNext()) {

v4.put(this.a(v2_1.next()));

}

v3.put("cell2", v4);

}

v1.put("cellStatus", v3);

}

f v0 = arg8.b;

if(v0 != null) {

JSONObject v2_2 = new JSONObject();

v2_2.put("updateTime", v0.a);

v2_2.put("mainWifi", this.a(v0.b));

List v0_1 = v0.b();

if(v0_1 != null && v0_1.size() > 0) {

JSONArray v3_1 = new JSONArray();

Iterator v4_1 = v0_1.iterator();

while(v4_1.hasNext()) {

v3_1.put(this.a(v4_1.next()));

}

v2_2.put("wifiList", v3_1);

}

v1.put("wifiStatus", v2_2);

}

arg7.put("fps", v1);

}

.

.

public JSONObject a() {

JSONObject v1 = new JSONObject();

try {

v1.put("curTime", this.A);

v1.put("ver", "4.9");

v1.put("action", 1);

v1.put("respctrl", this.a);

v1.put("src", this.b);

v1.put("license", this.c);

v1.put("extrakey", this.d);

v1.put("srvip", this.e);

v1.put("model", this.f);

v1.put("os", this.g);

v1.put("phoneNum", this.h);

v1.put("appName", this.i);

v1.put("imei", this.j);

v1.put("imsi", this.k);

v1.put("smac", i.a(this.l));

v1.put("sdkVersion", this.m);

v1.put("collectionVersion", this.n);

v1.put("utdid", this.o);

v1.put("adiu", this.p);

v1.put("nettype", this.q);

v1.put("inftype", this.r);

v1.put("gtype", this.s);

this.a(v1, this.t);

v1.put("macsAge", this.u);

this.a(v1, this.v);

v1.put("poiid", this.w);

v1.put("context", this.x);

}

catch(Exception v0) {

a.a("@_19_4_@", "@_19_4_1_@", v0);

}

return v1;

}

.

.

v0 = ((a)v0).getResultData();

if(g.l(this.a) < 5 && v0 != null && (((com.amap.location.c.e.a)v0).A())) {

com.amap.location.c.d.a.d("@_16_3_@", "@_16_3_13_@");

try {

com.amap.location.f.a.c v3_1 = com.amap.location.f.a.d.c();

if(v3_1 == null) {

goto label_291;

}

JSONObject v4 = new JSONObject();

v4.put("csid", v2.i());

v4.put("loc", ((com.amap.location.c.e.a)v0).c(1));

v4.put("request", v2.h().a());

v3_1.logServerParseErrorRequest(Base64.encodeToString(v4.toString().getBytes("UTF-8"), 2)); // 从这里大概可以知道个差不多了

g.m(this.a);

}

.

高德的位置服务器,高德位置服务浅析相关推荐

  1. 无法打开位置服务器,Win10定位服务无法开启灰色不可用怎么办?

    Win10定位服务无法开启灰色不可用怎么办?互联网时代无秘密,想开启就开启吧!咱是穷人咱怕谁!但是发现Win10定位开启按钮灰色不可用,想开启却开启不了,一定让您倍感郁闷!不过这个问题不是那么复杂,菜 ...

  2. 苹果手机的高德地图的位置服务器,苹果手机高德地图家人地图在哪

    高德地图近日开启了家人地图新功能,很多苹果手机用户都找到高德地图中家人地图的功能,那么各位小伙伴们知道苹果手机高德地图家人地图在哪吗?接下来91小编和大家一起分享一下苹果手机高德地图家人地图位置一览. ...

  3. uniapp微信小程序获取位置(高德SDK)

    效果图: 在uniapp官网给出了一个全局api用来获取用户位置 uni.getLocation 成功的回调函数会返回相关的用户信息 但是仔细参考,就会发现就address参数返回的很直接,但是也仅限 ...

  4. android定位附近店铺,高德地图怎么添加店铺位置_高德地图定位怎么设置添加自己家店铺位置_攻略...

    高德地图是国内最知名的地图导航软件,基本上每个人的手机上都有这款软件.如今想要方便出行都可以通过高得地图查询位置就可以了,给我们的生活带来了很多的便利.在高德地图上也可以很方便的查询各个地方的店铺,通 ...

  5. js 跳转到指定位置 高德地图_JS引入高德地图定位

    在此记录一下X项目使用高德地图的思路高德地图(X项目前端框架是Jquery) 2准备工作(封装方法,以便直接调用) -2.2封装超时方法($.timeOut-参考) -2.3封装异步调用地图的方法 / ...

  6. 基于高德地图实现融云位置共享功能

    基于高德地图实现融云位置共享功能(Android篇) 效果预览: 开发准备: 1: 登录 融云开发者账号,提交 server 平台工单申请开通 实时位置共享功能.工单回复开通成功后. 2 小时生效. ...

  7. 【AC.HASH】OpenHarmony啃论文俱乐部——在基于位置的隐私感知服务中实现K-匿名之浅析

    本文出自AC.HASH团队,AC<=>Adaptive Creator,适应性创作者,旨在能够在未来新领域下创造出新的哈希算法以应对未来局面. 产出本文的成员:中原工学院大一在校生 我们在 ...

  8. 基于移动位置服务器,基于移动位置的服务系统及方法

    本申请是申请号为03148343.7.申请日为2003年6月30日.发明名称为"基于移动位置的服务系统及方法"的发明专利申请的分案申请. 技术领域 本发明涉及一种基于位置的移动台服 ...

  9. java获取经纬度_java调用高德地图api获取某个位置的经纬度

    java调用高德地图api获取经纬度的方法,废话少说,直接上代码: import com.fasterxml.jackson.databind.JsonNode; import com.ning.ht ...

最新文章

  1. 利用MONAI加速医学影像学的深度学习研究
  2. 环形缓冲区: ringbuf.c
  3. POJ 2594 Treasure Exploration (可相交最小路径覆盖)
  4. 程序通过定义学生结构体变量,存储学生的学号、姓名和3门课的成绩。函数fun的功能是:对形参b所指结构体变量中的数据进行修改,并在主函数中输出修改后的数据。...
  5. 《it创业疯魔史》读后有感
  6. G - Hard problem CodeForces - 706C DP
  7. Python3标准库built-in、itertools、functools中的生成器
  8. linux 修改ramdisk内容,在Linux下使用RamDisk
  9. OC typedef(起别名)
  10. bypy更换绑定的百度云盘账户
  11. Flink 命令行提交参数
  12. 孙宏斌:生意总是有赚有赔,认赌服输(含说明会问答全文)
  13. 【入门6】函数与结构体【完结】
  14. Linux: 关于 SIGCHLD 的更多细节
  15. Python挑战游戏( PythonChallenge)闯关之路Level- 2
  16. 什么是 HTTP? HTTP 和 HTTPS 的区别?
  17. Android 框架学习1:EventBus 3.0 的特点与如何使用
  18. 甜甜用计算机计算1050,NVIDIA GTX 1050/1050 Ti发布:75W功耗、取代GTX960
  19. IT行业中,APaaS、SaaS、BaaS、DaaS都是什么
  20. 读取Java文件到byte数组的三种方式及Java文件操作大全(包括文件加密,String加密)

热门文章

  1. 有哪些公司为外贸独立站提供收款服务?
  2. 最强 IDE,Visual Studio 2017 正式版发布
  3. 关于github的license选择
  4. PS 选区时显示像素
  5. windows script host是什么意思,windows based script host
  6. Bilinear CNN Faster代码解读
  7. 王者荣耀服务器怎么修改,王者荣耀常用英雄自定义攻略怎么设置 自定义攻略设置方法介绍...
  8. NPN和PNP开关电路使用
  9. 使用 @Transactional 时常犯的N种错误
  10. 如何将MAC的文件存储至NAS网络存储?