隐私检测篇-魔改Logd来分发msg

由于小伙伴反映用我的隐私检测插件做检测时,看log要看到头疼,我决定做一个带UI的工具,对隐私检测插件的数据进行接受。最后花了几天时间做好了,隐私插件中也进行了适当修改,数据不再以log形式输出,而是创建一个服务端,由PC端的客户端来主动获取,以下是效果图

隐私检测篇-魔改Logd来分发msg_第1张图片

隐私检测篇-魔改Logd来分发msg_第2张图片

现在又有个问题,隐私检测除了用插件来检测,某些场景下,插件用不了,需要用隐私检测rom来做检测。隐私检测rom里面的数据也是以log形式输出的,如果要全部改为网络收发,那要改的点有点多,毕竟这么多桩点。后来想想,决定从logd入手,在logd中做个劫持,筛选,转发给系统服务,然后再写个app从系统服务中获取msg,PC端的客户端与app中的服务端通信,获取数据,下面就讲一下实现过程:

一、修改logd

在 /system/logging/logd/LogListener.cpp 文件中

在HandleData函数中插入下面的函数

void sendLog(uid_t uid, const char* msg, ssize_t size){ 
    if (uid < 10100){
        return;
    }
    if (strstr(msg, "Antiy_log") == NULL){
        return;
    }
    int sock = socket(AF_UNIX, SOCK_STREAM, 0);
    if (sock == -1) {
        return;
    }
    char name[19] = "@/dev/socket/yooha"; 
    struct sockaddr_un local;
    memset(&local, 0, sizeof(local));
    strncpy(local.sun_path, name, sizeof(local.sun_path) - 1);
    local.sun_path[0] = 0;
    local.sun_family = AF_UNIX;
    int len = strlen(name) + offsetof(struct sockaddr_un, sun_path);

    if (connect(sock, (struct sockaddr *) &local, len) == -1){
        close(sock);
        return;
    }
    write(sock, (msg + strlen(msg) + 1), (size - strlen(msg) - 1));
    close(sock);
}

创建 /dev/socket/yooha ,/system/logging/logd/logd.rc

service logd /system/bin/logd
    socket logd stream 0666 logd logd
    socket logdr seqpacket 0666 logd logd
    socket logdw dgram+passcred 0222 logd logd
    socket yooha stream 0666 system system # add here
    file /proc/kmsg r
    file /dev/kmsg w
    user logd
    group logd system package_info readproc
    capabilities SYSLOG AUDIT_CONTROL
    priority 10
    writepid /dev/cpuset/system-background/tasks

二、创建一个系统服务收发MSG

新建 /frameworks/base/core/java/android/app/yooha/ILogSocket.aidl

package android.app.yooha;

import android.app.yooha.ILogListener;


/**
*@hide
*/
interface ILogSocket{
    void start();
    void addLogListener(ILogListener lis);
    void removeLogListener(ILogListener lis);
}

新建 /frameworks/base/core/java/android/app/yooha/LogListener.java
 

package android.app.yooha;


public interface LogListener {
    void onLogChange(String log);
}

新建 /frameworks/base/core/java/android/app/yooha/LogListenerManager.java

package android.app.yooha;

import android.annotation.NonNull;
import android.app.yooha.ILogListener;
import android.app.yooha.LogListener;
import java.util.concurrent.Executor;
import java.lang.Runnable;

/**
*@hide
*/
public class LogListenerManager extends ILogListener.Stub {
	private LogListener listener;
	private Executor executor;


	public LogListenerManager(@NonNull Executor ect, @NonNull LogListener lstn){
		listener = lstn;
		executor = ect;
	}

	public void onLogChange(@NonNull String log){
		executor.execute(new Runnable(){
			@Override
			public void run(){
				if (listener != null){
					listener.onLogChange(log);
				}
			}
		});

	}
}

新建 /frameworks/base/core/java/android/app/yooha/ILogListener.aidl
 

package android.app.yooha;

/**
*@hide
*/
interface ILogListener{
    void onLogChange(String log);
}

新建 /frameworks/base/services/core/java/com/android/server/LogSocketService.java
 

package com.android.server;

