Todays been a productive day…

May 7th, 2010 mike 11 comments

So, you probably havn’t heard from me for a while… Dominic has been doing well with the crypto, and since I’ve had a spare couple a hours/days I thought i’d give my two cent. Enough of the crap anyway, lets cut straight to the exciting stuff.

As you may be aware, Sulake (obviously) obfuscate all released revisions of the Habbo.SWF (or Habbo10.SWF, whatever). This means function names are pretty much scrambled, meaning it’s difficult to understand what function does what. An example of an obfuscated function name is “_-0b12″. Same goes with variables, and also in most cases Method Bodies (Obfuscation makes the code pretty difficult to understand by adding in weird-ass bitshifts, and in-appropriate code that would typically error a compiler). Upon examination of the Actionscript Virtual Machine processing the Habbo.SWF Bytecode, I could pretty much see every plaintext, non-obfuscated function name along with all their traits. Not too useful? Well, it certainly is when it comes to knocking the client down to ABCCode and manipulating Actionscript bytecode itself. Also gives you an insight into what the function ACTUALLY does, which means in turn you can probably make more sense of the obfuscated horrific code. Anyway, I took the interesting shit and left aside all the boring stuff – just because I wanna see if Sulake really shitbrix or not.

The RC4 Class functions (Currently package _0Nq)
Package -> com.sulake.core.communication.encryption :: Class name -> RC4

init(param1 ByteArray) = Used for setting up encryption tables and class. The ByteArray is the Diffie-Hellman shared key once calculated.

initFromState(param1 ConnectionState) = Not sure what this would be used for, but it doesn’t appear to be used atm. But im guessing its used to init the crypto depending on a passed ConnectionState.

encipher(param1 ByteArray, param2 boolean) = Good ol’ Encipher method.

decipher(param1 ByteArray, param2 boolean) = Opposite to Encipher ;)

customHackScramble(param1 Array, param2 int, param3 int) = Sulakes way of trying to confuse us.

swap(param1 int, param2 int) = Swapping of tables.

Just because you might wanna see how this looks (MethodInfo and such), heres the raw log.

72619:method[12072]
        returnType={public}::*
        param_count=0
        name_index=18850 "com.sulake.core.communication.encryption:RC4/RC4"
        flags=0
    72625:method[12073]
        returnType=void
        param_count=1
            paramType[1]=flash.utils::ByteArray
        name_index=21247 "com.sulake.core.communication.encryption:RC4/init"
        flags=0
    72632:method[12074]
        returnType=void
        param_count=1
            paramType[1]=_-0Nq::_-16-
        name_index=18495 "com.sulake.core.communication.encryption:RC4/initFromState"
        flags=0
    72640:method[12075]
        returnType=flash.utils::ByteArray
        param_count=2
            paramType[1]=flash.utils::ByteArray
            paramType[2]=Boolean
        name_index=29283 "com.sulake.core.communication.encryption:RC4/encipher"
        flags=8
    72651:method[12076]
        returnType=void
        param_count=3
            paramType[1]=Array
            paramType[2]=int
            paramType[3]=int
        name_index=21055 "com.sulake.core.communication.encryption:RC4/protected:customHackScramble"
        flags=0
    72660:method[12077]
        returnType=flash.utils::ByteArray
        param_count=1
            paramType[1]=flash.utils::ByteArray
        name_index=19625 "com.sulake.core.communication.encryption:RC4/decipher"
        flags=0
    72667:method[12078]
        returnType=void
        param_count=2
            paramType[1]=uint
            paramType[2]=uint
        name_index=20071 "com.sulake.core.communication.encryption:RC4/protected:swap"
        flags=0

Oh wow looky looky, Sulake also have classes with an implementation of the Release 27 crypto?!?

The RC4_R27 Class functions (Currently package _-0wd)
Package -> com.sulake.core.communication.encryption :: Class name -> RC4_R27

getEncodedSize(param1 int) = Title explains for itself.

getDecodedSize(param1 int) = Title explains for itself again.

Constructor/RC4_R27(param1 SomeClass, param2 SomeOtherClass) = Constructor, probably either connection states and a Biginteger passed here.

init(param1 ByteArray) = Same as prev. explained RC4 class.

encipher(param1 ByteArray, param2 boolean) = Same as prev. explained RC4 Class.

customHackScramble(param1 Array, param2 int, param3 int) = Same as prev. explained RC4 class.

