Android Open Source - BluetoothHidEmu Bluetooth Adapter Spoofer Generic






From Project

Back to project page BluetoothHidEmu.

License

The source code is released under:

Apache License

If you think the Android project BluetoothHidEmu listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package andraus.bluetoothhidemu.spoof;
//  w  w  w . j  av a 2s . c  o  m
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.os.ParcelUuid;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

import andraus.bluetoothhidemu.R;
import andraus.bluetoothhidemu.spoof.Spoof.SpoofMode;
import andraus.bluetoothhidemu.spoof.jni.BluetoothSocketJni;
import andraus.bluetoothhidemu.util.DoLog;

public class BluetoothAdapterSpooferGeneric extends BluetoothAdapterSpoofer {
    

    private static final String CMD_SU = "su";

    private static final String CMD_ID = "id\n";
    private static final String CMD_ID_RESP = "uid=0(root)";
    
    private static final String CMD_READ_CLASS = " read_class\n";
    private static final String CMD_READ_CLASS_RESP = "class";
    
    private static final String CMD_SPOOF_CLASS = " spoof_class 0x%06X\n";
    private static final String CMD_SPOOF_CLASS_RESP = "class spoofed.";
    
    private static final String CMD_ADD_HID_SDP_GENERIC = " add_hid_generic\n";
    private static final String CMD_ADD_HID_SDP_BDREMOTE = " add_hid_bdremote\n";
    private static final String CMD_ADD_HID_SDP_PS3KEYPAD = " add_hid_ps3keypad\n";
    private static final String CMD_ADD_HID_SDP_RESP = "handle";
    
    private static final String CMD_DEL_HID_SDP = " del_hid 0x%06X\n";
    
    private String mHidEmuPath = null;

    private int mHidSdpHandle;

    /**
     * 
     * @param appContext
     * @param adapter
     */
    protected BluetoothAdapterSpooferGeneric(Context appContext,
            BluetoothAdapter adapter) {
        super(appContext, adapter);
    }

    /**
     * 
     */
    private class ShellResponse {
        static final int ERROR = -0x1;
        static final int SUCCESS = 0x0;
        static final int NON_ROOT = 0xff;
        
        int code = -1;
        String msg;
        
    }
    
    private String getHidEmuPath() {
        return "/data/data/" + mContext.getPackageName() + "/hid_emu";
    }
    
    private ShellResponse installHidEmu() {
        boolean result = true;
        ShellResponse shellResp = null;
        mHidEmuPath = getHidEmuPath();
        
        DoLog.d(TAG, "Checking existence of " + mHidEmuPath);
        
        File hidEmu = new File(mHidEmuPath);
        
        if (!hidEmu.exists()) {
            DoLog.d(TAG, "hid_emu does not exist. Installing...");
            InputStream inStream = null;
            OutputStream outStream = null;
            try {
                inStream = mContext.getAssets().open("hid_emu");
                outStream = new FileOutputStream(mHidEmuPath);
                
                byte[] buffer = new byte[1024];
                int size;
                while ((size = inStream.read(buffer)) > 0) {
                    outStream.write(buffer, 0, size);
                }
                outStream.flush();
                
            } catch (IOException e) {
                DoLog.e(TAG,  "Failed to install hid_emu:", e);
                result = false;
            } finally {
                if (outStream != null)
                    try {
                        outStream.close();
                    } catch (IOException e) {
                        DoLog.e(TAG, "Failed to close output stream: ", e);
                    }
                if (inStream != null)
                    try {
                        inStream.close();
                    } catch (IOException e) {
                        DoLog.e(TAG, "Failed to close input stream: ", e);
                    }
            }
            DoLog.d(TAG, "hid_emu installed. Setting permissions...");
            shellResp = executeShellCmd("chmod 744 " + mHidEmuPath + "\n");
            
            result  = (shellResp.code == 0);
        }
        
        if (result) {
            shellResp = executeShellCmd(mHidEmuPath + "\n");
            if (shellResp.code == 0) {
                DoLog.d(TAG, "hid_emu version: " + shellResp.msg);
            }
        }
        
        return shellResp;
    }
    
    private ShellResponse executeShellCmd(String cmd) {
        ShellResponse shellResponse = new ShellResponse();
        
        Process process = null;
        try {
            process = Runtime.getRuntime().exec(CMD_SU);
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            writer.write(cmd);
            writer.flush();
            writer.write("exit\n");
            writer.flush();
            
            String line = null;
            while ((line = reader.readLine()) != null) {
                shellResponse.msg = line;
                DoLog.d(TAG, "shell: " + shellResponse.msg);
            }
            
            shellResponse.code = process.waitFor();
            DoLog.d(TAG, "process exit value: " + shellResponse.code);
            
        } catch (IOException e) {
            DoLog.d(TAG, "ioexception: ", e);
            // Probably su doesn't exist.
            shellResponse.code = ShellResponse.NON_ROOT;
        } catch (InterruptedException e) {
            DoLog.e(TAG, "interrupted exception: ", e);
            shellResponse.code = ShellResponse.ERROR;
        } finally {
            if (process != null) {
                process.destroy();
            }
        }
        
        return shellResponse;
    }

