Permalink
Browse files

Wait for enter key on completion

Should help people who double click the program and find the terminal
window closes too fast to read the output.

Add an -nopause option to disable the end of run pause

Also display the raw plist file if breaking the PIN itself should fail
for some reason
  • Loading branch information...
1 parent 28d0f8d commit c6b8ad3be5d40ef9c23594b0f34fc33d905a02de @gwatts committed Oct 24, 2015
Showing with 104 additions and 23 deletions.
  1. +33 −0 .gitignore
  2. +70 −22 pinfinder.go
  3. +1 −1 pinfinder_test.go
View
@@ -0,0 +1,33 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+pinfinder
+pinfinder.exe
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.out
+*.sw?
+*~
+*.test
+.DS_Store
+#*
+.#*
+*#
View
@@ -31,12 +31,15 @@
package main
import (
+ "bufio"
"bytes"
"crypto/sha1"
"encoding/base64"
"encoding/xml"
"errors"
+ "flag"
"fmt"
+ "io"
"os"
"os/user"
"path"
@@ -49,7 +52,14 @@ import (
"golang.org/x/crypto/pbkdf2"
)
-const maxPIN = 10000
+const (
+ maxPIN = 10000
+ version = "1.2.0"
+)
+
+var (
+ noPause = flag.Bool("nopause", false, "Set to true to prevent the program pausing for input on completion")
+)
func isDir(p string) bool {
s, err := os.Stat(p)
@@ -110,13 +120,24 @@ func findLatestBackup(backupDir string) (string, error) {
return "", errors.New("No backup directories found in " + backupDir)
}
-type Plist struct {
+type plist struct {
+ Path string
Keys []string `xml:"dict>key"`
Data []string `xml:"dict>data"`
}
-func loadPlist(fn string) (*Plist, error) {
- var p Plist
+func (p *plist) DumpTo(w io.Writer) error {
+ f, err := os.Open(p.Path)
+ if err != nil {
+ return fmt.Errorf("Failed to dump plist data: %s", err)
+ }
+ defer f.Close()
+ io.Copy(w, f)
+ return nil
+}
+
+func loadPlist(fn string) (*plist, error) {
+ var p plist
f, err := os.Open(fn)
if err != nil {
return nil, err
@@ -125,10 +146,11 @@ func loadPlist(fn string) (*Plist, error) {
if err := xml.NewDecoder(f).Decode(&p); err != nil {
return nil, err
}
+ p.Path = fn
return &p, nil
}
-func findRestrictions(fpath string) (*Plist, error) {
+func findRestrictions(fpath string) (*plist, error) {
d, err := os.Open(fpath)
if err != nil {
return nil, err
@@ -159,7 +181,7 @@ func findRestrictions(fpath string) (*Plist, error) {
return nil, errors.New("No matching plist file - Are parental restrictions turned on?")
}
-func parseRestrictions(pl *Plist) (pw, salt []byte) {
+func parseRestrictions(pl *plist) (pw, salt []byte) {
pw, _ = base64.StdEncoding.DecodeString(strings.TrimSpace(pl.Data[0]))
salt, _ = base64.StdEncoding.DecodeString(strings.TrimSpace(pl.Data[1]))
return pw, salt
@@ -209,49 +231,71 @@ func findPIN(key, salt []byte) (string, error) {
select {
case <-wg.WaitChan():
- return "", errors.New("failed to calculate PIN number.")
+ return "", errors.New("failed to calculate PIN number")
case pin := <-found:
return pin, nil
}
}
+func exit(status int, addUsage bool, errfmt string, a ...interface{}) {
+ if errfmt != "" {
+ fmt.Fprintf(os.Stderr, errfmt+"\n", a...)
+ }
+ if addUsage {
+ usage()
+ }
+ if !*noPause {
+ fmt.Printf("Press Enter to exit")
+ bufio.NewReader(os.Stdin).ReadBytes('\n')
+ }
+ os.Exit(status)
+}
+
func usage() {
- fmt.Println("Usage:", path.Base(os.Args[0]), " [<path to latest itunes backup directory>]")
- os.Exit(101)
+ fmt.Fprintln(os.Stderr, "Usage:", path.Base(os.Args[0]), " [flags] [<path to latest iTunes backup directory>]")
+ flag.PrintDefaults()
+}
+
+func init() {
+ flag.Usage = usage
}
func main() {
var backupDir, syncDir string
var err error
- switch len(os.Args) {
- case 1:
+ fmt.Println("PIN Finder", version)
+
+ flag.Parse()
+
+ args := flag.Args()
+ switch len(args) {
+ case 0:
syncDir, err = findSyncDir()
if err != nil {
fmt.Println(err.Error)
usage()
}
backupDir, err = findLatestBackup(syncDir)
if err != nil {
- fmt.Println(err.Error())
- usage()
+ exit(101, true, err.Error())
}
- case 2:
- backupDir = os.Args[1]
+
+ case 1:
+ backupDir = args[0]
+
default:
- usage()
+ exit(102, true, "Too many arguments")
}
if !isDir(backupDir) {
- fmt.Println("Directory not found: ", backupDir)
- usage()
+ exit(103, true, "Directory not found: %s", backupDir)
}
fmt.Println("Searching backup at", backupDir)
pl, err := findRestrictions(backupDir)
if err != nil {
- fmt.Println("Failed to find/load restrictions plist file: ", err)
- os.Exit(102)
+ exit(104, false, "Failed to find/load restrictions plist file: ", err.Error())
}
key, salt := parseRestrictions(pl)
@@ -260,8 +304,12 @@ func main() {
startTime := time.Now()
pin, err := findPIN(key, salt)
if err != nil {
- fmt.Println(err)
- os.Exit(103)
+ // Failed to break the PIN; dump the plist data for debugging purposes
+ fmt.Fprintln(os.Stderr, err.Error()+"\n")
+ fmt.Fprintln(os.Stderr, "Source data file: ", pl.Path)
+ pl.DumpTo(os.Stderr)
+ exit(105, false, "")
}
fmt.Printf(" FOUND!\nPIN number is: %s (found in %s)\n", pin, time.Since(startTime))
+ exit(0, false, "")
}
View
@@ -62,7 +62,7 @@ func TestFindRestrictions(t *testing.T) {
}
func TestParseRestriction(t *testing.T) {
- pl := &Plist{
+ pl := &plist{
Keys: []string{"RestrictionsPasswordKey", "RestrictionsPasswordSalt"},
Data: []string{"ioN63+yl6OFZ4/C7xl9VejMLDi0=", "iNciDA=="},
}

0 comments on commit c6b8ad3

Please sign in to comment.