And the raw log:


    72683:method[12081]
        returnType=int
        param_count=1
            paramType[1]=int
        name_index=21753 "com.sulake.habbo.communication.encryption:RC4_R27/getEncodedSize"
        flags=0
    72690:method[12082]
        returnType=int
        param_count=1
            paramType[1]=int
        name_index=36157 "com.sulake.habbo.communication.encryption:RC4_R27/getDecodedSize"
        flags=0
    72697:method[12083]
        returnType={public}::*
        param_count=2
            paramType[1]=_-0Nq::_-16-
            paramType[2]=_-0wd::_-07l
        name_index=24949 "com.sulake.habbo.communication.encryption:RC4_R27/RC4_R27"
        flags=0
    72707:method[12084]
        returnType=void
        param_count=1
            paramType[1]=flash.utils::ByteArray
        name_index=27011 "com.sulake.habbo.communication.encryption:RC4_R27/init"
        flags=0
    72714:method[12085]
        returnType=flash.utils::ByteArray
        param_count=2
            paramType[1]=flash.utils::ByteArray
            paramType[2]=Boolean
        name_index=32377 "com.sulake.habbo.communication.encryption:RC4_R27/encipher"
        flags=8
    72725:method[12086]
        returnType=void
        param_count=3
            paramType[1]=Array
            paramType[2]=int
            paramType[3]=int
        name_index=36683 "com.sulake.habbo.communication.encryption:RC4_R27/protected:customHackScramble"
        flags=0

It seems Sulake also have all their useful encryption-related functions stored within a lovely static class too.

The CryptoTools Class functions (Currently package _-0Nq)
Package -> com.sulake.core.communication.encryption :: Class name -> CryptoTools

byteArrayToString(param1 ByteArray) = Function name explains itself methinks!

stringToByteArray(param1 String) = Function name explains itself methinks!

byteArrayToHexString(param1 ByteArray, param2 boolean) = Converts a bytearray to a string in the form of hexadecimal.

hexStringToByteArray(param1 String) = Opposite as byteArrayToHexString.

BigIntegerToRadix(param1 ByteArray, param2 unsigned-integer) = Converts a BigInteger Object ;)

And the raw loogg for you!

72453:method[12047]
        returnType=String
        param_count=1
            paramType[1]=flash.utils::ByteArray
        name_index=18945 "com.sulake.core.communication.encryption:CryptoTools/byteArrayToString"
        flags=0
    72460:method[12048]
        returnType=flash.utils::ByteArray
        param_count=1
            paramType[1]=String
        name_index=34592 "com.sulake.core.communication.encryption:CryptoTools/stringToByteArray"
        flags=0
    72467:method[12049]
        returnType=String
        param_count=2
            paramType[1]=flash.utils::ByteArray
            paramType[2]=Boolean
        name_index=21047 "com.sulake.core.communication.encryption:CryptoTools/byteArrayToHexString"
        flags=8
    72478:method[12050]
        returnType=flash.utils::ByteArray
        param_count=1
            paramType[1]=String
        name_index=31111 "com.sulake.core.communication.encryption:CryptoTools/hexStringToByteArray"
        flags=0
    72485:method[12051]
        returnType=String
        param_count=2
            paramType[1]=flash.utils::ByteArray
            paramType[2]=uint
        name_index=30438 "com.sulake.core.communication.encryption:CryptoTools/BigIntegerToRadix"
        flags=8
    72496:method[12052]
        returnType={public}::*
        param_count=0
        name_index=33918 "com.sulake.core.communication.encryption:CryptoTools/CryptoTools"
        flags=0

Theres also a PseudoRandom class for maths related stuff. Feels kinda pointless to post it here but i’ll add the cherry ontop.


    72742:method[12089]
        returnType=void
        param_count=2
            paramType[1]=int
            paramType[2]=int
        name_index=32038 "com.sulake.habbo.communication.encryption:PseudoRandom/PseudoRandom"
        flags=0
    72750:method[12090]
        returnType=int
        param_count=0
        name_index=20554 "com.sulake.habbo.communication.encryption:PseudoRandom/nextInt"
        flags=0

Oh, and Base64 stuff (WEDGIEDECODER ANYONE?!?) package name is currently _-1dE. It’s only useful for the RC4 Encipher/Decipher functions anyhow.

I’m feeling kinda lazy, so instead of explaining HabboCommunicationDemo im’a just post the full raw log right here for your viewing pleasure:

