上一篇粗略的过了一遍数据请求流的过程。
1.发送请求 AddRequest() 在这里面构造数据流请求的路径
2.请求数据LoadStream()
3.数据解析 ProcessStreamData()
数据解析ProcessStreamData() 通过AbstractXmlDataReader.as里面的ReadStream()函数来解析。我们重点分析这个函数的走向
public override function ReadStream(stream:flash.net.URLStream, arg2:uqee.core.entity.StreamRequestInfo):String
{
var bt:* = new flash.utils.ByteArray();
//stream.readBytes(bt,0,stream.length);
//trace("长度:"+bt.length);
//trace(bt);
var loc1:*=null;
var loc2:*=0;
var loc3:*=null;
var loc4:*=0;
var loc5:*=null;
var loc6:*=null;
var loc7:*=null;
var loc8:*=null;
if (!arg2.IsConfusion) /*如果是未加密的数据就直接读取并存储*/
{
loc1 = new flash.utils.ByteArray();
stream.readBytes(loc1, 0, loc2);
loc1.position = 0;
this.Store(arg2.FileName, new XML(loc1));
return null;
}
/*处理加密的xml数据*/
while (stream.bytesAvailable > 0)
{
if ((loc2 = stream.readInt()) != 0)
{
loc7 = new flash.utils.ByteArray();
stream.readBytes(loc7, 0, loc2);
loc7.uncompress();
loc7.position = 0;
loc3 = loc7.readMultiByte(loc7.length, "gbk");
loc2 = stream.readInt();
}
else
{
loc3 = arg2.FileName.replace("_" + uqee.core.global.GlobalVariables.Lang, "");
loc2 = stream.bytesAvailable;
}
if(false)
{
}
else
{
loc4 =16;
loc8 = arg2.Url.replace("_" + uqee.core.global.GlobalVariables.Lang, "").split("/");
loc4 = loc8[(loc8.length - 1)].indexOf(".");
}
loc5 = this.ReadCompressStream(stream,loc2,loc4);
this.Store(loc3,loc5);
}
return null
}
可以看到这个函数的流程
根据Isconfusion判断是否加密。这里是mns_zh_CN.dat 文件 它是一个加密的文件 文件大小5163
以下是文件开始的部分十六进制数据视图
00000000h: 00 00 00 00 2B B0 00 16 E4 34 00 00 00 00 00 00 ; ....+?.?......
00000010h: 1E 0F CB 87 11 D8 CE 66 91 0F 83 1E CA FD 7B 33 ; ..藝.匚f??数{3
00000020h: D4 7F E9 B7 DA 28 31 76 25 66 20 4D 2A 09 6D 89 ; ?榉?1v%f M*.m?
00000030h: BA 5D 89 1B 90 49 4A 8D B8 2C 4E 0C 52 31 21 80 ; 篯?怚J嵏,N.R1!€
00000040h: 8A 78 53 5F A6 BB 89 D2 00 99 BA 96 80 04 4E 77 ; 妜S_壱.櫤杸.Nw
00000050h: 54 46 94 CE F1 F3 30 B8 6A 1B E6 B0 1C 7C 2A 9E ; TF斘耋0竕.姘.|*?
00000060h: 88 52 D7 24 60 9E 45 20 33 D6 BB 20 F4 73 15 92 ; 圧?`濫 3只 魋.?
00000070h: D3 99 D3 38 F8 47 3A 1E 8E 0A 18 C4 E5 99 6C 56 ; 訖?鳪:.?.腻檒V
00000080h: A7 C3 78 03 14 54 7C 32 05 F4 64 15 00 A9 D1 7E ; x..T|2.鬱..┭~
00000090h: 98 9A 09 6E 78 A3 7A 84 8F 7E FE 88 4B BD D6 8F ; 槡.nx剰~K街?
000000a0h: 6F 41 45 21 73 D5 24 C9 1B 4A E5 F9 9C 40 48 2E ; oAE!s??J妁淍H.
000000b0h: A2 2E F0 D1 05 23 F1 AA E5 B9 09 C3 06 FF 8F 6E ; ?鹧.#癃骞.?弉
000000c0h: 9E D0 64 88 FB DE 05 1E 3C 33 E2 8C DC 4A 3E 09 ; 炐d堺?.<3鈱躂>.
000000d0h: 5D D6 CF 01 5C 3B 0B AF B2 4B 27 69 C0 52 F2 ED ; ]窒.\;.K'i繰蝽
000000e0h: 35 4F F3 B1 69 EB 97 8F 09 CE 9B 9A B8 F6 4F B1 ; 5O蟊i霔?螞毟鯫?
000000f0h: 9C 4A 11 37 84 54 F6 13 EC 79 66 C4 1A 0A B8 44 ; 淛.7凾?靬f?.窪
00000100h: E1 E2 E0 E9 DD 22 BB 41 82 80 BD 9B 3E BC 87 62 ; 徕嚅?籄個經>紘b
00000110h: B1 68 15 D8 54 CA 47 50 27 B4 8C 40 8B 3A 2A 47 ; 県.豑蔊P'磳@?*G
00000120h: AE 33 E7 AD B5 6F 93 8B 0C 4A 33 21 47 95 03 0D ; ?绛祇搵.J3!G?.
00000130h: A7 40 F1 D5 44 1E D2 BE 26 7E B4 55 D5 23 BA 8A ; 裾D.揖&~碪?簥
00000140h: BD 34 51 AB D7 06 8C 24 84 DF 09 7E 1B 2C 5B 75 ; ?Q.?勥.~.,[u
这个函数为了调试方便我有所修改。所以简单的说一下原来的解密流程。
首先读取头4个字节,都是0 此时 文件的availablebyte 5159字节 文件名中的语言字符要被替换为空 也就是说mns_zh_CN.dat被替换为 mns.dat
然后通过indexOf(".")函数查找文件名mns.dat分割点号的位置 这里是3 这些数值在进行解密的时候都会用到
这个dat文件采用了LZMA加密方式,文件中加入了杂数据用来扰乱视线。所以在进行LZMA标准解密的时候需要去掉这些杂数据。
在ReadCompressStream()函数中它仅仅是设置了 LZMA 解密的properties,这是5个字节的数组 内容是固定的,
var loc1:*; (loc1 = new flash.utils.ByteArray()).writeByte(93); loc1.writeByte(0); loc1.writeByte(0); loc1.writeByte(128); loc1.writeByte(0);
接下来就是从mns.dat 的 5159个字节中读取有效的数据
protected function ReadConfusionStream(arg1:flash.net.URLStream, arg2:int, arg3:flash.utils.ByteArray, arg4:int):void { var loc1:*=10; var loc2:*; var loc3:*; if ((loc3 = (loc2 = arg4 % loc1 + arg4 / loc1 + loc1) % (loc1 * loc1)) == 0) { loc3 = 24; } var loc4:*=arg3.length; if ((arg4 = arg4 % loc3) <= 0) { arg4 = loc3; } arg1.readBytes(arg3, loc4, arg4); var loc5:*=new flash.utils.ByteArray(); arg1.readBytes(loc5, 0, arg4); arg1.readBytes(arg3, arg4 + loc4, arg2 - arg4 * 2 - (loc3 - arg4)); if (loc3 > arg4) { arg1.readBytes(loc5, 0, loc3 - arg4); } arg3.position = 0; return; }
arg2 的值是5159 不解释
arg3是存放标准的带解密的LZMA数据
arg4的值是3 ,也就是之前mns.dat文件分割点号的位置
它首先根据arg4进行一系列的运算得出一个loc3 这个值是作为 arg4的后备值,只有在 if ((arg4 = arg4 % loc3) <= 0) 的情况下才会有作用,暂时可以忽略。
这时候开始读数据
第一次读取3个字节
从要解密的5159个字节的数据中读取3个字节到arg3中,也就是arg4的值,读取的数据放在properties值的后面
所以这时候 arg3的值就是8个字节
5D 00 00 80 00 2B B0 00
第二次读取3个字节
它会将3个废弃的字节读取到loc5中
也就是说 16 E4 34 这三个字节是无效的。
在文件最后还有无效的字节,无效的字节数为 loc3 - arg4 = 10 个
所以它接下来要读取的有效字节数为 5159- 3*2 - 10 = 5143 个
那么最终要交给LZMA 解密的数据长度是
数据头的5个字节properties
3字节的有效数据 2B B0 00
5143个有效数据 ...
共计 5151 个字节
其中舍弃的数据有3字节+末尾的10字节
此时已经将所有有效数据读取到arg3中了。接下来要做的就是通过标准LZMA解密就OK了。很奇怪的是用反汇编出来的工程里面的LZMA解密代码解密出现问题,解密出来的文件长度是对的,但解密出来的数据全都是m 后来找了几个版本的LZMA解密代码,c++的,as的都解密成功。为什么工程里面的无法解密,这真是让人费解,希望有大神能给个解答。
解密出来的数据长度是45099
文件部分内容如下
<?xml version="1.0" encoding="utf-8"?><Modules fcmKey="P%2BViyZLtO^gRT2Huxqx#5VygbflvZx$8mFpX61VWvd;ivPu~XjL`CD7FrIe8=0" sid="P%2BViyZLtO^gRT2Huxqx#5Vygbfl$8m" uuid="P%2BViyZLtO^gRT2Huxqx#5VygbflvZx$8mFpX61VWvd;ivPu~XjL`CD7FrIe8=0">
<Module name="Common">
<Dll label="公共组件" name="LyingDragon_Common" version="1.4.3.2"/>
<StaticData label="静态数据" name="KeyWord_zh_CN" version="1.4.2.1"/>
</Module>
<Module name="BeforeLoad">
<Dll label="基础组件" name="LyingDragon_Base" version="1.4.3.2"/>
<Text label="文本" name="Text_zh_CN" version="1.4.3.4"/>
<Image label="图标" name="qt">
<File name="lvup.swf"/>
<File name="QT046.swf"/>
<File name="QT047.swf"/>
<File name="QT048.swf"/>
<File name="QT2.0.swf"/>
</Image>
<Image label="图标" name="CoreIcon">
mns_zh_CN.dat 成功解密
这里附上我测试成功的 LZMA 解密代码
参数就是要解密的LZMA加密的数据(数据格式必须如下注释所说properties 5个字节,数据长度标记8字节)
返回值就是解密后的数据
//解码方式 0-4 为5个字节的properties 5-12 8个字节为解压后的数据长度 public static function decode(src:ByteArray) : ByteArray { if (src == null || src.length < 16) { return null; } var inStream:InputStream = new InputStream(src); var propertiesSize:int = 5; var properties:Vector.<uint> = new Vector.<uint>(propertiesSize); if (inStream.readVOL(properties, 0, propertiesSize) != propertiesSize) return null; var decoder:Decoder = new Decoder(); if (!decoder.SetDecoderProperties(properties)) return null; var outSize:uint = 0; for (var i:int = 0; i < 8; i++) { var v:int = inStream.read(); if (v < 0) return null; outSize |= (v << (8 * i)); } var ret:ByteArray = new ByteArray(); ret.length = outSize; var outStream:OutputStream = new OutputStream(ret); if (!decoder.Code(inStream, outStream, outSize)) return null; inStream.close(); outStream.close(); ret.position =0; return ret; }
/********************Witch_soya****************************/
/***********************2014-4-27*************************/