0x61 Service Call or Transact

0 25
‘It’s 2202, and you are still concerned about the security of Android Service?’...

‘It’s 2202, and you are still concerned about the security of Android Service?’ Yes, that’s right. However, what we are talking about here is not just the Service, which is one of the four major components of Android, but also the Android system Service. At the beginning of the popularity of Android systems, there were countless researchers studying the security of application layer Service. However, up to now, there is still little systematic research on the security of Android system Service.

We will comprehensively analyze the types and usage methods of Android Service, including application layer Service, framework layer Service, and Native layer Service, and examine the architecture of Android Service from the perspective of source code. Of course, we will also intersperse the explanation of Binder, one of the core components of Android. Since we are not Android application developers or system developers, we will not elaborate on the underlying principles of Binder (In the Android system, the IPC mechanism is called Binder. The security of Android Binder services has always been a research direction for many vulnerability researchers), and we will focus on the principles, framework, and existing security issues of Service.

0x00 Basic Knowledge of Xiao Bai

0x01 Binder

0x61 Service Call or Transact

Binder is a new inter-process communication mechanism based on OpenBinder for Android development, providing remote procedure call (RPC) functionality.

  • Intuitively, Binder is a class in the Android SDK, inheriting the IBinder interface;

  • From the IPC perspective, Binder is the core inter-process communication method in Android, which does not exist in Linux, and makes up for some of the shortcomings of traditional Linux IPC;

  • From the perspective of the device, Binder can be understood as a virtual physical device, with the device driver being /dev/binder;

  • From the Android application layer, Binder is the communication medium between the client and server, for example, when the client binds to a Service, it will return a Binder object containing the server's business calls. Through this Binder object, the client can obtain the services or data provided by the server (Android Service is a typical architecture of this kind).

Binder 架构图如下所示,如果你不理解,没有关系,这张图只是给大家一个感性的认识,说明 Binder 其实自顶向下贯穿 AOSP 整个架构。你会在后文中慢慢理解这张架构图的含义。

image

The Binder architecture diagram is as follows. If you do not understand, it is okay. This diagram is just to give everyone a sensory understanding, to show that Binder actually runs through the entire AOSP architecture from top to bottom. You will gradually understand the meaning of this architecture diagram in the following text.

0x02 Service

  • Android Service can refer to the service that Android developers often say is one of the four major components of Android, or it can refer to the many services provided by the Android framework itself. The types of Android Service are as shown below

  • Application Layer Service

    • System Service

    • Android Service (usually refers to the Service written in Java)

Native Service (Service written in C++)

image

Service communicates between different components through the Binder channel provided by intent. Through intent, we can pass parameters to the target Service to achieve certain functions. Of course, Service can also provide some interface methods, which can be called by the application itself or provided to other applications.

0x10 Application Layer Service

Here, the general Service refers to the application layer Service, which is a Service defined by the application developer. As one of the four major components of Android, the application layer service is mainly a solution for implementing background operations in Android. Activity provides the user interface, while Service is just suitable for operations that do not require interaction with the user.

Here, we will briefly discuss the usage of the application layer Service. The service end definition is as follows

public class MyService extends Service {
    public MyService() {
    }

    @Override
    /* Binding service, it is an abstract method, must be overridden */
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    /* Create service, if the service is already running, it will not be executed */
    public void onCreate() {
        super.onCreate();
    }

    /* Handle business, receive intent */
    public int onStartCommand(Intent intent, int flags, int startId) {
        // Log.i(TAG, intent.getStringExtra("MainActivity"));
        return super.onStartCommand(intent, flags, startId);
    }

    /* Destroy */
    public void onDestroy() {
        super.onDestroy();
    }
}

Android Studio will automatically register the service in the Manifest file. The Activity registers through start/stopServiceStart or stop the service. You can also use bindService()Start the service.

final Intent intent = new Intent(this, MyService.class);
Button button = findViewById(R.id.fisrt_button);
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        intent.putExtra(TAG, "This is MainActivity");
        startService(intent);	// Start the service
        stopService(intent);	// Stop the service
    }
});

The following figure is Android DeveloperThe example diagram used on the official website to explain the Service lifecycle. The left figure shows the lifecycle when creating thestartService()Lifecycle, the right figure shows the lifecycle when creating the servicebindService().

image

The Service lifecycle of both methods

  • startService: onCreate -> onStartCommand -> onDestory

  • bindService: onCreate -> onBind -> onDestory

0x11 Component communication with the application layer Service

By binding components to Services, it is very convenient to implement inter-process or inter-process communication. There are many ways to use Service for inter-process communication, each with its specific application scope.

