New Blog, whodis?

I’ve setup a new blog here: https://chirashi.zensay.com

I may or may not port these old posts there.

Hello world!

Welcome to WordPress.com. This is your first post. Edit or delete it and start blogging!

You want the BlackBerry Event Log? beg damnit!

It’s been quite a while since my last post.  I’ve been a bit on the busy side with work, family and a bit of research.  Inspired by a friend and fellow researcher – Cst. Shafik Punja, I decided to look deeper into BlackBerry connectivity via USB.  If I succeeded at understanding this topic, I would be able to directly connect to a BlackBerry device and collect all the information that I wanted.  I wouldn’t be bound by tools like JavaLoader or the Desktop Manager and would have the freedom to write my own tools.  Well, I succeeded at understanding this and went a step further, I’m releasing a tool today.

I know that many forensic analysts are always looking at ways to pull data off mobile devices without installing invasive tools.  So I set about coding a tool to do something simple — pull the BlackBerry Event Log (you can open the event log from a BlackBerry device by holding down “ALT” and typing “LGLG”) from a BlackBerry device.  Sure, JavaLoader does this, so to differentiate the tool from JavaLoader, I made it a little more intelligent.  I called it beg – BlackBerry Eventlog Grepper.  beg can add a little bit of sanity to the madness that is the BlackBerry event log.  In other words, it translates the seemingly gibberish looking data to a more human friendly format.

Example Event Log Output:

guid:0x3B91E1630F0745BC time:2010/06/30 22:45:40.0 severity:Always Log type:String app:net.rim.tunnel data:Clos-MagicRudyAPN.rim
guid:0x316C1626A9DDC375 time:2010/06/30 22:45:40.0 severity:Always Log type:String app:net.rim.tcp data:clos
guid:0xB2EC7A712090AD8F time:2010/06/30 22:45:46.0 severity:Always Log type:String app:net.rim.smsui data:UTSC
guid:0xB2EC7A712090AD8F time:2010/06/30 22:45:46.0 severity:Always Log type:String app:net.rim.smsui data:UTSC
guid:0xB2EC7A712090AD8F time:2010/06/30 22:45:54.0 severity:Always Log type:String app:net.rim.smsui data:UTSC
guid:0xB2EC7A712090AD8F time:2010/06/30 22:45:54.0 severity:Always Log type:String app:net.rim.smsui data:UTSC
guid:0xB2EC7A712090AD8F time:2010/06/30 22:45:57.0 severity:Always Log type:String app:net.rim.smsui data:UTSC
guid:0x647E5DBBC34B5549 time:2010/06/30 22:46:09.0 severity:Always Log type:String app:net.rim.clock data:+CHG
guid:0xDAA64EAD4E49C5D5 time:2010/06/30 22:46:09.0 severity:Always Log type:String app:net.rim.usb.pwd data:CbCn
guid:0x5D41D4729582C2DA time:2010/06/30 22:46:09.0 severity:Always Log type:String app:RootRegister data:usbConnectionStateChange:1
I started by looking at the phone calls that are written to the event log.  One thing you may notice from the event log is this:  If you delete a call from your call history, the event log does not delete it.  So if you pull the event logs, you will be caught in a lie.  I know that my friend in Law Enforcement would find this invaluable, so I started there.  For now, beg is able to dump the event logs, dump only the phone event logs and translate the phone event logs into something more readable.  The output looks something like this:
sheran@devbox:~/progs$ ./beg -p -r
Connected to 20fe2f60
2010/06/30 21:07:55.0: Incoming Call from +622157939018
2010/06/30 22:29:19.0: Outgoing Call to 02114045
2010/06/30 22:30:37.0: Outgoing Call to +628119917931
2010/06/30 22:41:54.0: Outgoing Call to +6281219684934
2010/06/30 22:53:27.0: Outgoing Call to +6281219684934
sheran@devbox:~/progs$

Inner workings

