Pillow

今天找一个标准文件,结果没找到能下载的,后来折腾半天发现道客巴巴有,质量还行。

扒下来是图片文字分离的,文字坐标倒是有了,不过还在研究怎么合并到pdf上去。

这不是本文重点,重点是怎么合并图片到PDF,谷歌许多,都不太理想,最后看到说用Pillow,一试效果还不错。

Code

几个说明:

  • 最后调用save方法的_rgb对应应当是第一页的图片,所以程序循环里面有一个判断
  • 我对文件夹里面的图片进行了排序,请自行修改lambda表达式
  • img到rgb是进行了RGBA到RGB的转换
  • 注意这个代码非常吃内存,但好消息是不会崩!

搜寻过程中了解到的一些工具/库:img2pdf pgmagick ImageMagick fpdf PyPDF2

要提一下的是ImageMagick也不崩,但量大的时候命令行都显示完成了,任务管理器还是显示在占用内存。。

最后分享代码如下:

from PIL import Image
from pathlib import Path

def png_to_pdf():
    fpath = Path(r"path/to/images")
    imgs = []
    paths = [path for path in fpath.iterdir()]
    paths = sorted(paths, key=lambda p: int(p.stem.split("_")[-1]))
    for index, path in enumerate(paths):
        img: Image.Image = Image.open(str(path.resolve()))
        rgb = Image.new('RGB', img.size, (255, 255, 255))
        rgb.paste(img, mask=img.split()[3]) 
        if index == 0:
            _rgb = rgb
        else:
            imgs.append(rgb)

    pdf_path = str(Path("filename.pdf").resolve())
    _rgb.save(pdf_path, "PDF", resolution=200.0, save_all=True, append_images=imgs)

if __name__ == "__main__":
    png_to_pdf()

原标题:Chrome下使用可调试版Flash进行swf分析

感觉这标题不行,换个大气一点的:SWF逆向环境搭建教程(免安装Chrome + Adobe Flash Player)

关键步骤

  • 制作免安装版Chrome并配置
  • 安装Header Editor
  • 安装debug版Adobe Flash Player
  • 修改注册表
  • 检查效果

制作免安装版Chrome并配置

常规安装在此略过

自行动手整一个免安装版Chrome

网上免安装版很多,这里自己动手搞一个。
首先下载一个standalone版的离线安装包,下载链接:

https://www.google.com/chrome/?standalone=1&platform=win64

2020-09-12T08:04:45.png

双击安装,这里不是真的要安装,只是为了提取需要的部分,如图可以看到提示(当然得先开好UAC,不然会直接安装?):
2020-09-12T08:10:17.png

这个时候点否,然后进入

C:\Users\用户名\AppData\Local\Temp

或者win+r输入%TEMP%回车打开,然后就能找到一个名字类似GUMB973.tmp的文件,太多不好找就按时间排序一下。
2020-09-12T08:14:23.png

这个时候把名字里有chrome_installer.exe的这个文件复制出来,用解压软件打开,可以发现是一个chrome.7z,这就是需要的本体了。
2020-09-12T08:16:15.png

然后记得取消掉chrome的安装
2020-09-12T08:18:02.png

在解压后的文件夹下新建init.bat脚本文件,具体内容如下,作用是创建User Data文件夹和快捷键方式

@echo off

set SCRIPT="%TEMP%\%RANDOM%-%RANDOM%-%RANDOM%-%RANDOM%.vbs"
set ChromePath=%~dp0chrome.exe
set ChromeInkPath=%~dp0chrome.lnk
set ChromeUserDataDirPath=%~dp0User Data

echo Set oWS = WScript.CreateObject("WScript.Shell") >> %SCRIPT%
echo sLinkFile = "%ChromeInkPath%" >> %SCRIPT%
echo Set oLink = oWS.CreateShortcut(sLinkFile) >> %SCRIPT%
echo oLink.TargetPath = "%ChromePath%" >> %SCRIPT%
echo oLink.Arguments = "--user-data-dir=""%ChromeUserDataDirPath%""" >> %SCRIPT%
echo oLink.Description = "custom standalone version chrome" >> %SCRIPT%
echo oLink.WorkingDirectory = "%~dp0" >> %SCRIPT%
echo oLink.Save >> %SCRIPT%