import android.app.yooha.ILogSocket;
import android.app.yooha.ILogListener;
import android.content.Context;
import android.net.LocalServerSocket;
import android.net.LocalSocket;
import java.lang.JLog;
import java.io.IOException;
import java.io.DataInputStream;
import org.json.JSONObject;
import java.util.ArrayList;
import android.app.yooha.DispatchLogThread;

/**
*@hide
*/
public class LogSocketService extends ILogSocket.Stub{
	private Context mContext;
	private LocalServerSocket mServer = null;
	private boolean bStart = false;
	private ArrayList lList = new ArrayList();
	private LocalSocket recv = null;
	private DataInputStream inFromClient = null;

	public Context getContext(){
		return mContext;
	}

	public LogSocketService(Context context) {
		mContext = context;
		try{
			mServer = new LocalServerSocket("/dev/socket/yooha");
		}catch (Exception e) {
			JLog.showException(e);
		}
		
	}

	public void start(){
		if (bStart){
			return;
		}
		bStart = true;
        new Thread() {
            public void run() {
            	JLog.debug("LogSocketService running");
            	if (mServer != null){
	            	while (true){
		                try {
							try{
								recv = mServer.accept();
							}catch (Exception e) {
								JLog.showException(e);
								continue;
							}

							try{
								recv.setReceiveBufferSize(0x1500);
								inFromClient = new DataInputStream(recv.getInputStream());
							}catch (Exception e) {
								JLog.showException(e);
								continue;
							}

							try{
								byte[] buffer = new byte[0x1500];
								int read = inFromClient.read(buffer);
				            	if (read != -1){
				            		new DispatchLogThread(lList, buffer, read).start();
				            	}
							}catch (Exception e) {
								JLog.showException(e);
				            	if (inFromClient != null){
				            		inFromClient.close();
				            	}
				            	if (recv != null){
				            		recv.close();
				            	}
							}
		                } catch (Exception e) {
							if (mServer != null){
								try {
									mServer.close();
								} catch (IOException ie) {
									JLog.showException(ie);
								}
							}
							JLog.showException(e);
		                }
	            	}
            	}
			}
        }.start();
    }


    public void addLogListener(ILogListener lis){
		if(!lList.contains(lis)){
			lList.add(lis);
		}
    }

    public void removeLogListener(ILogListener lis){
		if(lList.contains(lis)){
			lList.remove(lis);
		}
    }
}

修改 /frameworks/base/Android.bp (忽略lint检查)

metalava_framework_docs_args = "--manifest $(location core/res/AndroidManifest.xml) " +
    "--hide-package com.android.server " +
    "--hide-package android.audio.policy.configuration.V7_0 " +
    "--error UnhiddenSystemApi " +
    "--hide RequiresPermission " +
    "--hide CallbackInterface " +
    "--hide MissingPermission --hide BroadcastBehavior " +
    "--hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol " +
    "--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo " +
    "--error NoSettingsProvider " +
    "--force-convert-to-warning-nullability-annotations +*:-android.*:+android.icu.*:-dalvik.* " +
    "--api-lint-ignore-prefix android.icu. " +
    "--api-lint-ignore-prefix java. " +
    "--api-lint-ignore-prefix junit. " +
    "--api-lint-ignore-prefix android.app.yooha. " + // add start
    "--api-lint-ignore-prefix org. "

新建 /frameworks/base/core/java/android/app/yooha/DispatchLogThread.java
 

package android.app.yooha;

import android.app.yooha.ILogListener;
import android.net.LocalSocket;
import org.json.JSONObject;
import java.io.DataInputStream;
import java.util.Arrays;
import java.lang.JLog;
import java.util.ArrayList;
import java.util.List;
import android.annotation.NonNull;

public class DispatchLogThread extends Thread{
    private ArrayList lists = null;
    private String log = null;

    public DispatchLogThread(@NonNull ArrayList lists, @NonNull byte[] buffer, int size){
        try{
            this.lists = lists;
            this.log = new String(buffer, 0, size - 1);
        } catch (Exception e) {
            JLog.showException(e);
        }
    }

    public void run() {
        try {
            
            for(ILogListener l:lists){
            	try{
                    if (l != null){
                        l.onLogChange(log);
                    }
            	} catch (Exception e) {
            	}
            }
        } catch (Exception e) {
            JLog.showException(e);
        }
    }

