Giter Club home page Giter Club logo

gidevice's Introduction

Golang-iDevice

go doc go report license

much more easy to use 👉 electricbubble/gidevice-cli

Installation

go get github.com/electricbubble/gidevice

Devices

package main

import (
	giDevice "github.com/electricbubble/gidevice"
	"log"
)

func main() {
	usbmux, err := giDevice.NewUsbmux()
	if err != nil {
		log.Fatalln(err)
	}

	devices, err := usbmux.Devices()
	if err != nil {
		log.Fatal(err)
	}

	for _, dev := range devices {
		log.Println(dev.Properties().SerialNumber, dev.Properties().ProductID, dev.Properties().DeviceID)
	}
}

GetValue

package main

import (
	"encoding/json"
	"fmt"
	giDevice "github.com/electricbubble/gidevice"
	"log"
)

type DeviceDetail struct {
	DeviceName                string `json:"DeviceName,omitempty"`
	DeviceColor               string `json:"DeviceColor,omitempty"`
	DeviceClass               string `json:"DeviceClass,omitempty"`
	ProductVersion            string `json:"ProductVersion,omitempty"`
	ProductType               string `json:"ProductType,omitempty"`
	ProductName               string `json:"ProductName,omitempty"`
	ModelNumber               string `json:"ModelNumber,omitempty"`
	SerialNumber              string `json:"SerialNumber,omitempty"`
	SIMStatus                 string `json:"SIMStatus,omitempty"`
	PhoneNumber               string `json:"PhoneNumber,omitempty"`
	CPUArchitecture           string `json:"CPUArchitecture,omitempty"`
	ProtocolVersion           string `json:"ProtocolVersion,omitempty"`
	RegionInfo                string `json:"RegionInfo,omitempty"`
	TelephonyCapability       bool   `json:"TelephonyCapability,omitempty"`
	TimeZone                  string `json:"TimeZone,omitempty"`
	UniqueDeviceID            string `json:"UniqueDeviceID,omitempty"`
	WiFiAddress               string `json:"WiFiAddress,omitempty"`
	WirelessBoardSerialNumber string `json:"WirelessBoardSerialNumber,omitempty"`
	BluetoothAddress          string `json:"BluetoothAddress,omitempty"`
	BuildVersion              string `json:"BuildVersion,omitempty"`
}

func main() {
	usbmux, err := giDevice.NewUsbmux()
	if err != nil {
		log.Fatal(err)
	}

	devices, err := usbmux.Devices()
	if err != nil {
		log.Fatal(err)
	}

	if len(devices) == 0 {
		log.Fatal("No Device")
	}

	d := devices[0]

	detail, err1 := d.GetValue("", "")
	if err1 != nil {
		fmt.Errorf("get %s device detail fail : %w", d.Properties().SerialNumber, err1)
	}

	data, _ := json.Marshal(detail)
	d1 := &DeviceDetail{}
	json.Unmarshal(data, d1)
	fmt.Println(d1)
}

DeveloperDiskImage

package main

import (
	"encoding/base64"
	giDevice "github.com/electricbubble/gidevice"
	"log"
)

func main() {
	usbmux, err := giDevice.NewUsbmux()
	if err != nil {
		log.Fatal(err)
	}

	devices, err := usbmux.Devices()
	if err != nil {
		log.Fatal(err)
	}

	if len(devices) == 0 {
		log.Fatal("No Device")
	}

	d := devices[0]

	imageSignatures, err := d.Images()
	if err != nil {
		log.Fatalln(err)
	}

	for i, imgSign := range imageSignatures {
		log.Printf("[%d] %s\n", i+1, base64.StdEncoding.EncodeToString(imgSign))
	}

	dmgPath := "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/14.4/DeveloperDiskImage.dmg"
	signaturePath := "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/14.4/DeveloperDiskImage.dmg.signature"

	err = d.MountDeveloperDiskImage(dmgPath, signaturePath)
	if err != nil {
		log.Fatalln(err)
	}
}

App

package main

import (
	giDevice "github.com/electricbubble/gidevice"
	"log"
	"path/filepath"
)

