Flash之swf文件的加密与破解

2025-10-13 20:27:38

Flash之swf文件的加密与破解

Flash,现在叫animate,风靡于PC网络时代,整个时代弥漫着无数经典的作品,现在是移动互联时代H5逐渐代替了她的位置。逐渐地,flash变成了制作H5的一个工具。

深呼吸一下……顺便追忆前世今生 。 好了,闲言少叙,且看flash的swf文件。 swf文件是一种公开标准的文件格式,一般由flash软件发布。 文件格式(SWF)详细说明书https://blog.csdn.net/yjfkpyu/article/details/4032202http://www.360doc.com/content/15/0112/12/9200790_440101266.shtml 用其开发软件可以承载交互丰富的多媒体内容。 为了保护软件内容不被轻易的盗取,一般都要进行加密。

一般swf加密方法,都是按照一定的算法将文件的bytearray进行变换,得到一个player无法识别的文件。 player播放时需要按照算法逆运算,就可以得到swf文件然后进行装载播放了。 说白了加密解密就是玩一个字符串的游戏。 常用的操作如下 异或、替换或增加数据、改变字节顺序、base64转换、压缩等

本来嘛,内容既要隐藏又要展现就是矛盾的。

软件可以扫描内存从中提取展示的swf文件。 不管怎样内容还是要给人看的,所以再怎么变换也有让别人拿走的机会。 因此这些加密的手法也只能做到在一定程度上的防备。

对于一个经验多一点的闪客来说,想要的都能想办法拿到。声明:本人遵纪、守法、讲道德,且一贯的尊重所有软件的知识产权。反编译代码仅为学习研究之目的,并无恶意。

下面举个栗子: 案例1

base64+增加数据实施对文件的加密。 反编译代码

package