    @NonNull
    public String byteToString(@NonNull byte[] data, int size){
        StringBuffer sb = new StringBuffer();
        String tmp = null;
        for (int i = 0; i < size; i++){
            tmp = Integer.toHexString(0xFF & data[i]);
            if (tmp.length() == 1){
                tmp = "0" + tmp;
            }
            sb.append(tmp + " ");
        }
        return sb.toString();
    }

    @NonNull
    public String byteToString(@NonNull byte[] data){
        int index = data.length;
        for (int i = 0; i < data.length; i++){
            if (data[i] == 0){
                index = i;
                break;
            }
        }
        return new String(data, 0, index);
    }
}

新建 /frameworks/base/core/java/android/app/yooha/LogSocketManager.java
 

package android.app.yooha;

import android.content.Context;
import android.app.yooha.ILogSocket;
import android.app.yooha.ILogListener;
import android.app.yooha.LogListenerManager;
import java.lang.JLog;
import android.annotation.NonNull;
import java.util.HashMap;
import java.util.concurrent.Executor;
import android.annotation.SystemService;
import android.annotation.CallbackExecutor;

@SystemService(Context.LOG_SOCKET_SERVICE)
public class LogSocketManager {
    private final ILogSocket mLogSocket;
    private Context mContext;
    private final HashMap mListeners = new HashMap();

    /**
    *@hide
    */
    public LogSocketManager(@NonNull Context c, @NonNull ILogSocket f){
        mLogSocket = f;
        mContext = c;
    }


    public void start(){
        try{
            mLogSocket.start();
        } catch (Exception ie) {
            JLog.showException(ie);
        }
    }

    /**
    *@hide
    */
    public LogListenerManager getLogListenerManager(@NonNull @CallbackExecutor Executor executor, @NonNull LogListener lis){
        return new LogListenerManager(executor, lis);
    }

    public void addLogListener(@NonNull @CallbackExecutor Executor executor, @NonNull LogListener lis){
    	try{
    		if (lis == null){
    			return;
    		}
    		LogListenerManager cb = mListeners.get(lis);
    		if (cb == null){
	    		LogListenerManager listener = getLogListenerManager(executor, lis);
	    		mLogSocket.addLogListener(listener);
	    		mListeners.put(lis, listener);
    		}
    	}catch (Exception ie) {
            JLog.showException(ie);
        }
    }

    public void removeLogListener(@NonNull LogListener lis){
    	try{
    		if (lis == null){
    			return;
    		}
    		LogListenerManager cb = mListeners.get(lis);
    		if (cb != null){
    			mLogSocket.removeLogListener(cb);
    			mListeners.remove(lis);
    		}
    	}catch (Exception ie) {
            JLog.showException(ie);
        }
    }
}

修改 /frameworks/base/services/java/com/android/server/SystemServer.java

private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
    ......
            // add start
            t.traceBegin("Start LogSocketService");
            LogSocketService logsocketservice= new LogSocketService(context);
            //logsocketservice.start();  
            ServiceManager.addService("log_socket", logsocketservice);
            t.traceEnd();
            // add end
    ......
    }

修改 /frameworks/base/core/java/android/app/SystemServiceRegistry.java

static {
    ......
// add start
        registerService(Context.LOG_SOCKET_SERVICE, LogSocketManager.class,
            new CachedServiceFetcher() {
            @Override
            public LogSocketManager createService(ContextImpl ctx) throws ServiceNotFoundException {
                IBinder b = ServiceManager.getService(Context.LOG_SOCKET_SERVICE);
                return b == null ? null : new LogSocketManager(ctx, ILogSocket.Stub.asInterface(b));
        }});
// add end
    }

修改 /frameworks/base/core/java/android/content/Context.java

public static final String LOG_SOCKET_SERVICE = "log_socket"; // add start

三、修改SELINUX

以下文件添加:log_socket                              u:object_r:log_socket_service:s0
system\sepolicy\private\service_contexts
system\sepolicy\prebuilts\api\26\private\service_contexts
system\sepolicy\prebuilts\api\27\private\service_contexts
system\sepolicy\prebuilts\api\28\private\service_contexts
system\sepolicy\prebuilts\api\29\private\service_contexts
system\sepolicy\prebuilts\api\30\private\service_contexts
system\sepolicy\prebuilts\api\31\private\service_contexts

