Skip to content

Commit 74d8368

Browse files
author
Alyx Ferrari
committed
iOS-Restrictions-Recovery v0.7.3
1 parent 31188b3 commit 74d8368

File tree

4 files changed

+110
-77
lines changed

4 files changed

+110
-77
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,5 @@
2323
hs_err_pid*
2424
/bin/
2525
/target/
26+
/keychain_dumper
27+
keychain_dumper

keychain_dumper

42.7 KB
Binary file not shown.

src/com/emeryferrari/iosrr/Display.java

Lines changed: 107 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.emeryferrari.iosrr;
22
import javax.swing.*;
3+
import java.net.*;
34
import java.awt.event.*;
45
import java.io.*;
56
import net.schmizz.sshj.*;
@@ -82,89 +83,119 @@ public void actionPerformed(ActionEvent ev) {
8283
new Thread() {
8384
@Override
8485
public void run() {
86+
Display.FRAME.getContentPane().removeAll();
8587
try {
86-
int confirm = 0;
87-
if (confirm == 0) {
88-
String ip = JOptionPane.showInputDialog("Device IP address? OpenSSH and SQLite 3.x must be installed on your device.");
89-
String portStr = JOptionPane.showInputDialog("Device SSH server port? (press enter to default to 22)");
90-
int port = 22;
91-
if (!portStr.equals("")) {
92-
port = Integer.parseInt(portStr);
88+
String ip = JOptionPane.showInputDialog("Device IP address? OpenSSH and SQLite 3.x must be installed on your device.");
89+
String portStr = JOptionPane.showInputDialog("Device SSH server port? (press enter to default to 22)");
90+
int port = 22;
91+
if (!portStr.equals("")) {
92+
port = Integer.parseInt(portStr);
93+
}
94+
String rootPass = JOptionPane.showInputDialog("What is your device's root password? (press enter to default to 'alpine')");
95+
if (rootPass.equals("")) {
96+
rootPass = "alpine";
97+
}
98+
File keychain_dumper = new File("keychain_dumper");
99+
if (!keychain_dumper.exists()) {
100+
Display.FRAME.getContentPane().add(new JLabel("Couldn't find keychain_dumper!"));
101+
JLabel progress = new JLabel("Downloading keychain_dumper from GitHub...");
102+
Display.FRAME.getContentPane().add(progress);
103+
Display.refresh();
104+
URL url = new URL("https://raw.githubusercontent.com/ptoomey3/Keychain-Dumper/master/keychain_dumper");
105+
InputStream is = url.openStream();
106+
FileOutputStream fos = new FileOutputStream("keychain_dumper");
107+
URLConnection connection = url.openConnection();
108+
if (connection instanceof HttpURLConnection) {
109+
((HttpURLConnection)connection).setRequestMethod("HEAD");
93110
}
94-
String rootPass = JOptionPane.showInputDialog("What is your device's root password? (press enter to default to 'alpine')");
95-
if (rootPass.equals("")) {
96-
rootPass = "alpine";
111+
connection.getInputStream();
112+
int total = connection.getContentLength();
113+
int b;
114+
byte[] data = new byte[1024];
115+
int count = 0;
116+
while ((b = is.read(data, 0, 1024)) != -1) {
117+
fos.write(data, 0, b);
118+
count += b;
119+
progress.setText("Downloading keychain_dumper from GitHub... (" + count + " bytes / " + total + " bytes)");
120+
Display.refresh();
97121
}
98-
Display.FRAME.getContentPane().removeAll();
99-
Display.FRAME.getContentPane().add(new JLabel("Connecting to " + ip + ":" + port + " over SSH..."));
100-
Display.refresh();
101-
System.out.println("Connecting to " + ip + ":" + port + " over SSH...");
102-
SSHClient ssh = new SSHClient();
103-
ssh.addHostKeyVerifier(new PromiscuousVerifier());
104-
ssh.connect(ip, port);
105-
Display.FRAME.getContentPane().add(new JLabel("Logging in as user 'root'..."));
106-
System.out.println("Logging in as user 'root'...");
107-
Display.refresh();
108-
ssh.authPassword("root", rootPass);
109-
Display.FRAME.getContentPane().add(new JLabel("Uploading keychain_dumper to device..."));
110-
Display.refresh();
111-
System.out.println("Uploading keychain_dumper to device...");
112-
ssh.newSCPFileTransfer().upload("keychain_dumper", "/User/Documents/keychain_dumper");
113-
Session session = ssh.startSession();
114-
Display.FRAME.getContentPane().add(new JLabel("Giving keychain_dumper '+x' permissions..."));
115-
System.out.println("Giving keychain_dumper '+x' permissions...");
116-
Display.refresh();
117-
session.exec("chmod +x /User/Documents/keychain_dumper");
118-
Display.FRAME.getContentPane().add(new JLabel("Disconnecting..."));
119-
System.out.println("Disconnecting...");
120-
Display.refresh();
121-
ssh.disconnect();
122-
ssh.close();
123-
SSHClient ssh2 = new SSHClient();
124-
ssh2.addHostKeyVerifier(new PromiscuousVerifier());
125-
Display.FRAME.getContentPane().add(new JLabel("Reconnecting to " + ip + ":" + port + "..."));
126-
System.out.println("Reconnecting to " + ip + ":" + port + "...");
127-
Display.refresh();
128-
ssh2.connect(ip, port);
129-
Display.FRAME.getContentPane().add(new JLabel("Logging in as user 'root'..."));
130-
System.out.println("Logging in as user 'root'...");
131-
Display.refresh();
132-
ssh2.authPassword("root", rootPass);
133-
Session session2 = ssh2.startSession();
134-
JOptionPane.showMessageDialog(null, "Please make sure your device is unlocked and on the home screen.");
135-
Display.FRAME.getContentPane().add(new JLabel("Dumping your device's Keychain... (if this blocks, make sure your device is unlocked)"));
136-
System.out.println("Dumping your device's Keychain... (if this blocks, make sure your device is unlocked)");
137-
Display.refresh();
138-
Session.Command cmd = session2.exec("./../mobile/Documents/keychain_dumper");
139-
String keychain = IOUtils.readFully(cmd.getInputStream()).toString();
140-
Display.FRAME.getContentPane().add(new JLabel("Disconnecting..."));
141-
System.out.println("Disconnecting...");
142-
Display.refresh();
143-
ssh2.disconnect();
144-
ssh2.close();
145-
Display.FRAME.getContentPane().add(new JLabel("Parsing Keychain dump..."));
146-
System.out.println("Parsing Keychain dump...");
147-
Display.refresh();
148-
String[] list = keychain.split("ParentalControls")[1].split("\n");
149-
String password = null;
150-
for (int i = 0; i < 20; i++) {
151-
if (list[i].startsWith("Keychain Data: ")) {
152-
password = list[i].split(": ")[1];
153-
break;
154-
}
122+
fos.flush();
123+
fos.close();
124+
}
125+
Display.FRAME.getContentPane().add(new JLabel("Connecting to " + ip + ":" + port + " over SSH..."));
126+
Display.refresh();
127+
System.out.println("Connecting to " + ip + ":" + port + " over SSH...");
128+
SSHClient ssh = new SSHClient();
129+
ssh.addHostKeyVerifier(new PromiscuousVerifier());
130+
ssh.connect(ip, port);
131+
Display.FRAME.getContentPane().add(new JLabel("Logging in as user 'root'..."));
132+
System.out.println("Logging in as user 'root'...");
133+
Display.refresh();
134+
ssh.authPassword("root", rootPass);
135+
Display.FRAME.getContentPane().add(new JLabel("Uploading keychain_dumper to device..."));
136+
Display.refresh();
137+
System.out.println("Uploading keychain_dumper to device...");
138+
ssh.newSCPFileTransfer().upload("keychain_dumper", "/User/Documents/keychain_dumper");
139+
Session session = ssh.startSession();
140+
Display.FRAME.getContentPane().add(new JLabel("Giving keychain_dumper '+x' permissions..."));
141+
System.out.println("Giving keychain_dumper '+x' permissions...");
142+
Display.refresh();
143+
session.exec("chmod +x /User/Documents/keychain_dumper");
144+
Display.FRAME.getContentPane().add(new JLabel("Disconnecting..."));
145+
System.out.println("Disconnecting...");
146+
Display.refresh();
147+
ssh.disconnect();
148+
ssh.close();
149+
SSHClient ssh2 = new SSHClient();
150+
ssh2.addHostKeyVerifier(new PromiscuousVerifier());
151+
Display.FRAME.getContentPane().add(new JLabel("Reconnecting to " + ip + ":" + port + "..."));
152+
System.out.println("Reconnecting to " + ip + ":" + port + "...");
153+
Display.refresh();
154+
ssh2.connect(ip, port);
155+
Display.FRAME.getContentPane().add(new JLabel("Logging in as user 'root'..."));
156+
System.out.println("Logging in as user 'root'...");
157+
Display.refresh();
158+
ssh2.authPassword("root", rootPass);
159+
Session session2 = ssh2.startSession();
160+
JOptionPane.showMessageDialog(null, "Please make sure your device is unlocked and on the home screen.");
161+
Display.FRAME.getContentPane().add(new JLabel("Dumping your device's Keychain... (if this blocks, make sure your device is unlocked)"));
162+
System.out.println("Dumping your device's Keychain... (if this blocks, make sure your device is unlocked)");
163+
Display.refresh();
164+
Session.Command cmd = session2.exec("./../mobile/Documents/keychain_dumper");
165+
String keychain = IOUtils.readFully(cmd.getInputStream()).toString();
166+
session2 = ssh2.startSession();
167+
Display.FRAME.getContentPane().add(new JLabel("Removing keychain_dumper from device..."));
168+
System.out.println("Removing keychain_dumper from device...");
169+
Display.refresh();
170+
session2.exec("rm ./../mobile/Documents/keychain_dumper");
171+
Display.FRAME.getContentPane().add(new JLabel("Disconnecting..."));
172+
System.out.println("Disconnecting...");
173+
Display.refresh();
174+
ssh2.disconnect();
175+
ssh2.close();
176+
Display.FRAME.getContentPane().add(new JLabel("Parsing Keychain dump..."));
177+
System.out.println("Parsing Keychain dump...");
178+
Display.refresh();
179+
String[] list = keychain.split("ParentalControls")[1].split("\n");
180+
String password = null;
181+
for (int i = 0; i < 20; i++) {
182+
if (list[i].startsWith("Keychain Data: ")) {
183+
password = list[i].split(": ")[1];
184+
break;
155185
}
156-
Display.FRAME.getContentPane().add(new JLabel("Found Screen Time passcode! Passcode: " + password));
157-
System.out.println("Found Screen Time passcode! Passcode: " + password);
158-
Display.refresh();
159-
JButton button = new JButton("Back");
160-
button.addActionListener(new BackListener());
161-
Display.FRAME.getContentPane().add(button);
162-
Display.refresh();
163-
JOptionPane.showMessageDialog(null, "Found Screen Time passcode! Passcode: " + password);
164186
}
187+
Display.FRAME.getContentPane().add(new JLabel("Found Screen Time passcode! Passcode: " + password));
188+
System.out.println("Found Screen Time passcode! Passcode: " + password);
189+
Display.refresh();
190+
JButton button = new JButton("Back");
191+
button.addActionListener(new BackListener());
192+
Display.FRAME.getContentPane().add(button);
193+
Display.refresh();
194+
JOptionPane.showMessageDialog(null, "Found Screen Time passcode! Passcode: " + password);
165195
} catch (Exception ex) {
166196
handleException(ex, true);
167197
Display.FRAME.getContentPane().add(new JLabel("Failed to retrieve Screen Time passcode! If you're sure you've done everything correctly, create an issue on GitHub."));
198+
Display.FRAME.getContentPane().add(new JLabel(ex.getClass().toString().split(" ")[1]+ ": " + ex.getMessage()));
168199
JButton button = new JButton("Back");
169200
button.addActionListener(new BackListener());
170201
Display.FRAME.getContentPane().add(button);
@@ -359,7 +390,7 @@ public void run() {
359390
KeySaltPair pair = PropertyListReader.getKeyAndSaltFromPlist("password.plist");
360391
String passcode = RestrictionsRecovery.calculate(pair.getKey(), pair.getSalt(), false);
361392
if (passcode == null) {
362-
throw new Exception("Passcode could not be found. Key and salt does not correspond to any passcode between 0000 and 9999.");
393+
throw new Exception("Passcode could not be found. Specified key and salt do not correspond to any passcode between 0000 and 9999.");
363394
} else {
364395
JOptionPane.showMessageDialog(null, "Passcode: " + passcode, "Passcode found!", 1);
365396
}

src/com/emeryferrari/iosrr/RRConst.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
public class RRConst {
33
private RRConst() {}
44
public static final String NAME = "iOS-Restrictions-Recovery";
5-
public static final String VERSION = "v0.7.2";
5+
public static final String VERSION = "v0.7.3";
66
public static final String AUTHOR = "Alyx Ferrari";
77
public static final String FULL_NAME = NAME + " " + VERSION;
88
public static final String TITLE = "<html><body><font size=\"5\">" + FULL_NAME + "</font></body></html>";

0 commit comments

Comments
 (0)