cscript /nologo %SCRIPT%
del %SCRIPT%

if not exist "%~dp0User Data" mkdir "%~dp0User Data"

pause

再新建一个mm.bat,内容如下:

@echo off

set mmcfgPath="%~dp0User Data\Default\Pepper Data\Shockwave Flash\System\"
set mmcfg=%mmcfgPath%mm.cfg

if not exist %mmcfgPath% mkdir %mmcfgPath%

echo ErrorReportingEnable=1 >> %mmcfg%
echo TraceOutputFileEnable=1 >> %mmcfg%

pause

双击快捷方式运行Chrome,初始化一些默认设置,然后关闭Chrome,再执行mm.bat生成mm.cfg。
当然你也可以手动新建一个名为mm.cfg,内容为

ErrorReportingEnable=1
TraceOutputFileEnable=1

的文件,位于解压路径下的

User Data\Default\Pepper Data\Shockwave Flash\System\

至此,chrome设置部分完成

安装Header Editor

插件商店地址、项目地址

https://github.com/FirefoxBar/HeaderEditor
https://chrome.google.com/webstore/detail/eningockdidmgiojffjmkdblpjocbhgh

Header Editor设置

主要是为了避免下载Flash Player被重定向到特供版,另外这个插件也能修改很多东西,可以让你更像是在一个纯英文环境。

新版chrome会自动隐藏已经开启的插件的图标,在这里打开:
2020-09-12T09:37:10.png

然后进入设置(左键点击):
2020-09-12T09:37:56.png

右下角加号添加规则:
2020-09-12T09:38:47.png

设置如图:
2020-09-12T09:41:12.png

然后就可以下载Flash Player了

如何直接从webstore下载crx文件

这是一个补充知识点,其实抓包就能知道怎么下了,简而言之就是:

https://clients2.google.com/service/update2/crx?response=redirect&os=win&arch=x86&os_arch=x86_64&nacl_arch=x86-64&prod=chromiumcrx&prodchannel=stable&prodversion=85.0&lang=zh-CN&acceptformat=crx2,crx3&x=id%3D{插件ID}%26installsource%3Dondemand%26uc

替换这个{插件ID}部分,这部分就是插件地址最后面的部分,那么Header Editor的crx下载地址就是:

https://clients2.google.com/service/update2/crx?response=redirect&os=win&arch=x86&os_arch=x86_64&nacl_arch=x86-64&prod=chromiumcrx&prodchannel=stable&prodversion=85.0&lang=zh-CN&acceptformat=crx2,crx3&x=id%3Deningockdidmgiojffjmkdblpjocbhgh%26installsource%3Dondemand%26uc

2020-09-12T09:29:49.png

安装本地的crx要先打开chrome,进入chrome://extensions/,把开发者模式打开,然后把crx拖进来就行了,当然能在线安装更好。
2020-09-12T09:35:31.png

安装debug版Adobe Flash Player

debug版下载地址:

https://www.adobe.com/support/flashplayer/debug_downloads.html
https://fpdownload.macromedia.com/pub/flashplayer/updaters/32/flashplayer_32_ppapi_debug.exe

在安装前,建议卸载已有的Adobe Flash Player,否则后面很可能会出现这个提示:
2020-09-12T09:44:41.png

如果出现这种情况,按照官方方案,需要删除全部的pepflashplayer.dll,然后重新安装Adobe Flash Player

pepflashplayer.dll可能出现的路径举例,主要是第三个,第四个是免安装下的路径:

C:\Windows\SysWOW64\Macromed\Flash\pepflashplayer32_32_0_0_433_pepper.dll
C:\Windows\System32\Macromed\Flash\pepflashplayer64_32_0_0_433_pepper.dll
%USERPROFILE%\AppData\Local\Google\Chrome\User Data\PepperFlash\32.0.0.433\pepflashplayer.dll
Chrome文件夹\User Data\PepperFlash\32.0.0.433\pepflashplayer.dll

假设你已经卸载了原有的Flash。

下载后安装,然后把

Chrome文件夹\User Data\PepperFlash\32.0.0.433\pepflashplayer.dll

这个备份(改个名字),然后将

C:\Windows\System32\Macromed\Flash\pepflashplayer64_32_0_0_433_pepper.dll

