From ac1c17e5836a6953a03a336684198fc5aecc97cd Mon Sep 17 00:00:00 2001 From: dylanhitt Date: Thu, 1 Aug 2024 11:55:50 -0400 Subject: [PATCH] feat: add afc.WalkDirectory --- afc/afc.go | 103 +++++++++++++++++++++++++++++++++++++++++++ afc/errors.go | 20 +++++++++ lockdown/errors.go | 22 +++++++++ lockdown/lockdown.go | 64 +++++++++++++++++++-------- thing/main.go | 27 +++++++++--- thing/main_test.go | 7 +++ 6 files changed, 219 insertions(+), 24 deletions(-) create mode 100644 afc/afc.go create mode 100644 afc/errors.go create mode 100644 thing/main_test.go diff --git a/afc/afc.go b/afc/afc.go new file mode 100644 index 0000000..8b01f46 --- /dev/null +++ b/afc/afc.go @@ -0,0 +1,103 @@ +package afc + +// #cgo pkg-config: libimobiledevice-1.0 +// #include +// #include +// int afc_length(char **arr) +// { +// int length = 0; +// int k = 0; +// for (k = 0; arr[k] != NULL; k++) { +// length = length + 1; +// } +// return length; +// } +import "C" +import ( + "unsafe" + + "github.com/nowsecure/goidevice/idevice" + "github.com/nowsecure/goidevice/lockdown" +) + +type AFC struct { + a C.afc_client_t +} + +func NewClient(device idevice.Device, svc *lockdown.Service) (*AFC, error) { + var a C.afc_client_t + err := resultToError( + C.afc_client_new( + (C.idevice_t)(idevice.GetPointer(device)), + (C.lockdownd_service_descriptor_t)(svc.GetDescriptor()), + &a, + ), + ) + return &AFC{a}, err +} + +func (a *AFC) WalkDirectory(path string) ([]SourceFile, error) { + dir, err := a.ReadDirectory(path) + if err != nil { + return []SourceFile{}, err + } + + files := []SourceFile{} + for _, f := range dir { + if f.format == "S_IFDIR" { + childDir, err := a.WalkDirectory(f.Name) + if err != nil { + return []SourceFile{}, err + } + files = append(files, childDir...) + continue + } + files = append(files, f) + } + return files, nil +} + +type SourceFile struct { + Name string + + format string +} + +func (a *AFC) ReadDirectory(path string) ([]SourceFile, error) { + var directoryC **C.char + defer C.afc_dictionary_free(directoryC) + + sourceFiles := []SourceFile{} + pathC := C.CString(path) + defer C.free(unsafe.Pointer(pathC)) + + err := resultToError(C.afc_read_directory(a.a, pathC, &directoryC)) + if err != nil { + return []SourceFile{}, err + } + + directory := unsafe.Slice(directoryC, C.afc_length(directoryC)) + for i := range directory { + file := SourceFile{ + Name: C.GoString(directory[i]), + } + if file.Name == ".." || file.Name == "." { + continue + } + + var fileInfoC **C.char + C.afc_get_file_info(a.a, directory[i], &fileInfoC) + if fileInfoC != nil { + fileInfo := unsafe.Slice(fileInfoC, C.afc_length(fileInfoC)) + + for j := 0; j < len(fileInfo); j += 2 { + if C.GoString(fileInfo[j]) == "st_ifmt" { + file.format = C.GoString(fileInfo[j+1]) + } + } + } + C.afc_dictionary_free(fileInfoC) + sourceFiles = append(sourceFiles, file) + } + return sourceFiles, nil +} diff --git a/afc/errors.go b/afc/errors.go new file mode 100644 index 0000000..62d8d21 --- /dev/null +++ b/afc/errors.go @@ -0,0 +1,20 @@ +package afc + +// #cgo pkg-config: libimobiledevice-1.0 +// #include +// #include +import "C" +import ( + "errors" + "fmt" +) + +func resultToError(result C.afc_error_t) error { + switch result { + case 0: + return nil + default: + fmt.Println(result) + return errors.New("unknown") + } +} diff --git a/lockdown/errors.go b/lockdown/errors.go index 4c2b940..457ef7a 100644 --- a/lockdown/errors.go +++ b/lockdown/errors.go @@ -2,6 +2,7 @@ package lockdown // #cgo pkg-config: libimobiledevice-1.0 // #include +// #include import "C" import ( "errors" @@ -174,3 +175,24 @@ func resultToError(result C.lockdownd_error_t) error { return ErrUnknown } } + +func serviceResultToError(result C.service_error_t) error { + switch result { + case 0: + return nil + case -1: + return errors.New("invalid args") + case -3: + return errors.New("mux error") + case -4: + return errors.New("ssl error") + case -5: + return errors.New("start service error") + case -6: + return errors.New("not enough data error") + case -7: + return errors.New("timeout") + default: + return errors.New("unknown") + } +} diff --git a/lockdown/lockdown.go b/lockdown/lockdown.go index df0d515..ed80a6e 100644 --- a/lockdown/lockdown.go +++ b/lockdown/lockdown.go @@ -21,8 +21,10 @@ type Client interface { ValidatePair() error DeviceName() (string, error) PList(domain string) (*plist.PList, error) - Close() error + Free() error + GetClient() unsafe.Pointer StartService(d idevice.Device, serviceName string) (*Service, error) + StartServiceClient(d idevice.Device, serviceName string) (*Service, error) } type client struct { @@ -99,25 +101,30 @@ func (s *client) PList(domain string) (*plist.PList, error) { return list, nil } -func (s *client) Close() error { - err := resultToError(C.lockdownd_client_free(s.p)) - if err == nil { - s.p = nil - } - return err +func (s *client) Free() error { + return resultToError(C.lockdownd_client_free(s.p)) } -type Service struct { - s C.service_client_t +func (s *client) GetClient() unsafe.Pointer { + return unsafe.Pointer(s.p) } -const ( - CRASH_REPORT_MOVER_SERVICE = "com.apple.crashreportmover" -) +// GetDescriptor gets the lockdown descriptor for the service +func (s *Service) GetDescriptor() unsafe.Pointer { + return unsafe.Pointer(s.descriptor) +} + +func (s *Service) FreeDescriptor() { + C.lockdownd_service_descriptor_free(s.descriptor) +} + +func (s *Service) Free() { + C.lockdownd_service_descriptor_free(s.descriptor) + C.service_client_free(s.s) +} func (s *client) StartService(d idevice.Device, serviceName string) (*Service, error) { var p C.lockdownd_service_descriptor_t - svc := C.CString(serviceName) defer C.free(unsafe.Pointer(svc)) err := resultToError(C.lockdownd_start_service(s.p, svc, &p)) @@ -125,13 +132,32 @@ func (s *client) StartService(d idevice.Device, serviceName string) (*Service, e return nil, err } - var c C.service_client_t - res := C.service_client_new((C.idevice_t)(idevice.GetPointer(d)), p, &c) - C.lockdownd_service_descriptor_free(p) - if res != 0 { - return nil, errors.New(":(") + return &Service{descriptor: p}, nil +} + +type Service struct { + s C.service_client_t + descriptor C.lockdownd_service_descriptor_t +} + +const ( + CRASH_REPORT_MOVER_SERVICE = "com.apple.crashreportmover" + CRASH_REPORT_COPY_MOBILE_SERVICE = "com.apple.crashreportcopymobile" +) + +func (s *client) StartServiceClient(d idevice.Device, serviceName string) (*Service, error) { + svc, err := s.StartService(d, serviceName) + if err != nil { + return nil, err } - return &Service{c}, nil + + err = serviceResultToError( + C.service_client_new((C.idevice_t)(idevice.GetPointer(d)), + svc.descriptor, + &svc.s, + ), + ) + return svc, err } func (s *Service) ReadPing() error { diff --git a/thing/main.go b/thing/main.go index 8b11834..1500316 100644 --- a/thing/main.go +++ b/thing/main.go @@ -1,15 +1,16 @@ package main import ( + "fmt" "log" - "os" + "github.com/nowsecure/goidevice/afc" "github.com/nowsecure/goidevice/idevice" "github.com/nowsecure/goidevice/lockdown" ) func main() { - device, err := idevice.New(os.Args[1]) + device, err := idevice.New("bd133240a37062e545bbbbf664f0011c9f45895d") if err != nil { log.Fatal(err) } @@ -17,14 +18,30 @@ func main() { if err != nil { log.Fatal(err) } - client, err := lock.StartService(device, lockdown.CRASH_REPORT_MOVER_SERVICE) + client, err := lock.StartServiceClient(device, lockdown.CRASH_REPORT_MOVER_SERVICE) if err != nil { log.Fatal(err) } + defer client.Free() err = client.ReadPing() if err != nil { log.Fatal(err) - } else { - log.Println("yay we did it") } + + service, err := lock.StartService(device, lockdown.CRASH_REPORT_COPY_MOBILE_SERVICE) + if err != nil { + log.Fatal(err) + } + defer service.Free() + + afc, err := afc.NewClient(device, service) + if err != nil { + log.Fatal(err) + } + k, _ := afc.WalkDirectory(".") + for _, v := range k { + fmt.Println(v) + } + + log.Println("yay we did it") } diff --git a/thing/main_test.go b/thing/main_test.go new file mode 100644 index 0000000..87a1775 --- /dev/null +++ b/thing/main_test.go @@ -0,0 +1,7 @@ +package main + +import "testing" + +func Test_ke(t *testing.T) { + main() +}