1 Extend the Binder class

Add an inner class binder in the inherited Service class and define some common methods. By binding the Service to the front-end component, the public methods of the binder subclass can be called. If the service is justIntra-process callPrefer to use this method.

In the Service classCreate binder subclass and use onbinder method to return binder instance

private static final String TAG = "MyService";
private LocalBinder mBinder = new LocalBinder();

public class LocalBinder extends Binder {
    public void start() {
        Log.d(TAG, "start:");
    }
    public void end() {
        Log.d(TAG, "end:");
    }
}

@Override
/* Binding service, it is an abstract method, must be overridden */
public IBinder onBind(Intent intent) {
    return mBinder;
}

Components to be associated, create ServiceConnectionAnonymous inner class

private MyService.LocalBinder loadBinder;   // Get the LocalBinder defined in the service

private ServiceConnection connection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        // Binding successful, you can call any public method
        loadBinder = (MyService.LocalBinder) service;
        loadBinder.start();
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
    }
};

Binding or unbindingService

bindService(intent, connection, BIND_AUTO_CREATE);
unbindService(connection);

2 Use Messenger

Messenger is to implement IPC (Inter-process communicationThe simplest method, Messenger creates a message queue containing all requests through a single thread, developers do not need to consider thread safety.

image

Create Messenger on the server sideAnonymous inner class, and return instance using onbinder

public class MyService extends Service {
    private static final String TAG = "MyService";
    Messenger serverMessenger = new Messenger(new Handler() {
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            /* Receive message */
            Bundle bundle = msg.getData();
            String recv = bundle.getString("message_from_client");
            Log.d(TAG, recv);

            /* Send message */
            Messenger clientMessenger = msg.replyTo;   // Client messenger
            Message message = new Message();
            Bundle bundleSend = new Bundle();
            bundleSend.putString("message_from_server", "Hi, this is MyService");
            message.setData(bundleSend);
            try {
                clientMessenger.send(message);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    });

    @Override
    public IBinder onBind(Intent intent) {
        return serverMessenger.getBinder();
    }
}

the components to be associated (i.e., the client), create ServiceConnectionAnonymous inner class

private Messenger serverMessenger;
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            serverMessenger = new Messenger(service); // Obtain the server messenger through the service
            Message message = new Message();
            message.replyTo = serverMessenger;
            Bundle bundle = new Bundle();
            bundle.putString("message_from_client", "Hello, this is client_MainActivity");
            message.setData(bundle);
            try {
                serverMessenger.send(message);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    };

Binding or unbinding Service with the one mentioned earlierExtend the Binder classbe the same.

3 Use AIDL

AIDL (Android Interface Definition Language) can bind to another process's service through AIDL to achieve inter-process communication. Compared to Messenger, AIDL inter-process communication canAllow a Service to handle multiple requests at the same time.

Android Interface Definition Language (AIDL) is a tool available to users for abstracting IPC. For example, in .aidlFor the interface specified in the file, various build systems will use aidlConstruct a binary file binding in C++ or Java to use this interface across processes, regardless of its runtime environment or bitness.

in the Service application,}Create a new AIDL file. The AIDL file is actually an interface file, similar to the header file in C language, and other applications can call the methods declared by AIDL.

interface IMyAidlInterface {
    /* Automatically generated methods, describing the data types supported by the current AIDL, which can be ignored */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
	
    /* Methods intended to be provided for inter-process calls by other applications */
    String getTime();
}

Synchronize AIDL information (sync project-> rebuild), create an inner class in the Service class that inherits the Stub class of the interface, and implements the relevant methods declared by the AIDL interface.

public IBinder onBind(Intent intent) {
    return myBinder;
}

MyBinder myBinder = new MyBinder();

class MyBinder extends IMyAidlInterface.Stub {
    public String getTime() {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return df.format(new Date());
    }

    public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
                    double aDouble, String aString){};
}

About Android Stub class

Stub, which is the stub class, implements an interface, but each method implemented is empty. If an interface has many methods, to implement this interface, all methods must be implemented. However, from a business perspective, a class may only need one or two methods. If you implement the interface directly, in addition to implementing the required methods, you also have to implement all the irrelevant methods. But if you implement the interface by inheriting the stub class, you can avoid this trouble.

Client application copies AIDL files, it is necessary to copy the entire AIDL file on the server side, including the package name. Similarly, after copying the AIDL file, it needs to be synchronized, otherwise other classes cannot refer to the methods declared in the AIDL file.

image

the client application binds to the Service, and in onServiceConnectedCall the AIDL interface method in the method, which is the same as what was said beforeExtend the Binder classIt is still the same.

