纯真 IP 库自动更新

创建:xiaozi · 最后修改:xiaozi 2020-01-01 23:06 ·

抓包

纯真数据库没有提供单独的文件下载,只在 Windows 下提供了一个可以查询和更新数据库的桌面软件;所以想要在服务器上自动更新IP数据库,需要对它更新的时候进行抓包,看看它是怎么从服务器端下载新的数据库文件的。

qqwry

使用 wireshark 抓包,filter过滤表达式如下

http.request.method == 'GET' and http.host == 'update.cz88.net'

wireshark

抓包发现了两个请求 /ip/copywrite.rar/ip/qqwry.rar;copy 其中的 http request 头信息,Accept: text/html, */*User-Agent: Mozilla/3.0 (compatible; Indy Library),至于为什么要记录这两个头,使用浏览器打开这两个链接就知道了,是没有办法直接打开的,我们需要模拟它的桌面端,发起请求。

文件的结构如下:当我们使用上述的方式将 copywrite.rarqqwry.rar 下载下来之后,怎么变成 qqwry.dat 呢?以 rar 结尾的,但并不是 rar 文件。

todo IDA pro 分析过程

copywrite.rar

qqwry.rar 的前 512(0x200) 个字节,需要用到 copywrite.rar 中的 key 进行解密。

自动更新

import struct
import zlib
import requests
import logging
import time


logging.getLogger().setLevel(logging.INFO)

class QQWryUpdater(object):
    version_file = "./tmp/qqwry_version.bin"
    tmp_file = "./tmp/qqwry.dat"
    target_file = "./data/qqwry.dat"
    copywrite_url = "http://update.cz88.net/ip/copywrite.rar"
    qqwry_url = "http://update.cz88.net/ip/qqwry.rar"
    headers = {
        "User-Agent": "Mozilla/3.0 (compatible; Indy Library)",
        "Accept": "text/html, */*",
    }

    @classmethod
    def update(cls):
        curr_version, check_time, update_time = (0, 0, 0)
        with open(cls.version_file, "rb+") as handle:
            content = handle.read()
            if len(content) > 0:
                curr_version, check_time, update_time = struct.unpack("<3I", content)

        check_time = int(time.time())
        copywrite = requests.get(cls.copywrite_url, headers = cls.headers).content
        # copywrite[:4] == b"CZIP" # 纯真IP

        version, unknown1, size, unknown2, key = struct.unpack_from("<5I", copywrite, 4)
        if version == curr_version:
            logging.info("no update for version %d", curr_version)
            with open(cls.version_file, "wb+") as handle:
                handle.write(struct.pack("<3I", version, check_time, update_time))
            return
        logging.info("new version %d, size %d", version, size)

        update_time = int(time.time())
        qqwry = requests.get(cls.qqwry_url, headers = cls.headers).content

        head = bytearray(0x200)
        for i in range(0x200):
            key = (key * 0x805 + 1) & 0xFF
            head[i] = qqwry[i] ^ key

        qqwry = head + qqwry[0x200:]
        data = zlib.decompress(qqwry)
        with open(cls.tmp_file, "wb") as handle:
            handle.write(data)

        with open(cls.version_file, "wb+") as handle:
            handle.write(struct.pack("<3I", version, check_time, update_time))

    @classmethod
    def cover(cls):
        if os.path.isfile(cls.tmp_file):
            shutil.move(cls.tmp_file, cls.target_file)

    @classmethod
    def updateAndCover(cls):
        cls.update()
        cls.cover()
        logging.info("[DONE]")

if __name__ == '__main__':
    QQWryUpdater.updateAndCover()

发布

自动更新完了还没了事,跟发布系统一样;我们的文件不能更新到一半的时候使用,所以需要更新完之后覆盖回去;那就涉及到mv和cp的选择, 这里我们必须选择mv,因为linux系统中记录的文件的inode,mv只是rename了这个inode,没有进行实际的文件copy


浏览 40051 次 · 下载PDF

首页
Copyright © 2011-2021 iteam. Current version is 2.78.0. UTC+08:00, 2021-10-19 18:52
浙ICP备14020137号-1 $访客地图$