分析微信發送消息接口(基於網頁版分析)

日常咱們用微信都是使用安卓客戶端或者,IOS客戶端,或者網頁版,可是做爲一個Programmer,必須得有點Programmer的亞子。 下載連接javascript

本文只做爲學習交流,不可用於其餘用途,如有冒犯之處,請當即聯繫我刪除。java

在閱讀以前請確保你有Javascript的基礎,和Http相關的基礎。git

本文只分析微信發送消息(文本),不涉及其餘微信其餘接口的分析。web

Step:1 找到微信發送消息的請求

  1. 打開chromeDevTool
  2. 找到network選項(專門用於查看網絡請求的選項)
  3. 點擊XHR(過濾其餘請求)
  4. 就是他了(webwxsendmsg聽名字就像)

Step:2 查看請求詳細信息

Step:3 分析其請求參數

其參數有兩部分,第一部分是QueryStringParameter裏面的pass_ticket,登錄以後就是固定值。chrome

第二部分是請求體中的部分:json

  • DeviceId:是按照當前時間隨機生成的生成規則以下:微信

    "e" + ("" + Math.random().toFixed(15)).substring(2, 17)
    複製代碼
  • Sid是在Cookie中的:cookie

    getSid: function() {
                      return n || (n = a.getCookie("wxsid"))
                  },
    複製代碼
  • Skey:固定值(服務端傳回來的,同一帳號每次登錄都是如此)網絡

  • Uin:固定值(服務端傳回來的,同一帳號每次登錄都是如此)app

  • ClentMsgId和LocalId:經過當前時間戳生成:

    //utilFactory.now()等同於Date.now()
    e.ClientMsgId = e.LocalID = e.MsgId = (utilFactory.now() + Math.random().toFixed(3)).replace(".", "")
    複製代碼
  • Content:消息內容

  • FromUserName:自身帳號的標識(每次登錄都會不一樣)

  • ToUserName:消息接收用戶的標識(每次登錄都會不一樣)

  • Type:消息類型

    • 1——文本消息
    • 3——圖片消息
    • 34——語音消息
    • 43——視頻消息
    • 62——小視頻
    • 47——表情符號
    • 49——app
    • 50——網絡電話
    • 52——網絡電話通知
    • 53——網絡電話邀請
    • 48——定位
    • 51——狀態喚醒
    • 9999——系統通知
    • 40——單向好友消息
    • 37——驗證消息
    • 42——SHARECARD
    • 1e4——SYS

Step:4 分析其相應結果

成功的示例包含:

  • Ret=0
  • ErrMsg=""
  • 會將咱們發送的LocalId返回來
  • MsgID:也會有值

Ok,若是咱們能獲取到如上的返回結果就基本確承認以發出去了。

Step:5 發送消息

這次使用Java進行測試,並在下面貼出了代碼。其餘語言想測試的話,可參考思路。

測試類

import org.jsoup.Connection;
import org.jsoup.Jsoup;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.NumberFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class Ts {
    public static void main(String[] args) throws IOException {
        WX wx = new WX();
        HashMap<String, String> map = new HashMap<>();
        map.put("passTicket", "xc5t%252FDlS9Rwo47Fn9etDMuF7RwmY3g9eFQmRVuioZAudH3T8EuAYXQB8MhdywQRd");
        map.put("cookie", "wxuin=1581772621; webwxuvid=41eb93e6ef2e38a577ea2ea6b903594c88846cca31e6dda901afa2f0f2681cd59a0c8dacb47291f8e654bdc71f66e5bd; last_wxuin=1581772621; pgv_pvi=540184576; pgv_pvid=5488108125; ptui_loginuin=228846384; RK=RZKt0BQJZO; ptcz=b1c17e858051a1a4b4ae7af9bbda73303db615c3aa263dc5d0d37e2788187d0f; mm_lang=zh_CN; MM_WX_NOTIFY_STATE=1; MM_WX_SOUND_STATE=1; wxsid=F4EYzJ9vuXu0ruhm; webwx_data_ticket=gSc4Xg3VXZl/lJGgCqpviUOv; webwx_auth_ticket=CIsBEMjWxBEagAF3bcXg4+deLUBcXm7QCmJlYQa4NzMYR+J8Mo1vx06AorpEG4CqhlYzsKxfJTWUIxcX0uNifVtbz/5MTQGkhu/ZG3oAQfEqqMN8aj/RPMWUFSDk0YwcnniAVH1joTTq3m/Znp2WGmL8zpZQoOkbhWx8mRsYH07Ln7EKExxiNaLwfw==; login_frequency=2; wxloadtime=1562203882_expired; wxpluginkey=1562197398");
        String fromUser = "@38a4bd3020c368f82d7cf6183f545bb2b8aa0096995c06c9ebfedaac8729cdc5";
        String toUser = "@52e7190ff0ab4006f5199fda9a47def0cd5815d437ded69bd75d3d44551b938e";
        wx.sendMsg("你好", map, fromUser, toUser);
    }
}
複製代碼

