In this chapter, we continue describing some of the trojan components. We realized that the code contains some ServerSocket stuff so let’s take a look at the system.
To obtain more information about a process on android we can upload the lsof tool to a rooted via adb tools. You can download the lsof static file here http://android-group-korea.googlecode.com/files/lsof.arm926ejs.static [no longer available].
To use the Android Debug Bridge (ADB) the device needs to have the debug mode enable:
Settings > Applications > Development > USB Debugging
Then connecting the device to the host computer using a USB cable or using the android emulator to simulate a phone we can use the adb tools. To upload the lsof binary:
jaime:tools jaimeblasco$ ./adb push lsof.static /data/ 633 KB/s (3517525 bytes in 5.420s)
I recommend you to upload a busybox binary as well in order to be able to use commands like grep, find… You can obtain a busybox binary here
Then we can obtain a shell on the device running adb shell:
jaime:tools jaimeblasco$ ./adb shell # id uid=0(root) gid=0(root) # cd /data/ # chmod 777 busybox # chmod 777 lsof.static
Now we can use lsof to list interesting data about our process:
# ps|./busybox grep -i monk app_32 526 33 109024 19224 ffffffff afd0eb08 S com.dseffects.MonkeyJump2 # ./lsof.static -p 526 2>/dev/null COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME ... ... cts.Monke 526 10032 0u CHR 1,3 42 /dev/null cts.Monke 526 10032 1u CHR 1,3 42 /dev/null cts.Monke 526 10032 2u CHR 1,3 42 /dev/null cts.Monke 526 10032 3w CHR 10,58 55 /dev/log/main cts.Monke 526 10032 4w CHR 10,56 57 /dev/log/radio cts.Monke 526 10032 5w CHR 10,57 56 /dev/log/events ... ... cts.Monke 526 10032 10u unix 0xc9f610c0 2515 socket ... ... cts.Monke 526 10032 20u unix 0xc9fdb260 2519 socket ... ... cts.Monke 526 10032 26r REG 31,1 570420 284 /data/app/com.dseffects.MonkeyJump2-1.apk cts.Monke 526 10032 27r REG 31,1 570420 284 /data/app/com.dseffects.MonkeyJump2-1.apk cts.Monke 526 10032 28r REG 31,1 570420 284 /data/app/com.dseffects.MonkeyJump2-1.apk cts.Monke 526 10032 29u IPv4 2534 TCP *:5432 (LISTEN)
I have removed almost all the data, you can access a complete dump here http://alienvault-labs-garage.googlecode.com/svn/trunk/geinimi/lsof_geinimi.txt [no longer available]
As you can see the process has a listening socket on port 5432
Let’s start inspecting the code with the purpose of interacting with the listening socket. Before we begin looking at the code, this document comes handy to understand the Dalvik opcodes.
The thread that starts and manages the socket is defined in ./smali/com/dseffects/MonkeyJump2/jump2/j.smali
As we can see a ServerSocket object is created (from Lcom/dseffects/MonkeyJump2/jump2/e;->c), the accept() method is called and it returns a socket object to access java/io/InputStream and java/io/OutputStream to receive and send data. Let’s see how the ServerSocket is created:
Following the code we can see how the ServerSocket is created listening on port 0x15t 0x38t => 5432.
So, let’s continue analyzing the run() method of the previous j class.
Once the connection is established, the thread reads 256 bytes from the socket and builds a string, if the data received is “hi,are you online?” the program answer with he string “yes,I‘m online!”.
Then the client should send two bytes that the program will use later. Finally it sends 0xa 0x05 and closes the connection.
Based on the two bytes sent, the program does some checks.
It gets the string [const-string v0, “10.7”] from Lcom/dseffects/MonkeyJump2/jump2/e/k;->f() and split the string saving the integers to v0 and v1 respectively.
Then if the first byte we sent (v3) is greater than v1 (7) the program jumps to :cond_0.
Basically the program set a boolean variable on the service object that makes the service not to restart if the service stops. Finally it calls stopSelf() function to stop the service.
Let’s use this little script http://alienvault-labs-garage.googlecode.com/svn/trunk/geinimi/geinimi_comm.py [no longer available] to recreate the communication to restart the service.
jaime:tools jaimeblasco$ python geinimi_comm.py 192.168.1.32 5432 Received "yes,I'm online!" Sending 'p' Received ' ' Received ''
If we take a look at the android event log using "logcat -b events", we see that a destroy_service request has been sent
I/am_destroy_service( 61): [1140917416,com.dseffects.MonkeyJump2/.jump2.c.AndroidIME,301]
I have written a nmap script to remotely check the presence of the trojan. Download http://alienvault-labs-garage.googlecode.com/svn/trunk/geinimi/geinimi.nse [no longer available]
jaime:nmap-5.35DC1 jaimeblasco$ ./nmap -v --script=geinimi -p5432 192.168.1.32 Starting Nmap 5.35DC1 ( http://nmap.org ) at 2011-01-04 17:49 CET NSE: Loaded 1 scripts for scanning. Discovered open port 5432/tcp on 127.0.0.1 Completed Connect Scan at 17:49, 0.00s elapsed (1 total ports) NSE: Script scanning 127.0.0.1. NSE: Starting runlevel 1 (of 1) scan. Initiating NSE at 17:49 Completed NSE at 17:49, 5.00s elapsed Nmap scan report for localhost (127.0.0.1) Host is up (0.00013s latency). PORT STATE SERVICE 5432/tcp open postgresql |_geinimi: Geinimi trojan present
My conclusion is that the authors used this service during development but maybe the service was made to detect compromised phones. What do you think?.
On the other hand Tim Strazzere from Lookout, has just told me a better theory: he discovered that the 10.7 string is the SDK version so this is a way to update the trojan version.