以下文件添加:type log_socket_service, app_api_service, system_api_service, system_server_service, service_manager_type;
system\sepolicy\public\service.te
system\sepolicy\prebuilts\api\26\public\service.te
system\sepolicy\prebuilts\api\27\public\service.te
system\sepolicy\prebuilts\api\28\public\service.te
system\sepolicy\prebuilts\api\29\public\service.te
system\sepolicy\prebuilts\api\30\public\service.te
system\sepolicy\prebuilts\api\31\public\service.te

以下文件添加: /dev/socket/ayooha	u:object_r:log_socket:s0
/system/sepolicy/private/file_contexts
system/sepolicy/prebuilts/api/26/private/file_contexts
system/sepolicy/prebuilts/api/27/private/file_contexts
system/sepolicy/prebuilts/api/28/private/file_contexts
system/sepolicy/prebuilts/api/29/private/file_contexts
system/sepolicy/prebuilts/api/30/private/file_contexts
system/sepolicy/prebuilts/api/31/private/file_contexts

以下文件添加: type log_socket, file_type, coredomain_socket, mlstrustedobject;
/system/sepolicy/public/file.te
system/sepolicy/prebuilts/api/26/public/file.te
system/sepolicy/prebuilts/api/27/public/file.te
system/sepolicy/prebuilts/api/28/public/file.te
system/sepolicy/prebuilts/api/29/public/file.te
system/sepolicy/prebuilts/api/30/public/file.te
system/sepolicy/prebuilts/api/31/public/file.te

以下文件参照logw来添加内容:
/system/sepolicy/private/compat/26.0/26.0.cil
/system/sepolicy/private/compat/27.0/27.0.cil
/system/sepolicy/private/compat/28.0/28.0.cil
/system/sepolicy/private/compat/29.0/29.0.cil
/system/sepolicy/private/compat/30.0/30.0.cil
/system/sepolicy/private/compat/31.0/31.0.cil
system/sepolicy/prebuilts/api/31.0/private/compat/26.0/26.0.cil
system/sepolicy/prebuilts/api/31.0/private/compat/27.0/27.0.cil
system/sepolicy/prebuilts/api/31.0/private/compat/28.0/28.0.cil
system/sepolicy/prebuilts/api/31.0/private/compat/29.0/29.0.cil
system/sepolicy/prebuilts/api/31.0/private/compat/30.0/30.0.cil

以下文件参照logw来添加内容:
/system/sepolicy/prebuilts/api/26.0/nonplat_sepolicy.cil
/system/sepolicy/prebuilts/api/27.0/nonplat_sepolicy.cil
/system/sepolicy/prebuilts/api/28.0/plat_pub_versioned.cil
/system/sepolicy/prebuilts/api/28.0/vender_sepolicy.cil
/system/sepolicy/prebuilts/api/29.0/plat_pub_versioned.cil
/system/sepolicy/prebuilts/api/30.0/plat_pub_versioned.cil

文件/system/sepolicy/prebuilts/api/31.0/public/untrusted_app.te 添加如下内容:
allow untrusted_app log_socket_service:service_manager find;
allow untrusted_app_29 log_socket_service:service_manager find;
allow untrusted_app_27 log_socket_service:service_manager find;
allow untrusted_app_25 log_socket_service:service_manager find;
allow untrusted_app system_server:unix_stream_socket connectto;
allow untrusted_app_29 system_server:unix_stream_socket connectto;
allow untrusted_app_27 system_server:unix_stream_socket connectto;
allow untrusted_app_25 system_server:unix_stream_socket connectto;


文件 /system/sepolicy/public/untrusted_app.te 添加如下内容:
allow untrusted_app log_socket_service:service_manager find;
allow untrusted_app_29 log_socket_service:service_manager find;
allow untrusted_app_27 log_socket_service:service_manager find;
allow untrusted_app_25 log_socket_service:service_manager find;
allow untrusted_app system_server:unix_stream_socket connectto;
allow untrusted_app_29 system_server:unix_stream_socket connectto;
allow untrusted_app_27 system_server:unix_stream_socket connectto;
allow untrusted_app_25 system_server:unix_stream_socket connectto;

