Goal of this article
This article's main goal is to show how to manage SWF encoded files with .NET, C#, or VB.NET. SWF is a binary format which represents compiled Flash animations.
Using the SwfDotNet library
The SwfDotNet library is a C# open source framework available at:
This library offers some good stuff to read and write SWF format files from version 1 to 7 for now. SwfDotNet.IO.dll is compatible with the .NET framework 1.1, 2.0 and +. This library respects MacromediaTM SWF format specifications. You can read and download the Macromedia official specifications here.
For our decompiler application, we used this framework like in these examples:
Include the SwfDotnNet library in your class:
using SwfDotNet.IO;
Create a SwfReader object to get a Swf object:
SwfReader swfReader = new SwfReader("myfile.swf");
Swf swf = swfReader.ReadSwf();
Console.WriteLine("Version: " + swf.Version);
Console.WriteLine("Size: " + swf.Header.Width +
"x" + swf.Header.Height);
Console.WriteLine("Fps: " + swf.Header.Fps);
Console.WriteLine("File size: " + swf.Header.FileSize);
Console.WriteLine("Frames count: " + swf.Header.Frames);
Console.WriteLine("Signature: " + swf.Header.Signature);
swfReader.Close();
Write in a Swf object and save as an SWF file or stream:
Swf swf = new Swf();
swf.Tags.Add(new SetBackgroundColorTag(255, 0, 0));
swf.Tags.Add(new ShowFrameTag());
SwfWriter writer = new SwfWriter("myfile.swf");
writer.Write(swf);
writer.Close();
List of available tag objects in the framework:
using SwfDotNet.IO.Tags;
...
ShowFrameTag resTag = new ShowFrameTag();
EndTag resTag = new EndTag();
FrameLabelTag resTag = new FrameLabelTag();
PlaceObjectTag resTag = new PlaceObjectTag();
PlaceObject2Tag resTag = new PlaceObject2Tag();
RemoveObjectTag resTag = new RemoveObjectTag();
RemoveObject2Tag resTag = new RemoveObject2Tag();
SetBackgroundColorTag resTag = new SetBackgroundColorTag();
ProtectTag resTag = new ProtectTag();
SetTabIndexTag resTag = new SetTabIndexTag();
DefineBitsTag resTag = new DefineBitsTag();
DefineBitsLossLessTag resTag = new DefineBitsLossLessTag();
DefineBitsLossLess2Tag resTag = new DefineBitsLossLess2Tag();
JpegTableTag resTag = new JpegTableTag();
DefineBitsJpeg2Tag resTag = new DefineBitsJpeg2Tag();
DefineBitsJpeg3Tag resTag = new DefineBitsJpeg3Tag();
DefineButtonTag resTag = new DefineButtonTag();
DefineButton2Tag resTag = new DefineButton2Tag();
DefineButtonCxFormTag resTag = new DefineButtonCxFormTag();
DefineButtonSoundTag resTag = new DefineButtonSoundTag();
DefineSpriteTag resTag = new DefineSpriteTag();
DefineEditTextTag resTag = new DefineEditTextTag();
DefineFontTag resTag = new DefineFontTag();
DefineFont2Tag resTag = new DefineFont2Tag();
DefineFontInfoTag resTag = new DefineFontInfoTag();
DefineFontInfo2Tag resTag = new DefineFontInfo2Tag();
DefineTextTag resTag = new DefineTextTag();
DefineText2Tag resTag = new DefineText2Tag();
DefineMorphShapeTag resTag = new DefineMorphShapeTag();
DefineShapeTag resTag = new DefineShapeTag();
DefineShape2Tag resTag = new DefineShape2Tag();
DefineShape3Tag resTag = new DefineShape3Tag();
DefineSoundTag resTag = new DefineSoundTag();
SoundStreamBlockTag resTag = new SoundStreamBlockTag();
SoundStreamHeadTag resTag = new SoundStreamHeadTag();
SoundStreamHead2Tag resTag = new SoundStreamHead2Tag();
StartSoundTag resTag = new StartSoundTag();
DefineVideoStreamTag resTag = new DefineVideoStreamTag();
VideoFrameTag resTag = new VideoFrameTag();
DoActionTag resTag = new DoActionTag();
EnableDebuggerTag resTag = new EnableDebuggerTag();
EnableDebugger2Tag resTag = new EnableDebugger2Tag();
ExportAssetsTag resTag = new ExportAssetsTag();
ImportAssetsTag resTag = new ImportAssetsTag();
InitActionTag resTag = new InitActionTag();
ScriptLimitTag resTag = new ScriptLimitTag();
Use the byte code decompiler to get the action script code of an Action tag:
using SwfDotNet.IO.ByteCode;
...
IEnumerator tagsEnu = swf.Tags.GetEnumerator();
while (tagsEnu.MoveNext())
{
BaseTag tag = (BaseTag)tagsEnu.Current;
if (tag.ActionRecCount != 0)
{
IEnumerator byteCodeEnu = tag.GetEnumerator();
while (enum2.MoveNext())
{
Decompiler dc = new Decompiler(swf.Version);
ArrayList actions = dc.Decompile((byte[])tagsEnu.Current);
foreach (BaseAction obj in actions)
{
Console.WriteLine(obj.ToString());
}
}
}
}
We can directly extract media files from tags:
IEnumerator tagsEnu = swf.Tags.GetEnumerator();
while (tagsEnu.MoveNext())
{
BaseTag tag = (BaseTag)tagsEnu.Current;
if (tag is DefineBitsJpeg2Tag)
{
((DefineBitsJpeg2Tag)tag).DecompileToFile("extract_image.jpeg");
Image img = ((DefineBitsJpeg2Tag)tag).DecompileToImage();
}
else if (tag is DefineSoundTag)
{
DefineSoundTag soundTag = (DefineSoundTag)tag;
if (soundTag.SoundFormat == SoundCodec.MP3)
soundTag.DecompileToFile("extract_sound.mp3");
else
soundTag.DecompileToFile("extract_sound.wav");
}
}
Creating the SWF decompiler sample
The goal of this sample is to create a very simple SWF decompiler. From a compiled FlashTM animation (SWF file), we want to load it, and extract in separate files, all the pictures and all the embedded MP3 files.
Attention: This sample decompiler is not a full SWF decompiler! This sample only decompiles embedded JPEG files without the JPEG table, and only non-streamed MP3 and WAV sounds. Only the action script byte code is extracted too.
You can see a file called SwfDecompiler.exe.log.xml in the project, this file is the log4net framework configuration file. For more information about log4net, you can read this article or go to the official web site.
The SwfDotNet library uses log4net for all the trace operations. When you read an SWF file, you can trace all the SWF
tags read by the SwfReader
object, and you can trace the different shapes contained by a DefineShape
tag for example.
To do it, just change these lines in the
SwfDecompiler.exe.log.xml file:
<!---->
<logger name="SwfDotNet.IO">
<level value="ALL" /> <!---->
</logger>
<!---->
<logger name="SwfDotNet.IO.Tags.Types">
<level value="ALL" /> <!---->
</logger>
If you change these values and execute the decompiler one more time, a file named "Log.txt" will appear in the same directory of the application, with some lines like this::
[DEBUG] - **************** Start to decompile file ..\input\sample.swf
[INFO ] - SetBackgroundColor....OK (5)
[INFO ] - SoundStreamHead2....OK (6)
[INFO ] - DefineBitsJpeg2....OK (43816) <== A DefineBitsJpeg2
tag has been readed
which contains
43816 octects of data
[INFO ] - Shape: StyleChangeRecord
[INFO ] - Shape: StraightedEdgeRecord
[INFO ] - Shape: StraightedEdgeRecord <== A straighted edge
shape has been readed
[INFO ] - Shape: StraightedEdgeRecord
[INFO ] - Shape: StraightedEdgeRecord
[INFO ] - Shape: EndShapeRecord
[INFO ] - DefineShape....OK (61)
[INFO ] - PlaceObject2....OK (8)
[INFO ] - DefineSound....OK (8439)
[INFO ] - StartSound....OK (9)
[INFO ] - DefineSound....OK (293373)
[INFO ] - StartSound....OK (9)
[INFO ] - ShowFrame....OK (2)
[INFO ] - ShowFrame....OK (2)
.....
Conclusion
As you can see, thanks to the SwfDotNet library, you can easily analyse, manage, create, read, or write SWF binary files. This sample is a really "light" SWF decompiler but shows the way to do it, shows how to do a real one, and doesn't require to be a binary reading process expert.
Moreover, the SwfDotNet library is 100% free (GPL license) and not platform dependent: you can use it in a web project or in a WinForms application, and, for sure, with Mono.
History
- 19/12/2006: First article version.