private ServiceConnection connection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        IMyAidlInterface iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
        try {
            String result = iMyAidlInterface.getTime();
            Log.d(TAG, result);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {

    }
};

/* Bind service */
Intent intent = new Intent();
ComponentName componentName = new ComponentName("com.example.service", "com.example.service.MyService");
intent.setComponent(componentName);
bindService(intent, connection, BIND_AUTO_CREATE);

If setComponent is not used to explicitly bind the Service component, setAction can also be used to bind the Service, but in this case, it is necessary to add in the service end Android Manifest.xml file,Declare the Service component as remote and add an action, the action must be named service package name.aidl

<service
    android:name=".MyService"
    android:process=":remote"
    android:exported="true"
    <intent-filter>
    	<action android:name="com.example.service.IMyAidlInterface" />
    </intent-filter>
</service>

A brief summary, regardless of whether Service extends the Binder class, uses Messenger, or AIDL, the client binds to the Service using the same method, and overrides the onServiceConnected method in the ServiceConnection instance to complete the corresponding IPC.

0x20 System Service

System Service, that is, the Android system service, is different from the Service at the application layer (one of the four major components of Android, implemented by application developers themselves), the system Service is at the Framework layer of the Android system, **The Android Service we usually talk about refers to the Service written in Java. While Nativce Serice refers to the Service written in C++.**System Service is predefined by AOSP, and manufacturers can also implement their own system Service. Application developers only need to use the Service directly. When talking about system Service, we must mention Service Manager.

image

All system services are managed by Service Manager and will be registered in Service Manager.When our own APP wants to use system Service, we can obtain the service through Service Manger and use it. System Service and Service Manager are at the Framework layer.

You can use service listList all system services (format:Service name[interface name/description]),The system services built-in in the OnePlus 3T phone are as follows

image

0x21 Android Service

Service nameIt is determined by the first parameter of addService in the ServiceManager of AOSP source code, for example iphonesubinfoService, registration path: /frameworks/opt/telephony/src/java/com/android/internal/telephony/PhoneSubInfoController.javaThrough addService to register the service, and through getService to obtain the service.

image

Interface descriptionThat is, the interface name, which is mostly corresponding to the AIDL file name

image

How to find the definitions of these methods?

Search the AOSP source code according to the pattern of implementing AIDL at the application layer IPhoneSubInfo.Stubto get the code path of the Service implementation /frameworks/opt/telephony/src/java/com/android/internal/telephony/PhoneSubInfoController.java

image

The client calls the method provided by iphonesubinfo, taking the unit test Robolectric provided by AOSP as an example (android-all-7.1.0_r7-robolectric-0.jar), the client calls the getDeviceId method of the iphonesubinfo service, which actually implements AIDL.robolectricClass com.android.internal.telephony.IPhoneSubInfoImplementation.

  • The client creates a Proxy class, unifies the implementation of the methods provided by the server class (com.android.internal.telephony.IPhoneSubInfo), but the actual methods are still defined on the server side. Of course, the client's IPhoneSubInfo also needs to copy the server's asInterface

image

  • The asInterface method converts the IBinder object to the IInterface interface

image

  • The interface object converted directly calls the relevant methods

image

The principle diagram is as follows, with a deeper understanding can be gained from the analysis of the context.

image

0x22 Native Service

For Native Service, the description is provided by IMPLEMENT_META_INTERFACEDefinition, for example media.drmService (Digital Rights Management)

image

The service is a typical Native Service (Server) code as follows /frameworks/av/drm/libmediadrm/IMediaDrmService.cppCHECK_INTERFACE is used to determine if the interface passed in by the client matches the server. An error will be thrown if they do not match "Binder invocation to an incorrect interface".

image

Client CallThe media.drm service is called multiple times, taking nuplayer as an example /frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp

image

Key Methods

  • Parcel.readStrongBinder(): Reads IBinder type from the parcel object

  • Parcel.writeStrongBinder(): Writes IBinder to Parcel

  • interface_cast: Converts the IBinder object to a strong reference type IInterface

When combined with the code, the principle diagram becomes simpler.

  • Client: BpBinder.transact() sends data

  • Server: BBinder.onTransact() receives data

image

BpBinder and BBinder are both representatives of Android communication and Binder, and are derived classes of IBinder.

  • BpBinder, the proxy class used by the client to interact with the Server

  • BBinder, BpBinder correspond to the server-side IBinder.

One point to note here is:onTransact() method as the function that truly handles the business logic, its implementation is not in BBinder, but in BnBinder derived from BBinder. I believe that careful students have already seen the implementation of BnMediaDrmService in the above case.

