jesusfreke, the guy who wrote smali/baksmali, has some nice documentation on the smali syntax on the wiki for his project: http://code.google.com/p/smali/w/list i learned some stuff! thanks jesusfreke.
Wednesday, April 27, 2011
Wednesday, April 20, 2011
Simple List
Simple List Free is a small, intuitive and easy-to-use application. Designed to be able to create an unlimited amount of lists...you'll be organised before you know it!
Within each list you can add many entries, rank them them and check them off as completed.
Can be used for grocery lists, check lists, packing list, basically whereever there is a need for a list you can use Simple List. If all you want to do is manage lists without the bells and whistles then this is the
application for you.
application for you.
1. Creating a List
The first time you launch Simple List you will see the following screen:
To create your first list, enter the name of the list in the text box at the bottom of the screen. You should then select the add button or press the return key:
The Edit List Screen will then be opened:
You can add as many items to the list as you like by entering them into the text box at the bottom of the screen. As with adding lists you select the add button or press the return key to add an item to the list.
2. Quick Actions
You can select any List or List-Item by using a Long Press and a quick action bar will appear:
The options available are:
- Edit (List Only)
- Check/Uncheck (List-Item only)
- Remind (List-Item only)
- Send (List Only)
- Delete
- Rename
- Move Up
- Move Down
3. Gestures
A Single tap will open up a list.
A Long press will open the quick action bar
If you swipe across a List-Item it will check or uncheck this swiped List-Item.
A Long press will open the quick action bar
If you swipe across a List-Item it will check or uncheck this swiped List-Item.
Monday, April 18, 2011
antilvl 1.1.5
thanks to Notion and SuRViVe pointing out some instances of the lvl not being properly identified. i removed some requirements to match some key files that weren't likely necessary and were not being found recently. two new anti-cracking methods have been added and testtarget was updated appropriately.
grab it here:
http://androidcracking.blogspot.com/p/antilvl_01.html
grab it here:
http://androidcracking.blogspot.com/p/antilvl_01.html
Friday, April 8, 2011
antilvl 1.1.4
antilvl 1.1.4 has been released. main new feature is support for cracking amazon appstore drm. it also includes the apk i use to test new releases called testtarget.apk.
let me know if the new release breaks something :D
grab it here: http://androidcracking.blogspot.com/p/antilvl_01.html
let me know if the new release breaks something :D
grab it here: http://androidcracking.blogspot.com/p/antilvl_01.html
Saturday, April 2, 2011
cracking amazon drm
update: antilvl 1.1.4 can handle amazon drm protection.
amazon has an app store now and they rolled their own drm. Anonymous was kind enough to post a link describing how to crack the protection: http://pastebin.com/cFddguZX
there may be a cleaner solution, and if you find one you are encouraged to share it. here's the code from the above link but syntax highlighted:
the file name will likely always be different with obfuscation. just search for strings like "LICENSE_FAILURE_CONTENT" or "APPLICATION_LICENSE" and perform the three modifications mentioned above.
i'll be adding this functionality to the next release of antilvl. it will also contain a few more bypasses for anti-cracking techniques i've seen, and some improvements in lvl fingerprinting.
amazon has an app store now and they rolled their own drm. Anonymous was kind enough to post a link describing how to crack the protection: http://pastebin.com/cFddguZX
there may be a cleaner solution, and if you find one you are encouraged to share it. here's the code from the above link but syntax highlighted:
# virtual methods
.method public final a()V
.registers 6
const-string v4, "LICENSE_FAILURE_CONTENT"
iget-object v0, p0, Lcom/amazon/android/aa/d;->b:Lcom/amazon/android/o/d;
const-string v1, "APPLICATION_LICENSE"
invoke-virtual {v0, v1}, Lcom/amazon/android/o/d;->b(Ljava/lang/String;)Z
move-result v0
# Comment out first jump
#if-eqz v0, :cond_14
sget-object v0, Lcom/amazon/android/aa/d;->a:Lcom/amazon/android/u/a;
const-string v1, "license verification succeeded"
invoke-virtual {v0, v1}, Lcom/amazon/android/u/a;->a(Ljava/lang/String;)V
:goto_13
return-void
:cond_14
invoke-virtual {p0}, Lcom/amazon/android/aa/d;->f()Z
move-result v0
# Comment out second jump
#if-eqz v0, :cond_1d
invoke-virtual {p0}, Lcom/amazon/android/aa/d;->g()V
:cond_1d
new-instance v1, Lcom/amazon/android/l/m;
iget-object v0, p0, Lcom/amazon/android/aa/d;->b:Lcom/amazon/android/o/d;
const-string v2, "LICENSE_FAILURE_CONTENT"
invoke-virtual {v0, v4}, Lcom/amazon/android/o/d;->a(Ljava/lang/String;)Ljava/lang/Object;
move-result-object v0
check-cast v0, Lcom/amazon/android/l/d;
# Comment out third jump
#if-eqz v0, :cond_3d
iget-object v2, p0, Lcom/amazon/android/aa/d;->b:Lcom/amazon/android/o/d;
const-string v3, "LICENSE_FAILURE_CONTENT"
iget-object v2, v2, Lcom/amazon/android/o/d;->a:Lcom/amazon/android/o/b;
invoke-virtual {v2, v4}, Lcom/amazon/android/o/b;->c(Ljava/lang/String;)V
:goto_34
invoke-direct {v1, v0}, Lcom/amazon/android/l/m;->(Lcom/amazon/android/l/d;)V
iget-object v0, p0, Lcom/amazon/android/aa/d;->c:Lcom/amazon/android/l/f;
invoke-interface {v0, v1}, Lcom/amazon/android/l/f;->a(Lcom/amazon/android/l/a;)V
goto :goto_13
:cond_3d
sget-object v0, Lcom/amazon/android/aa/f;->e:Lcom/amazon/android/l/d;
goto :goto_34
.end method
the file name will likely always be different with obfuscation. just search for strings like "LICENSE_FAILURE_CONTENT" or "APPLICATION_LICENSE" and perform the three modifications mentioned above.
i'll be adding this functionality to the next release of antilvl. it will also contain a few more bypasses for anti-cracking techniques i've seen, and some improvements in lvl fingerprinting.
Thursday, March 31, 2011
spoof getinstallerpackagename with adb
as i wrote back in another post about anti-cracking technique examples, one method that is often used is getinstallerpackagename(). if the apk is installed from adb, it will be null, but if it's installed from the market it will be com.google.android.feedback. antilvl is well aware of this already, but there is an easier solution for when you're in a hurry. i learned it reading this post at tim's fantastic blog on reversing. he's not affiliated with me and for all i know he's an upstanding white hat who just loves hacking android.
all you need is adb. just give it this command either in a shell or as:
all you need is adb. just give it this command either in a shell or as:
adb install -i com.google.android.feedback com.protected.appthis will setup com.google.android.feedback as the installer for the com.protected.app. if you're not sure what the app name is for a given apk, just use aapt, from the android-sdk. ex: aapt d --values badging someapk.apk
Thursday, March 24, 2011
original smalihook java source
i've noticed some interest about a file that antilvl sometimes uses when cracking a program. it's called smalihook and it's purpose is to provide "hook" (actually replacement) methods for things like getting device id or signature. it's not really anything special, unless you actually modify the places in the app that make use of certain function calls. there is also a smalihook.java floating around that is actually a badly decompiled, broken version. i'd rather people have the real thing.
the variable strings that start with "%!" (ex: %!AppPackage%) are for antilvl to replace with the actual information when it copies it over.
if you want to use any of the functions here you can simply use antilvl.
if you just want to spoof your android_id or getdeviceid, try this: http://strazzere.com/blog/?p=217
the variable strings that start with "%!" (ex: %!AppPackage%) are for antilvl to replace with the actual information when it copies it over.
if you want to use any of the functions here you can simply use antilvl.
if you just want to spoof your android_id or getdeviceid, try this: http://strazzere.com/blog/?p=217
package lohan;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Random;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.content.pm.PackageManager.NameNotFoundException;
import android.telephony.TelephonyManager;
import android.util.Log;
/*
* TODO:
* I wonder if it's possible to check getClasses or getMethods to detect this
* hook
* Hooks:
* PackageManager
* getInstallerPackageName
* getPackageInfo
* getApplicationEnabledSetting
* checkSignatures
* getDeviceID - requires context
* File
* length
* lastModified
*/
public class SmaliHook {
// replace with random var per antilvl run
private static String PrefsFile = "HookSettings";
private static Context myAppContext = null;
// random - always random, permute - unreversible permutation
// session means until app is reinstalled
private static enum DEVICE_ID_SPOOF {
RANDOM, SESSION_RANDOM, SESSION_PERMUTE
};
private static DEVICE_ID_SPOOF myIDSpoof = DEVICE_ID_SPOOF.SESSION_RANDOM;
private static String LOG_TAG = "lohan";
private static boolean DEBUG = true;
private static boolean DUMP_STACK = false;
public static Object invokeHook(Method method, Object receiver,
Object[] args) throws IllegalArgumentException,
IllegalAccessException, InvocationTargetException,
NameNotFoundException {
boolean HookEnabled = true;
String methodClassName = "unknown-static";
String methodName = method.getName();
if ( receiver != null )
methodClassName = receiver.getClass().getName();
else methodClassName = method.getDeclaringClass().getName();
if ( DEBUG ) {
String logStr = "Invoke Hook: " + methodClassName + "."
+ methodName + "(";
if ( args != null ) {
String argStr = "";
for ( Object arg : args )
argStr += arg.getClass().getName() + ":" + arg + ", ";
if ( argStr.length() > 2 )
argStr = argStr.substring(0, argStr.length() - 2);
logStr += argStr;
}
Log(logStr + ")");
}
DumpStackIfWeShould();
if ( !HookEnabled ) return method.invoke(receiver, args);
if ( methodClassName
.equals("android.app.ContextImpl$ApplicationPackageManager")
|| methodClassName
.equals("android.app.ApplicationContext$ApplicationPackageManager")
|| methodClassName.equals("android.content.pm.PackageManager")
|| methodClassName.contains("ApplicationPackageManager") ) {
if ( methodName.equals("getInstallerPackageName") ) {
// Hook get installer package name
return getInstallerPackageName((String) args[0]);
}
else if ( methodName.equals("getPackageInfo") ) {
// Hook get package info for signatures
int flags = (Integer) args[1];
if ( methodClassName
.equals("android.content.pm.PackageManager") )
return SmaliHook.getPackageInfo(
((PackageManager) receiver), (String) args[0],
flags);
// Cannot simply recast receiver to
// ContextImpl.ApplicationPackageManager or we get error
Object result = null;
try {
result = method.invoke(receiver, args);
}
catch (Exception e) {
result = method.invoke(receiver, "%!AppPackage%");
}
if ( (flags & PackageManager.GET_SIGNATURES) == PackageManager.GET_SIGNATURES ) {
Signature[] spoofSigs = SmaliHook.spoofSignatures();
// should only need to spoof the first one
((PackageInfo) result).signatures[0] = spoofSigs[0];
}
return result;
}
else if ( methodName.equals("getApplicationEnabledSetting") ) {
int result = getApplicationEnabledSetting(
(PackageManager) receiver, (String) args[0]);
return (Object) Integer.valueOf(result);
}
else if ( methodName.equals("checkSignatures") ) {
// This could be detected by comparing a known installed package
// that will not match signatures. Will deal with that if it
// ever happens. :D
return checkSignatures((String) args[0], (String) args[1]);
}
}
else if ( methodClassName.equals("java.io.File") ) {
if ( shouldSpoofFileInfo((File) receiver) ) {
if ( methodName.equals("length") ) { return length((File) receiver); }
if ( methodName.equals("lastModified") ) { return lastModified((File) receiver); }
}
}
// No hooks, work as normal
return method.invoke(receiver, args);
}
public static int checkSignatures(String p1, String p2) {
Log("checkSignatures returning SIGNATURE_MATCH");
DumpStackIfWeShould();
return PackageManager.SIGNATURE_MATCH;
}
public static int checkSignatures() {
Log("checkSignatures returning SIGNATURE_MATCH");
DumpStackIfWeShould();
return PackageManager.SIGNATURE_MATCH;
}
public static String getInstallerPackageName(String packageName) {
// LIE and say installed from market :D
String result = "com.google.android.feedback";
Log("getInstallerPackageName returning " + result);
DumpStackIfWeShould();
return result;
}
public static int getApplicationEnabledSetting(PackageManager pm,
String packageName) {
int result;
try {
result = pm.getApplicationEnabledSetting(packageName);
}
catch (IllegalArgumentException ex) {
result = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
}
// Fake value if it's disabled
if ( result == PackageManager.COMPONENT_ENABLED_STATE_DISABLED )
result = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
Log("enabledSetting returning " + result);
DumpStackIfWeShould();
return result;
}
public static PackageInfo getPackageInfo(PackageManager pm,
String packageName, int flags) throws NameNotFoundException {
// Get regular package info
PackageInfo pi = null;
try {
pi = pm.getPackageInfo(packageName, flags);
}
catch (NameNotFoundException e) {
// Sometimes the app wants to know of other, helper apps are
// installed or if trial / nonfull versions are installed
// Fail normally if it's NOT checking for pro/full version stuff
if ( !(packageName.toLowerCase().contains("pro")
|| packageName.toLowerCase().contains("full")
|| packageName.toLowerCase().contains("donate") || packageName
.toLowerCase().endsWith("key")) )
throw new NameNotFoundException();
// Spoof with this package's info
pi = pm.getPackageInfo("%!AppPackage%", flags);
}
// Populate with fake signatures if flags ask for it
if ( (flags & PackageManager.GET_SIGNATURES) == PackageManager.GET_SIGNATURES ) {
Signature[] spoofSigs = SmaliHook.spoofSignatures();
for ( int i = 0; i < pi.signatures.length; i++ )
pi.signatures[i] = spoofSigs[i];
Log("spoofing signatures for " + packageName);
DumpStackIfWeShould();
}
return pi;
}
public static Signature[] spoofSignatures() {
final int certCount = Integer.parseInt("%!CertCount%");
Signature[] result = new Signature[certCount];
// Usually check signature of package and not individual files
// This will only fool checks of entire package
// Individual files would require a lot of smali generation
String replace = "%!SignatureChars%";
for ( int i = 0; i < certCount; i++ )
result[i] = new Signature(replace);
return result;
}
public static long length(File f) {
long retVal = Long.parseLong("%!OrigFileSize%");
if ( !shouldSpoofFileInfo(f) ) {
retVal = f.length();
Log("spoofing file length of " + f.getName() + " with " + retVal);
DumpStackIfWeShould();
}
return retVal;
}
public static long lastModified(File f) {
// long retVal = 1287850800968L;
long retVal = Long.parseLong("%!OrigLastModified%");
if ( DUMP_STACK ) Thread.dumpStack();
if ( !shouldSpoofFileInfo(f) ) {
retVal = f.lastModified();
Log("spoofing file modified of " + f.getName() + " with " + retVal);
DumpStackIfWeShould();
}
return retVal;
}
public static String getDeviceID() {
if ( myAppContext == null ) {
Log("getDeviceID has no context, can't spoof device id");
return "";
}
// final TelephonyManager tm = (TelephonyManager)
// myAppContext.getSystemService(Context.TELEPHONY_SERVICE);
// Log("this is my device id: " + tm.getDeviceId());
// fallback id
String spoofID = "359881030314356";
if ( myIDSpoof == DEVICE_ID_SPOOF.RANDOM )
spoofID = generateRandomDeviceID();
else {
SharedPreferences settings = myAppContext.getSharedPreferences(
PrefsFile, Context.MODE_PRIVATE);
spoofID = settings.getString("android_id", "");
if ( spoofID.length() == 0 ) {
if ( myIDSpoof == DEVICE_ID_SPOOF.SESSION_RANDOM )
spoofID = generateRandomDeviceID();
else if ( myIDSpoof == DEVICE_ID_SPOOF.SESSION_PERMUTE )
spoofID = getPermutedDeviceID();
SharedPreferences.Editor editor = settings.edit();
editor.putString("android_id", spoofID);
editor.commit();
}
}
Log("spoofing device id: " + spoofID);
return spoofID;
}
private static boolean shouldSpoofFileInfo(File f) {
boolean result = false;
if ( f.exists() ) result = false;
if ( f.getName().contains("%!AppPackage%")
&& f.getName().endsWith(".apk") ) result = true;
return result;
}
public static void SetAppContext(Context c) {
if ( myAppContext == null ) myAppContext = c;
}
private static String getPermutedDeviceID() {
// permute device id
final TelephonyManager tm = (TelephonyManager) myAppContext
.getSystemService(Context.TELEPHONY_SERVICE);
// lazy lazy lazy http://www.random.org/sequences/
// this is a permutation with a loss of information
// prevent anyone from knowing the id even if they knew the mapping
final int[] p = { 12, 2, 10, 2, 13, 8, 0, 3, 14, 3, 6, 9, 5, 1, 12 };
String deviceId = tm.getDeviceId();
String result = "";
if ( deviceId != null ) {
for ( int i : p )
result += deviceId.charAt(i);
}
return result;
}
private static String generateRandomDeviceID() {
// device id is 15 digit number with seemingly no pattern
// only changed by factory reset or with root
// ex: 359881030314356 (emulators is all 0s)
return generateString("0123456789", 15);
}
private static String generateString(String charSet, int length) {
Random rng = new Random();
char[] text = new char[length];
for ( int i = 0; i < length; i++ )
text[i] = charSet.charAt(rng.nextInt(charSet.length()));
return new String(text);
}
public static void Log(Object o) {
if ( !DEBUG ) return;
Log.d(LOG_TAG, String.valueOf(o));
}
public static void DumpStackIfWeShould() {
if ( !DUMP_STACK ) return;
DumpStack();
}
public static void DumpStack() {
StackTraceElement[] ste = Thread.currentThread().getStackTrace();
// skip the first 4, it's just local stuff
String trace = "Stack trace:\n";
for ( int i = 4; i < ste.length; i++ )
trace += " " + ste[i].toString() + "\n";
Log.d(LOG_TAG, trace);
}
public static void Toast(Object o) {
// todo: implement
}
}
Subscribe to:
Posts (Atom)