func main() {
	usbmux, err := giDevice.NewUsbmux()
	if err != nil {
		log.Fatalln(err)
	}

	devices, err := usbmux.Devices()
	if err != nil {
		log.Fatalln(err)
	}

	if len(devices) == 0 {
		log.Fatalln("No Device")
	}

	d := devices[0]

	bundleID := "com.apple.Preferences"
	pid, err := d.AppLaunch(bundleID)
	if err != nil {
		log.Fatalln(err)
	}

	err = d.AppKill(pid)
	if err != nil {
		log.Fatalln(err)
	}

	runningProcesses, err := d.AppRunningProcesses()
	if err != nil {
		log.Fatalln(err)
	}

	for _, process := range runningProcesses {
		if process.IsApplication {
			log.Printf("%4d\t%-24s\t%-36s\t%s\n", process.Pid, process.Name, filepath.Base(process.RealAppName), process.StartDate)
		}
	}
}

Screenshot

package main

import (
	giDevice "github.com/electricbubble/gidevice"
	"image"
	"image/jpeg"
	"image/png"
	"log"
	"os"
)

func main() {
	usbmux, err := giDevice.NewUsbmux()
	if err != nil {
		log.Fatalln(err)
	}

	devices, err := usbmux.Devices()
	if err != nil {
		log.Fatalln(err)
	}

	if len(devices) == 0 {
		log.Fatalln("No Device")
	}

	d := devices[0]

	raw, err := d.Screenshot()
	if err != nil {
		log.Fatalln(err)
	}

	img, format, err := image.Decode(raw)
	if err != nil {
		log.Fatalln(err)
	}
	userHomeDir, _ := os.UserHomeDir()
	file, err := os.Create(userHomeDir + "/Desktop/s1." + format)
	if err != nil {
		log.Fatalln(err)
	}
	defer func() { _ = file.Close() }()
	switch format {
	case "png":
		err = png.Encode(file, img)
	case "jpeg":
		err = jpeg.Encode(file, img, nil)
	}
	if err != nil {
		log.Fatalln(err)
	}
	log.Println(file.Name())
}

SimulateLocation

package main

import (
	giDevice "github.com/electricbubble/gidevice"
	"log"
)

func main() {
	usbmux, err := giDevice.NewUsbmux()
	if err != nil {
		log.Fatalln(err)
	}

	devices, err := usbmux.Devices()
	if err != nil {
		log.Fatalln(err)
	}

	if len(devices) == 0 {
		log.Fatalln("No Device")
	}

	d := devices[0]

	// https://api.map.baidu.com/lbsapi/getpoint/index.html
	if err = d.SimulateLocationUpdate(116.024067, 40.362639, giDevice.CoordinateSystemBD09); err != nil {
		log.Fatalln(err)
	}

	// https://developer.amap.com/tools/picker
	// https://lbs.qq.com/tool/getpoint/index.html
	// if err = d.SimulateLocationUpdate(120.116979, 30.252876, giDevice.CoordinateSystemGCJ02); err != nil {
	// 	log.Fatalln(err)
	// }

	// if err = d.SimulateLocationUpdate(121.499763, 31.239580,giDevice.CoordinateSystemWGS84); err != nil {
	// if err = d.SimulateLocationUpdate(121.499763, 31.239580); err != nil {
	// 	log.Fatalln(err)
	// }

	// err = d.SimulateLocationRecover()
	// if err != nil {
	// 	log.Fatalln(err)
	// }
}

XCTest

package main

import (
	"fmt"
	giDevice "github.com/electricbubble/gidevice"
	"log"
	"os"
	"os/signal"
)

func main() {
	usbmux, err := giDevice.NewUsbmux()
	if err != nil {
		log.Fatal(err)
	}

	devices, err := usbmux.Devices()
	if err != nil {
		log.Fatal(err)
	}

	if len(devices) == 0 {
		log.Fatal("No Device")
	}

	d := devices[0]

	out, cancel, err := d.XCTest("com.leixipaopao.WebDriverAgentRunner.xctrunner")
	if err != nil {
		log.Fatal(err)
	}

	done := make(chan os.Signal, 1)
	signal.Notify(done, os.Interrupt)

	go func() {
		for s := range out {
			fmt.Print(s)
		}
	}()

	<-done
	cancel()
	fmt.Println()
	log.Println("DONE")
}

Connect and Forward

package main

import (
	"fmt"
	giDevice "github.com/electricbubble/gidevice"
	"io"
	"log"
	"net"
	"os"
	"os/signal"
	"time"
	"syscall"
)

