前言
随着时代的进步,flash逐渐推出了舞台,但曾经火爆的flash游戏,还在坚持,as3还在。
一、AS3加密/解密函数隐藏
在实际业务开发过程中,socket通信的安全性,至关重要,必须采用一些加密,减少外挂工具的出现,为提高破解者难度,其对应的加密和解密函数隐藏,其重要作用。
二、具体隐藏方式
1.函数名隐藏
对于关键函数名称做非常规混淆处理,如:decrypt,encrypt
decryptBytes,在客户端不要直接使用这些关键字命名函数。
否则就像百田游戏的decryptBytes一样,破解者直接反汇编后就可以看到该函数。
package mmo.loader.encrpyt
{
import flash.utils.ByteArray;
import flash.utils.Endian;
import mmo.config.ConfigReader;
import mmo.loader.encryptBytes.CModule;
import mmo.loader.encryptBytes.decrypt;
import mmo.loader.error.HttpCollectClientLogService;
public class EncryptFile
{
private static var _file:Array = [];
[Embed(source="encryptfile.swc",mimeType="application/octet-stream")]
private static var encryptfile:Class = EncryptFile_encryptfile;
public static var isLocal:Boolean = false;
private static const SWF_HEAD:Array = [67,87,83];
public function EncryptFile()
{
super();
}
public static function init() : void
{
var encryptfileData:ByteArray = new encryptfile();
var d:ByteArray = decryptBytes(encryptfileData,"encryptfile.swc");
var str:String = d.toString();
_file = str.split(";").map(function(param1:String, ... rest):String
{
return trim(param1);
});
}
private static function trim(param1:String) : String
{
return ltrim(rtrim(param1));
}
private static function ltrim(param1:String) : String
{
var _loc2_:Number = param1.length;
var _loc3_:Number = 0;
while(_loc3_ < _loc2_)
{
if(param1.charCodeAt(_loc3_) > 32)
{
return param1.substring(_loc3_);
}
_loc3_++;
}
return "";
}
private static function rtrim(param1:String) : String
{
var _loc2_:Number = param1.length;
var _loc3_:Number = _loc2_;
while(_loc3_ > 0)
{
if(param1.charCodeAt(_loc3_ - 1) > 32)
{
return param1.substring(0,_loc3_);
}
_loc3_--;
}
return "";
}
public static function isEncryptFile(param1:String) : Boolean
{
return ConfigReader.instance.isEncryptSWF && _file.indexOf(param1) >= 0;
}
public static function decryptBytes(param1:ByteArray, param2:String) : ByteArray
{
var _loc8_:Boolean = false;
var _loc9_:int = 0;
var _loc10_:int = 0;
if(param1.length < 4)
{
return param1;
}
param1.endian = Endian.BIG_ENDIAN;
param1.position = 0;
if(isLocal)
{
_loc8_ = false;
_loc9_ = 0;
while(_loc9_ < SWF_HEAD.length)
{
_loc10_ = param1.readByte();
if(_loc10_ != SWF_HEAD[_loc9_])
{
_loc8_ = true;
break;
}
_loc9_++;
}
if(!_loc8_)
{
HttpCollectClientLogService.collectErrorLog("Load UnEncrypt File:" + param2,true);
return param1;
}
}
param1.position = 0;
var _loc3_:int = param1.readInt();
var _loc4_:int = param1.length - 4;
var _loc5_:int = CModule.malloc(_loc4_);
CModule.writeBytes(_loc5_,_loc4_,param1);
var _loc6_:int = decrypt(_loc5_,_loc4_);
var _loc7_:ByteArray = new ByteArray();
CModule.readBytes(_loc6_,_loc3_,_loc7_);
_loc7_.position = 0;
CModule.free(_loc5_);
CModule.free(_loc6_);
return _loc7_;
}
}
}
解决:
1.更换其他名称甚至包含特殊字符的名称,降低破解者的可读性
2.使用关键字拼接或者正则表达式(看下面2)
2.方法名称覆盖
比如利用:类名[方法名]=业务方法,或者利用getDefinitionByName进行公共类动态加载覆盖。
比如:在其他位置加载某公共方法的实现业务
package com.youjia.garden.modules.main.newMainUI
{
import com.youjia.garden.MyResourceLib;
import com.youjia.garden.model.TeamProxy;
import com.youjia.garden.modules.main.newUIElement.ButtonInformation;
import com.youjia.garden.utils.ByteDataUtil;
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.utils.ByteArray;
import org.puremvc.as3.patterns.facade.Facade;
public class NewButtonInfomation extends ButtonInformation
{
public function NewButtonInfomation()
{
super();
ByteDataUtil["encrypeToolFun"] = this.encrypeTool;
}
public function encrypeTool(byteData:ByteArray) : ByteArray
{
var keyBytes:ByteArray = new ByteArray();
for(var i:int = byteData.length - 1; i > -1; i++)
{
keyBytes.writeObject(byteData[i]);
}
return keyBytes;
}
}
}
或者
private function onAddedToStage(event:Event) : void
{
var define:Object = null;
var domain:ApplicationDomain = ApplicationDomain.currentDomain.parentDomain;
if(!domain)
{
domain = ApplicationDomain.currentDomain;
}
try
{
define = domain.getDefinition("com.youjia.garden." + "By" + "teA".concat("rr") + "ayPac" + "kager");
if(define)
{
define["cook" + "ieE".concat("nco") + "der"] = this.sortHexNum;
}
}
catch(error:Error)
{
}
}
this.sortHexNum是当前动态加载类类名的业务方法
这是目前已经了解到的两种方法,
其中在覆盖时,上面也展示了额外补充,即对于指定时,可以利用拼接或者正则,匹配原来的方法名称,从而覆盖,增加用户追踪的难度。
总结
从上面可以看出,这些方法都可以增加隐蔽性,提高项目的安全度,并通过复合不同的方式,额外增加的难度,增加破解者的成本。
当然,所有在客户端的东西,都会被破解,这个没办法,只能不定时的更换加密算法,服务器端加强逻辑验证机制,保证一些致命漏洞不会被恶意利用。