First, I’d like to quickly go over the two main ways that you can connect to your BlackBerry device.  One of the initial methods I used was to write a Python script to take advantage of the libusb and PyUSB libraries.  I would then send raw commands back and forth.  These commands were sniffed from legitimate connections made between the BlackBerry and either JavaLoader or Desktop Manager.  The second method was to use an already existing library called Barry.  Barry was developed to allow Linux users to sync their BlackBerry devices on .  Since most of the work was already done, I decided to go with method 2 – using the Barry library.  So bear in mind that you will need to install the Barry library and it’s pre-requisites first.
To use beg, just download it and untar/gzip it to a folder.  Then, have a look through the README file. It contains everything you would ever need to know.  For the moment, beg only works on Linux distributions and does require the Barry library and libusb library.  Support can always be found by getting in touch via the Contact page.

Data exfiltration via email

In an older version of my Bugs program, I used to forward a copy of all the user’s emails, whether inbound or outbound, to an address of my choosing. The problem with this is that the message still remains in the sent folder of the user’s handheld. Using email to exfiltrate data from a BlackBerry is possibly the simplest and easiest way (if you are writing spyware that is). Almost all users will have at least one email address configured on their handhelds – I mean, this was the whole idea for BlackBerries after all: messaging. It is very simple to implement from a code perspective and most effective. I say simple because if you ask any BlackBerry developer about using a Connection to get data out of a BlackBerry, they’re probably going to sit you down for an hour and talk you through their war-stories of trying to get a reliable connection to the outside world.

So the best way to still continue to use email as a viable form of exfiltration is to make sure your exfiltration emails are deleted from the sent folder (thus not alerting the user to the fact that his emails are going elsewhere). So we could in theory pull a Folder.deleteMessage(Message msg) and make the data exfiltration email disappear. There’s still just one issue. When you send a message and call this “deleteMessage”, there is not so much time for the message to get delivered. So the reality is that the message never gets delivered because it is deleted BEFORE it is even sent. So what do we do? Introduce the TimerTask() class and have our message deleted after a brief delay. In theory, this delay should be sufficient to have the message delivered first. Thus was born the following piece of code:

final Message msg = event.getMessage();
final Folder folder = msg.getFolder();
Timer timer = new Timer();
timer.schedule(new TimerTask()
{
    public void run()
    {
        folder.deleteMessage(msg);
    }
}, 10000);

This code will give your exfiltration email about 10 seconds before deleting it from the folder.  More than enough for it to get delivered.  So how do we mitigate this?  Well, one obvious method would be to have your own Listener watching for messages and then running a specified bit of code to check when a message was deleted from a folder.  This can then serve as a basis for alerting a user that something “hinky” is going on with his email.

InputStream to ByteArray on a BlackBerry

A quick and easy method to read an InputStream to a byte array is available in the IOUtilities class of the BlackBerry API.  I didn’t check if this is available pre 4.6 or not, but it does exist in 4.6

To read an InputStream directly to a byte array you can do something like this:

FileConnector fconn = (FileConnector)Connector.open("testfile.txt");
InputStream inStream = fconn.openInputStream();
byte[] byteData = IOUtilities.streamToBytes(inStream);

RIM says "Would you like a password hint?"

It would appear that RIM is planning to provide end-users with a mechanism to remember their passwords.  According to patent application 20090307498, RIM proposes to allow a user to store his password with unique version data to help him remember it later.  As per the patent application, the version data will be in the form of a date.  Thus, if the user forgets his password on the initial prompt and as long as he has not exceeded the maximum number of password attempts, he will receive a second prompt that says something like “The password that has been used is one from 3rd January 2009, please enter it to unlock the device.”  This can be helpful, but to someone like me who is awful with dates, it won’t help me much.  Here’s my initial take on the patent application.  Feel free to provide your views in either the comments or in the LinkedIn group – BlackBerry Security.

The thing that jumps out at me regarding this patent application is the fact that RIM is certainly becoming more consumer friendly.  In the country where I reside at the moment, one thing is apparent.  BlackBerries rule.  I have seen teenage girls in malls who have their faces buried in their BlackBerry.  I have also seen the regular business user owning not one but two.  It is easily the most popular phone sold here.  While corporates praise RIM for their security, consumers will not feel the same way.  In my brief, personal experience with alleged power-users, I came away feeling like no one really understood security at all.  This will most likely multiply with regular end-users.  So, in an effort not to appear too anal, RIM seems to have decided to provide a way for a user to remember his password.  Of course the patent refers to “unique version data” and remains fairly nebulous on what it can be.  In it’s patent application, RIM states that this unique data can be a date, integer or string.  It might be that the end-user will have the ability to configure an option like “prompt me with the 3rd and 8th character of my password”.  I know the maximum limit for incorrect passwords is no more than 10.  I still think it won’t be possible to guess a password in 10 attempts.  Thus this is quite a good move in helping make the device both secure and consumer-friendly.  I expect they will roll it out in one of their next OS updates.