0x23 ADB communication with system Service

We have already explained the Service of the framework and native layers in the above text, and the corresponding client calling methods have also been roughly sorted out, but the explanations are all about the framethe client of the framework layer calls the service of the framework layer, originalclient calls the native serviceSo how can ordinary developers or security testers directly call the system provided Service?

adb provides service callYou can directly call the method provided by the system Service, we still take the iphonesubinfo service as an example. 1 represents the first method of the AIDL file, which is what we mentioned earlier getDeviceId

image

Of course, you can also pass parameters to the corresponding function

image

It can also be filtered out by regular expression matching

# IMEI
adb shell "service call iphonesubinfo 1 | grep -o '[0-9a-f]\{8\} ' | tail -n+3 | while read a; do echo -n \u${a:4:4}\u${a:0:4}; done"
# IMSI
adb shell "service call iphonesubinfo 7 | grep -o '[0-9a-f]\{8\} ' | tail -n+3 | while read a; do echo -n \u${a:4:4}\u${a:0:4}; done"
# ICCID
adb shell "service call iphonesubinfo 11 | grep -o '[0-9a-f]\{8\} ' | tail -n+3 | while read a; do echo -n \u${a:4:4}\u${a:0:4}; done"

0x24 APP communication with system Service

For Framework Service,Provide AIDL filesThese services can communicate with the application layer Service directly, and the client can communicate with them using AIDL;Native Service, only some of which provide AIDL (such as the HIDL of the HAL layer)You need to obtain the Binder object directly and then call the transact function of the Binder object.

  • Using AIDLIt is not very stable and needs to import AIDL files, which is not friendly for black-box testing. The usage is similar to the previous one.

  • Reflect to get ServiceMangerIt is stable, but there is a possibility of failure.

If you have an Android compilation environment, you can android.os.ServiceManagerEasily use ServiceManager to find the corresponding Service and call the relevant methods.

// NativeService.java
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;

public class NativeService {
    private static final String SERVICE_NAME = "nativeservice";

    public static boolean invoke(int code, Parcel data, Parcel reply) throws RemoteException {
        IBinder service = ServiceManager.getService(SERVICE_NAME);
        if(service != null){
            Parcel data = Parcel.obtain();
            data.writeInterfaceToken(TOKEN);
            data.appendFrom(data, 0, data.dataSize());
            boolean result = service.transact(code, data, reply, 0);
            data.recycle();
            return true;
        }
        Log.e("shell", "service not running");
        return false;
    };
}

But unfortunately, more often than not, we are just ordinary application developers, android.os.ServiceManagerIt is a hidden class that is not in android.jar, so it cannot be called directly. However, fortunately, **any hidden class can be called using the reflection API.** As shown below

// ((TelephonyManager) getSystemService(TELEPHONY_SERVICE)).getDeviceId();
try {
    Parcel data = Parcel.obtain();
    Parcel replay = Parcel.obtain();
    /* Obtain the ibinder object of Service through reflection */
    IBinder iBinder = (IBinder) Class.forName("android.os.ServiceManager").getMethod("getService", String.class).invoke(null, "iphonesubinfo");
    /* Obtain interface description through the ibinder object */ /* If there is no interface, i.e., Nativce Service, it is not necessary to write */
    iBinder.transact(IBinder.INTERFACE_TRANSACTION, data, replay, 0);
    /* Write interface description */
    data.writeInterfaceToken(replay.toString());
    /* Pass parameters (if any) */
    data.writeInt(0);
    Log.d(TAG, replay.readString());
    /* Send data */
    iBinder.transact(1, data, replay, 0);
    /* Receive data */ 
    Log.d(TAG, replay.readString()); // It is actually empty, the reason is unknown
    /* Recycle the parcel object */
    data.recycle();
    replay.recycle();
} catch (Exception e) {
    e.printStackTrace();
}

Note that the system Service may require permissions, and therefore, the permission should also be declared in the AndroidManifest file. After Android Marshmallow (6.0),Risk permissions need to be dynamically applied.

image

transactDescription of method parameters

  • code, also known as TransactionID, indicates the method number of the server side.

  • data, the parameters that the client needs to pass.

  • replay, the parameters returned by the server.

  • flags, 0 represents a return value, 1 represents no return value.

0x25 APP communication with other application services

