声明:这里所讨论的(以及后续相关的as3加密教程)所有方法都来自网络和我个人试验,
如果有错误,还请大家赐教,所有其它内容均为个人观点,若有不同意见,也可提出讨论。
所列举方法与代码引用了许多其它资料,在此可能不会一一列举出,相关作者如有需要注明来源,可以自行联系我(回帖或邮件都可)。
另外,这几篇加密入门教程其实也可以看成普通教程,只不过披件“加密”外衣而已。
比如,alchemy混淆可以看成简单的alchemy调用as3函数教程,跳转指令混淆可以看成as3c的hello world级入门教程。
为什么要加密?
1保护游戏数据,防止外挂作弊
2客户要求
3老板要求
4保护个人权利
之前对swf加解密没有研究,也不太感兴趣。一月份有位朋友同我探讨这一问题,才开始关注,也学到不少相关东西,空余也做了几个加壳、混淆试验。虽然商业的swf加密、破解软件已很成熟,网上关于这方面的资料却不多,这里总结了一下几个实际中常用as3代码混淆方法。
如果说加壳是对swf化装,那么混淆就是整容,不,更确切的说是毁容,对破解者来说是才是整容。俗话说,毁容容易整容难,这就是混淆的优势。这里总结几个常见的方法,来把你的swf毁个面目全非。
据我了解,实际中as3程序员对代码保护基本上都是手动混淆(修改变量名)。强制使用非法变量名完全可以保护住代码,尤其是源代码比较长,类文件比较多时。反编译出的东西基本没可用性。很少有人去用加密软件,即时用加密软件,基本上也就混淆一下代码,深度加密(加壳,随机跳转指令等)会降低flash运行效率,并很容易带来一些不可预知错误,甚至有时多次调试都发现不了,得不偿失。
所以这里首先推荐强制使用非法变量名混淆方法。另外,我认为alchemy是flash10最有用、最有意义的东西(3D API目前就是个鸡肋,pixel bender实现的功能太弱,其他新功能也没见对flash有何惊人改变),
alchemy的出现同时也给所有的swf反编译软件带来了一次“危机”。
这里第一部分是一个简单的alchemy混淆代码教程(其实就是alchemy调用flash函数教程)。对alchemy不感兴趣的朋友可直接跳到第二部分-强制使用非法变量名。
第一部分 使用alchemy混淆as3代码(选用)
为什么要用alchemy?
1.C语言是程序员的老本行,alchemy使用C/C++写代码,对多数程序员来说要比用as3更加得心应手。
2.Alchemy代码效率高,使用一些优化指令,尤其对计算速度提升明显。Joa Ebert给过一个极端的例子:纯as3的fps3~5,使用Alchemy优化指令编译后fps飙到200多。当然一般来说速度不会这么大幅改进。我的Bengine引擎最初是纯as3写的,fps0~5,使用Alchemy后可达到8~40.
3.Alchemy代码移植性好,尤其对纯bitmapdata操作的试验,可很方便地与allegro,sdl程序代码互相转换。
目前没有反编译软件可导出使用Alchemy写的源C/C++代码。Alchemy使用C/C++直接生成AS3字节码,目前反编译软件只能针对as3代码反编译,而且编译生成swc就自动加入c标准库,直接导致源文件变大,导致破解难度加大。
我估计以后也很难有反编译软件可以导出alchemy源C/C++代码,引用一段asv作者Burak关于反编译alchemy的评论"For Alchemy some new bytecode instructions were introduced to AVM2 (see Scott Petersen slides PDF). I'm not sure what this will mean for ASV. If we will be dealing with a full featured optimizing C/C++ compiler, decompiling back to C/C++ will be really hard work for us, that I can say..."(一些新的bytecode指令因alchemy而引入AVM2,我不敢肯定这对asv意味着什么。如果我们要面对的是一个全功能优化的C / C + +编译器,反编译回C/C++对我们来说将是非常困难的,我可以说…)
使用alchemy混淆代码简单例子(源代码见附件):
其实反编译器对HaXe生成的代码支持也不好。直接用HaXe写,代码反编译出,绝大多数不能编译,但一般代码结构还很清楚。如果项目比较大,使用HaXe写基本也用不着去加密。
不喜欢使用HaXe原因:1.已有了Alchemy,2.HaXe资料少。
基本思想,代码关键部分使用alchemy写(其实只有某一重要的小部分用alchemy也可以),as3部分只写一个class Main extends Sprite作容器。
下面代码给了一个简单例子,其实as3部分还可以减少,转为alchemy部分。
(项目文件以打包提供下载,见附件)
代码(as3部分):
- package {
- import cmodule.Bengine.CLibInit;
- import flash.display.*;
- import flash.events.*;
- [SWF(width="300", height="300", backgroundColor="#123456")]
- public class Main extends Sprite {
- public var cLibInit : CLibInit;//alchemy库
- public var alcLookupLib:Object;
- public function Main()
- {
- cLibInit = new CLibInit();
- alcLookupLib = cLibInit.init();//初始化alchemy库
- addChild(new Sprite())//添加一个空Sprite对象到舞台
- addEventListener(Event.ENTER_FRAME,enterFrame)// 添加帧循环
- }
- public function enterFrame(e):void
- {
- removeChildAt(0)
- addChild(alcLookupLib.initialize())//添加alchemy生成的Sprite对象到舞台
- }
- }
- }
代码(C部分):
- #include "AS3.h"
- int r=0;//
- AS3_Val initialize(void* self, AS3_Val args)
- {
- AS3_Val spNS = AS3_String("flash.display");//取得命名空间
- AS3_Val spClass = AS3_NSGetS(spNS, "Sprite");//取得Sprite类
- AS3_Val emptyParams = AS3_Array("");//Sprite类参数
- AS3_Val sp = AS3_New(spClass, emptyParams);//声明一个Sprite对象
- AS3_Val gpc= AS3_GetS(sp, "graphics");//取得该Sprite对象graphics属性
- AS3_CallTS("beginFill", gpc, "IntType",0xffffff*rand());//使用随机颜色填充
- AS3_CallTS("drawRect", gpc, "IntType, IntType, IntType, IntType",-100,-100,200,200);
- //画一个方形
- r+=5;//旋转角度增加
- AS3_Val ro = AS3_Int(r);//转换C-Int为AS3-Int
- AS3_SetS(sp,"rotation",ro);//设置当前Sprite对象旋转角度
- AS3_Release(ro);
- AS3_Val xy = AS3_Int(150);
- AS3_SetS(sp,"x",xy); //设置当前Sprite对象x位置
- AS3_SetS(sp,"y",xy); //设置当前Sprite对象y位置
- AS3_Release(xy);//释放无用变量
- return sp;// 返回当前Sprite对象
- }
- int main()
- {
- AS3_Val initializeMethod = AS3_Function( NULL, initialize);
- AS3_Val result = AS3_Object("initialize: AS3ValType",initializeMethod);
- AS3_Release( initializeMethod );
- AS3_LibInit( result );
- return 0;
- }//end of int main
编译过程:C部分:打开cygwin->cd /cygdrive/f/alchemy/ALCSWF/lib
source /cygdrive/f/alchemy/alchemy-setup
alc-on
gcc ALCSWF.c -O3 -Wall -swc -o ALCSWF.swc
生成ALCSWF.swc
AS3部分:打开ALCSWF.as3proj->build project
编译结果见附件。
大家可以尝试使用反编译软件看下源码。 alcswf.zip (161.04 KB)