As you can see under the Authorization header, it sends: tjs326:sYdJ7U1tvBzdm0fkCbuMCJDCiIQ=:20161220053432+00

but looking at another call to MeDelta it sends this: tjs326:jxFqfzZqU2oEib6ogZTwMKb8ysA=:20161220054021+00

It looks like it’s some sort of signature or hash for each request. This can be used for a few reasons. First, it means if someone somehow gets access to your network and looks at your traffic, they won’t be able to make other requests for you. This is because they don’t have the original auth key, which is probably used to create the string. I also think that the time is used because the exact same requests have a different header, and it appends what i assume to be a timestamp to each request: 20161220054021+00

the request was sent at 12/20/16 00:40:21 according to Charles so

2016 12 20 05 40 21 +00 makes sense (05 is the hour in UTC which is 5 hours ahead of ET). Unfortunately, this is as far as we can go without diving deeper. The Authorization hash could be made in any way and there is no way to know how without the code. Fortunately, there are ways to do this, such as decompilation.

Decompiling The App

Decompiling apps is a way to see what’s going on inside. You can find decompilers for most languages with varying results. In my experience, Android is the best option to go with if you can, because it is written in Java. There are some great decompilers for Java that will give you back somewhat readable source code to look through, which can’t quite be said for others. In addition, if you do it on iOS, you need a jailbroken phone to pull the decrypted IPA app off your phone to look through. The best decompiler I have found for iOS is Hopper, which is pretty good but more difficult.

But Drexel One has an Android app so we will be going down that road instead. For this section, Android experience will be very helpful because you will recognize the project structure and have a basic idea where to look in the project. The first thing you will need to do is download the app’s APK. I use https://apkpure.com for this. Just paste in the apps URL in the search bar and click “download”.

Next you will need to decompile the APK. There is a great online website that will actually do this for you and give you a zip file with the decompiled project in it. It uses the apktool decompiler but does everything for you so no need to download a program and run the command line. Go to http://www.javadecompilers.com/apk and upload the APK we just got and save the zip to your computer. Once you unzip it you will see something like this:

If you have done Android development before then this may look familiar to you. If not, that’s fine. The most useful stuff will most likely be in the assets folder, the res/values folder, and any com/*/* folder and edu/*/* folders. The trick is knowing which parts can be ignored, such as default android classes and libraries that have been packaged in the app. For instance, the com folder doesn’t seem to contain anything interesting, only libraries:

The edu folder, however, contains this:

All the Java code we could ever want!

Now, here comes the boring part. It will take a while to find what you’re looking for. You will have to look around to find where things are and how classes call each other. Some first places to consider first would be helpers, such as Util classes, Network handler classes, and dashboard classes. After looking around for a while I found this in UserDashboard.java

private class AuthGetRequest extends AsyncTask<String, Void, String> {

.........

protected String doInBackground(String... urls) {

String responseMessage = BuildConfig.FLAVOR;

String eTag = BuildConfig.FLAVOR;

for (String url : urls) {

try {



HttpClient httpclient = new DefaultHttpClient();

HttpParams params = httpclient.getParams();

HttpConnectionParams.setConnectionTimeout(params, REGISTRATION_TIMEOUT);

HttpConnectionParams.setSoTimeout(params, WAIT_TIMEOUT);

ConnManagerParams.setTimeout(params, 30000);

SharedPreferences appSettings = UserDashboard.this.getSharedPreferences("d1ma3", 0);

String user = appSettings.getString("user", BuildConfig.FLAVOR);

String authKey = appSettings.getString("authKey", BuildConfig.FLAVOR);

String time = Utils.getUTCdatetimeAsString();

String auth = new StringBuilder(String.valueOf(user)).append(":").append(Utils.generateHash(authKey, new StringBuilder(String.valueOf(url)).append(time).toString()).replace("

", BuildConfig.FLAVOR)).append(":").append(time).toString();

HttpGet httpGet = new HttpGet(url);

httpGet.setHeader(HttpHeaders.ACCEPT, HttpRequest.CONTENT_TYPE_JSON);

httpGet.setHeader(AUTH.WWW_AUTH_RESP, auth);

HttpResponse httpResponse = httpclient.execute(httpGet);

Header responseEtag = httpResponse.getFirstHeader(HttpHeaders.ETAG);

if (responseEtag != null) {

eTag = responseEtag.getValue();

}

StatusLine statusLine = httpResponse.getStatusLine();

if (statusLine.getStatusCode() == 200) {

ByteArrayOutputStream out = new ByteArrayOutputStream();

httpResponse.getEntity().writeTo(out);

out.close();

responseMessage = out.toString();

} else {

Log.e("User Dashboard.authGetRequest", "Could not retreive data: " + statusLine.getReasonPhrase());

httpResponse.getEntity().getContent().close();

Log.e("User Dashboard.authGetRequest", "Closing connection: " + statusLine.getReasonPhrase());

}

} catch (Exception e) {

e.printStackTrace();

}

}

return responseMessage;

}





..........

}

Now this looks like what we are looking for!

String user = appSettings.getString("user", BuildConfig.FLAVOR); String authKey = appSettings.getString("authKey", BuildConfig.FLAVOR);

String time = Utils.getUTCdatetimeAsString();

String auth = new StringBuilder(String.valueOf(user)).append(":").append(Utils.generateHash(authKey, new StringBuilder(String.valueOf(url)).append(time).toString()).replace("

", BuildConfig.FLAVOR)).append(":").append(time).toString();

I’m going to assume the “user” String is my username, tjs326, the “authkey” String is the authkey we got from the first API call, and the “time” String is that timestamp we saw in the request.

Now all we need is to figure out what’s happening in the “auth” String. It looks like it’s just “{my username}:{Utils.generateHash method}:{timestamp}”. Hey, that looks exactly like what our API call header looked like:

tjs326:jxFqfzZqU2oEib6ogZTwMKb8ysA=:20161220054021+00

Now we just need to figure out what’s happening in the generateHash call. It looks like it’s passing in the authkey as the first parameter, and the URL of the call with the time string appended as the second parameter. Let’s go take a look.

We go into the utils.java file and search for the function. Ah, here we go:

public static String generateHash(String key, String data) {

String hash = BuildConfig.FLAVOR;

try {

Mac mac = Mac.getInstance("HmacSHA1");

mac.init(new SecretKeySpec(key.getBytes(HTTP.UTF_8), mac.getAlgorithm()));

hash = Base64.encodeToString(mac.doFinal(data.getBytes()), 0);

Log.v("D1M", hash);

return hash;

} catch (Exception e) {

System.out.println(e.getMessage());

return hash;

}

}

Ok so it looks like its just doing a HmacSHA1 hash of the URL and time using the AuthKey as the secret key and converting it into base64. Lets try this out. Go to https://www.liavaag.org/English/SHA-Generator/HMAC/

and paste in the URL and time as the input and the AuthKey you got before as the key. set the SHA variant to SHA1 and the output type as base64 and presto!

The result is the same as the header from before:

tjs326:jxFqfzZqU2oEib6ogZTwMKb8ysA=:20161220054021+00

We now have everything we need to make all the requests we could ever want. The rest of the poking around I will leave to you. Look around in Charles to see what different API calls return, and what you need to send to get it. If you look back to the decompiled folder and look in /res/values/strings.xml, you will see all the URLs theoretically supported by the API. Here are the first few.