39471:method[6710]
        returnType=String
        param_count=5
            paramType[1]=flash.utils::ByteArray
            paramType[2]=uint
            paramType[3]=uint
            paramType[4]=flash.geom::Point
            paramType[5]=flash.geom::Point
        name_index=19594 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/private:decode"
        flags=0
    39482:method[6711]
        returnType=String
        param_count=2
            paramType[1]=String
            paramType[2]=String
        name_index=20196 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/private:xor"
        flags=0
    39490:method[6712]
        returnType=com.sulake.core.communication::_-28A
        param_count=0
        name_index=29276 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/communicationManager/get"
        flags=0
    39497:method[6713]
        returnType=com.sulake.habbo.configuration::_-0qN
        param_count=0
        name_index=21990 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/habboConfiguration/get"
        flags=0
    39504:method[6714]
        returnType=com.sulake.habbo.communication::_-08g
        param_count=0
        name_index=29865 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/habboCommunication/get"
        flags=0
    39511:method[6715]
        returnType=com.sulake.habbo.window::IHabboWindowManager
        param_count=0
        name_index=27898 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/windowManager/get"
        flags=0
    39517:method[6716]
        returnType=void
        param_count=1
            paramType[1]=String
        name_index=26947 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/ssoTicket/set"
        flags=0
    39524:method[6717]
        returnType=void
        param_count=1
            paramType[1]=String
        name_index=27321 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/shockwaveClientUrl/set"
        flags=0
    39531:method[6718]
        returnType={public}::*
        param_count=3
            paramType[1]=com.sulake.core.runtime::IContext
            paramType[2]=uint
            paramType[3]=com.sulake.core.assets::IAssetLibrary
        name_index=30850 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/HabboCommunicationDemo"
        flags=8
    39546:method[6719]
        returnType=void
        param_count=0
        name_index=18646 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/dispose"
        flags=0
    39552:method[6720]
        returnType=void
        param_count=2
            paramType[1]=com.sulake.core.runtime::_-0vP
            paramType[2]=com.sulake.core.runtime::IUnknown
        name_index=18266 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/private:onHabboConfigurationInit"
        flags=8
    39565:method[6721]
        returnType=void
        param_count=2
            paramType[1]=com.sulake.core.runtime::_-0vP
            paramType[2]=com.sulake.core.runtime::IUnknown
        name_index=33599 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/private:onWindowManagerReady"
        flags=0
    39573:method[6722]
        returnType=void
        param_count=2
            paramType[1]=com.sulake.core.runtime::_-0vP
            paramType[2]=com.sulake.core.runtime::IUnknown
        name_index=34407 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/private:onRoomSessionManagerReady"
        flags=0
    39581:method[6723]
        returnType=void
        param_count=2
            paramType[1]=com.sulake.core.runtime::_-0vP
            paramType[2]=com.sulake.core.runtime::IUnknown
        name_index=19363 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/private:onHabboCommunication"
        flags=8
    39594:method[6724]
        returnType=void
        param_count=1
            paramType[1]=flash.events::Event
        name_index=25819 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/private:onConfigurationLoaded"
        flags=8
    39604:method[6725]
        returnType=void
        param_count=1
            paramType[1]=flash.events::Event
        name_index=30682 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/private:onComponentsRunning"
        flags=8
    39614:method[6726]
        returnType=void
        param_count=1
            paramType[1]=flash.events::Event
        name_index=33135 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/private:onInitConnection"
        flags=8
    39624:method[6727]
        returnType=void
        param_count=1
            paramType[1]=flash.events::Event
        name_index=34913 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/private:onConnectionEstablished"
        flags=8
    39634:method[6728]
        returnType=void
        param_count=1
            paramType[1]=com.sulake.core.communication.messages::IMessageEvent
        name_index=34988 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/private:onHelloEvent"
        flags=0
    39641:method[6729]
        returnType=void
        param_count=1
            paramType[1]=com.sulake.core.communication.messages::IMessageEvent
        name_index=36672 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/private:onInitCrypto"
        flags=0
    39648:method[6730]
        returnType=void
        param_count=1
            paramType[1]=com.sulake.core.communication.messages::IMessageEvent
        name_index=35850 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/private:onSecretKeyEvent"
        flags=0
    39655:method[6731]
        returnType=void
        param_count=1
            paramType[1]=com.sulake.core.communication.connection::IConnection
        name_index=33911 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/private:sendConnectionParameters"
        flags=0
    39663:method[6732]
        returnType=void
        param_count=1
            paramType[1]=com.sulake.core.communication.messages::IMessageEvent
        name_index=28256 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/private:onSessionParamsEvent"
        flags=0
    39670:method[6733]
        returnType=void
        param_count=3
            paramType[1]=String
            paramType[2]=String
            paramType[3]=int
        name_index=33812 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/sendTryLogin"
        flags=8
    39682:method[6734]
        returnType=void
        param_count=1
            paramType[1]=com.sulake.core.communication.messages::IMessageEvent
        name_index=23382 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/private:onAuthenticationOK"
        flags=0
    39689:method[6735]
        returnType=void
        param_count=1
            paramType[1]=com.sulake.core.communication.messages::IMessageEvent
        name_index=34236 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/private:onUserObject"
        flags=0
    39696:method[6736]
        returnType=void
        param_count=2
            paramType[1]=_-1Oj::IAlertDialog
            paramType[2]=flash.events::Event
        name_index=0
        flags=0
    39703:method[6737]
        returnType=void
        param_count=2
            paramType[1]=_-1Oj::IAlertDialog
            paramType[2]=flash.events::Event
        name_index=0
        flags=0
    39710:method[6738]
        returnType=void
        param_count=1
            paramType[1]=com.sulake.core.communication.messages::IMessageEvent
        name_index=19101 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/private:onGenericError"
        flags=2
    39717:method[6739]
        returnType=void
        param_count=1
            paramType[1]=com.sulake.core.communication.messages::IMessageEvent
        name_index=31618 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/private:onPing"
        flags=0
    39724:method[6740]
        returnType=void
        param_count=1
            paramType[1]=_-0um::_-1Tx
        name_index=29072 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/private:onUniqueMachineId"
        flags=0
    39732:method[6741]
        returnType=void
        param_count=1
            paramType[1]=_-0um::_-0XP
        name_index=30188 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/private:onIdentityAccounts"
        flags=0
    39740:method[6742]
        returnType=void
        param_count=2
            paramType[1]=_-1Oj::IAlertDialog
            paramType[2]=flash.events::Event
        name_index=0
        flags=0
    39747:method[6743]
        returnType=void
        param_count=1
            paramType[1]=com.sulake.core.communication.messages::IMessageEvent
        name_index=30017 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/private:onErrorReport"
        flags=2
    39754:method[6744]
        returnType=void
        param_count=1
            paramType[1]=flash.events::Event
        name_index=19050 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/private:onConnectionDisconnected"
        flags=0
    39761:method[6745]
        returnType=void
        param_count=1
            paramType[1]=com.sulake.core.communication.messages::IMessageEvent
        name_index=25428 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/private:onDisconnectReason"
        flags=0
    39768:method[6746]
        returnType=String
        param_count=1
            paramType[1]=String
        name_index=34881 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/private:setOriginProperty"
        flags=0
    39775:method[6747]
        returnType=void
        param_count=1
            paramType[1]=_-2CJ::_-rM
        name_index=22181 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/private:onRoomEntryInfoEvent"
        flags=0
    39783:method[6748]
        returnType=void
        param_count=1
            paramType[1]=_-Ei::_-2AK
        name_index=23340 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/private:onRoomSessionEnded"
        flags=0
    39791:method[6749]
        returnType=void
        param_count=0
        name_index=28850 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/private:showHotelView"
        flags=0
    39797:method[6750]
        returnType=void
        param_count=1
            paramType[1]=String
        name_index=29370 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/private:dispatchLoginStepEvent"
        flags=0
    39804:method[6751]
        returnType=void
        param_count=1
            paramType[1]=flash.display::BitmapData
        name_index=19943 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/private:onHotelViewBannerLoaded"
        flags=0
    39811:method[6752]
        returnType=String
        param_count=1
            paramType[1]=uint
        name_index=26392 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/private:generateRandomHexString"
        flags=8
    39821:method[6753]
        returnType=void
        param_count=1
            paramType[1]=String
        name_index=36005 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/out"
        flags=0
    39828:method[6754]
        returnType=void
        param_count=2
            paramType[1]=com.sulake.core.runtime::_-0vP
            paramType[2]=com.sulake.core.runtime::IUnknown
        name_index=22207 "com.sulake.habbo.communication.demo:HabboCommunicationDemo/private:receiveLoggerInterface"
        flags=0