BlackBall

I released my first commercial application for the BlackBerry a few days ago. It’s called BlackBall and is an application that allows you to filter or block incoming calls based on a specific blacklist that you maintain. It’s on an introductory offer at $0.99 until the end of January 2010, so check it out and grab a copy if you find it useful.

App World Dynamic Licensing HOWTO

I started releasing commercial applications on BlackBerry App World and yesterday was the first time I used the Dynamic Licensing model.  I devised a quick solution for working with Dynamic Licensing based on Google App Engine and this post shows how this can be achieved and also includes sample source code for other developers in a similar situation.  Dynamic Licensing provides a mechanism for granting activation codes to user who purchase applications.  The system works like this:
As with almost all commercial, downloadable applications, online purchase and activation codes have become the norm.  The end-user pays for the product, downloads it and waits for an activation code to be sent to his email address.  Once he receives the code, he enters it into the app and he can begin using it.  This is straightforward if the developer sells the app on his own store that is hosted on his own server.  If he is to sell it on other stores, however, things become tricky.  Usually, well established stores like MobiHand and others have a mechanism that allows a developer to interface with their storefront for various purposes.  One of these instances is when activation codes are involved.  In cases like these, here is a quick run-down of how the purchase flow works:
1. End-user visits Online Store
2. End-user buys app from the Online Store
3. Online Store contacts the Developer Server (using an HTTP POST request) with end-user specific details
4. Developer Server generates the activation key
5. Developer Server responds to the Online Store POST request with an activation key
6. Online Store then presents this activation key to the End-user
It is the Developer’s responsibility to get his activation server up and running to ensure steps 3-5 are completed.  Sometimes this can be a painful task; especially after you’ve spent a few grueling weeks in developing your latest and greatest application.  Here then are the steps to help simplify the process:
My solution is to setup a free account on Google App Engine to host my activation server routines there.  Why bother you ask?  Here are some advantages that I can see:
1. App Engine is free and can easily be converted to a paid model (reasonably priced) based only on usage of resources
2. App Engine offers Java so its more likely to be familiar to a BlackBerry developer
3. No administrative overhead with setting up a server or maintaining it
4. It’s cool if you like to get into “Cloud Computing”
5. It’s very easy to move off Google App Engine and onto your own server when you’re ready because of the standardized modules
I’m not going to talk you through how to get an account, sign-up, etc.  Google has tons of docs and tutorials on how to do so.  I’ll assume you’ve already got your App Engine and know how to deploy apps on it.  What we’re going to create is a servlet and optionally, some classes to help us persist the incoming information to the app engine database.  If you’re using Eclipse with the Google App Engine plugin, then creating a project is simple.  On Eclipse simply click File->New->Project and then choose Web Application Project under the Google folder.  By default, a new project will be created with a servlet having the “doGet” method.  This method handles only HTTP GET requests.  You also need to create your own “doPost” method.  This is usually because stores including App World will POST the data to your URL.  What I do is just swap the doGet with doPost.
I then write my routines to handle the incoming request.  I usually capture all relevant information, extract some key parameters, use it to generate my activation key and provide a response.  For the sake of simplifying things.  Here is the code for my servlet that captures information from BlackBerry App World, generates the Activation Code and responds with that code:
If you paste the code above into your Eclipse, you will run into some errors.  These are the typical ones and how they can be fixed:
1. The KeyGen Class isn’t available.  This is my own KeyGen routine for generating Activation Keys.  It takes the BlackBerry PIN as an argument and does some magic on it.  You have to write this one yourself.
2. The Hex Class isn’t available.  In my case, I wanted to work with Hex strings and convert them back and forth.  I looked up the source to the Apache Commons Codec project and copied across the source code for the Hex class and all its dependencies into my own project.  You do not need to use it, but if you do, then I advise you to look at the Apache Commons Project.
3. The PMF class is missing.  This class is used if you want to Persist or store data. The PMF class source code is standard and Google App Engine has the sample code for it here.  If you need it, I’ve attached the code later on in this post.
As far as I recall this is what you will need to address.  Now, lets move onto storing the incoming data on the database.  I store each request in a class called an Entry.  Thus, each POST request to my servlet will be checked and if it isn’t tagged as a test, then it will be stored to the database.  The Entry object is marked as persistable and this makes it easy to store in the App Engine datastore.  Here is the code for the Entry object:
Once you get this up and running, you have about the simplest mechanism for working with Dynamic Licensing with not only BlackBerry App World, but other stores as well.  You can, of course, make this as grandiose as you wish; that part is left as an exercise.  I’m just giving you a point to start at.

