momo is a very popular social app in China,and it use some tech to protect it from reversing it。Using apktool to unpack and pack it normally, u get this:

2014.07.05-17.47.36 

Grep 盗版 or its UTF-8 code,nothing will be showed。So this keyword is eliminated from momo.

So how to solve it?

Running hierarchyviewer, we can see:

image

So we know the ID of the dialog to display this message is dialog_tv_message. Do this:

$ grep -r dialog_tv_message com.immomo.momo 
com.immomo.momo/res/values/public.xml:    <public type="id" name="dialog_tv_message" id="0x7f0703cd" /> 


$ grep -r 0x7f0703cd com.immomo.momo 
com.immomo.momo/smali/com/immomo/momo/android/view/a/y.smali:    const v0, 0x7f0703cd

Investigating a/y.smali, method a(Ljava/lang/CharSequence;) is called to display this message.

Adding divideZero() to its entry to get stacktrace:

07-05 19:26:17.053: E/AndroidRuntime(5490): java.lang.ArithmeticException: divide by zero 
07-05 19:26:17.053: E/AndroidRuntime(5490):     at com.westsword.ads.LogUtils.divideZero(LogUtils.java:32) 
07-05 19:26:17.053: E/AndroidRuntime(5490):     at com.immomo.momo.android.view.a.y.a(Unknown Source) 
07-05 19:26:17.053: E/AndroidRuntime(5490):     at com.immomo.momo.android.view.a.y.b(Unknown Source) 
07-05 19:26:17.053: E/AndroidRuntime(5490):     at com.immomo.momo.android.activity.account.k.a(Unknown Source) 
07-05 19:26:17.053: E/AndroidRuntime(5490):     at com.immomo.momo.android.c.d.a(Unknown Source) 
07-05 19:26:17.053: E/AndroidRuntime(5490):     at com.immomo.momo.android.c.d.onPostExecute(Unknown Source) 
07-05 19:26:17.053: E/AndroidRuntime(5490):     at android.os.AsyncTask.finish(AsyncTask.java:602) 

There is only one android.c.d.onPostExecute instance. And reading codes, we can know more about a.y.b(Unknown Source),  account.k.a(Unknown Source) and android.c.d.a(Unknown Source)

  • a.y.b(Unknown Source)=a.y.b(Landroid/content/Context;Ljava/lang/CharSequence;Landroid/content/DialogInterface$OnClickListener;)Lcom/immomo/momo/android/view/a/y;
  • account.k.a(Unknown Source)=account.k.a(Ljava/lang/Exception;)V
  • android.c.d.a(Unknown Source)=android.c.d.a(Lcom/immomo/momo/android/c/a;)

Reading c.d.a(…), there is on place calling account.k.a(…). Why?  account.k.a is a child class of c.d.a. So the codes of calling c.d.a(Ljava/lang/Exception;)V in c.d.a(…) may in fact to call account.k.a(Ljava/lang/Exception;)V.

So we need to pay more attention to account.k. onPostExecute means the asynTask completes, then call anroid.c.d.a(Lcom/immomo/momo/android/c/a;) to display the exception message. We need to know the logic before onPostExecute. The asynTask’s main logic lies in the function doInBackground(…).

  • Lcom/immomo/momo/android/c/d;->b([Ljava/lang/Object;)Lcom/immomo/momo/android/c/a;
  • Lcom/immomo/momo/android/c/d;->a([Ljava/lang/Object;)Ljava/lang/Object;

account.k overrides a([Ljava/lang/Object;)Ljava/lang/Object; That is the point.

Adding trace codes to differenct phase of this function, we see that

invoke-virtual/range {v0 .. v6}, Lcom/immomo/momo/protocol/a/ac;->a(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/lang/String;Ljava/util/concurrent/atomic/AtomicInteger;)Lcom/immomo/momo/service/bean/bq; 

never returns. Then it will call

  • invoke-virtual {p0, v3, v0}, Lcom/immomo/momo/protocol/a/ac;->a(Ljava/lang/String;Ljava/util/Map;)Ljava/lang/String;  

Adding codes to print ac;->a(…)’s arguments, we see

  • 07-05 21:10:23.083: I/LogUtils.printLog(6072): com/immomo/momo/protocol/a/ac;->a(…) v3:: https://api.immomo.com/api/v2/login
  • 07-05 21:10:23.086: I/LogUtils.printLog(6072): com/immomo/momo/protocol/a/ac;->a(…) v0:: {uid=4261dd518a2ab24e2ee820b7e2433f43, screen=540×960, model=ZTE V970, rqid=a5b6b437, rom=4.0.4, phone_type=GSM, device_type=android, router_mac=78:54:2e:e5:85:40, emu=0, mac=34:e0:cf:bf:3a:00, buildnumber=IMM76D/20120828.093925, password=xxxxxxxxxxxxxxxxxxxxx, ct=1404565823079193, apksign=???????????????????????????????, version=206, phone_netWork=1, network_class=wifi, osversion_int=15, account=18612531073, gapps=0, imsi=ca623d1141b4b046ea81194698b50e85, market_source=1, etype=2}

look at apksign=????????????????????????????????????, that is why momo know your apk is an illegal one.

So we need to know how v0 is calculated?

Looking at the implementation of

a/ac;->a(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/lang/String;Ljava/util/concurrent/atomic/AtomicInteger;)Lcom/immomo/momo/service/bean/bq;, 

v0 is derived from its arg p4. 

Lcom/immomo/momo/a;->F()Ljava/util/HashMap; is to calculate p4

We see “android”,”version”,”phone_type”etc, but not apksign. So where is apksign?

Adding trace code to print all jni/Codec;->(), we know Dse() return apksign. and com/immomo/momo/f;->ad() is to calculate apksign value.

We now know how apksign is calculated and sent to momo server to verify if the apk is illegal. And we can modify codes to always send legal apksign.

    const-string v0, "/sdcard/download/com.immomo.momo.apk" 

    invoke-direct {v7, v0}, Ljava/io/File;-><init>(Ljava/lang/String;)V 

/sdcard/download/com.immomo.momo.apk is where the legal momo apk is.

Repackaging and rerun, the dialog is now gone, but a new problem appears. 

2014.07.05-22.04.59

Next paper will analyze this, and give solution to it.

Advertisements