The two functions that are of high priority atm are the “xor” and “decode” functions. Where “xor” processes the final result from the pixels read from the “decode” function. (“decode” is basically my implementation of decodeBitmap(banner.png?token=[tokenhere]) that reads the bitmap at a specific location, where P and G are hidden).

It’s also possible to inject your own SWF into the client without it erroring now. HavvocMini anyone?!? (Click the image for direct link to img)

hax

And the log:

##############################
#	OFFICE.BOY & MYRAX		#
#  http://script-o-matic.net #
##############################
[->] Successfully injected to Stage!
*** Security Sandbox Violation ***
SecurityDomain 'http://www.habbo.co.uk/client' tried to access incompatible context 'http://images.habbo.com/gordon/RELEASE50-26273-26272-201004300318_e963ec498a8fe4fa08a3a75db39a267a/Habbo10.swf'
[->] Attatched Debugger....
[->] HabboMain Interface = [object HabboMain]
Warning: Ignoring 'secure' attribute in policy file from http://hotel-uk.habbo.com/crossdomain.xml.  The 'secure' attribute is only permitted in HTTPS and socket policy files.  See http://www.adobe.com/go/strict_policy_files for details.
Found Pet Pack: dog
Found Pet Pack: cat
Found Pet Pack: croco
Found Pet Pack: terrier
Found Pet Pack: bear
Found Pet Pack: pig
Found Pet Pack: terrier
Found Pet Pack: bear
Found Pet Pack: pig
Warning: Ignoring illegal port number specification '993' in policy file at xmlsocket://game-uk.habbo.com:30000
Warning: Ignoring illegal port number specification '993' in policy file at xmlsocket://game-uk.habbo.com:30000
Warning: Ignoring illegal port number specification '993' in policy file at xmlsocket://game-uk.habbo.com:30000