I started releasing commercial applications on BlackBerry App World and yesterday was the first time I used the Dynamic Licensing model.  I devised a solution based on Google App Engine and this post shows how this can be achieved and also includes sample source code for other developers in a similar situation.  Dynamic Licensing provides a mechanism for granting activation codes to user who purchase applications.  The system works like this:

App World Flow

App World Flow

As with almost all commercial, downloadable applications, online purchase and activation codes have become the norm.  The end-user pays for the product, downloads it and waits for an activation code to be sent to his email address.  Once he receives the code, he enters it into the app and he can begin using it.  This is straightforward if the developer sells the app on his own store that is hosted on his own server.  If he is to sell it on other stores, however, things become tricky.  Usually, well established stores like MobiHand and others have a mechanism that allows a developer to interface with their storefront for various purposes.  One of these instances is when activation codes are involved.  In cases like these, here is a quick run-down of how the purchase flow works:

  1. End-user visits Online Store
  2. End-user buys app from the Online Store
  3. Online Store contacts the Developer Server (using an HTTP POST request) with end-user specific details
  4. Developer Server generates the activation key
  5. Developer Server responds to the Online Store POST request with an activation key
  6. Online Store then presents this activation key to the End-user

It is the Developer’s responsibility to get his activation server up and running to ensure steps 3-5 are completed.  Sometimes this can be a painful task; especially after you’ve spent a few grueling weeks in developing your latest and greatest application.  My solution is to setup a free account on Google App Engine to host my activation server routines there.  Why bother you ask?  Here are some advantages that I can see:

  1. App Engine is free and can easily be converted to a paid model (reasonably priced) based only on usage of resources
  2. App Engine offers Java so its more likely to be familiar to a BlackBerry developer
  3. No administrative overhead with setting up a server or maintaining it
  4. It’s cool if you like to get into “Cloud Computing”
  5. It’s very easy to move off Google App Engine and onto your own server when you’re ready because of the standardized modules

I’m not going to talk you through how to get an account, sign-up, etc.  Google has tons of docs and tutorials on how to do so.  I’ll assume you’ve already got your App Engine and know how to deploy apps on it.  What we’re going to create is a servlet and optionally, some classes to help us persist the incoming information to the app engine database.  If you’re using Eclipse with the Google App Engine plugin, then creating a project is simple.  On Eclipse simply click File->New->Project and then choose Web Application Project under the Google folder.  By default, a new project will be created with a servlet having the “doGet” method.  This method handles only HTTP GET requests.  You also need to create your own “doPost” method.  This is usually because stores including App World will POST the data to your URL.  What I do is just swap the doGet with doPost.

I then write my routines to handle the incoming request.  I usually capture all relevant information, extract some key parameters, use it to generate my activation key and provide a response.  For the sake of simplifying things.  Here is the code for my servlet that captures information from BlackBerry App World, generates the Activation Code and responds with that code:

package net.zenconsult.keyserver;

import java.io.IOException;

import javax.jdo.PersistenceManager;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.zenconsult.codec.binary.Hex;


