Yahoo Messenger Client with Action Script 3

Hello everyone, as I said, my next article is about how to create a Yahoo Messenger client. I quit do the client in php due to loop running problems and I port the code to the action script.
Why am I doing this yahoo messenger client in action script!? All started with my invisible detector website www.yahoo-messenger.ro, before i use a affiliate service for detecting invisible users. One day, I decided to have my own invisible detector. So, I started to look on the internet about yahoo messenger’s protocol and invisible detecting hacking. The founded documentation on this subject is few and unclear. All I found is a few frameworks, like openymsg, a library written in java and a c++ library called ymsg. The next step in my creations was to study about the YMSG protocol packet structure and communication flow. Below, I present you a summery of yahoo messenger packet and communication flow, from my point of view.

Yahoo Messenger Packet Diagram

A – 4 bytes that keeps the “magic packet” which is a string that specify the name of the protocol “ymsg”.
B – 2 bytes with the protocol version
C – 2 bytes with client id
D – 2 bytes with the body size
E – 2 bytes with the service number
F – 4 bytes that keeps the user status
G – 4 bytes with the session id
H – the body of the packet with key value pairs

The work with this packet is very simple when you  use action script, the class which manipulate the bytes is the ByteArray class. For php i personally use the Zend_Io package.
For example, i use a class called Packet which convert raw data to human readable values, and for sending back , i have a method called toRaw().

package albu
{
	import flash.utils.ByteArray;
	import flash.utils.Endian;

	public class Packet
	{
		//body data separator
		public static const SEPARATOR:Array = [0xC0, 0x80];

		//client version
		public static const VERSION:Array = [0x00, 0x10, 0x00, 0x00];

		//service
		public var service:Number;

		//user status
		public var status:uint = 0;

		//session id
		public static var session:Number = 0x00;

		//packet body
		public var _body:PacketBody;

		public function Packet()
		{
			_body = new PacketBody();
		}

		public function get length():Number
		{
			return body.bytes.length;
		}

		public function get body():PacketBody
		{
			return _body;
		}

		public function getBytes():ByteArray
		{
			var ba:ByteArray = new ByteArray();

			var packetBody:ByteArray = body.bytes;

			ba.endian = Endian.BIG_ENDIAN;

			//magic packet
			ba.writeUTFBytes("YMSG");

			// Version
			ByteUtil.writeArray(ba, VERSION);

			//packet length
			ba.writeShort( packetBody.length );

			//service
			ba.writeShort(service);

			//status
			ba.writeInt(status);

			//session
			ba.writeInt(session);

			//body
			ba.writeBytes( packetBody );

			return ba;
		}

		public function toString():String
		{
			var out:String = "";

			out += "----------- PACKET -------------\n";

			out += "Service: " + service + "\n";
			out += "Length: " + length + "\n";
			out += "Body: " + body + "\n";

			out += "----------- PACKET -------------\n";

			return out;
		}
	}
}

Now , that we know how to use a packet for communication with the yahoo messenger servers, we need to understand the communication flow. For me, it  was not so hard to catch it. See the diagram below for a login and retrive the buddy list process.

Next , there are few words about this diagram, because i`m sure the detailed informations is neded. First, we send over the socket created to the yahoo server the checking packet that contains a ket/value pair with key “1” and value the username used for login. This packet is sent with service 0x57. Yeah, about services… Services are like a command used by yahoo servers to communicate with clients. On the internet you  find a lots of articles with the services used and known, i`m sure that are more services and which  are unknown, because the YMSG protocol is not public.

package albu
{
	public class Service
	{
		public static const AUTH:Number = 0x57;

		public static const AUTHRESP:Number = 0x54;

		public static const MESSAGE:Number = 0x6;

		public static const BUDDY_LIST:Number = 241;

		public static const TYPEING:Number = 0x4B;

		public static const KEEPALIVE:Number = 0x8a;
	}
}

This is a minimal list of services used by this example. For a complete list you look here

