如何防止SWF文件被反编译-程序员宅基地

技术标签: ViewUI  开发工具  javascript  

这篇文章的标题所提出的问题的答案是“不可能”。至少对我来说是不可能的。借助适当的工具,我们可以反编译任何SWF文件。所以,不要将重要的信息置于SWF文件中。SWF文件中不要包含个人的帐号或者密码。

  我将简要的论述“保护”技术的历史,和他们是如何失败的,接着我将说明我们能尽的最大努力。中国古语有云,“规则只能防君子,不能仿小人”。

  公开的文件格式

  在讨论之前,我们先要知道,SWF的文件格式是公开的。公开的文件格式,意味着SWF文件并不是只能由Flash生成。其他公司也能制作可以在SWF播放器上播放的SWF文件。公开的文件格式意味着从什么位置获取什么信息是众所周知的,也就意味着每个字节都是众所周知的。因此,如果我有时间来一个字节一个字节的检查SWF文件,我可以了解所有的细节。

  当然,对于一个2M大小的SWF文件,我没有时间来逐个字节的检查。因此,我就借助软件来完成这个工作。如果软件遇到问题,我会暂时接管这个工作,检查发生问题的字节。修正它,然后继续。所以,没有什么东西能够掩藏的住,其限制只是我的时间和我的耐性。如果反编译一个SWF文件的酬劳是数百美元的话,我想我会花上数年时间来逐个字节的读取它。

  好了,以下是反编译和保护技术之间的战争历史。

  防止被导入

  伴随着Flash的出现,Macromedia提供给开发者一个“防止导入的口令保护”功能。如果你给SWF文件加上导入口令的话,这个SWF文件就不能被导入了(知道倒入密码除外)。SWF文件不加保护的话,其中的矢量图形可以被导入到fla文件中。这种保护没有什么用处,仅仅是假想的安全。

  试想一下,你的SWF被用户的播放器来播放的,你不可能利用用户的播放器来保护你的SWF文件。因此,它是如何来保护SWF文件的呢?很简单,这种保护存在于你所买的Flash开发工具中。Flash开发工具不能导入有(导入)密码的SWF文件。没关系,对吧?我可以用十六进制编辑打开那个SWF文件,删除保护密码,从而也就移除了保护功能。

  如此简单,所以忘记导入保护功能吧。

  转换成放映机文件并且压缩

  如果我将它转化成exe格式的放映机文件,还可以被反编译吗?答案:是的,SWF文件仍然存在其中。借助软件可以很容易的将SWF文件从exe文件中释放出来。压缩可以使SWF文件不能被十六进制编辑器读取,压缩是一种保护措施吗?压缩算法类似于zip算法,很容易被破解。

  FLASM AND THE P-CODE

  在flash5的时代,出现了两种流行的工具,免费的“Flasm”和商业的“ASV 2.0”。Flasm就是“Flash asm”,它将SWF中的字节码解释成可理解的简短代码(p-codes)。比如“a=3”显示为"push 'a', 3", "setVariable";SWF中的字节码是:"96 08 00 00 61 00 07 03 00 00 00 1D".如果想学习“SWF格式结构”的话,这是个非常有价值的工具。

  程序员喜欢用高级语言(比如:C、C++)来开发软件,但是当讲求效率的时候,他们会在其中混合使用低级的汇编语言。因此,有时候开发者会利用Flasm编写低级别的p-codes来增加效率。所以,Flasm编辑SWF中的actionscript是强有力的。你可以参考例子,了解如何利用这种技术来优化3D代码,但是怀有恶意的用户能够“编辑”SWF文件,SWF中的任何保护措施都可以不费力的移除。我们不需要知道密码就可以移除保护措施。

  这儿有个通用、知名的技术来保护我们的影片不被偷窃并在其它的范围内显示。我们编辑脚本来检查_url属性,如果_url不是我们(合法)的范围,就使功能失效并显示一条“You are thief”的消息。可是,借助Flasm可以很容易删除这条脚本语句。不需要1分钟便可以破解这种保护措施。

  ACTIONSCRIPT VIEWER AND "void (a)<=b>"c" || 0(!1 && !0)"

  ASV(ActionScript Viewer)能够从SWF中提取出角色,例如::声音、形状和位图等都可以被窃取。

  它同样可以提取actionscript字节码,ASV 2尝试将p-codes匹配成高级别的actionscript.当遇到"push 'a', 3", "setVariable";时显示"a=3"这样的等同于actionscript的语言。然而我们能够创造没有任何模式来匹配的代码,从而破坏ASV的解析。利用Flasm,可以容易的编写不同于标准模式的代码,从而使ASV不能进行匹配工作。扰乱ASV 2工作的一句有名的代码是“;”,这是一条jung代码。它不做任何事,但是能搞乱ASV 2的工作。

  但是,当保护脚本众所周知时,ASV的作者(Burakk)当然不会放过它。这种保护技术对于ASV 3来说就失效了。

  飞速发展的反编译工具

  之后是MX时代的到来,许多反编译工具的出现,加快了Flash厄运的速度。

  现行版本的ASV 4除了显示得到匹配的actionscript代码,得不到匹配的代码以p-codes形式显示。如果解释成p-codes发生问题,将显示SWF中的字节码。它同样能够显示代码在SWF文件中所处的偏移量,这意味着它不会失效。你不可能扰乱它的工作,因为,至少它能显示SWF文件中的“字节码”。

  更甚的是,Flash MX2004提供通过JavaScript API来生成“fla”文件。那使它能够建立发布成SWF格式的fla文件。此刻,所有的东西都在那边了。

  更不用说声音、形状和位图了,偷窃者不喜欢这些东西,因为它们套容易取得了。偷窃者喜欢切的actionscript,因为其中隐藏着密码,因为其中有阻止此影片正常播放的脚本代码,

  如果ASV只能将脚本反编译成字节码,那么它对于大多数偷窃者是没有用处的。因此很多人进他们的最大努力来阻止ASV 4将脚本反编译成actionscript或者p-codes.实际上,对于大多数反编译者来说,脚本得不到匹配,反编译工具就无用了。

  这是曾经用过的一些技术,当它们在因特网上发布并且被反编译组织揭示之后,每种技术的保护效果最终都会变得非常薄弱和气数将尽。

  依据数据尺寸(句子)分块反编译

  大多数之所以能够成功的迷惑或者破坏反编译器,原因在于播放器和反编译器的不同行为。播放器逐个的执行字节码,就像现实世界中的读书一样,一个单词,接着下一个单词。然而反编译器通常将字节链分成有意义的片断,犹如现实世界中的读书一样,一个句子,接着下一个句子。

  反编译器的行为如此简单的原因在于大多数的p-code都是遵循数据大小规律的。对于字节码("96 08 00 00 61 00 07 03 00 00 00 1D"),反编译器遇到代表"push"操作的0x96时会想“push什么呢”?下个字节(0x0008)指示的内容:接下去8个字节中的内容压入堆栈,即把("00 61 00 07 03 00 00 00")压入堆栈。所以,通常反编译器依据数据大小将简短的片断切成一块一块的,这样便会解释成“push something”。因此,("96 08 00 00 61 00 07 03 00 00 00")就成为一个句子。下一个字节是下一个句子的开始,就是代表"setVariable"的0x1D.这样8个字节的"something",将被更进一步解释成一个字符串“a”和一个数字“3”。

  让我们来看一下字节码:("99 02 00 05 00 96")。0x99意味着分支(或者跳转),在哪里分支呢?接下去的是(0002),因此数据存储在机下去的两个字节中,将它在下面两个字节处截断。总之,我们知道"99 02 00 05 00"是个句子。接下去的是0x96,代表下个句子的开始。

  再看第三个例子,字节码:("88 08 00 03 00 63 00 62 00 61 00 96 07 00")。0x88代表定义常数,定义的常数内容是什么呢?后续字节(0008),表明常数内容存储在后继的8个字节中。所以,句子就是:("88 08 00 03 00 63 00 62 00 61 00")。代表下个句子开始的("96 07 00 ……),意味着将7个字节的数据压入堆栈。

  因此,字节码砍成单独的句子。每个句子由命令和数据组成,并且以命令打头。因此,每个句子都是一个基本的单元。理论上来说,对于这种方法没有什么错误。

  使播放器从句子中间开始读数据

  让我们开始讨论“是播放器从句子中间读数据”的破坏反编译器的技术。

  首先,我举一个现实世界的例子:

  John says good morning. Mary says thank you.现在生成SWF文件:

  skip 9 words Tom says John says good morning. skip 3 words back 7 wordsMary says thank you.如果逐个字读的话,结果和原来一样,然而反编译器按句子来读取,自然发生错误。第一,它知道Tom说了什么,但语法不对,汇报出错;第二,它没有看到第二个“skip”命令,因为它处于句子中间;第三,当它被迫退回7个字后,感到迷惑,认为应该从“Tom said”开始执行整个句子;第四,这个错误使它在第二行和第三行之间陷入无限循环之中。

  总之,我们增加了“Tom said”这句垃圾代码,并提供整个句子长度的错误数据大小信息。这个错误的长度覆盖了“skip”命令。

  来看个真实的例子,请注意,这些技术需要操作字节码,纯actionscript不能够实现。

  例1 :

  向前跳转的包含无效尺寸数据的死代码。

  push True branchifTrue label2 constants ''label2:push 'a',3setVariable你仔细看的话,会发现"constants ''"这行是垃圾代码,它不可能被执行到。然而,理论上,当第二行的结果为"not True"时,它将被执行。因此,反编译器尝试对它进行反编译。

  让我们来增大"0x88 - constants"后面的"sentence size",从而包括知道脚本结尾的所有字节。你知道,反编译器将把字节码砍成像这样的3个句子:

  push True branchifTrue label2 constants label2: push 'a',3 setVariable如果你试图反编译此SWF文件,根据我前面提到的4个错误,一些反编译器将碰壁。仍旧有些反编译器幸存,但只是显示:"if(false){};".ASV 3也不能显示此脚本,但是ASV 4能够显示。为了破解这个SWF,我们移除死代码"constant xxxx", (0x88和随后两个字节),然后所有的东西都得到反编译。

  这儿是zip格式的文件,将详细解释怎样制作这样的受保护文件。

  例2:

  先后跳转的包含无效尺寸数据的死代码。

  push 'b' label1:push 'a',3 setVariable branch label2 branch label1

  label2:push 'b'是句垃圾代码,我们将修改它,用来使ASV 4碰壁。让我们来修改push 'b'的"length of sentence".修改"0x96"后面的2个字节的数据,使句子的长度增长到分支Label1之前。这样,反编译器将把字节码作为3个句子:

  push label1: push 'a',3 setVariable branch label2 branch label1 label2:

  现在,反编译器不知道将把什么压入堆栈,同样它将在第一个句子和第二个句子之间形成死循环。这种技术将使大部分反编译器碰壁。Flasm、ASV 4同样也无效。为了破解这个SWF,我们手工删除"push b" (0x96和后随的2个字节),这样所有的东西都可反编译了。

  当这个技术流传后,burakk将修改ASV 4,使它能正确处理死循环。这样下个版本的ASV就可对付这种技术了。

  这儿是zip格式的文件,将详细解释怎样制作这样的受保护文件

  

  非显示字符和混淆器

  除了阻碍反编译器的技术之外,我们还可以使反编译的结果不容易读。你可以浏览关于混淆器的网站。

  基本上,它是对变量和函数的名字进行重命名。

  function -3(-4){trace(-4);} function -1(0,-2){ if(0<-2){-3(1);} }

  肯定的是,偷窃者不能仅仅是拷贝、粘贴就能使用这些代码。编译器不允许你对一个函数进行这样的命名。

  混淆器的局限是改变函数的名字可能给下面的脚本代码带来麻烦。

  function myFun(){trace("myFun");} a="my";b="Fun";this[a+b]();

  另一个技术是使函数的名字不可显示。比如,用汉字作为函数名,反编译器可能就会不能很好的显示它。然后,我们便会看到:

  function ?(){?,?){?。?=?;}

  ASV 4使用unicode编码显示不可显示字符,所以,结果是易读的,只不过增加了点轻微的难度。

  自我保护

  如果你找到一个很好的方法来保护自己的SWF不备反编译,不要与别人分享这个方法,至少不要再因特网上公开它。当然,它不能过100%的防反编译,至少对我来说是这样。但是,不是所有的人都对SWF的格式了如指掌。许多,偷窃者仅仅只会借助软件来反编译SWF.因此,如果你的目的是尽可能少的偷窃者能够偷窃你的SWF,那么请保护好你的(白虎SWF的)秘密方法。

  只是在此提醒你,你的SWF是无保护的。对于熟悉SWF格式的人来说,所有东西都是毫无遮掩的。如果你的目标只是保护“一些函数”的话,它应该是安全的。他们未必会窃取你的函数,他们会编写自己的函数。

  通用保护措施

  我们在网站上放了个联机游戏,不幸的是,许多访问者只是访问我们的站点仅仅一次而已,然后利用下载的版本来离线玩。有时,我们甚至发现我们的游戏出现在其他的站点上。

  为了避免这种情况发生,下面是可采取的保护措施:

  1. 所属领域检查

  编写脚本检查_url,如果_url是""就播放影片,否则不播放或者退出。当离线播放的时候,_url应该像"file://C| someSub/game.SWF";但它在其它domain中时,_url就形如"".因此,这个技术可以恰当的加上一些保护。当然,对于心存不良的反编译者来说是无用的。那些脚本可以借助Flasm来删除或者修改为不检查。尽管在其它公开场合未必能看到被破解的SWF文件,但是离线也能够播放的SWF就可能发生上述情况。

  2. 服务端口令验证

  编写脚本,并且在开始游戏时从服务端加载密码。如果密码为空,则停止游戏或者退出游戏。这很容易被怀有恶意的用户破解,他们只要编辑SWF文件,将那些脚本删除即可。哪些脚本不可以被删除呢?当开始游戏时,从服务端加载的地图数据是进行游戏必须的,所以心存不良的用户不可能删除这些脚本。为了进行游戏,它必须提供这些地图数据。当然,它可以从缓存在临时文件夹中的数据中挑选地图数据,提供给SWF,从而激活游戏。

  3.将SWF或者变量置于服务端

  这是第二种技术的扩展、延伸,该技术已经广泛的使用着。起初的游戏(SWF)文件只是个装载器,当单击播放(或开始)按钮后,将加载另一个SWF文件。当需要地图文件的时候,便从服务端加载地图数据。当加载数据遇到阻碍时,将从服务段再次加载受到阻碍的SWF文件。新层上的数据也是从服务端传过来。

  从这儿。我们可以看到一个原则:防止反编译的最好方法是“不给”。

  如果一些愚蠢的窃贼只下载game.SWF文件,他不可能玩这个游戏。 他需要在缓存中挑选出所有的SWF文件和变量。打开所有的SWF文件,编辑这些变量的名字,使它与缓存中的变量的名字一致。

  如果我们的地图由CGI随机产生,那么窃贼只可能拥有一份地图,他没有随机产生地图的权力。如果是个迷宫游戏的话,充其量,他只能玩一个迷宫,他没有“动态产生迷宫”的功能。如果心存不良的用户玩这个游戏将碰到一个新的阻碍,因为在他的缓存中没有这个新的受到阻碍的SWF文件,所以将无法进行游戏。

  因此,许多算法和功能都放在服务端,那个SWF文件只是个界面而已。这是个完美的保护措施,但是缺陷是这件产生一个转为游戏工作的CGI,而不是Flash.我们正在讨论关于SWF的保护问题,这个解决方案是不妥当的,因为SWF文件自身得不到保护

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_34239169/article/details/85817895

智能推荐

自定义配置ros arduino bridge功能包集_ros_arduino_bridge-程序员宅基地

文章浏览阅读5.8k次,点赞10次,收藏47次。写在前面首先我对未及时分享自己的配置及源码向各位网友道歉。本文是对博文ros_arduino_bridge功能包集的使用的拓展,主要是对如何修改ros arduino bridge功能包集,使其兼容其他硬件做一些简要的说明。在这里我以自己的配置为例为大家讲解,如有疑问可以通过csdn私信我或者通过邮箱联系我,我的email:[email protected],欢迎大家为我纠错。..._ros_arduino_bridge

多模块依赖mybatis扫描不到xml文件_mybatis扫描另一个module的xml-程序员宅基地

文章浏览阅读541次。分了多个模块,查询xml报错org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.zjp.mapper.UserMapper.selectAll没有找到xml原来配置成下图:最终还是扫描不到xml解决:原来在配置mybatis:mapper-locations:classpath:xxxxx时,需要在classpath后加个号(classpath:),表示扫描所有模块下指定扫_mybatis扫描另一个module的xml

cocos2d-x3.x屏蔽触摸遮罩层屏蔽按钮_cocos2d如何实现长按时屏蔽其他事件-程序员宅基地

文章浏览阅读3.1k次。cocos2d-x3.x屏蔽触摸遮罩层屏蔽按钮_cocos2d如何实现长按时屏蔽其他事件

Android CameraX和HyperLPR3配合使用-程序员宅基地

文章浏览阅读398次,点赞10次,收藏9次。在实时图像预览里面,调用HyperLPR3识别摄像机实时图像里面的车牌号,需要用到图片缓存区。CameraX应该按照如下代码使用。

SpringMVC配置Swagger2_swagger2 springmvc 版本匹配-程序员宅基地

文章浏览阅读1.4w次,点赞5次,收藏17次。先把配置清单摆上,然后再讲下再配置的时候遇到的坑1. pom配置&lt;!-- 这里有几点需要注意的,就是jackson的版本号与swagger的版本号问题,我尝试过jackson的版本是2.4,然后swagger的版本是2.7的,配置不成功,后面把swgger的版本号降成2.4才可以。下面的jackson不需要全部配置,只需要配置jackson-databind即可..._swagger2 springmvc 版本匹配

《从LFS到自己的Linux发行版》系列教程:一步一步体验LFS11.0_lfs 11.2教程-程序员宅基地

文章浏览阅读2.5k次,点赞3次,收藏9次。​关联文章:从LFS到自己的Linux发行版—系列教程之一:一步一步带你体验LFS8.2LFS技术细节解析(1):Linux shell硬盘自动分区脚本详解LFS技术细节解析(2):echo命令实现Linux shell人机交互详解文章目录前言第一步:LFS准备工作第二步:LFS你的的Linux系统第三步:开启你的Linux系统结语前言如果你把从源代码开始编译构建一个操作系统的工作当成厨师做一桌菜的话,LFS就是一份“菜谱”。 从今天开始,我准备一步一步带着大家从开源软件的源代码(大厨的“食料_lfs 11.2教程

随便推点

Mac上Homebrew的使用 (Homebrew 使 OS X 更完整)_homebrew `ensure in mktmpdir-程序员宅基地

文章浏览阅读10w+次。2014-02-22 wcdj0 Homebrew是啥?“Homebrew installs the stuff you need that Apple didn’t.——Homebrew 使 OS X 更完整”。Homebrew的官网[1](多语言版本)简单明了地介绍了如何安装和使用这个工具,并提供了自己的Wiki。1 安装Homebrewbrew的安装很简单,使用一_homebrew `ensure in mktmpdir

docker构建openrety + lua + mysql + rediscluster_docker openresty 添加ngx_cache_purge模块-程序员宅基地

文章浏览阅读447次。1,构建前准备名称 说明 地址 openresty-1.17.8.1.tar.gz openresty 安装包 OpenResty - 中文官方站 ngx_cache_purge-2.3.tar.gz 清理nginx缓存模块(不用可不装) FRiCKLE Labs / nginx / ngx_cache_purge lua-resty-redis-cluster-master.zip rediscluster模块,redis集群使用 GitH_docker openresty 添加ngx_cache_purge模块

POJ3352-Road Construction-程序员宅基地

文章浏览阅读484次。Road ConstructionTime Limit: 2000MS Memory Limit: 65536KTotal Submissions: 8652 Accepted: 4323DescriptionIt's almost summer time, and that means that it's almost

nowcoder 粉樱花之恋 矩阵乘法+递推_粉嘤花之恋-程序员宅基地

文章浏览阅读122次。原题地址思路:递推构造矩阵+矩阵乘法分析:由第一次为2,第二次为4,第三次为7,第四次为12,第5次20,很容易可以发现,第n次恰好是斐波那契数的第n+3项-1,由Fn=Fn-1+Fn-2直接构造矩阵{{1,1},{1,0}},取n+3次幂后-1即得答案,这道题时间卡的比较紧,一些其他的思路时间复杂度稍大一点就过不了了ac 代码:#include<iostream>#include<cstring>#include<cstdio>#include<al_粉嘤花之恋

反向传播算法_反向传播会更新哪些函数-程序员宅基地

文章浏览阅读487次。1、损失函数 损失函数在统计学中是一种衡量损失和误差程度的函数,它一般包括损失项(loss term)和正则项(regularization term)。 损失项 损失项比较常见的有平方损失,常用在回归问题;以及对数损失函数,常用在分类问题。 正则项 加入正则项目的是减小权重的幅度,防止过度拟合。常用的有L1-r_反向传播会更新哪些函数

并查集小结 (参考birdfly+修改)-程序员宅基地

文章浏览阅读121次。并查集的作用:并和查,即合并和查找,将一些集合合并,快速查找或判断某两个集合的关系,或某元素与集合的关系,或某两个元素的关系。 并查集的结构:并查集主要操作对象是森林,树的结构赋予它独特的能力,对整个集合操作转换为对根节点(或称该集合的代表元素)的操作,一个集合里的元素关系不一定确定,但相对于根节点的关系很明了,这也是为了查找方便。 并查集优化方法:按秩合并和..._birdfly注册码simulink 小程序