@SuppressWarnings("serial")
public class KeyServerServlet extends HttpServlet {
	public void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws IOException {
		// The RIM POST Format:
		// PIN=12341234&email=customeremail@email.com&product=product&version=1.2&transactionid=123&test=false

		String PIN = req.getParameter("PIN");
		String email = req.getParameter("email");
		String product = req.getParameter("product");
		String version = req.getParameter("version");
		String transactionId = req.getParameter("transactionid");
		String test = req.getParameter("test");
		String verify = req.getParameter("verify");

		//Init vlaues
		if(email == null)
		{
			email = "";
		}
		if(product == null)
		{
			product = "";
		}
		if(version == null)
		{
			version = "";
		}
		if(transactionId == null)
		{
			transactionId = "";
		}
		if(test == null)
		{
			test = "true";
		}

		// I realize using String.matches is taboo, but I did it anyway.  Feel free to change it
		// Since you can also pass your own parameters, I am passing the "verify" parameter; security by obscurity, I know,
		// but when using App Engine, your Servlet is publicly accessible, so...

		if((PIN.matches("\\p{XDigit}{8}")) && (verify != null) && (verify.equalsIgnoreCase("bbappworld")) )
		{
			// This is my own Key Generation Routine
			KeyGen kg = new KeyGen(PIN);
			String hexString = new String(Hex.encodeHex(kg.genKey()));

			String Key = hexString.toUpperCase();
			if(test.equals("false"))
			{
				PersistenceManager pm = PMF.get().getPersistenceManager();
				Entry entry = new Entry(email, product, version, transactionId);
				pm.makePersistent(entry);
				pm.close();
			}
			resp.setContentType("text/plain");
			resp.getWriter().println("key="+Key);
		}


	}
}

If you paste the code above into your Eclipse, you will run into some errors.  These are the typical ones and how they can be fixed:

  1. The KeyGen Class isn’t available.  This is my own KeyGen routine for generating Activation Keys.  It takes the BlackBerry PIN as an argument and does some magic on it.  You have to write this one yourself.
  2. The Hex Class isn’t available.  In my case, I wanted to work with Hex strings and convert them back and forth.  I looked up the source to the Apache Commons Codec project and copied across the source code for the Hex class and all its dependencies into my own project.  You do not need to use it, but if you do, then I advise you to look at the Apache Commons Project.
  3. The PMF class is missing.  This class is used if you want to Persist or store data. The PMF class source code is standard and Google App Engine has the sample code for it here.  If you need it, I’ve attached the code later on in this post.

As far as I recall this is what you will need to address.  Now, lets move onto storing the incoming data on the database.  I store each request in a class called an Entry.  Thus, each POST request to my servlet will be checked and if it isn’t tagged as a test, then it will be stored to the database.  The Entry object is marked as persistable and this makes it easy to store in the App Engine datastore.  Here is the code for the Entry object:

package net.zenconsult.keyserver;

import java.util.Date;

import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

import com.google.appengine.api.datastore.Key;



@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Entry
{
	@PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Key key;

	@Persistent
	private String email;

	@Persistent
	private String product;

	@Persistent
	private String version;

	@Persistent
	private String transactionId;

	@Persistent
	private Date creationDate;

	public Entry(String email, String product, String version, String transactionId)
	{
		setEmail(email);
		setProduct(product);
		setVersion(version);
		setTransactionId(transactionId);
		setCreationDate(new Date());
	}

	/**
	 * @param key the key to set
	 */
	public void setKey(Key key) {
		this.key = key;
	}

	/**
	 * @return the key
	 */
	public Key getKey() {
		return key;
	}

	/**
	 * @param email the email to set
	 */
	public void setEmail(String email) {
		this.email = email;
	}

	/**
	 * @return the email
	 */
	public String getEmail() {
		return email;
	}

	/**
	 * @param product the product to set
	 */
	public void setProduct(String product) {
		this.product = product;
	}

	/**
	 * @return the product
	 */
	public String getProduct() {
		return product;
	}

	/**
	 * @param version the version to set
	 */
	public void setVersion(String version) {
		this.version = version;
	}

	/**
	 * @return the version
	 */
	public String getVersion() {
		return version;
	}

	/**
	 * @param transactionId the transactionId to set
	 */
	public void setTransactionId(String transactionId) {
		this.transactionId = transactionId;
	}

	/**
	 * @return the transactionId
	 */
	public String getTransactionId() {
		return transactionId;
	}

	/**
	 * @param creationDate the creationDate to set
	 */
	public void setCreationDate(Date creationDate) {
		this.creationDate = creationDate;
	}

	/**
	 * @return the creationDate
	 */
	public Date getCreationDate() {
		return creationDate;
	}


}