To continue from the first step when the auth packet is sent, the one with the service 0x57 is the auth packet. If this packet is sending in the right format, next you receive a packet with the session id and the seed used to compute our yahoo messenger password.

https://login.yahoo.com/config/pwtoken_get?src=ymsgr&ts=&login={USERNAME}&passwd={URLENCODED_PASSWORD}&chal={URLENCODED_TOKEN}

The next step is the password computation, and wich is made with a url from the yahoo login process. This url generate a token from password, username and the seed received from the socket. The response of this url is a text with two lines. The first line keeps the response code of authentification process.

A list with response codes:

  • 1235 – Login Failed, Invalid username
  • 1212 – Login Failed, Wrong password
  • 1213 – Login locked: Too many failed login attempts
  • 1236 – Login locked

The second line is the token generated when there is no error response code and wich is used to the next process to finalize the login.

https://login.yahoo.com/config/pwtoken_login?src=ymsgr&ts=&token={TOKEN}

This url will return a four line reponse with the response code a crumb, cookie Y and cookie T.
As i know, the response code 0 is no error and that is enought for me :).  The crumb and the two cookies are used to compute the challenge with yahoo base64 encode algorithm and md5 function.
The result of challange computer is used in the next packet which is the login packet sent over the socket with the service 0x54.

var version:uint = stream.readInt();
var length:uint  = stream.readShort();
var service:uint = stream.readShort();
var status:uint  = stream.readInt();
var session:uint = stream.readInt();

if(stream.bytesAvailable >= length)
{
	var p:Packet = new Packet();

	if(!Packet.session)
	{
		Packet.session = session;
	}

	p.status = status;
	p.service = service;

	//read entire buffer for packet body
	var bodyBytes:ByteArray = new ByteArray();
	stream.readBytes(bodyBytes, stream.position, p.length);

	//set the packet body
	p.body.bytes = bodyBytes;

	var newStream:ByteArray = new ByteArray();

	stream.clear();

	stream.writeBytes(newStream);

	packetStack.push( p );
}

About this packet, i can’t tell you more details out of that are abvious, the username, client version which is what you want to put there, is the version of this client, version name. and the challange response. That will return the chuncked packet with ymsg buddy list. From now, you are connected to the yahoo and you can communicate with servers. You can send, receive messages, send buzz and all features used by yahoo messenger.

//auth packet
var p:Packet = new Packet();
p.body.add(1, _user);
p.body.add(0, _user);
p.body.add(277, chall[0]);
p.body.add(278, chall[1]);
p.body.add(307, chall[2]);
p.body.add(244, CLIENT_VERSION_ID);
p.body.add(2, _user);
p.body.add(2, "1");
p.body.add(135, CLIENT_VERSION);

p.service = Service.AUTHRESP;

network.send( p );

This is a simple example with basic functionality, i`m sure if you are using the wireshark you will find more about ymsg protocol, but this is the basic usage and it is a mochup.

yahoo messenger application in flex

Buddy and BuddyGroups are classes wich is like a value objcts for keeping users data.  Network is the classs wich create the socket connection and send the events to the YMSession. Packet and PacketBody keeps the data for a packet. Service class keeps constants with some of known services. And the most important class is YMSession wich wire rest of the classes. This class makes the login process receiving messages and sending messages, buzz and other services.

For personal testing and debugging download the files

I hope my second post will be usefully to someone :) . If you are something to ask me, don`t hesitate to tell me what do you think about this article.

Using amf in flex

Hi everyone!
My name is Cosmin Albulescu and this is the first time I’m posting on my blog. I’ve been working as a web developer for about 6 years, using common technologies like javascript, php, action script, or flex.

This post may be very useful for those who want to create a simple remote procedure call with amf and flex.

AMF (Action Message Format) is used in action script in order to exchange serialized data between a flash application and a remote server. To find more information about the amf please visit this link

Why using amf protocol, there are lots of advantages.

  • It is faster than usually calling a php file that returns an xml
  • It is more practical because the data is already serialized
  • iIn flex you already have classes that work with amf

