We use the JPEXS Free Flash Decompiler program in order to inspect the SWF file. This program is useful to guide us on the SWF file structure and content so that we can mimic what it does.
More info on the SWF file structure can be found on the file swf-file-format-spec.pdf
inside the documentation
folder. Chapter 2 is particularly important. The SWF Reference by Alexis - part of the free SSWF project - is also very useful, it is inside the documentation
folder with the name SWF File Format Reference.pdf
Other useful tools are an hex editor and a program to find differences between binary files (eg. VBinDiff) so that we can see what modifications JPEXS does to the SWF.
swf-file-format-spec.pdf
- Page 139
swf-file-format-spec.pdf
- Page 179
Flash, objects are serialized in Action Message Format.
AMF0 file format AMF3 file format
TODO
What is P-code: https://en.wikipedia.org/wiki/Bytecode
The SWF file structure[1] starts with a a signature which can be one of the following:
FWS
- UncompressedCWS
- zlib compressedZWS
- LZMA compressed
The signature is followed by the SWF version.
zlib compression works for SWF files of version >= 6. However, for SWF files with lower version it might work by simply changing the version byte to 6.
The algorithm to compress is as follows:
- Copy the first 8 bytes of the SWF file which correspond to SWF file signature (3), version (1) and file length (4) to a buffer.
- Change the 'F' in the signature to 'C'
- Change the version to 6 if it is lower.
- zlib compress the remaining bytes of the SWF file and add them to the buffer.
LZMA compression works for SWF files of version >= 13. However, for SWF files with lower version it might work by simply changing the version byte to 13.
LZMA compressed SWF files will work in Flash Player 11 or AIR 3 or higher.
The algorithm to compress is as follows:
- Copy the first 8 bytes of the SWF file which correspond to SWF file signature (3), version (1) and file length (4) to a buffer.
- Change the 'F' in the signature to 'Z'
- Change the version to 13 if it is lower.
- LZMA compress the remaining bytes of the SWF file but don't add them to the buffer yet.
- Calculate the length of the compressed bytes and subtract 5 to it (excluding LZMA properties[2]).
- Add the length calculated to the buffer in 4 little-endian bytes. Buffer should now have 12 bytes.
- Add the compressed data to the buffer.
Note: Using XZ tools provides compression/decompression for formats .xz and .lzma. Both seem to not work with Adobe Flash Player. So I used LZMA SDK.
[1]: swf-file-format-spec.pdf - Chapter 2
[2]: lzma-file-format.txt - Chapter 1.1
Source: https://github.com/OpenGG/swfzip/blob/master/swfzip.py
Finding how to programmatically convert a .swf file to a .exe file was not straightforward. There are a few programs out there that do this (e.g. swf2exe), but they are apparently not open source. It was by chance that I was able to find this piece of code by devil-tamachan on GitHub that showed me how to do this programmatically.
The algorithm is quite simple to implement, but I don't know yet why it works like this. For starters, there is a software called Adobe Flash Player projector (or Stand Alone), which is basically a program (.exe) that can run flash files (.swf). This program also has an option to create an .exe of the .swf file.
To convert programmatically, we do the following:
- Create a copy of the Flash Player projector.
- Append the .swf file to the projector's copy (merging the binaries basically).
- Append the following footer to the file: [0x56, 0x34, 0x12, 0xFA]
- Append the size of the .swf file (4 bytes) to the file in little-endian format (less significant byte first). This can be the compressed length or uncompressed length, although the compressed length will allow us to calculate the start of the swf file afterwards.
There are different versions of the Flash Player projector, but this algorithm should work for all of them.
It is also possible to convert the SWF to a Linux binary, using the Adobe Flash Player projector for Linux. Programmatically it is slightly different than windows:
- Create a copy of the Flash Player projector.
- Append the size of the .swf file (4 bytes) to the file in little-endian format (less significant byte first). This can be the compressed length or uncompressed length, although the compressed length will allow us to calculate the start of the swf file afterwards.
- Append the following footer to the file: [0x56, 0x34, 0x12, 0xFA]
- Append the .swf file to the projector's copy (merging the binaries basically).
Note: Flash Player 11 Projector consumes less RAM than its successors, and FP 32 no longer works for embedding swf files.
This method assumes that the SWF is inside the executable and not encrypted, so it is a matter of detecting the start and the end of the SWF file in order to extract it.
- Detect if the file is a Windows executable, Linux executable, or not an executable.
- We could search for the SWF signature, but there's no guarantee that there won't be multiple occurrences of this signature in the file. We could also check the length to make sure it reaches the end of the file where the footer FA123456 is found, although we could have a different executable that doesn't make use of this footer. To make things simple, we'll assume that we are dealing with the Flash Player projector and thus we have the footer FA123456 followed by the SWF file length (compressed) at the end of the file, in the case of Windows. In the case of Linux we have the footer FA123456 followed by the SWF and preceded by the SWF length
[1]: PE file format image and PE file format documentation
[2]: the initials of the designer of the file format, Mark Zbikowski: Wikipedia - Magic Number
[3]: Executable and Linkable Format
Adobe Flash Player projector can be downloaded here
Change icon with Resource Hacker (.exe must not be compressed with UPX).
The Adobe Flash Player projector executable file is about 14-15 MiB in size. By using UPX we can decrease the size to about 5.5 MiB!
Note: SA stands for Standalone