以下文件注释掉:neverallow { all_untrusted_apps -mediaprovider } init:unix_stream_socket connectto;
/system/sepolicy/private/app_neverallows.te
/system/sepolicy/prebuilts/api/31.0/private/app_neverallows.te

以下文件添加:allow logd system_server:unix_stream_socket connectto;
./public/logd.te
./prebuilts/api/30.0/public/logd.te
./prebuilts/api/27.0/public/logd.te
./prebuilts/api/29.0/public/logd.te
./prebuilts/api/31.0/public/logd.te
./prebuilts/api/26.0/public/logd.te
./prebuilts/api/28.0/public/logd.te

四、写一个app从系统服务获取msg

注册日志监听器

    public void register(String uid){
        try{
            Object service = this.getSystemService("log_socket");
            Class clsLogSocketManager = Class.forName("android.app.yooha.LogSocketManager");
            Class clsLogListener = Class.forName("android.app.yooha.LogListener");
            Method start = clsLogSocketManager.getDeclaredMethod("start");
            Method addLogListener = clsLogSocketManager.getDeclaredMethod("addLogListener", Executor.class, clsLogListener);

            start.setAccessible(true);
            start.invoke(service);

            addLogListener.setAccessible(true);
            Log.e("testlog", "register:1");
            MyLogListener obj = MyLogListener.getInstance();
            Log.e("testlog", String.valueOf(obj));
            obj.setUid(uid);
            Log.e("testlog", "register:2");
            addLogListener.invoke(service, Executors.newSingleThreadExecutor(), MyLogListener.getInstance());
        } catch (Throwable th){
            Log.e("testlog", "register:" + th.toString());
        }
    }

接受日志,先解包,再按协议重新组包

    @Override
    public void onLogChange(String log) {
        try{
            JSONObject json = new JSONObject(log);
            String type = json.getString("Type");
            if (type.equals("Antiy-Privacy")){
                String Uid = json.getString("Uid");
                if (Uid.equals(this.uid)){
                    String info = json.getString("Info");
                    String[] infos = info.split("->");
                    String clz = infos[0].replace(" ", "");
                    String method = infos[1].substring(0, infos[1].indexOf(":"));
                    String description = infos[1].substring(infos[1].indexOf(":") + 1);
                    String stack = json.getString("stackTrace");
                    String currentTime = sdf.format(new Date());
                    send(currentTime, clz, method, "", description, "", "", stack);
                }
            }
        } catch (Throwable th){
            Log.e("testlog", th.toString());
            Log.e("testlog", log);
        }
    }

    public void send(String time, String clz, String method, String total, String descrip, String param, String ret, String stack){
        try{
            JSONObject json = new JSONObject();
            json.put("Time", time);
            json.put("Class", clz);
            json.put("Method", method);
            json.put("Total", total);
            json.put("Description", descrip);
            json.put("Params", param);
            json.put("Return", ret);
            json.put("StackTrace", stack);
            NanoServer.recvMsg(json.toString());
        }catch(Throwable th){
            Log.e("testlog", th.toString());
        }
    }

由服务端来发送msg


public class NanoServer extends EdNanoHTTPD {
    public static final LinkedList mMsg = new LinkedList(); //消息队列

    public NanoServer() throws IOException {
        super(Data.PORT);
        start();
    }

    public static void recvMsg(String msg){
        synchronized (mMsg){
            mMsg.add(msg);
        }
    }


    @Override
    public Response serve(IHTTPSession session) {
        String msg = "";
        if (Method.GET == session.getMethod()) {
            String uri = session.getUri();
            if (uri.contains("api/getlog")){
                synchronized(mMsg) {
                    if (!mMsg.isEmpty()){
                        msg = (String)mMsg.poll();
                    }
                }
            }else if (uri.contains("api/connect")){
                msg = "connect";
            }
        }

        try {
            return newFixedLengthResponse(msg);
        } catch (Exception exception) {
            return newFixedLengthResponse(Response.Status.INTERNAL_ERROR, MIME_PLAINTEXT, "Internal Server Error!!!");
        }

    }
}

做一个界面,让用户选择应用,然后传递UID到listener,只筛选执行UID的log

隐私检测篇-魔改Logd来分发msg_第3张图片

最后测试一下效果:

隐私检测篇-魔改Logd来分发msg_第4张图片

你可能感兴趣的:(android)