Skip to content

Commit

Permalink
Release v0.5
Browse files Browse the repository at this point in the history
  • Loading branch information
Emery Ferrari committed Feb 28, 2020
1 parent ca7f79f commit 3748c36
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 44 deletions.
7 changes: 1 addition & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# iOS Restrictions Recovery

by Emery Ferrari<br/>
A command-line tool (for now) that will recover the restrictions passcode from a device running iOS 7.0-11.4.1.
A GUI/command-line that will recover the restrictions passcode from a device running iOS 7.0-11.4.1.

## Credit

Expand All @@ -25,11 +25,6 @@ To use the iproxy feature:<br/>

This tool can either be run from the .jar executable of the latest release in the Releases tab, or can be compiled using javac.

## Prerequisites

Java Runtime Environment or Java Development Kit<br/>
macOS, Windows, or a Unix-based operating system

## Known issues

There are many performance and consistency issues in the source code. None of these will affect your experience with the program in practice, however these are planned to be fixed in a future pre-release update nonetheless.
Expand Down
89 changes: 89 additions & 0 deletions src/com/emeryferrari/iosrr/Display.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package com.emeryferrari.iosrr;
import javax.swing.*;
import java.awt.event.*;
public class Display {
private Display() {}
private static final Display CLASS_OBJ = new Display();
private static JFrame FRAME = new JFrame(RRConst.NAME + " - v" + RRConst.VERSION);
private static JLabel TITLE = new JLabel(RRConst.TITLE);
private static JButton KEY_SALT_BUTTON = new JButton(RRConst.KEY_SALT_BUTTON);
private static JButton FILE_BUTTON = new JButton(RRConst.FILE_BUTTON);
private static JButton SSH_BUTTON = new JButton(RRConst.SSH_BUTTON);
private static JButton IPROXY_BUTTON = new JButton(RRConst.IPROXY_BUTTON);
public static void createDisplay() {
Display.FRAME.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Display.FRAME.setSize(800, 600);
Display.FRAME.setLayout(new BoxLayout(FRAME.getContentPane(), BoxLayout.Y_AXIS));
Display.KEY_SALT_BUTTON.addActionListener(Display.CLASS_OBJ.new KeySaltButtonListener());
Display.FILE_BUTTON.addActionListener(Display.CLASS_OBJ.new FileButtonListener());
Display.SSH_BUTTON.addActionListener(Display.CLASS_OBJ.new SSHButtonListener());
Display.IPROXY_BUTTON.addActionListener(Display.CLASS_OBJ.new IproxyButtonListener());
Display.IPROXY_BUTTON.setEnabled(false);
Display.FRAME.getContentPane().add(Display.TITLE);
Display.FRAME.getContentPane().add(Display.KEY_SALT_BUTTON);
Display.FRAME.getContentPane().add(Display.FILE_BUTTON);
Display.FRAME.getContentPane().add(Display.SSH_BUTTON);
Display.FRAME.getContentPane().add(Display.IPROXY_BUTTON);
Display.FRAME.setVisible(true);
}
public class KeySaltButtonListener implements ActionListener {
public void actionPerformed(ActionEvent ev) {
try {
String key = JOptionPane.showInputDialog("Key?");
String salt = JOptionPane.showInputDialog("Salt?");
String passcode = RestrictionsRecovery.calculate(key, salt, false);
if (passcode == null) {
throw new Exception();
} else {
JOptionPane.showMessageDialog(null, "Passcode: " + passcode);
}
} catch (Exception ex) {
Display.handleException(ex);
}
}
}
public class FileButtonListener implements ActionListener {
public void actionPerformed(ActionEvent ev) {
try {
String file = JOptionPane.showInputDialog("Property list path?");
KeySaltPair pair = PropertyListReader.getKeyAndSaltFromPlist(file);
String passcode = RestrictionsRecovery.calculate(pair.getKey(), pair.getSalt(), false);
if (passcode == null) {
throw new Exception();
} else {
JOptionPane.showMessageDialog(null, "Passcode: " + passcode);
}
} catch (Exception ex) {
Display.handleException(ex);
}
}
}
public class SSHButtonListener implements ActionListener {
public void actionPerformed(ActionEvent ev) {
try {
String ip = JOptionPane.showInputDialog("Device IP address?");
String password = JOptionPane.showInputDialog("Device root password?");
String port = JOptionPane.showInputDialog("Device SSH port?");
RestrictionsRecovery.downloadViaSSH(ip, Integer.parseInt(port), password, false);
KeySaltPair pair = PropertyListReader.getKeyAndSaltFromPlist("password.plist");
String passcode = RestrictionsRecovery.calculate(pair.getKey(), pair.getSalt(), false);
if (passcode == null) {
throw new Exception();
} else {
JOptionPane.showMessageDialog(null, "Passcode: " + passcode);
}
} catch (Exception ex) {
Display.handleException(ex);
}
}
}
public class IproxyButtonListener implements ActionListener {
public void actionPerformed(ActionEvent ev) {
// not implemented yet
}
}
private static void handleException(Exception ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(null, "Error occurred while calculating the passcode. Check the console for details.");
}
}
9 changes: 8 additions & 1 deletion src/com/emeryferrari/iosrr/RRConst.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
package com.emeryferrari.iosrr;
public class RRConst {
private RRConst() {}
public static final String VERSION = "0.4.3";
public static final String NAME = "iOS-Restrictions-Recovery";
public static final String VERSION = "0.5";

public static final String TITLE = "<html><body><font size=\"10\">iOS-Restrictions-Recovery</font></body></html>";
public static final String KEY_SALT_BUTTON = "From key and salt";
public static final String FILE_BUTTON = "From property list file";
public static final String SSH_BUTTON = "From device via SSH";
public static final String IPROXY_BUTTON = "From device via iproxy over USB";
}
89 changes: 52 additions & 37 deletions src/com/emeryferrari/iosrr/RestrictionsRecovery.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,50 +9,63 @@
public class RestrictionsRecovery {
private RestrictionsRecovery() {}
public static void main(String[] args) throws Exception {
RRArguments arguments = ArgumentParser.parseArguments(args);
if (arguments.getRequestType() == RequestType.IPROXY) {
int port = 22;
String password = "alpine";
if (arguments.getPort() != null) {
port = Integer.parseInt(arguments.getPort());
}
if (arguments.getPassword() != null) {
password = arguments.getPassword();
}
RestrictionsRecovery.launchIproxy(port, password);
} else if (arguments.getRequestType() == RequestType.SSH) {
int port = 22;
String password = "alpine";
if (arguments.getPort() != null) {
port = Integer.parseInt(arguments.getPort());
}
if (arguments.getPassword() != null) {
password = arguments.getPassword();
}
RestrictionsRecovery.downloadViaSSH(arguments.getSsh(), port, password);
} else if (arguments.getRequestType() == RequestType.FILE) {
KeySaltPair pair = PropertyListReader.getKeyAndSaltFromPlist(arguments.getFile());
RestrictionsRecovery.calculate(pair.getKey(), pair.getSalt());
} else if (arguments.getRequestType() == RequestType.KEYSALT) {
RestrictionsRecovery.calculate(arguments.getKey(), arguments.getSalt());
} else if (arguments.getRequestType() == RequestType.VERSION) {
CommandLineOutput.printVersion();
if (args.length == 0) {
Display.createDisplay();
} else {
CommandLineOutput.printUsage();
RRArguments arguments = ArgumentParser.parseArguments(args);
if (arguments.getRequestType() == RequestType.IPROXY) {
int port = 22;
String password = "alpine";
if (arguments.getPort() != null) {
port = Integer.parseInt(arguments.getPort());
}
if (arguments.getPassword() != null) {
password = arguments.getPassword();
}
RestrictionsRecovery.launchIproxy(port, password, true);
} else if (arguments.getRequestType() == RequestType.SSH) {
int port = 22;
String password = "alpine";
if (arguments.getPort() != null) {
port = Integer.parseInt(arguments.getPort());
}
if (arguments.getPassword() != null) {
password = arguments.getPassword();
}
RestrictionsRecovery.downloadViaSSH(arguments.getSsh(), port, password, true);
KeySaltPair pair = PropertyListReader.getKeyAndSaltFromPlist("password.plist");
RestrictionsRecovery.calculate(pair.getKey(), pair.getSalt(), true);
} else if (arguments.getRequestType() == RequestType.FILE) {
KeySaltPair pair = PropertyListReader.getKeyAndSaltFromPlist(arguments.getFile());
RestrictionsRecovery.calculate(pair.getKey(), pair.getSalt(), true);
} else if (arguments.getRequestType() == RequestType.KEYSALT) {
RestrictionsRecovery.calculate(arguments.getKey(), arguments.getSalt(), true);
} else if (arguments.getRequestType() == RequestType.VERSION) {
CommandLineOutput.printVersion();
} else {
CommandLineOutput.printUsage();
}
}
}
private static void calculate(String key, String salt) throws NoSuchAlgorithmException, InvalidKeySpecException, UnsupportedEncodingException {
public static String calculate(String key, String salt, boolean exit) throws NoSuchAlgorithmException, InvalidKeySpecException, UnsupportedEncodingException {
System.out.println("Bruteforcing restrictions passcode...");
String passcode = PasscodeChecker.getPasscode(key, salt);
if (passcode.length() == 4) {
System.out.println("Found passcode!");
System.out.println("Restrictions passcode: " + passcode);
if (exit) {
System.exit(0);
}
return passcode;
} else {
System.out.println("The key " + key + " with the salt " + salt + " does not appear to be a valid combination for any iOS restrictions passcode. Please ensure you have entered the key and salt correctly.");
if (exit) {
System.exit(0);
}
return null;
}
System.exit(0);
}
private static void downloadViaSSH(String ip, int port, String password) throws IOException {
public static void downloadViaSSH(String ip, int port, String password, boolean exit) throws IOException {
if (RestrictionsRecovery.identifyHostOS() != OperatingSystem.OTHER) {
SSHClient ssh = new SSHClient();
ssh.addHostKeyVerifier(new PromiscuousVerifier());
Expand All @@ -62,12 +75,14 @@ private static void downloadViaSSH(String ip, int port, String password) throws
ssh.newSCPFileTransfer().download("/private/var/mobile/Library/Preferences/com.apple.restrictionspassword.plist", "password.plist");
ssh.disconnect();
ssh.close();
System.exit(0);
if (exit) {
System.exit(0);
}
} else {
CommandLineOutput.printUnsupportedOS();
}
}
private static OperatingSystem identifyHostOS() {
public static OperatingSystem identifyHostOS() {
String os = System.getProperty("os.name").toLowerCase();
if (os.indexOf("win") >= 0) {
return OperatingSystem.WINDOWS;
Expand All @@ -87,7 +102,7 @@ private static OperatingSystem identifyHostOS() {
return OperatingSystem.OTHER;
}
}
private static void launchIproxy(int port, String password) throws IOException, SAXException, ParserConfigurationException, InvalidKeySpecException, NoSuchAlgorithmException {
public static void launchIproxy(int port, String password, boolean exit) throws IOException, SAXException, ParserConfigurationException, InvalidKeySpecException, NoSuchAlgorithmException {
ProcessBuilder builder = null;
if (RestrictionsRecovery.identifyHostOS() == OperatingSystem.MACOSMOJAVE || RestrictionsRecovery.identifyHostOS() == OperatingSystem.UNIX) {
builder = new ProcessBuilder("/bin/bash", "-c", "iproxy", "23", ""+port);
Expand All @@ -103,9 +118,9 @@ private static void launchIproxy(int port, String password) throws IOException,
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = reader.readLine();
if (line.equals("waiting for connection")) {
RestrictionsRecovery.downloadViaSSH("127.0.0.1", 23, password);
RestrictionsRecovery.downloadViaSSH("127.0.0.1", 23, password, exit);
KeySaltPair pair = PropertyListReader.getKeyAndSaltFromPlist("password.plist");
RestrictionsRecovery.calculate(pair.getKey(), pair.getSalt());
RestrictionsRecovery.calculate(pair.getKey(), pair.getSalt(), exit);
} else {
CommandLineOutput.printIproxyError();
}
Expand Down

0 comments on commit 3748c36

Please sign in to comment.