咱們看到了確實成功了。

發送消息類

import org.jsoup.Connection;
import org.jsoup.Jsoup;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.NumberFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class WX {

    public static String sendMsg(String msg, Map<String, String> map, String fromUser, String toUser) throws IOException {

        BigDecimal b = new BigDecimal(Math.random());
        double v = b.setScale(15, BigDecimal.ROUND_HALF_UP).doubleValue();
        String dId = "e" + ("" + v).substring(2, 17);
        String timeStamp = getTimeStamp();

        String param = "{\n" +
                " \"BaseRequest\": {\n" +
                " \"Uin\": 1581772621,\n" +
                " \"Sid\": \"F4EYzJ9vuXu0ruhm\",\n" +
                " \"Skey\": \"@crypt_94354c03_6bff423a698bb93e83549fd90906c2d6\",\n" +
                " \"DeviceID\": \"" + dId + "\"\n" +
                " },\n" +
                " \"Msg\": {\n" +
                " \"Type\": 1,\n" +
                " \"Content\": \"" + msg + "\",\n" +
                " \"FromUserName\": \"" + fromUser + "\",\n" +
                " \"ToUserName\": \"" + toUser + "\",\n" +
                " \"LocalID\": \"" + timeStamp + "\",\n" +
                " \"ClientMsgId\": \"" + timeStamp + "\"\n" +
                " },\n" +
                " \"Scene\": 0\n" +
                "}";

        System.out.println(param);
        System.out.println(dId);
        URL url = new URL("https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?pass_ticket=" + map.get("passTicket"));
        HttpURLConnection urlconn = (HttpURLConnection) url.openConnection();
        urlconn.setRequestMethod("POST");
        urlconn.setDoInput(true);
        urlconn.setDoOutput(true);
        urlconn.setRequestProperty("userAgent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36");
        urlconn.setRequestProperty("referrer", "https://wx2.qq.com/?&lang=zh_CN");
        urlconn.setRequestProperty("Accept", "application/json, text/plain, */*");
        urlconn.setRequestProperty("Accept-Encoding", "gzip, deflate, br");
        urlconn.setRequestProperty("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8");
        urlconn.setRequestProperty("Connection", "keep-alive");
        urlconn.setRequestProperty("Cookie", map.get("cookie"));
        urlconn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
        urlconn.setRequestProperty("Host", "wx.qq.com");

        OutputStream outputStream = urlconn.getOutputStream();
        outputStream.write(param.getBytes());
        outputStream.flush();
        int responseCode = urlconn.getResponseCode();
        if (responseCode != 200) {
            throw new RuntimeException("Failed : HTTP error code : "
                    + urlconn.getResponseCode());
        }

        BufferedReader responseBuffer = new BufferedReader(new InputStreamReader(
                (urlconn.getInputStream()), "UTF-8"));
        String output = "";
        StringBuffer stringBuffer = new StringBuffer();
        System.out.println("Output from Server:\n");
        while ((output = responseBuffer.readLine()) != null) {
            stringBuffer.append(output);
            System.out.println(output);
        }

        urlconn.disconnect();
        return stringBuffer.toString();
    }

    private static String getTimeStamp() {
        NumberFormat nf = NumberFormat.getNumberInstance();
        // 保留兩位小數
        nf.setMaximumFractionDigits(3);
        // 若是不須要四捨五入,可使用RoundingMode.DOWN
        nf.setRoundingMode(RoundingMode.UP);
        return (new Date().getTime() + "" + nf.format(Math.random())).replace(".", "");

    }
}
複製代碼

關於chrome調試的問題,下次文章會發出來,敬請期待。

下載類文件以後,請注意修改包名。

相關文章
相關標籤/搜索