func main() {
	usbmux, err := giDevice.NewUsbmux()
	if err != nil {
		log.Fatal(err)
	}

	devices, err := usbmux.Devices()
	if err != nil {
		log.Fatal(err)
	}

	if len(devices) == 0 {
		log.Fatal("No Device")
	}

	d := devices[0]

	localPort, remotePort := 8100, 8100

	listener, err := net.Listen("tcp", fmt.Sprintf(":%d", localPort))

	go func(listener net.Listener) {
		for {
			var accept net.Conn
			if accept, err = listener.Accept(); err != nil {
				log.Println("accept:", err)
			}

			fmt.Println("accept", accept.RemoteAddr())

			rInnerConn, err := d.NewConnect(remotePort)
			if err != nil {
				log.Println(err)
				os.Exit(0)
			}

			rConn := rInnerConn.RawConn()
			_ = rConn.SetDeadline(time.Time{})

			go func(lConn net.Conn) {
				go func(lConn, rConn net.Conn) {
					if _, err := io.Copy(lConn, rConn); err != nil {
						//do sth
					}
				}(lConn, rConn)
				go func(lConn, rConn net.Conn) {
					if _, err := io.Copy(rConn, lConn); err != nil {
						//do sth
					}
				}(lConn, rConn)
			}(accept)
		}
	}(listener)

	done := make(chan os.Signal, syscall.SIGTERM)
	signal.Notify(done, os.Interrupt, os.Kill)
	<-done
}

Thanks

About
libimobiledevice/libimobiledevice A cross-platform protocol library to communicate with iOS devices
anonymous5l/iConsole iOS usbmuxd communication impl iTunes protocol
alibaba/taobao-iphone-device tidevice can be used to communicate with iPhone device

Thank you JetBrains for providing free open source licenses

gidevice's People

Contributors

electricbubble avatar prife avatar solskgaer avatar zhouyixun avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gidevice's Issues

[Q] xctest貌似会偶断

xctest启动后几分钟不动会断开,访问/status也是死掉了,然后过阵子访问又可以,这情况发生概率有点高。断开期间已确认没有任何wda指令发送过去阻塞。tidevice没有这个问题,不知道是tidevice做的xctest监听异常就杀掉重启的功劳还是底层实现不一样呢?

同学,您这个项目引入了9个开源组件,存在2个漏洞,辛苦升级一下

检测到 electricbubble/gidevice 一共引入了9个开源组件,存在2个漏洞

漏洞标题:go-yaml < 2.2.8拒绝服务漏洞
缺陷组件:gopkg.in/[email protected]
漏洞编号:CVE-2019-11254
漏洞描述:gopkg.in/yaml.v2是go语言中用于处理yaml格式的包。
在2.2.8之前的版本中,处理恶意的yaml数据时,会导致CPU资源耗尽。
漏洞由Kubernetes开发者在fuzz测试中发现并提交修复补丁。
国家漏洞库信息:https://www.cnvd.org.cn/flaw/show/CNVD-2020-35519
影响范围:(∞, 2.2.8)
最小修复版本:2.2.8
缺陷组件引入路径:github.com/electricbubble/gidevice@->gopkg.in/[email protected]

另外还有2个漏洞,详细报告:https://mofeisec.com/jr?p=a68dca

XCTest 异常如何监测

	out, cancel, err := d.XCTest("com.aichy.wb.xctrunner")
	if err != nil {
		log.Fatal(err)
	}

这里如果手机连接状态异常比如usb拔掉了或者 XCTest 崩溃了如何监测呢?感谢~

运行时偶现 panic

运行命令

./gidevice xctest com.facebook.WebDriverAgentRunner.xctrunner -u xxxx --env=USE_PORT=8100 --env=MJPEG_SERVER_PORT=9100

执行一段时间后,运行基于 appium 的 UI 自动化脚本时,出现如下报错然后自动退出:

 t =  3505.76s     Requesting snapshot of accessibility hierarchy for app with pid 566
    t =  3506.16s     Find: Descendants matching type Any
    t =  3506.17s     Find: Elements matching predicate '(wdType == "XCUIElementTypeTextField" AND wdValue == "请输入手机号") AND (1 == 1 OR identifier == 0 OR frame == 0 OR value == 0 OR title == 0 OR label == 0 OR elementType == 0 OR enabled == 0 OR placeholderValue == 0 OR selected == 0)'
panic: runtime error: slice bounds out of range [:209106] with capacity 132768

goroutine 8 [running]:
github.com/electricbubble/gidevice/pkg/libimobiledevice.(*dtxMessageClient).ReceiveDTXMessage(0xc00038b1a0, 0xc000096000, 0x0, 0x0)
	/home/runner/go/pkg/mod/github.com/electricbubble/[email protected]/pkg/libimobiledevice/client_dtxmessage.go:180 +0x1265