移动过来并改名为pepflashplayer.dll,自行对应版本(64/32)。

这个时候运行chrome浏览器,并打开https://helpx.adobe.com/flash-player.html,点击Check Now就能看到Flash信息了,显示debug version说明debug版Flash安装成功了。
2020-09-12T09:56:58.png
2020-09-12T09:57:31.png

修改注册表

由于新版的chrome不能直接设置默认就运行Flash,所以得修改下注册表,这样方便一些。
根据官方文档,建立一个如下内容的reg文件,然后双击添加:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome] 

"DefaultPluginsSetting"=dword:00000001 

[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome\PluginsAllowedForUrls] 

"1"="http://*" 

"2"="https://*"

"3"="http://v.qq.com"

"4"="https://v.qq.com"

这里后两个是完整域名地址,这是因为85版本后的chrome不能直接用通配符的方式以达到让全部网站都自动启用Flash了,只能单个域名(完整二级域名)设定,这样添加主要是为了测试腾讯的swf,测试的swf地址不同还请自行修改添加。

原文档说明:

Starting in Chrome 85: For the PluginsAllowedForUrls and PluginsBlockedForUrls policies, you can no longer use wildcards in hostnames, such as https:// and https://[.]solarmora.com.

添加结果如图:
2020-09-12T10:06:16.png
2020-09-12T10:06:58.png

修改hosts

为了保险起见,屏蔽Flash有关的域名,hosts路径

C:\Windows\System32\drivers\etc\hosts

追加内容:

127.0.0.1  geo2.adobe.com
127.0.0.1 flash.2144.com
127.0.0.1 www.2144.cn
127.0.0.1 fpdownload2.macromedia.com
127.0.0.1 fpdownload.macromedia.com
127.0.0.1 macromedia.com
127.0.0.1 flash.cn

检查效果

找一个需要运行swf的地址就行(一般都会有输出日志),比如腾讯视频的:

http://v.qq.com/iframe/player.html?vid=n0147bokgun

效果如图,可以看到Flash选项是强制默认开启的,这个报错估计是Flash版本问题,没有大碍:
2020-09-12T10:17:12.png

swf产生的日志也有了,在这个路径:

chrome文件夹\User Data\Default\Pepper Data\Shockwave Flash\WritableRoot\Logs\flashlog.txt

2020-09-12T10:19:27.png

日志文件路径在新版本是无法修改的,免安装版就是在上面这个路径,安装版应该是在

%USERPROFILE%\AppData\Local\Google\Chrome\User Data\Default\Pepper Data\Shockwave Flash\WritableRoot\Logs\flashlog.txt

具体参见:

https://helpx.adobe.com/flash-player/kb/configure-debugger-version-flash-player.html

至此,SWF的调试环境就搭建好了,你可以通过反编译SWF,添加一些trace语句等,然后通过flashlog.txt追踪进行逆向分析。

感觉是个很蠢的方案。

相关资料和下载链接

  1. https://helpx.adobe.com/flash-player/kb/enable-flash-player-content-debugger-in-google-chrome.html
  2. https://helpx.adobe.com/flash-player/kb/configure-debugger-version-flash-player.html
  3. https://support.google.com/chrome/a/answer/7084871?hl=en
  4. https://www.flashdevelop.org/community/viewtopic.php?f=11&t=13028
  5. https://github.com/ir73/vizzy/releases
  6. http://ercrta.blogspot.com/2010/04/flash-develop-flash.html

成品

最后将我整理好的完整的环境压缩包奉上,另外85版本(不能对全部网站自动开启Flash)有一点新,找了一个84版本的(84.0.4147.105)。

下载:https://www.lanzoux.com/ityNPgk6ggj 密码:4mky

另外压缩包附带一个日志分析工具Vizzy,需要手动选择一下日志目录,FlashDevelop需要的话请自己下:
2020-09-12T10:42:26.png

成品使用:

  1. 执行init.bat
  2. 运行chrome快捷方式
  3. 运行flash.reg
  4. 运行mm.bat
  5. 安装debug版Flash

本文耗时:一天。

设计师里面的“提升为”就是在应用自定义部件,但是一看到这个.h就感觉不太好了,网上一搜都是新建头文件云云。。
2020-08-09T04:51:12.png
我以为得写C++呢!