It’s not just a image copy&pasted onto a screenshot, i’ll post a video sometime to prove the layering and what-not.

haxhax1

It’s been a while,
- Mike

Categories: Crypto, Habbo, Reverse Engineering Tags:

Right Guys.

April 29th, 2010 Dominic Gunn 9 comments

Right, I thought I best make a post after seeing this on Shenk’s shoutbox.

Shenk:
@Scott – I think they changed the SSL Ticket implementation actually… but yeah, it broke all of them apart from Dashboard because Dom created it with a bypass method! ^-^
Scott:
@Alex – I’m aware, but it was my impression that they implemented a new packet structure for initiating encryption that broke most packet loggers in Release 47.

To my knowledge, nothing has been changed in terms of initializing the encryption, there’s been a few mathematical changes in the actual algorithm itself but other than that it’s pretty much the same. Oh, and they’re reading a few ‘new’ files (well i’ve not seen them before anyway)

var _loc_1:* = _-sc.assets.loadAssetFromFile(“config.xml”, new URLRequest(“config_habbo.xml”));

Might just be me who has missed them.

Anyway, with Dashboard. The reason it’s still working is because it never, ever used a legitimate login method to log you in. IE, it didn’t use POST or set cookies, it cheated. Therefore it should continue to work for the foreseeable future. Infact, I can only see it not working should they change the old ‘credentials.username’ and ‘credentials.password’ (I think that’s what they are!). So you guys are all safe on that side.

It seems upon releasing my ‘Flash Unbanner’ I forgot to do some proper research, every Habbo account has a unique Flash ID that Habbo re-assigns to your computer everytime you login on said account. So I don’t actually think the flash unbanner would be much use, you could try loading the client up and then during cilent boot-time running the unbanner, but as I haven’t been flash banned i’m unable to test it!

There’s also another ‘Sandbox’ ready to be released soon, this one however is for the real Habbo. It may come hand in hand with a suprise that’s being packed for the day of the merge. However, don’t hold me to that. ;)

Dominic Gunn

Sorry guys, AGAIN!

February 23rd, 2010 Dominic Gunn 36 comments

Things getting a little hectic in real life and i’m finding it hard to allocate time to this little project; however i’m pretty certain i’m done. Almost.

I’ve finally managed to peace together the problems with my decodeBitmap() and decodeBitmapString() and together they’re now generated a decrypted bitmap string is indeed a BigInt(), which. You guessed it, holds the P&G keys! Waaaaaaaaay!

My next post will be the final heave on this encryption cracking; and i’m pretty certain by the next post it will be done. However for now i have another little gift.

As you’re aware a Habbo user known to a few of you on Shenkx.co.uk as Imadj recently found an exploit in the facebook method of Habbo registration; allowing you to create mutant figures! Exciting as that is, he was quick to find out that Habbo have a new sort of ban. Remember the old shockwave ban? Well think of this one was a flash ban! Needless to say, you have no need to fear. Here’s a tool that will do exactly the same as SonicMouse’s Unbanner did, and will restore you to your former Habbo Glory. Click here, to download!

Dominic Gunn
Categories: General Tags:

Sorry guys!

January 30th, 2010 Dominic Gunn 56 comments