github.com/electricbubble/gidevice/pkg/libimobiledevice.(*dtxMessageClient).startReceive.func1(0xc00038b1a0)
	/home/runner/go/pkg/mod/github.com/electricbubble/[email protected]/pkg/libimobiledevice/client_dtxmessage.go:326 +0x5e
created by github.com/electricbubble/gidevice/pkg/libimobiledevice.(*dtxMessageClient).startReceive
	/home/runner/go/pkg/mod/github.com/electricbubble/[email protected]/pkg/libimobiledevice/client_dtxmessage.go:320 +0x3f

目前为偶现,暂时未找到稳定复现步骤。

反复插拔usb 加载gidevice 会panic 建议增加Recover

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x20 pc=0xabaa90]

goroutine 232 [running]:
github.com/electricbubble/gidevice/pkg/libimobiledevice.(*dtxMessageClient).startReceive.func1()
	/home/work/go/pkg/mod/github.com/electricbubble/[email protected]/pkg/libimobiledevice/client_dtxmessage.go:323 +0x30
created by github.com/electricbubble/gidevice/pkg/libimobiledevice.(*dtxMessageClient).startReceive
	/home/work/go/pkg/mod/github.com/electricbubble/[email protected]/pkg/libimobiledevice/client_dtxmessage.go:320 +0x5b

undefined: io.ReadAll

package main
import (

	giDevice "github.com/electricbubble/gidevice"
	"github.com/electricbubble/gidevice/pkg/libimobiledevice"

)

func main() {
	libimobiledevice.SetDebug(true)
	giDevice.NewUsbmux()
}

vendor/github.com/electricbubble/gidevice/pkg/ipa/ipa.go:35:17: undefined: io.ReadAll

我需要初始化什么么?

SimulateLocationUpdate return InvalidService error

hi, I ran the example code of SimulateLocation but return error as below

2021/06/12 01:07:39 receive packet: InvalidService

Here is my code and iOS version is 14.0.1

package main

import (
	"log"

	giDevice "github.com/electricbubble/gidevice"
	"github.com/electricbubble/gidevice/pkg/libimobiledevice"
)

func main() {
	libimobiledevice.SetDebug(true)

	usbmux, err := giDevice.NewUsbmux()
	if err != nil {
		log.Fatalln(err)
	}

	devices, err := usbmux.Devices()
	if err != nil {
		log.Fatalln(err)
	}

	if len(devices) == 0 {
		log.Fatalln("No Device")
	}

	d := devices[0]

	// https://developer.amap.com/tools/picker
	// https://lbs.qq.com/tool/getpoint/index.html
	if err = d.SimulateLocationUpdate(113.925734, 22.511836, giDevice.CoordinateSystemWGS84); err != nil {
		log.Fatalln(err)
	}
}

I tried to debug this program and found it break at this function

func (c *lockdown) startService(service string, escrowBag []byte) (dynamicPort int, enableSSL bool, err error) {
	req := c.client.NewStartServiceRequest(service)
	if escrowBag != nil {
		req.EscrowBag = escrowBag
	}

	var pkt libimobiledevice.Packet
	if pkt, err = c.client.NewXmlPacket(req); err != nil {
		return 0, false, err
	}

	if err = c.client.SendPacket(pkt); err != nil {
		return 0, false, err
	}
        // returned error InvalidService
	respPkt, err := c.client.ReceivePacket()
	if err != nil {
		return 0, false, err
	}

	var reply libimobiledevice.LockdownStartServiceResponse
	if err = respPkt.Unmarshal(&reply); err != nil {
		return 0, false, err
	}

	if reply.Error != "" {
		return 0, false, fmt.Errorf("lockdown start service: %s", reply.Error)
	}

	dynamicPort = reply.Port
	enableSSL = reply.EnableServiceSSL

	return
}

Any Suggestion?

Fail when installing big ipa file

When installing a big ipa file (3.3G), it will report error after uploading to PublicStaging:

device_test.go:104: receive packet: read tcp 127.0.0.1:15119->127.0.0.1:27015: wsarecv: An established connection was aborted by the software in your host machine.