遇事不决问谷歌

然后,果然还是在StackOverflow找到了答案。
2020-08-09T04:54:08.png

原来设计师这个只是一个提示,本质上就是替换了一下字符,所以只需要填写类名和你预先写好的py文件的相对路径即可。

注意相对路径的形式,末尾是.h不是.py,斜杠方向不要错了,这样通过pyuic5转换ui文件到py文件时才会生成正确的导入。

path/to/py.h

算是一个练习

之前都是用的BeautifulSoup来提取需要的信息,相对来说操作简单,但是需要这个额外的库有时候感觉还是比较慢。

之前也知道python内置了HTMLParser,可以用来解析html,但是一直没用过,这次用这个来做。

关键目标

  • 尽量保持原有对齐
  • mediainfo分离
  • 图片

实现代码

直接上代码了。

from html.parser import HTMLParser

class THTMLParser(HTMLParser):

    def __init__(self):
        super(THTMLParser, self).__init__()
        self.brflag = 0
        self.qflag = None
        self.imgtag = None
        self.xtag = False
        self.recording = False
        self.record_step = 0 # 抽取进入的深度
        self.record_data = []

    def handle_starttag(self, tag, attrs):
        if tag == "legend":
            # 跳过 legend
            self.recording = False
        if tag == "x":
            self.xtag = True
        if tag == "div":
            if self.recording is True:
                self.record_step += 1
            for key, value in attrs:
                if key == "id" and value == "kdescr":
                    self.recording = True # 开始记录
                    self.record_step += 1 # 步进步数
                    break
        if tag == "fieldset":
            if self.recording is True:
                self.record_step += 1
            if self.qflag is None:
                self.qflag = "quote_start"

    def handle_endtag(self, tag):
        if tag == "legend":
            self.recording = True
            return
        if self.recording is True:
            self.record_step -= 1
            # 回退到起始tag 则说明要抽取的部分遍历结束了
            if self.record_step == 0:
                self.recording = False
        # if self.xtag is True:
        #     self.xtag = False
        if tag == "fieldset" and self.qflag == "find_next":
            self.record_data[-1] += "[/quote]"
            self.qflag = None

    def handle_startendtag(self, tag, attrs):
        if self.recording is False:
            return
        # 处理 <tagname /> 这种形式的tag
        if tag == "br":
            if self.brflag != 0:
                if len(self.record_data) > 0:
                    if len(self.record_data[-1]) > 0 and self.record_data[-1][-1] != "\n":
                        self.record_data[-1] += "\n"
                self.brflag = 0
            self.brflag += 1
        if tag == "hr":
            if self.qflag is None:
                self.qflag = "quote_start"
            if self.qflag == "find_next":
                self.record_data[-1] += "[/quote]"
                self.qflag = None
        if tag == "img":
            for key, value in attrs:
                if key == "src":
                    text = f"[img]{value}[/img]"
                    self.record_data.append(text)

    def handle_data(self, data: str):
        if self.recording is True:
            # 这里没有处理 \u3000 即全角空白 因为全角空白可以对齐
            text = data.strip("\n\t").replace("\xa0", " ")
            if text != "":
                if self.brflag == 1:
                    self.brflag = 0
                if self.xtag is True:
                    self.record_data[-1] += text
                    self.xtag = False
                else:
                    if self.qflag == "quote_start":
                        text = "[quote]" + text
                        self.qflag = "find_next"
                    self.record_data.append(text)
                if self.record_data[-1] in ["Video", "Audio", "Other"]:
                    self.record_data[-1] = "\n" + self.record_data[-1]

    def handle_comment(self, data):
        pass
        # print('<!--', data, '-->')

    def handle_entityref(self, name):
        pass
        # print('&%s;' % name)

    def handle_charref(self, name):
        pass
        # print('&#%s;' % name)

if __name__ == "__main__":
    with open(r"torrent.html", "r", encoding="utf-8") as f:
        content = f.read()
    parser = THTMLParser()
    parser.feed(content)
    with open(r"torrent.md", "w", encoding="utf-8") as f:
        content = f.write("\n".join(parser.record_data))

提取效果预览

2020-07-05T10:24:53.png