PPPP API: what I know

While analyzing security of iMiniCam app, I learned some part of UDP protocol used to communicate with the camera. Here is quick bunch of facts.

UDP layer

Port 32100 (Proto_Hello, to external server) and port 32108 (others, to camera).

Type-length layer

Following structure represents first header that is always found in datagram.

struct header {
  uint8_t magic;
  enum proto_type type;
  uint16_t length;
}

In this structure magic is always set to 0xf1, type is one of the below values, packed on single byte and length count data that follows this packet, so if it is equal to zero, only those four bytes are transmitted.

Packet types

These are all the types present in binary, I was reverse engineering. Names are derived from function names that crafts their content, so i.e. for Proto_DevLgn that is equal to 0x10 there exists function PPPP_Proto_Write_DevLgn, PPPP_Proto_Read_DevLgn and PPPP_Proto_Send_DevLgn.

enum proto_type {
  Proto_Hello = 0;
  Proto_HelloAck = 1;
  Proto_HelloTo = 2;
  Proto_HelloToAck = 3;
  Proto_QueryDID = 8;
  Proto_QueryDIDAck = 9;
  Proto_DevLgn = 0x10;
  Proto_DevLgnAck = 0x11;
  Proto_DevLgn_CRC = 0x12;
  Proto_DevLgn1_CRC = 0x13;
  Proto_P2PReq = 0x20;
  Proto_P2PReqAck = 0x21;
  Proto_LanSerch = 0x30;
  Proto_PunchTo = 0x40;
  Proto_PunchPkt = 0x41;
  Proto_P2PRdy = 0x42;
  Proto_RSLgn = 0x60;
  Proto_RSLgnAck = 0x61;
  Proto_RSLgn1 = 0x62;
  Proto_RSLgn1Ack = 0x63;
  Proto_ListReq1 = 0x67;
  Proto_ListReq = 0x68;
  Proto_ListReqAck = 0x69;
  Proto_RlyHello = 0x70;
  Proto_RlyHelloAck = 0x71;
  Proto_RlyPort = 0x72;
  Proto_RlyPortAck = 0x73;
  Proto_ByteCount = 0x78;
  Proto_RlyReq = 0x80;
  Proto_RlyReqAck = 0x81;
  Proto_RlyTo = 0x82;
  Proto_RlyPkt = 0x83;
  Proto_RlyRdy = 0x84;
  Proto_SDevRun = 0x90;
  Proto_SDevLgn = 0x91;
  Proto_SDevLgn_CRC = 0x92;
  Proto_DRWAck = 0xd1;
  Proto_PSR = 0xd8;
  Proto_Alive = 0xe0;
  Proto_AliveAck = 0xe1;
  Proto_Close = 0xf0;
  Proto_MGMDumpLoginDID = 0xf4;
  Proto_MGMDumpLoginDIDDetail = 0xf5;
  Proto_MGMDumpLoginDID1 = 0xf6;
  Proto_MGMLogControl = 0xf7;
  Proto_MGMRemoteManagement = 0xf8;
}

Proto_Hello

This packet’s content is empty (length=0). Sent to external server. Response is Proto_HelloAck.

Proto_HelloAck

Length is 0x10. Content is according to following structure:

struct HelloAck {
  struct sockaddr_in wan_addr;
}

Final word

I hope this very quick introduction will help someone and will lead to documenting the protocol, in enough part, that it will be possible to develop open source client application able to communicate with the cameras using it.

Security analysis of spy camera sold by Chinese suppliers: iMiniCam app

Lately, I bought some random, noname spy camera from usual Chinese sources. Just after unboxing, one detail seemed a bit suspicious to me: together with the camera there comes a link to Android app, that is meant to control the camera. What is worse, the link leads to some Chinese app shop, obviously with only one language available (notice the version – 1.0.33, as it is not the only one in the wild):

http://m.app.so.com/detail/index?pname=com.hbwy.fan.iminicams&id=3646142

As I’ve already seen apps that i.e. calls home, despite having no need to open a single socket and then sending data like IMEI, IMSI, MAC addresses and so on, red lamp turned on and I said to myself: stop. Let’s reverse engineer the thing first!

OSINT

Before I begun my reverse engineering, I attempted to ask uncle Google (and his friends 🙂 ) to gain some knowledge. Usual virustotal gives me this:

Results of virustotal scan of original link (click for details)

Not bad for such a simple application. Searching other shops for the same name leaded to exactly the same application (shared objects included matches), but older version (1.0.25) and in their case virustotal stopped complaining. For me there are two possible reason for that:

  1. Google Play app is not supported by vendor anymore
  2. There is special edition for Chinese, with few surprises

In favor of the second option is the fact that Java code of only the China edition is heavily bloated and usual decompilers cannot reverse the code properly, so somebody tried to make reverse engineer’s life harder. In apk downloaded from downloadapk.net and apkplz.com, everything seem to be fine.