    @Override
    protected int getBluetoothDeviceClass() {
        int[] clazz = BluetoothSocketJni.readBluetoothDeviceClass();

        /**
         * result is 0xaabbcc
         *  so:
         *  clazz[2] = aa
         *  clazz[1] = bb
         *  clazz[0] = cc
         */

        return (clazz[2] << 16) + (clazz[1] << 8) + (clazz[0]);
    }

    @Override
    protected int spoofBluetoothDeviceClass(int deviceClass) {
        
        mOriginalDeviceClass = getBluetoothDeviceClass();
        DoLog.d(TAG, String.format("original class stored: 0x%06X", mOriginalDeviceClass));
        
        ShellResponse shellResp = executeShellCmd(mHidEmuPath + String.format(CMD_SPOOF_CLASS, deviceClass));
        
        if (shellResp.code != 0) {
            throw new IllegalStateException("Unexpected failure");
        }
        
        if (CMD_SPOOF_CLASS_RESP.equals(shellResp.msg)) {
            return 0;
        } else {
            return -1;
        }
    }

    @Override
    protected int addHidDeviceSdpRecord(SpoofMode mode) {
        
        if (mHidSdpHandle != 0) {
            DoLog.w(TAG, String.format("HID SDP record already present. Handle: 0x%06X",mHidSdpHandle));
            return mHidSdpHandle;
        }
        String cmd;
        switch (mode) {
        case HID_BDREMOTE:
          cmd = CMD_ADD_HID_SDP_BDREMOTE;
          break;
        case HID_PS3KEYPAD:
          cmd = CMD_ADD_HID_SDP_PS3KEYPAD;
          break;
        case HID_GENERIC:
        default:
          cmd = CMD_ADD_HID_SDP_GENERIC;
          break;
        }
        
        ShellResponse shellResp = executeShellCmd(mHidEmuPath + cmd);
        
        if (shellResp.code != 0) {
            throw new IllegalStateException("Unexpected failure");
        }
        
        /*
         * response from hid_emu add_hid is like:
         * handle: 0xaabbcc
         * 
         * using ": 0x" as reg. exp for split, will result in
         * token[0] = handle
         * token[1] = aabbcc
         */
        String[] token = shellResp.msg.split(": 0x");
        if (CMD_ADD_HID_SDP_RESP.equals(token[0])) {
            mHidSdpHandle = Integer.parseInt(token[1], 16);
        }
        
        return mHidSdpHandle;
    }

    /**
     * Removes the SDP record of mHidSdpHandle
     */
    protected void delHidDeviceSdpRecord() {
        if (mHidSdpHandle == 0) {
            DoLog.w(TAG, "No HID SDP record handle present.");
            return;
        }
        
        ShellResponse shellResp = executeShellCmd(mHidEmuPath + String.format(CMD_DEL_HID_SDP, mHidSdpHandle));
        
        if (shellResp.code != 0) {
            throw new IllegalStateException("Unexpected failure");
        }
        mHidSdpHandle = 0;
        
        /*
         * response from hid_emu del_hid <handle> is like:
         * Removed handle: 0xaabbcc
         */

    }

    @Override
    public BluetoothSocket connectL2capSocket(BluetoothDevice device, int port,
                                              boolean auth, boolean encrypt) throws IOException {

        int fd = BluetoothSocketJni.createL2capFileDescriptor(auth, encrypt);

        DoLog.d(TAG, "L2CAP socket File descriptor: " + fd);

        return createL2capBluetoothSocket(device, port, auth, encrypt, fd);

    }