Sorry for the ridiculously late post, stuff’s been going on and I really wanted to have something to give you guys before I made another post, but that’s not going to happen just yet. So I thought i’d throw this up for you.

I’ve decided to go about the encryption another way; as oppose to waiting for Sulake to screw up with one of their obfuscations, which could take a lifetime! The new idea is to dissamble the Habbo.swf into AVM2 bytecode, modify the functions we need (decodeBitmap etc) then recompile the result back into native AVM2 code. Hopefully allowing me to use something along the lines of trace(param1); just to make sure they’re not doing anything sneaky! I’m going to be using as3c to do this. Feel free to have a look and a bit of a mess-around with it, if you get far enough you’ll notice that it wont work off the bat with static classes. That’s a rather easy fix though, however if you can’t be bothered to figure it out, just wait for the post entailing how to crack the encryption! (a detailed guide!) ;]

I also plan to release tutorials on how to inject your own .swf’s into the client, and an opensource C# Habbo applicaton. Those will probably be in the next few posts so stay tuned.

One final thing, I do have a present for Habbo emulator users. The Sandbox application that I want for the offical Habbo Hotel obviously needs to be designed and tested somewhere! So what other place than on unsecure Habbo Emulators! Here’s a version that was designed for HabboRP, it’s not complete nor do I promise that any of the features will still work. Just remember guys, because it’s open-source Aaron also has access to it, so when he patches things don’t come moaning to me. I’m not going to help you! Also this isn’t me attacking anyones retro, purely just releasing an application that’ll help people do so! You can download the binarys and source code by clicking here.

Oh, and check out http://suelake.com. It’s a great Habbo V5 emulator!

Until next time guys.

Dominic Gunn

Merry Christmas!

December 25th, 2009 Dominic Gunn 22 comments

One of two of you may have noticed that SOM has been all over the place today, and yesterday! Well i’m glad to say it’s now back on it’s feet and none of that should be happening again! There’s still a few things to sort out regarding the blog (Categories, links and what not!), but they’ll be done in time.

Regardless, hope you’re all having a great day and have got everything you wanted. I know i’ll be having fun later tonight, you should too! Merry Christmas!

Dominic Gunn
Categories: General Tags:

Problems…

December 21st, 2009 Dominic Gunn 14 comments

So, to my fustration I still can’t get this decodeBitmap function working correctly. It could be because of a number of reasons. These are:
1. Habbo sanitize something within the token before passing it onto the decodeBitmapString() function
2. The Bitmap is modified via an asset library before being passed onto the decodeBitmap() function
3. The position calculation within the decodeBitmap() function is incorrect

I havn’t seen any evidence of 1 and 2, so the best bet is point 3… I’ve debugged the client to a point where I know FOR CERTAIN where the initial decoding of the bitmap is – by getting an output of an error stack trace ;)

Stay tuned, hopefully I can move onto the next stage soon – as all this “bitmap” shit is giving me a headache!

Dominic Gunn
Categories: Crypto, Habbo Tags:

Late post.

December 12th, 2009 Dominic Gunn 33 comments

Sorry for the lack of updates recently been busy with a few other things, but this blog isn’t about that!

The decodeBitmap() function i’m working on isn’t acting aswell as it should. I’m pretty certain that the only incorrect piece of code is this one:

pixels.position = position + channel;

That line alone is the cause of what I think is making the Sandbox give me the incorrect p&g keys. Currently the SandBox outputs:

P len is 53
G len is 51
P is 72057331058456166916582840012450119041673124206131971
G is 860860017052136081176025452969014307125978262247352

P should be almost double that length. However i’ve debugged through all the code and yeah, I’m pretty certain it’s just pixels.position that’s incorrect. The obfuscated version of it is unclear in every single habbo.swf that i’ve looked at.

Alongside that i’ve been working on injecting my own swf into the client. It’s been going pretty well I guess. The few first attempts churned out the following error from the flash client:

Warning: Ignoring 'secure' attribute in policy file from http://hotel-uk.habbo.com/crossdomain.xml.  The 'secure' attribute is only permitted in HTTPS and socket policy files.  See http://www.adobe.com/go/strict_policy_files for details.
Warning: Not a known player download type, http://images.habbo.com/c_images/hotel_view_images_hq/hotelview_dec09.png

--> attempting to inject malicious swf...