In addition to the several conventional methods mentioned at the beginning of the article, application communication with other application services can also be achieved directly by obtaining the iBinder object through binderService, and then invoking through the AIDL method.

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button button = findViewById(R.id.my_button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setComponent("com.xxx.text", "com.xxx.test.service");
                bindService(intent, connection, BIND_AUTO_CREATE);
            }
        });
    }

    IBinder binder;
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            binder = service;
            // Through bindService to obtain the iBinder object
            Parcel _data = Parcel.obtain();
            Parcel _reply = Parcel.obtain();
            _data.writeInterfaceToken("com.xxx.test.service.aidl.xxxExtendService");
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            binder = null;
        }
    };

The several methods mentioned in 0x23-0x25 are commonly used Service communication methods by security testers, while Section 0x11 explains more from the perspective of developers on how to communicate with Service.Once you master the basic communication methods, the subsequent testing will naturally follow.

0x26 Service Security

For Service, these interfaces between components are our focus. For security testing, understanding the knowledge in the above section is sufficient for beginners to delve into Android Service vulnerabilities, and you can directly read the chapter "Service attack surface and security issuesHowever, if you want to delve deeper from the source code perspective, then the subsequent chapters "Case Analysis of DRM Source Codeis a good choice for reading.

0x30 Hardware Abstraction Layer HAL

Android HAL (Hardware Abstraction Layer) is located between Framework and kernel. The Treble project is a major architectural change in the Android operating system framework, officially introduced in Android 8.0. It aims to allow manufacturers to update devices to the new Android system more easily, quickly, and at a lower cost.

By introducing HIDL (HAL Description Language), Framework and HAL are separated, and device suppliers only need to build HAL once and place it in the vendor partition to achieve the separation of the system and HAL. The upgrade of AOSP will not affect the HAL customized by manufacturers. Device manufacturers or chip suppliers no longer need to adapt to new versions of Android.

image

Due to historical reasons, many manufacturers are unwilling to migrate to the Treble architecture all at once, and it was not until Android 8.0 that the coexistence of multiple HALs emerged.

0x31 HAL

The Android kernel is based on Linux, and for traditional Unix-like operating systems, the operation of hardware is completed by the kernel. The Linux kernel uses the GPL protocol, and the kernel code needs to be publicly disclosed. However, Android divides the operation of hardware into HAL (Hardware Abstraction Layer) and kernel drivers, allowing hardware manufacturers to place their core algorithms or logic in the HAL layer, thereby protecting their interests.

The HAL module code is located /hardware/libhardware/modules/is located in the Android file system after compilation /vendor/lib/hw/. For example

# ls /vendor/lib/hw/ | grep drm
android.hardware.drm@1.0-impl.so

0x32 HAL type

AOSP provides the tool lshal, which can directly view the system HAL. HAL services can be implemented using Java or C++.

Binderized HAL (HIDL), that is, the introduction of the Treble architecture, Android versions after 8.0 must use this method. HAL and user calls are in different processes, HAL is written as binder service, and user interfaces such as frameworks as binder clients implement inter-process interface calls through the IPC mechanism. This is Google's ultimate design goal.

image

Compatibility mode, this mode is designed to be compatible with old versions of HAL, the implementation of old HAL is still provided in the form of a dynamic library, but the binder service links the dynamic library HAL implementation, that is, the binder service links the old HAL implementation through hw_get_module, and the user end indirectly interacts with the old HAL through IPC communication with the binder service.

  • Binderized mode

image

  • Not binderized

image

The traditional mode, before Android 8.0, the HAL of all previous versions was compiled into so and then dynamically linked to various framework services.

0x33 HIDL and Service

Previously, Framework and HAL were compiled together into system.img. The emergence of HIDL made Framework no longer directly call HAL, but instead call HAL modules indirectly through HIDL. HAL is compiled into a separate partition vendor.img. Each HAL module can correspond to a HIDL service. The Android framework layer creates HIDL services through HwBinder and obtains HAL modules through HIDL services. That is to say,Service is a means to implement HAL, which can expose HAL modules to the application layer for calls. Of course, it can also be used to call HAL directly through C client without going through Serivce..

0x40 Case analysis of DRM source code

The Android Digital Rights Management framework (DRM, Digital Rights Management) is a typical Service and HAL implementation solution. The DRM framework is extensible, and device manufacturers can implement their own license restriction management according to specific devices.

image

The figure above is the DRM framework before Android 11, for beginners, it is still very difficult to understand without combining the source code. DRM SERVER and MEDIA DRM SERVER are the implementations before and after Android 8.0. At the level of the Android file system, it is represented by two binary programs, which are loaded when the system starts up.

image

0x41 Traditional implementation

The DRM service list is as follows,drm.drmManagerIs the service name,drm.IDrmManagerServiceIs the service interface description, how do they get it? Below, we analyze how the service is registered from the code level.

image