It seems like lockdown connection has been closed by the phone.
A simple fix would work:
`

func (d *device) AppInstall(ipaPath string) (err error) {
if _, err = d.AfcService(); err != nil {
return err
}

stagingPath := "PublicStaging"
if _, err = d.afc.Stat(stagingPath); err != nil {
	if err != ErrAfcStatNotExist {
		return err
	}
	if err = d.afc.Mkdir(stagingPath); err != nil {
		return fmt.Errorf("app install: %w", err)
	}
}

var info map[string]interface{}
if info, err = ipa.Info(ipaPath); err != nil {
	return err
}
bundleID, ok := info["CFBundleIdentifier"]
if !ok {
	return errors.New("can't find 'CFBundleIdentifier'")
}

installationPath := path.Join(stagingPath, fmt.Sprintf("%s.ipa", bundleID))

var data []byte
if data, err = os.ReadFile(ipaPath); err != nil {
	return err
}
if err = d.afc.WriteFile(installationPath, data, AfcFileModeWr); err != nil {
	return err
}

d.lockdown = nil

if _, err = d.installationProxyService(); err != nil {
	return err
}

return d.installationProxy.Install(fmt.Sprintf("%s", bundleID), installationPath)

}

`

Add a d.lockdown = nil before loading installation proxy service.
But I'm not sure that's the best way of fixing.

watch service

Can you add watch service also like it's implemented in tidevice?

IOS 17 Support

Starting at iOS 17.0, Apple refactored a lot in the way iOS devices communicate with the macOS. Up until iOS 16, The communication was TCP based (using the help of usbmuxd for USB devices) with TLS (for making sure only trusted peers are able to connect).

Since the above change I am not able to use the screenshot service.

Can someone please look into how to integrate the new service according to new protocol please?

[feat] WebInspector

我预计六月份补充一下com.apple.webinspector service implementation.

How to get value with domain?

I want to get battery data.

device.GetValue("com.apple.mobile.battery","")

but I get nil map.
What should I do? thx

gidevice 和 gwda 如何在一个项目里配合使用呢?

gidevice 开启 XCTest 确认连接状态使用 gwda控制

	out, cancel, err := ID.XCTest(bundleID)
	if err != nil {
		log.Fatal(err)
	}

	done := make(chan os.Signal, 1)
	signal.Notify(done, os.Interrupt)

	go func() {
		for s := range out {
			fmt.Print(s)
			has := strings.Contains(s, "Using singleton test manager")
			if has {
				driver, _ := gwda.NewUSBDriver(nil)
				driver.PressButton(gwda.DeviceButtonHome)
				driver.SiriActivate("What's the weather like today")
			}
		}
	}()

	<-done
	cancel()

或者有更好的办法么?

com.apple.instruments.server.services.coreprofilesessiontap,返回的数据异常

我这边正在基于gidevice开发Go版的性能监控工具,CPU、GPU、流量等功能已正常实现,当尝试实现统计帧率、jank次数、和卡顿率功能时,参考了py-ios-device中获取并解析com.apple.instruments.server.services.coreprofilesessiontap帧渲染数据的逻辑,发现gidevice返回的数据不正常,预期返回的数据长度应该是和py-ios-device一样(64的整数倍),但实际测试返回的数据长度是随机没有规律的,如下图所示:

  1. py-ios-device返回的数据header:
    企业微信截图_16682485471343

  2. gidevice返回的数据header:
    企业微信截图_16682488998392

造成这种现象我觉得最大的可能是调用com.apple.instruments.server.services.coreprofilesessiontap时,传过去的参数没有被正确接受和解析,导致InstrumentsServer返回的不是预期的数据,希望大佬帮忙排查一下,参数结构如下图所示:

  1. py-ios-device传的参数:
    image

  2. gidevice传的参数:
    image

  3. 尝试过在gidevice发送请求时,直接将aux替换成py-ios-device中的aux,返回的数据依旧异常:
    image

panic: runtime error: invalid memory address or nil pointer dereference

用的过程会有偶现这个报错,一般重试可以正常运行,但是想看看能不能优化一下这部分

panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x20 pc=0x704070]

goroutine 9 [running]:
github.com/electricbubble/gidevice/pkg/libimobiledevice.(*dtxMessageClient).startReceive.func1()
        *********/go/pkg/mod/github.com/electricbubble/[email protected]/pkg/libimobiledevice/client_dtxmessage.go:342 +0x30
created by github.com/electricbubble/gidevice/pkg/libimobiledevice.(*dtxMessageClient).startReceive
       ********/go/pkg/mod/github.com/electricbubble/[email protected]/pkg/libimobiledevice/client_dtxmessage.go:339 +0x56
exit status 2

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.