TypeError: Error #1009: Cannot access a property or method of a null object reference.
	at com.sulake.core.assets::_-4z/_-WM()
	at com.sulake.core.runtime.events::EventDispatcher/_-nd()
	at flash.events::EventDispatcher/dispatchEventFunction()
	at flash.events::EventDispatcher/dispatchEvent()
	at com.sulake.core.runtime.events::EventDispatcher/dispatchEvent()
	at com.sulake.core.utils::LibraryLoader/loadEventHandler()

The source of the problem seemed to be related to the Habbo.swf not inheriting hh_hack.swf as it should. So I decided to try an alternative root. After a few attempts I got what seems to be a successfull injection!

-->
Warning: Ignoring 'secure' attribute in policy file from http://hotel-uk.habbo.com/crossdomain.xml. The 'secure' attribute is only permitted in HTTPS and socket policy files. See http://www.adobe.com/go/strict_policy_files for details.
Found Pet Pack: dog
Found Pet Pack: cat
Found Pet Pack: croco
Found Pet Pack: terrier
Found Pet Pack: bear
Found Pet Pack: pig
Found Pet Pack: terrier
Found Pet Pack: bear
Found Pet Pack: pig
(x=0, y=0, w=66, h=22) (x=0, y=1, w=66, h=19)
(x=0, y=0, w=66, h=22) (x=0, y=1, w=66, h=19)
(x=0, y=0, w=55, h=22) (x=0, y=1, w=55, h=19)
(x=0, y=0, w=55, h=22) (x=0, y=1, w=55, h=19)
(x=0, y=0, w=88, h=22) (x=0, y=1, w=88, h=19)
(x=0, y=0, w=88, h=22) (x=0, y=1, w=88, h=19)
--> attempting to inject malicious swf...
--> Injected Successfully................
TypeError: Error #1010: A term is undefined and has no properties.
	at com.sulake.core.assets::_-4z$/_-1ld()
	at com.sulake.core.assets::_-4z/_-WM()
	at com.sulake.core.runtime.events::EventDispatcher/_-nd()
	at flash.events::EventDispatcher/dispatchEventFunction()
	at flash.events::EventDispatcher/dispatchEvent()
	at com.sulake.core.runtime.events::EventDispatcher/dispatchEvent()
	at com.sulake.core.utils::LibraryLoader/loadEventHandler()
Warning: Ignoring 'secure' attribute in policy file from http://www.habbo.co.uk/crossdomain.xml. The 'secure' attribute is only permitted in HTTPS and socket policy files. See http://www.adobe.com/go/strict_policy_files for details.

That particular error hasn’t managed to cause any actual client errors and Habbo itself still works as it should. I think I know what’s causing the error and needless to say it’s nothing to particularly worry about! Next step is to completely fix decodeBitmap(), and possibly try and call some functions through hh_hack.

Dominic Gunn

Under attack!

December 7th, 2009 Dominic Gunn 8 comments

Sorry to contradict myself, in the last post I stated that the next post would talk to you about how the encryption works, with a demonstration and such. However I felt it important to tell you all that Script-o-matic is under DDoS attack. We’re not sure why or by who in particular but I thought you should all know about it, just incase we happen to go down.

On a brighter note, everything is going strong. decodeBitmap() is almost done. It’s grabbing p&g keys nicely, just need to tweak a few things to finalise it completely! Until next time.

Dominic Gunn
Categories: General Tags: , ,

Flash client encryption – explained. [Part I]

December 5th, 2009 Dominic Gunn 19 comments

Okay, since this blog is going to contain a hell of a lot of confusing stuff related to reversing stuff – I thought it’d be a nice start to explain how the current encryption routine works within the Flash client. (If you don’t understand this blog post, then you sure as hell aren’t going to understand the future ones!) I’ll do my best to explain things as simply as possible, but it’s not exactly as “simple” as some may think. Sulake have gone to great lengths to prevent the encryption being tampered with again – and with the transition to a brand new flash client who can blame them? (*cough*). Sitting comfortably? Then I may begin…

To make life simplier, I’m going to split the whole encryption process into two parts. Essentially, there are two parts to the encryption now – the Key Side and the Crypto side. The reason i’ve split the whole process into two seperate parts is purely because the Client now performs more operations to instantiate the new RC4 algorithm than it previously used to (Even when DH (Diffie Hellman Key Exchange) was first introduced within the Shockwave client! [Poorly, may I add!]) Whats Diffie Hellman Key Exchange?!? Well, i’m not really going to cover it here – but it basically means the server and client can both agree upon a key to use without previous knowledge of each other (shared secret anyone?!?). If you want to read more in-depth about it, you can visit the Wiki article HERE.

