Skip to content

Commit

Permalink
feat: provide interface frida.Device
Browse files Browse the repository at this point in the history
  • Loading branch information
dylanhitt committed Jan 25, 2024
1 parent ef5b483 commit ad624be
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 66 deletions.
93 changes: 62 additions & 31 deletions frida/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,60 @@ 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))
}
return ""
}

// 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))
}
return ""
}

// 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))
Expand All @@ -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)
Expand All @@ -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{
Expand All @@ -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}
Expand All @@ -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
Expand All @@ -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)
Expand All @@ -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{}
Expand All @@ -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))
Expand Down Expand Up @@ -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))
Expand All @@ -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))
Expand All @@ -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))
Expand All @@ -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))
Expand All @@ -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))
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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 {
Expand All @@ -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) {
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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() {
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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))
Expand All @@ -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)
}
Expand All @@ -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)
}
Expand Down
14 changes: 7 additions & 7 deletions frida/frida.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,23 +41,23 @@ 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 {
dev, _ := mgr.DeviceByType(DeviceTypeLocal)
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 {
Expand All @@ -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 {
Expand All @@ -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.
Expand Down
Loading

0 comments on commit ad624be

Please sign in to comment.