跳转至

flash 数据请求与解析示例

本文档介绍了使用 flash 加载的页面,对应请求和解析规则

1. 文档简要

  • charles 抓包定位 flash 请求
  • 根据抓到的包来模拟请求数据
  • 若是正常 http 请求,直接正常请求即可
  • 若是 amf 协议请求,需要使用 pyamf 库来处理请求和响应
  • flash 的一些其它附加数据处理
  • 可能会在 swf 文件中添加对请求和响应的数据加密,编码等处理,需要使用 JPEXS 工具反编译来定位

2. 准备工作

flash 调试前准备如下:

  • 可以访问 flash 的浏览器,比如低版本的火狐,谷歌,推荐使用 360 极速浏览器
  • 下载安装好 adobe flash 软件,当调试 swf 时,需要下载 debugger 版本
  • charles 抓包工具
  • pip 安装 pyamf

3. 模拟 flash 请求

如果是普通的 http 请求时,直接按平常方式模拟即可,可能也会在 swf 文件中处理数据;本章节只讨论为 amf 格式请求的情况

3.1. 请求格式

此示例为成都项目:成都市住房

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import urllib
import uuid
import pyamf
import json
import copy
from urllib import request
from pyamf import remoting
from pyamf.flex import messaging


class BodyMiddle(object):
    def __init__(self, uno=None, hno=None, paramStr=None):
        self.UNO = uno
        self.HNO = hno
        self.paramStr = paramStr


class BodyObject(object):
    def __init__(self):
        self.UNO = None
        self.HNO = None
        self.paramStr = None


# 注册自定义的 Body 参数类型,这样数据类型 flex.messaging.messages.RemotingMessage 就会在后面被一并发给服务端(否则服务端就可能返回参数不是预期的异常 Client.Message.Deserialize.InvalidType)
pyamf.register_class(BodyObject, alias='flex.messaging.messages.RemotingMessage')
# 构造 flex.messaging.messages.RemotingMessage 消息
msg = messaging.RemotingMessage(
    operation='ExecRPC',
    # source=None,
    timeToLive=0,
    messageId=str(uuid.uuid1()).upper(),
    destination='SMService',
    # body=[],
    clientId=None,
    timestamp=0,
)


# 构造请求数据
def getRequestData():
    uno = '其他'
    hno = '地下室'
    paramStr = 'VrMDnR1zrkarltpNyFEfEIaWSLH9AW5wPT0gztBK7tbw7HwPIkNIddRVK31aoKsC+ayP7kdXzSUEHFoW2x3o58UJjEXj5tzUXIEhTTtLW5NTL3Qtn0yXE/1exxu1A0z95pszZgd+wCTreQF+XEbIcyzwIdxHFEH1WG2vNEjDEsU='
    msg.body = ['HouseTableServiceImpl', 'getHouses', BodyMiddle(uno, hno, paramStr)]
    msg.headers['DSEndpoint'] = 'my-amf'
    msg.headers['DSId'] = str(uuid.uuid1()).upper()
    # 按 AMF 协议编码数据
    req = remoting.Request('null', body=(msg,))
    env = remoting.Envelope(amfVersion=pyamf.AMF3)
    env.bodies = [('/2', req)]
    data = bytes(remoting.encode(env).read())
    return data


# 返回一个请求的数据格式
def getResponse(data):
    url = 'https://zw.cdzj.chengdu.gov.cn/DE-SMServerFx/messagebroker/amf'
    # req = Request(url, data, headers={'Content-Type': 'application/x-amf'})
    headers = {
        'Connection': 'keep-alive',
        'Pragma': 'no-cache',
        'Cache-Control': 'no-cache',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36',
        'Content-Type': 'application/x-amf',
        'Accept': '*/*',
        'Origin': 'https://zw.cdzj.chengdu.gov.cn',
        'X-Requested-With': 'ShockwaveFlash/34.0.0.184',
        'Sec-Fetch-Site': 'same-origin',
        'Sec-Fetch-Mode': 'no-cors',
        'Sec-Fetch-Dest': 'embed',
        'Referer': 'https://zw.cdzj.chengdu.gov.cn/DE-SMServerFx/FundateClient.swf?t=1&param=RrJw0Hr%2BoUejulOypoolBnDEFQ47eLMP1vIWbT2WbEiz9Z2daWruY1VF0UlympS4snJ3Fz5ICu6DOvoYJH1sNDeVe757q6jWvUpHMIbzBoH4PaZV7L9w9i4hg9LCcK6iAho6aqUkR4O%2Footqr14jLcdhP1X7CHbsUAZT0cpjr%2FY%3D',
        'Accept-Language': 'zh-CN,zh;q=0.9',
    }
    # req = urllib.request.Request(url, data, headers={'Content-Type': 'application/x-amf'})
    req = urllib.request.Request(url, data, headers=headers)
    # 解析返回数据
    # opener = urllib2.build_opener()
    opener = urllib.request.build_opener()
    return opener.open(req).read()


def getContent(response):
    amf_parse_info = remoting.decode(response)
    print("amf 响应数据:", amf_parse_info)
    curr_data = amf_parse_info.bodies[0][1].body.body['HOUSEITEMLIST'][0]
    print('响应中的第一条数据', curr_data)
    # print('ddddd', '\n'.join(['%s:%s' % item for item in curr_data.__dict__.items()]))
    # # 数据总条数
    # total_num = amf_parse_info.bodies[0][1].body.body[3]
    # info = amf_parse_info.bodies[0][1].body.body[0]
    # return total_num, info


def store2json(info):
    res = []
    for record in info:
        record['reportDate'] = record['reportDate'].strftime('%Y-%m-%d %H:%M:%S')
        record['auditDate'] = record['auditDate'].strftime('%Y-%m-%d %H:%M:%S')
        res.append(record)
    fp = open('info.json', 'w')
    json.dump(res, fp, indent=4)
    fp.close()


# 获取数据量
reqData = getRequestData()
rep = getResponse(reqData)
getContent(rep)

3.2. 请求格式说明

只要注意图片中标红的字段即可,其余可以不用修改。

  • 若出现请求失败,微调参数至成功即可 image-20210918162036365

请求参数配置图一

image-20210918162036365

请求参数配置图二

  • 最后,根据下图的响应内容解析字段即可

image-20210918162036365

响应内容图示

4. 参考文献:

评论

回到页面顶部