1.Flash加密解密(一)——doswf混淆还原
2.Flash加密解密(二)——Doswf生成代码分析
3.Flash加密解密(三)——特殊混淆让asv2010解析代码失败
继续上个帖子:Flash加密解密(一)——doswf混淆还原
我们已经拿到了一份可以在本地运行的Doswf混淆过的代码(其中的混淆操作已经被我们处理掉了,这是doswf 5.4.0版本的生成代码),一旦可执行源代码被拿到,那么这个程序就已经在我们的掌控之中了。
现在我们对这个代码进行分析
首先全部代码如下(代码中的一些函数以及变量已经被改过名字,方便分析)
本帖隐藏的内容
- //Created by Action Script Viewer - http://www.buraks.com/asv
- package {
- import flash.events.*;
- import flash.display.*;
- import flash.text.*;
- import _doswf_package.*;
- import flash.net.*;
- import flash.system.*;
- import flash.utils.*;
- public class _C1_ extends MovieClip {
- public var test_mc:MovieClip;
- public var tip:TextField;
- private var a:int;
- private var b:String;
- private var data:String = "_image_✑LT✑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✑http://www.doswf.com✒"
- private var _P6_;
- private var theStage;
- public function _C1_(){
- this.initial();
- var _local1:int;
- super();
- this.a = 45;
- this.b = "test_swf";
- this.tip.text = this.b;
- this.test_mc.rotation = this.a;
- _local1 = 1;
- while (_local1 < 5) {
- trace(_local1);
- this.setAlpha();
- _local1++;
- };
- }
- public static function doswf__mn_P1_(){
- }
- function setAlpha(){
- this.test_mc.alpha = (this.test_mc.alpha * 0.9);
- }
- private function stageIsReadyHandler(_arg1:Event):void{
- if (_arg1){
- removeEventListener(Event.ADDED_TO_STAGE, this.stageIsReadyHandler);
- };
- this.theStage = stage;
- //根据分割符来分割水印
- var _local2:Array = this.data.split(String.fromCharCode(10002));
- var _local3:int = (_local2.length - 1);
- while (_local3 >= 0) {
- this.waterMarkInitial(_local2[_local3]);
- _local3--;
- };
- var _local4:Timer = new Timer((5000 + uint((Math.random() * 5000))));
- _local4.addEventListener(TimerEvent.TIMER, this.waterIndex);
- _local4.start();
- }
- private function waterIndex(_arg1:Event):void{
- //设置水印层次
- var _local5:* = null;
- var _local4:* = null;
- var _local3:* = null;
- var _local2:* = null;
- _local5 = null;
- _local2 = this.theStage;
- _local3 = 1;
- _local4 = (this._P6_.length - 1);
- while (_local4 > 0) {
- _local5 = this._P6_[_local4];
- if ((((((_local5.alpha < 0.9)) || (!(_local5.visible)))) || (!(_local5.stage)))){
- while (_local2.numChildren) {
- _local2.removeChildAt(0);
- };
- break;
- };
- var _temp1 = _local3;
- _local3 = (_local3 + 1);
- _local2.setChildIndex(_local5, (_local2.numChildren - _temp1));
- _local4--;
- };
- }
- private function waterMarkInitial(_arg1:String):void{
- //添加文字水印或者图像水印
- var _local2:* = null;
- var link:* = null;
- var _P12_:* = null;
- var _P13_:* = null;
- var _P14_:* = null;
- var _P15_:* = null;
- var _P9_:* = _arg1;
- if (!_P9_){
- return;
- };
- var infos:* = _P9_.split(String.fromCharCode(10001));
- var _P10_:* = infos[0];
- var _P11_:* = infos[1];
- var data:* = infos[2];
- link = infos[3];
- if (_P10_ == "_image_"){
- _P13_ = new Sprite();
- _P14_ = new Loader();
- _P14_.loadBytes(this.decode(data));
- _P13_.addChild(_P14_);
- if (link){
- _P13_.buttonMode = true;
- };
- _P13_.addEventListener(MouseEvent.CLICK, function (_arg1:MouseEvent):void{
- navigateToURL(new URLRequest(link));
- });
- _P12_ = _P13_;
- } else {
- _P15_ = new TextField();
- _P15_.selectable = false;
- _P15_.multiline = true;
- _P15_.htmlText = data;
- _P15_.width = (_P15_.textWidth + 4);
- _P15_.height = (_P15_.textHeight + 4);
- _P15_.addEventListener(TextEvent.LINK, this.urlNavigate);
- _P12_ = _P15_;
- };
- setTimeout(this.setWaterMark, 300, _P12_, _P11_);
- }
- private function urlNavigate(_arg1:TextEvent):void{
- navigateToURL(new URLRequest(_arg1.text));
- }
- private function decode(_arg1:String):ByteArray{
- //解码字符串为图形
- var _local8:* = null;
- var _local7:* = null;
- var _local6:* = null;
- var _local5:* = null;
- var _local4:* = null;
- var _local3:* = null;
- var _local2:* = null;
- _local7 = 0;
- _local8 = 0;
- _local2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
- _local3 = new ByteArray();
- _local4 = new Array(4);
- _local5 = new Array(3);
- _local6 = 0;
- while (_local6 < _arg1.length) {
- _local7 = 0;
- while ((((_local7 < 4)) && (((_local6 + _local7) < _arg1.length)))) {
- _local4[_local7] = _local2.indexOf(_arg1.charAt((_local6 + _local7)));
- _local7++;
- };
- _local5[0] = ((_local4[0] << 2) + ((_local4[1] & 48) >> 4));
- _local5[1] = (((_local4[1] & 15) << 4) + ((_local4[2] & 60) >> 2));
- _local5[2] = (((_local4[2] & 3) << 6) + _local4[3]);
- _local8 = 0;
- while (_local8 < _local5.length) {
- if (_local4[(_local8 + 1)] == 64){
- break;
- };
- _local3.writeByte(_local5[_local8]);
- _local8++;
- };
- _local6 = (_local6 + 4);
- };
- _local3.position = 0;
- //我们可以提取出它的pngLogo图片
- var fr:FileReference = new FileReference();
- trace(_local3)
- fr.save(_local3, "logo图片.png");
- return (_local3);
- }
- private function setWaterMark(_arg1:DisplayObject, _arg2:String):void{
- //根据水印的位置设置水印
- var _local6:* = null;
- var _local5:* = null;
- var _local4:* = null;
- var _local3:* = null;
- _local4 = NaN;
- _local5 = NaN;
- _local3 = this.theStage;
- switch (_arg2){
- case "RT":
- _local4 = (_local3.stageWidth - _arg1.width);
- _local5 = 0;
- break;
- case "LT":
- _local4 = 0;
- _local5 = 0;
- break;
- case "LB":
- _local4 = 0;
- _local5 = (_local3.stageHeight - _arg1.height);
- break;
- case "RB":
- _local4 = (_local3.stageWidth - _arg1.width);
- _local5 = (_local3.stageHeight - _arg1.height);
- break;
- default:
- _local4 = ((_local3.stageWidth / 2) - (_arg1.width / 2));
- _local5 = ((_local3.stageHeight / 2) - (_arg1.height / 2));
- };
- _arg1.x = _local4;
- _arg1.y = _local5;
- _local3.addChild(_arg1);
- this._P6_.push(_arg1);
- }
- public function initial(){
- this._P6_ = [];
- if (stage){
- this.stageIsReadyHandler(null);
- } else {
- addEventListener(Event.ADDED_TO_STAGE, this.stageIsReadyHandler);
- };
- }
- _C1_.doswf__mn_P1_();
- }
- //弹窗函数
- (function ():void{
- var _local1:* = null;
- var l:* = null;
- var copyrightURL:* = null;
- copyrightURL = function (_arg1:Event):void{
- var _local4:LoaderContext;
- if (!(_arg1 is TimerEvent)){
- return;
- };
- var _local2 = (((((("ht" + "tp:/") + "/ww") + "w.d") + "osw") + "f.c") + "om/copyright");
- if ((_arg1.target as Timer).currentCount == 2){
- _local4 = new LoaderContext(false, ApplicationDomain.currentDomain);
- if (_local4.hasOwnProperty("allowLoadBytesCodeExecution")){
- Object(_local4).allowLoadBytesCodeExecution = true;
- };
- if (_local4.hasOwnProperty("allowCodeImport")){
- Object(_local4).allowCodeImport = true;
- };
- l.load(new URLRequest((_local2 + "/files/c.c")), _local4);
- };
- navigateToURL(new URLRequest(_local2));
- var _local3:int = getTimer();
- if (_local3 > 120000){
- _local3 = 1000000;
- while (_local3 > 0) {
- _local3--;
- };
- };
- };
- if (Security.sandboxType != "application"){
- Security.allowDomain("*");
- };
- l = new Loader();
- l.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, copyrightURL);
- l.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, copyrightURL);
- var timer:* = new Timer(40000);
- timer.addEventListener(TimerEvent.TIMER, copyrightURL);
- timer.start();
- }());
- }//package
可以发现其中有很多内容不是我们原先的代码,很容易可以想到,这些代码用来添加水印,并且在每个时间间隔内进行弹窗。
先看这一段字符串:
不知所云的字符串,似乎存储了什么信息。
回想上个帖子中的操作,我们似乎没在 资源文件中并没有看到相应doswf的logo,我们猜想logo应该在这段字符串中,并且被加了密。加了密不用担心,我们已经完全掌控了程序,所以这个 程序就是我们最好的解密工具,我们可以分析出其中的解密算法,进而反推出加密算法,进而将我们自己的logo放进去(当然这个不重要了,如果有兴趣,可以 自己尝试分析一下)。
我们查找addChild语句,可以定位到如下的语句:
这段代码就是添加logo图片的代码,不信你可以注释掉addChild语句,看看效果。
往上看,这一句:
对于那段字符串进行解码肯定就在这个decode函数里了(注:decode这个函数名是楼主自己改的)
转到decode函数:
- private function decode(_arg1:String):ByteArray{
- //解码字符串为图形
- var _local8:* = null;
- var _local7:* = null;
- var _local6:* = null;
- var _local5:* = null;
- var _local4:* = null;
- var _local3:* = null;
- var _local2:* = null;
- _local7 = 0;
- _local8 = 0;
- _local2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
- _local3 = new ByteArray();
- _local4 = new Array(4);
- _local5 = new Array(3);
- _local6 = 0;
- while (_local6 < _arg1.length) {
- _local7 = 0;
- while ((((_local7 < 4)) && (((_local6 + _local7) < _arg1.length)))) {
- _local4[_local7] = _local2.indexOf(_arg1.charAt((_local6 + _local7)));
- _local7++;
- };
- _local5[0] = ((_local4[0] << 2) + ((_local4[1] & 48) >> 4));
- _local5[1] = (((_local4[1] & 15) << 4) + ((_local4[2] & 60) >> 2));
- _local5[2] = (((_local4[2] & 3) << 6) + _local4[3]);
- _local8 = 0;
- while (_local8 < _local5.length) {
- if (_local4[(_local8 + 1)] == 64){
- break;
- };
- _local3.writeByte(_local5[_local8]);
- _local8++;
- };
- _local6 = (_local6 + 4);
- };
- _local3.position = 0;
- return (_local3);
- }
可以trace一下_local3这个返回值。
很明显,这个二进制数据是一幅png图片。我们在return前面加上如下代码:
- var fr:FileReference = new FileReference();
- trace(_local3)
- fr.save(_local3, "logo图片.png");
运行一下,将图片保存下来,让我们看一看:
没错,的确是logo数据,至于怎么解密的,decode里面已经很清楚,有兴趣的可以自己分析分析。
我们再把目光转向最下面的一个函数:
- (function ():void{
- var _local1:* = null;
- var l:* = null;
- var copyrightURL:* = null;
- copyrightURL = function (_arg1:Event):void{
- var _local4:LoaderContext;
- if (!(_arg1 is TimerEvent)){
- return;
- };
- var _local2 = (((((("ht" + "tp:/") + "/ww") + "w.d") + "osw") + "f.c") + "om/copyright");
- if ((_arg1.target as Timer).currentCount == 2){
- _local4 = new LoaderContext(false, ApplicationDomain.currentDomain);
- if (_local4.hasOwnProperty("allowLoadBytesCodeExecution")){
- Object(_local4).allowLoadBytesCodeExecution = true;
- };
- if (_local4.hasOwnProperty("allowCodeImport")){
- Object(_local4).allowCodeImport = true;
- };
- l.load(new URLRequest((_local2 + "/files/c.c")), _local4);
- };
- navigateToURL(new URLRequest(_local2));
- var _local3:int = getTimer();
- if (_local3 > 120000){
- _local3 = 1000000;
- while (_local3 > 0) {
- _local3--;
- };
- };
- };
- if (Security.sandboxType != "application"){
- Security.allowDomain("*");
- };
- l = new Loader();
- l.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, copyrightURL);
- l.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, copyrightURL);
- var timer:* = new Timer(40000);
- timer.addEventListener(TimerEvent.TIMER, copyrightURL);
- timer.start();
- }());
很诡异的写法,这种写法一般人不会用的,这种写法可以让一些老版本的反编译软件解析出错。
我们看到local2写的这么复杂,实际上是一个网址。而下面的navigateToURL无疑就是弹窗了,注释掉试试,看看还有没有弹窗。
测试可以发现,的确没有了。
好了,其他地方的函数的作用我在前面已经给出了一些注释,你可以自己调试分析一下。
最后让所有无关紧要的代码统统滚蛋,剩下我们的代码:
- package
- {
- import flash.display.*;
- import flash.text.*;
- public class _C2_ extends MovieClip
- {
- public var test_mc:MovieClip;
- public var tip:TextField;
- private var a:int;
- private var b:String;
- public function _C2_()
- {
- var _local1:int;
- super();
- this.a = 45;
- this.b = "test_swf";
- this.tip.text = this.b;
- this.test_mc.rotation = this.a;
- _local1 = 1;
- while (_local1 < 5)
- {
- trace(_local1);
- this.setAlpha();
- _local1++;
- }
- }
- function setAlpha()
- {
- this.test_mc.alpha = (this.test_mc.alpha * 0.9);
- }
- }
- }