在远古的过去(Win7之前),Adobe Flash Player 的 ActiveX插件还可以在PowerPoint中使用。当年有不少PPT中内嵌了Flash 的教案。

在2020的现在,当年的那些PowerPoint里面的Flash已经无法在Office 2016以及更高的版本播放了。更糟糕的是,你想直接导出文件也变得极度困难。

目前网上常见的招数是使用WinHex之类的软件直接硬导出 .ppt 内的文件。该方法虽然在一定程度上可行,但是过于硬核,实际操作难度非常大。

为了解决这个问题,我从另一个角度提取PPT中的Flash文件。

这种方法必须将PowerPoint文件转成 .pptx 格式。原因是 .pptx 格式的本质是一个 .zip 的压缩包,我们可以使用压缩工具解压里面的资源文件。

使用压缩工具打开 .pptx 文件后,可以在 ppt/activeX 文件夹找到PowerPoint中所有的 ActiveX 插件对应的原始的原始文件。其名称类似于 activeX{数字}.bin

那如何识别这个 .bin 文件原本是什么文件呢?很简单,该文件后缀为 .xml 的资源配置文件里面就有答案。

1
2
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<ax:ocx ax:classid="{D27CDB6E-AE6D-11CF-96B8-444553540000}" ax:persistence="persistStorage" r:id="rId1" xmlns:ax="http://schemas.microsoft.com/office/2006/activeX" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"/>

上面是一个Flash文件的资源配置文件内容,其中 classid 的值是代表该文件被什么 ActiveX 插件使用。

然后,classidD27CDB6E-AE6D-11CF-96B8-444553540000 时,代表该 .bin 文件内存有的是 Flash 文件(.swf)。

是的,你没有听错,这个 .bin 文件还不是 .swf 格式的!我们还需要从里面提取文件。

使用 WinHex 打开这些 .bin 文件,我们可以发现它们的文件头都是 D0CF11E0A1B11AE1

通过Google这个文件头,可以很容易发现这些 .bin 文件都是 .cfb 格式的文件 (The Microsoft Compound File Binary (CFB) file format)。

知道了这个线索之后,我们就可以找一些现成的 .cfb 格式的库来提取里面的文件了。

为了实现的方便,特意使用 GoLang 实现了 .cfb 格式的提取。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package main

import (
"fmt"
"github.com/richardlehane/mscfb"
"io/ioutil"
"os"
"strings"
)

func main() {
info, err := ioutil.ReadDir("./") // 搜索当前文件夹里面所有文件
if err != nil {
fmt.Printf("Failed to read path\n")
return
}

for i := 0; i < len(info); i++ {
// 只有 ActiveX{数字}.bin 的文件名才是cfb文件
if strings.HasPrefix(info[i].Name(), "activeX") == false ||
strings.HasSuffix(info[i].Name(), ".bin") == false {
continue
}

// 打开这个CFB文件
file, _ := os.Open("./" + info[i].Name())
doc, err := mscfb.New(file)
if err != nil {
_ = file.Close()
fmt.Printf("Failed to read file %s\n", info[i].Name())
continue
}

// 遍历导出里面的文件
for entry, err := doc.Next(); err == nil; entry, err = doc.Next() {
buf, err := ioutil.ReadAll(entry)
if err != nil {
fmt.Printf("Failed to read content from CFB file. filename = %s, contentName = %s\n",
info[i].Name(), entry.Name)
continue
}

// 设置导出的文件的文件名,将数据写出到该文件中
outputName := info[i].Name() + "_" + info[i].Name() + ".swf"
// 需要从第8个字节开始提取,前八个字节非文件原始数据
err = ioutil.WriteFile(outputName, buf[8:], os.ModePerm)
if err != nil {
fmt.Printf("Failed to read content from CFB file. filename = %s, contentName = %s, output = %s\n",
info[i].Name(), entry.Name, outputName)
continue
}
}
}
}

上述代码可以非常轻易把程序运行目录下全部的 ActiveX 的 .bin 文件里面的真实文件提取出来。此处假设都是Flash文件,所以格式都是 .swf

看了一下网上还没有人提出这个方法,所以写出来分享给大家,有兴趣可以试验一下哈哈哈。

除非注明,麦麦小家文章均为原创,转载请以链接形式标明本文地址。

版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)

本文地址:https://blog.micblo.com/2020/04/27/%E4%BB%8EPPT%E4%B8%AD%E6%8F%90%E5%8F%96Flash%E6%96%87%E4%BB%B6/