https://github.com/chrisniael/gmessage-thirdpart

疫情期间公司强制要求每天用手机 App 上报健康状况,可是公司的 app 做的是着实难用,卡不说了,还动不动清空之前填写的内容,每次填写上报内容都挺痛苦的,可能也和我还在 3 年前的老机器有关系,就想办法 Hack 一下公司的 App,做了 gmessage-thirdpart 这个项目,下面是一些技术点的零散总结。

HTTP API 安全设计

  • 身份认证

    标志用户身份。

  • 防止数据篡改

    劫持某个请求后,篡改这个请求的某个参数数值,然后再发送。

  • 时效性(防止重放)

    劫持某个请求后,再发送同样的请求。

参数签名

参数签名的意义主要就是实现上面提到的 HTTP API 安全设计的几个要点,举个简单的例子:

Client 登陆成功后会持有一个服务器返回的 SecretKey,然后每次发起 HTTP 请求的时候,都把 URL、 Body 的所有参数和 SecretKey 以某种方式拼接成一个字符串,然后将这个字符串的 md5 值作为 URL 参数或 Body 参数的一部分。

login_response_sid="123"  # 标志用户的 ID
login_response_key="abcdef"  # SecretKey


function get_sign() {
  echo -n "${1}${login_response_key}" | md5sum | awk -F ' ' '{print $1}' | tr a-z A-Z
}

params="appid=1614&sid=${login_response_sid}"
sign=$(get_sign $params)
curl --silent \
  --request GET \
  --url "https://example.com/v1/api?${params}&sign=${sign}"

这样即使用抓包工具抓到数据包也不能伪造身份和篡改数据(防止重放的方案这里先暂时先不做介绍),因为参数签名值 sign 的生成方式是未知的,所以模拟客户端 HTTP 请求最艰难的一步就是需要想办法知道参数签名 sign 是如何生成的,这就需要对客户端进行逆向工程了,下面会提到。

有些 HTTP API 请求会在客户端本地存一些数据在 Cookie 里,所以模拟 HTTP 请求的时候,就需要把 Response 的 Cookie 存下来,并在 Request 的时候把 Cookie 带上。

HTTP 抓包工具

抓包分析 HTTP 接口的目的是为了简单了解 HTTP 请求的 URL 和参数名,方便后面逆向工程后搜索关键代码,从而找到 sign 生成的算法。

Android 逆向工程

  • apktool : .apk -> .xml, .smali, .so

    apktool 可以将 apk 包里的资源文件很完好的逆向出来,包括 .xml、.smali、.so 等。

      apktool d <file_apk>
    

    可以将上面抓包工具分析出的接口名字和参数名作为关键词搜索所有 .smali 文件,从而推断出关键代码所在 java 代码的位置,因为通过 jd-gui 工具查看 .jar 对应的 java 代码是不能全局搜索代码内容的,只能是搜索类名,函数名之类的,所以 .smali 文件可以用来辅助定位关键代码位置。

  • unzip: .apk -> .dex

      cp example.apk example.apk.zip
      unzip example.apk.zip
    

    .apk 文件的本质是压缩文件,解压出来的文件结构大致是这样的:

      .
      ├── AndroidManifest.xml
      ├── META-INF
      ├── assets
      ├── classes.dex
      ├── classes2.dex
      ├── com
      ├── lib
      ├── miui_push_version
      ├── okhttp3
      ├── org
      ├── org.jivesoftware.smack
      ├── org.jivesoftware.smackx
      ├── push_version
      ├── res
      ├── resources.arsc
      └── templates
    

    我们需要用的是 .dex 文件,它是 Android 的核心文件,java 代码最终会被编译成 .dex 文件来执行。这里拆分成了 2 个 .dex 文件,说明工程方法比较多。

  • dex2jar : .dex -> .jar

      d2j-dex2jar classes.dex
      d2j-dex2jar classes2.dex
    

    将 .dex 文件转化成 .jar 文件。

  • jd-gui : .jar -> .java

      classes-dex2jar.jar
      classes2-dex2jar.jar
    

    GUI 工具,明文显示 .jar 文件里的 java 代码。这里就可以用通过 .smali 文件推断出的 java 代码位置来查找和分析参数签名 sign 的生成方法了。

curl 发送 HTTP(s) 请求

会用到的一些 curl 参数:

  • s-, –silent : 不显示进度条和错误信息。
  • -c, –cookie-jar <filename> : 指定要保存 cookie 的文件。
  • -b, –cookie <data|filename> : 指定要使用的 cookie 值或由 -c, –cookie-jar 保存的 cookie 文件。
  • –request : 指定 HTTP 请求使用的方法。
  • –url : 指定访问的 URL。
  • –data : 指定 POST 方法使用的数据。

Example

  • POST 请求,保存 Response 的 cookie 到本地文件
curl --silent \
  --cookie-jar <cookie_file> \
  --request POST \
  --url <url>
  --data <data>
  • POST 请求,携带本地存储的 cookie 值,并保存 Response 的 cookie 到本地文件
curl --silent \
  --cookie <cookie_file> \
  --cookie-jar <cookie_file> \
  --request POST \
  --url <url>
  --data <data>