xDroid's Blog

Google壁纸

话说这个 Google 出的壁纸应用倒还是挺好看的嘛,不过只能在手机上使用未免有些可惜……于是决定找一找有没有什么网址之类的……

手上明明有一堆 ddl ,却偏要挖坑给自己跳。

那么首先总先要搞到网址:这很简单,拿 apktool 反编译一下 apk 文件,再用 grep 匹配出 https 开头的地址就可以了,于是我们得到了:

bfg.smali: const-string v4, "https://clients3.google.com/cast/chromecast/home/wallpaper/collections?rt=b"
bfg.smali: const-string v4, "https://clients3.google.com/cast/chromecast/home/wallpaper/collection-images?rt=b"
bfg.smali: const-string v4, "https://clients3.google.com/cast/chromecast/home/wallpaper/image?rt=b"
bjq.smali: const-string v1, "https://app-measurement.com/a"

这TM是啥?似乎 https://clients3.google.com/cast/chromecast/home/wallpaper/collections?rt=b 并查不到任何东西……那试试 https://clients3.google.com/cast/chromecast/home/ (请一定要尝试)。

Chromecast待机壁纸

原来这个是chromecast的待机画面(来源请求)!好吧,那图片是从哪里来的呢?

……

……

审查元素大法好!

<script type="text/javascript">angular.module(...)</script>

这一段似乎很可疑,拿出来看一下……

angular.module('home.constants', []).constant('initialStateJson', JSON.parse('[[[\x22https:\/\/lh6.googleusercontent...

哇!看起来像是和app上面的分类有对应关系。

Terminal中运行 node , parse 一下这个数组……

哎等等……突然想到其实有可能只是服务端渲染好了页面代码,再发送到本地,然后本地 angular 载入代码获取图片……不禁陷入了沉思……


手机端截包有困难……因为难以搭建两层代理(因为天朝网络原因),所以决定通过观察的方式获得图片:

https://www.gstatic.com/chromecast/home/geo/1920x1080/earth-[001-201].jpg
https://ssl.gstatic.com/chromecast/customize/customize-photos-[01-03].jpg

(那怎么还有像 https://www.gstatic.com/chromecast/home/geo/1920x1080/earth-6510.jpg 这种地址呢???)


终于下决心折腾一下,于是在 Windows 下载了 Fiddler 截包,欢天喜地拿到了数据包,然后用 curl 试了一下发现……为毛 curl 总是要把数据包开头的换行符 0x0a 扔掉啊喂!!!

非常无奈,于是只好用 node.js 写这个东西,总之就是通过观察总结一下规律,用正则表达式拎出图片地址,再写到文件里去就好了。

嗯又是一个flag:因为用 node.js 又埋下了不少坑。简单地说,用到了一些 deprecated 的方法,然后有些地方没有写二进制 flag 。

这件事先折腾这么多吧……


P.S: bash代码(简单粗暴……可以调整一下上限……)

for i in `seq 1 200`; do wget "https://www.gstatic.com/chromecast/home/geo/1920x1080/earth-"`printf "%03d" $i`".jpg"; done

P.P.S: node.js代码(用法 node wallpaper.js path/to/save/pictures)

'use strict'

const request = require('request-promise')
const fs = require('fs')

let options = process.argv
options = options.slice(-1)

request
  .post({
    url: 'https://clients3.google.com/cast/chromecast/home/wallpaper/collections?rt=b',
    headers: { "Content-Type": "application/protobuf"},
    body: "\x0a\x05\x7a\x68\x2d\x43\x4e"
  })
  .then(body => {
    // No actual uses.
  })
  .catch(err => {
    console.log("Error!")
    console.log(err.message)
    exit(0)
  })
  .then(() => {
    return request
      .post({
        url: 'https://clients3.google.com/cast/chromecast/home/wallpaper/collection-images?rt=b',
        headers: { "Content-Type": "application/protobuf"},
        body: "\x0a\x04\x63\x69\x74\x79\x12\x05\x7a\x68\x2d\x43\x4e" // city
        // "\x0a\x09\x73\x61\x74\x65\x6c\x6c\x69\x74\x65\x12\x05\x7a\x68\x2d\x43\x4e" // satellite
        // "\x0a\x09\x6c\x61\x6e\x64\x73\x63\x61\x70\x65\x12\x05\x7a\x68\x2d\x43\x4e" // landscape
        // "\x0a\x10\x6d\x61\x74\x65\x72\x69\x61\x6c\x2d\x74\x65\x78\x74\x75\x72\x65\x12\x05\x7a\x68\x2d\x43\x4e" // texture
        // "\x0a\x08\x61\x62\x73\x74\x72\x61\x63\x74\x12\x05\x7a\x68\x2d\x43\x4e" // abstract
      })
  })
  .then(res => {
    let wallpaperUrls = res.match(/\x01https.*\x1a.http/g).map(str => {return str.slice(1, -6)})
    console.log(wallpaperUrls.length + " pictures!")

    let index = 0
    for (let url of wallpaperUrls) {
      request
        .get({
          url: url + "=s2880-l90",
          //: url + "=s612-v1",
          //: url + "=s50-v1",
          headers: {'Accept-Encoding': 'identity'},
          //encoding: 'binary'
        })
        .pipe(fs.createWriteStream(`${options[0]}/city_${index++}.jpg`))
    }
  })