DRM SERVER is a binary, the corresponding source code location /frameworks/av/drm/drmserver/, from the main function entry, analyze layer by layer, used for service registration.

image

DrmManagerServiceClass uses Binder's addService to register the service to the Service Manager

image

And DrmManagerServiceClass inherits from BnDrmManagerService, this class is in IDrmManagerServiceImplementation. IDrmManagerService implements the Service interface description,Methods available for remote invocationDefinition (implementation of onTransact method), client proxy.

image

The loadPlugIns function is implemented in libdrmframework.so, used for loading so

image

The directory below is the dynamic library of the HAL layer implemented by the manufacturer

image

0x42 Treble implementation

The introduction of HIDL in the Treble project brings innovation to the Android HAL architecture. Similar to the 'traditional implementation', the MEDIA DRM SERVER is also used for service registration, but the binary code of this Service is located at /frameworks/av/services/mediadrm/ ,Binder IPC proxy code is still located at the old location /frameworks/av/drm/libmediadrm/ .

image

The registration of Service has been analyzed in the previous text, here only a brief statement is made. The binary registered service of mediadrmserver is media.drmIMediaDrmService.cppdefines interface description android.media.IMediaDrmService,and has implemented the onTransact method (There is a simple analysis in the Native Service chapter),no further elaboration.

