混校
2009-09-19 22:38 宝宝合凤凰 阅读(2457) 评论(0) 收藏 举报防止被ASV6.0破解的方法
发布:李淳 | 发布时间: 2008年10月4日这是一些关于如何保护自己的作品不被 ASV 破解的方法,仅供参考。
demons:
//Demon.S flash fuction lib
//protect flash swf head
void(a)<=b>"c"||0(!1 && !0);
chocobo:
1(hacker=1);
fictiony:
呵呵,画魔的方法其实和JJ的方法一样的哦!其实都不用那么麻烦啦,只要写“0()”就可以了。ASV对非法函数名的解码有问题,没有出错处理。所以只要是带有非法函数名的语句都会中断asv解码。
除了这种方法,其他还有几种反asv的方法:
1、使用Unicode码为0xa920的字符。
这个字符很奇怪,它会使得asv解码过程出现问题,但不是中断。asv读到这个字符(不论放在哪儿)后,会出现死循环解码的情况,并每解一句提示一个错误。这个方法的好处是不受代码的局限,随便什么地方都能放,而且可以插入到字符串中去,缺点是代码仍能被解出,只是变得乱七八糟了。
2、利用16进制编辑器修改swf文件。
利用16进制编辑器修改需要一定的耐心,因为并不是每次修改都成功的,而是需要多次修改和测试。一般,可以找到需要加密的代码段开头位置(可以用pino的dswf,^v^,免费给他做广告),然后将其前一字节从00改成10(当然改成其他也未必不行)。因为这个字节所在的位置是用来指定这段代码的某个属性的,所以asv就有可能读取出错。不过,这种改法未必次次奏效,所以需要改好后运行一下看看是否没问题,再用asv解一下是否不能解。如此反复直到成功。
3、利用swf反汇编器。
swf反汇编器现在有很多,最有名的就是flasm,它能将swf里的action代码反汇编成元指令代码,并可经一定修改后重编译成swf。不过它对图形的支持不好,所以一般只用在做成swf的action代码库。我们可以把需要用到的代码都写成一批函数,并放在一个单独的flash文件里生成swf,用的时候利用loadMovie来载入就可以了,这样虽然麻烦,但行之有效。用flasm处理过的swf文件一般不能被asv解码,而且执行效率也有所提高。
以上3种方法再加上开头提的那种一共4种方法,不过都是针对asv的缺陷的,并不能说治本。不过大可不必担心,除非新版的asv极为强大,或者对方是一个hacker级的高手,否则要解码还是有天大的麻烦的。
顺便提一句,这几种方法都是互不相干的,所以你可以在一个动画里统统用上——反正破了一种还有三种在,破了两种还有两种挺着……呵呵,看着办吧!
---------------------------------------------------
先看Flash虚拟机的ABC部分的规范和SWF的格式
参照这个才可能知道SWF为什么会被反编译,什么样的SWF能够被执行,什么样的SWF反编译后不容易被读懂
---------------------------------------
swfencrypt的出现,flash文件的AS得到了有效的保护,但ASV又成为其竞敌,两者多次通过升级,在加密与解密中较量,我们应该思考,swfencrypt的加密原理是什么,不可能用到对称或不对称等加密算法,unswfencrypt的作者对此有深入的研究,但不太详细,原文如下:
SWFEncrypt4.0是工作于Flash ActionScript 的 AS2.0 SDK环境,仅能对Flash没有使用AS3.0进行PCode的SWF发布文件。它的加密原理也比较简单,当然前提是你对SWF文件结构有一定的了解,其实SWFEncrypt对SWF到底做了什么,网络对官方产品说:SWF Encrypt是一款强大的Flash加密工具,使用DMM(动态内存修改)技术和Action script混淆技术来保护您的原创设计,可以抵御绝大多数主流的Flash反编译器,据某人说若使用某知名国产Flash反编译器来尝试处理经SWF Encrypt加密的文件时会使前者陷入死锁
了解的人定会知道,确切来说它根本没有加密AS,因为我能原原本本的从SWF文件里挑出来,它能做的是把AS增肥,蒙骗一下主流的Flash反编译器,它骗不了我的分析引擎,它的设计是被Flash的开放格式结构和运行速度差少所限制的,这是它没有加密的原因。SWFEncrypt4.0还原的关键还是在于查找ConstPool简称字典池吧,RCE Forums的Malware Analysis and Unpacking Forum的SWF Encrypt explanation.有外囯人的分析,仅有一个人说到关键上,但他没有真正有效的查找方法,他仅对英文的ACII码判定,这肯定是不科学的,你想想,Flash是个能够跨平台,跨国家语言的东西(连变量名也可以是中文名),而且作者会做假的ConstPool,让你搜索判断不准。那么,我们必须使用有效的方法对ConstPool是否存在,若存在如何能正确找到它做准确的判断和查找,这里我们可以做个虚拟机,模拟执行作者设计的混淆PCode,若有ConstPool快结束时就会停在ConstPool处,再过好步就会跳转到(呵呵)真身处。为什么会这样,因为作者只是将AS分成两部分:1.原始PCode;2.在ConstPool中嵌入混淆PCode。再将其衔接(可能是DMM吧)!
--------------------------------------------------------
必须知道 swf的字节码 格式 以及 反编译软件通过什么解析字节码 以及flash player怎么解析字节码
-------------------------------------------------------
SWFEncrypt的前身是flashincrypt,其加密原理在网上少有探讨,unSWFEncrypt的作者给出了部分原理,但不是很详细,原文如下:SWFEncrypt4.0是工作于Flash ActionScript 的 AS2.0 SDK环境,仅能对Flash 没有使用AS3.0进行PCode的SWF发布文件。它的加密原理也比较简单,当然前提是你对SWF文件结构有一定的了解,其实SWFEncrypt对SWF到底做了什么,网络对官方产品说:SWF Encrypt 是一款强大的Flash加密工具,使用 DMM(动态内存修改) 技术和 Actions cript 混淆技术来保护您的原创设计,可以抵御绝大多数主流的 Flash 反编译器,据某人说若使用某知名国产 Flash 反编译器来尝试处理经 SWF Encrypt 加密的文件时会使前者陷入死锁
了解的人定会知道,确切来说它根本没有加密AS,因为我能原原本本的从SWF文件里挑出来,它能做的是把AS增肥,蒙骗一下主流的 Flash 反编译器,它骗不了我的分析引擎,它的设计是被Flash的开放格式结构和运行速度差少所限制的,这是它没有加密的原因。SWFEncrypt4.0还原的关键还是在于查找 ConstPool 简称字典池吧,RCE Forums 的 Malware Analysis and Unpacking Forum 的SWF Encrypt explanation.有外囯人的分析,仅有一个人说到关键上,但他没有真正有效的查找方法,他仅对英文的ACII码判定,这肯定是不科学的,你想想,Flash是个能够跨平台,跨国家语言的东西(连变量名也可以是中文名),而且作者会做假的ConstPool,让你搜索判断不准。那么,我们必须使用有效的方法对 ConstPool 是否存在,若存在如何能正确找到它做准确的判断和查找,这里我们可以做个虚拟机,模拟执行作者设计的混淆PCode,若有 ConstPool 快结束时就会停在 ConstPool 处,再过好步就会跳转到(呵呵)真身处。为什么会这样,因为作者只是将AS分成两部分:1.原始PCode;2.在 ConstPool 中嵌入混淆PCode。再将其衔接(可能是DMM吧)。swfencrypt的确可以被破解,而且AS越复杂,加密后的体积越大,复杂到一定程度ASV6也没办法,本人提供的精美万年历.swf 大家可以试试。同时也传一个英文版的SWF结构文章供参考,请英文好的朋友翻译一下,也可与本人合作。谢了!
等看明白了 自然知道 怎么写了
--------------------------------------------
swf代码混淆的心得
这是一个比较折磨人的过程。到目前而言,60%的工作已经完成。演示地址请查看:http://www.laaan.cn/?p=422
目前做到的程度:
1:对类名进行混淆;包名称统统去除——这样的话反编译出来的类就没有包结构了。
2:混淆类的常量、静态方法。
3:混淆实例常量、变量以及方法。
大的过程:
过程是一个比较复杂的过程。基本工作很多,比如swf文件的解析及拼凑,比如abc文件的解析及拼凑。其中涉及的内容比较多。其实最基础的还是二进制操作以及位操作。像UB, SB, FB的读取等都是比较基础。
接着是需要了解整个swf中视觉元素和abc代码的关联。这个过程我刚开没有太注重,结果最后遇到了很大问题。比如swf标签中的SymbolClass标签中,存在类链接信息。
接下来就是从abc文件中提取类名、变量、方法等元素,进行混淆操作。
细节:
1:混淆操作是将所有需要混淆的字段添加到一个列表。然后混淆为a_0,a_1…. 这个过程比较简单。就是一个变量递增。考虑到以后的扩展,就把整个混淆数据都保存下来了。作为一个标签加入到了swf文件中。
2:类名的混淆是难一点。由于库中原件可以链接到一个类,当这个类类名被更改时,需要相应的更改连接名称。这个时候需要提取出SymbolClass信息——一个swf中有可能会存在多个SymbolClass。将SymbolClass中绑定的类名提取出来。这是,当混淆一个类时,同时更改相应的绑定类名称。
3:方法的混淆是目前遇到的最难的一步操作了。有方法是可以override的;而且还有可能是一个接口的实现。比如一个类实现了接口IEventDispacher。这个时候这个类实例是有方法addEventListener。在混淆操作时,方法addEventListener被提取出来做混淆操作——其实是一个错误的过程。但是在abc文件中,这些是没有任何特殊标记的。无法判断该方法是否是接口方法。于是需要一个特殊字符集:处在该字符集中的字符是不会被混淆的。
这个时候有会遇到一个问题:字符集怎么来收集。
我的操作是将abc文件中所有的flash自带类的方法名作为特殊字符。比如你的程序用到了Timer,此时reset,start,stop等关键字被收集到特殊字符集;比如你用到了IEventDispatcher, 则addEventListener,removeEventListener等关键字被列为特殊字符。
这个过程是一个相对死过程。主要目的是让混淆过程忽略一些关键字。
这个时候又会遇到一个问题:比如说你的程序是从外部加载数据解析数据:xml.imageURL。而,此时你恰好有一个类中存在方法imageURL。由于所有字符在字符池里面是单一存在的,你将方法imageURL混淆为a_123时,对xml.imageURL的解析便变为了xml.a_123。这种情况是混淆程序是无法预知的。此时就需要让用户建立一个特殊字符集。http://www.laaan.cn/?p=422中的演示就已提供一个特殊字符集输入过程。
4:到这个步骤后,大多是swf已经安全混淆了。但是,还存在个别问题:动态获取类的问题。有的时候程序还存在这样的语句getDefinitionByName(”laan.config::Config”);由于类名及包名已被混淆,因此需要将”laan.config::Config”这样的字符更改为对应的混淆后的字符。这时回到类混淆——在类名混淆时,需要记录下原始类名及混淆后类名的对应关系。待到最后,对整个字符池进行遍历,找出这样的字符,替换。阿弥陀佛~~~
唉~~~ 过程真的是比较痛苦。就此中告一小段落了。
-------------================
swf混淆研究到…
swf的abc结构还算比较容易理解。由大到小,就是scripe,class,instance,然后就是方法及变量了。个人理解是一个类,编译后在abc中体现就是一个class和一个instance。而一个as文件就是一个scripte。有什么区别呢?如果一个as文件中写了两个class,这时候就可以看出区别了。这个as文件会对应两个class和两个instance,而只对应一个scripte。
script有初始化方法,在该方法内,会初始化存在于该script中所有的类。这个方法只执行一次。于是可以想到,可是使用prototype来注入方法。在所有类初始化后,将类对应的instance方法注入到该类的prototype中去;然后删除instance的所有方法。这样的话,效果是一样,但是代码就隐藏起来了(听说asv目前的版本可以看到script中的代码了)。
当然这个时候会产生一些问题。最为明显的就是方法调用。swf中指令findpropstrict(0×5d)是其实是不会搜索prototype中的方法——除非使用with控制scope数据。于是还需要在所有指令findpropstrict前注入指:令:
getlocal0(0xd0),pushwith(0×1c),popscope(0×1d)
air代码:swfBytes = new ByteArray();
var file:File = new File("app:/test.swf");
var stream:FileStream = new FileStream();
stream.open(file, FileMode.READ);
stream.readBytes(swfBytes, 0, stream.bytesAvailable)
stream.close();
var i:uint = 0;
var j:uint = 0;
var k:uint = 0;
var abc:ABC;
for (i = 0; i < swf.tags.length; i++) {
if (swf.tags[i] is DoABC || swf.tags[i].tagId == 72) {
if (swf.tags[i] is DoABC) {
var doabc:DoABC = swf.tags[i] as DoABC;
} else {
var abcBytes:SwfBytes = new SwfBytes();
abcBytes.writeUnsignedInt(1);
abcBytes.writeString(”laaan.cn”);
abcBytes.writeBytes(Tag(tags[i]).data);
doabc = new DoABC(abcBytes);
}
abc = new ABC(doabc.abcCode);
//添加 prototype multiname
var ptMN:MultiName = new MultiName();
ptMN.kind = MultiNameKind.QName;
ptMN.data.name = abc.constantPool.addStringInfo(”prototype”);
ptMN.data.ns = abc.constantPool.addNameSpaceInfo(NamespaceKind.PackageNamespace, “”);
abc.constantPool.multiNames.push(ptMN);
//添加全局访问namespace set
var globalNS:NamespaceSetInfo = new NamespaceSetInfo();
for (k = 1; k < abc.constantPool.namespaces.length; k++) {
globalNS.ns.push(k);
}
abc.constantPool.nsSets.push(globalNS);
//==============================================================================================
for (k = 0; k < abc.scripts.length; k++) {
//InstanceInfo(abc.instances[k]).iinit = abc.scripts[k].init;
var code:Array = abc.scripts[k].readableData.init.body.codes;
code.pop();
for (var kk:uint = 0; kk < abc.scripts[k].traits.length; kk++) {
var traitInfo:TraitInfo = abc.scripts[k].traits[kk];
if (traitInfo.kind != TraitKind.Class) continue;
var traits:Array = abc.instances[ClassTraitData(traitInfo.data).clazz].traits;
for (j = 0; j < traits.length; j++) {
if (TraitInfo(traits[j]).kind == TraitKind.Method) {
//getlocal0
code.push(0xd0);
//pushwith
//code.push(0×1c);
//getproperty
code.push(0×66);
code.push(traitInfo.name);
//getproperty prototype
code.push(0×66);
code.push(abc.constantPool.multiNames.length – 1);
//newfunction
code.push(0×40);
code.push(MethodTraitData(traits[j].data).method);
//setproperty
code.push(0×61);
var methodName:uint = traits[j].name;
code.push(methodName);
var mn:MultiName = abc.constantPool.multiNames[methodName];
mn.kind = MultiNameKind.Multiname;
delete mn.data.ns;
mn.data.nsSet = abc.constantPool.nsSets.length – 1;
traits.splice(j, 1);
j–;
//break;
}
}
//removevoide
code.push(0×47);
}
}
for (k = 0; k < abc.methods.length; k++) {
//code = abc.methods[i].readableData.body.codes;
var methodBody:MethodBodyInfo = MethodBodyInfo.getMethodBodyByMethod(abc.methods[k]);
methodBody.maxScopeDepth += 1;
code = methodBody.codes;
var indent:uint = 0;
trace(k);
var codeInfo:Array = InstructionManager.doCodes(code) as Array;
for (j = 0; j < codeInfo.length; j++) {
if (codeInfo[j] == “_$_%_findpropstrict”) {
//getlocal0
code.splice(j + indent, 0, 0xd0);
//pushwith
code.splice(j + indent+1, 0, 0×1c);
//popscope
code.splice(j + indent+4, 0, 0×1d);
indent += 3;
}
}
}
doabc.abcCode = abc.byteArray;
swf.tags.splice(i, 1, doabc);
break;
}
}
var confuseBytes:ByteArray = new ByteArray();
confuseBytes.writeObject(confuseMap);
swf.tags.push(TagFactory.createTag(201, confuseBytes));
var newSWF:ByteArray = swf.createSWF();
file = new File(”c:/test.swf”);
stream = new FileStream();
stream.open(file, FileMode.WRITE);
stream.writeBytes(newSWF, 0, newSWF.bytesAvailable)
stream.close();
=============================
关于as3的代码混淆
这个功能在DoSWF1.x版本就实现过,使用的是一种比较傻同时又不太准确的方案:根据代码中使用到的内部类信息来组成一个特殊字符集,这个特殊字符集在混淆过程中是不会被混淆。比如你使用了MovieClip类,于是MovieClip, alpha, visible,等所有MovieClip中的关键字段都被定义为特殊字符集了。
有了这个特殊字符集后,混淆就好办了。首先提取出所有类的类名、包名、方法名、属性名,把这些字段一一用混淆字段替换——当然,在特殊字符集中的字段被忽略。比如你写了override public function get width():Number 方法,由于width已收录在特殊字符集中,于是这个字段不会被混淆。
混淆结束后,对新的数据进行重组,生成一个新的swf。这样就完成了混淆过程。不过这个方案会造成很多的误杀,以致很多程序混淆后几乎不能运行了。比如你使用了ExternalInterface.call(”getURL”)来调用js代码,在这种方案下,“getURL”无法检测出来,于是被混淆了。这样就破环了原先程序。于是一直在寻找一种更好的方案。
首先想到的是模拟AVM来运行所有指令,根据运行状态来得到特殊字符集。后来一想,乖乖不得了,完全不可能实现。马上放弃,慢慢想别的出路… 一边生活一边工作,有空就想象这个东西该怎么做。
直到上周六,有人加我QQ说已经破了我DoSWF的授权控制了。强汗~~ 也该升级了。都已经磨蹭快4个月了。奋起。没有别的办法了,写一个指令运行器吧。忙了两天,终于得到一个勉强还可以运行的东西了。植入到DoSWF中去,发现还真的比以前的方案精确了不少。
谈谈加密和混淆吧
还是谈谈自己一直在做的一个应用:flash加密及混淆。从去年8,9月份开始研究。先是研究swf的文件结构,然后是abc的结构。慢慢也明了swf运 行的原理。特别是研究abc结构后,收获很多。然后在写as代码的时候会联想到这些会编译后对应的指令。比如 var a:Number = 3。对应指令就先在local数据中设置一个空间:null,接着一个指令将该空间转换为Number类型,然后添加一个byte数据3到scope,最 后才是指令将3复制到给先前的空间。a字段是不会被编译进去的,这就是为什么用编译软件看到的临时变量都不是原先的名称;再引申下,你可以尽量明了的命名 临时变量,比如:var theFirstValue:Number = 0, 而不用var b:Number = 0。很明显theFirstValue很适合阅读,而且反正也不会编译到swf中去,不用担心太长而增加swf体积。
接下来自己便开始做 加密。先想到的是加壳的方法。后来和别人一交流,才发现,这种方法其实已经早已不是什么新想法了。只要你研究写swf的文件结构,就很容易想到这个方法。 虽然后来想久,尝试很久,还是没有更好的加密方法。其实对于swf而言,已没有加密可言。除非借助与第三方交互。或者adobe自己的人去加密——毕竟 swf文件结构白皮书公布的信息只是一部分而已。所以,最好还是混淆。
加密完成之后,我就开始研究混淆。研究过abc结构的人,应该都很 清楚:要混淆一个方法、一个类名其实很容易。比如你有一个类ABCD,这时候你只要在abc数据中找到这个ABCD,替换为你想混淆成的样子,比如 aaa1。重新组装abc,就完成了混淆。但是如果你有一个类alpha呢?你将alpha混淆成aaa1了。然后你会发现你的代码:(new MovieClip).alpha = 0.3;变成了(new MovieClip).aaa1= 0.3;——swf是一个高压缩的文件格式,abc也是如此。它不可能为同一个字段保存两字。也就是说你的类名alpha和属性alpha引用的是同一数 据,当这个数据被改变是,一切引用该数据的地方都改变了。于是,你需要一个操作:将不混淆字段复制。就上面这个例子:将alpha数据复制一份给“new MovieClip”使用,而类alpha使用的一份进行混淆。
好,这样完成了一小部分。但是还会有问题。比如你从服务器接受了一个xml数据:
<root>
<title>best wish to demi</title>
</root>
然 后你会通过xml.title来得到这个数据。但是你恰恰这个时候有类方法:public function get title():String。然后你混淆了title为aaa1,然后xml.titlt变为xml.aaa1了,就获取不到数据了。于是又涉及到一个 问题了:特殊字段。还比如:
getDefinitionByName(”MainAPP”); MainAPP是特殊字
ExternalInterface.call(”eval”, “alert(’asdf’);”); eval是关键字
等等。有了这些特殊字和copy字段后,就可以进行大力混淆了。当然本人研究也是有限,很多情况没有遇到过,所以肯定会漏掉一些情况。
以上只是自己的对加密和混淆的一些心得。有不对的地方,敬请指正。
=========================================
混淆一个很常用的手段就是将一些无用的指令随即的加入到程序中。这样,既不会影响程序运行速度, 又可以达到混淆目的了。先看看效果:
这个是没有注入随机用反编译工具看到的代码:
public static function reverse(param1:String) : String { var _loc_2:String; while (_loc_3– >= 0){ _loc_2 = _loc_2 + param1.charAt(param1.length–); } return _loc_2; }// end function这个是注入指令后看到的代码:
public static function ?(:String) : String {;
return null;
var _loc_2:String;
;
return ;
;
return null.length–;
var _loc_3:String;
while (_loc_3– >= 0){
;
return ;
;
return _loc_3;
_loc_2 = null + null.charAt(_loc_2);
;
return null;
}
return _loc_2;
}// end function
========================================================================
format.abc: ActionScript Bytecode
format.abc is the successor to hxAsm and is included in the File Formats library. This library can dynamically compile Flash9 assembly code into ABC (ActionScript Bytecode) which can be executed by the AVM2 (Flash 9+).
When compiling to SWF, you can execute this code using format.swf to wrap the bytecode, then loading this movie using the flash.display.Loader.loadBytes method.
Usage
First, create a new haXe Project and include the format library. Then you can start writing in Flash9 assembler. Here's a small example :
import format.abc.Data; import format.swf.Data; class Test { static var loader : flash.display.Loader; static function main() { var ctx = new format.abc.Context(); // defines a class called Main ctx.beginClass("Main"); // the type 'int' in Flash9 var tint = ctx.type("int"); // create a member method called 'test' // with 0 arguments and return type 'int' var m = ctx.beginMethod("test",[],tint); // the maximum size of the stack in this method m.maxStack = 1; // write bytecode into the current method ctx.ops([ OInt(667), ORet, ]); // we are done with all the bytecode writing ctx.finalize(); // compile ActionScript bytecode var abcOutput = new haxe.io.BytesOutput(); format.abc.Writer.write(abcOutput, ctx.getData()); var abcBytes:haxe.io.Bytes = abcOutput.getBytes(); // create a new SWF var swfOutput:haxe.io.BytesOutput = new haxe.io.BytesOutput(); var swfFile:format.swf.SWF = { header: { version : 9, compressed : false, width : 400, height : 300, fps : 30, nframes : 1 }, tags: [ TSandBox(25), // Flash9 Sandbox TActionScript3(abcBytes), // ActionScript block TShowFrame // Show frame ] } // write SWF var writer:format.swf.Writer = new format.swf.Writer(swfOutput); writer.write(swfFile); var swfBytes:haxe.io.Bytes = swfOutput.getBytes(); // load locally loader = new flash.display.Loader(); loader.contentLoaderInfo.addEventListener(flash.events.Event.COMPLETE, onLoaded); loader.loadBytes(swfBytes.getData()); } // the data has been succesfully loaded public static function onLoaded(e) { // get the Main class var m = loader.contentLoaderInfo.applicationDomain.getDefinition("Main"); // create an instance of it var inst : Dynamic = Type.createInstance(m,[]); // call the 'test' method trace(inst.test()); // this should display '667' } }
Another example that shows good performances is the Fibonnacci recursive calculus. It's defined in haXe as the following method :
static function fib( n : Int ) : Int { if( n <= 1 ) return 1; return fib(n - 1) + fib(n - 2); }
Here's the corresponding Flash9 bytecode :
// fib takes an integer argument and returns an integer var m = ctx.beginMethod("fib",[tint],tint); // we will have up to 3 values on the stack m.maxStack = 3; ctx.ops([ OReg(1), // register 1 = first argument OSmallInt(1), // the integer 1 OJump(JGt,3), // jump 3 bytes if reg1 > 1 OInt(1), ORet, // return 1 ODecrIReg(1), // decrement register 1 OThis, OReg(1), // call this.fib(reg1) with 1 argument OCallProperty(ctx.property("fib"),1), ODecrIReg(1), // decrement register 1 OThis, OReg(1), // call this.fib(reg1) with 1 argument OCallProperty(ctx.property("fib"),1), OOp(OpIAdd), // add the two values ORet, // returns ]);
When timed, fib(35) shows a +30% speedup in assembler versus the AS3/haXe version.
Performing jumps
It's not always easy to count bytes when writing a OJump opcode. There is an API to make it more easy to works with jumps. Here's the modified fib version that uses this API :
var m = ctx.beginMethod("fib",[tint],tint); m.maxStack = 3; ctx.ops([ OReg(1), OSmallInt(1), ]); var j = ctx.jump(JGt); // prepare a jump ctx.ops([ OInt(1), ORet, ]); j(); // patch the jump with current position ctx.ops([ ODecrIReg(1), OThis, OReg(1), OCallProperty(ctx.property("fib"),1), ODecrIReg(1), OThis, OReg(1), OCallProperty(ctx.property("fib"),1), OOp(OpIAdd), ORet, ]);
The ctx.jump method writes a OJump opcode, then returns a function. This function can be called when you reach the place of the jump target.
There's also a ctx.backwardJump that works the following :
var j = ctx.backwardJump(); // .... j(JAlways); // jump to saved position
FAQ
- In order to read an array, first push on the stack the array and the index, then use
OGetProp(ctx.arrayProp) - In order to write into an array, first push on the stack the array, the index and the value, then use
OSetProp(ctx.arrayProp) - I'm getting a "VerifyError":
#1017: This is ascope overflowerror. Try increasing your "maxScope" count.#1018: This is ascope underflowerror. It means that you are using an operation (such asOPopScope) while there are not enough scopes in the chain.#1021: This is aninvalid jump addresserror. This shouldn't occur if you use the Jump API that is presented before.#1023: This is astack overflowerror. Try increasing themaxStackproperty of your method.#1024: This is astack underflowerror. It means that you are using an operation (such asORet) while there are not enough values on the stack.#1025: This is aninvalid register error. Try increasing thenRegsproperty of your method.#1030: This is astack unbalancederror. It means that two branches of a Jump result in different stack sizes when they join back. All jumps or code leading to a given position should result in the same stack size.
ASM Reference
A good reference of the Flash9 AVM2 instructions can be found here. The names in this reference are not always the same as in format.abc, but they should be similar. If you edit format/abc/OpWriter.hx you'll see for each opcode the hex code AVM2 is using.
A list of available opcodes, jump styles, and operators can be found in format/abc/Data.hx.
Don't hesitate to ask on the haXe mailing list if you have any question about format.abc usage.
--------------------------------------
File Formats
The format library enables you to read/write several file formats, see the Home Page for the list of supported formats.
You can download it by using haxelib install format
You can use the library by adding -lib format to haxe commandline parameters.
The package format contains one subpackage per supported file format.
Reference
===============================================================
swf混淆研究到…
| swf的abc结构还算比较容易理解。由大到小,就是scripe,class,instance,然后就是方法及变量了。个人理解是一个类,编译后在abc中体现就是一个class和一个instance。而一个as文件就是一个scripte。有什么区别呢?如果一个as文件中写了两个 class,这时候就可以看出区别了。这个as文件会对应两个class和两个instance,而只对应一个scripte。 script有初始化方法,在该方法内,会初始化存在于该script中所有的类。这个方法只执行一次。于是可以想到,可是使用prototype 来注入方法。在所有类初始化后,将类对应的instance方法注入到该类的prototype中去;然后删除instance的所有方法。这样的话,效果是一样,但是代码就隐藏起来了(听说asv目前的版本可以看到script中的代码了)。 当然这个时候会产生一些问题。最为明显的就是方法调用。swf中指令findpropstrict(0×5d)是其实是不会搜索prototype中的方法——除非使用with控制scope数据。于是还需要在所有指令findpropstrict前注入指:令:getlocal0(0xd0),pushwith(0×1c),popscope(0×1d) 处理示例: 不过目前还没有写出应用。只是自己的尝试。先前的swf加密/混淆,请查看这里》》》》 air代码:
|
浙公网安备 33010602011771号