背景
网上大部分的文章都是在讲binder的原理,但都没有详细地解释使用以及跨进程调用的条件以及注意的点,这篇文章主要是关注以上的点。
跨进程
跨进程需要注意的点:
- 客户端与服务端的aidl文件必须完全一致才行
- 如果不存在android:process属性,只有应用app本身进程存活,才可以进行跨进程调用
- 如果存在android:process属性,无论app本身进程是否存活,只有process指定进程存活,才可以进行跨进程调用
代码实现
binderserver
OnTransact式实现:
package cn.tasfa.binderserver;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
/**
* @author Tasfa
*/
public class VulnerableService extends Service {
private static final String TAG = "VulnerableService";
public final static int COMMUNICATION_CODE = 1;
public final static String COMMUNICATION_CODE_DESCRIPTOR = "com.tasfa.Hacker.binder";
/**
* 配合VulImpBinder
*/
public interface IVulInterface {
int getKey(String values, int type);
}
/**
* 此类实现通讯 可跨进程调用
* 但是,需要服务端启动该服务,如果该服务不存在,无法调用
* 关键点: 实现了onTransact函数,因此可远程调用
*/
public static final class VulImpBinder extends Binder implements IVulInterface {
/**
* 该方法重载,实现自己的业务逻辑,也是跨进程的关键点
* @param code code
* @param data data
* @param reply reply
* @param flags flags
* @return bool
* @throws RemoteException RemoteException
*/
@Override
protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
switch (code) {
case COMMUNICATION_CODE:
data.enforceInterface(COMMUNICATION_CODE_DESCRIPTOR);
String values = data.readString();
int type = data.readInt();
int result = getKey(values, type);
reply.writeInterfaceToken(COMMUNICATION_CODE_DESCRIPTOR);
reply.writeInt(result);
return true;
default:
break;
}
return super.onTransact(code, data, reply, flags);
}
@Override
public int getKey(String values, int type) {
return type + 300;
}
}
/**
* 此类方法不可以跨进程调用
* 关键点:未实现onTransact函数,无法远程调用
*/
/* public static final class VulBinder extends Binder {
public int getKey(String values, int type) throws RemoteException {
return type + 100;
}
}*/
private VulImpBinder mImpBinder;
public VulnerableService() {
mImpBinder = new VulImpBinder();
}
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind return binder");
return mImpBinder;
}
@Override
public void onCreate() {
super.onCreate();
if (mImpBinder == null){
mImpBinder = new VulImpBinder();
}
}
}
AndroidManifest.xml
<service
android:name=".VulnerableService"
android:enabled="true"
android:process=":vulbinder"> <!-- 可不使用该属性 -->
<intent-filter>
<action android:name="com.tasfa.pp.vulbinder.action" />
</intent-filter>
</service>
<service
android:name=".VulnerableServiceB"
android:enabled="true"
android:process=":aidlvul"> <!-- 可不使用该属性 -->
<intent-filter>
<action android:name="com.tasfa.wdj.vulbinder.action"/>
</intent-filter>
</service>
AIDL方式实现:
package cn.tasfa.binderserver;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
public class VulnerableServiceB extends Service {
public VulnerableServiceB() {
mVulAIDLBinder = new VulAIDLBinder();
}
/**
* 此类使用AIDL可以跨进程调用
* 无需启动该服务,也可实现调用
*/
public static final class VulAIDLBinder extends IVulAidlInterface.Stub {
@Override
public int getKey(String values, int type) throws RemoteException {
return type + 200;
}
}
private VulAIDLBinder mVulAIDLBinder;
@Override
public IBinder onBind(Intent intent) {
return mVulAIDLBinder;
}
@Override
public void onCreate() {
super.onCreate();
if (mVulAIDLBinder == null){
mVulAIDLBinder = new VulAIDLBinder();
}
}
}
binderclient
package cn.tasfa.binderclient;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import cn.tasfa.binderserver.IVulAidlInterface;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "binderClient";
/**
* OnTransact式跨进程调用
*/
private class HackerConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG, "onServiceConnected Successfully !!!");
useParcelHacker(service);
}
/**
* 远程服务不使用AIDL
* 使用自己实现的onTransact函数
* @param service IBinder
*/
private void useParcelHacker(IBinder service){
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
String hackerInterfaceToken = "com.tasfa.Hacker.binder";
int hackerInterfaceCode = 1;
data.writeInterfaceToken(hackerInterfaceToken);
data.writeString("hello");
data.writeInt(1);
try {
service.transact(hackerInterfaceCode, data, reply, 0);
} catch (RemoteException e) {
e.printStackTrace();
}
reply.enforceInterface(hackerInterfaceToken);
int result = reply.readInt();
Log.d(TAG, "useParcelHacker result: " + result);
data.recycle();
reply.recycle();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
/**
* AIDL Interface
* 注意这里"包名以及内容"必须与远程服务的AIDL文件是一致的
*
*/
private IVulAidlInterface mIHackerAidlInterface;
/**
* AIDL式跨进程调用
*/
private class HackerAIDLConnection implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.d(TAG, "onServiceConnected Successfully !!!");
aidlHacker(iBinder);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
mIHackerAidlInterface = null;
}
/**
* AIDL 远程调用函数
* @param service IBinder
*/
private void aidlHacker(IBinder service){
mIHackerAidlInterface = IVulAidlInterface.Stub.asInterface(service);
try {
int rel = mIHackerAidlInterface.getKey("hello",1);
Log.d(TAG, "mIHackerAidlInterface rel: " + rel);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startAttack();
}
});
Button aidl = findViewById(R.id.aidl);
aidl.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startAIDLAttack();
}
});
}
private void startAttack(){
Intent intent = new Intent();
String vulPackageName = "cn.tasfa.binderserver";
String vulBinderServiceClassName = "cn.tasfa.binderserver.VulnerableService";
intent.setClassName(vulPackageName,vulBinderServiceClassName);
bindService(intent, new HackerConnection(), BIND_AUTO_CREATE);
Log.d(TAG, "Start Attack !");
}
private void startAIDLAttack(){
Intent intent = new Intent();
String vulPackageName = "cn.tasfa.binderserver";
String vulBinderServiceClassName = "cn.tasfa.binderserver.VulnerableServiceB";
intent.setClassName(vulPackageName,vulBinderServiceClassName);
bindService(intent, new HackerAIDLConnection(), BIND_AUTO_CREATE);
Log.d(TAG, "Start AIDL Attack !");
}
}