# service call media.drm 1
Result: Parcel(
  0x00000000: 73682a85 00000113 00000002 00000000 '.*hs............'
  0x00000010: 00000000 00000000                   '........
# Return a Crypto/CryptoHal object

The client can ultimately call the remote service end makeCryto/Hal through Binder, returning a CryptoHal object, this method is in /frameworks/av/drm/libmediadrm/CryptoHal.cppimplementation

image

Originally:CryptoEach method can be called, through Binder, the proxy is registered at ICrypto.cppinterface.

Now:CryptoHalEach method can be called.The purpose of this interface is to allow non-privileged applications to decrypt DRM data.

  • makeCryptoFactories -> ICryptoFactory -> ICryptoFactory.hal(Some methods are publicly exposed in the form of HIDL interfaces, allowing hardware manufacturers to implement the methods declared by HIDL themselves)

  • makeCryptoPlugin -> ICryptoPlugin -> ICryptoPlugin.hal

0x50 Service Attack Surface and Security Issues

Service, like other components, has many security issues.

0x51 Permission Bypass

Service also has permission control, not all applications have the permission to call any Service. The application layer Service uses the ordinary App's permission management, which can be directly scanned by AndroidManifest.xml. HoweverFor system services, there is currently no general method to directly find the permissions required to call a system service..

The AOSP native system service uses functions like android::checkPermission to judge the permissions of the caller process. Generally, there is no problem. For example, the media.extractor service indicates that the program needs the android.permission.DUMP permission to obtain system dump information from the system service.

image

However, some phone manufacturers or Android emulators often have their own business. Due to the lack of a unified permission control scheme for system services, they may not have done a good job of permission control when implementing their own services, leading to security issues such as permission bypass. For example

image

The aforementioned service itself does not have permission control, and the function sendDataToPc can be directly controlled by the caller. The service itself is designed to be used only by applications with System permissions, but appUid is not obtained from the system, but controlled by the service parameters.

0x52 Out-of-bounds Read

Let's take a look at an actual case: CVE-2018-9411, a vulnerability that affects multiple high-permission Android services. This vulnerability is related to the HIDL design. In the case of HIDL, an important shared memory object is hidl_memory. hidl_memory is a structure that can be used to transmit shared memory segments between processes.

image

Complex data structures will have their own definitions through the Binder transmission structure in HIDL (such as hidl_handle, hidl_string), while simple data structures like integers (uint64_t) are transmitted as is. However, some old dynamic libraries still use 32-bit data. For example, the mapping of hidl_memory objects ashmem

image

mem.size() is 64-bit, while the type of the length field in the mmap signature is size_t, which means its bit size matches the bit size of the process. There is no problem in 64-bit processes, everything is 64-bit. However, in 32-bit processes, its size is truncated to 32 bits, soOnly the low 32 bits will be usedTherefore, when the HAL module is compiled as 32-bit, applying hidl_memory exceeding UINT32_MAX (0xFFFFFFFF) will be truncated.

Details will not be described in detail. The vulnerable service that finally matched is MediaCasService, and this ordinary service has the permission to read and write TEE, which led to privilege escalation due to out-of-bounds read.

0x53 Denial of Service

Denial of service in application layer Service is a frequently discussed topic. In the era of mobile internet, it was prevalent, but now few people pay attention to it. In fact, denial of service in system Service is also a common problem. Service does not judge the parameters passed in by the remote caller, directly references the client object, and does not catch exceptions, leading to service crashes. For example, the following is a case of Service implementation. This method does not judge the input parameters and prints the result directly.

image

the system will generate the onTransact method according to the AIDL file, and the method here catches exceptions

image

but in realitysystem developersusually need to implement the onTransact method by themselves, and it is very likely that exceptions have not been caught. When the client calls getAge with the input "xiaoming", it leads to a null pointer dereference

image

Many Service vulnerabilities, such as CVE-2015-1526, can lead to denial of service.

0x54 serialization

Java provides Serializable, and Android provides Parcelable for object serialization. Denial of service caused by serialization is also a common problem in early application layer Services, and like the above problem, catching exceptions can solve it.

Serializable

Intent i = getIntent();
if(i.getAction().equals("serializable_action"))
{
	i.getSerializableExtra("serializable_key"); // No exception handling done
}

Parcelable

this.b = (RouterConfig);
this.getIntent().getParcelableExtra("filed_router_config"); // This line causes a class cast exception crash

Similar to some common vulnerabilities at the application layer, serialization and deserialization also have other types of vulnerabilities, such as CVE-2015-3525, CVE-2014-7911, which can also be used for privilege escalation. Due to the age of the vulnerabilities, readers who are interested can look them up themselves.

0x55 buffer overflow

Historically, there have also been some Service vulnerabilities, a typical one being the Android Drm service stack overflow vulnerability (CVE-2017-13253). This vulnerability is quite complex and requires the reader to have a deep understanding of the Android Service architecture. If you want to delve deeper into Native Service, this is a good entry point for learning. Since we are in the "Case Analysis of DRM Source CodeThe chapter has already analyzed DRM, now looking back at the cause of this vulnerability is not so difficult. The key to analyzing this vulnerability is to clarify two points

  • Service and HIDL Data stream

  • ComplexData structure

Vulnerability point, the function CryptoPlugin::decrypt memcpy has overflow /frameworks/av/drm/mediadrm/plugins/clearkey/CryptoPlugin.cppHere, the focus is on the data stream, clarifying the call relationship between Service and HAL, the specific data structure, and the cause of overflow can be viewed in the reference literature.

image

Upper-level call /hardware/interfaces/drm/1.0/default/CryptoPlugin.cpp(Generated automatically by the HAL compilation tool)

image

/hardware/interfaces/drm/1.0/ICryptoPlugin.halBy the / of the Framework layerframeworks/av/drm/libmediadrm/ICrypto.cppCall

image

And ICrypto is exactly the Binder IPC Proxy implementation of the media.drm service that we analyzed before, which is externally controllable.

1. Are the names and interfaces of the Service one-to-one corresponding?

Most of the time, a Service may not have an interface, or at most one interface, but there are also cases where two Services share the same interface, for example android.hardware.ICamera

image

2. Does each Service have an interface name?

Some Native services do not have interface descriptions, for example media.extractor

image

In fact, you can also see it in the corresponding code implementation.

image

0x60 Fuzzing

For the Service implemented in Java (i.e., what we call Framework Service), we need to be concerned about whether the methods in ADIL or the specific implementation of xxx extends xxx.Stub have security issues. For the Service implemented in C (i.e., what we call Native Service), we need to be concerned about whether the onTransact method implemented by BnBinder has security issues. These are actually the entry functions of the Service.

image

where the entry function of the Fuzz engine is tansact(code, data, reply, flag)

  • code is of int type, specifying the service method number;

  • data is of the parcel type, and it is the data sent, which meets the binder protocol rules;

  • reply is also of the parcel type, and it is the data returned after communication is completed;

  • flag is the mark bit, 0 is normal RPC, which needs to wait, and the call is in a blocked state until the return is received, 1 is one-way RPC, indicating a transaction that does not require a reply, usually a one-way call without a return value.

data is the parameter sent by binder, and its composition is RPC header + parameter 1 + parameter 2 + ..., the RPC header is the so-called interface name (the interface description mentioned earlier). Up to this point, we have completed the preliminary knowledge of Fuzzing.

0x61 Service Call or Transact

adb provides tools that can directly call services and supports passing various parameters. This method is simple and rough, but the types of parameters that adb can pass are limited. For slightly complex types or some custom type parameters, the ability of adb to call services is restricted. Therefore, it is possible to write an APP to call system services, and the relevant methods have also been mentioned in the above chapter "Communication between Components and System Services", and here the methods are further formalized.

Get all system services

/**
 * Get all service names in the system
 * @return Service list
 */
public String[] ListService() {
    String[] ServiceList = {};
    try {
        ServiceList = (String [])Class.forName("android.os.ServiceManager").getMethod("listServices").invoke(null);
        // Log.d(TAG, "I find there are " + ServiceList.length + " System Services");
        for (int i = 0; i < ServiceList.length; i++) {
            //  Log.d(TAG, ServiceList[i]);
        }
    } catch(Exception e) {
        e.printStackTrace();
    }

    return ServiceList;
}

Get the IBinder interface object

/**
 * Use reflection to get the IBinder interface of the service
 * @param ServiceName Service name
 * @return Return the IBinder interface of the service
 * @throws Exception
 */
private static IBinder getIBinder(String ServiceName) throws Exception{
    return (IBinder) Class.forName("android.os.ServiceManager").getMethod("getService", String.class).invoke(null, ServiceName);
}

Get the interface description or the interface name

/**
 * Get the interface name
 * @param serHandle The IBinder interface of the service
 * @return Return the interface name string
 * @throws RemoteException
 */
private static String getInterfaceName(IBinder IBinder) throws RemoteException {
    Parcel data = Parcel.obtain();
    Parcel reply = Parcel.obtain();
    IBinder.transact(IBinder.INTERFACE_TRANSACTION, data, reply, 0);
    String interfacename = reply.readString();
    data.recycle();
    reply.recycle();
    return interfacename;
}

Call the relevant method of the system service

void test(String sername, int code) {
    for (int i = 0; i < testcaseint.length; i++)
        for (int j = 0; j < testcaseint.length; j++) {
            try {
                Log.d(tag, "-" + sername + "-" + code + "-arg1-" + testcaseint[i] + "-arg2-" + testcaseint[j]);
                Parcel data = Parcel.obtain();
                Parcel reply = Parcel.obtain();
                IBinder ib = getIBinder(sername);
                String in = getInterfaceName(ib);
                data.writeInterfaceToken(in);
                data.writeInt(testcaseint[i]);
                data.writeInt(testcaseint[j]);
                ib.transact(code, data, reply, 0);
                Log.d(tag, "-" + sername + "-" + code + "-" + "reply is \n" + reply.readString());
                reply.readException();
                data.recycle();
                reply.recycle();
            } catch (Exception e) {
            }
        }
}

The limitation of traditional Service Fuzzing lies in the fact that it is impossible to predict the parameter types of the target service methods in advance, although we can find them in the source code, but this requires refilling the parameter types for each method individually; at the same time, it is also difficult to construct for multi-level interfaces.

0x62 Native Service Fuzz

FANSIt is an open-source tool for Android Service Fuzzing published by Liu Baozheng of Tsinghua University in USENIX Security'20. It solves the problem of how to automatically construct interface model test cases in traditional Fuzzing. Its most outstanding contribution is that it automatically extracts the interface model from the abstract syntax tree (AST) of the target interface, in short, it can automatically infer the parameter types of the target method.

image

The Interface Collector collects all interfaces in the target service, including top-level interfaces and multi-level interfaces. Then, the Interface Model Extractor extracts the input and output formats, as well as variable semantics, such as variable names and types, of each candidate transaction in each collected interface. The extractor also collects definitions of structures, enumerations, and type aliases related to variables. Next, the Dependency Inference Engine infers interface dependencies, as well as variable dependencies within and between transactions. Finally, based on the above information, the Fuzzing Engine randomly generates transactions and calls the corresponding interfaces to fuzz the local system service. The Fuzzing Engine also has a manager responsible for synchronizing data between the host and the phone being tested.

The disadvantage of FANS is that there must be a source code compilation environment, and it may be necessary to adapt to different manufacturers.

Summary

As one of the core components of Android, Binder provides a unique inter-process communication method for Android. Android Service is the best embodiment of Binder. Through Service, we can better understand Binder. This article systematically introduces the classification, principle, and usage methods of Android Service, then analyzes the common security issues combined with practical security vulnerabilities, and finally gives the corresponding Fuzzing model.

References

The completion of this article is also due to the excellent works of various bigwigs on the Internet. Some text descriptions and some architectural diagrams come from the following articles, and I would like to express my gratitude again! Some architectural diagrams are drawn by the author, and the source code screenshots in the text are taken by the author on Android XRef8.0/9.0 completed, the command line screenshot is the result of executing on a OnePlus 3 (Android 8.0.0) phone. There are numerous articles or books about the Android system architecture, if you want to learn more, read the following blogs, and you will be surprised by the unexpected gains!

你可能想看:
最后修改时间:
admin
上一篇 2025年03月25日 05:56
下一篇 2025年03月25日 06:18

评论已关闭