-
Notifications
You must be signed in to change notification settings - Fork 5
/
idb
executable file
·546 lines (501 loc) · 18.6 KB
/
idb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
#! /bin/sh
# Definitions at top of file for easy editing.
# Local machine's TCP relay port
LOCALPORT=2222
# Port on the computer to use for iproxy's TCP forwarding. Low port numbers
# may require root on some systems.
# Remote port
REMOTEPORT=22
# The port sshd runs on on the device. The default sshd listens on is usually
# port 22, so use that unless you've changed it on the iDevice in /etc/sshd_config
# "Overrides" configuration file
CONFFILE="$HOME"'/.config/idb.conf'
# Location of a file which contains UDID-specific override settings
# (port numbers and such) for specific iDevices. See the sample idb.conf
# for more information on how to use it. Only really handy if you have
# more than one device wired in to your computer at a time.
# User name on iDevice
DEVICE_USER="mobile"
# The user to log in as, for operations performed through SSH-over-USB.
# ideviceinstaller name/path goes here.
IDEVICEINSTALLER="ideviceinstaller"
# You should change this only if you have ideviceinstaller outside of your
# $PATH or you have renamed the program.
# idevicedebug name/path goes here.
IDEVICEDEBUG="idevicedebug"
# You should change this only if you have idevicedebug outside of your
# $PATH or you have renamed the program.
# idevicesyslog name/path goes here.
IDEVICESYSLOG="idevicesyslog"
IDEVICEIMAGEMOUNTER="ideviceimagemounter"
IDEVICESCREENSHOT="idevicescreenshot"
# developer disk image can optionally go here. /dev/null = no image.
# Can be overridden by idb.conf.
DEVDISKIMG=/dev/null
# Should IPA's be installed via SSH commands or via libimobiledevice?
# In future: should we use SSH or libimobiledevice functions to administer
# your device, if both methods are available?
SSH_PREFERRED=0
# 0 to use ideviceinstaller, anything else to run a command on the iDevice
# over an SSH connection via USB TCP relaying.
# In the future, this will be used to say that SSH is preferred over libusb
# for all tasks where possible. This is useful if one of your devices is
# connected via network instead of a USB cord, but requires SSH on your
# iDevice. There are some things I have not figured out how to do without SSH,
# so it is likely that for full functionality SSH will always be a requirement.
# The ideviceinstaller method is nicer for idevices that don't have sshd
# started at boot, like modern tethered iOS jailbreaks (the poor things).
# It also will work for non-jailbroken devices if the app is signed off on by
# Apple, and is a lot less fickle to set up than sshd and iproxy since the
# program comes with the unofficial FLOSS libimobiledevice suite. It can also
# be compiled and installed to operate alongside the official library on OSX
# and Windows.
# The SSH method is my original behavior and requires an IPA installer
# program to be installed on the iDevice, which must be jailbroken and also
# running an SSH daemon.
REMOTE_IPA_INSTALL_PROG="ipainstaller" # Program on the iDevice to install IPA's with.
IPROXY_PROG="iproxy"
#IPROXY_PROG="iproxy-quiet" # Change to 'iproxy' if you don't want to use my
# patched version or haven't renamed it.
IPADDR="127.0.0.1" # Don't change unless you plan to use this for wireless ssh.
UDID='' # If empty, the script chooses the first UDID enumerated later on.
### SCRIPT BODY STARTS HERE ###
# Check if my 'escapify' tool is built (lets one not have to double-escape
# things with spaces and such for them to work in ssh commands)
type escapify
HAS_ESCAPIFY=$?
export HAS_ESCAPIFY
# remove grep aliases as to avoid color highlighting potential issues
# don't show any error messages
# (used for kill-server)
2>/dev/null 1>&2 unalias grep
2>/dev/null 1>&2 unalias tail
2>/dev/null 1>&2 unalias awk
IPROXYPID="" # placeholder global variable, set by some commands
getCol() {
echo "$2" | awk '{ print $'"$1"' }'
}
confLoad() {
if [ -e "$HOME"'/.config/idb.conf' ]; then # if idb.conf exists
# search for given UDID.
# last instance supersedes previous ones (but you should not have multiple)
# !!Spaces might cause issues with this implementation!!
# (they are okay in comments only.)
CONFLINE="$(grep '^'"$1"':' "$CONFFILE"|tail -n 1|sed 's/:/\t/g')"
if [ -n "$CONFLINE" ]; then # if conf line is not empty (was found)
REMOTEPORT="$(getCol 2 "$CONFLINE")"
LOCALPORT="$(getCol 3 "$CONFLINE")"
IPADDR="$(getCol 4 "$CONFLINE")"
SSH_PREFERRED="$(getCol 5 "$CONFLINE")"
DEVDISKIMG="$(getCol 6 "$CONFLINE")"
fi # /if conf line was found
fi # /if idb.conf exists
# do nothing if no match was found or file doesn't exist (continue on)
}
# check if UDID is specified. If not, the tools I call should default to the
# first device that is enumerated by 'idevice_id -l'.
if [ "$1" = '-u' ]; then
shift
UDID="$1"
shift
else #choose first device that appears otherwise
UDID=`idevice_id -l | head -n 1`
fi
# attempt to load UDID-specific config overrides from ~/.config/idb.conf, if
# said file exists
confLoad "$UDID"
startRelay() {
# hide iproxy output. Look here if you can't make it work and remove the
# pipe to see the diagnostics.
set -x
"$IPROXY_PROG" "$LOCALPORT" "$REMOTEPORT" "$UDID" > /dev/null 2>&1 &
set +x
IPROXYPID="$!"
}
listDevices() {
# preliminary work to support multiple iDevices, untested because I only own
# one iDevice. Uses "idevice_id" from libimobiledevice tools at
# https://github.com/libimobiledevice/libimobiledevice.git
echo "Listing all iDevice UDID's."
SPACING=18
fetch(){
# Ensure even spacing for each column.
# This can likely be optimized massively.
# One simple thing would be replacing [ ] with [[ ]], but that's not
# in POSIX so you'd have to change this script to be using bash/ksh or
# something. If using ksh, $(( )) for math instead of 'expr' would also
# help a lot.
printf ' '"$2"':'
LEN=$( expr "$SPACING" '-' "$( printf "$2" | wc -c )" )
I=0
while [ "$I" -lt "$LEN" ]; do
printf ' '
I=`expr $I '+' 1`
done
ideviceinfo -u "$1" -k "$2"
}
idevice_id -l | while read UUID; do # get info about each UUID's properties.
# Slow because it ends up having to call ideviceinfo once for each field.
# Saving the output of a single run to a temporary file and reading that
# would likely be much more performant.
# Unfortunately, mktemp isn't a POSIX command though and I haven't felt
# up to rolling my own just yet.
idevicename -u "$UUID" | tr '\n' ':' | sed 's/:$/:\n/'
printf " UUID: ""$UUID"'\n'
fetch "$UUID" "ProductType"
fetch "$UUID" "ProductVersion"
done
# idevice_id -l
}
push() {
if [ $HAS_ESCAPIFY -eq 0 ] && [ -z $NO_ESCAPIFY ]; then
scp -P"$LOCALPORT" "$1" "$DEVICE_USER""@""$IPADDR"":""$(escapify "$2")"
else
scp -P"$LOCALPORT" "$1" "$DEVICE_USER""@""$IPADDR"":""$2"
fi
}
pull() {
# if only one argument is supplied, the file's destination is in the current
# directory.
if [ -z "$2" ]; then
DEST="."
else
DEST="$2"
fi
# check if we have my 'escapify' program. If so, idb push/pull won't require
# additional escaping like scp usually does (it will work more as expected).
# NO_ESCAPIFY can be set to non-empty to force idb to not use it.
if [ $HAS_ESCAPIFY -eq 0 ] && [ -z $NO_ESCAPIFY ]; then # has escapify
scp -P"$LOCALPORT" "$DEVICE_USER""@""$IPADDR"":""$(escapify "$1")" "$DEST"
else
# will neex extra escaping for spaces and such.
scp -P"$LOCALPORT" "$DEVICE_USER""@""$IPADDR"":""$1" "$DEST"
fi
}
# uses forced pseudoterminal allocation by default (-t)
shell() {
if [ $HAS_ESCAPIFY -eq 0 ] && [ -z $NO_ESCAPIFY ]; then # has escapify
set -x
ssh -t -p"$LOCALPORT" "$DEVICE_USER""@""$IPADDR" "$(escapify "$@")"
set +x
else
set -x
ssh -t -p"$LOCALPORT" "$DEVICE_USER""@""$IPADDR" "$@"
set +x
fi
}
# to enable later: x forwarded shell
shellx() {
if [ $HAS_ESCAPIFY -eq 0 ] && [ -z $NO_ESCAPIFY ]; then # has escapify
set -x
ssh -Y -p"$LOCALPORT" "$DEVICE_USER""@""$IPADDR" "$(escapify "$@")"
set +x
else
set -x
ssh -Y -p"$LOCALPORT" "$DEVICE_USER""@""$IPADDR" "$@"
set +x
fi
}
# to enable later: shell w/o forced pseudoterminal allocation
shellnt() {
if [ $HAS_ESCAPIFY -eq 0 ] && [ -z $NO_ESCAPIFY ]; then # has escapify
set -x
ssh -p"$LOCALPORT" "$DEVICE_USER""@""$IPADDR" "$(escapify "$@")"
set +x
else
set -x
ssh -p"$LOCALPORT" "$DEVICE_USER""@""$IPADDR" "$@"
set +x
fi
}
killServer() {
# Only POSIX way to get PID's of processes by name that I can find.
# pidof is not POSIX, nor is pkill, nor is killall.
# this makes a space-separated list of PID's to kill, and then pumps them
# through xargs to kill. Since POSIX kill does not explicitly say that
# killing multiple PID's with one command is supported, I run it once for
# each PID in the list.
# I am 99.9% sure this sed usage is POSIX, but I'm not very good at
# regexes.
echo "Killing all instances of ""$IPROXY_PROG""..."
PIDS=`ps -o pid,comm -u "$USER" | grep "$IPROXY_PROG" | sed 's/\s.*$//' | tr '\n' ' '`
echo "$PIDS" | xargs -n 1 kill
echo "Done."
}
install() {
if [ "$SSH_PREFERRED" -ne 0 ]; then
FILENAME=`basename "$1"`
echo 'Pushing '"$1"' to the iDevice...'
push "$1" '/private/var/'"$DEVICE_USER"'/'"$FILENAME"
echo 'Installing '"$FILENAME"' using '"$REMOTE_IPA_INSTALL_PROG"'... Please wait.'
shell "$REMOTE_IPA_INSTALL_PROG" "/private/var/""$DEVICE_USER""/""$FILENAME"
echo "Install program finished, deleting the IPA from the iDevice..."
shell rm '/private/var/'"$DEVICE_USER"'/'"$FILENAME"
else
# use ideviceinstaller and obviate the need for ssh availability.
# nice for idevices that don't have sshd started at boot, like modern
# tethered ones (poor things).
"$IDEVICEINSTALLER" -u "$UDID" -i "$1"
fi
echo "Done."
}
remove() {
# todo: try to implement an ssh version of this command?
"$IDEVICEINSTALLER" -u "$UDID" -U "$1"
}
forward() {
if [ ! "$#" -eq 2 ]; then
echo "forward: error: Need two args, but was given ""$#""." 1>&2
echo "Syntax:" 1>&2
echo " forward [local port] [remote port]" 1>&2
else
echo "Attempting to forward between local port ""$1"" & remote port ""$2""."
echo "Use ^C to close the connection (it runs in the foreground.)"
"$IPROXY_PROG" "$@"
fi
}
listPackages() {
# last arg flag takes precedence, ignore all others
# default is to list user apps only
MODE='list_user'
# confusing syntax, but i'm saying "while $1 starts with a dash"
while case $1 in -*) true;; *) false;; esac; do
case $1 in
-a) #list all packages
MODE='list_all'
;;
-u)
MODE='list_user'
;;
-s)
MODE='list_system'
;;
-x)
MODE='xml'
;;
*)
echo "Warning: Unknown parameter passed to listPackages: ""$1" 1>&2
;;
esac
shift
done
if [ -n "$1" ]; then
"$IDEVICEINSTALLER" -u "$UDID" -l -o "$MODE" | grep '^'"$1"','
else
"$IDEVICEINSTALLER" -u "$UDID" -l -o "$MODE"
fi
}
mountimg() {
# if not already mounted, try to mount
"$IDEVICEIMAGEMOUNTER" -u "$UDID" -l | grep ImagePresent | grep -q false
if [ "$?" -eq 0 ]; then
if [ -n "$DEVDISKIMG" ]; then
"$IDEVICEIMAGEMOUNTER" -u "$UDID" "$DEVDISKIMG" "$DEVDISKIMG"'.signature'
fi
fi
}
debug() { # uses idevicedebug
# idevicedebug [OPTIONS] COMMAND
# command:
# run BUNDLEID [ARGS...] run app BUNDLEID with optional ARGS on the device.
# options:
# -e, --env NAME=VALUE set environment variable NAME to VALUE
# -d, --debug enable communication debugging
mountimg
"$IDEVICEDEBUG" -u "$UDID" run "$@"
}
screenshot() {
mountimg
# outputs a tiff image
"$IDEVICESCREENSHOT" -u "$UDID" "$@"
}
syslog() {
"$IDEVICESYSLOG" -u "$UDID" "$@"
}
logcat() { # alias for syslog (not 'debug')
syslog "$@"
}
experimentalFeatureMsg() {
echo " - Experimental, on account of requiring pre-configuration in the sparsely"
echo " documented and highly volatile 'idb.conf' file for mounting an iOS"
echo " developer disk image. Some brief explanation is in the README as well as"
echo " an example file."
}
# Printed when no command is given as a memory jogger.
# 'usageHelp' contains the full descriptions.
usageHelpBrief() {
echo "Abridged usage:"
echo " ""`basename "$0"`"" push [target] [destination]"
echo " ""`basename "$0"`"" pull [target] [destination]"
echo " ""`basename "$0"`"" shell"
echo " ""`basename "$0"`"" shell [command]"
echo " ""`basename "$0"`"" forward [local] [remote]"
echo " ""`basename "$0"`"" install [target]"
echo " ""`basename "$0"`"" uninstall [appid]"
echo " ""`basename "$0"`"" list-packages [-a|-u|-s|-x] [appid]"
echo " ""`basename "$0"`"" devices"
echo " ""`basename "$0"`"" list"
echo " ""`basename "$0"`"" kill-server"
echo " ""`basename "$0"`"" help"
echo "To see more detailed descriptions of these commands, as well as more options,"
echo "run '""`basename "$0"`"" help'."
}
usageHelp() {
echo "Usage:"
echo "`basename "$0"`"" [-u <UDID>] command [options]"
echo " -u <UDID> can optionally be placed before most commands to make them operate"
echo ' on the device with the given UDID (check with "'"`basename "$0"`"' devices" or "'"`basename "$0"`"' list").'
echo ''
echo "Detailed descriptions:"
echo "`basename "$0"`"" push [target] [destination]"
echo " Copies a targeted file on the computer to a destination on the iDevice."
echo "`basename "$0"`"" pull [target] [destination]"
echo " Copies a targeted file from the iDevice to a destination on the computer."
echo "`basename "$0"`"" shell"
echo " Starts a remote shell on the iDevice."
echo "`basename "$0"`"" shell [command]"
echo " Starts a remote shell on the iDevice, runs the given command, and exits."
echo "`basename "$0"`"" forward [local] [remote]"
echo " Forwards socket connections (currently only TCP ports are tested)."
echo " Unlike ADB, [local] and [remote] here should be integer values. That is,"
echo " 'tcp:25565', the ADB syntax, would be just '25565' here."
echo "`basename "$0"`"" syslog [options]"
echo " Display the iDevice's system message log. See the documentation for"
echo " libimobiledevice's idevicesyslog for a full description of options."
echo "`basename "$0"`"" debug [application bundle identifier]"
echo " [EXPERIMENTAL] View the diagnostics log of the specified application."
experimentalFeatureMsg
echo "`basename "$0"`"" screenshot [options] [output_filename]"
echo " [EXPERIMENTAL] Take a screenshot of the display on a connected"
echo " iDevice. 'output_filename' is optional; if not given a screenshot will be"
echo " written to a file in 'screenshot-DATE' format."
echo " Options are also, of course, optional. See the 'idevicescreenshot'"
echo " documentation for a list of options."
experimentalFeatureMsg
echo "`basename "$0"`"" install [target]"
if [ "$SSH_PREFERRED" -ne 0 ]; then
echo " Installs the indicated target IPA on the iDevice using ""$REMOTE_IPA_INSTALL_PROG""."
echo " Will need modification to work with other CLI IPA installer programs"
echo " (which need to be installed on the iDevice itself via Cydia or similar)."
else
echo ' Installs the indicated target IPA on the iDevice using '"$IDEVICEINSTALLER"
echo ' from libimobiledevice. '"$IDEVICEINSTALLER"' must of course be installed'
echo ' on this computer for this to work.'
fi
echo "`basename "$0"`"" uninstall [appid]"
echo " Try to remove the app with the given ID from the iDevice. May fail on"
echo " system apps."
echo "`basename "$0"`"" remove [appid]"
echo " Synonym for "'`uninstall`'"."
echo "`basename "$0"`"" list-packages [-a|-u|-s|-x] [appid]"
echo " Lists packages installed on the iDevice. Has several optional flags:"
echo " -a: List all packages on the iDevice."
echo " -u: List user packages on the iDevice (default)."
echo " -s: List system packages on the iDevice."
echo " -x: List all packages on the iDevice in XML format."
echo " If 'appid' is specified, only that package's information is displayed."
echo " This is incompatible with -x (for now at least)."
echo "`basename "$0"`"" devices"
echo " Lists the UDID's of all connected devices. Part of preliminary"
echo " (incomplete but in progress) support for multi-device capability."
echo "`basename "$0"`"" list"
echo " Synonym for '""`basename "$0"`"" devices'."
echo "`basename "$0"`"" kill-server"
echo " Kills all instances of ""$IPROXY_PROG"", the TCP-over-usbmuxd program."
echo "`basename "$0"`"" help"
echo " Show this usage information."
echo "`basename "$0"`"" -h"
echo " Synonym for '""`basename "$0"`"" help'."
echo "`basename "$0"`"" --help"
echo " Synonym for '""`basename "$0"`"" help'."
echo
echo "Some configuration inside this script's source may be required."
echo "Open this program in a text editor for more documentation."
}
case "$1" in
# push
"push")
startRelay
shift 1 # strip first argument (i.e., "push"), leaving only remaining args
push "$1" "$2"
;;
# pull
"pull")
startRelay
shift 1
pull "$1" "$2"
;;
# shell with forced pseudoterminal allocation (works for ncurses programs)
"shell")
startRelay
shift 1
shell "$@"
;;
# shell without pseudoterminal allocation
"shellnt")
startRelay
shift 1
shellnt "$@"
;;
"forward")
shift 1
forward "$@"
;;
"install")
if [ "$SSH_PREFERRED" -ne 0 ]; then
startRelay
fi
shift 1
install "$1"
;;
# uninstall (remove)
"uninstall"|"remove")
shift 1
remove "$1"
;;
# list-packages
"list-packages")
shift 1
listPackages "$@"
;;
# list (devices)
"list"|"devices")
listDevices
;;
# debug (logcat)
"debug"|"logcat")
shift
debug "$@"
;;
# screenshot
"screenshot")
shift
screenshot "$@"
;;
"syslog")
shift
syslog "$@"
;;
# kill-server
"kill-server")
killServer
;;
# help
"help"|"-help"|"--help"|"-h")
usageHelp
;;
*)
if [ "$#" -gt 0 ]; then # If we were given a command, but it was incorrect
# The fallback case should dump the help text to stderr rather than stdout.
echo "`basename "$0"`"": Error: '""$1""' is not a valid command." 1>&2
echo "Please note that not all 'adb'commands have exact analogues in this" 1>&2
echo "script." 1>&2
else
echo "`basename "$0"`"": Error: No command given." 1>&2
usageHelpBrief 1>&2
fi
;;
esac
# clean-up
kill "$IPROXYPID" 2>/dev/null # not all commands need to use iproxy, but for those that do we need to make sure it's closed.
true #return 0