Reverse Engineering Android app binaries (APK) for Legitimate Analysis

Android APK
Finally, I have some chance to get back to blogging since I was very busy last month. Now, let’s go in the details in our today’s topic.

Sometimes, you may have a situation to reverse engineer your existing APKs for legitimate analysis reasons such as making queries on the app source (including used third party libraries) for getting more inside information.

This post shows you how to revere engineer an existing APK for the purpose of such good reasons (again for purpose of *good* reasons).

Detailed way / Using Mainly Three Tools

In order to reverse engineer an APK file from its source, you need to do the following:

  • Exploding APK
  • Extracting Java Classes
  • Decompiling Java Sources
  • Inspecting APK Content

Now, let’s go through them quickly.

Exploding APK

First of all, we need to explode the apk file to mainly the apk resources (assets, libraries, and manifest files).

In order to achieve this step, you need to download and use ApkTool which can be found in:
https://ibotpeaches.github.io/Apktool/

After downloading the jar, execute the library jar as follows.

java -jar apktool_2.2.0.jar decode --no-src myApk.apk

Note that if you do not specify the no-src parameter, then the Apk tool will decode sources and generate SMALI code (Not Java).

Extracting Java Classes

The second step is to convert the APK DEX file(s) into Java jar file(s). You will be find the DEX files whose names
are following classes(i).dex pattern under the exploded apk file directory (note that if your apk is multi-dex then beside the main classes.dex file, you can find classes2.dex, (and/or) classes3.dex … and so on).

In order to make this extraction, you can use a very good tool called (dex2jar) which can be found below:
https://sourceforge.net/projects/dex2jar/

Download the zip file and extract it, then run the dex2jar tool from command line as follows (assuming
that the dex2jar directory is directly located in the same level of the DEX file(s)).

sh d2j-dex2jar.sh ../myApk/classes.dex -o ../myApk/src.jar

Decompiling Java Sources

After having the jars, now we can simply decompile these jars into original Java sources. For this, we can use the command line Java Decompiler which is available in:
https://github.com/kwart/jd-cmd

For every jar we have, we can simply decompile it by running jd-cli as follows.

./jd-cli src.jar

Inspecting APK Content

Finally, we can inspect the APK content as much as we wish. For example, we can get all the strings in the content which are following a URL pattern by executing the following grep command on the exploded apk root folder.

grep -Eo '(http|https)://[^/"]+' -R .

This command will output the complete list of files whose contents are matching this grep regular expression.

Fast way / Using Jadx

Jadx is a powerful tool for directly converting an APK to its original sources, it can be found in:
https://github.com/skylot/jadx
So for our myApk.apk, all what we need to get its original source is to use Jadx tool as follows.

./jadx myApk.apk 

Executing the previous command will do all the previous explained three steps for you.

Now, we are done, see you in the next post.

Dojo Ajaxified multi-file upload (including IE7)

One of the most common requirements of business applications is to develop Ajaxified multi-file upload. Thanks to Dojo 1.6 (and later), you can achieve this requirement, however, there are some tricks that you need to do in order to have this feature developed across all the browsers including IE. Let’s start to see the code.

The following listing shows the HTML code part of the file uploader.

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
	<title>File Upload POC</title>
	
	<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/dojo/1.7.2/dojo/dojo.js">
	</script>
</head>
<body>
	<script type="text/javascript" src="${pageContext.request.contextPath}/js/fileUploader.js"></script>
	<div id="container">
		<form method="post" id="myForm" enctype="multipart/form-data">
		    <fieldset>
		        <legend>Form Files Test</legend>
		        
		        <input id="clearBtn" type="button" value="Clear"></input><br/><br/>
				<div id="uploader"></div><br/>
				<div id="uploaderStatus"></div>
      					
		        <input id="uploadBtn" type="button" value="Submit"></input>
		    </fieldset>
		</form>
	</div>
</body>
</html>

As shown the file upload HTML, the form’s enctype needs to be set to “multipart/form-data”. The form contains “uploader” div that represents the Ajaxified file upload component and “uploaderStatus” div that represents the status panel of the selected files and finally it contains the upload button that will be used for uploading.

Now, Let’s look at the JavaScript file (fileUploader.js) which uses the dojos/form/Uploader module.