{

import com.hurlant.util.*;

import flash.utils.*;

public class ByteCodeMix extends Object

{

public function ByteCodeMix(arg1:String)

{

super();

if (arg1)

{

_key = arg1 + innerKey;

}

else

{

_key = innerKey;

}

endkb = new flash.utils.ByteArray();

endkb.writeUTFBytes(endkey);

return;

}

public function enCodeMix(arg1:flash.utils.ByteArray, arg2:int):flash.utils.ByteArray

{

var loc3:*;

(loc3 = new flash.utils.ByteArray()).writeUTF(_key);

var loc4:*;

(loc4 = new flash.utils.ByteArray()).writeInt(loc3.length);

loc4.writeBytes(loc3);

loc4.writeBytes(arg1);

loc4.writeBytes(endkb);

var loc5:*;

(loc5 = new flash.utils.ByteArray()).writeBytes(loc4, 0, arg2);

var loc1:*=com.hurlant.util.Base64.encodeByteArray(loc5) + _key;

var loc2:*;

(loc2 = new flash.utils.ByteArray()).writeUTF(loc1);

loc2.writeBytes(loc4, arg2);

return loc2;

}

public function deCodeMix(arg1:flash.utils.ByteArray):flash.utils.ByteArray

{

arg1.position = 0;

var loc3:*=(loc3 = arg1.readUTF()).replace(_key, "");

var loc2:*=com.hurlant.util.Base64.decodeToByteArray(loc3);

var loc1:*=new flash.utils.ByteArray();

arg1.readBytes(loc1, 0, arg1.bytesAvailable);

var loc4:*;

(loc4 = new flash.utils.ByteArray()).writeBytes(loc2);

loc4.writeBytes(loc1);

var loc6:*=new flash.utils.ByteArray();

loc4.position = 0;

var loc5:*=loc4.readInt();

loc4.position = loc4.position + loc5;

loc4.readBytes(loc6, 0, loc4.length - loc5 - 4 - endkb.length);

return loc6;

}

private var _key:String;

private var innerKey:String="iZSBGbGV4IDQgQXBwbGljYXRpb248";

private var endkey:String="lt_xggh_fla.sprite185copy3_89";

private var endkb:flash.utils.ByteArray;

}

解密方法

loc1 = (loc3 = new ByteCodeMix("RpdGxlPjxkYzpkZXNjcmlwdG")).deCodeMix(flash.net.URLLoader(arg1.target).data as flash.utils.ByteArray);

分析: 能看出 有用的加密的文件结构是 -------------------------------------------------------------------------- | RpdGxlPjxkYzpkZXNjcmlwdGiZSBGbGV4IDQgQXBwbGljYXRpb248 | -------------------------------------------------------------------------- | swf数据 | -------------------------------------------------------------------------- | lt_xggh_fla.sprite185copy3_89 | --------------------------------------------------------------------------

案例2

改变顺序反编译代码

package

{

import flash.display.*;

import flash.events.*;

import flash.net.*;

import flash.system.*;

import flash.utils.*;

public class DecryptLoader extends flash.events.EventDispatcher

{

public function DecryptLoader(arg1:String, arg2:String, arg3:Boolean=true)

{

super();

isEncode = arg3;

_strUrl = arg1;

_strKey = arg2;

return;

}

public function get getUrl():String

{

return _strUrl;

}

public function get getKey():String

{

return _strKey;

}

public function set setUrl(arg1:String):void

{

_strUrl = arg1;

return;

}

public function set setkey(arg1:String):void

{

_strKey = arg1;

return;

}

private function validKey(arg1:Array):Boolean

{

arg1.sort();

trace(arg1);

return arg1.every(sequential);

}

private function sequential(arg1:*, arg2:int, arg3:Array):Boolean

{

return arg1 == arg2;

}

public function startLoad(arg1:Function=null):void

{

var loc2:*=new flash.net.URLRequest(_strUrl);

var loc1:*=new flash.net.URLLoader();

loc1.dataFormat = "binary";

loc1.addEventListener("complete", handleUrlLoadComplete);

loc1.addEventListener("ioError", onErr);

if (arg1 != null)

{

_progress = arg1;

loc1.addEventListener("progress", arg1);

}

loc1.load(loc2);

return;

}

private function onErr(arg1:flash.events.IOErrorEvent):void

{

dispatchEvent(new flash.events.Event("LoadFail"));

return;

}

private function handleUrlLoadComplete(arg1:flash.events.Event):void

{

if (_progress != null)

{

arg1.target.removeEventListener("progress", _progress);

}

var loc1:*=arg1.target.data as flash.utils.ByteArray;

var loc4:*=new flash.utils.ByteArray();

if (isEncode)

{

if (!decrypt(loc1, loc4))

{

dispatchEvent(new flash.events.Event("LoadFail"));

return;

}

}

var loc2:*=new flash.display.Loader();

loc2.contentLoaderInfo.addEventListener("complete", handleByteLoadComplete);

var loc3:*;

(loc3 = new flash.system.LoaderContext()).allowCodeImport = true;

loc3.allowLoadBytesCodeExecution = true;

loc3.applicationDomain = flash.system.ApplicationDomain.currentDomain;

if (isEncode)

{

loc2.loadBytes(loc4, loc3);

bytes = loc4;

}

else

{

loc2.loadBytes(loc1, loc3);

bytes = loc1;

}

loader = loc2;

return;

}

private function decrypt(arg1:flash.utils.ByteArray, arg2:flash.utils.ByteArray):Boolean

{

var loc4:*=0;

var loc6:*=0;

var loc3:*=0;

if (arg1.length < 2000)

{

return false;

}

if (_strKey.length != 20 * 2)

{

return false;

}

var loc5:*=[];

var loc7:*=[];

loc4 = 0;

while (loc4 < _strKey.length)

{

loc5.push(_strKey.substr(loc4, 2));

loc7.push(_strKey.substr(loc4, 2));

loc4 = loc4 + 2;

}

if (!validKey(loc7))

{

return false;

}

var loc2:*=[];

var loc1:*=new flash.utils.ByteArray();

loc6 = 0;

while (loc6 < loc5.length)

{

loc2["byte" + loc6] = new flash.utils.ByteArray();

arg1.readBytes(loc2["byte" + loc6], 0, 2000 / 20);

++loc6;

}

arg1.readBytes(loc1);

loc3 = 0;

while (loc3 < loc5.length)

{

trace("byte" + loc5[loc3]);

arg2.writeBytes(loc2["byte" + int(loc5[loc3])]);

++loc3;

}

arg2.writeBytes(loc1);

return true;

}

private function handleByteLoadComplete(arg1:flash.events.Event):void

{

trace((arg1.target as LoaderInfo).loader);

dispatchEvent(arg1);

return;

}

public var loader:Loader;

public var bytes:ByteArray;

private const KEYLENGTH:uint=20;

private const BUFFERSIZE:uint=2000;

private var _strUrl:String;

private var _strKey:String;

private var _progress:Function;

private var isEncode:Boolean;

}

}

}

解密代码

var loc1:*=new DecryptLoader(arg1, "0010170918061315121405160704110803021901");

loc1.addEventListener("LoadFail", loadFail);

loc1.startLoad();

分析: 很有意思的参数"0010170918061315121405160704110803021901"是0-19的组合 也是打乱顺序的规则。 100个字节为1组,打乱前20组。