    private BluetoothSocket createL2capBluetoothSocket(BluetoothDevice device, int port,
            boolean auth, boolean encrypt, int fd) throws IOException {
        
        final int TYPE_L2CAP = 3;
        
        BluetoothSocket socket = null;
        Class<?>[] argsClasses = new Class[] { int.class /* type */,
                                            int.class /* fd */,
                                        boolean.class /* auth */,
                                        boolean.class /* encrypt */,
                                BluetoothDevice.class /* device */,
                                            int.class /* port */,
                                     ParcelUuid.class /* uuid */ };
        
        Object[] args = new Object[] {  Integer.valueOf(TYPE_L2CAP),
                                        Integer.valueOf(fd),
                                        Boolean.valueOf(auth),
                                        Boolean.valueOf(encrypt),
                                        device,
                                        Integer.valueOf(port),
                                        null };
        
        try {
            Class<BluetoothSocket> bluetoothSocketClass = BluetoothSocket.class;
            Constructor<BluetoothSocket> bluetoothSocketConstructor;
            bluetoothSocketConstructor = bluetoothSocketClass.getDeclaredConstructor(argsClasses);
            bluetoothSocketConstructor.setAccessible(true);
            
            socket = bluetoothSocketConstructor.newInstance(args);
            
        } catch (SecurityException e) {
            DoLog.e(TAG, "Reflection error:", e);
            throw new IOException("Reflection error", e);
        } catch (NoSuchMethodException e) {
            DoLog.e(TAG, "Reflection error:", e);
            throw new IOException("Reflection error", e);
        } catch (IllegalArgumentException e) {
            DoLog.e(TAG, "Reflection error:", e);
            throw new IOException("Reflection error", e);
        } catch (InstantiationException e) {
            DoLog.e(TAG, "Reflection error:", e);
            throw new IOException("Reflection error", e);
        } catch (IllegalAccessException e) {
            DoLog.e(TAG, "Reflection error:", e);
            throw new IOException("Reflection error", e);
        } catch (InvocationTargetException e) {
            DoLog.e(TAG, "Reflection error:", e);
            throw new IOException("Reflection error", e);
        }
        
        
        return socket;
        
    }

    @Override
    public boolean requirementsCheck() {
        ShellResponse shellResp = executeShellCmd(CMD_ID);
        
        switch (shellResp.code) {
            case ShellResponse.NON_ROOT:
                mSetupErrorMsg = mContext.getResources().getString(R.string.msg_no_root); 
                return false;
            case ShellResponse.SUCCESS:
                if (shellResp.msg != null && shellResp.msg.contains(CMD_ID_RESP)) {
                    mSetupErrorMsg = null;
                    shellResp = installHidEmu();
                    if (shellResp.code != 0) {
                        String errorMsg = shellResp.msg == null ? Integer.toString(shellResp.code) : shellResp.msg;
                        mSetupErrorMsg = mContext.getResources().getString(R.string.msg_generic_failure, errorMsg);
                    }
                    return (shellResp.code == 0);
                } else {
                    mSetupErrorMsg = mContext.getResources().getString(R.string.msg_no_root);
                    return false;
                }
            case ShellResponse.ERROR:
            default:
                mSetupErrorMsg = shellResp.msg;
                return false;
        }
    }
}




Java Source Code List

andraus.bluetoothhidemu.BluetoothHidEmuActivity.java
andraus.bluetoothhidemu.ButtonClickListener.java
andraus.bluetoothhidemu.Constants.java
andraus.bluetoothhidemu.KeyboardKeyListener.java
andraus.bluetoothhidemu.KeyboardTextWatcher.java
andraus.bluetoothhidemu.SpecialKeyListener.java
andraus.bluetoothhidemu.TouchpadListener.java
andraus.bluetoothhidemu.settings.BluetoothAdapterStateReceiver.java
andraus.bluetoothhidemu.settings.BluetoothDeviceStateReceiver.java
andraus.bluetoothhidemu.settings.Settings.java
andraus.bluetoothhidemu.sock.BluetoothSocketThread.java
andraus.bluetoothhidemu.sock.SocketManager.java
andraus.bluetoothhidemu.sock.payload.HidConsumerPayload.java
andraus.bluetoothhidemu.sock.payload.HidKeyPair.java
andraus.bluetoothhidemu.sock.payload.HidKeyboardPayload.java
andraus.bluetoothhidemu.sock.payload.HidPayload.java
andraus.bluetoothhidemu.sock.payload.HidPointerPayload.java
andraus.bluetoothhidemu.sock.payload.HidSixaxisPayload.java
andraus.bluetoothhidemu.spoof.BluetoothAdapterSpooferFactory.java
andraus.bluetoothhidemu.spoof.BluetoothAdapterSpooferGeneric.java
andraus.bluetoothhidemu.spoof.BluetoothAdapterSpooferMotoReflect.java
andraus.bluetoothhidemu.spoof.BluetoothAdapterSpooferMoto.java
andraus.bluetoothhidemu.spoof.BluetoothAdapterSpoofer.java
andraus.bluetoothhidemu.spoof.CleanupExceptionHandler.java
andraus.bluetoothhidemu.spoof.Spoof.java
andraus.bluetoothhidemu.spoof.jni.BluetoothSocketJni.java
andraus.bluetoothhidemu.ui.GenericUiControls.java
andraus.bluetoothhidemu.ui.Ps3KeypadUiControls.java
andraus.bluetoothhidemu.ui.UiControls.java
andraus.bluetoothhidemu.util.DoLog.java
andraus.bluetoothhidemu.view.ArrowButton.java
andraus.bluetoothhidemu.view.BluetoothDeviceArrayAdapter.java
andraus.bluetoothhidemu.view.BluetoothDeviceView.java
andraus.bluetoothhidemu.view.EchoEditText.java
andraus.bluetoothhidemu.view.ViewUtils.java