require([
        "dojo/parser", "dojox/form/Uploader", "dojo/dom", "dojo/on", "dojo/has", 
        "dojox/form/uploader/FileList", "dojox/form/uploader/plugins/IFrame", 
        "dojo/domReady!"], 
function(parser, Uploader, dom, on, has) {    
    parser.parse(document.getElementById("container"));
    
    var uploaderDIV = document.getElementById("uploader");
    
    var up = new dojox.form.Uploader({
        label: 'Select files',
        style : 'background-color: #ddddff; border: solid 1px;', //Externalize ...
        multiple: true,
        url: "/multifile-ajax-poc/UploaderServlet"
    }).placeAt(uploaderDIV);
    
    on (dom.byId("uploadBtn"), "click", function(evt) {
    	
    	//You can put some validations here ...
        up.submit();
    });  

    on (dom.byId("clearBtn"), "click", function(evt) {
        dom.byId("uploaderStatus").innerHTML = "";
        up.reset();
    });
    
    dojo.connect(up, "onComplete", function(dataArray) {
        var i = 0;
        
        dom.byId("uploaderStatus").innerHTML = "";
        
        if (!dataArray.error) {
            for (i = 0; i < dataArray.length; ++i) {
            	dom.byId("uploaderStatus").innerHTML += "File ID is: " + dataArray[i].id + " is uploaded" + "<br/>";
            }
        } else {
        	dom.byId("uploaderStatus").innerHTML = "Unable to upload the file(s)";
        }
    });    
    
    dojo.connect(up, "onChange", function(evt) {
        var i = 0;
        var content = "";
        var dataArray = up.getFileList();
        
        for (i = 0; i < dataArray.length; ++i) {
            content += dataArray[i].name + "<br/>";
        }
        
        dom.byId("uploaderStatus").innerHTML = content;
    });    
    
    up.startup();     
}
);

As shown in the code, the Dojo Ajaxified file uploader is created using dojox.form.Uploader constructor with specifying the main important attributes:
1. label.
2. multiple attribute is set to true in order to support multi-file uploading.
3. url attribute is set to the Java Servlet which handles the file uploading.

In order to get the uploader working fine, you need to call startup() method of the component.

There are important methods that are needed to be considered:
1. submit() method which allows submitting the selected files to the Java Servlet specified in the url attribute.
2. reset() method which is used to clear the selected files. Note that one of the limitations of this component is that it does not allow removing the selected files individually so the only option you have is ti clear all the files and select them again.
3. getFileList() method which is used to get the list of selected files that you can display for example in the “on change” event of the component as shown by the example.

One important thing to note is dojox/form/uploader/plugins/IFrame plugin which is essential for non-HTML5 browser in order to perform Ajaxified file uploads. Using this plugin will allow file uploading to be done through iframe for poor browsers like IE7.

Finally, let’s come to the most important trick of Ajaxified file uploading which is the server side part. The following code listing shows UploaderServlet Java Servlet.

package servlets;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

@WebServlet("/UploaderServlet")
public class UploaderServlet extends HttpServlet {
	private static final long serialVersionUID = 1809724554045451657L;

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		DiskFileItemFactory factory = new DiskFileItemFactory();
		ServletFileUpload upload = new ServletFileUpload(factory);
		String result = "";
		
		try {
			List<FileItem> items = upload.parseRequest(request);
			Iterator<FileItem> iter = items.iterator();
			int index = 0;

			result += "[";
			
			while (iter.hasNext()) {
			    FileItem item = iter.next();

			    if (!item.isFormField()) {
				    if (index != 0) {
				    	result += ", ";
				    }
				    
			        String feedback = processUploadedFile(item);
			        
			        //Handle IE7 ugly uploading bug
			        if (feedback == null) {
			        	continue;
			        } else {
			        	result += feedback;
			        }
			        
				    ++index;
				    
				    System.out.println(index);
			    }
			}
			
			result += "]";
			
			System.out.println(result);
			
		} catch (FileUploadException e) {
			result = "{'error':'" + e.getLocalizedMessage() + "'}";
			e.printStackTrace();
		}
		
		respondToClient(request, response, result);
	}

	private String processUploadedFile(FileItem item) {
		byte[] data = item.get();
	    String fileName = item.getName();
	    String contentType = item.getContentType();
	    
	    // Handle IE7 file uploading ugly bug ...
	    if (fileName.equals("")) {
	    	return null; //ignore
	    }
	    
		System.out.println(fileName + ", " + contentType + ", " + data.length);	    
	    
	    return "{'fileName':'" + fileName + "', " + 
	    		"'contentType':'" + contentType + "', " + 
	    		"'size':" + data.length + ", " + 
	    		"'id':" + (System.currentTimeMillis() + new Random().nextInt(100)) + "}";
	}
	
	private void respondToClient(HttpServletRequest request, HttpServletResponse response, String result) throws IOException {
        response.setContentType("text/html");
		PrintWriter writer = response.getWriter();		
		String browser = request.getHeader("User-Agent");
		
		if (browser.indexOf("MSIE 9") &gt; 0 || browser.indexOf("MSIE 8") &gt; 0 || browser.indexOf("MSIE 7") &gt; 0 ) {
			
			// For IE 9, 8, and 7 browser, render JSON object inside text area ...
			//String sampleOutput = "<textarea>[{'success':'true', 'id':'123456789'}]</textarea>";
			writer.write("<textarea>" + result + "</textarea>");
		} else {
			
			//For non-IE browsers, render normal JSON objects.
			//String sampleOutput = "[{\"success\":\"true\", \"id\":\"123456789\"}]";
			writer.write(result.replace("'", "\""));
		}		

		writer.flush();		
	}
}

