我们正在构建一个具有应用程序主swf的系统,并从单独的swfs加载单独的工具 - 由于单独的swfs来自cms, 将来会成为版本问题(特别是现在,因为我们仍在开发,但将来当其他开发人员可能会创建一个不兼容的工具时)。我正在努力尽可能地阻止它们,但我真的希望能够在加载不兼容的swf时向系统用户显示消息。
这意味着我们需要捕获VerifyError或至少由于某种原因确定加载失败 - 我现在还不知道如何处理它。我怀疑使用10.1和uncaughtError系统是可能的,但我们目前的目标是flash player 10.有没有人有个好主意? (我们已经在处理IOErrorEvent.IO_ERROR)
更新:我已经构建了一个在导入之前扫描字节码的解决方案,看起来会起作用。我稍后会发布解决方案。
答案 0 :(得分:1)
执行此操作的最佳方法是使用其中一个bhups建议的库。我在下一个例子中使用了senocular's。 此外,由于senocular的库仅为解析的SWF提供基本操作,因此您可能需要SWF格式规范(adobe.com/devnet/swf/pdf/swf_file_format_spec_v10.pdf)才能从加载的SWF中获取所需信息。
下一个示例列出了加载的SWF中的所有类名:
package swf
{
import flash.events.Event;
import flash.net.URLRequest;
import flash.net.URLStream;
import flash.utils.ByteArray;
import flash.utils.Endian;
import swf.SWFReader;
public class GetSWFInfo
{
private var swfInfo:SWFReader;
public function GetSWFInfo()
{
var urlRequest:URLRequest = new URLRequest("theswf.swf");
var loader:URLStream = new URLStream();
loader.load(urlRequest);
loader.addEventListener(Event.COMPLETE, onComplete);
}
public function onComplete(e:Event):void {
var recivedByteArray :ByteArray = new ByteArray();
URLStream(e.currentTarget).readBytes(recivedByteArray);
//create a new instance of SWFReader
swfInfo = new SWFReader();
//readTag it's a callback function that will be called when a tag is read during the SWF parse process.
//read more on tags in the SWF specification document
swfInfo.tagCallback = readTag;
//start parsing
swfInfo.parse(recivedByteArray);
}
public function readTag(tag:uint, bytes:ByteArray):void {
//76 it's the tag type for SymbolClass tag
//read more in the SWF specification document
if (76 == tag) {
var classesArray:Array = new Array();
var symbolsNumber:uint = 0;
var currentId:uint = 0;
bytes.endian = Endian.LITTLE_ENDIAN;
//read the symbols Number
//again read more in the SWF specification document
symbolsNumber = bytes.readShort();
bytes.position = 4;
while (true) {
var i:uint = bytes.position;
//every string name ends with a null byte
//again read more in the SWF specification document
while(bytes[i] != 0) i++;
var readAmount:uint = i - bytes.position;
classesArray.push(bytes.readUTFBytes(readAmount));
//the last ID is always the base class Id, and it's 0
currentId=bytes.readUnsignedShort();
bytes.position++;
if (currentId==0) {
break;
}
}
//this two should be equal
trace(classesArray.length + 1);//the number of elements in the classesArray
trace(symbolsNumber);//the number of classes retrived from the SWF
//list the names
var name:String;
for each (name in classesArray) {
trace(name);
}
//now you have an array with all the class names that you can use to compare
}
}
}
}
答案 1 :(得分:1)
答案 2 :(得分:0)
我过去曾使用过这种应用程序,但我认为最好修复加载的SWF而不是处理VerifyError。 VeriyError表示加载的SWF已损坏或格式错误。
自然而然,SWF本身是畸形的,而不是SWF在传输过程中被破坏。我想你正在尝试加载名为“.swf”的png或其他格式,或者SWF是由Flex编译器或Flash之外的某些软件生成的,例如swfmill(在后一种情况下,该软件中会有一个错误)。 / p>
答案 3 :(得分:0)
我认为有办法解决这个问题。
答案 4 :(得分:0)
最后回答我自己的问题,这是我用来检测可能的错误的实用程序类。我将SWF作为bytearray加载并扫描内容,然后将其作为实际的MovieClip加载。
正如您所看到的,我的代码在很大程度上取决于com.segfaultlabs.swfutils package
重要提示:我已经停止使用这种防止错误的方法,选择通过实际尝试加载文件来检查文件的更多手动方法,看看它们是否有效。这是因为实用程序不完整,而且我目前对ABC格式的了解不足以确保我可以开发一个始终正确的检查。
在此处发布我的代码,作为其他想要攻击它的人的起点: - )
package nl.ijsfontein.utils
{
import com.segfaultlabs.swfutils.ABC.ABCCPool;
import com.segfaultlabs.swfutils.ABC.ABCClass;
import com.segfaultlabs.swfutils.ABC.ABCInstance;
import com.segfaultlabs.swfutils.ABC.ABCMethodInfo;
import com.segfaultlabs.swfutils.ABC.ABCMultiname;
import com.segfaultlabs.swfutils.ABC.ABCParser;
import com.segfaultlabs.swfutils.ABC.ABCTraitConstSlot;
import com.segfaultlabs.swfutils.ABC.ABCTraitsInfo;
import com.segfaultlabs.swfutils.ABC.ABCinfo;
import com.segfaultlabs.swfutils.SWFDataInput;
import com.segfaultlabs.swfutils.SWFFile;
import flash.system.ApplicationDomain;
import flash.utils.ByteArray;
/**
* utility to see which classes a swf uses, but doesn't contain itself
* - this can be used to detect possible VerifyErrors before they happen.
*/
public class SwfDependencyUtil
{
public function SwfDependencyUtil()
{
}
// return null if ok, or name of needed class if external depencendy
private static function resolveSuper(abc:ABCinfo, superClass:String):String
{
//if (superClass.indexOf("flash.") == 0 || superClass.indexOf("*") == 0 || superClass.indexOf("Object") == 0)
if (superClass.indexOf("*") == 0)
{
trace(' super: ' + superClass + " (ignore)");
}
else
{
var superClassClass:ABCClass = null;
for each ( var c:ABCClass in abc.classes )
{
if (c.name == superClass)
{
superClassClass = c;
}
}
if (superClassClass)
{
trace(' super: ' + superClass + " (resolved internally)");
return resolveSuper(abc, superClassClass.iref.base);
}
else
{
trace(' super: ' + superClass + " (NOTFOUND)");
return superClass;
}
}
return null;
}
/*
* checks: classes, superclasses, static variables, member variables
* TODO: function arguments
* won't check: method bodies
*
* TODO: refactor to multiple methods
*/
public static function getDependencies(swfBytes:ByteArray):Array /* of String */
{
var result:Array = [];
swfBytes.position = 0;
var swfr:SWFFile = new SWFFile(swfBytes);
var arr:Array;
if ( swfr.compressed )
{
swfr.dataInput = swfr.uncompress();
swfr.readHeader();
};
arr = swfr.parseTags();
if ( arr[82] != null )
{
var abc:ABCinfo = new ABCinfo();
var cpool:ABCCPool = new ABCCPool();
var abcparse:ABCParser = new ABCParser();
abcparse.readMethodBytes = true;
abcparse.readExceptions = false;
for ( var j:int = 0; j < arr[82].length; j += 1 )
{
swfr.dataInstance.position = arr[82][j].position;
try
{
abcparse.parse( swfr.dataInput as SWFDataInput, abc, cpool, new FakeLogger() );
for each ( var c:ABCClass in abc.classes )
{
trace('class:', c.name);
var superClass:String = c.iref.base;
var dependency:String = resolveSuper(abc, superClass);
if (dependency)
{
result.push(dependency);
}
for each (var mn:ABCMultiname in c.iref.interfaces)
{
var interfaceName:String = mn.nsset[0] != "" ? mn.nsset[0] + "::" + mn.name : mn.name;
var interfaceDependency:String = resolveSuper(abc, interfaceName);
if (interfaceDependency)
{
result.push(interfaceDependency);
}
}
for each (var ti:ABCTraitsInfo in c.traits)
{
if (ti is ABCTraitConstSlot)
{
var constName:String
if (QName(ABCTraitConstSlot(ti).type).uri)
{
constName = QName(ABCTraitConstSlot(ti).type).uri + "::" + QName(ABCTraitConstSlot(ti).type).localName
}
else
{
constName = QName(ABCTraitConstSlot(ti).type).localName
}
var constDependency:String = resolveSuper(abc, constName);
if (constDependency)
{
result.push(constDependency);
}
}
else if (ti is ABCMethodInfo)
{
trace('method', ABCMethodInfo(ti).name);
} else
{
trace(ti);
}
// trace(ti.type.localName);
}
// const (static?) members: c.traits
}
for each ( var i:ABCInstance in abc.instances )
{
// trace(i);
for each (var instanceTi:ABCTraitsInfo in i.traits)
{
if (instanceTi is ABCTraitConstSlot)
{
trace('instance:', createClassNameFromQname(ABCTraitConstSlot(instanceTi).type));
var csdep:String = resolveSuper(abc, createClassNameFromQname(ABCTraitConstSlot(instanceTi).type));
if (csdep)
{
result.push(csdep);
}
}
else if (instanceTi is ABCMethodInfo)
{
}
else
{
trace('unexpected trait type');
}
}
}
abc.dispose();
}
catch ( e:Error )
{
trace( " Error ",e.getStackTrace() );
};
};
cpool.dispose();
}
else
{
trace("No DoABC block... ;(");
}
return result;
}
private static function createClassNameFromQname(qn:QName):String
{
var result:String
if (qn.uri)
{
result = qn.uri + "::" + qn.localName
}
else
{
result = qn.localName
}
return result;
}
public static function getUnsatisfiedDependencies(swfBytes:ByteArray):Array /* of String */
{
var result:Array = [];
var dependencies:Array = SwfDependencyUtil.getDependencies(swfBytes)
for each (var dependency:String in dependencies)
{
if (ApplicationDomain.currentDomain.hasDefinition(dependency))
{
trace('ok: ', dependency);
}
else
{
trace('ERROR: unsatisfied dependency: ', dependency);
result.push(dependency);
}
}
return result;
}
}
}