Below are the links, I’ve used in comparison:

  1. Google Play: https://play.google.com/store/apps/details?id=com.hbwy.fan.iminicams (1.0.25)
  2. downloadapk.net: https://downloadapk.net/down_IPLiveCam.html (1.0.25)
  3. apkplz.com: https://apkplz.com/android-apps/iplivecam-apk-download (1.0.25)

Just for completeness, below is the name and webpage of suspected vendor of the stuff, I found accidentally: Albert Technology Co., Ltd. Shenzhenshihong Bo, and their webpage is here: http://www.honest-tech.com/en/

Let’s reverse then

First thing,I’ve noticed after decompilation of APK’s Java classes is:

  public static String a(String paramString)
  {
    if (paramString == null)
      return "";
    if (paramString.length() == 0)
      return "";
    paramString = new BigInteger(paramString.getBytes());
    return new BigInteger("0933910847463829232312312").xor(paramString).toString(16);
  }

  public static String b(String paramString)
  {
    if (paramString == null)
      return "";
    if (paramString.length() == 0)
      return "";
    BigInteger localBigInteger = new BigInteger("0933910847463829232312312");
    try
    {
      paramString = new String(new BigInteger(paramString, 16).xor(localBigInteger).toByteArray());
      return paramString;
    }
    catch (Exception paramString)
    {
    }
    return "";
  }

So, it’s gonna be interesting… As it turns out this one seem to be unused. But, after going a bit further and searching for all hardcoded strings I found this:

cfans/ufo/sdk/d/a.java:37:    PPPP_APIs.PPPP_Initialize("EBGDEIBIKEJOGCJNEBGBFDEOHJNDHANKGEFCBNCJAPJILDLIDEABCLOKGMLNJBKDALMNLKDOONMGAFCJJKNHJN".getBytes());

PPPP is shared object linked to the app via NDK, so I started reversing this libPPPP_API.so. Not so long time later, I was able to see decoded string by running the library and connecting gdb to it:

(gdb) p (char*)$sp+0xc
$16 = 0xbefff78c "121.40.184.33,120.25.151.105,120.25.157.75,"

I’ve check the addresses in whois database and all of them leads to Hangzhou, Zhejiang, China.

Next to decoding of these addresses, there is UDP socket opening routine and at least two ports are used: 32100 and 32108, where first one is used to connect to these services (all three of them) and port 32108 seem to be the port of camera.

What is my IP address?

So far, I identified at least one request that for sure goes to the hardcoded server, so in fact it is used to call home. This is the so called hello request. It sends nothing at all, as can be seen below:

00000000  f1 00 00 00                                       |....|
00000004

[len] [magic] [typ]

And in response it gets packet like that:

00000000  f1 01 00 10 00 02 7b 3d  xx xx xx xx 00 00 00 00  |......{=........|
00000010  00 00 00 00                                       |....|
00000014

[len] [magic] [sockaddr_in] [typ]

Content of this packet is then cast to sockaddr_in packet and experimentally, I was able to tell that it contains WAN address of requesting side (this is the censored part). I haven’t noticed the original sockaddr_in, that was used to send this hello message in memory, so chances are this is the only purpose of that server.

However, there are a lot of other datagrams crafted from same function as this one (including so called P2P requests), so I cannot guarantee I haven’t missed anything. In my opinion, further dynamic analysis is required. And I want to do one either way.

Other indicators?

Beside these suspicious addresses, I noticed some ioctl usage, but this seem to be quite legit. It just checks configuration of network interfaces (the worst that can happen out of this is sending somewhere MAC address of all interfaces available, that is both WiFi and cellular).

I focused my analysis on libPPPP_API, but beside that, there exists also UFO SDK and Adpcm codec. While Adpcm can be considered safe, as it does not import anything weird, UFO SDK is suspicious, just like PPPP API. Maybe little less, as it does not seem to obfuscate any strings. Nevertheless, it opens some sockets,probably only for RTP, but still.

Conclusion

The most important recommendation is to never trust any source of APKs beside official shops, most notably Google Play, as in it there exist some administration staff, that can react in case of obvious malware (how often and in which cases they do is another story). As can be seen in this case, either app vendor, or a shop is attaching some stuff, which is recognized as malware. In case of Google Play variant (and other Play-cloning shops), things are much better and no alert is raised by VirusTotal.

Second point is how to treat the fact of calling home, especially in situation where app vendor tries to hide the fact by obfuscating the string that contains the addresses. In my opinion, it is enough to not let that app do anything outside some closed network (with no means of sending packet to the internet), at least to be able to check the behavior in practice. And this is probably what I am going to try next. However, I can imagine that I will be using the app, despite that, but after banning these three servers. I can also understand that most people will ignore that fact (or even more – will be unaware of that), as in today’s world there is such a huge amount of services that are gathering our data, that it is impossible to block them all.

To sum up, if you want to use it, download from Google Play and keep in mind, some data might leak somewhere on he Chinese coast.

PS: I am not planning to publish complete API, which I am in theory able to reverse engineer. However, expect some quick summary of what I already know about the protocl 🙂