The first thing that needs to be done when you want to use amf protocol is to write your server side methods and pass it to the amf protocol hanlder class. The amf handler class receives the binary call from flash or flex application, calls your service method and returns the binary serialized data back to the flash.

There are several classes that do this thing for most of all programming languages. For the php the most known are AMFPHP, SabreAMF, WebORB for PHP, Zend_Amf, php-amf3 extension.

In this example is used the Zend_Amf from the Zend Framework, a framework library written by the zend community.

Steps to build your remote service methods

STEP 1 – Create amf Service file

Create a file called phonebook.php wich holds the main service methods

class Phonebook
{
 const DATA_FILE = "phonebook.dat";

 private $phonebook;

 public function __construct()
 {
 $this->phonebook = unserialize(file_get_contents(self::DATA_FILE));
 session_start();
 }

 public function login($user, $password)
 {
 if($user == "admin" && $password == "1234")
 {
 $_SESSION['logged'] = true;
 return true;
 }

 return false;
 }

 public function sync($phonebook = null)
 {
 if(is_array($phonebook) && count($phonebook))
 {
 $this->phonebook = $phonebook;
 file_put_contents(self::DATA_FILE, serialize($this->phonebook));
 }

 return $this->phonebook;
 }
}
}

The php code above is a simple phonebook application that save your serialized array with phone numbers into a file. This is a fast method just to show how to use the amf. You may also use mysql or other saving methods. The functions of this class must be public to be accesible from flex, you cannot call the private or protected methods.

STEP 2 – Instantiate the Zend_Amf_Server for handling the service class

Now will create a file called api.php with code below wich handle our public methods. For that we need to download the Zend Amf package, a simple way for get this is to use the packageizer application This package generator pack just nedded classes from the framework.

.

    //set your include path to the zend framework
    require "Phonebook.php";
    require "Zend/Amf/Server.php";
    $server = new Zend_Amf_Server();
    $server->setClass('Phonebook');
    $response = $server->handle();
    echo $response;

This class is simple to use just instantiate the Zend_Amf_Server class and pass your class to it. The setProduction method is used for throwing or not the errors generated from Phonebook class. For more documentation about using the Zend_Amf_Server please visit documentation page. From this point your service is functionable and the public methods can be called. From now on will need to do the flex application mxml wich will use this remote file.

STEP 3 – Create flex main file

This is a simple layout  having two states one for logged and other for editing mode with a DataGrid component and buttons for add and remove item. The code below is all needed to do for flex side, create the ui and build the logic for it.

View the mxml source

The class that is used to call remote amf methods is RemoteObject, if this is used from action script make sure you have been imported from the right package. The package for doing with the action script is mx.rpc.messaging. After will done with the RemoteObject initialization we need to create the operation that are linked to server side amf methods.

private function init():void
 {
 rpc = new RemoteObject();

 var channels:ChannelSet = new ChannelSet();
 channels.addChannel( new AMFChannel("api", "api.php") );

 rpc.destination = "api";
 rpc.channelSet = channels;

 rpc_login = rpc.getOperation('Phonebook.login') as Operation;
 rpc_login.addEventListener(ResultEvent.RESULT, onLoginResponse);

 rpc_sync = rpc.getOperation('Phonebook.sync') as Operation;
 rpc_sync.addEventListener(ResultEvent.RESULT, onSyncResponse);

 addEventListener(StateChangeEvent.CURRENT_STATE_CHANGE, onStateChanged);
 }

After the RemoteObject and operation instances are created make sure you add handlers for operations that are waiting for response for example the login method will return true if user has been logged in or false if not. A important think is to create crossdomain.xml on root where api.php file is created, otherwise the remote calls will be blocked by the flash security concern. This is just in case you are using a different domain if all files are in the same path is not necessary.

Try using user admin and password 1234

This is just a demo and data will be deleted after 10 items.

Download the source file

I hope this post is usefully for flex beginners if so i will be glad to hear your comments about it. Stay closed the next article will be about how to create a yahoo messenger client written in php and implemented on the last version of YMSG protocol.