Awesome Android eXtreme Hacking. Part II (Sensors)

Awesome Android eXtreme Hacking Part I HeaderAwesome Android eXtreme Hacking Part I Header


NOTE
This article has already been moved to the our new blog. Please update any link to this post as it will be removed in the future. This post is available clicking the link below:

http://papermint-designs.com/dmo-blog/2016-04-awesome-android-extreme-hacking--part-ii-sensors

Welcome back to the Awesome Android eXteme Hacking Tutorial. Hope you are ready for some more awesomeness :). In the last issue (http://papermint-designs.com/community/node/419) we learn how to create and run a C application on our Android phone. That allows you to build almost any application that does not require access to special features on your phone, in other words, pretty much any standard console based UNIX application.

Now we are going one step further hacking into your phone sensors. Yes, you phone is full of sensors and peripherals: Buttons, Touchscreen, accelerometers, gyroscopes and even temperature and pressure sensors. Android provides APIs to access those sensors from Java in a convenient way, but we want to hack into them, because that is a lot more awesome!... So, let's start.

The first thing we need to know is that the sensors are managed by the kernel and exposed to the user space through a device driver... you know, those files in the /dev folder. For the specific case of the sensors we will have to look into the so-called input devices. These devices are used by the Linux kernel to deliver events to the user space whenever something needs to be reported... This is how keyboards, mouses or joysticks reports which key had been pressed or in which direction the mouse or joystick have moved.

As you already know, or at least you can imagine, not all devices provide information this way, however, this seems to be the way Android had chosen to report data from sensors.... Let's do a quick check.

First, check that you PATH allows you to run adb and get into your device. Then, use the getevent tool to get a list of sensors and start receiving events. This is what getevents shows on my Samsung S4.

NOTE: Press CTRL+C after running the command to stop receiving events and to be able to check the list of devices.

~/aaxh $ adb shell
/ $ getevent
add device 1: /dev/input/event19
  name:     "sec_touchkey"
add device 2: /dev/input/event2
  name:     "max77693-muic"
add device 3: /dev/input/event0
  name:     "pmic8xxx_pwrkey"
add device 4: /dev/input/event17
  name:     "apq8064-tabla-snd-card Headset Jack"
add device 5: /dev/input/event16
  name:     "apq8064-tabla-snd-card Button Jack"
add device 6: /dev/input/event18
  name:     "gpio-keys"
add device 7: /dev/input/event15
  name:     "ssp_context"
add device 8: /dev/input/event14
  name:     "step_cnt_sensor"
add device 9: /dev/input/event13
  name:     "step_det_sensor"
add device 10: /dev/input/event12
  name:     "sig_motion_sensor"
add device 11: /dev/input/event11
  name:     "geomagnetic_sensor"
add device 12: /dev/input/event10
  name:     "temp_humidity_sensor"
add device 13: /dev/input/event9
  name:     "proximity_sensor"
add device 14: /dev/input/event8
  name:     "light_sensor"
add device 15: /dev/input/event7
  name:     "gesture_sensor"
add device 16: /dev/input/event6
  name:     "pressure_sensor"
add device 17: /dev/input/event5
  name:     "gyro_sensor"
add device 18: /dev/input/event4
  name:     "accelerometer_sensor"
add device 19: /dev/input/event1
  name:     "sii8240_rcp"
could not get driver version for /dev/input/mice, Not a typewriter
add device 20: /dev/input/event3
  name:     "sec_touchscreen"
You would probably get a quite different list of sensors. Do not panic. In this tutorial we will be using the touchscreen (device 20 in the list above) ... and ... every Android phone has one of those :). Now we need to find out how to read and interpret those events. As you my had noted, every device has a /dev entry associated. Those are the files we have to read in order to get the data we want. Let's try to read the events from the touchscreen device. You will probably have to activate the screen to get events (press the power button to get into the lock or home screen)
/ $ cat /dev/input/event3
???
Well, Those weird characters are not very useful... don't they?. We need to parse them. Fortunately for us, those input devices sends data out using a well-known format... the EEEVEEEENTTSSSS!!!. You can get more information about the whole thingreading the Documentation folder of the Linux kernel. If you do not have the Linux Kernel source code on your hard drive (shame on you), you can check the documents on-line here https://www.kernel.org/doc/Documentation/input/input.txt and here https://www.kernel.org/doc/Documentation/input/event-codes.txt. At the very end of the first link you will find the definition of the event structure that we reproduce here for your convenience.
struct input_event {
	struct timeval time;
	unsigned short type;
	unsigned short code;
	unsigned int value;
};
As you can see, it is a binary structure (that is what we get all those weird martian characters on the console) containing a timestamp, a type, a code and a value. The possible values for those three last fields ares described in the second kernel document linked above. The output from getevent is pretty useful, but in order to get a better insight on our phone's sensors, it would be very useful to get a more comprehensive description of the events. And now is when evtest.c (http://elinux.org/images/9/93/Evtest.c) comes to the rescue. This is a standard GNU/Linux application that you can easily find on Internet (we had already provided the link :). A version is included in the source code package for this tutorial. The most interesting thing about this application is that it provides a very convenient skeleton to develop our sensor monitor applications. Anyway, let's compile it, upload it and run it (check part I of the AAXH http://papermint-designs.com/community/node/419). You should get an output like this (remember to change your device if required)
/data/local/tmp $ ./evtest /dev/input/event3                   
Input driver version is 1.0.1
Input device ID: bus 0x18 vendor 0x0 product 0x0 version 0x0
Input device name: "sec_touchscreen"
Supported events:
  Event type 0 (Sync)
  Event type 1 (Key)
    Event code 325 (ToolFinger)
    Event code 330 (Touch)
  Event type 3 (Absolute)
    Event code 47 (?)
      Value      0
      Min        0
      Max        9
    Event code 48 (?)
      Value      0
      Min        0
      Max      255
    Event code 49 (?)
      Value      0
      Min        0
      Max      255
    Event code 50 (?)
      Value      0
      Min        0
      Max      255
    Event code 53 (?)
      Value      0
      Min        0
      Max     1079
    Event code 54 (?)
      Value      0
      Min        0
      Max     1919
    Event code 57 (?)
      Value      0
      Min        0
      Max    65535
    Event code 59 (?)
      Value      0
      Min        0
      Max      255
    Event code 60 (?)
      Value      0
      Min        0
      Max       90
    Event code 61 (?)
      Value      0
      Min        0
      Max        1
  Event type 5 (?)
    Event code 22 (?)
Testing ... (interrupt to exit)
Pretty good. This tool already gives us some details about the events we should expect from the device. We can try to wonder what they mean or we can just swipe our finger on the screen and see what we get: Note: Remember to switch on the screen if you are not getting any events
...
Event: time 140136.107859, type 1 (Key), code 330 (Touch), value 1
Event: time 140136.107889, type 3 (Absolute), code 53 (?), value 85
Event: time 140136.107889, type 3 (Absolute), code 54 (?), value 1129
....
Event: time 140136.207011, -------------- Report Sync ------------
Event: time 140136.218760, type 3 (Absolute), code 53 (?), value 186
Event: time 140136.218760, type 3 (Absolute), code 54 (?), value 1111
Event: time 140136.218760, type 3 (Absolute), code 60 (?), value -90
Event: time 140136.218790, -------------- Report Sync ------------
Event: time 140136.230479, type 3 (Absolute), code 53 (?), value 246
Event: time 140136.230479, type 3 (Absolute), code 54 (?), value 1106
Event: time 140136.230509, type 3 (Absolute), code 60 (?), value -82
Event: time 140136.230509, -------------- Report Sync ------------
Event: time 140136.418314, -------------- Report Sync ------------
Event: time 140136.429636, type 3 (Absolute), code 57 (?), value -1
Event: time 140136.429697, type 1 (Key), code 330 (Touch), value 0
Event: time 140136.429697, -------------- Report Sync ------------
We had removed many of the events on the output, and just keeping the ones relevant for our current discussion. Those are the ones:
  • Type 3. Code 53 -> X coordinate
  • Type 3. Code 54 -> Y Coordinate
  • Type 3. Code 57 -> Tap counter
  • Type 1. Code 330 -> Touch
So far, so good. But...once again, you might be wondering... what's awesome about this?... a bunch of number in a console?... are you kidding me?... OK, you are right... let's do some awesome stuff. What about detecting gestures on the touch screen to launch specific applications at any time?... isn't this awesome or what?! So, let's implement a very simple gesture recognizer. Probably the simplest way to recognise basic gestures on a touch screen is to use a low resolution grid. We will first find out what is the range of the values reported by the input device. Scale those values down to a 3x3 matrix and number the matrix entries as we move our finger over the touch screen. Pretty easy... The algorithm may be something like this:
  • If we touch the screen start gesture recognition.
  • Initialise a counter to zero
  • Get the touch screen event and extract the coordinates.
  • Divide the horizontal one by width/3 and the vertical one by height/3.
  • If the coordinates changed since last check, increase the counter
  • Use those values to set the matrix cell to the counter
  • If we stop touching the screen
  • reset and start with new gesture
  • Check the matrix pattern and launch the associated application
The whole application can be found on the source code for this tutorial (check the link at the end of the text), including the algorithm described above. You might need to tweak it for your device resolution or maybe chose different events to detect the start/stop of the gesture, after all this is a hacking tutorial... you should start doing some hacking on your own. A hint for the first problem, check evtest.c source code. Let's go on. This is what we get on the adb shell console when running the application and swiping right and then left.
$ ./touch /dev/input/event3     
Input device name: "sec_touchscreen"
Gesture Started
(0,1) = 1
(1,1) = 2
(2,1) = 3
Gesture Finished
0 0 0 
1 2 3 
0 0 0 
Gesture Started
(2,1) = 1
(1,1) = 2
(0,1) = 3
Gesture Finished
0 0 0 
3 2 1 
0 0 0 
You can see how the application detects that we had started a gesture and then starts to populate the 3x3 matrix with a counter as we swipe our finger left to right. When we detect that the gesture is finished the final matrix (or recognizer pattern) is dump for easy visualisation of the gesture. Using the counter provides us with a rudimentary way to detect the direction of the gesture. Now we need a second function to map our gesture vector (or matrix if you prefer) to the application we want to launch. But first, let's define a convenient structure to hold our command and the associated pattern.
#define SIZE 3
#define SIZE2 3 * 3

typedef struct pat_t
{
  char *cmd;
  int pat[SIZE2];

} PAT;
Based on that structure, a simple matching function will look like this:
int
match_pat ()
{
  int  i, j;
  int  found;

  for (i = 0; pat_cmd[i].cmd; i++, found = 0)
    {
      for (j = 0; j < SIZE2; j++) 
	{
	  found = 0;
	  if (_pat[j] != pat_cmd[i].pat[j]) break;
	  found = 1;
	}
      if (found) return i;
    }
  return -1;
}
NOTE: This is not the final code of the function, but is convenient right now :) Now we just need to define and fill our pat_cmd array. Let's use a couple of gestures to start our Hello Android from Web application introduced in the previous AAXH tutorial. When we swipe from left to right on the bottom part of the screen we launch our minimal webserver, and when we swipe from bottom to top we kill it....
static PAT pat_cmd[] = {
  {"/data/local/tmp/hellow &",
   {0, 0, 0,
    0, 0, 0,
    1, 2, 3} 
  },
  {"kill $(pidof hellow)", 
   {0, 3, 0,
    0, 2, 0,
    0, 1, 0}
  },
  {NULL, 
   {-1,-1,-1,
    -1,-1,-1,
    -1,-1,-1}
  }
};
Not bad, but that is not that much awesome. What about launching some Android applications?. Let's modify our data structure to launch the camera with the first gesture, and a web browser pointing to an awesome site with the second...
static PAT pat_cmd[] = {
  {"am start -a android.media.action.IMAGE_CAPTURE",
   {0, 0, 0,
    0, 0, 0,
    1, 2, 3} 
  },
  {"am start http://papermint-designs.com/community", 
   {0, 3, 0,
    0, 2, 0,
    0, 1, 0}
  },
  {NULL, 
   {-1,-1,-1,
    -1,-1,-1,
    -1,-1,-1}
  }
};
We are pretty sure all the readers can figure out what the two gestures defined in the structure above does. But... wait!, what is that "am start" thingy?. Good catch little grasshopper. You had spotted the Activity Manager... OMG! The am command allows you to do a lot of stuff with the Android activities. Just type am on the command line to get a list of options, or check this site for more human-readable details (http://developer.android.com/tools/help/adb.html#am). For the lazy reader, what we are doing, is using the Activity Manager to launch standard Android application using Intents. An intent is something like a generic application execution. We tell the system, for instance, that we want to see a web site, and then the system, either uses the default application for web browsing or provides you with a list of applications that can be used for that INTENTION. Our example uses the camera and the web browsing, but you can experiment with others. Check this page for a extensive list (https://developer.android.com/guide/components/intents-common.html). So, this concludes the second part of the Android Awesome eXtreme Hacking tutorial. We still have to say a couple more things about sensors, but that will come later. You can download the code from this link (http://papermint-designs.com/picoflamingo/download/aaxh02-code.tgz) Happy hacking! Awesome Welles