Skip to content

Commit

Permalink
Add some features and fix some bugs (#38)
Browse files Browse the repository at this point in the history
* add pcap file export

* add comment and make it better

* Replace println with fmt.Println to avoid the problem of output to stderr

* trim log message

* redef pph

* feat: pcap use --pid or --process to filter specific processes
  • Loading branch information
appl3s authored May 12, 2021
1 parent e053e33 commit 6d10947
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 37 deletions.
92 changes: 64 additions & 28 deletions ios/pcap/pcap.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ package pcap

import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"os"
"strings"
"time"

"github.com/danielpaulus/go-ios/ios"
Expand All @@ -14,16 +14,41 @@ import (
"howett.net/plist"
)

// PcapPlistHeader :)
// ref: https://github.com/iOSForensics/pymobiledevice/blob/master/pymobiledevice/pcapd.py
type PcapPlistHeader struct {
HdrSize int `struc:"uint32,big"`
Xxx int `struc:"uint8,big"`
PacketSize int `struc:"uint32,big"`
Flag1 int `struc:"uint32,big"`
Flag2 int `struc:"uint32,big"`
OffsetToIPData int `struc:"uint32,big"`
Zero int `struc:"uint32,big"`
var (
// IOSPacketHeader default is -1
Pid = int32(-2)
ProcName string
)

// IOSPacketHeader :)
// ref: https://github.com/gofmt/iOSSniffer/blob/master/pkg/sniffer/sniffer.go#L44
type IOSPacketHeader struct {
HdrSize uint32 `struc:"uint32,big"`
Version uint8 `struc:"uint8,big"`
PacketSize uint32 `struc:"uint32,big"`
Type uint8 `struc:"uint8,big"`
Unit uint16 `struc:"uint16,big"`
IO uint8 `struc:"uint8,big"`
ProtocolFamily uint32 `struc:"uint32,big"`
FramePreLength uint32 `struc:"uint32,big"`
FramePstLength uint32 `struc:"uint32,big"`
IFName string `struc:"[16]byte"`
Pid int32 `struc:"int32,little"`
ProcName string `struc:"[17]byte"`
Unknown uint32 `struc:"uint32,little"`
Pid2 int32 `struc:"int32,little"`
ProcName2 string `struc:"[17]byte"`
Unknown2 [8]byte `struc:"[8]byte"`
}

func (iph *IOSPacketHeader) ToString() string {
trim := func(src string) string {
return strings.ReplaceAll(src, "\x00", "")
}
iph.IFName = trim(iph.IFName)
iph.ProcName = trim(iph.ProcName)
iph.ProcName2 = trim(iph.ProcName2)
return fmt.Sprintf("%v", *iph)
}

func Start(device ios.DeviceEntry) error {
Expand All @@ -32,7 +57,12 @@ func Start(device ios.DeviceEntry) error {
return err
}
plistCodec := ios.NewPlistCodec()
fname := fmt.Sprintf("dump-%d.pcap",time.Now().Unix())
fname := fmt.Sprintf("dump-%d.pcap", time.Now().Unix())
if Pid > 0 {
fname = fmt.Sprintf("dump-%d-%d.pcap", Pid, time.Now().Unix())
} else if ProcName != "" {
fname = fmt.Sprintf("dump-%s-%d.pcap", ProcName, time.Now().Unix())
}
f, err := createPcap(fname)
if err != nil {
return err
Expand All @@ -52,10 +82,11 @@ func Start(device ios.DeviceEntry) error {
if err != nil {
return err
}

err = writePacket(f, packet)
if err != nil {
return err
if len(packet) > 0 {
err = writePacket(f, packet)
if err != nil {
return err
}
}
}
}
Expand Down Expand Up @@ -107,8 +138,8 @@ func createPcap(name string) (*os.File, error) {
func writePacket(f *os.File, packet []byte) error {
now := time.Now()
phs := &PcaprecHdrS{
int(now.UTC().Unix()),
int(now.UTC().UnixNano() * 1000),
int(now.Unix()),
int(now.UnixNano() / 1e6),
len(packet),
len(packet),
}
Expand All @@ -123,24 +154,29 @@ func writePacket(f *os.File, packet []byte) error {
}

func getPacket(buf []byte) ([]byte, error) {
pph := PcapPlistHeader{}
iph := IOSPacketHeader{}
preader := bytes.NewReader(buf)
struc.Unpack(preader, &pph)
struc.Unpack(preader, &iph)

interfacetype := make([]byte, pph.HdrSize-25)
cnt, err := preader.Read(interfacetype)
if err != nil {
return []byte{}, err
// Only return specific packet
if Pid > 0 {
if iph.Pid != Pid && iph.Pid2 != Pid {
return []byte{}, nil
}
}
if cnt != pph.HdrSize-25 {
return []byte{}, errors.New("invalid HdrSize")

if ProcName != "" {
if !strings.HasPrefix(iph.ProcName, ProcName) && !strings.HasPrefix(iph.ProcName2, ProcName) {
return []byte{}, nil
}
}
log.Debug(interfacetype)

log.Info("IOSPacketHeader: ", iph.ToString())
packet, err := ioutil.ReadAll(preader)
if err != nil {
return packet, err
}
if pph.OffsetToIPData == 0 {
if iph.FramePreLength == 0 {
ext := []byte{0xbe, 0xfe, 0xbe, 0xfe, 0xbe, 0xfe, 0xbe, 0xfe, 0xbe, 0xfe, 0xbe, 0xfe, 0x08, 0x00}
return append(ext, packet...), nil
}
Expand Down
25 changes: 16 additions & 9 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"io/ioutil"
"path/filepath"
"runtime/debug"
"strings"
"syscall"

"os"
Expand Down Expand Up @@ -56,7 +57,7 @@ Usage:
ios forward [options] <hostPort> <targetPort>
ios dproxy [--binary]
ios readpair [options]
ios pcap [options]
ios pcap [options] [--pid=<processID>] [--process=<processName>]
ios apps [--system] [options]
ios launch <bundleID> [options]
ios runtest <bundleID> [options]
Expand Down Expand Up @@ -96,7 +97,7 @@ The commands work as following:
> to stop usbmuxd and load to start it again should the proxy mess up things.
> The --binary flag will dump everything in raw binary without any decoding.
ios readpair Dump detailed information about the pairrecord for a device.
ios pcap [options] Starts a pcap dump of network traffic
ios pcap [options] [--pid=<processID>] [--process=<processName>] Starts a pcap dump of network traffic, use --pid or --process to filter specific processes.
ios apps [--system] Retrieves a list of installed applications. --system prints out preinstalled system apps.
ios launch <bundleID> Launch app with the bundleID on the device. Get your bundle ID from the apps command.
ios runtest <bundleID> Run a XCUITest.
Expand Down Expand Up @@ -159,6 +160,10 @@ The commands work as following:

b, _ = arguments.Bool("pcap")
if b {
p, _ := arguments.String("--process")
i, _ := arguments.Int("--pid")
pcap.Pid = int32(i)
pcap.ProcName = p
err := pcap.Start(device)
if err != nil {
exitIfError("pcap failed", err)
Expand Down Expand Up @@ -466,9 +471,9 @@ func printDeviceName(device ios.DeviceEntry) {
allValues, err := ios.GetValues(device)
exitIfError("failed getting values", err)
if JSONdisabled {
println(allValues.Value.DeviceName)
fmt.Println(allValues.Value.DeviceName)
} else {
println(convertToJSONString(map[string]string{
fmt.Println(convertToJSONString(map[string]string{
"devicename": allValues.Value.DeviceName,
}))
}
Expand All @@ -491,7 +496,7 @@ func saveScreenshot(device ios.DeviceEntry, outputPath string) {
exitIfError("write file failed", err)

if JSONdisabled {
println(outputPath)
fmt.Println(outputPath)
} else {
log.WithFields(log.Fields{"outputPath": outputPath}).Info("File saved successfully")
}
Expand All @@ -504,7 +509,7 @@ func processList(device ios.DeviceEntry) {
exitIfError("failed opening deviceInfoService for getting process list", err)
}
processList, err := service.ProcessList()
println(convertToJSONString(processList))
fmt.Println(convertToJSONString(processList))
}

func printDeviceList(details bool) {
Expand Down Expand Up @@ -582,7 +587,7 @@ func startListening() {
log.Error("Stopped listening because of error")
break
}
println(convertToJSONString((msg)))
fmt.Println(convertToJSONString((msg)))
}
}
}()
Expand Down Expand Up @@ -614,11 +619,13 @@ func runSyslog(device ios.DeviceEntry) {
if err != nil {
exitIfError("failed reading syslog", err)
}
logMessage = strings.TrimSuffix(logMessage, "\x00")
logMessage = strings.TrimSuffix(logMessage, "\x0A")
if JSONdisabled {
print(logMessage)
fmt.Println(logMessage)
} else {
messageContainer["msg"] = logMessage
println(convertToJSONString(messageContainer))
fmt.Println(convertToJSONString(messageContainer))
}
}
}()
Expand Down

0 comments on commit 6d10947

Please sign in to comment.