美文网首页
高德位置服务浅析

高德位置服务浅析

作者: that_is_this | 来源:发表于2020-06-19 14:25 被阅读0次

    前言

    在分析华为 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 <zlib.h>
    #include <assert.h>
    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);
                    }
    .
    
    

    相关文章

      网友评论

          本文标题:高德位置服务浅析

          本文链接:https://www.haomeiwen.com/subject/atvvxktx.html