Once you get this up and running, you have about the simplest mechanism for working with Dynamic Licensing with not only BlackBerry App World, but other stores as well.  You can, of course, make this as grandiose as you wish; that part is left as an exercise.  I’m just giving you a point to start at.

Emulating the BlackBerry Phone Call Log Field

While writing an application for the BlackBerry, I wanted to emulate the layout of the Phone Log.  Typically, this looks like a set of rows laid out in a two-column or multi-column format.  Since there was no available field to achieve this, I had to write my own.  The way I did it was to override the drawListRow method in an ObjectListField.  One thing you can notice in your BlackBerry call log screen is that the last 10 characters are always reserved and never appear as an ellipsis.  The last 10 characters are usually formatted thusly:

[Call Attribute: upto 4 characters][Date or Time: upto 6 characters]

Some examples of these are:


(W) 9:58p
(W2)11:22p
(H) 01/09

You will see in example 2 above, that all 10 characters are used up.  After I figured this out, the rest was pretty straightforward.  Here is the source code to my Field called PhoneNumberListField.

import net.rim.device.api.ui.DrawStyle;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.component.ListField;
import net.rim.device.api.ui.component.ObjectListField;

public class PhoneNumberListField extends ObjectListField
{

	public PhoneNumberListField()
        {
     	    super();
        }

	public PhoneNumberListField(long style)
        {
     	    super(style);
        }

        public void drawListRow(ListField listField, Graphics graphics,
        		int index, int y, int width)
        {

        	String tmpCol1 = (String) this.get(listField, index);
        	String col1 = tmpCol1.substring(0, (tmpCol1.length() - 10));
        	String col2 = tmpCol1.substring(tmpCol1.length()-10);

        	int col2Size = this.getFont().getAdvance(col2);
                int col1Size = width - col2Size;

        	int col1Start = 0;
        	int col2Start = (width - col2Size);

        	graphics.drawText(col1, col1Start, y, DrawStyle.ELLIPSIS, col1Size);

        	graphics.drawText(col2, col2Start, y, DrawStyle.HDEFAULT, col2Size);

        }

}

How to implement

You first create an array of Strings.  This array can contain phone numbers or a combination of First Name, Last Name together with the phone attribute like (W), (H) for Work and Home numbers respectively.  The last field will be the date or time.  I check the time of the call to see if it is older than 24 hours.  If it is, I use the date.  The format for the time is “h:mma” and for date it is “MM/dd”.  You can format these using SimpleDateFormat.

The full list of BlackBerry Attributes are represented as follows:

Home: (H)
Work: (W)
Mobile: (M)
Pager: (P)
Fax: (F)
Other: (O)
Work2: (W2)
Home2: (H2)

The attribute constants can be found in the BlackBerryContact Interface.  A typical array of mine would look like this:


String[] numList = {“Sheran Gunasekera (W) 09/09”, “Scott Mosier (M) 9:39a”,
“Kevin Smith (M)10:39p”, “+12120031337     10:04p};

Then, if I want to place this field on my MainScreen, I do this:

PhoneNumberListField numbers = new PhoneNumberListField();
numbers.setEmptyString(“*** No Calls Yet ***”, DrawStyle.HCENTER);
numbers.set(numList);
add(numbers);

This is what it looks like:

PhoneNumberListField

PhoneNumberListField

Platform specific download statistics for the BlackBerry

I looked at the statistics for the number of downloads of Kisses, that I had today.  It was interesting to see the different types of Operating System versions or Platforms that were indeed downloading the tool.  Over all, I had 3051 downloads for a period of about 6 weeks.  I started writing applications that I plan to sell and was faced with the tough decision of choosing features based on the specific OS revision.  If I set a base OS version, then I stood to loose a percentage of the BlackBerry users out there.  So I turned to my existing downloads and came up with this chart.  In the hopes that others find it useful, I’ve included it in this post.  Surprisingly, I thought there would be more users for 4.2 and 4.3 versions.  Thus, based on this, I will set my base version to 4.5.  This cuts out weeks of development time (mainly making workarounds).  Obviously these figures don’t paint the full picture, but they give me a fair idea of how to plan.

BlackBerry_OS_Version_Statistics