Hi!!
I've been looking deeper and net.bigpoint.darkorbit.net.netty.CommandHandler is the class that encryptes and decryptes the data.
This is how it looks:
package net.bigpoint.darkorbit.net.netty
{
import flash.events.EventDispatcher;
import net.bigpoint.darkorbit.net.netty.commands.ModuleFactory;
import flash.utils.IDataInput;
import flash.utils.IDataOutput;
import flash.net.Socket;
import flash.utils.ByteArray;
import net.bigpoint.darkorbit.net.netty.utils.EncryptionFacade;
public class CommandHandler extends EventDispatcher
{
public function CommandHandler()
{
this._socketSessionCache = new SocketSessionCache();
this._messageByteArray = new ByteArray();
super();
this.initialize();
}
public static const EVENT_EXECUTE_COMMAND:String = "Event.ExecuteCommand";
private static const COMMAND_NOT_FOUND:String = "command not found for: ";
private static const HEADER_LENGTH:int = 2;
private static var _commandFactory:ModuleFactory = new ModuleFactory();
public static function retrieveMessage(param1:IDataInput) : ICommand
{
var _loc2_:uint = param1.readShort();
var _loc3_:ICommand = _commandFactory.createInstance(_loc2_);
_loc3_.read(param1);
return _loc3_;
}
public static function writeMessage(param1:ICommand, param2:IDataOutput) : void
{
param2.writeShort(param1.getId());
param1.write(param2);
}
private var _socketSessionCache:SocketSessionCache;
private var _socket:Socket;
private var _messageByteArray:ByteArray;
private var _encryptionFacade;
protected function initialize() : void
{
this._encryptionFacade = new EncryptionFacade();
}
public function reset() : void
{
this._encryptionFacade.reset();
}
public function readData() : void
{
this.parseData(this._socket);
}
private function parseData(param1:IDataInput) : void
{
var _loc2_:* = 0;
var _loc3_:ByteArray = null;
var _loc4_:ByteArray = null;
var _loc5_:ByteArray = null;
var _loc6_:ByteArray = null;
var _loc7_:uint = 0;
var _loc8_:ICommand = null;
do
{
_loc2_ = param1.bytesAvailable;
if(this._socketSessionCache.isReady())
{
if(_loc2_ >= this._socketSessionCache.getLength())
{
_loc3_ = new ByteArray();
this._socket.readBytes(_loc3_,0,this._socketSessionCache.getLength());
_loc4_ = this._encryptionFacade.decode(_loc3_);
_loc8_ = retrieveMessage(_loc4_);
dispatchEvent(new CommandHandlerEvent(EVENT_EXECUTE_COMMAND,_loc8_));
this._socketSessionCache.reset();
}
}
else if(_loc2_ > HEADER_LENGTH)
{
_loc5_ = new ByteArray();
this._socket.readBytes(_loc5_,0,2);
_loc6_ = this._encryptionFacade.decode(_loc5_);
_loc7_ = _loc6_.readUnsignedShort();
if(_loc7_ > 0)
{
this._socketSessionCache.setLength(_loc7_);
}
}
}
while(_loc2_ > HEADER_LENGTH && _loc2_ >= this._socketSessionCache.getLength());
}
public function sendMessage(param1:ICommand) : void
{
this._messageByteArray.clear();
writeMessage(param1,this._messageByteArray);
this._messageByteArray.position = 0;
this._messageByteArray.writeShort(this._messageByteArray.length - HEADER_LENGTH);
var _loc2_:ByteArray = this._encryptionFacade.encode(this._messageByteArray);
this._socket.writeBytes(_loc2_,0,_loc2_.length);
this._socket.flush();
}
public function setSocket(param1:Socket) : void
{
this._socket = param1;
}
public function setSecurityKey(param1:ByteArray) : void
{
this._encryptionFacade.setSecretKey(param1);
}
public function setEncryptionFacade(param1:Object) : void
{
this._encryptionFacade = param1;
}
public function injectObfuscation(param1:ByteArray, param2:uint, param3:Function) : void
{
this._encryptionFacade.injectObfuscation(param1,param2,param3);
}
}
}
The method "sendMessage" encrypts and sends the message through SocketManager:
public function sendMessage(param1:ICommand) : void
{
this._messageByteArray.clear();
writeMessage(param1,this._messageByteArray);
this._messageByteArray.position = 0;
this._messageByteArray.writeShort(this._messageByteArray.length - HEADER_LENGTH);
var _loc2_:ByteArray = this._encryptionFacade.encode(this._messageByteArray);
this._socket.writeBytes(_loc2_,0,_loc2_.length);
this._socket.flush();
}
It calls encryptionFacade to encode message's bytes, this is the method:
public function encode(param1:ByteArray) : ByteArray
{
if(this.activated)
{
this.currentEncodeAlgorithm.encrypt(param1);
}
var _loc2_:ByteArray = this.injection.encode(param1);
var _loc3_:ByteArray = new ByteArray();
_loc3_.writeBytes(_loc2_);
_loc3_.position = 0;
return _loc3_;
}
this.currentEncodeAlgorithm is an object of com.hurlant.crypto.prng.ARC4 and it looks like this:
package com.hurlant.crypto.prng
{
import com.hurlant.crypto.symmetric.IStreamCipher;
import flash.utils.ByteArray;
import com.hurlant.util.Memory;
public class ARC4 extends Object implements IPRNG, IStreamCipher
{
public function ARC4(param1:ByteArray = null)
{
i = 0;
j = 0;
super();
S = new ByteArray();
if(param1)
{
init(param1);
}
}
public function decrypt(param1:ByteArray) : void
{
encrypt(param1);
}
public function init(param1:ByteArray) : void
{
var _loc2_:* = 0;
var _loc3_:* = 0;
var _loc4_:* = 0;
_loc2_ = 0;
while(_loc2_ < 256)
{
S[_loc2_] = _loc2_;
_loc2_++;
}
_loc3_ = 0;
_loc2_ = 0;
while(_loc2_ < 256)
{
_loc3_ = _loc3_ + S[_loc2_] + param1[_loc2_ % param1.length] & 255;
_loc4_ = S[_loc2_];
S[_loc2_] = S[_loc3_];
S[_loc3_] = _loc4_;
_loc2_++;
}
this.i = 0;
this.j = 0;
}
private var S:ByteArray;
public function dispose() : void
{
var _loc1_:uint = 0;
_loc1_ = 0;
if(S != null)
{
_loc1_ = 0;
while(_loc1_ < S.length)
{
S[_loc1_] = Math.random() * 256;
_loc1_++;
}
S.length = 0;
S = null;
}
this.i = 0;
this.j = 0;
Memory.gc();
}
public function encrypt(param1:ByteArray) : void
{
var _loc2_:uint = 0;
_loc2_ = 0;
while(_loc2_ < param1.length)
{
param1[_loc2_++] = param1[_loc2_++] ^ next();
}
}
private var i:int = 0;
private var j:int = 0;
private const psize:uint = 256;
public function next() : uint
{
var _loc1_:* = 0;
i = i + 1 & 255;
j = j + S[i] & 255;
_loc1_ = S[i];
S[i] = S[j];
S[j] = _loc1_;
return S[_loc1_ + S[i] & 255];
}
public function getBlockSize() : uint
{
return 1;
}
public function getPoolSize() : uint
{
return psize;
}
public function toString() : String
{
return "rc4";
}
}
}
Once the packet is encrypted with ARC4 it's encrypted again with ObfuscationWrapper, it looks like this:
package net.bigpoint.darkorbit.net.netty.utils
{
import flash.events.EventDispatcher;
import flash.utils.ByteArray;
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.events.Event;
import flash.events.IOErrorEvent;
public class InjectedObfuscationWrapper extends EventDispatcher
{
public function InjectedObfuscationWrapper()
{
this.§_-zn§ = new ByteArray();
this.§_-EN§ = new ByteArray();
super();
}
public static const §_-i13§:uint = 4096;
public static const §_-x2f§:Array = [67,87,83,11,227,11,0,0,64,3,192,3,192,0,24,1,0,68,17,25,0,0,0,198,10,97,98,99,95,65,0];
public static const §_-1A§:Array = [10,19,1,0,0,0,100,105,100,73,68,0,64,0,0,0];
private var §_-zn§:ByteArray;
private var §_-EN§:ByteArray;
protected var §_-j1G§:Boolean;
protected var §_-A1E§:Object;
protected var §_-N24§:Function;
protected var §_-N1k§:ByteArray;
protected function §_-qz§() : void
{
var _loc3_:uint = 0;
this.§_-EN§ = new ByteArray();
var _loc1_:uint = §_-1A§.length;
var _loc2_:* = 0;
while(_loc2_ < _loc1_)
{
_loc3_ = §_-1A§[_loc2_];
this.§_-EN§.writeByte(_loc3_);
_loc2_++;
}
}
protected function §_-H37§() : void
{
var _loc3_:uint = 0;
this.§_-zn§ = new ByteArray();
var _loc1_:uint = §_-x2f§.length;
var _loc2_:* = 0;
while(_loc2_ < _loc1_)
{
_loc3_ = §_-x2f§[_loc2_];
this.§_-zn§.writeByte(_loc3_);
_loc2_++;
}
}
public function injectAndBuild(param1:ByteArray, param2:uint, param3:Function) : void
{
this.§_-N24§ = param3;
if(param2 > 0)
{
this.§_-F2O§(param2);
}
if(param1.length < §_-i13§)
{
this.§_-S37§(param1);
}
}
private function §_-F2O§(param1:uint) : void
{
var _loc2_:uint = param1 & 255;
var _loc3_:uint = (param1 & 65280) >> 8;
var _loc4_:uint = (param1 & 16711680) >> 16;
var _loc5_:uint = (param1 & 4.27819008E9) >> 24;
§_-x2f§[4] = _loc2_;
§_-x2f§[5] = _loc3_;
§_-x2f§[6] = _loc4_;
§_-x2f§[7] = _loc5_;
}
private function §_-S37§(param1:ByteArray) : void
{
this.§_-II§();
this.§_-N1k§ = new ByteArray();
this.§_-N1k§.writeBytes(this.§_-zn§);
this.§_-N1k§.writeBytes(param1);
this.§_-N1k§.writeBytes(this.§_-EN§);
this.§_-a3H§();
}
private function §_-II§() : void
{
this.§_-H37§();
this.§_-qz§();
}
protected function §_-a3H§() : void
{
var _loc1_:Loader = new Loader();
var _loc2_:LoaderInfo = _loc1_.contentLoaderInfo;
_loc2_.addEventListener(Event.COMPLETE,this.§_-Z1x§);
_loc2_.addEventListener(IOErrorEvent.IO_ERROR,this.§_-W3t§);
_loc1_.loadBytes(this.§_-N1k§);
}
private function §_-W3t§(param1:IOErrorEvent) : void
{
}
protected function §_-Z1x§(param1:Event = null) : void
{
var _loc2_:LoaderInfo = param1.target as LoaderInfo;
_loc2_.removeEventListener(Event.COMPLETE,this.§_-Z1x§);
_loc2_.removeEventListener(IOErrorEvent.IO_ERROR,this.§_-W3t§);
this.§_-A1E§ = _loc2_.content;
this.activate();
this.§_-N24§();
}
public function decode(param1:ByteArray) : ByteArray
{
if(this.§_-W3c§())
{
return this.§_-A1E§.decode(param1);
}
return param1;
}
public function encode(param1:ByteArray) : ByteArray
{
if(this.§_-j1G§)
{
return this.§_-A1E§.encode(param1);
}
return param1;
}
private function §_-r1Q§() : void
{
var _loc1_:ByteArray = new ByteArray();
_loc1_.writeByte(255);
_loc1_.writeByte(0);
var _loc2_:ByteArray = this.encode(_loc1_);
var _loc3_:ByteArray = this.decode(_loc2_);
}
public function activate() : void
{
this.§_-j1G§ = true;
}
public function deactivate() : void
{
this.§_-j1G§ = false;
}
public function §_-W3c§() : Boolean
{
return this.§_-j1G§;
}
}
}
Then it's encoded with Pandora's Box, but I couldn't find it yet, pff, 8 ecnryptions for 1 packet -.-