MicroTrend – Android – VirusClicker

Hi!

I recently discover Xposed, a great framework to hook methods in android application. You don’t even need to modify / recompile /sign the apk.

So I wanted to see how we can use this framework to solve CTF challenges. I tried it with MicroTrend Virusclicker challenge and it was successful.

To do it you need:

  • Genymotion (Android emulator). Any other should work too.
  • Jd-gui (read .jar source code)
  • XPosed framework
  • Android visual studio

 

I will not go through the full process to setup this environment. Sorry đŸ˜›

You can download the APK from github.

As usual with a .apk we are going to transform it to a jar:

$ d2j-dex2jar VirusClicker.apk
dex2jar VirusClicker.apk -> VirusClicker-dex2jar.jar
public class Bypass implements IXposedHookLoadPackage {

    public static int i = 0;
    public static int j = 0;
    public static boolean doit=true;
    public static  Timer timer;
    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable{
        if(lpparam.packageName.equals("com.tm.ctf.clicker")) {

            XposedBridge.log("Loaded App: " + lpparam.packageName);

            XposedHelpers.findAndHookMethod("com.tm.ctf.clicker.activity.c", lpparam.classLoader, "onTouchEvent", MotionEvent.class, new XC_MethodHook() {

              
                @Override
                protected void afterHookedMethod(final MethodHookParam param) throws Throwable {
                    if(timer==null) {
                        timer = new Timer();
                    }

                    final Object object = param.thisObject;
                    if(i>10000000) {
                        timer.cancel();
                    }

                    if(doit) {
                            doit = false;
                        for(int j=0;j<1000;j++) {
                            timer.scheduleAtFixedRate(new TimerTask() {
                                @Override
                                public void run() {
                                    // Obtain MotionEvent object
                                    long downTime = SystemClock.uptimeMillis();
                                    long eventTime = SystemClock.uptimeMillis() + 1;
                                    float x = 5.0f;
                                    float y = 5.0f;
// List of meta states found here: developer.android.com/reference/android/view/KeyEvent.html#getMetaState()
                                    int metaState = 0;
                                    MotionEvent motionEvent = MotionEvent.obtain(
                                            downTime,
                                            eventTime,
                                            MotionEvent.ACTION_UP,
                                            x,
                                            y,
                                            metaState
                                    );

                                    XposedHelpers.callMethod(object, "dispatchTouchEvent", motionEvent);
                                    i++;
                                }
                            }, 0, 1);
                        }

                    }

                }
            });

        }
    }
}

So what are we doing here?

We put a “afterHookMethod” on a method called onTouchEvent in a specific class. So once the method will finish its work, we will get our code called with the same arguments of the method (we are not using them in this case).

The method onTouchEvent looks like that:

public boolean onTouchEvent(MotionEvent paramMotionEvent)
 {
   switch (paramMotionEvent.getAction())
   {
   }
   do
   {
     return true;
     this.h = true;
     return true;
     this.h = false;
     this.g = (1 + this.g);
     a.b();
     if ((3769 == this.g) || (10007 == this.g) || (59239 == this.g) || (100003 == this.g) || (495221 == this.g) || (1000003 == this.g) || (9999999 == this.g))
     {
       Intent localIntent = new Intent("com.tm.ctf.clicker.SCORE");
       localIntent.putExtra("SCORE", this.g);
       this.a.sendBroadcast(localIntent);
     }
   } while (10000000 > this.g);
   Message localMessage = Message.obtain();
   localMessage.obj = (this.q + "Jh");
   this.b.sendMessage(localMessage);
   return true;
 }

Nothing special for the moment. It increments the counter (this.g), that’s it (for the moment…)!

 

Now let’s run our application in Genymotion with our new Xposed Framework and see what’s going on…

It goes quick fast and click automatically, it’s great!

Ho… but wait… I got 10’000 click in 30 seconds… so I need to be quite patient to reach 10’000’000 clicks… :-/

So let’s try to read a little bit more the code and see if there isn’t another solution…

In the method onTouchEvent we see that the code is doing special process for some values of the counter. We can then suppose that we have to go through this numbers.

What happen if we go only through this number? It would be quite easy and we would need only 7 clicks.

Another great thing with Xposed is that we can set value of a variable inside a class. So we could set the value of g to our values (minus one since it is incremented in the method).

First thing, we will define an array of integer with our number inside.

public static Integer[] list = new Integer[]{0, 3768,10006, 59238,100002, 495220, 1000002, 9999998,9999999,10000000};

I will explain later why we need the 0 and the 10000000 at the end. Don’t forget to remove the previous hook method by the way…

Now let’s add a hook before our method that set g.

XposedHelpers.findAndHookMethod("com.tm.ctf.clicker.activity.c", lpparam.classLoader, "onTouchEvent", MotionEvent.class, new XC_MethodHook() {

                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {

                    MotionEvent me = (MotionEvent) param.args[0];
                    if(me.getAction()==MotionEvent.ACTION_UP) {
                        XposedBridge.log("Before hooking, set g = " + list[i]);

                        XposedHelpers.setIntField(param.thisObject, "g", list[i]);
                        i++;
                    }

                }

            });

Nice.

If you run your module like that, your application will close after one click.

Why? Because there is a check in the Constructor of the class:

if (this.g != a.c())
    {
      Message localMessage = Message.obtain();
      localMessage.obj = "QUIT";
      this.b.sendMessage(localMessage);
    }

So if the g variable is not equal to a.c(), it quits. a.c() read inside SharedPreferences and return a value. This value is incremented in the onTouchEvent method with a.b();

So what can we do?
Exactly! We can replace our method so we control what it returns!
We should return the element inside the list.

XposedHelpers.findAndHookMethod("com.tm.ctf.clicker.a.a", lpparam.classLoader, "c", new XC_MethodReplacement() {
                    @Override
                    protected Object replaceHookedMethod(MethodHookParam methodHookParam) throws Throwable {
                        XposedBridge.log("Returning " + list[i]);
                        return list[i];

                    }
                });

It is really not complicated right? We wrote 8 lines of code, 2 are logs…

Now you can run your application. You understand now why you need the 0 at the beginning (a.c() should return 0 at the start) and the 10000000 at the end (it should be equal to this number in “CongratulationsActivity”).

Hope you enjoyed this write up and that it will give you idea for your next CTF!

Video