From ad624be5ee01da333a13a1e74da5faa3ef518c9b Mon Sep 17 00:00:00 2001 From: dylanhitt Date: Thu, 25 Jan 2024 01:59:16 -0500 Subject: [PATCH 1/2] feat: provide interface frida.Device --- frida/device.go | 93 ++++++++++++++++++++++++++-------------- frida/frida.go | 14 +++--- frida/manager.go | 50 ++++++++++----------- frida/portal_service.go | 4 +- frida/types_converter.go | 2 +- 5 files changed, 97 insertions(+), 66 deletions(-) diff --git a/frida/device.go b/frida/device.go index 1ca79c0..d74debb 100644 --- a/frida/device.go +++ b/frida/device.go @@ -10,13 +10,44 @@ import ( "unsafe" ) -// Device represents FridaDevice struct from frida-core -type Device struct { +type Device interface { + ID() string + Name() string + DeviceIcon() any + Bus() *Bus + Manager() DeviceManager + IsLost() bool + Params() (map[string]any, error) + FrontmostApplication(scope Scope) (*Application, error) + EnumerateApplications(identifier string, scope Scope) ([]*Application, error) + ProcessByPID(pid int, scope Scope) (*Process, error) + ProcessByName(name string, scope Scope) (*Process, error) + FindProcessByPID(pid int, scope Scope) (*Process, error) + FindProcessByName(name string, scope Scope) (*Process, error) + EnumerateProcesses(scope Scope) ([]*Process, error) + EnableSpawnGating() error + DisableSpawnGating() error + EnumeratePendingSpawn() ([]*Spawn, error) + EnumeratePendingChildren() ([]*Child, error) + Spawn(name string, opts *SpawnOptions) (int, error) + Input(pid int, data []byte) error + Resume(pid int) error + Kill(pid int) error + Attach(val any, opts *SessionOptions) (*Session, error) + InjectLibraryFile(target any, path, entrypoint, data string) (uint, error) + InjectLibraryBlob(target any, byteData []byte, entrypoint, data string) (uint, error) + OpenChannel(address string) (*IOStream, error) + Clean() + On(sigName string, fn any) +} + +// DeviceImpl represents DeviceImpl struct from frida-core +type DeviceImpl struct { device *C.FridaDevice } // ID will return the ID of the device. -func (d *Device) ID() string { +func (d *DeviceImpl) ID() string { if d.device != nil { return C.GoString(C.frida_device_get_id(d.device)) } @@ -24,7 +55,7 @@ func (d *Device) ID() string { } // Name will return the name of the device. -func (d *Device) Name() string { +func (d *DeviceImpl) Name() string { if d.device != nil { return C.GoString(C.frida_device_get_name(d.device)) } @@ -32,7 +63,7 @@ func (d *Device) Name() string { } // DeviceIcon will return the device icon. -func (d *Device) DeviceIcon() any { +func (d *DeviceImpl) DeviceIcon() any { if d.device != nil { icon := C.frida_device_get_icon(d.device) dt := gPointerToGo((C.gpointer)(icon)) @@ -42,7 +73,7 @@ func (d *Device) DeviceIcon() any { } // DeviceType returns type of the device. -func (d *Device) DeviceType() DeviceType { +func (d *DeviceImpl) DeviceType() DeviceType { if d.device != nil { fdt := C.frida_device_get_dtype(d.device) return DeviceType(fdt) @@ -51,7 +82,7 @@ func (d *Device) DeviceType() DeviceType { } // Bus returns device bus. -func (d *Device) Bus() *Bus { +func (d *DeviceImpl) Bus() *Bus { if d.device != nil { bus := C.frida_device_get_bus(d.device) return &Bus{ @@ -62,7 +93,7 @@ func (d *Device) Bus() *Bus { } // Manager returns device manager for the device. -func (d *Device) Manager() DeviceManager { +func (d *DeviceImpl) Manager() DeviceManager { if d.device != nil { mgr := C.frida_device_get_manager(d.device) return &deviceManager{mgr} @@ -71,7 +102,7 @@ func (d *Device) Manager() DeviceManager { } // IsLost returns boolean whether device is lost or not. -func (d *Device) IsLost() bool { +func (d *DeviceImpl) IsLost() bool { if d.device != nil { lost := C.frida_device_is_lost(d.device) return int(lost) == 1 @@ -80,7 +111,7 @@ func (d *Device) IsLost() bool { } // Params returns system parameters of the device -func (d *Device) Params() (map[string]any, error) { +func (d *DeviceImpl) Params() (map[string]any, error) { if d.device != nil { var err *C.GError ht := C.frida_device_query_system_parameters_sync(d.device, nil, &err) @@ -97,7 +128,7 @@ func (d *Device) Params() (map[string]any, error) { // FrontmostApplication will return the frontmost application or the application in focus // on the device. -func (d *Device) FrontmostApplication(scope Scope) (*Application, error) { +func (d *DeviceImpl) FrontmostApplication(scope Scope) (*Application, error) { if d.device != nil { var err *C.GError app := &Application{} @@ -123,7 +154,7 @@ func (d *Device) FrontmostApplication(scope Scope) (*Application, error) { } // EnumerateApplications will return slice of applications on the device -func (d *Device) EnumerateApplications(identifier string, scope Scope) ([]*Application, error) { +func (d *DeviceImpl) EnumerateApplications(identifier string, scope Scope) ([]*Application, error) { if d.device != nil { queryOpts := C.frida_application_query_options_new() C.frida_application_query_options_set_scope(queryOpts, C.FridaScope(scope)) @@ -161,7 +192,7 @@ func (d *Device) EnumerateApplications(identifier string, scope Scope) ([]*Appli } // ProcessByPID returns the process by passed pid. -func (d *Device) ProcessByPID(pid int, scope Scope) (*Process, error) { +func (d *DeviceImpl) ProcessByPID(pid int, scope Scope) (*Process, error) { if d.device != nil { opts := C.frida_process_match_options_new() C.frida_process_match_options_set_timeout(opts, C.gint(defaultProcessTimeout)) @@ -179,7 +210,7 @@ func (d *Device) ProcessByPID(pid int, scope Scope) (*Process, error) { } // ProcessByName returns the process by passed name. -func (d *Device) ProcessByName(name string, scope Scope) (*Process, error) { +func (d *DeviceImpl) ProcessByName(name string, scope Scope) (*Process, error) { if d.device != nil { nameC := C.CString(name) defer C.free(unsafe.Pointer(nameC)) @@ -200,7 +231,7 @@ func (d *Device) ProcessByName(name string, scope Scope) (*Process, error) { } // FindProcessByPID will try to find the process with given pid. -func (d *Device) FindProcessByPID(pid int, scope Scope) (*Process, error) { +func (d *DeviceImpl) FindProcessByPID(pid int, scope Scope) (*Process, error) { if d.device != nil { opts := C.frida_process_match_options_new() C.frida_process_match_options_set_timeout(opts, C.gint(defaultProcessTimeout)) @@ -218,7 +249,7 @@ func (d *Device) FindProcessByPID(pid int, scope Scope) (*Process, error) { } // FindProcessByName will try to find the process with name specified. -func (d *Device) FindProcessByName(name string, scope Scope) (*Process, error) { +func (d *DeviceImpl) FindProcessByName(name string, scope Scope) (*Process, error) { if d.device != nil { nameC := C.CString(name) defer C.free(unsafe.Pointer(nameC)) @@ -239,7 +270,7 @@ func (d *Device) FindProcessByName(name string, scope Scope) (*Process, error) { } // EnumerateProcesses will slice of processes running with scope provided -func (d *Device) EnumerateProcesses(scope Scope) ([]*Process, error) { +func (d *DeviceImpl) EnumerateProcesses(scope Scope) ([]*Process, error) { if d.device != nil { opts := C.frida_process_query_options_new() C.frida_process_query_options_set_scope(opts, C.FridaScope(scope)) @@ -266,7 +297,7 @@ func (d *Device) EnumerateProcesses(scope Scope) ([]*Process, error) { } // EnableSpawnGating will enable spawn gating on the device. -func (d *Device) EnableSpawnGating() error { +func (d *DeviceImpl) EnableSpawnGating() error { if d.device != nil { var err *C.GError C.frida_device_enable_spawn_gating_sync(d.device, nil, &err) @@ -279,7 +310,7 @@ func (d *Device) EnableSpawnGating() error { } // DisableSpawnGating will disable spawn gating on the device. -func (d *Device) DisableSpawnGating() error { +func (d *DeviceImpl) DisableSpawnGating() error { if d.device != nil { var err *C.GError C.frida_device_disable_spawn_gating_sync(d.device, nil, &err) @@ -292,7 +323,7 @@ func (d *Device) DisableSpawnGating() error { } // EnumeratePendingSpawn will return the slice of pending spawns. -func (d *Device) EnumeratePendingSpawn() ([]*Spawn, error) { +func (d *DeviceImpl) EnumeratePendingSpawn() ([]*Spawn, error) { if d.device != nil { var err *C.GError spawnList := C.frida_device_enumerate_pending_spawn_sync(d.device, nil, &err) @@ -315,7 +346,7 @@ func (d *Device) EnumeratePendingSpawn() ([]*Spawn, error) { } // EnumeratePendingChildren will return the slice of pending children. -func (d *Device) EnumeratePendingChildren() ([]*Child, error) { +func (d *DeviceImpl) EnumeratePendingChildren() ([]*Child, error) { if d.device != nil { var err *C.GError childList := C.frida_device_enumerate_pending_children_sync(d.device, nil, &err) @@ -338,7 +369,7 @@ func (d *Device) EnumeratePendingChildren() ([]*Child, error) { } // Spawn will spawn an application or binary. -func (d *Device) Spawn(name string, opts *SpawnOptions) (int, error) { +func (d *DeviceImpl) Spawn(name string, opts *SpawnOptions) (int, error) { if d.device != nil { var opt *C.FridaSpawnOptions = nil if opts != nil { @@ -361,7 +392,7 @@ func (d *Device) Spawn(name string, opts *SpawnOptions) (int, error) { } // Input inputs []bytes into the process with pid specified. -func (d *Device) Input(pid int, data []byte) error { +func (d *DeviceImpl) Input(pid int, data []byte) error { if d.device != nil { gBytesData := goBytesToGBytes(data) runtime.SetFinalizer(gBytesData, func(g *C.GBytes) { @@ -380,7 +411,7 @@ func (d *Device) Input(pid int, data []byte) error { } // Resume will resume the process with pid. -func (d *Device) Resume(pid int) error { +func (d *DeviceImpl) Resume(pid int) error { if d.device != nil { var err *C.GError C.frida_device_resume_sync(d.device, C.guint(pid), nil, &err) @@ -393,7 +424,7 @@ func (d *Device) Resume(pid int) error { } // Kill kills process with pid specified. -func (d *Device) Kill(pid int) error { +func (d *DeviceImpl) Kill(pid int) error { if d.device != nil { var err *C.GError C.frida_device_kill_sync(d.device, C.guint(pid), nil, &err) @@ -408,7 +439,7 @@ func (d *Device) Kill(pid int) error { // Attach will attach on specified process name or PID. // You can pass the nil as SessionOptions or you can create it if you want // the session to persist for specific timeout. -func (d *Device) Attach(val any, opts *SessionOptions) (*Session, error) { +func (d *DeviceImpl) Attach(val any, opts *SessionOptions) (*Session, error) { if d.device != nil { var pid int switch v := reflect.ValueOf(val); v.Kind() { @@ -443,7 +474,7 @@ func (d *Device) Attach(val any, opts *SessionOptions) (*Session, error) { // InjectLibraryFile will inject the library in the target with path to library specified. // Entrypoint is the entrypoint to the library and the data is any data you need to pass // to the library. -func (d *Device) InjectLibraryFile(target any, path, entrypoint, data string) (uint, error) { +func (d *DeviceImpl) InjectLibraryFile(target any, path, entrypoint, data string) (uint, error) { if d.device != nil { var pid int switch v := reflect.ValueOf(target); v.Kind() { @@ -500,7 +531,7 @@ func (d *Device) InjectLibraryFile(target any, path, entrypoint, data string) (u // InjectLibraryBlob will inject the library in the target with byteData path. // Entrypoint is the entrypoint to the library and the data is any data you need to pass // to the library. -func (d *Device) InjectLibraryBlob(target any, byteData []byte, entrypoint, data string) (uint, error) { +func (d *DeviceImpl) InjectLibraryBlob(target any, byteData []byte, entrypoint, data string) (uint, error) { if d.device != nil { var pid int switch v := reflect.ValueOf(target); v.Kind() { @@ -557,7 +588,7 @@ func (d *Device) InjectLibraryBlob(target any, byteData []byte, entrypoint, data } // OpenChannel open channel with the address and returns the IOStream -func (d *Device) OpenChannel(address string) (*IOStream, error) { +func (d *DeviceImpl) OpenChannel(address string) (*IOStream, error) { if d.device != nil { addressC := C.CString(address) defer C.free(unsafe.Pointer(addressC)) @@ -573,7 +604,7 @@ func (d *Device) OpenChannel(address string) (*IOStream, error) { } // Clean will clean the resources held by the device. -func (d *Device) Clean() { +func (d *DeviceImpl) Clean() { if d.device != nil { clean(unsafe.Pointer(d.device), unrefFrida) } @@ -591,7 +622,7 @@ func (d *Device) Clean() { // - "output" with callback as func(pid, fd int, data []byte) {} // - "uninjected" with callback as func(id int) {} // - "lost" with callback as func() {} -func (d *Device) On(sigName string, fn any) { +func (d *DeviceImpl) On(sigName string, fn any) { if d.device != nil { connectClosure(unsafe.Pointer(d.device), sigName, fn) } diff --git a/frida/frida.go b/frida/frida.go index 87655d6..20f3aef 100644 --- a/frida/frida.go +++ b/frida/frida.go @@ -41,11 +41,11 @@ func getDeviceManager() DeviceManager { data.Store("mgr", mgr) return mgr } - return v.(DeviceManager) + return v.(*deviceManager) } // LocalDevice is a wrapper around DeviceByType(DeviceTypeLocal). -func LocalDevice() *Device { +func LocalDevice() Device { mgr := getDeviceManager() v, ok := data.Load("localDevice") if !ok { @@ -53,11 +53,11 @@ func LocalDevice() *Device { data.Store("localDevice", dev) return dev } - return v.(*Device) + return v.(*DeviceImpl) } // USBDevice is a wrapper around DeviceByType(DeviceTypeUsb). -func USBDevice() *Device { +func USBDevice() Device { mgr := getDeviceManager() v, ok := data.Load("usbDevice") if !ok { @@ -73,11 +73,11 @@ func USBDevice() *Device { data.Store("usbDevice", dev) return dev } - return v.(*Device) + return v.(*DeviceImpl) } // DeviceByID tries to get the device by id on the default manager -func DeviceByID(id string) (*Device, error) { +func DeviceByID(id string) (Device, error) { mgr := getDeviceManager() v, ok := data.Load(id) if !ok { @@ -93,7 +93,7 @@ func DeviceByID(id string) (*Device, error) { data.Store(id, dev) return dev, nil } - return v.(*Device), nil + return v.(*DeviceImpl), nil } // Attach attaches at val(string or int pid) using local device. diff --git a/frida/manager.go b/frida/manager.go index e9585e4..86c96ae 100644 --- a/frida/manager.go +++ b/frida/manager.go @@ -8,15 +8,15 @@ import "unsafe" // DeviceManager is the device DeviceManager interface type DeviceManager interface { Close() error - EnumerateDevices() ([]*Device, error) - LocalDevice() (*Device, error) - USBDevice() (*Device, error) - RemoteDevice() (*Device, error) - DeviceByID(id string) (*Device, error) - DeviceByType(devType DeviceType) (*Device, error) - FindDeviceByID(id string) (*Device, error) - FindDeviceByType(devType DeviceType) (*Device, error) - AddRemoteDevice(address string, remoteOpts *RemoteDeviceOptions) (*Device, error) + EnumerateDevices() ([]Device, error) + LocalDevice() (Device, error) + USBDevice() (Device, error) + RemoteDevice() (Device, error) + DeviceByID(id string) (Device, error) + DeviceByType(devType DeviceType) (Device, error) + FindDeviceByID(id string) (Device, error) + FindDeviceByType(devType DeviceType) (Device, error) + AddRemoteDevice(address string, remoteOpts *RemoteDeviceOptions) (Device, error) RemoveRemoteDevice(address string) error Clean() On(sigName string, fn any) @@ -47,7 +47,7 @@ func (d *deviceManager) Close() error { } // EnumerateDevices will return all connected devices. -func (d *deviceManager) EnumerateDevices() ([]*Device, error) { +func (d *deviceManager) EnumerateDevices() ([]Device, error) { var err *C.GError deviceList := C.frida_device_manager_enumerate_devices_sync(d.manager, nil, &err) if err != nil { @@ -55,11 +55,11 @@ func (d *deviceManager) EnumerateDevices() ([]*Device, error) { } numDevices := int(C.frida_device_list_size(deviceList)) - devices := make([]*Device, numDevices) + devices := make([]Device, numDevices) for i := 0; i < numDevices; i++ { device := C.frida_device_list_get(deviceList, C.gint(i)) - devices[i] = &Device{device} + devices[i] = &DeviceImpl{device} } clean(unsafe.Pointer(deviceList), unrefFrida) @@ -67,23 +67,23 @@ func (d *deviceManager) EnumerateDevices() ([]*Device, error) { } // LocalDevice returns the device with type DeviceTypeLocal. -func (d *deviceManager) LocalDevice() (*Device, error) { +func (d *deviceManager) LocalDevice() (Device, error) { return d.DeviceByType(DeviceTypeLocal) } // USBDevice returns the device with type DeviceTypeUsb. -func (d *deviceManager) USBDevice() (*Device, error) { +func (d *deviceManager) USBDevice() (Device, error) { return d.DeviceByType(DeviceTypeUsb) } // RemoteDevice returns the device with type DeviceTypeRemote. -func (d *deviceManager) RemoteDevice() (*Device, error) { +func (d *deviceManager) RemoteDevice() (Device, error) { return d.DeviceByType(DeviceTypeRemote) } // DeviceByID will return device with id passed or an error if it can't find any. // Note: the caller must call EnumerateDevices() to get devices that are of type usb -func (d *deviceManager) DeviceByID(id string) (*Device, error) { +func (d *deviceManager) DeviceByID(id string) (Device, error) { idC := C.CString(id) defer C.free(unsafe.Pointer(idC)) @@ -94,12 +94,12 @@ func (d *deviceManager) DeviceByID(id string) (*Device, error) { if err != nil { return nil, &FError{err} } - return &Device{device: device}, nil + return &DeviceImpl{device: device}, nil } // DeviceByType will return device or an error by device type specified. // Note: the caller must call EnumerateDevices() to get devices that are of type usb -func (d *deviceManager) DeviceByType(devType DeviceType) (*Device, error) { +func (d *deviceManager) DeviceByType(devType DeviceType) (Device, error) { var err *C.GError device := C.frida_device_manager_get_device_by_type_sync(d.manager, C.FridaDeviceType(devType), @@ -109,12 +109,12 @@ func (d *deviceManager) DeviceByType(devType DeviceType) (*Device, error) { if err != nil { return nil, &FError{err} } - return &Device{device: device}, nil + return &DeviceImpl{device: device}, nil } // FindDeviceByID will try to find the device by id specified // Note: the caller must call EnumerateDevices() to get devices that are of type usb -func (d *deviceManager) FindDeviceByID(id string) (*Device, error) { +func (d *deviceManager) FindDeviceByID(id string) (Device, error) { devID := C.CString(id) defer C.free(unsafe.Pointer(devID)) @@ -130,12 +130,12 @@ func (d *deviceManager) FindDeviceByID(id string) (*Device, error) { return nil, &FError{err} } - return &Device{device: device}, nil + return &DeviceImpl{device: device}, nil } // FindDeviceByType will try to find the device by device type specified // Note: the caller must call EnumerateDevices() to get devices that are of type usb -func (d *deviceManager) FindDeviceByType(devType DeviceType) (*Device, error) { +func (d *deviceManager) FindDeviceByType(devType DeviceType) (Device, error) { timeout := C.gint(defaultDeviceTimeout) var err *C.GError @@ -148,11 +148,11 @@ func (d *deviceManager) FindDeviceByType(devType DeviceType) (*Device, error) { return nil, &FError{err} } - return &Device{device: device}, nil + return &DeviceImpl{device: device}, nil } // AddRemoteDevice add a remote device from the provided address with remoteOpts populated -func (d *deviceManager) AddRemoteDevice(address string, remoteOpts *RemoteDeviceOptions) (*Device, error) { +func (d *deviceManager) AddRemoteDevice(address string, remoteOpts *RemoteDeviceOptions) (Device, error) { addressC := C.CString(address) defer C.free(unsafe.Pointer(addressC)) @@ -162,7 +162,7 @@ func (d *deviceManager) AddRemoteDevice(address string, remoteOpts *RemoteDevice return nil, &FError{err} } - return &Device{device: device}, nil + return &DeviceImpl{device: device}, nil } // RemoveRemoteDevice removes remote device available at address diff --git a/frida/portal_service.go b/frida/portal_service.go index f03c718..6361a37 100644 --- a/frida/portal_service.go +++ b/frida/portal_service.go @@ -22,9 +22,9 @@ func NewPortal(clusterParams, controlParams *EndpointParameters) *Portal { } // Device returns portal device. -func (p *Portal) Device() *Device { +func (p *Portal) Device() Device { dev := C.frida_portal_service_get_device(p.portal) - return &Device{dev} + return &DeviceImpl{dev} } // ClusterParams returns the cluster parameters for the portal. diff --git a/frida/types_converter.go b/frida/types_converter.go index 145b904..726a305 100644 --- a/frida/types_converter.go +++ b/frida/types_converter.go @@ -189,7 +189,7 @@ func getFridaChild(val *C.GValue) any { func getFridaDevice(val *C.GValue) any { dev := (*C.FridaDevice)(C.g_value_get_object(val)) - return &Device{ + return &DeviceImpl{ device: dev, } } From b923fafab9aee8aacadcea290346d46c944fb3f8 Mon Sep 17 00:00:00 2001 From: dylanhitt Date: Thu, 25 Jan 2024 09:10:10 -0500 Subject: [PATCH 2/2] feat: changing api to expose DeviceInt to provide a mockable interface to the caller Expose the concrete type of DeviceManager so the end user can mock it however they see fit. I.E the go saying of "Accept Interfaces, Return Structs". However, return a frida.Device Interface when DeviceManager/Portal is being used for access to provide the end user a mockable interface. --- frida/device.go | 68 ++++++++++++++++++------------------ frida/frida.go | 22 ++++++------ frida/manager.go | 74 ++++++++++++++++++++-------------------- frida/portal_service.go | 4 +-- frida/types_converter.go | 2 +- 5 files changed, 85 insertions(+), 85 deletions(-) diff --git a/frida/device.go b/frida/device.go index d74debb..5944ec1 100644 --- a/frida/device.go +++ b/frida/device.go @@ -10,12 +10,12 @@ import ( "unsafe" ) -type Device interface { +type DeviceInt interface { ID() string Name() string DeviceIcon() any Bus() *Bus - Manager() DeviceManager + Manager() *DeviceManager IsLost() bool Params() (map[string]any, error) FrontmostApplication(scope Scope) (*Application, error) @@ -41,13 +41,13 @@ type Device interface { On(sigName string, fn any) } -// DeviceImpl represents DeviceImpl struct from frida-core -type DeviceImpl struct { +// Device represents Device struct from frida-core +type Device struct { device *C.FridaDevice } // ID will return the ID of the device. -func (d *DeviceImpl) ID() string { +func (d *Device) ID() string { if d.device != nil { return C.GoString(C.frida_device_get_id(d.device)) } @@ -55,7 +55,7 @@ func (d *DeviceImpl) ID() string { } // Name will return the name of the device. -func (d *DeviceImpl) Name() string { +func (d *Device) Name() string { if d.device != nil { return C.GoString(C.frida_device_get_name(d.device)) } @@ -63,7 +63,7 @@ func (d *DeviceImpl) Name() string { } // DeviceIcon will return the device icon. -func (d *DeviceImpl) DeviceIcon() any { +func (d *Device) DeviceIcon() any { if d.device != nil { icon := C.frida_device_get_icon(d.device) dt := gPointerToGo((C.gpointer)(icon)) @@ -73,7 +73,7 @@ func (d *DeviceImpl) DeviceIcon() any { } // DeviceType returns type of the device. -func (d *DeviceImpl) DeviceType() DeviceType { +func (d *Device) DeviceType() DeviceType { if d.device != nil { fdt := C.frida_device_get_dtype(d.device) return DeviceType(fdt) @@ -82,7 +82,7 @@ func (d *DeviceImpl) DeviceType() DeviceType { } // Bus returns device bus. -func (d *DeviceImpl) Bus() *Bus { +func (d *Device) Bus() *Bus { if d.device != nil { bus := C.frida_device_get_bus(d.device) return &Bus{ @@ -93,16 +93,16 @@ func (d *DeviceImpl) Bus() *Bus { } // Manager returns device manager for the device. -func (d *DeviceImpl) Manager() DeviceManager { +func (d *Device) Manager() *DeviceManager { if d.device != nil { mgr := C.frida_device_get_manager(d.device) - return &deviceManager{mgr} + return &DeviceManager{mgr} } return nil } // IsLost returns boolean whether device is lost or not. -func (d *DeviceImpl) IsLost() bool { +func (d *Device) IsLost() bool { if d.device != nil { lost := C.frida_device_is_lost(d.device) return int(lost) == 1 @@ -111,7 +111,7 @@ func (d *DeviceImpl) IsLost() bool { } // Params returns system parameters of the device -func (d *DeviceImpl) Params() (map[string]any, error) { +func (d *Device) Params() (map[string]any, error) { if d.device != nil { var err *C.GError ht := C.frida_device_query_system_parameters_sync(d.device, nil, &err) @@ -128,7 +128,7 @@ func (d *DeviceImpl) Params() (map[string]any, error) { // FrontmostApplication will return the frontmost application or the application in focus // on the device. -func (d *DeviceImpl) FrontmostApplication(scope Scope) (*Application, error) { +func (d *Device) FrontmostApplication(scope Scope) (*Application, error) { if d.device != nil { var err *C.GError app := &Application{} @@ -154,7 +154,7 @@ func (d *DeviceImpl) FrontmostApplication(scope Scope) (*Application, error) { } // EnumerateApplications will return slice of applications on the device -func (d *DeviceImpl) EnumerateApplications(identifier string, scope Scope) ([]*Application, error) { +func (d *Device) EnumerateApplications(identifier string, scope Scope) ([]*Application, error) { if d.device != nil { queryOpts := C.frida_application_query_options_new() C.frida_application_query_options_set_scope(queryOpts, C.FridaScope(scope)) @@ -192,7 +192,7 @@ func (d *DeviceImpl) EnumerateApplications(identifier string, scope Scope) ([]*A } // ProcessByPID returns the process by passed pid. -func (d *DeviceImpl) ProcessByPID(pid int, scope Scope) (*Process, error) { +func (d *Device) ProcessByPID(pid int, scope Scope) (*Process, error) { if d.device != nil { opts := C.frida_process_match_options_new() C.frida_process_match_options_set_timeout(opts, C.gint(defaultProcessTimeout)) @@ -210,7 +210,7 @@ func (d *DeviceImpl) ProcessByPID(pid int, scope Scope) (*Process, error) { } // ProcessByName returns the process by passed name. -func (d *DeviceImpl) ProcessByName(name string, scope Scope) (*Process, error) { +func (d *Device) ProcessByName(name string, scope Scope) (*Process, error) { if d.device != nil { nameC := C.CString(name) defer C.free(unsafe.Pointer(nameC)) @@ -231,7 +231,7 @@ func (d *DeviceImpl) ProcessByName(name string, scope Scope) (*Process, error) { } // FindProcessByPID will try to find the process with given pid. -func (d *DeviceImpl) FindProcessByPID(pid int, scope Scope) (*Process, error) { +func (d *Device) FindProcessByPID(pid int, scope Scope) (*Process, error) { if d.device != nil { opts := C.frida_process_match_options_new() C.frida_process_match_options_set_timeout(opts, C.gint(defaultProcessTimeout)) @@ -249,7 +249,7 @@ func (d *DeviceImpl) FindProcessByPID(pid int, scope Scope) (*Process, error) { } // FindProcessByName will try to find the process with name specified. -func (d *DeviceImpl) FindProcessByName(name string, scope Scope) (*Process, error) { +func (d *Device) FindProcessByName(name string, scope Scope) (*Process, error) { if d.device != nil { nameC := C.CString(name) defer C.free(unsafe.Pointer(nameC)) @@ -270,7 +270,7 @@ func (d *DeviceImpl) FindProcessByName(name string, scope Scope) (*Process, erro } // EnumerateProcesses will slice of processes running with scope provided -func (d *DeviceImpl) EnumerateProcesses(scope Scope) ([]*Process, error) { +func (d *Device) EnumerateProcesses(scope Scope) ([]*Process, error) { if d.device != nil { opts := C.frida_process_query_options_new() C.frida_process_query_options_set_scope(opts, C.FridaScope(scope)) @@ -297,7 +297,7 @@ func (d *DeviceImpl) EnumerateProcesses(scope Scope) ([]*Process, error) { } // EnableSpawnGating will enable spawn gating on the device. -func (d *DeviceImpl) EnableSpawnGating() error { +func (d *Device) EnableSpawnGating() error { if d.device != nil { var err *C.GError C.frida_device_enable_spawn_gating_sync(d.device, nil, &err) @@ -310,7 +310,7 @@ func (d *DeviceImpl) EnableSpawnGating() error { } // DisableSpawnGating will disable spawn gating on the device. -func (d *DeviceImpl) DisableSpawnGating() error { +func (d *Device) DisableSpawnGating() error { if d.device != nil { var err *C.GError C.frida_device_disable_spawn_gating_sync(d.device, nil, &err) @@ -323,7 +323,7 @@ func (d *DeviceImpl) DisableSpawnGating() error { } // EnumeratePendingSpawn will return the slice of pending spawns. -func (d *DeviceImpl) EnumeratePendingSpawn() ([]*Spawn, error) { +func (d *Device) EnumeratePendingSpawn() ([]*Spawn, error) { if d.device != nil { var err *C.GError spawnList := C.frida_device_enumerate_pending_spawn_sync(d.device, nil, &err) @@ -346,7 +346,7 @@ func (d *DeviceImpl) EnumeratePendingSpawn() ([]*Spawn, error) { } // EnumeratePendingChildren will return the slice of pending children. -func (d *DeviceImpl) EnumeratePendingChildren() ([]*Child, error) { +func (d *Device) EnumeratePendingChildren() ([]*Child, error) { if d.device != nil { var err *C.GError childList := C.frida_device_enumerate_pending_children_sync(d.device, nil, &err) @@ -369,7 +369,7 @@ func (d *DeviceImpl) EnumeratePendingChildren() ([]*Child, error) { } // Spawn will spawn an application or binary. -func (d *DeviceImpl) Spawn(name string, opts *SpawnOptions) (int, error) { +func (d *Device) Spawn(name string, opts *SpawnOptions) (int, error) { if d.device != nil { var opt *C.FridaSpawnOptions = nil if opts != nil { @@ -392,7 +392,7 @@ func (d *DeviceImpl) Spawn(name string, opts *SpawnOptions) (int, error) { } // Input inputs []bytes into the process with pid specified. -func (d *DeviceImpl) Input(pid int, data []byte) error { +func (d *Device) Input(pid int, data []byte) error { if d.device != nil { gBytesData := goBytesToGBytes(data) runtime.SetFinalizer(gBytesData, func(g *C.GBytes) { @@ -411,7 +411,7 @@ func (d *DeviceImpl) Input(pid int, data []byte) error { } // Resume will resume the process with pid. -func (d *DeviceImpl) Resume(pid int) error { +func (d *Device) Resume(pid int) error { if d.device != nil { var err *C.GError C.frida_device_resume_sync(d.device, C.guint(pid), nil, &err) @@ -424,7 +424,7 @@ func (d *DeviceImpl) Resume(pid int) error { } // Kill kills process with pid specified. -func (d *DeviceImpl) Kill(pid int) error { +func (d *Device) Kill(pid int) error { if d.device != nil { var err *C.GError C.frida_device_kill_sync(d.device, C.guint(pid), nil, &err) @@ -439,7 +439,7 @@ func (d *DeviceImpl) Kill(pid int) error { // Attach will attach on specified process name or PID. // You can pass the nil as SessionOptions or you can create it if you want // the session to persist for specific timeout. -func (d *DeviceImpl) Attach(val any, opts *SessionOptions) (*Session, error) { +func (d *Device) Attach(val any, opts *SessionOptions) (*Session, error) { if d.device != nil { var pid int switch v := reflect.ValueOf(val); v.Kind() { @@ -474,7 +474,7 @@ func (d *DeviceImpl) Attach(val any, opts *SessionOptions) (*Session, error) { // InjectLibraryFile will inject the library in the target with path to library specified. // Entrypoint is the entrypoint to the library and the data is any data you need to pass // to the library. -func (d *DeviceImpl) InjectLibraryFile(target any, path, entrypoint, data string) (uint, error) { +func (d *Device) InjectLibraryFile(target any, path, entrypoint, data string) (uint, error) { if d.device != nil { var pid int switch v := reflect.ValueOf(target); v.Kind() { @@ -531,7 +531,7 @@ func (d *DeviceImpl) InjectLibraryFile(target any, path, entrypoint, data string // InjectLibraryBlob will inject the library in the target with byteData path. // Entrypoint is the entrypoint to the library and the data is any data you need to pass // to the library. -func (d *DeviceImpl) InjectLibraryBlob(target any, byteData []byte, entrypoint, data string) (uint, error) { +func (d *Device) InjectLibraryBlob(target any, byteData []byte, entrypoint, data string) (uint, error) { if d.device != nil { var pid int switch v := reflect.ValueOf(target); v.Kind() { @@ -588,7 +588,7 @@ func (d *DeviceImpl) InjectLibraryBlob(target any, byteData []byte, entrypoint, } // OpenChannel open channel with the address and returns the IOStream -func (d *DeviceImpl) OpenChannel(address string) (*IOStream, error) { +func (d *Device) OpenChannel(address string) (*IOStream, error) { if d.device != nil { addressC := C.CString(address) defer C.free(unsafe.Pointer(addressC)) @@ -604,7 +604,7 @@ func (d *DeviceImpl) OpenChannel(address string) (*IOStream, error) { } // Clean will clean the resources held by the device. -func (d *DeviceImpl) Clean() { +func (d *Device) Clean() { if d.device != nil { clean(unsafe.Pointer(d.device), unrefFrida) } @@ -622,7 +622,7 @@ func (d *DeviceImpl) Clean() { // - "output" with callback as func(pid, fd int, data []byte) {} // - "uninjected" with callback as func(id int) {} // - "lost" with callback as func() {} -func (d *DeviceImpl) On(sigName string, fn any) { +func (d *Device) On(sigName string, fn any) { if d.device != nil { connectClosure(unsafe.Pointer(d.device), sigName, fn) } diff --git a/frida/frida.go b/frida/frida.go index 20f3aef..9b07f1f 100644 --- a/frida/frida.go +++ b/frida/frida.go @@ -34,30 +34,30 @@ func Version() string { return C.GoString(C.frida_version_string()) } -func getDeviceManager() DeviceManager { +func getDeviceManager() *DeviceManager { v, ok := data.Load("mgr") if !ok { mgr := NewDeviceManager() data.Store("mgr", mgr) return mgr } - return v.(*deviceManager) + return v.(*DeviceManager) } // LocalDevice is a wrapper around DeviceByType(DeviceTypeLocal). -func LocalDevice() Device { +func LocalDevice() *Device { mgr := getDeviceManager() v, ok := data.Load("localDevice") if !ok { dev, _ := mgr.DeviceByType(DeviceTypeLocal) data.Store("localDevice", dev) - return dev + return dev.(*Device) } - return v.(*DeviceImpl) + return v.(*Device) } // USBDevice is a wrapper around DeviceByType(DeviceTypeUsb). -func USBDevice() Device { +func USBDevice() *Device { mgr := getDeviceManager() v, ok := data.Load("usbDevice") if !ok { @@ -71,13 +71,13 @@ func USBDevice() Device { return nil } data.Store("usbDevice", dev) - return dev + return dev.(*Device) } - return v.(*DeviceImpl) + return v.(*Device) } // DeviceByID tries to get the device by id on the default manager -func DeviceByID(id string) (Device, error) { +func DeviceByID(id string) (*Device, error) { mgr := getDeviceManager() v, ok := data.Load(id) if !ok { @@ -91,9 +91,9 @@ func DeviceByID(id string) (Device, error) { return nil, err } data.Store(id, dev) - return dev, nil + return v.(*Device), nil } - return v.(*DeviceImpl), nil + return v.(*Device), nil } // Attach attaches at val(string or int pid) using local device. diff --git a/frida/manager.go b/frida/manager.go index 86c96ae..b41d7ec 100644 --- a/frida/manager.go +++ b/frida/manager.go @@ -5,18 +5,18 @@ import "C" import "unsafe" -// DeviceManager is the device DeviceManager interface -type DeviceManager interface { +// DeviceManagerInt is the device DeviceManagerInt interface +type DeviceManagerInt interface { Close() error - EnumerateDevices() ([]Device, error) - LocalDevice() (Device, error) - USBDevice() (Device, error) - RemoteDevice() (Device, error) - DeviceByID(id string) (Device, error) - DeviceByType(devType DeviceType) (Device, error) - FindDeviceByID(id string) (Device, error) - FindDeviceByType(devType DeviceType) (Device, error) - AddRemoteDevice(address string, remoteOpts *RemoteDeviceOptions) (Device, error) + EnumerateDevices() ([]DeviceInt, error) + LocalDevice() (DeviceInt, error) + USBDevice() (DeviceInt, error) + RemoteDevice() (DeviceInt, error) + DeviceByID(id string) (DeviceInt, error) + DeviceByType(devType DeviceType) (DeviceInt, error) + FindDeviceByID(id string) (DeviceInt, error) + FindDeviceByType(devType DeviceType) (DeviceInt, error) + AddRemoteDevice(address string, remoteOpts *RemoteDeviceOptions) (DeviceInt, error) RemoveRemoteDevice(address string) error Clean() On(sigName string, fn any) @@ -24,20 +24,20 @@ type DeviceManager interface { getManager() *C.FridaDeviceManager } -// deviceManager is the main structure which holds on devices available to Frida -// Single instance of the deviceManager is created when you call frida.Attach() or frida.LocalDevice(). -type deviceManager struct { +// DeviceManager is the main structure which holds on devices available to Frida +// Single instance of the DeviceManager is created when you call frida.Attach() or frida.LocalDevice(). +type DeviceManager struct { manager *C.FridaDeviceManager } // NewDeviceManager returns new frida device manager. -func NewDeviceManager() DeviceManager { +func NewDeviceManager() *DeviceManager { manager := C.frida_device_manager_new() - return &deviceManager{manager} + return &DeviceManager{manager} } // Close method will close current manager. -func (d *deviceManager) Close() error { +func (d *DeviceManager) Close() error { var err *C.GError C.frida_device_manager_close_sync(d.manager, nil, &err) if err != nil { @@ -47,7 +47,7 @@ func (d *deviceManager) Close() error { } // EnumerateDevices will return all connected devices. -func (d *deviceManager) EnumerateDevices() ([]Device, error) { +func (d *DeviceManager) EnumerateDevices() ([]DeviceInt, error) { var err *C.GError deviceList := C.frida_device_manager_enumerate_devices_sync(d.manager, nil, &err) if err != nil { @@ -55,11 +55,11 @@ func (d *deviceManager) EnumerateDevices() ([]Device, error) { } numDevices := int(C.frida_device_list_size(deviceList)) - devices := make([]Device, numDevices) + devices := make([]DeviceInt, numDevices) for i := 0; i < numDevices; i++ { device := C.frida_device_list_get(deviceList, C.gint(i)) - devices[i] = &DeviceImpl{device} + devices[i] = &Device{device} } clean(unsafe.Pointer(deviceList), unrefFrida) @@ -67,23 +67,23 @@ func (d *deviceManager) EnumerateDevices() ([]Device, error) { } // LocalDevice returns the device with type DeviceTypeLocal. -func (d *deviceManager) LocalDevice() (Device, error) { +func (d *DeviceManager) LocalDevice() (DeviceInt, error) { return d.DeviceByType(DeviceTypeLocal) } // USBDevice returns the device with type DeviceTypeUsb. -func (d *deviceManager) USBDevice() (Device, error) { +func (d *DeviceManager) USBDevice() (DeviceInt, error) { return d.DeviceByType(DeviceTypeUsb) } // RemoteDevice returns the device with type DeviceTypeRemote. -func (d *deviceManager) RemoteDevice() (Device, error) { +func (d *DeviceManager) RemoteDevice() (DeviceInt, error) { return d.DeviceByType(DeviceTypeRemote) } // DeviceByID will return device with id passed or an error if it can't find any. // Note: the caller must call EnumerateDevices() to get devices that are of type usb -func (d *deviceManager) DeviceByID(id string) (Device, error) { +func (d *DeviceManager) DeviceByID(id string) (DeviceInt, error) { idC := C.CString(id) defer C.free(unsafe.Pointer(idC)) @@ -94,12 +94,12 @@ func (d *deviceManager) DeviceByID(id string) (Device, error) { if err != nil { return nil, &FError{err} } - return &DeviceImpl{device: device}, nil + return &Device{device: device}, nil } // DeviceByType will return device or an error by device type specified. // Note: the caller must call EnumerateDevices() to get devices that are of type usb -func (d *deviceManager) DeviceByType(devType DeviceType) (Device, error) { +func (d *DeviceManager) DeviceByType(devType DeviceType) (DeviceInt, error) { var err *C.GError device := C.frida_device_manager_get_device_by_type_sync(d.manager, C.FridaDeviceType(devType), @@ -109,12 +109,12 @@ func (d *deviceManager) DeviceByType(devType DeviceType) (Device, error) { if err != nil { return nil, &FError{err} } - return &DeviceImpl{device: device}, nil + return &Device{device: device}, nil } // FindDeviceByID will try to find the device by id specified // Note: the caller must call EnumerateDevices() to get devices that are of type usb -func (d *deviceManager) FindDeviceByID(id string) (Device, error) { +func (d *DeviceManager) FindDeviceByID(id string) (DeviceInt, error) { devID := C.CString(id) defer C.free(unsafe.Pointer(devID)) @@ -130,12 +130,12 @@ func (d *deviceManager) FindDeviceByID(id string) (Device, error) { return nil, &FError{err} } - return &DeviceImpl{device: device}, nil + return &Device{device: device}, nil } // FindDeviceByType will try to find the device by device type specified // Note: the caller must call EnumerateDevices() to get devices that are of type usb -func (d *deviceManager) FindDeviceByType(devType DeviceType) (Device, error) { +func (d *DeviceManager) FindDeviceByType(devType DeviceType) (DeviceInt, error) { timeout := C.gint(defaultDeviceTimeout) var err *C.GError @@ -148,11 +148,11 @@ func (d *deviceManager) FindDeviceByType(devType DeviceType) (Device, error) { return nil, &FError{err} } - return &DeviceImpl{device: device}, nil + return &Device{device: device}, nil } // AddRemoteDevice add a remote device from the provided address with remoteOpts populated -func (d *deviceManager) AddRemoteDevice(address string, remoteOpts *RemoteDeviceOptions) (Device, error) { +func (d *DeviceManager) AddRemoteDevice(address string, remoteOpts *RemoteDeviceOptions) (DeviceInt, error) { addressC := C.CString(address) defer C.free(unsafe.Pointer(addressC)) @@ -162,11 +162,11 @@ func (d *deviceManager) AddRemoteDevice(address string, remoteOpts *RemoteDevice return nil, &FError{err} } - return &DeviceImpl{device: device}, nil + return &Device{device: device}, nil } // RemoveRemoteDevice removes remote device available at address -func (d *deviceManager) RemoveRemoteDevice(address string) error { +func (d *DeviceManager) RemoveRemoteDevice(address string) error { addressC := C.CString(address) defer C.free(unsafe.Pointer(addressC)) @@ -182,7 +182,7 @@ func (d *deviceManager) RemoveRemoteDevice(address string) error { } // Clean will clean the resources held by the manager. -func (d *deviceManager) Clean() { +func (d *DeviceManager) Clean() { clean(unsafe.Pointer(d.manager), unrefFrida) } @@ -193,10 +193,10 @@ func (d *deviceManager) Clean() { // - "added" with callback as func(device *frida.Device) {} // - "removed" with callback as func(device *frida.Device) {} // - "changed" with callback as func() {} -func (d *deviceManager) On(sigName string, fn any) { +func (d *DeviceManager) On(sigName string, fn any) { connectClosure(unsafe.Pointer(d.manager), sigName, fn) } -func (d *deviceManager) getManager() *C.FridaDeviceManager { +func (d *DeviceManager) getManager() *C.FridaDeviceManager { return d.manager } diff --git a/frida/portal_service.go b/frida/portal_service.go index 6361a37..b57c802 100644 --- a/frida/portal_service.go +++ b/frida/portal_service.go @@ -22,9 +22,9 @@ func NewPortal(clusterParams, controlParams *EndpointParameters) *Portal { } // Device returns portal device. -func (p *Portal) Device() Device { +func (p *Portal) Device() DeviceInt { dev := C.frida_portal_service_get_device(p.portal) - return &DeviceImpl{dev} + return &Device{dev} } // ClusterParams returns the cluster parameters for the portal. diff --git a/frida/types_converter.go b/frida/types_converter.go index 726a305..145b904 100644 --- a/frida/types_converter.go +++ b/frida/types_converter.go @@ -189,7 +189,7 @@ func getFridaChild(val *C.GValue) any { func getFridaDevice(val *C.GValue) any { dev := (*C.FridaDevice)(C.g_value_get_object(val)) - return &DeviceImpl{ + return &Device{ device: dev, } }