Our UploaderServlet main purpose is to receive the files and if it succeeds to process the files, then it returns a simple array with the basic information of the files that are successfully uploaded.

The most important thing to notice here is for IE7 and IE8 and IE9 (NOT IE 10), a special handling is needed to be taken into consideration in the Servlet response:
1. The response data must be wrapped into textarea field.
2. Do not use double quotes (“) inside the returned JSON array, instead use single quote (‘).

In other modern browsers (which support HTML5 file uploading), you do not need to wrap the content in textarea as it does not use iframe for uploading, and you can freely use the double quotes (“) in the JSON array.

There is an ugly bug that you need to take care about in IE 7 and 8 and also 9 with the Dojo file uploader component, this bug is about having a redundant file with non-name that is always sent in the request of the multiple-file Ajax uploading. In order to handle this bug, just ignore the file which does not have a name (Ugly problem and ugly fix :-)).

This is all about my experience in this component, I wish that it can be helpful to you.

Download the code sample

The effective Java logout servlet code

What is the issue?

You may face an issue when you try to write your own Servlet logout code as follows:

protected void doGet(HttpServletRequest request,
		HttpServletResponse response) throws ServletException, IOException {

	request.getSession().invalidate();
	response.sendRedirect(request.getContextPath() + "/login.jsp");
}

The issue in this code is that after it runs on the web container, You may find that the user session is not cleared completely in IE (However, on Safari, Chrome, and Firefox, it may work fine). i.e) You can access pages that requires a user authentication after running this logout code in IE.

Why do we have this issue?

Well, this issue is related to the caching of the pages in the Internet Explorer.

How to solve this issue?

You need to prevent the page caching from the HTTP response as follows:

protected void doGet(HttpServletRequest request,
		HttpServletResponse response) throws ServletException, IOException {

	response.setHeader("Cache-Control", "no-cache, no-store");
	response.setHeader("Pragma", "no-cache");

	request.getSession().invalidate();
	response.sendRedirect(request.getContextPath() + "/login.jsp");
}

After writing the first two headers response lines, your logout will work in all the browsers.

Java getting the class path in the runtime

In some cases, you may need to know for debugging purposes from where a specific class is loaded. This happens usually if there are two different versions of the class in the class path (the one used in compilation is different from the one used in the runtime) which results in the popular java.lang.NoClassDefFoundError error).

Thanks to the ProtectionDomain, you can get this information as shown below.

try {
	Class myclass = Class.forName("org.apache.commons.logging.Log"); /*or any other class you wish*/
	System.out.println(myclass.getProtectionDomain().getCodeSource()
			.getLocation());

} catch (ClassNotFoundException e) {
	e.printStackTrace();
}

Java Converting String to InputStream

This is the short tip of the day, this tip can be helpful to you if you are wishing, for example, to parse an XML String using the Java DOM APIs or in general if you are working with an API that does not expose an interface to accept the content as a String and it exposes an interface that accepts an input stream.

Using the java.io.ByteArrayInputStream class you can convert a String object to a byte array input stream as follows:

InputStream istream = new ByteArrayInputStream(xmlString.getBytes("UTF-8"));

Protect your Java web application from the consequences of uploading large files

Problem Description:
Sometimes in our web applications, we provide HTML file inputs to our application users so they can upload their documents to the server.

BUT what will happen if a user or more upload a 3 or 4 or more giga bytes files to the server in the same time?
Unfortunately the server may have an OutOfMemory exception.

Another problem is that the client side file size validation is not supported on all browsers for security reasons (Actually the only allowed file size validation is on IE through the “Scripting.FileSystemObject” ActiveX control). So this sort of validation unfortunately has to be done on the server side???

Problem Solution:
Limiting the HTTP post size through setting a value for the (PostSizeLimit) parameter in the HTTP server.
In the IBM HTTP server (for example), this parameter exists in a file called (plugin-cfg.xml) under (/WebSphere/AppServer/config/cells).

Setting the PostSizeLimit to “20971520” means that the maximum file size to be allowed is 20 MB.
And setting the PostSizeLimit parameter to “-1” means unlimited post size.

I wish that this tip can be useful to you guys.