對某APP的逆向之旅(2)

接着上面的分析過程,繼續
本次分析下java層和ndk通信的框架
首先,執行上一節分析中解密的文件,如下:
這裏寫圖片描述

繼續分析:

private static int a(Context context, String arg13) {
        int v9 = 3;
        int v4 = -1;
        int v1 = 0;
        Runtime.getRuntime().exec("chmod 755 " + arg13);
        String[] v0 = new String[v9];
        v0[0] = "su";
        v0[1] = "-c";
        v0[2] = arg13;
        Log.d("TAG", Build.CPU_ABI + " - -" + Build.CPU_ABI2 + " -- " + System.getProperty("os.arch"));
        Process decodeExe = Runtime.getRuntime().exec(v0);
        q ServerSocketThread = new q();
        ServerSocketThread.start();
        RootManager.waitThread(((Thread)ServerSocketThread));
        int v2 = decodeExe.getErrorStream().read();
        if(v2 != 120) {
            Log.d("TAG", "RE:" + v2);
            return v4;
        }

        ServerSocketThread.getPort();
        q serverSocket_1 = ServerSocketThread;
        int v0_2 = 0;
    label_51:
        if(!serverSocket_1.isAlive()) {
            serverSocket_1 = new q();
            serverSocket_1.start();
        }

        RootManager.waitThread(((Thread)serverSocket_1));
        int localPort = serverSocket_1.getPort();
        if(v0_2 > v9 && localPort == 0) {
            v0_2 = 1;
            goto label_60;
        }

        long v7 = 100;
        try {
            Thread.sleep(v7);
        }
        catch(InterruptedException v7_1) {
            v7_1.printStackTrace();
        }

        ++v0_2;
        if(localPort == 0) {
            goto label_51;
        }

        v0_2 = 0;
    label_60:
        OutputStreamWriter v3 = new OutputStreamWriter(decodeExe.getOutputStream());
        v3.write(String.valueOf(localPort) + "\n");
        v3.flush();
        if(v0_2 != 0) {
            g.a(context).setProcess(decodeExe);
            g.a(context).initStream(decodeExe.getInputStream(), decodeExe.getOutputStream());
            return v1;
        }

        try {
            serverSocket_1.join();
            long v6_1 = SystemClock.uptimeMillis();
        label_89:
            Socket receiveSocket = serverSocket_1.getReceiveSocket();
            if(receiveSocket == null) {
                if(SystemClock.uptimeMillis() - v6_1 > 32000) {
                    return -3;
                }

                serverSocket_1.run();
                Log.d("TAG", "Check alive2");
                goto label_89;
            }

            g.a(context).setProcess(decodeExe);
            g.a(context).initStream(receiveSocket.getInputStream(), receiveSocket.getOutputStream());
        }
        catch(InterruptedException v0_3) {
            Log.d("TAG", "InterruptedExceptioned");
            decodeExe.destroy();
            v1 = v4;
        }

        return v1;
    }

裏面函數名我已經改成了容易識別的名字。該函數的流程如下:
1、修改執行文件的權限,執行文件。
2、創建socket服務端,監聽socket連接數據。
3、通過檢查socket服務端的本地端口,檢查創建是否成功,成功,則通過socket通信(receiveSocket.getInputStream()、 receiveSocket.getOutputStream()),否則直接通過進程通信(decodeExe.getInputStream(), decodeExe.getOutputStream())。
下面看下通信框架,主要在下面的兩個函數中
1、g.a(context).setProcess()
2、g.a(context).initStream(,)
第一個函數比較簡單,就是將子進程傳遞進去。如下:

    public void setProcess(Process arg1) {
        this.c = arg1;
    }

主要看第二個函數,如下:

    public void initStream(InputStream arg3, OutputStream arg4) {
        this.d = new BufferedReader(new InputStreamReader(arg3));
        this.e = new DataOutputStream(arg4);
        new p(this, null).start();
    }

初始化了輸入輸出流,然後執行了一個線程,來到線程p看看,

public void run() {
        long v1_1;
        String v0_3;
        Object v1;
        BufferedReader v5 = null;
        if(g.a(this.a) != null) {
            try {
                while(true) {
                label_5:
                    v1 = g.a;
                    __monitor_enter(v1);
                    break;
                }
            }
            catch(InterruptedException v0) {
                goto label_40;
            }
            catch(IOException v0_1) {
                goto label_29;
            }

            try {
                Log.w("xltest", "get lock mReader");
                v0_3 = g.a(this.a).readLine();
                Log.w("xltest", "release lock..mReader,=" + v0_3);
                __monitor_exit(v1);
                v1_1 = 10;
            }
            catch(Throwable v0_2) {
                goto label_37;
            }

            try {
                Thread.sleep(v1_1);
                if(v0_3 == null) {
                    goto label_5;
                }

                g.a(this.a, v0_3);
                goto label_5;
            }
            catch(InterruptedException v0) {
                goto label_40;
            }
            catch(IOException v0_1) {
                goto label_29;
            }

            try {
            label_37:
                __monitor_exit(v1_1);
            }
            catch(Throwable v0_2) {
                goto label_37;
            }

            try {
                throw v0_2;
            }
            catch(InterruptedException v0) {
            label_40:
                v0.printStackTrace();
            }
            catch(IOException v0_1) {
            label_29:
                Log.w("GameSpeed", "reader thread", ((Throwable)v0_1));
                g.a(this.a, v5);
                g.a(this.a, ((DataOutputStream)v5));
            }

            super.run();
        }
    }

看起來比較複雜,其實實質的內容很少,主要邏輯如下:

v0_3 = g.a(this.a).readLine();
Thread.sleep(v1_1);
g.a(this.a, v0_3);

我們再來看最後一個函數,這個函數主要是用來接收socket消息的,函數名已經修改過:

    static boolean a(g arg1, String arg2) {
        return arg1.sendLocalBroadcast(arg2);
    }

    private boolean sendLocalBroadcast(String arg6) {
        boolean v0 = true;
        if(!arg6.startsWith("key")) {
            goto label_24;
        }

        if(as.b(this.h, "setting_volume", false)) {
            String v1 = arg6.split(":")[1];
            c v2 = c.a(this.h);
            Intent v3 = new Intent();
            v3.setAction("sb.key.pressed");
            v3.putExtra("key", v1);
            v2.a(v3);  // 發送本地廣播
        }
        else {
            Log.d("key", arg6);
            return v0;
        label_24:
            Log.d("xltest", "update=" + arg6);
            v0 = false;
        }

        return v0;
    }

發送消息的函數爲(只列舉設置和停止):

    public void sendMsg(int arg4) {
        try {
            this.e.writeBytes("t set " + arg4 + "\n");
            this.e.flush();
        }
        catch(IOException v0) {
            v0.printStackTrace();
            this.b();
        }
    }

    public void a() {
        Log.d("xltest", "resetSystemTime");
        try {
            this.e.writeBytes("t stop\n");
            this.e.flush();
        }
        catch(IOException v0) {
            v0.printStackTrace();
            this.b();
        }
    }

就是通過本地廣播,實現java層和ndk層的通信。
NDK層的分析,有時間再寫吧!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章