The Key side:
Sulake have really excelled themselves this time when implementing the encryption within the Flash client. As explained by Mike (Office.Boy) on the SOM placeholder page stating that it was closed, Sulake now have a new method of transferring the Diffie Hellman variables across an un-secured connection. Instead of the client grabbing a separate file (as the Shockwave client did) – it grabs a bitmap image. I know, how on earth can a bitmap image store any form of data without being visibly noticeable? Sulake have used a form of “Stenography” (Google it if you’re unsure what it is) to hide the P and G BigInteger’s which are then used to instiantate the RC4 class. Once the client has established a connection with the Habbo game server, and all handshakes have been performed appropriately – The server sends a packet which contains a unique “Hash” code (Explained later). This code is then used to grab the bitmap image containing the DYNAMIC P and G BigIntegers required to setup the encryption. The url of which the bitmap is grabbed from is:

http://www.habbo.co.uk/gamedata/banner?token=<HASH GOES HERE>

Of course, if an invalid token is specified – you just get a plain banner with no apparent data within it. However, if a valid token is provided – the server must generate a bitmap with the required P and G variables hidden within it. When analysying the image, the results of where the data is stored becomes apparent. Here are the two images next to eachother for comparison:

banner_exposed habbo_bitmap

And thats about it when relating to the new key distribution implementation! Moving onto the Cryptology side now.. Here’s when things get even MORE interesting!

The Cryptology side:

The physical RC4 class has changed a lot since we previously remember. (Gone were the days where we could just simply setup the RC4 with the public key (@A) and encipher/decipher at will!) The current encryption still contains the functions (most) of you will probably remember:

  • init(int[] key) -> Here is where the tables are setup, ready for enciphering/deciphering.
  • encipher(string data) -> Here is where packets are encrypted… Although the actual flash client takes a ByteArray, you can deal with a string and perform the parsing later on ;)
  • decipher(string data) -> Same as above, except this is where packets are decrypted
  • moveUp() -> Used within the encipher/decipher functions to essential “move up” the Encryption table.
  • premixTable(string premixString, int count) -> Ahh, the ol’ premix that caused issues in V9 of Habbo. A given string is enciphered a given amount of times (count). The server also does this so the encryption table matches both client-side and server-side.

The only changes to the above are the way Encipher/decipher now currently work. (Everyones worst nightmare :-( It was going to change sooner or later though!). Instead of using Hexadecimal, Sulake has decided to go with an alternative route known as Base64. This isn’t any odd Base64 though, it’s their own custom implementation of it – which is classed as by the RFC 2152 as UTF-7 Base64. Of course, the premix values (string and count) have changed too – but this doesn’t pose much of an issue as it’s simple to find! (Remember, premix is also not just called within init(int[] key), but after each decipher/encipher too!)

However, with the integration of base64 enciphering/deciphering, Sulake decided to implement their own custom (Hence the “UTF7″) padding! Heres the newer (and simple, yet complicated to use) functions integrated within the algorithm (not directly, but externally):

  • addPad(string data, int count) -> Adds a given amount of padding to a whole packet. The initial padding doesn’t matter, aslong as it is padded a given amount of times!
  • headerPad(string header) -> Adds a single char onto a header of a packet. Once again, it doesn’t matter initially what padder is used!
  • iterateRandom(int seed) -> Used to generate a random number for addPad count.

Waste of resources if you ask me (padding packets so much), but I guess it’s Sulakes way of trying to confuse us! That’s the end of part I, the next post will focuse on how all this flows together step-by-step – as well as examples and demonstrations! If you have any questions or queries, or if you felt interested in this article – feel free to post within the comments! Questions, feedback and discussions are more than welcome!

Dominic Gunn

Hey guys!

December 4th, 2009 Dominic Gunn 14 comments

Just wanted to post another quick update, to tell you that updates may not be as frequent over the weekend, jam packed with things to do but i’ll work on this the best I can! Deobfuscation is going great.

I’ve looked at everyones posts regarding a forum and for now have decided to just, ignore them! There is no plans for a forum as yet!

Anyway, might as well give you an example of the deobfuscation so far, this is a snippet of the BigInteger() class!

Obfuscated:

public function _-Bl() : BigInteger
{
	;
	var _loc_1:* = (null * (( <= _loc_1) * null))._-03q();
	_-Pq._-RC(this, _loc_1);
	return _loc_1;
}

Deobfuscated:

public function negate():BigInteger
{
	var r:BigInteger = nbi();
        ZERO.subTo(this, r);
        return r;
}

Expect more in the coming days!

Dominic Gunn