Flash on a PDF with miniPDF.py…
February 11, 2010
Due to the recent advances in exploitation techniques it became really important to put flash every were we can.
|
Flash AHAHHHHHHHHHHHHHHH!!!! In this post we are going to show how to add a swf(Flash) file to a PDF file using our miniPDF.py lib. |
![]() |
Flash support is relatively new in PDF and come into the scene primary for doing the PDF portable collection thing and such. We’ll follow the steps described in Adobe® Supplement to the ISO 32000 , so you probably need to grab it and keep it close to you. In the case you’ve missed the previous posts here you have a copy of the miniPDF.py so you can take a quick look. We are going to use that lib mainly as we did in earlier posts and start adding PDF objects until… –FLASH!– we end up with a one paged PDF with a running embedded SWF. OK, so lets start…
First we import the lib and create a PDFDoc object representing a document in memory …
doc = PDFDoc()
… prepare an empty content stream for the page and add it to the document.
contents = PDFStream('')
doc.add(contents)
The minimal page object. We construct it and add it to the document like this…
page = PDFDict()
page.add("Type", PDFName("Page"))
page.add("Contents", PDFRef(contents))
doc.add(page)
… then we need the list of pages. In this case containing just or blank page.
pages = PDFDict()
pages.add("Type", PDFName("Pages"))
pages.add("Kids", PDFArray(PDFRef(page)))
pages.add("Count", PDFNum(1))
doc.add(pages)
Let’s be nice and honor the PDF structure as stated in .We link the page to its parent.
page.add("Parent", PDFRef(pages))
And finally we add the catalog wich is the root object of this PDF.
catalog = PDFDict()
catalog.add("Type", PDFName("Catalog"))
catalog.add("Pages", PDFRef(pages))
doc.add(catalog)
doc.setRoot(catalog)
If we render that like this…
print doc
we’ll get a clean minimalistic PDF file with just one blank page.
![]() |
Here you have the mkMINIPDF.py python file and the generated example.
-Hey Mom look what I did!! A mini blank PDf file!!! look! look!
Not so exiting though. |
The annotation
As stated in the Adobe® Supplement to the ISO 32000 flash support in PDF is implemented as a type of annotation. More precisely, annotation type “RichMedia”. So we go back to the PDF32000 specification section 12.5 and take a look what a annotation is.
So we construct the RichMedia annotation object with all the required fields …
annot = PDFDict()
annot.add('Type',PDFName('Annot'))
annot.add('Subtype',PDFName('RichMedia'))
annot.add('Rect','[ 266 116 430 204 ]')
doc.add(annot)
… and we add it to our page.
page.add("Annots", PDFArray([PDFRef(annot)]))
This has nothing to do with flash yet. If we keep going trough the Adobe® Supplement to the ISO 32000 in TABLE 9.49 there is a list of the extra annotation entries specific to a RichMedia annotation. Wich are RichMediaSettings and RichMediaContents. So let’s add those two to the annotation dictionary.
Add a RichMediaSetting empty container to the document..
RMS = PDFDict() doc.add(RMS)
… then the same with the a RichMediaContent dictionary.
RMC = PDFDict() doc.add(RMC)
Both empty for now, we add it to the annotation..
annot.add('RichMediaSettings', PDFRef(RMS))
annot.add('RichMediaContent', PDFRef(RMC))
The RichMediaSettings
For the RichMediaSettings dictionary we need an activation and a deactivation dictionaries basically telling when the annotation should activate and deactivate…
First we add the activation dictionary. The ‘PO’ condition means ‘when the page containing the annotation is opened’. There are other options in the doc.
activation = PDFDict()
activation.add('Type', PDFName('RichMediaActivation'))
activation.add('Condition', PDFName('PO'))
doc.add(activation)
And the deactivation dictionary. The ‘XD’ means ‘run until deactivated by the user’.
deactivation = PDFDict()
deactivation.add('Type', PDFName('RichMediaDeactivation'))
deactivation.add('Condition', PDFName('XD'))
doc.add(deactivation)
And then the RichMediaSettings, flagging the annotations as being of type ‘Flash’. Note that we’ve already constructed and added an empty object representing this a couple of line before. We just populate it.
RMS.add('Type',PDFName('RichMediaSettings'))
RMS.add('Subtype',PDFName('Flash'))
RMS.add('Activation', PDFRef(activation))
RMS.add('Deactivation', PDFRef(deactivation))
The RichMediaContents
For the RichMediaContent dictionary we first need at least two things. The assets, a name tree of embedded file specification dictionaries. And a bunch of RichMediaConfiguration dictionaries.
The assets is the one pointing to the files involved as, for example, our .swf file. An asset name tree has this look:
29 0 obj << /Names [ (Flash.swf) 31 0 R ] >> endobj
We take the file embedding functionality from this post. And will not trait it here, there is enough PDF madness with the Flash part. The _zipEmbeddeFile function take a filename return a filespec object after embedding the file into the PDF doc. We take the Flash filename from the first argument to the python.
assets = PDFDict()
swfname = PDFString(sys.argv[1])
efref = PDFRef(_zipEmbeddeFile(doc, sys.argv[1]))
assets.add('Names',PDFArray([swfname, efref]))
doc.add(assets)
Now we need the RichMediaConfiguration dictionaries that wich in our case will be just one (see Adobe® Supplement to the ISO 32000#TABLE 9.51).
RichMediaConfiguration Dictionary
But first lets declare the instances array we need for the RichMediaConfiruration. We’ll populate it in a while.
instances = []
And the actual RichMediaConfiguration.
RMCfg = PDFDict()
RMCfg.add('Type',PDFName('RichMediaConfiguration'))
RMCfg.add('Subtype',PDFName('Flash'))
RMCfg.add('Name',PDFString('ElFlash'))
RMCfg.add('Instances', PDFArray(instances))
doc.add(RMCfg)
And now we have most of the necessary for the RichMediaContent, lets add it…
RMC = PDFDict()
RMC.add('Type', PDFName('RichMediaContent'))
RMC.add('Assets', PDFRef(assets))
RMC.add('Configurations',PDFArray([PDFRef(RMCfg)]))
doc.add(RMC)
But we have leaved the instances array empty, and erg.. we need it so..
RichMediaInstance Dictionary
We are basically going to use this for designating wich embedded file is the flash and for passing arguments to it. Yes we can pass arguments to it!!!
The RichMediaInstances array has this look:
15 0 obj % RichMediaInstances array [ 17 0 obj ] endobj 17 0 obj << /Type /RichMediaInstance /Subtype /Flash /Asset 31 0 R /Params 18 0 R >> endobj
And now we put together our only RichMediaInstance dictionary (see Adobe® Supplement to the ISO 32000#TABLE 9.51b)…
RMI = PDFDict()
RMI.add('Type',PDFName('RichMediaInstance'))
RMI.add('Subype',PDFName('Flash'))
RMI.add('Asset',efref)
doc.add(RMI)
And add it to the list of instances referenced from RichMediaConfiguration dict.
instances.append(PDFRef(RMI))
Also for passing parameters we could add a RichMediaParams dictionary (see Adobe® Supplement to the ISO 32000#TABLE 9.51c). We get the parameters from the content of the file named in the second argument passed to the python.
RMParams = PDFDict()
RMParams.add('Type', PDFName('RichMediaParams'))
RMParams.add('FlashVars', PDFString(file(sys.argv[2]).read()))
RMParams.add('Binding', PDFName('Background'))
doc.add(RMParams)
Also we need to link it from the RichMediaInstance…
RMI.add('Params',PDFRef(RMParams))
THAT’S IT!!! We only need to render the PDF…
print doc
Uff! Finally! The resulting python has this from ant it runs like this
And it works!!! I took a swf from the web and put it, here is the screenshot…
And HERE you have the test bundle with all this.
Untested and related: Also in my tests the authplay.dll, the dll providing all the Flash functionality to the Adobe Reader, is loaded at a fixed address in XPSPx when in IE or stand alone, wich means you can bypass DEP trough some ret2authplay.dll. Also when in stand alone the Reader dosn’t opt in for DEP
f/



Nice !
2 little windows-related fixes:
the SWF file should be read as binary, and redirecting the output creates wrong return caracters.
@@ -6,7 +6,7 @@
import zlib,sys,md5
def _zipEmbeddeFile(doc, f,minimal=False):
– fileStr = file(f).read()
+ fileStr = file(f, “rb”).read()
embedded = PDFStream(fileStr)
if not minimal:
embedded.add(‘Type’, PDFName(‘EmbeddedFile’))
@@ -167,7 +167,9 @@
#add the RichMedia annotation to the 1st page
page.add(“Annots”, PDFArray([PDFRef(annot)]))
-print doc
+f = open(sys.argv[3], “wb”)
+f.write(str(doc))
+f.close()
also you didn’t include the (empty) vars file.