CHAPTER 6
Java Mobile Edition Security

image

Java is an extremely popular language and runtime technology developed by Sun. It powers everything from complex enterprise applications to the software in Blu-ray players and vending machines. Most developers are familiar with Java 2 Standard Edition (J2SE) and Java 2 Enterprise Edition (J2EE), but fewer know about Java’s mobile cousin Java Mobile Edition (JME). Previously known as Java 2 Mobile Edition (J2ME), it is one of the most popular development platforms for mobile application developers and has been embraced by many of the major network operators and phone manufacturers. At the time of this writing, seven of the top ten most popular mobile phones sold in the United Kingdom support JME (http://reviews.cnet.co.uk/mobiles/popular.htm).

JME has a fairly good security history, and the JME standards include in-depth security sections that define how each technology should be used and secured. The security approach is comprised of three main principles:

image    Sandbox applications and prevent them from interacting with each other.

image    Limit applications’ raw hardware access.

image    When all else fails, ask the user.

Most of this security was designed to protect the phone and carrier’s network by making it more difficult to implement certain revenue-draining technologies, such as VoIP. These restrictions have had the nice side effect of protecting users, and few JME security incidents or vulnerabilities have been reported.

Standards Development

Unlike some other mobile platforms, such as Windows Mobile and iPhone, JME is not a full operating system (OS). Rather, it is a collection of standards that defines a runtime and API set. If an operator wants their device to run JME applications, they implement the required standards and verify that their implementation passes the published compatibility tests. The standards abstract or deny access to most of the hardware functionality because JME runs on many different devices, and each of those devices has wildly different capabilities.

New standards are defined through the Java Community Process (JCP), a framework for companies and individuals to work together and define common Java functionality. The process is similar to that used by the IETF and W3C when creating industry standards. Once a standard has been ratified, it is published as a Java Specification Request (JSR). All Java editions, not just Mobile, go through this process. Each JSR includes a reference implementation that can be licensed for a nominal fee. Companies may end up writing their own implementations, especially in the mobile space where memory and speed come at a premium. For example, BlackBerry has its own Java virtual machine (JVM) that can run JME applications and applications that use BlackBerry-specific extensions. The most important point to remember is that every implementation of the standard may vary in quality and behavior. This author has done his best to highlight known differences, but there are so many phones that knowing how each one behaves is impossible. The fractured world of JME implementations poses a sizable security issue when it comes to testing and verifying the security of any application. For truly sensitive applications, security verification may need to be performed on a device-by-device basis.

Configurations, Profiles, and JSRs

Lots of different JSRs make up JME; in fact, even using the term JME is a bit ambiguous because there are so many different ways that blocks of functionality can be put together. Intermixed through all of the standards are a couple of key ones that define configuration and profiles. Configuration standards define the minimum capabilities, such as memory and speed, of a Java device. They are tightly scoped so that they can apply to as many devices as possible, and to the user they are not very valuable on their own. Profiles extend capabilities and add functionality that targets a device for a certain use. The difference between Profiles and Configurations is similar to the difference between kernel mode and user mode. The kernel is general purpose, but only supports raw functionality that is unwieldy and difficult to write applications with. User mode APIs abstract this raw functionality and make it usable. In JME’s case, Connected Limited Device Configuration (CLDC) is the general-purpose configuration for small-memory devices, and Mobile Information Device Profile (MIDP) is the profile that introduces much of the functionality that makes JME devices useful as a mobile device development platform.

All profiles and configurations are defined within JSRs. Additional JSRs will define optional functionality for capabilities that only exist on certain devices (for example, camera or GPS functionality). The term optional JSRs refers to this group. All JSRs can be downloaded for free from the JCP website (http://jcp.org/en/home/index).

Configurations

As mentioned earlier, configurations define the minimum capabilities of the Java technology required—for example, the memory footprint and the core class libraries. Modern devices will have more power than the devices that existed when the configuration was defined, and the standards may seem to require too little. But, the common baseline gives mobile developers and manufacturers a profile they can rely upon. Configurations rarely, if ever, define optional features. Therefore, configurations are an easily achievable goal for most devices. If the requirements were too hefty, the configuration wouldn’t be adopted or would be inconsistently implemented. Connected Device Configuration (CDC) and Connected Limited Device Configuration (CLDC) are the two most commonly used JME configurations. CDC is used in devices that have more processing power than those that use CLDC, and it’s very similar to J2SE. Even though mobile devices are much more powerful today, few phones implement CDC. It just doesn’t make sense because so many applications target CLDC.

Most of the time, when mobile developers refer to JME applications, they are referring to the combination of CLDC and MIDP.

CLDC is most commonly used in mobile devices. There are two versions of CLDC: 1.0 (JSR 30) and 1.1 (JSR 139). The two standards are virtually identical, except that 1.1 adds support for floating point and removes support for serialization and reflection. The “Limited” in CLDC’s name is not a misnomer, and the configuration really requires very little from the hardware. Specifically, CLDC mandates that devices must have 160KB of nonvolatile memory, and 32KB of volatile (RAM). Most of the core Java standard library has been removed, and base classes, such as those in java.lang and java.util, have been pared down significantly. The requirements are so limited that CLDC does not even require devices to have screens or network access! This makes sense, though, because CLDC may show up in unexpected places, such as the soda machine in a hotel lobby.

CLDC defines which code the Java virtual machine must support and how code will be loaded. Applications must be bundled into JAR files and contain only valid Java code. Applications may not use reflection or Java native invocation (JNI) to call into libraries or other parts of the system. These restrictions are used to enforce code security and ensure that the device is always running a constrained set of valid Java code.

The CLDC specification does not discuss applications in much depth and instead it delegates application responsibilities to any implemented profiles. Therefore, CLDC does not define many application security features. What CLDC does do is define the basic virtual machine security mechanisms and specifies that the runtime must not load malformed or unverified Java bytecode. The mechanism the runtime uses to enforce this will be addressed later.

Version 1.0 of CLDC is still in widespread use, but lots of newer devices fully support CLDC 1.1. CLDC v1.1 was released in 2003, and the most recent maintenance version was published in 2007.

Profiles

Profiles define a group of technologies that targets a device for a specific use. Unlike configurations, which are meant to be general, profiles are much more specific and include a lot more functionality. Because profile specifications include so many features, not all of the profile’s functionality must be implemented. Where functionality is optional, it is clearly laid out using standard RFC keywords such as MUST and SHOULD.

Most profiles target one configuration, but they don’t have to. Just remember that when talking about a JME environment, you are almost always talking about a combination of a profile, a configuration, and some optional JSRs.

Mobile Information Device Profile (MIDP)

The majority of JME phones implement some version of MIDP. At publishing time, the most common version is MIDP 2.0 (MIDP2), which was released in 2002 and is deployed widely. MIDP 3.0 (MIDP3) is entering final draft phase and will likely be ratified and start appearing on devices within the next few years. MIDP2 is tied to the CLDC configuration and is never implemented on top of CDC. MIDP2 is defined by JSR-118.

MIDP makes it practical to write mobile applications by providing APIs and standards for graphics, sound, storage, networking, and security. More importantly, MIDP defines the application’s life cycle, the process of installing, updating, and removing applications. MIDP gives developers a reasonable amount of functionality and a path to get their software on to the millions of phones that exist in the marketplace. The application life cycle definition defines a security sandbox model because part of the installation process is helping users determine whether or not they should trust an application.

Profiles may extend configuration hardware requirements, and MIDP2 requires an additional 256KB of nonvolatile memory, 8KB of nonvolatile memory, and 128KB of volatile memory for the Java heap. These may seem like small numbers, but on a mobile device these numbers significantly increase the resources available to application writers.

MIDP applications are known as MIDlets. They can be bundled together into an MIDP suite for easy distribution or to share data. Suites and standalone application do not differ much in their behaviors.

MIDP 2.1

MIDP 2.1 is a small but important update to the MIDP2 specification and resolves many of the ambiguities found in the original MIDP2 specification. Specifically, MIDP 2.1 enables developers to require CLDC 1.1 or 1.0 at installation; requires implementations support HTTP, HTTPS, and Secure Sockets; and defines protection domains that manufacturers can implement. Phones don’t always list themselves as MIDP 2.1 compatible, even though they are, and will simply show as MIDP2 devices.

MIDP 3.0

MIDP 3.0 adds tons of functionality to MIDP and, to accommodate these new features, increases the memory requirements on implemented devices. The specification is much more complex, and most of the security features focus on removing the barriers between applications that made MIDP2 a successful security endeavor. Some of the big changes in MIDP 3.0: not constrained to CLDC or CDC, support for shared libraries (“liblets”), permissions model more similar to J2SE, multiple MIDlet suite signers, and expanded memory capabilities. It will be interesting to see how it plays out in the marketplace, but this author believes that MIDP 3.0 will have a weaker security architecture that is more difficult to model and to understand.

Optional Packages

There are JSRs that define functionality that may not exist on all mobile devices. For example, not all devices have a camera, so implementing the camera JSR might not make sense. Even if the device has a camera, the manufacturer or carrier may not want applications using it and won’t implement the JSR. Like RFCs, some JSRs are only as good as the number of supporters and implementations and some JSRs, such as JSR-0179, the PDA (a.k.a. Contacts) JSR, are so popular that they exist on almost every phone.

Remember that a given device may not implement the same set of JSRs as other devices. Also, individual manufacturers may not completely implement the JSR. When reviewing any device, make sure to check out the manufacturer’s website and keep your eye out for papers that describe how half-hearted a given implementation is. For example, at the time of this writing, Samsung’s file implementation did not support hidden files. These aren’t a security mechanism, but subtle differences such as these make it difficult to have confidence in individual devices.

Development and Security Testing

Because JME is a Java standard, developers and security testers benefit from being able to use roughly the same toolchain as used for standard Java development. If you have a favorite Java development environment, it may be worth sticking with it. The only unique development requirements are a device emulator and the CLDC and MIDP libraries. The compiler is identical. Sun freely provides the Java ME SDK (the SDK), which includes an emulator, emulator images, class libraries, samples, and a simple development environment. Each device manufacturer or operator may also distribute their own version of the toolkit, which contains additional emulator images and libraries. These custom toolkits are generally only required when targeting specific devices.

JME development tools for CLDC, CDC, and MIDP applications used to be distributed independently. Now every mobile configuration and profile is bundled together in the SDK and available as one download.

This author’s preferred development environment is NetBeans with the NetBeans Mobility Pack. It seamlessly integrates with the SDK and requires very little configuration to get things up and running. Other developers prefer Eclipse (www.eclipse.org) with the Mobile Tools for Eclipse plug-in installed (www.eclipse.org/dsdp/mtj/). Unfortunately, some of the JME profiling tools are not yet integrated into Eclipse. Throughout this chapter, screenshots and instructional text will refer to development using the free NetBeans editor and the Java ME SDK. At the time of this writing, the most recently released version of the SDK is 3.0.

To find manufacturer custom SDKs, visit the manufacturer’s website. If you’re testing a device on a specific carrier, that carrier may offer unique emulator images that are customized and differ from the manufacturer’s standard images. Almost everyone requires registration, but the APIs themselves are almost always free. Use the carrier specific packages if they exist because many operators, especially in North America, change security settings, add software, or otherwise affect the device’s behavior. Here are some manufacturer and carrier download sites:

image    Sun Mobile Development Network (http://java.sun.com/javame/index.jsp) is the main JME site and the distribution point for the SDK.

image    Samsung Mobile Innovator (http://innovator.samsungmobile.com/) provides emulator images and articles specific to Samsung development.

image    Sony Ericsson Developer World (http://developer.sonyericsson.com/site/global/home/p_home.jsp) provides documentation and emulator images for Sony Ericsson development.

image    BlackBerry Developer Zone (http://na.blackberry.com/eng/developers/) is a comprehensive site for BlackBerry developers. For more information, see Chapter 5.

image    Motorola MotoDev (http://developer.motorola.com) is Motorola’s developer site.

Configuring a Development Environment and Installing New Platforms

Follow these steps to install NetBeans and the JME SDK 3.0 on Windows:

1. Download and install version 5 or 6 of the Java Development Kit (JDK). This is required to run NetBeans.

2. Download the SDK from Sun’s website (http://java.sun.com/javame/downloads/sdk30.jsp). Installing Sun’s SDK is not strictly required because a version is included with NetBeans. However, installing the latest version is always a good idea.

3. Run the downloaded executable file (sun_java_me_sdk-3_0-win.exe).

4. Click through the installer and read the options to make sure they work for you. By default, the SDK will be installed to Java_ME_platform_SDK_3.0.

5. Download NetBeans with the Mobility Pack (www.netbeans.org/downloads/index.html). Make sure to select a version that supports Java ME development. Alternatively, you could use the pared-down version of NetBeans that comes with Sun’s SDK, but it does not have a debugger, which is an essential security testing tool.

6. After installing NetBeans, make sure to install any updates. There have been security vulnerabilities in the JME SDK before.

7. Once NetBeans has been installed, start the IDE by clicking on the NetBeans IDE icon in the Start menu. See Figure 6-1 for the screenshot.

8. You will now have to tell NetBeans about the new version of the JME SDK. After you do this, NetBeans will be able to compile using those libraries and use the emulator images. This is the same process used when downloading and installing operator and manufacturer SDKs.

image


Figure 6-1 NetBeans JME development environment

9. Within NetBeans, open the Tools menu and select Java Platforms.

10. Click Add Platform to add a new Java platform.

11. Select the Java ME MIDP Platform Emulator radio button and click Next.

12. NetBeans should find the third-edition SDK automatically. If it doesn’t, navigate to the folder where the SDK was installed (for example, c:JAVA_ME_platform_SDK_3.0).

13. Click Okay to install the platform.

Emulator and Data Execution Protection

If you are running on a Windows system with Data Execution Protection (DEP) enabled, the emulator may crash immediately because it is executing code from operating system memory pages not marked as executable. Here’s how to fix this:

1. In Windows, open the Advanced System Settings dialog by right-clicking on Computer and choosing Properties.

2. Select the Advanced tab and click Performance Options.

3. Choose the Data Execution Prevention tab.

4. Add the emulator runtime to the DEP excepted programs list (C:Java_ME_platform_SDK_3.0 untimescldc-hi-javafxin runMidlet.exe).

Each wireless toolkit names this executable slightly differently. To determine which executable is crashing, review the system crash report. Be careful not to leave nonspecialized applications such as java.exe in the exclusion list because this does decrease your machine’s anti-exploitation protections.

14. To test everything out, import one of the sample projects by clicking File | New Project. Select the Java ME category, choose the Mobile Projects with Existing MIDP Sources project type, and navigate to one of the samples installed with the JME SDK. The Demos application is a good starting point (C:Java_ME_platform_SDK_3.0appsDemos).

15. Once the project is imported, click the green Run arrow in the toolbar to actually run the project. If all has gone well, an emulator should pop up and the application should be started.

Emulator

The emulator lets you simulate real-world devices without having the actual hardware. For JME, this is especially invaluable because there are thousands of different models in the marketplace. Thankfully, the SDK contains emulator images for the most popular devices and form factors. These images are a great place to start when you’re first poking around with JME.

One advantage of JME over other shared mobile platforms (such as Windows Mobile) is that the application and platform security behavior is specified by MIDP and CLDC. Therefore, the emulator’s behavior should be relatively consistent with the behavior of real devices. However, some manufacturers and carriers do tweak the rules, so always make sure to test on the target device.

Configuring the Emulator

The default SDK emulators support many of the newer JSRs that may not be available on production devices. Also, the emulators don’t enforce security by default, which makes it impossible to test the security system. Before using the emulators, make sure to enable security and add or remove JSRs to match your testing target. This is especially handy when an emulator is not easily available from the device manufacturer.

Adding and Removing JSRs

To add or remove support for optional JSRs in NetBeans, do the following:

1. Open the project’s properties by right-clicking on the project and selecting Properties.

2. Select the Platform category from the right-side tree menu. This property page lets you tweak individual settings on the device.

3. Disable or enable individual JSRs by finding their API set and clicking the check box. Unfortunately, the actual JSR number is not provided in this list.

Enabling Security

The MIDP security specification groups access to a device into permission domains. By default, applications written in NetBeans will run in the Maximum permission domain, which should never happen in the real world and won’t exhibit close to the same security behavior as it will on an actual device. To actually test the security of your application, force the application to run in a restricted permission domain. This way, you can see how the application will respond on a real device. Of course, individual devices may behave differently, and any real testing should be performed with the appropriate target toolkit and certificates.

To cause an application to run in a particular permission domain when being deployed from NetBeans, do the following:

1. Open the project’s properties by right-clicking on the project and selecting Properties.

2. Select the Running category from the right-side tree menu.

3. Check the Specify the Security Domain check box and select a permission domain. For this exercise, choose Minimum.

4. Run the Demos project. Notice that the application won’t actually start. This is because the project uses the HTTP and HTTPS library and is not being signed by NetBeans, which causes the device to block the application from running.

Reverse Engineering and Debugging

Reverse engineering is a critical skill for almost every penetration tester and security engineer. Through reverse engineering, you can look at the hidden secrets of the platform and applications to find out how they really work and where the security flaws are. The goal is not to understand every instruction, but rather to understand what data the application is consuming and producing. After all, almost all security vulnerabilities result from errors when producing and consuming data.

Just as we benefit from being able to use the same development toolchain for JME, we benefit by being able to use the same debugging and reverse-engineering toolchain. Because JME code is Java, almost all of the standard Java security tools work, and there are even a couple of JME-specific tools that make reverse engineering and debugging easier.

Disassembly and Decompilation

Java application classes are compiled into Java “.class” files. These files contain Java bytecode, which is a machine-independent set of instructions for the Java virtual machine to execute. Machine-independent bytecode is what allows Java to run everywhere from ATMs to vending machines. When developers want to run Java on a new hardware platform or operating system, they create a new version of the Java virtual machine for that platform. If this virtual machine properly conforms to the Java specification, it will be able to execute Java bytecode without problems. For security reasons, Java mandates that bytecode be easily inspected at runtime. To support this, Java application bytecode must follow some conventions.

Disassembling x86 assembly code is a very painful process. Java instructions (a.k.a. opcodes) are each one byte in size. Depending on the opcode, there may or may not be instruction operands. Whether or not operands exist doesn’t matter. Every instruction will always be a predictable size. This quality is very important during runtime code inspection because it allows the virtual machine to easily traverse the application in a predictable manner. Additionally, instructions are not allowed to jump to invalid memory locations, use uninitialized data, or access private methods and data (see http://en.wikipedia.org/wiki/Java_virtual_machine). Contrast this to x86 programs, where these methods are often used to hide an application’s true behavior.

Just like the runtime does, reverse engineers can take advantage of the consistent size and variable rules to convert the program from its compiled form back into instructions—a process known as disassembly. Java is easy to disassemble—that is, it can be “decompiled” and turned back into Java source code. The results aren’t always pretty, but it is much easier to read messy Java source code than to read Java virtual machine opcodes.

Decompiling Java Applications

There are many Java decompilers to choose from. This author prefers the classic Java application decompiler (Jad). Jad was written in 2001 by Pavel Kouznetsov. It has not been changed since then, but still works remarkably well. To install Jad, download your desktop operating system’s version from the distribution source (http://www.varaneckas.com/jad) and decompress it to a folder.

To decompile code, follow these steps:

1. JME applications come packaged as Java archive files (JAR). Within a JAR file can be lots of different file types, but we are interested in the ones that contain code. These are the “.class” files. To extract them from the JAR, simply change the JAR file’s extension to .zip and use your favorite extraction utility to extract the “.class” files. For this exercise, extract the files to the root folder e_appcode. Keep the directory structure intact when you extract the files.

2. Create the folder e_appsrc. This is where the decompiled source files will go.

3. Run the following command from the e_app directory:

jad -o -r -sjava -dsrc code/**/*.class

4. Jad will decompile the application and generate the resultant Java files in the e_appsrc directory. The -r option is for recursive directory travel, and explicit output path (code/**/*.class) instructs Jad to reconstruct the packages and directories as they appeared in the input.

If you want to make a modification to the decompiled code and then recompile the application, you may be able to do so by loading the project into NetBeans. This doesn’t always work because the decompilation process is imperfect. For certain applications, some decompilers work better than others. This author has had limited success with JD-GUI (http://java.decompiler.free.fr/) and the DJ Java Decompiler (http://www.neshkov.com/dj.html).

Obfuscation

A small hurdle for reverse engineers is that many Java applications are intentionally made confusing through obfuscation. This process intentionally changes instruction paths and removes symbolic information, such as class and method names, from the compiled application. For example, an obfuscator renames the class com.isecpartners.test.MyApplication as a.a.a.C. This is not always done to confuse reverse engineers. Shorter Java class names and compressed code save memory, an important commodity on mobile devices. There are many obfuscators available, but one of the most common is ProGuard (http://proguard.sourceforge.net/). It is freely available and easy to use. Both NetBeans and the SDK bundle it with their software. For more information on obfuscators and how they work, visit the RCE forums (http://www.woodmann.com/forum/index.php).

Recovering original symbolic names after obfuscation is impossible. When reviewing obfuscated applications, look for references to core platform classes and APIs. References to these cannot be obfuscated. Reviewing between method calls can give you good insight into how the application works and is much more efficient than attempting to piece the application’s obfuscated code back together. At the very least, you will know which parts are important to analyze.

The following code is a sample decompilation of an obfuscated method. Notice that all symbolic information has been lost, so the decompiler has used alphabetic letters for class, method, variable, and parameter names. The mathematical operations are not a result of the obfuscation process.

protected final void I(int ai[], int i, int j, int k, int l, int i1, int j1)

{
    int k1 = (F >> 15) - 36;
    int l1 = k1 - 32;
    int i2 = 512;
    if(l1 > 64)
        i2 = 32768 / l1;
    int j2 = l1;
    if(j2 > j1)
        j2 = j1;
    for(int k2 = l; k2 < j2; k2++)
        I(ai, i, j, k, k2, i1, k2 + 1,
          C(0xff3399ff, 0xff005995, (l1 - k2) * i2));

Hiding Cryptographic Secrets

Developers often use obfuscation to hide cryptographic keys and other secrets in their applications. While tempting, this is a fool’s errand. Obfuscation will slow reverse engineers down, but will never stop them. Even obfuscated code must be executed by the Java virtual machine and therefore must always be reversible.

Debugging Applications

NetBeans includes a full source debugger for stepping through application source code on real devices or on emulators. Unfortunately, you are not able to single-step through Java disassembly. To debug applications without source code, run the application through a decompiler, build it, and then debug it using NetBeans. Unfortunately, this is easier said than done because getting decompiled applications to compile again and work properly can be a challenge.

NetBeans communicates with the JVM on the machine using the KVM Debug Wire Protocol (KDWP). A specification for this protocol is available free from Sun (http://java.sun.com/javame/reference/docs/kdwp/KDWP.pdf). KDWP enables NetBeans to communicate directly with the JVM running on either the emulator or a real device. The protocol runs over a socket connection to the actual device. Not all devices are KDWP enabled, and many manufacturers require that you purchase KDWP devices directly from them. The KDWP can be used for custom debugging and reverse-engineering tasks where custom debug tools are required.

To debug an application in NetBeans, load the application project, ensure that it has no compile errors, and click the Debug Main Project button in the toolbar. This will deploy the project to the appropriate device and start the application. Breakpoints can be set up by pressing CTRL-F8 on the target source code line.

Network Monitor

Decompiling and debugging are effective tools for reverse-engineering applications, but they can be time consuming and are not always the most efficient way to approach a reversing problem. Monitoring input and output provides great insight into an application’s behavior and is significantly easier. The SDK includes a network monitor for monitoring network connections being made by a device or emulator. The best part is that it doesn’t just monitor HTTP or TCP traffic, it also monitors SMS traffic and shows SSL in cleartext.

Unlike debugging, which is enabled per invocation, network monitor logging is a configuration property of the emulator. To enable the network monitor, open a command prompt and run the following command:

c:Java_ME_platform_SDK_3.0in etmon-console.exe

This tool connects to running JME emulators and starts recording network traffic. When the netmon-console detects a new emulator, it logs a message (Output file: C:Usersob etmon-9.nms) to the console. This file contains the network capture. You can also collect the capture from within NetBeans by changing the emulator’s configuration and selecting Network Monitor.

To view the network capture, follow these steps:

1. Open the JME 3.0 SDK development environment. NetBeans does not include an option for opening saved network capture files.

2. Select Tools | Load Network Monitor Snapshot.

3. Browse to the file containing the snapshot (for example, C:Usersob etmon-9.nms).

4. The snapshot will load in Network Monitor and display a view similar to Figure 6-2.

Now the fun begins. The topmost pane contains the list of network connections made by or to the application. The Protocol field lists the protocol used (arrows pointing to the right indicate the client initiated the connection; arrows pointing to the left are caused by server-generated traffic). You can dig deeper into individual packets by clicking on the connection and exploring the Hex View panels.

The Network Monitor is a great tool and has vastly improved in version 3.0 of the SDK. Use it when reverse engineering for its ease of setup and the depth of information it provides.

Profiler

Another useful application included with the SDK is the Application Profiler. Developers use this tool to help them find performance problems—a real concern for mobile applications. The Profiler records how much time is spent in each application method. This information is valuable to reverse engineers for finding the core methods of an application. It is especially useful when the application is obfuscated and you are not sure at which point to begin analysis.

Like the Network Monitor, the Profiler is more cleanly integrated into the newest version of the JME SDK than it is in NetBeans. There are some downsides: The profiler uses lots of memory and will significantly slow down your application.

image


Figure 6-2 Network Monitor displaying UDP and HTTP traffic

It also does not provide a huge amount of detail. After all, it was built for performance analysis with well-understood applications, not for hackers.

Follow these steps to capture data using the Profiler:

1. Open the JME SDK and load your source project. Make sure it compiles.

2. Right-click on the emulator profile in the Device Manager pane and select Properties.

3. Choose Enable Profiler. Record the Profiler filename listed in the properties panel (the filename will have the extension .prof).

4. Start the project by clicking the Run arrow.

5. Exercise the application. The goal is to figure out which code blocks are executed the most often and which system APIs are being called.

6. Terminate the application and close the emulator.

7. Open the Profiler log by clicking on Tools | Import JME SDK Snapshot.

image


Figure 6-3 Profiler view after running the NetworkDemo application

8. Browse to the stored .prof file and click Okay.

9. The result will appear similar to Figure 6-3. The call graph can be expanded by clicking the plus arrow.

Code Security

All JME code is written in Java, and Java is a memory managed language that prevents buffer and integer overflows and direct manipulation of memory and the hardware. The virtual machine makes this security magic possible by verifying every instruction before execution and ensuring that all application code handles memory and objects safely. Not having to worry about memory-related security issues is a real boon to developers, but it doesn’t mean that they are free and clear. Application code can still use the network and local storage insecurely, and the virtual machine implementation itself might have problems that attackers could exploit to compromise devices. For example, Adam Gowdiak reported avulnerability in the Kilobyte Virtual Machine’s verifier that an application could use to escape the sandbox (http://secunia.com/advisories/12945/). The risk of a JVM error pales in comparison to the risk of writing every JME application in an unmanaged language such as C.

CLDC Security

The CLDC JSR specifies that JVMs implementing the CLDC configuration must only load and execute valid Java bytecode. In addition, CLDC JVMs do not support all of Java’s language features. Specifically, the CLDC 1.1 JSR says that CLDC must ensure the following:

image    Class files must be properly verified and the Java bytecode well formed. All code branches must follow predictable paths and jump to controlled memory addresses. Code verification ensures that the application is not able to execute illegal instructions.

image    Applications cannot load custom class loaders or classes of their choosing. If attackers could load their own classes, they could pull in application code without the user’s knowledge.

image    The API set exposed to applications is predefined. Therefore, applications cannot use Java reflection to dynamically load classes or access private methods. By forcing a predefined set, device manufacturers and carriers know which platform APIs are exposed and how the application will be able to access the hardware. Device manufacturers and carriers can always add to the protected set if they want to expose device model-specific functionality (for example, the camera or a digital compass).

image    Native functionality is prohibited. Java native invocation (JNI) is a technology used to bridge between native code (such as C/C++) and managed Java code. Native code executes outside of the JVM and cannot be monitored. Therefore, JME applications must be prevented from using JNI and including native extension libraries.

image    Applications cannot extend classes in the java.*, javax.microedition.*, and other manufacturer-specific packages. If malicious applications were allowed to overload sensitive system classes, they might be able to take advantage of polymorphism and force system APIs to execute attacker-supplied code when calling object methods.

image    All classes must come from the same JAR file. This requirement prevents applications from loading and using classes from other applications that may be installed on a device. This restriction may change when libraries are introduced as part of MIDP 3.0.

These restrictions aim to stop applications from running Java code that cannot be managed or accesses the hardware in unexpected way. MIDP relies on this infrastructure to build a higher level application sandbox, which will be discussed later in this chapter. To enforce these restrictions, CLDC performs “class file verification” and inspects the Java bytecode to ensure that all variables are initialized, the actual instructions are legitimate, and that only valid types are used.

Pre-verification

To have an impact, the CLDC JVM security rules must actually be enforced when the code is installed and executed on the device. Pre-verification is the process that evaluates application code and creates markings that will be used by the JVM during installation or runtime verification. All Java virtual machines perform some sort of verification process, but only JME performs the verification process at compilation time—hence, the name per-verification. CLDC doesn’t actually require pre-verification to be used, but on mobile devices it is preferred over standard verification, which consumes large amounts of system resources.

Pre-verification works by scanning the application’s bytecode and generating a series of “StackMap” attributes for each code item in an application. The StackMap includes information about the local variable types being used by each basic block of the application. Once the StackMap attributes are generated, they are inserted into the attribute section of each code attribute in the application. When the application is installed onto the device, the JVM performs a linear scan of the application’s bytecode and compares references and object types to the information contained in the StackMap. The device refuses to load the application if any part of the comparison fails.

Storing StackMap entries does marginally increase the size of applications, but enables the verification algorithm to execute in linear time and with predictable resource use—important qualities for mobile devices. The algorithm is resistant to malicious tampering or manufacturing of StackMap entries, and an invalid or incomplete StackMap will cause the application to be rejected when a user loads it onto a device.

Use preverify.exe to perform pre-verification of your applications. Sun’s official reference implementation is included with the SDK and NetBeans, and both will automatically perform pre-verification as part of the build process. The ProGuard obfuscation toolset also includes an alternate implementation of the pre-verifier. To learn more about pre-verification, see Appendix 1 of the CLDC 1.1. specification.

Application Packaging and Distribution

CLDC requires that all JME application code be packaged into Java archive files. JAR is a compressed file format very similar to ZIP. Each application JAR has an associated Java Application Descriptor (JAD). The JAD file is a simple text file with a listing of key/value pairs that describe certain properties of the application (for example, the application’s author and the location of the developer’s website). The combination of the JAR and the JAD is what actually composes a JME application. This differs from standard Java applications, which do not have JAD files and keep their metadata in the JAR file. JME JARs still have metadata, but they can grow to be quite large and be prohibitive to download over slow and costly cellular links. By putting the metadata in the JAD file, which is much smaller than the JAR, mobile devices can present the user with a choice before downloading the entire application.

More on JAD Files

JAD files are an important part of the MIDP application life cycle and contain application signatures, permission listings, and other important security information. Each line in a JAD file consists of an attribute name and attribute value. A sample JAD follows:

MIDlet-1: iSEC Partners Maps, , com.isecpartners.jme.iSECNavigator
MIDlet-Jar-URL:
http://www.isecpartners.com/applications/v1/isecnav.jar
MIDlet-Jar-Size: 6479
MIDlet-Name: iSEC Maps
MIDlet-Permissions: javax.microedition.io.Connector.http
MIDlet-Icon: icon16x16.png
MIDlet-Version: 1.0.2
MIDlet-Vendor: iSEC Partners
MIDlet-Install-Notify:
http://www.isecpartners.com/applications/v1/cust

This JAD file provides the name of the application (iSEC Maps), the vendor (iSEC Partners), and the location of the actual JAR file. After the JAD is downloaded, this information will be shown to the user so they can decide whether or not to install the application. Also note that the JAD is requesting the javax.microedition.io.Connector.http permission by using the MIDlet-Permissions attribute. Phones could use this as part of a permission UI at installation time.

Most JAD attributes are defined in the MIDP JSR and the optional JAD JSRs. Vendors may define additional attributes that are unique to their device. Samsung, for example, defines the MIDlet-Touch-Support option for indicating that your application should be displayed full screen. None, or very few, of the vendor-specific options have an actual impact on security.

The information in the JAD can be duplicated in the application manifest and the JAD must match the manifest exactly. In MIDP 1.0, JAD information took priority over MIDP information. MIDP 2.0 requires the match. Otherwise, the JAD could claim the application has different metadata than it actually does. Other security vulnerabilities related to JAD file parsing have also been reported. For example, Ollie Whitehouse from Symantec discovered that embedding character return characters in a JAD can cause some phones to display incorrect information on the installation screen.

Signatures

Devices uses code signatures to verify the integrity and origin of applications and then use this information to decide how much to trust a given application. Standard Java applications also use signatures for this purpose, but the signature is embedded in the JAR file. JME signatures are attached to the JAD, and the rules are slightly different: Every application can only have one signer, and any changes to the JAR file invalidate the application’s signature.

Two attributes are used to express JAD signatures: MIDlet-Certificate-X-Y and MIDlet-Jar-RSA-SHA1. The MIDlet-Certificate attribute describes the certificate chain. X is the chain number, and Y is the certificate’s position in the chain. A value of 1 for Y denotes the leaf certificate. The MIDlet-Jar-RSA-SHA1 is an RSA-encrypted SHA-1 hash of the JAR file and will be verified against the certificate described in the JAD and the device’s certificate store. Both entries are Base-64 encoded. Here are sample JAD signature nodes:

MIDlet-Certificate-1-1:
MIICGTCCAYKgAwIBAgIESjmCFjANBgkqhkiG9w0BAQUFADBRMQwwCgYDVQQGEwNVU0ExC
zAJBgNVBAgTAkNBMQ8wDQYDVQQKEwZpc2Vjb3UxDTALBgNVBAsTBGlzZWMxFDASBgNVBA
MMC2lzZWNfc2lnbmVyMB4XDTA5MDYxNzIzNTM1OFoXDTA5MTIxNDIzNTM1OFowUTEMMAo
GA1UEBhMDVVNBMQswCQYDVQQIEwJDQTEPMA0GA1UEChMGaXNlY291MQ0wCwYDVQQLEwRp
c2VjMRQwEgYDVQQDDAtpc2VjX3NpZ25lcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCg
YEAiTLVnE4/EFFvJORxa0/wFYi8/QZfufiu4QGFdB4jJchKalxDe1UoqorbEDiowcUw7M
AFoVR6yKOeHRZVTuKU4uq4fti/XcmwyML7loHw39Pd097384PK745DGUirDCqf6Dak1Tq
NG9EjicQKXDNaAd98xaEJGpeqpOHhN5K0LokCAwEAATANBgkqhkiG9w0BAQUFAAOBgQA8
IxC1OLw86yt8U2u9ufogaD7comUZyg+USjI0pkdaUVTRY+Xd+QCNh6PJpwItH8ImuioRs
elLJH4Tel7KRrXNchJYuoDF+K4ajpc62dpfpIB0FlPhuXFMD5z0E3Mkd4cfWVUIGvE/ZB
7xVBNtZEmINIQjvtKcZG6v6izO5uxilw==

MIDlet-Jar-RSA-SHA1:
hSd7tIqqIh+Aw08DUYvc2OtoMP5DiMsFZbt0M/cjlkaQfvZaEGy061KlvwSSoNF9kPhLT
G1scZnN5j597d5xGuk+WkOzLhUlKwNtZYEDRPnwsiOw56qhvOw2yNQH2gF+Cj9VR6dWL5
1MvnFk8PJeU5Q2Uey0NeROFlQ6F/i1Shc=

Obtaining a Signing Key

To generate signatures, you will need a certificate and a public/private keypair. These can be purchased from different code-signing Certification Authorities (CA). Despite everyone’s best intentions, getting a signing key that works on all devices and all networks around the world is very difficult. Each carrier has a unique application approval process and rules; often these rules are enforced by requiring code to be signed with a certificate from a particular CA. Sun recently introduced the Java Verified program, which seeks to ease developers’ pain and make the JME ecosystem more consistent with standard CAs and testing procedures. It is not clear yet if it is going to be a success. To find out more information, visit http://javaverified.com/. For a more traditional approach, visit the mobile development website of your target carrier.

Of course, paying for a certificate is no fun if you just want to learn about device security. Therefore, feel free to generate test certificates using the Java SE keytool.exe tool. These self-signed certificates can be used to sign applications and deploy them to emulators. These signatures will not be accepted by real-world devices. Follow these steps to create a key for signing:

1. Install the Java Runtime Environment (JRE). If you have been running NetBeans or any Java applications, this will already be installed. If not, download the JRE from www.java.com.

2. Open a command prompt (Start | Run and type cmd.exe).

3. Change to the JRE bin directory (for example, C:Program FilesJavajdk1.6.0_13jrein).

4. Generate a keypair by running the following command:

keytool -genkey -keyalg RSA -keysize 1024 -alias SigKey
-keystore c:dropkeystore

This command will create a new key with the alias “SigKey” and a new keystore file at c:dropkeystore. During the key-creation process, you will be asked for some information. Because this is a self-signed certificate, feel free to enter whatever you wish. Also make sure to specify a secure password for the keystore. This password is used to encrypt the keystore and ensure that no one else can access it.

Signing JME Applications

Now that you have a signing key, it is possible to actually sign JME applications. To do so, use the jadtool.exe program that comes with the JME SDK. This tool takes a JAD and a JAR as input, calculates the signature, and then updates the JAD for you. To generate a signature, follow these steps:

1. Install the JME SDK. These instructions assume that you have installed version 3.0.

2. Open a command prompt (Start | Run and type cmd.exe).

3. Change to the JME SDK bin directory (for example, C:Java_ME_platform_SDK_3.0in).

4. Run the jadtool and add the public key of your signing certificate into MyApp’s JAD file using the following command:

jadtool -addcert -alias SigKey -keystore c:dropkeystore
-inputjad myapp.jad -outputjad myapp-key.jad

5. This command refers to the key that was created earlier, so make sure that the key alias and keystore file path match up. After running this command, you can open the generated myapp-key.jad file and see that the MIDlet-Certificate-1-1 attribute has been added.

6. Now sign the application with this command:

jadtool -addjarsig -alias SigKey -keystore c:dropkeystore
-inputjad myapp-cert.jad -outputjad myapp-signed.jad
-storepass password -keypass password -jarfile myapp.jar

7. You will need to substitute the appropriate password values for the storepass and keypass parameters and make sure that the filenames point to your actual application.

Both keystore management and signing can be performed using the NetBeans IDE. To manage keystores, use Tools | Keystore. To control signing, right-click on a project, open the Properties panel, and select the BuildSigning category.

Distribution

How JME applications are distributed varies by device and network. Almost every carrier has some sort of application store that is accessible via the phone. However, there are many other websites that offer JME applications, and unlike with the iPhone, users are not locked in to getting applications from just their carrier. Naturally, this increases the risk of users being tricked into installing malicious applications from questionable sources.

Installation

All MIDP 2.0 devices must support Over-The-Air (OTA) application installation. Of course, the implementation will vary between vendors, but they all follow the same pattern. To install an application OTA, the user visits a website and downloads the JAD file. The device parses the file and displays the application’s information to the user. At this point, the user must be presented with an option of canceling installation. If the user chooses to proceed, the device will download the application’s JAR file from the URL specified in the JAD file and install the application into the local package manager.

Note that both the JAD and JAR files are downloaded using the cleartext and non-integrity-protected HTTP protocol. The use of signatures mitigates the risk that an attacker could modify the application as it is downloaded. Of course, the attacker could just remove the signature, but that would hopefully cause the user to not accept the application’s installation or cause the device to run the application with reduced privileges.

Permissions and User Controls

The MIDP security system is clearly described in the MIDP specification and should behave similarly on all devices. In the real world, many phones and carriers do behave slightly differently, and this is one of the primary challenges of JME development.

Each application is granted a set of permissions that allows the application to use sensitive phone functionality (for example, GPS or the cellular network). The permissions are defined using fully qualified package names. Earlier in the sample JAD file, you saw the permission javax.microedition.io.Connector.http. Many of these permissions are defined in the MIDP JSR, but Optional JSRs may define permissions as well. The Location Services JSR, for example, defines permissions that are required in order to access location data. Applications are isolated from each other almost completely, with small exceptions made for applications signed with the same signature.

Not all applications may be authorized to use all permissions because not all applications are equally trusted. JME applications trust is determined by examining the application’s origin and integrity. Most devices use X.509 certificates and rely on the certificate’s common name (CN) and issuing CA as proof of origin. The signature in the JAD file binds the origin to the application and ensures that the application’s code has not been tampered with since it was signed.

After its identity is verified, the JVM assigns the application to a protection domain. These are groups of permissions that allow access to certain classes and functionality. A MIDlet suite may only be allowed to access one protection domain at a time, although MIDP 3.0 may change this. Frankly, having more than one set of permissions applying to an application at one time may be confusing. It will be interesting to see how that problem is resolved.

The protection domains are not standard across manufacturers and carriers, but with MIDP 2.1 there was an effort to standardize protection domains for GSM/UMTS phones. This effort produced the following domains, as detailed in the MIDP 2.1 specification:

image    Unidentified Third Party protection domain (a.k.a. untrusted) All unsigned code is placed in this domain. Irrespective of the MIDP 2.1 specification, all phones must have an untrusted domain and support running unsigned code.

image    Identified Third Party protection domain Code that has been signed with a certificate issued by a CA that the operator or manufacturer trusts. Code in this domain may be able to use the network or advanced phone functionality without user prompting.

image    Operator protection domain A highly trusted domain restricted to code signed by an operator-owned certificate. Generally allowed to do anything on the device.

image    Manufacturer protection domain A highly trusted domain restricted to code signed by a manufacturer-owned certificate. Generally allowed to do anything on the device.

Not all carriers follow these specifications exactly, but any changes tend to err on the more restrictive side. T-Mobile North America, for example, doesn’t include an Identified Third Party domain. Therefore, applications signed with popular JME signing certificates aren’t allowed to run on T-Mobile’s phones.

The untrusted protection domain is a special case and must exist on all MIDP phones. Applications without signatures are automatically placed in this domain, and for many applications that arrangement works perfectly well. Games, for example, don’t need to access much of the phones functionality, and the MIDP API set is intentionally designed to allow them to run without requiring signatures or special permissions. This means there are a lot of unsigned JME applications out there.

Interestingly, if an application has a signature that is either unknown or corrupted, the application will not be placed into the untrusted zone. Instead, the application will simply be rejected. This causes problems for developers with applications signed with a certificate that is recognized on one network but not on another. Just like getting into an exclusive night club, getting into the desired domain on certain carriers can be a combination of luck and skill.

The JVM enforces all permissions at runtime, and if an application attempts to access an API without permission, a dialog will be shown to the user asking for permission (see Figure 6-4 for an example of this). Alternatively, the device could fail the API call by throwing a java.lang.SecurityException. The MIDP specification contains a list of which APIs require prompting, but manufacturers can always choose to completely block access. Two sample APIs that require prompting are javax.microedition.io.HttpConnection and javax.microedition.io.HttpsConnection. These APIs are considered sensitive because they allow access to the network.

image


Figure 6-4 Device prompting for network access

Devices may adopt different prompting modes that control how often the user is asked for permission. The MIDP specification outlines three models: oneshot, session, and blanket. These models are respectively valid for one API use, one execution lifetime of an application, and for the entire lifetime of an application. Most devices use the oneshot mode because it is the most annoying and will force the developer to sign their code. Granting a permission is granting the application access to an entire API. Permissions are not necessarily provided on a per-item basis. For example, MIDP is asking “Do you want this application to be able to manipulate contacts?” It is not asking, “Do you want this application to be able to manipulate Nancy Jones’s contact?”

Overall, the MIDP permission system does well at controlling how applications are allowed to interact with each other and with the system, and there have been few reports of JME malware. The system is not without its downsides—the prompts can be confusing to users, and getting code signed properly can be difficult due to the way each carrier handles security.

Data Access

Mobile devices are nothing without the ability to access data from different sources. Normally, the Java.io and Java.net packages contain Java’s data access functionality. However, including all of these classes in JME would require too much memory. So JME uses the CLDC generic connector API, which is a framework for defining read/write operations on arbitrary stream data. By having one API, the number of classes in the standard API is kept down.

The connector API references data sources using standard URIs—for example, www.isecpartners.com for accessing the iSEC Partners website and “comm:0; baudrate=9600” for using the serial port. There are also connectors for accessing sockets, Bluetooth, and HTTPS. Not all connector exist on all devices, because not all devices support the same hardware. Three permission modes are defined when using the connector API: READ_ONLY, WRITE_ONLY, and READ_WRITE. The semantics of these modes change depending on the connector being used.

Network Access

All MIDP 2.1 platforms must support HTTP, HTTPS, Socket, and Secure Socket connectors. By default, untrusted applications are not allowed to use the network without prompting. On some carriers (but not all), signed applications can use the network silently. To learn more about the connector API, review the CLDC 1.1 specification and the javax.microedition.io.Connector documentation. Both describe the reasoning behind the generic connection framework and how to use it.

Record Stores

JME devices are normally resource constrained and may not have file systems. However, every device supports MIDP2 Record Management Store (RMS) databases. These can be used for persistently storing arbitrary blobs of binary data. For example, a geo-caching application may store the last location it recorded. Because they persist data, they are particularly interesting to security review. Thankfully, MIDP does the right thing—RMS databases are, by default, only accessible to the MIDlet suite that creates them. (Note that I said “by default.”)

RMS databases can be shared between applications if the AUTHMODE_ANY flag is specified at RMS creation time. This publicizes the database to any other application that knows the package and RMS database name (for example, com.isecpartners.testapp.RMS_STORE). The sharing is limited to the named record store and does not affect any of the application’s private record stores.

Sharing is not recommended for both privacy and security reasons, because users aren’t able to control which applications can access shared RMS databases. Even untrusted MIDlets can read or update shared RMS databases. Additionally, RMS doesn’t synchronize access to RMS records, so corruption is highly likely. If you’re planning on sharing any data, make sure the user is properly informed before doing so and be aware that sharing does not work on all phones. BlackBerry, for example, requires applications to use a more secure proprietary sharing mechanism.

Cryptography

By default, JME storage is not encrypted, and robust cryptographic classes are not included with the default SDK. To perform in-depth encryption, use the Legion of the Bouncy Castle’s JME cryptographic provider, available for free from http://www.bouncycastle.org/.

Conclusion

JME is an advanced development platform with a broad deployed base and thousands of applications. The platform combines the proven Java language with a security system that provides appropriate protections for mobile devices. Some of the hardest security challenges are the ones that developers face when trying to deploy their applications on all the networks around the world. However, this is much better than the pain users experience by being constantly subjected to malware.

The most important thing to consider when you’re reviewing security or writing a JME application is what device and what network the application is targeting. The individual configuration of a device may affect your application and the security behavior. So make sure to move past the emulator and on to real hardware.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
52.15.57.3