A while back when grep’ing through the AOSP for package manager references, I noticed something weird;
|
1 2 3 4 5 6 7 8 |
tstrazzere@spinach:~/repo/android$ grep -ir "/system/bin/pm" * ... packages/experimental/droiddreamclean/droiddreamclean.c: fp = popen("/system/bin/pm list packages", "r"); packages/experimental/droiddreamclean/droiddreamclean.c: printf("failed to run /system/bin/pm list packages. not removing apps.\n"); packages/experimental/droiddreamclean/droiddreamclean.c: system("/system/bin/pm uninstall com.android.providers.downloadsmanager"); packages/experimental/droiddreamclean/droiddreamclean.c: system("/system/bin/pm uninstall com.android.providers.ammanage"); Binary file packages/experimental/AndroidVendorSecurityTool/assets/droiddreamcleanall matches ... |
What’s this directory? What is contained in it? Let’s look at the readme;
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
tstrazzere@spinach:~/repo/android/packages/experimental$ ls -lhGg total 60K -rw-rw-r-- 1 143 2011-12-13 15:23 Android.mk drwxrwxr-x 5 4.0K 2011-12-13 15:23 AndroidVendorSecurityTool drwxrwxr-x 4 4.0K 2011-12-13 15:23 BugReportSender drwxrwxr-x 4 4.0K 2011-12-13 15:23 CameraPreviewTest -rw-rw-r-- 1 2.2K 2011-12-13 15:23 CleanSpec.mk drwxrwxr-x 5 4.0K 2011-12-13 15:23 DreamTheater drwxrwxr-x 2 4.0K 2011-12-13 15:23 droiddreamclean drwxrwxr-x 4 4.0K 2011-12-13 15:23 ExampleImsFramework drwxrwxr-x 4 4.0K 2011-12-13 15:23 LoaderApp drwxrwxr-x 2 4.0K 2011-12-13 15:23 procstatlog -rw-rw-r-- 1 844 2011-12-13 15:23 README drwxrwxr-x 4 4.0K 2011-12-13 15:23 RpcPerformance drwxrwxr-x 4 4.0K 2011-12-13 15:23 StrictModeTest drwxrwxr-x 4 4.0K 2011-12-13 15:23 UiAutomation drwxrwxr-x 3 4.0K 2011-12-13 15:23 UiAutomationDemo tstrazzere@spinach:~/repo/android/pacakges/experimental$ cat README The packages/experimental/ directory is for NON-SHIPPING code that is not included with any flavor of the device, the SDK, or any other kind of public release, but which might be useful for someone as a test harness, development tool, or general fun times. >> Every package under this directory must have a README file << Official SDK development samples should NOT go here, they should go in development/samples/ instead. Unlike the rest of the tree, code in experimental/ is NOT built by default, and may be arbitrarily broken. Caveat user! Individual packages must be built directly with "mmm" or equivalent: mmm packages/experimental/BugReportSender Like a communal fridge, this directory will be cleaned periodically. Every major release, we intend to remove and archive any package that does not have an active owner and users. |
Ops! Did someone mean to publish this repo? It’s all a bunch of experimental and interesting code. Granted it’s a bit old now, but still very interesting to look at. Specifically there are what looks to be the precursor to fragments and ui testing automation, done and committed before the final work was committed to AOSP. There is also the DroidDreamCleaner utility which is interesting. While it was an fix for an old issue, it’s just interesting to see how Google coders handled the issue without having to reverse it. We can even see a “DreamThreater” application which looks like some work done to make an Android screen saver. Sadly not all this code can compile since it relies on some code which isn’t accessible to us and the released branches of AOSP. It seems this code may have been mistakenly committed to the public branch after the kernel.org mishaps, as it appears to have been made public after AOSP became available on Google’s own servers.
If you don’t have all of AOSP pulled, you can get it by just cloning the following repository;
|
1 |
git clone https://android.googlesource.com/platform/packages/experimental |
Again, nothing ground breaking – but definitely an interest repository of code to take a look at, if not to see how Google coders work on “internal” code which isn’t released but to see their comments and documentation that is sometimes stripped from AOSP
Normally I like spending time fuzzing/causing segfaults with real devices, not sure why – maybe it’s just because it just feels more gratifying. Though recently for a small project at work, I need to be able to do multiple devices for longer periods of time and swap out different modules relatively fast. This would be a huge problem – but I wanted to automate it and do the least amount of work possible. A challenge that comes up sometimes with the somewhat stock phones I use for testing, is that some compiled modules/elf binaries never worked that well. Sometimes due to carrier modifications, sometimes due to Cyanogen modifications other times just due to me being stupid and compiling things horribly wrong. Since I just got my desktop machine all set up, it seemed like the perfect time to try and automate this on a box I could just SSH into and let run all the time!
After a quick bit of Googling, I didn’t see many instructions on how to modify emulator images fast. Lots of people said, generate an emulator, then change the system.img by mounting it, then restart the emulator and make sure it doesn’t overwrite changes. That’s a pain though, I don’t want to mount anything! Though this did remind me of building the AOSP which can product the system.img — perfect!
After making all my changes, some Dalvik changes and some Webkit changes, kicked off a full build via the normal commands;
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
tstrazzere@spinach:~/repo/android$ . build/envsetup.sh including device/samsung/maguro/vendorsetup.sh including device/samsung/tuna/vendorsetup.sh including device/ti/panda/vendorsetup.sh including sdk/bash_completion/adb.bash tstrazzere@spinach:~/repo/android$ lunch full-eng ============================================ PLATFORM_VERSION_CODENAME=AOSP PLATFORM_VERSION=4.0.1.2.3.4.5.6.7.8.9 TARGET_PRODUCT=full TARGET_BUILD_VARIANT=eng TARGET_BUILD_TYPE=release TARGET_BUILD_APPS= TARGET_ARCH=arm TARGET_ARCH_VARIANT=armv7-a HOST_ARCH=x86 HOST_OS=linux HOST_BUILD_TYPE=release BUILD_ID=OPENMASTER OUT_DIR=out ============================================ tstrazzere@spinach:~/repo/android$ make -j4 ============================================ PLATFORM_VERSION_CODENAME=AOSP PLATFORM_VERSION=4.0.1.2.3.4.5.6.7.8.9 TARGET_PRODUCT=full TARGET_BUILD_VARIANT=eng TARGET_BUILD_TYPE=release TARGET_BUILD_APPS= TARGET_ARCH=arm TARGET_ARCH_VARIANT=armv7-a HOST_ARCH=x86 HOST_OS=linux HOST_BUILD_TYPE=release BUILD_ID=OPENMASTER OUT_DIR=out ============================================ ... target Symbolic: libwebcore (out/target/product/generic/symbols/system/lib/libwebcore.so) target Strip: libwebcore (out/target/product/generic/obj/lib/libwebcore.so) Install: out/target/product/generic/system/lib/libwebcore.so target Executable: webcore_test (out/target/product/generic/obj/EXECUTABLES/webcore_test_intermediates/LINKED/webcore_test) Finding NOTICE files: out/target/product/generic/obj/NOTICE_FILES/hash-timestamp target Symbolic: webcore_test (out/target/product/generic/symbols/system/bin/webcore_test) target Strip: webcore_test (out/target/product/generic/obj/EXECUTABLES/webcore_test_intermediates/webcore_test) Combining NOTICE files: out/target/product/generic/obj/NOTICE.html Installed file list: out/target/product/generic/installed-files.txt Target system fs image: out/target/product/generic/obj/PACKAGING/systemimage_intermediates/system.img Install system fs image: out/target/product/generic/system.img |
While waiting for the compilation to finish – I prepped a “target platform” to build an emulator image for. To quickly do this I just copied the android-15 directory under the platforms directory of the sdk. This will give us the proper structure and files required while keeping the normal platform for android-15 intact.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
tstrazzere@spinach:~/android/android-sdk-linux/platforms$ cp -r android-15 custom tstrazzere@spinach:~/android/android-sdk-linux/platforms$ cd custom/ tstrazzere@spinach:~/android/android-sdk-linux/platforms/custom$ ls -l tstrazzere@spinach:~/android/android-sdk-linux/platforms/custom$ ls -l total 13124 -rw-rw-r-- 1 tstrazzere tstrazzere 13402051 2012-01-14 18:46 android.jar -rw-rw-r-- 1 tstrazzere tstrazzere 1371 2012-01-14 18:46 build.prop drwxrwxr-x 4 tstrazzere tstrazzere 4096 2012-01-14 18:46 data -rw-rw-r-- 1 tstrazzere tstrazzere 1796 2012-01-14 18:46 framework.aidl drwxrwxr-x 2 tstrazzere tstrazzere 4096 2012-01-14 18:46 images drwxrwxr-x 4 tstrazzere tstrazzere 4096 2012-01-14 18:46 renderscript -rw-rw-r-- 1 tstrazzere tstrazzere 206 2012-01-14 18:46 sdk.properties drwxrwxr-x 3 tstrazzere tstrazzere 4096 2012-01-14 18:46 skins -rw-rw-r-- 1 tstrazzere tstrazzere 398 2012-01-14 18:46 source.properties drwxrwxr-x 2 tstrazzere tstrazzere 4096 2012-01-14 18:46 templates tstrazzere@spinach:~/android/android-sdk-linux/platforms/custom$ cd images/ tstrazzere@spinach:~/android/android-sdk-linux/platforms/custom/images$ ls -l total 121400 -rwxrwxr-x 1 tstrazzere tstrazzere 1445004 2012-01-14 18:46 kernel-qemu -rw-rw-r-- 1 tstrazzere tstrazzere 359448 2012-01-14 18:46 NOTICE.txt -rw-rw-r-- 1 tstrazzere tstrazzere 149875 2012-01-14 18:46 ramdisk.img -rw-rw-r-- 1 tstrazzere tstrazzere 119406144 2012-01-14 18:46 system.img -rw-rw-r-- 1 tstrazzere tstrazzere 2948352 2012-01-14 18:46 userdata.img tstrazzere@spinach:~/android/android-sdk-linux/platforms/custom/images$ rm system.img rm: remove regular file `system.img'? y tstrazzere@spinach:~/android/android-sdk-linux/platforms/custom/images$ cp ~/repo/android/out/target/product/generic/system.img $PWD tstrazzere@spinach:~/android/android-sdk-linux/platforms/custom/images$ ls -l total 170976 -rwxrwxr-x 1 tstrazzere tstrazzere 1445004 2012-01-14 18:46 kernel-qemu -rw-rw-r-- 1 tstrazzere tstrazzere 359448 2012-01-14 18:46 NOTICE.txt -rw-rw-r-- 1 tstrazzere tstrazzere 149875 2012-01-14 18:46 ramdisk.img -rw------- 1 tstrazzere tstrazzere 170172288 2012-01-14 18:48 system.img -rw-rw-r-- 1 tstrazzere tstrazzere 2948352 2012-01-14 18:46 userdata.img |
Awesome, we copied over the system.img too the nessicary directory, lets just edit a few files so I don’t forget what this when I build my emulators. Open up the source.properties file and edit the version number to something you can remember, I just changed mine to say 4.0.3-hacked;
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
tstrazzere@spinach:~/android/android-sdk-linux/platforms/custom$ android list targets Available Android targets: ... ---------- id: 22 or "android-15" Name: Android 4.0.3-hacked Type: Platform API level: 15 Revision: 1 Skins: WXGA (default) ABIs : armeabi ---------- ... |
Now I can just create an emulator like normal and fire it up;
|
1 2 3 4 5 6 7 8 9 10 |
tstrazzere@spinach:~/android/android-sdk-linux/platforms/custom$ android create avd -t 27 -n dalvik_webcore_fuzz Auto-selecting single ABI armeabi-v7a Android 4.0.3-hacked is a basic Android platform. Do you wish to create a custom hardware profile [no] Created AVD 'dalvik_webcore_fuzz' based on Android 4.0.3-hacked, ARM (armeabi-v7a) processor, with the following hardware config: hw.lcd.density=240 vm.heapSize=48 hw.ramSize=512 tstrazzere@spinach:~/android/android-sdk-linux/platforms/custom$ emulator -avd dalvik_webcore_fuzz |
Now it just time to attach your fuzzing and other automated tools to the emulator.
Progress has been quiet slow as of lately, albeit progress none the less though. As normal, I figured I’d attempt to document this so that anyone attempting to root devices in the future that might be similar to the Archos might have an easier time
Thus far when rooting phones we have been coming in contact with less protection. After gaining root we have been able to remount the partitions and edit them directly – making the changes persistent immediately. Though there is a fundamental difference with the Archos that comes into play. The Archos stores everything on a (maybe two or three?) flash chips. The partitions of the chips are like normal phones and mounted as read-only. The problem comes into play since what is mounted is not a filesystem, but a cramfs file. This cramfs file is what needs to be modified to create any changes to the system files.
So just modify the cramfs file, right? Nope – Archos caught you on this one. Simply modifying the cramfs, which is actually a “cramfs.secure” file will lead to a bad signature error. What the heck is that all about? Essentially when Archos creates a firmware update and flashes a new ‘androidroot.cramfs.secure‘ to the device. This file is signed with a signature of itself. Sadly we cannot recreate the signature for the file since it’s an RSA/MD5 signature of the contents. This means that they basically run a program after the have a androidroot.cramfs to append the signature like the following:
secure = RSA(MD5(cramfsFile)) + cramfsFile;
The RSA function uses a private key that we do not, and most likely will never have. Essentially in the bootloader there is a program called cramfschecker that does something like the following pseudo code:
if(RSADecrypt(signature) == MD5(file)) ? return goodFile : return badFile;
The RSADecrypt function uses a public key that we have found, but is no help to us.
Alright, know that we know what files need to get modified and how we are locked out of them, how do we actually get past this? This is where we have to get into modifying the kernel and boot loader. The flash memory is a little tricky but essentially is mapped out like the following:
[code]
mtd device - name ----- nickname - description
mtd0 ------- stage1 --- boot0 ---- bootloader part 1, also contains keystore
mtd1 ------- stage2 --- boot1 ---- bootloader part 2, also contains boot image
mtd2 ------- recovery - recovery - recovery kernel and recovery.cpio (filesystem)
mtd3 ------- init ----- init ----- init (main) kernel and init.cpio (filesystem)
[/code]
Now here is where the cool stuff comes into play. Stage1, among other things, checks the signature of stage2 to verify that it has not been modified. When stage2 begins it performs the same type of check on recovery and init. Inside recovery and init a program called cramfschecker is called, which checks the actual cramfs.secure files that we want to change. So the chain of trust is as follows:
Stage1 -> Stage2 -> recovery/init -> cramfs.secure
We need to modify Stage1 to accept any stage2, stage2 to accept any recovery/init and then remove the cramfschecker call so we can execute anything we’d like without worrying about if it is signed or not.
Now we know everything that needs to be done, so lets do it! Well, it’s sadly not that easy. We know how and can modify the cramfs files, that’s not hard. We can flash new a recovery/init, and even flash a new stage2. The problem is that we cannot currently flash a stage1 since it is marked as read-only after boot by the kernel. Yes, it is marked read-only, not locked – which if it where we could simply use a ‘flash_unlock‘ tool on it.
Currently I’ve been diving into the init kernel, which is at the beginning part of the init section, gzipped. This has been pretty tough trudging and I’ve enlisted the help of EiNSTeiN_. This is still pretty ugly stuff to look through though – we are basically looking for a small struct that make uses the kernel module to set the partition to read-only. The struct should look something like this:
|
1 2 3 4 5 6 7 8 |
struct mtd_partition { char name; /* identifier string */ uint64_t size; /* partition size */ uint64_t offset; /* offset within the master MTD space */ // Probably set to MTD_WRITEABLE (0x0400), since it is MASKING this flag uint32_t mask_flags; /* master MTD flags to mask out for this partition */ struct nand_ecclayout *ecclayout; /* out of band layout for this partition (NAND only)*/ }; |
Though this should all be GPLed code – since it is the kernel! Ah hah! That could make things so much easier. Sadly Archos has not yet posted the GPLed kernel source code for the Gen7 devices (which the Android model is).
After about two to three weeks of trying to track down someone, anyone with an Archos contact, or even just someone at Archos who isn’t outsourced technical support I finally got an answer! Prior to reaching this person I mainly got the run around, saying it will be up soon or that it is already posted. For some reason it also kept getting lost in the translation that I was requesting the GPLed *kernel* source code from the Archos 5 Android model. Someone in France apparently kept seeing “Android” and said “NO! It’s Apache, we don’t have to release that, Google hosts the source, goto them!” Finally I got a response, rather promptly I might add, from a USA Archos representative saying that Google hosts the code. After exchanging a few more emails they finally understood that I was requesting the Gen7 kernel source code, which is under the GPL license – NOT the Android source code which is under Apache. PHEW!
So the latest update is that we are essentially in a holding pattern, waiting for next week to come. I’ve been promised that the GPLed source code for the kernel will be posted by the end of next week, though I shouldn’t hold my breath until Friday. If it doesn’t appear on the site by Friday evening EST then I can start calling and complaining again… This time someone can actually be help responsible though, so I feel like it will actually happen. Once we get this code, it’s only a matter of time before EiNSTeiN_ and myself track down the right code which should help us in creating a program to patch the mtd partitions into being read/writable.
If you feel like you can help us with this, feel free to post here, email me or send a reply on twitter. Also if you just want to get the most updated information, I’d recommend you follow me on twitter @timstrazz.
Lately I’ve been receiving a bunch of emails regarding Android Market data and the Archos 5 IT. So I figured maybe a blog post would be the most appropriate place to attempt to address all the repeat questions, and heck – maybe answer a few before they are emailed to me!
Recently I’ve been working on numerous projects, my focus has mainly been on the Archos 5 IT as it’s my new toy! If you’ve been following me on , you’ve seen my little picture showing I’ve gotten root (yay!).
Regarding root on the Archos 5 IT, I’m currently running the firmware 1.1.01, the root method appears to work fine on the newest 1.2.03(?) though I have not updated my device yet. No, not out of fear of loosing the root method, more from the advice of other people saying more things are broken in this new upgrade – so I’d like to keep my device running smoothly for what I do until I can fully root it. What do I mean by that? Well essentially we have root on the device, but on reboot we loose root. I’m currently working with einstein_ to modify the bootloader to accept any android img. This will allow us to modify the android image, and keep root after a reboot. It’s posing trickier than we’d hoped so, people will just have to wait. Why are we waiting? Without a changable android image, no current android programs requiring root will function properly (there is no ‘su’ command to run) – so there is no reason to release it unless we want to see people brick their devices.
One of the other projects I’ve been working on is a web based version of AppsLib for the Archos 5 IT. This is essential a “cyrket”/”androlib” for the Archos library. The reason I’m doing this is because the current AppsLib application is garbage, there appear to be updates just about each week, yet each release appear to only cause more crashes… Maybe just for me, but I doubt that. Anyway I’ve posted some screen shots for what it’s going to look like on some forums and I’m relatively close to releasing it. It’s almost at the process of just being migrated from my developement machine to this server. Also note that it’s never probably going to be the most functional thing in the world, but it works – more than I can say for the application version right now. The features on release will most likely be, list ten applications in the date of release, give the information available for the item and a link to download it. I’ll add searching and category sorting later on hopefully.
A word on the Android Market data. I’ve not yet had time to write up all my posts on how to collect, spoof and do what not with the data. This will come, though maybe not in the most timely fashion. I know many people are emailing me saying they want to make an open source market client that downloads stuff, well I highly doubt that will happen. Yes we can download applications, yes we can get all the data. The problem lies with some SSL chatter that we cannot and probably will not decrypt.
Lastly, I want to remind people that I do have a paying job, a loving girlfriend and other activities I love doing outside of the computer/android realm. Please hang in there while I take care of my own things first and then work on these as I see fit. People have been telling me that certain ones are more important than the others, but it comes down to this is a hobby and not my real job. I do it in spare time and I’ve been making time for it enough lately. So try not to be too hard on me when I don’t release information you want immediately, when you want it. So, thats my appology on that — and that was my little State of the Archos (Android)
It turns out downloading a free application is actually pretty easy to reproduce. The things required by the google android servers are just four variables. The server needs to know your userId, authToken, deviceId and the applications assetId.
The userId is a unique number that is associated only with your gmail account, the one that is currently linked to the phone. I’m working on getting a generic way to grab this number, though I believe the request is buried in an ssl request to the google servers. So for now, you can obtain your own userId by doing a tcpdump of your market traffic, just do a download of an application and look for a “GET” request in wireshark. There does not appear to be a “hard” maximum character on this, I’ve seen userIds as low as 8 in length and as high as 13. A bad userId will return a 403 forbidden response.
The authToken is sent in cookie form to the server, to authenticate that the user is using a valid and non-expired token and well, is who they say they are! This is linked to the userId and must match the account that the userId is taken from. Expired tokens will return a 403 forbidden response.
The deviceId is simply your Android_ID, and is linked in anyway to the authtoken or user-id, so feel free to spoof this.
The assetId is a number (negative or positive) that identifies the current stream of the application you wish to download. More on this later when I cover how to get live market data. Note that this number is not always the same – it (appears) to change when something from the application is changed. Originally I referred to this in my research as a “cacheAppID” for just that purpose.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
// Downloading apk's without vending/market // Coded by Tim Strazzere import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLEncoder; import java.net.HttpURLConnection; public class main { public static void main(String[] args) { // current assetId for the yahoo search apk String assetId = "7884814897504696499"; // input your userId String userId = "12345678901"; // spoof your deviceId (ANDROID_ID) here String deviceId = "2302DEAD532BEEF5367"; // input your authToken here String authToken = "DQAAA...BLAHBLAHBLAHYOURTOKENHERE"; String cookie = "ANDROID=" + authToken; try { // prepare data for being 'get'ed String rdata = "?" + URLEncoder.encode("assetId", "UTF-8") + "=" + URLEncoder.encode(assetId, "UTF-8"); rdata += "&" + URLEncoder.encode("userId", "UTF-8") + "=" + URLEncoder.encode(userId, "UTF-8"); rdata += "&" + URLEncoder.encode("deviceId", "UTF-8") + "=" + URLEncoder.encode(deviceId, "UTF-8"); // Send data URL url = new URL("http://android.clients.google.com/market/download/Download" +rdata); HttpURLConnection conn = (HttpURLConnection)url.openConnection(); // For GET only conn.setRequestMethod("GET"); // Spoof values conn.setRequestProperty("User-agent", "AndroidDownloadManager"); conn.setRequestProperty("Cookie", cookie); // Read response and save file... InputStream inputstream = conn.getInputStream(); BufferedOutputStream buffer = new BufferedOutputStream(new FileOutputStream("out.put")); byte byt[] = new byte[1024]; int i; for(long l = 0L; (i = inputstream.read(byt)) != -1; l += i ) buffer.write(byt, 0, i); inputstream.close(); buffer.close(); System.out.println("File saved..."); } catch (FileNotFoundException e) { System.err.println("Bad url address!"); } catch (UnsupportedEncodingException e) { System.out.println(e); } catch (MalformedURLException e) { System.out.println(e); } catch (IOException e) { if(e.toString().contains("HTTP response code: 403")) System.err.println("Forbidden response received!"); System.out.println(e); } } } |
Hopefully someone will find this stuff useful
Better than me just sitting on it forever!
A recent addition to the android market has been ATD, Android Turret Defense. This is a Plox-like game, though it has the “maze” strategy element combined in it. Strangely — it reminds me of a few old maps I used to play with friend for starcraft… Anyway I finally got around to beating it which isn’t too difficult once you get the hang of placing turrets and a get a decent strategy. At the end it awards you with a “badge code” — not sure exactly what the author intends to use this for, but I decided to take a look at how these are created. I was interested in how they where generated, and to see if people could easily replicate them, or if there would be any deterrents to keep people from just sharing them. Again, this is possibly completely useless information, since we have no idea what these codes will be used for. The could be used for tournaments, downloads, prizes – or maybe to just “give” you an image of a badge… As of right now we just don’t know.
Below is a dump of the function we will be analyzing with my comments in it (highlighted green), they should be pretty easy to follow:
.method private createBadgeCode()Ljava/lang/String;
// Date now = New Date();
new-instance v2,java/util/Date
invoke-direct {v2},java/util/Date/; ()V // SimpleDateFormat dateFormat = new SimpleDateFormat(“yyMMddhhmm”);
new-instance v5,java/text/SimpleDateFormat
const-string v7,”yyMMddhhmm”
invoke-direct {v5,v7},java/text/SimpleDateFormat/; (Ljava/lang/String;)V // StringBuilder raw = new StringBuilder();
new-instance v7,java/lang/StringBuilder
invoke-direct {v7},java/lang/StringBuilder/; ()V // raw.append(dateFormat.format(now));
invoke-virtual {v5,v2},java/text/SimpleDateFormat/format ; format(Ljava/util/Date;)Ljava/lang/String;
move-result-object v8
invoke-virtual {v7,v8},java/lang/StringBuilder/append ; append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v7// raw.append(difficulty);
iget v8,v12,tx/games/atd_world.difficulty I
invoke-virtual {v7,v8},java/lang/StringBuilder/append ; append(I)Ljava/lang/StringBuilder;
move-result-object v7// raw.append(“tensaix2j”);
const-string v8,”tensaix2j”
invoke-virtual {v7,v8},java/lang/StringBuilder/append ; append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v7// Bytes[] rawbytes = raw.toString.getBytes;
invoke-virtual {v7},java/lang/StringBuilder/toString ; toString()Ljava/lang/String;
move-result-object v4
invoke-virtual {v4},java/lang/String/getBytes ; getBytes()[B
move-result-object v0/* Below code refined;
int sum = 0;for(int i = 0; i < rawbytes.length(); i++)
sum += rawbytes[i];
*/
const/4 v6,0
const/4 v3,0
l3c1e:
// length = rawbytes.length();
array-length v7// if( v3 > v7 ) goto: l3c30
if-ge v3,v7,l3c30// v7 = rawbytes(v0);
aget-byte v7,v0,v3// v6 += v7;
add-int/2addr v6,v7// v3 ++;
add-int/lit8 v3,v3,1
goto l3c1el3c30:
// StringBuilder badge = new StringBuilder();
new-instance v7,java/lang/StringBuilder
invoke-direct {v7},java/lang/StringBuilder/; ()V // v8 = Math.random();
invoke-static {},java/lang/Math/random ; random()D
nop
move-result-wide v8// v10 = 4652007308841189376;
const-wide v10,4652007308841189376 ; 0x408f400000000000// v8 = Math.round(v8*v10);
mul-double/2addr v8,v10// I thought it only took one variable??
invoke-static {v8,v9},java/lang/Math/round ; round(D)J
move-result-wide v8// v10 = 1000
const-wide/16 v10,1000// v8 += v10;
add-long/2addr v8,v10// badge.append(v8);
invoke-virtual {v7,v8,v9},java/lang/StringBuilder/append ; append(J)Ljava/lang/StringBuilder;
move-result-object v7// badge.append(dateFormat.format(now));
invoke-virtual {v5,v2},java/text/SimpleDateFormat/format ; format(Ljava/util/Date;)Ljava/lang/String;
move-result-object v8
invoke-virtual {v7,v8},java/lang/StringBuilder/append ; append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v7// badge.append(difficulty);
iget v8,v12,tx/games/atd_world.difficulty I
invoke-virtual {v7,v8},java/lang/StringBuilder/append ; append(I)Ljava/lang/StringBuilder;
move-result-object v7// badge.append(sum);
invoke-virtual {v7,v6},java/lang/StringBuilder/append ; append(I)Ljava/lang/StringBuilder;
move-result-object v7// return badge.toString();
invoke-virtual {v7},java/lang/StringBuilder/toString ; toString()Ljava/lang/String;
move-result-object v1
return-object v1
.end method
An example of the output of this function is; 1310090403121501473
Broken down the output looks like this;
1310090403121501473, (round(random * const)+1000
1310090403121501473, Date in yyMMddhhmm format.
1310090403121501473, “0″ Difficulty, Noob = 0, Normal = 1, Pro = 3
1310090403121501473, sum of bytes (date + difficulty + “tensaix2″)
I’ll post more later if the “badge system” is every finished and released. Hopefully this serves as a decent example on how to reverse simple android programs… Enjoy!
Currently working on some random things on the Android OS source – which of course if I can get my little, “additions”, to work properly I’ll be releasing them. Though I was having a few problems getting the code to compile – so I figured I’d throw together this post just in case anyone else is having similar trouble.
Essentially in the post I was originally reading here, stated the following;
At the time of writing, the Android Dream build was broken. I needed to do the following to make it work:
* Several (relatively minor) changes in the Dream audio driver code to fix compilation issues.
* Copied libOmxCore.so to mydroid/out/target/product/dream/system/lib (this was a missing step in the Building for Dream documentation, and something that should be in the HTC provided script)
Well that wasn’t the problem I was getting though — the erorr I had been getting was actually:
In file included from frameworks/base/libs/audioflinger/AudioResamplerCubic.cpp:20:
system/core/include/cutils/log.h:68:1: warning: this is the location of the previous definition
target thumb C++: libaudioflinger <= frameworks/base/libs/audioflinger/AudioFlinger.cpp
make: *** No rule to make targetout/target/product/dream/obj/lib/libaudio.so’, needed byout/target/product/dream/obj/SHARED_LIBRARIES/libaudioflinger_intermediates/LINKED/libaudioflinger.so'. Stop.
...
make: *** No rule to make target/tmp/dream/target/product/dream/obj/lib/libcamera.so', needed by/tmp/dream/target/product/dream/obj/SHARED_LIBRARIES/libcameraservice_intermediates/LINKED/libcameraservice.so'. Stop.
...
make: *** No rule to make target/tmp/dream/target/product/dream/obj/lib/libOmxCore.so', needed by/tmp/dream/target/product/dream/obj/SHARED_LIBRARIES/libopencorecommon_intermediates/LINKED/libopencorecommon.so'. Stop.
...
/media/other-storage/mydroid/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/../lib/gcc/arm-eabi/4.2.1/../../../../arm-eabi/bin/ld: warning: librpc.so, needed by /tmp/dream/target/product/dream/obj/lib/libaudio.so, not found (try using -rpath or -rpath-link)
...
make: *** No rule to make target/tmp/dream/target/product/dream/system/lib/libaudio.so', needed by/tmp/dream/target/product/dream/system/lib/libaudioflinger.so'. Stop.
...
make: *** No rule to make target/tmp/dream/target/product/dream/system/lib/libcamera.so', needed by/tmp/dream/target/product/dream/system/lib/libcameraservice.so'. Stop.
...
make: *** No rule to make target/tmp/dream/target/product/dream/system/lib/libOmxCore.so', needed by/tmp/dream/target/product/dream/system/lib/libopencorecommon.so'. Stop.
(This list was compiled over multiple re-runs of make)
The simple fix was essentially what was stated in the original post, though it just took me a few minutes to figure this out. After running the locate command like a mad man and not finding anything on my developer machine, I finally reread *everything* and checked the device for the file - and there it was!
I just ended up throwing this into my extract-files.sh;
adb pull /system/lib/libaudio.so proprietary/libaudio.so
adb pull /system/lib/libcamera.so proprietary/libcamera.so
adb pull /system/lib/libOmxCore.so proprietary/libOmxCore.so
adb pull /system/lib/librpc.so proprietary/librpc.so
So my resulting file looked like this;
[code]
#!/bin/sh
mkdir -p proprietary
adb pull /system/etc/AudioFilter.csv proprietary/AudioFilter.csv
adb pull /system/etc/AudioPara4.csv proprietary/AudioPara4.csv
adb pull /system/etc/gps.conf proprietary/gps.conf
adb pull /system/bin/akmd proprietary/akmd
adb pull /system/lib/libhtc_ril.so proprietary/libhtc_ril.so
adb pull /system/lib/libaudioeq.so proprietary/libaudioeq.so
adb pull /system/lib/libqcamera.so proprietary/libqcamera.so
adb pull /system/lib/libaudio.so proprietary/libaudio.so
adb pull /system/lib/libcameraservice.so proprietary/libcameraservice.so
adb pull /system/lib/libcamera.so proprietary/libcamera.so
adb pull /system/lib/libOmxCore.so proprietary/libOmxCore.so
adb pull /system/lib/librpc.so proprietary/librpc.so
chmod 755 proprietary/akmd
adb pull /system/etc/wifi/Fw1251r1c.bin proprietary/Fw1251r1c.bin
adb pull /system/etc/wifi/tiwlan.ini proprietary/tiwlan.ini
[/code]
libaudio.so, libcameraservice.so, libcamera.so, libOmxCore.so, librpc.so then needed to be copied over to TARGET/dream/target/product/dream/obj/lib/ and also to the locked folder TARGET/dream/target/product/dream/system/lib/
Ta-da! After approximately 10 runs, it finally compiled for me... Hopefully this helps anyone who ran into the same problems as me.
Alright so I’m doing some coding and kept running into this strange error while trying to connect to a site to perform a POST action.
12-01 18:27:52.175: WARN/System.err(764): java.net.UnknownHostException: Host is unresolved: www.strazzere.com:80
Obviously www.strazzere.com is a valid and resolvable host since you can read this post. This occurred whenever .connect() or .getOutputStream() was called. So after banging my head against a wall for a bit (ok more like an hour or so), I decided to try the fundamentals of troubleshooting.
Does the emulator have internet? Yeap – can connect to www.google.com
Can the emulator get the host www.strazzere.com? No… Strange – could have sworn it did though?
Apparently something must have happened with emulator upon switching connections or after hibernation. The solution seems to be to reboot the emulator. After doing so, I checked connection with www.strazzere.com and it worked fine. Yet another thing we can sing all-hail-reboot for I guess. Maybe the next version of the emulator will handle these better, though it’s not too bad as long as you know what is going on I guess.
Hopefully this article is found by some frustrated developer who hit the same wall I did!
Previously I wrote about how to uniquely identify Android devices without special permissions. However, maybe you want to get into the nitty-gritty and get an even more unique identifier for the device. This can be done, but you need special permissions. Essentially what I mean by “special permissions” is that the user will be prompted when installing that “this application tries to do this”. “This” referring to (in this specific case) Reading Phone State. This doesn’t mean it’s doing anything bad, however users might be turned off if your calculator wants to read the phones state etc. This is just how Google has set up the installation of applications, so that a user is properly notified of what an application is given permission to do.
What are the kind of identifiers we can get with this special permission? We can grade the “Device ID” which is the IMEI number, the phone number, Software Version (not sure if it’s currently being used?), Sim Serial Number and Subscriber ID.
That should be enough unique identifiers for anyone to come up with some hash! Heck, phone number alone should be enough since it would be readily known by a customer and easy to use.
To get these values add the following somewhere in your program;
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import android.telephony.*; ... TelephonyManager mTelephonyMgr = (TelephonyManager)getSystemService(TELEPHONY_SERVICE); String imei = mTelephonyMgr.getDeviceId(); // Requires READ_PHONE_STATE String phoneNumber=mTelephonyMgr.getLine1Number(); // Requires READ_PHONE_STATE String softwareVer = mTelephonyMgr.getDeviceSoftwareVersion(); // Requires READ_PHONE_STATE String simSerial = mTelephonyMgr.getSimSerialNumber(); // Requires READ_PHONE_STATE String subscriberId = mTelephonyMgr.getSubscriberId(); // Requires READ_PHONE_STATE |
Note that you MUST add permission access to android.permission.READ_PHONE_STATE otherwise your program will force close. This is added in the AndroidManifest.xml like the following;
|
1 |
<uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission> |
On the emulator it will output things like the following;
DeviceId(IMEI) = 000000000000000
DeviceSoftwareVersion = null
Line1Number = 15555218135
SimSerialNumber = 89014103211118510720
SubscriberId(IMSI) = 310995000000000
One should also note that a real device currently returns “00″ for Device Software Version, so it’s possible that this is something reserved for future use. These could all easily be used in some type of registration algorithm that you want to tie to a certain device. Also if you choose your identifiers properly you could allow your registration code to be complaint across all versions of your product. Using a phone number for example could allow a user to use your application on any phone they put their SIM card into. If you want to prevent this you could tie it to both the device ID and the phone number.
I’ve been working on the header a little more – so I figured I’d post some code I just finished throwing together quickly. It’s not all the code, since most of it is experimental and I’m not finished doing it, but this will provide people with the information on how to dump the dex file header information.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
/* File: DexNfo.java * * Coded: Timothy Strazzere * Date: 11/22/08 * * Dump header information from a dex file, only supports '035' dex files, though will * attempt to dump rest of the information, but will just warn you otherwise. * * Some code has been removed as it isn't sure if it full works properly yet. * */ import java.security.*; import java.util.zip.Adler32; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; /* To do... * * lots... * */ public class DexNfo{ public static void main(String[] args) { if (args.length == 1) { try { File file = new File(args[0]); byte[] barr, newbytes = null; newbytes = barr = getBytesFromFile(file); // add switch for this? System.out.printf("Original information: " + args[0]); int magic = 0; for(int i = 0; i<8; i++) magic+=barr[i]; if(magic!=483) // technically anything higher should be a new dex file... 'dex 036' etc.. System.out.printf("\n** Warning: Magic; bad dex file or unsupported version loaded!"); // Don't output char 4 since it's a newline char System.out.printf("\nMagic: %c%c%c %c%c%c", barr[0], barr[1], barr[2], /*barr[3],*/ barr[4], barr[5], barr[6], barr[7]); System.out.print("\nChecksum: "); for(int i = 8; i<12; i+=4) System.out.printf("0x%02X%02X%02X%02X ", barr[i+3], barr[i+2], barr[i+1], barr[i]); System.out.print("\nSignature: 0x"); for(int i = 12; i<32; i+=4) System.out.printf("%02X%02X%02X%02X ", barr[i], barr[i+1], barr[i+2], barr[i+3]); System.out.printf("\nLength: 0x%02X%02X", barr[33], barr[32]); if(barr[36]!= 112) // currently is always 0x70==(int)112... System.out.printf("\n** Warning: Header Length; bad dex file or unsupported version loaded!"); System.out.printf("\nHeader Length: 0x%02X", barr[36]); // endian tag int endian = 0; for(int i = 0; i < 4; i++) endian += barr[40+i]; if(endian != 276) // Currently always should be 0x78563412, which when added = int 114 System.out.printf("\n** Warning: Endian Tag; bad dex file or unsupported version loaded!"); System.out.printf("\nEndian Tag: 0x%02X%02X%02X%02X", barr[40], barr[41], barr[42], barr[43]); // map offset System.out.printf("\nMap Offset: 0x%02X%02X", barr[53], barr[52]); // string table size System.out.printf("\nString Table Size: 0x%02X%02X", barr[57], barr[56]); // string table offset System.out.printf("\nString Table Offset: 0x%02X%02X", barr[61], barr[60]); // type table size System.out.printf("\nType Table Size: 0x%02X%02X", barr[65], barr[64]); // type table offset System.out.printf("\nType Table Offset: 0x%02X%02X", barr[69], barr[68]); // Prototype table size System.out.printf("\nPrototype Table Size: 0x%02X%02X", barr[73], barr[72]); // Prototype table offset System.out.printf("\nPrototype Table Offset: 0x%02X%02X", barr[77], barr[76]); // Field table size System.out.printf("\nField Table Size: 0x%02X%02X", barr[81], barr[80]); // Field table offset System.out.printf("\nField Table Offset: 0x%02X%02X", barr[85], barr[84]); // Method table size System.out.printf("\nMethod Table Size: 0x%02X%02X", barr[89], barr[88]); // Method table offset System.out.printf("\nMethod Table Offset: 0x%02X%02X", barr[93], barr[92]); // Class table size System.out.printf("\nClass Table Size: 0x%02X%02X", barr[97], barr[96]); // Class table offset System.out.printf("\nClass Table Offset: 0x%02X%02X", barr[101], barr[100]); System.out.println(); // add switch for this too? calcSignature(newbytes); calcChecksum(newbytes); System.out.print("\n\nNew Checksum: "); for(int i = 8; i<12; i+=4) System.out.printf("0x%02X%02X%02X%02X ", newbytes[i+3], newbytes[i+2], newbytes[i+1], newbytes[i]); System.out.print("\nNew Signature: 0x"); for(int i = 12; i<32; i+=4) System.out.printf("%02X%02X%02X%02X ", newbytes[i], newbytes[i+1], newbytes[i+2], newbytes[i+3]); System.out.printf("\nLength: %04X", calcSize(newbytes)); // output compares to the two, highlight differences... } catch (Exception e) { System.err.println("File input error"); } } else System.out.println("Invalid parameters"); } public static byte[] getBytesFromFile(File file) throws IOException { InputStream is = new FileInputStream(file); // Get the size of the file long length = file.length(); if (length > Integer.MAX_VALUE) { // File is too large } // Create the byte array to hold the data byte[] bytes = new byte[(int)length]; // Read in the bytes int offset = 0; int numRead = 0; while (offset < bytes.length && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) { offset += numRead; } // Ensure all the bytes have been read in if (offset < bytes.length) { throw new IOException("Could not completely read file "+file.getName()); } // Close the input stream and return bytes is.close(); return bytes; } private static void calcSignature(byte bytes[]) { MessageDigest md; try { md = MessageDigest.getInstance("SHA-1"); } catch(NoSuchAlgorithmException ex) { throw new RuntimeException(ex); } md.update(bytes, 32, bytes.length - 32); try { int amt = md.digest(bytes, 12, 20); if(amt != 20) throw new RuntimeException((new StringBuilder()).append("unexpected digest write: ").append(amt).append(" bytes").toString()); } catch(DigestException ex) { throw new RuntimeException(ex); } } private static void calcChecksum(byte bytes[]) { Adler32 a32 = new Adler32(); a32.update(bytes, 12, bytes.length - 12); int sum = (int)a32.getValue(); bytes[8] = (byte)sum; bytes[9] = (byte)(sum >> 8); bytes[10] = (byte)(sum >> 16); bytes[11] = (byte)(sum >> 24); } public static int calcSize(byte bytes[]) { return(bytes.length); } } |
This now dumps all the header information from the original file, and will recalculate the signature and checksum in case something has changed. A version should be available shortly to check for differences in all the values, hopefully soon being able to calculate the correct values if something is wrong.
Maybe this will be useful for someone? Otherwise, oh well it’s just here in case I delete my files. Working on functions to find the new values after patching and to allow patching/injection of code. I’ll have to write up more later as I don’t have an overwhelming amount of time right now, busy day and I’m exhausted. Saw Sara play some volleyball, finished up solo campaign in COD5, spent a few hours reading and researching some dex related things and trying to get some more injection to work. Tomorrow I probably won’t have time to post – but trust me, this stuff will be up sooner or later. It’s a big puzzle I’m chipping away at, and it’s bugging the heck out of me not having the answers.






Recent Comments