Skip to content

Commit 73b31d7

Browse files
committed
Use lockdownd_get_value for reading ApNonce/generator in normal mode
1 parent 66cf582 commit 73b31d7

File tree

8 files changed

+119
-140
lines changed

8 files changed

+119
-140
lines changed

build.gradle

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,10 @@ repositories {
5050

5151
dependencies {
5252
implementation group: 'org.json', name: 'json', version: '20210307'
53-
implementation 'de.jangassen:nsmenufx:3.1.0'
54-
implementation 'net.java.dev.jna:jna:5.7.0:jpms'
53+
implementation ('de.jangassen:nsmenufx:3.1.0') {
54+
exclude group: 'net.java.dev.jna', module: 'jna' //separate jna version
55+
}
56+
implementation 'net.java.dev.jna:jna-jpms:5.9.0'
5557
implementation group: 'org.apache.commons', name: 'commons-compress', version: '1.21'
5658

5759
testImplementation 'org.junit.jupiter:junit-jupiter:5.7.2'

src/main/java/airsquared/blobsaver/app/LibimobiledeviceUtil.java

Lines changed: 48 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.sun.jna.Platform;
2424
import com.sun.jna.Pointer;
2525
import com.sun.jna.ptr.IntByReference;
26+
import com.sun.jna.ptr.LongByReference;
2627
import com.sun.jna.ptr.PointerByReference;
2728
import javafx.concurrent.Task;
2829
import javafx.scene.control.ButtonType;
@@ -36,23 +37,23 @@
3637
public class LibimobiledeviceUtil {
3738

3839
public static long getECID() throws LibimobiledeviceException {
39-
return Long.parseLong(getKeyFromConnectedDevice("UniqueChipID", PlistType.INTEGER));
40+
return getPlistLong(getLockdownValuePlist("UniqueChipID"));
4041
}
4142

4243
public static String getDeviceModelIdentifier() throws LibimobiledeviceException {
43-
return getKeyFromConnectedDevice("ProductType", PlistType.STRING);
44+
return getPlistString(getLockdownValuePlist("ProductType"));
4445
}
4546

4647
public static String getBoardConfig() throws LibimobiledeviceException {
47-
return getKeyFromConnectedDevice("HardwareModel", PlistType.STRING);
48+
return getPlistString(getLockdownValuePlist("HardwareModel"));
4849
}
4950

5051
public static String getApNonceNormalMode() throws LibimobiledeviceException {
51-
return LibimobiledeviceUtil.plistDataToString(LibimobiledeviceUtil.getMobileGestaltKey("ApNonce"), ByteOrder.BIG_ENDIAN);
52+
return plistDataToHexString(LibimobiledeviceUtil.getLockdownValuePlist("ApNonce"), ByteOrder.BIG_ENDIAN);
5253
}
5354

5455
public static String getGenerator() throws LibimobiledeviceException {
55-
return "0x" + LibimobiledeviceUtil.plistDataToString(LibimobiledeviceUtil.getMobileGestaltKey("BootNonce"), ByteOrder.LITTLE_ENDIAN);
56+
return "0x" + plistDataToHexString(getLockdownValuePlist("BootNonce"), ByteOrder.LITTLE_ENDIAN);
5657
}
5758

5859
public static void exitRecovery(Pointer irecvClient) throws LibimobiledeviceException {
@@ -135,17 +136,17 @@ protected Void call() throws LibimobiledeviceException {
135136
}
136137
throwIfNeeded(errorCode, ErrorCodeType.lockdownd_error);
137138

138-
PointerByReference service = new PointerByReference();
139+
PointerByReference plist = new PointerByReference();
139140
// don't reset timeout
140141
errorCode = -17;
141142
while (errorCode == -17 && System.currentTimeMillis() < endTime) {
142143
if (!sleep(1000)) {
143144
return null;
144145
}
145-
errorCode = lockdownd_start_service(lockdown.getValue(), "com.apple.mobile.diagnostics_relay", service);
146+
errorCode = lockdownd_get_value(lockdown.getValue(), Pointer.NULL, "BootNonce", plist);
146147
}
147148
if (errorCode == 0) {
148-
lockdownd_service_descriptor_free(service.getValue());
149+
Libplist.free(plist.getValue());
149150
}
150151
lockdownd_client_free(lockdown.getValue());
151152
idevice_free(device.getValue());
@@ -201,45 +202,10 @@ private static String getApnonce(Pointer irecv_client) {
201202
return Utils.bytesToHex(apnonceBytes, ByteOrder.BIG_ENDIAN);
202203
}
203204

204-
private static String getKeyFromConnectedDevice(String key, PlistType plistType) throws LibimobiledeviceException {
205-
if (plistType == null) {
206-
plistType = PlistType.STRING;
207-
}
208-
if (key == null) {
209-
key = "";
210-
}
211-
212-
Pointer client = lockdowndClientFromConnectedDevice();
213-
PointerByReference plist_value = new PointerByReference();
214-
int lockdowndGetValueErrorCode = lockdownd_get_value(client, Pointer.NULL, key, plist_value);
215-
if (lockdowndGetValueErrorCode == -8) {
216-
// try again, and if it doesn't work, show an error to the user + throw an exception
217-
// it always works the second time
218-
lockdownd_client_free(client);
219-
client = lockdowndClientFromConnectedDevice();
220-
throwIfNeeded(lockdownd_get_value(client, Pointer.NULL, key, plist_value), ErrorCodeType.lockdownd_error);
221-
} else {
222-
throwIfNeeded(lockdowndGetValueErrorCode, ErrorCodeType.lockdownd_error);
223-
}
224-
lockdownd_client_free(client);
225-
if (plistType.equals(PlistType.INTEGER)) {
226-
PointerByReference xml_doc = new PointerByReference();
227-
Libplist.toXml(plist_value.getValue(), xml_doc, new PointerByReference());
228-
Libplist.free(plist_value.getValue());
229-
String toReturn = xml_doc.getValue().getString(0, "UTF-8");
230-
return toReturn.substring(toReturn.indexOf("<integer>") + "<integer>".length(), toReturn.indexOf("</integer>"));
231-
} else {
232-
PointerByReference toReturn = new PointerByReference();
233-
Libplist.getStringVal(plist_value.getValue(), toReturn);
234-
Libplist.free(plist_value.getValue());
235-
return toReturn.getValue().getString(0, "UTF-8");
236-
}
237-
}
238-
239205
/**
240206
* Returns a plist with the root element being the requested item.
241207
* <p>
242-
* It will look something like this:
208+
* It will look something like this (might have different type):
243209
* <pre>
244210
* {@code
245211
* <?xml version="1.0" encoding="UTF-8"?>
@@ -252,34 +218,25 @@ private static String getKeyFromConnectedDevice(String key, PlistType plistType)
252218
* }
253219
* </pre>
254220
*/
255-
private static Pointer getMobileGestaltKey(String key) throws LibimobiledeviceException {
256-
PointerByReference device = new PointerByReference();
257-
throwIfNeeded(idevice_new(device, Pointer.NULL), ErrorCodeType.idevice_error);
258-
PointerByReference client = new PointerByReference();
259-
throwIfNeeded(lockdownd_client_new_with_handshake(device.getValue(), client, "blobsaver"), ErrorCodeType.lockdownd_error);
260-
PointerByReference service = new PointerByReference();
261-
throwIfNeeded(lockdownd_start_service(client.getValue(), "com.apple.mobile.diagnostics_relay", service), ErrorCodeType.lockdownd_error);
262-
lockdownd_client_free(client.getValue());
263-
264-
PointerByReference diagnosticsRelayClient = new PointerByReference();
265-
throwIfNeeded(diagnostics_relay_client_new(device.getValue(), service.getValue(), diagnosticsRelayClient), ErrorCodeType.diagnostics_relay_error);
266-
267-
Pointer keys = Libplist.newArray();
268-
Libplist.arrayAppendItem(keys, Libplist.newString(key));
269-
PointerByReference plistResult = new PointerByReference();
270-
throwIfNeeded(diagnostics_relay_query_mobilegestalt(diagnosticsRelayClient.getValue(), keys, plistResult), ErrorCodeType.diagnostics_relay_error);
271-
Pointer plistApnonce = Libplist.dictGetItem(Libplist.dictGetItem(plistResult.getValue(), "MobileGestalt"), key);
272-
273-
diagnostics_relay_goodbye(diagnosticsRelayClient.getValue());
274-
diagnostics_relay_client_free(diagnosticsRelayClient.getValue());
275-
lockdownd_service_descriptor_free(service.getValue());
276-
idevice_free(device.getValue());
277-
Libplist.free(keys);
221+
private static Pointer getLockdownValuePlist(String key) throws LibimobiledeviceException {
222+
Pointer client = lockdowndClientFromConnectedDevice();
223+
PointerByReference plist = new PointerByReference();
224+
int lockdowndGetValueErrorCode = lockdownd_get_value(client, Pointer.NULL, key, plist);
225+
if (lockdowndGetValueErrorCode == -8) {
226+
// try again, and if it doesn't work, show an error to the user + throw an exception
227+
// it always works the second time
228+
lockdownd_client_free(client);
229+
client = lockdowndClientFromConnectedDevice();
230+
throwIfNeeded(lockdownd_get_value(client, Pointer.NULL, key, plist), ErrorCodeType.lockdownd_error);
231+
} else {
232+
throwIfNeeded(lockdowndGetValueErrorCode, ErrorCodeType.lockdownd_error);
233+
}
234+
lockdownd_client_free(client);
278235

279-
return plistApnonce;
236+
return plist.getValue();
280237
}
281238

282-
private static String plistDataToString(Pointer plist, ByteOrder byteOrder) {
239+
private static String plistDataToHexString(Pointer plist, ByteOrder byteOrder) {
283240
IntByReference apnonceLength = new IntByReference();
284241
byte[] apnonceBytes = Libplist.getDataPtr(plist, apnonceLength).getByteArray(0, apnonceLength.getValue());
285242
String toReturn = Utils.bytesToHex(apnonceBytes, byteOrder);
@@ -288,6 +245,27 @@ private static String plistDataToString(Pointer plist, ByteOrder byteOrder) {
288245
return toReturn;
289246
}
290247

248+
private static long getPlistLong(Pointer plist) {
249+
LongByReference reference = new LongByReference();
250+
Libplist.getUintVal(plist, reference);
251+
Libplist.free(plist);
252+
return reference.getValue();
253+
}
254+
255+
private static String getPlistString(Pointer plist) {
256+
PointerByReference reference = new PointerByReference();
257+
Libplist.getStringVal(plist, reference);
258+
Libplist.free(plist);
259+
return reference.getValue().getString(0, "UTF-8");
260+
}
261+
262+
// Useful for debugging
263+
private static String plistToXml(Pointer plist) {
264+
PointerByReference xml_doc = new PointerByReference();
265+
Libplist.toXml(plist, xml_doc, new PointerByReference());
266+
return xml_doc.getValue().getString(0, "UTF-8");
267+
}
268+
291269
private static Pointer lockdowndClientFromConnectedDevice() throws LibimobiledeviceException {
292270
PointerByReference device = new PointerByReference();
293271
throwIfNeeded(idevice_new(device, Pointer.NULL), ErrorCodeType.idevice_error);
@@ -306,12 +284,8 @@ static void enterRecovery() throws LibimobiledeviceException {
306284
lockdownd_client_free(client);
307285
}
308286

309-
private enum PlistType {
310-
STRING, INTEGER
311-
}
312-
313287
private enum ErrorCodeType {
314-
idevice_error, lockdownd_error, irecv_error, diagnostics_relay_error
288+
idevice_error, lockdownd_error, irecv_error
315289
}
316290

317291
private static void throwIfNeeded(int errorCode, ErrorCodeType errorType) throws LibimobiledeviceException {
@@ -350,9 +324,6 @@ private static void throwIfNeeded(int errorCode, ErrorCodeType errorType) throws
350324
message = "irecovery error: code=" + errorCode +
351325
"\n\nIf your device is still in recovery mode, use the \"Exit Recovery Mode\" option from the help menu.";
352326
reportableError = true;
353-
} else if (errorType.equals(ErrorCodeType.diagnostics_relay_error)) {
354-
message = "Diagnostics Relay error: code=" + errorCode;
355-
reportableError = true;
356327
}
357328
throw new LibimobiledeviceException(message, errorType, errorCode, reportableError);
358329
}

src/main/java/airsquared/blobsaver/app/natives/Libimobiledevice.java

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,20 +41,8 @@ public class Libimobiledevice {
4141

4242
public static native int lockdownd_client_new_with_handshake(Pointer device, PointerByReference client, String label);
4343

44-
public static native int lockdownd_start_service(Pointer lockdownd_client, String identifier, PointerByReference service);
45-
4644
public static native void lockdownd_client_free(Pointer client);
4745

48-
public static native void lockdownd_service_descriptor_free(Pointer service);
49-
50-
public static native int diagnostics_relay_client_new(Pointer idevice, Pointer lockdownd_service_descriptor, PointerByReference diagnostics_relay_client);
51-
52-
public static native int diagnostics_relay_query_mobilegestalt(Pointer diagnostics_client, Pointer plist_keys, PointerByReference plist_node);
53-
54-
public static native void diagnostics_relay_goodbye(Pointer diagnostics_client);
55-
56-
public static native void diagnostics_relay_client_free(Pointer diagnostics_client);
57-
5846
public static native void idevice_free(Pointer idevice);
5947

6048
static {

src/main/java/airsquared/blobsaver/app/natives/Libirecovery.java

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,10 @@
1919
package airsquared.blobsaver.app.natives;
2020

2121
import airsquared.blobsaver.app.natives.NativeUtils.CFunctionName;
22-
import com.sun.jna.FunctionMapper;
23-
import com.sun.jna.Library;
24-
import com.sun.jna.Native;
25-
import com.sun.jna.NativeLibrary;
2622
import com.sun.jna.Pointer;
2723
import com.sun.jna.Structure;
2824
import com.sun.jna.ptr.PointerByReference;
2925

30-
import java.util.Map;
31-
3226
/**
3327
* https://github.com/libimobiledevice/libirecovery/blob/master/src/libirecovery.c
3428
*/
@@ -73,19 +67,15 @@ public static class irecv_device_info extends Structure {
7367

7468

7569
static {
76-
// try {
77-
// NativeUtils.register(Libimobiledevice.class, "irecovery");
78-
// } catch (UnsatisfiedLinkError e) {
79-
// try {
80-
// NativeUtils.register(Libimobiledevice.class, "irecovery-1.0");
81-
// } catch (UnsatisfiedLinkError e2) {
82-
// e.addSuppressed(e2);
83-
// throw e;
84-
// }
85-
// }
86-
Native.register(Libirecovery.class, NativeLibrary.getInstance("irecovery", Map.of(Library.OPTION_CLASSLOADER, Libirecovery.class.getClassLoader(),
87-
Library.OPTION_FUNCTION_MAPPER, (FunctionMapper) (lib, method) ->
88-
method.isAnnotationPresent(CFunctionName.class) ?
89-
method.getAnnotation(CFunctionName.class).value() : method.getName())));
70+
try {
71+
NativeUtils.register(Libirecovery.class, "irecovery");
72+
} catch (UnsatisfiedLinkError e) {
73+
try {
74+
NativeUtils.register(Libirecovery.class, "irecovery-1.0");
75+
} catch (UnsatisfiedLinkError e2) {
76+
e.addSuppressed(e2);
77+
throw e;
78+
}
79+
}
9080
}
9181
}

src/main/java/airsquared/blobsaver/app/natives/Libplist.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import airsquared.blobsaver.app.natives.NativeUtils.CFunctionName;
2222
import com.sun.jna.Pointer;
2323
import com.sun.jna.ptr.IntByReference;
24+
import com.sun.jna.ptr.LongByReference;
2425
import com.sun.jna.ptr.PointerByReference;
2526

2627
public class Libplist {
@@ -43,6 +44,9 @@ public class Libplist {
4344
@CFunctionName("plist_get_string_val")
4445
public static native void getStringVal(Pointer plist, PointerByReference value);
4546

47+
@CFunctionName("plist_get_uint_val")
48+
public static native void getUintVal(Pointer plist, LongByReference value);
49+
4650
@CFunctionName("plist_free")
4751
public static native void free(Pointer plist);
4852

src/test/java/airsquared/blobsaver/app/BlobsaverTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@
1818

1919
package airsquared.blobsaver.app;
2020

21-
import org.junit.jupiter.api.BeforeEach;
21+
import org.junit.jupiter.api.BeforeAll;
2222

2323
public class BlobsaverTest {
2424

25-
@BeforeEach
26-
public void setJNALibraryPath() {
25+
@BeforeAll
26+
public static void setJNALibraryPath() {
2727
Main.setJNALibraryPath();
2828
}
2929
}

src/test/java/airsquared/blobsaver/app/LibimobiledeviceTest.java

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,15 @@
1818

1919
package airsquared.blobsaver.app;
2020

21-
import airsquared.blobsaver.app.natives.Libirecovery;
22-
import com.sun.jna.Pointer;
23-
import com.sun.jna.ptr.PointerByReference;
2421
import org.junit.jupiter.api.Disabled;
2522
import org.junit.jupiter.api.Test;
2623

27-
import static org.junit.jupiter.api.Assertions.assertEquals;
28-
2924
@Disabled("disable tests unless device is connected")
3025
public class LibimobiledeviceTest extends BlobsaverTest {
3126

3227
@Test
3328
public void getECID() throws LibimobiledeviceUtil.LibimobiledeviceException {
34-
long ecid = LibimobiledeviceUtil.getECID();
35-
assertEquals(0L, ecid); // change to your device's ecid
29+
System.out.println(LibimobiledeviceUtil.getECID());
3630
}
3731

3832
@Test
@@ -41,25 +35,7 @@ public void enterRecovery() throws LibimobiledeviceUtil.LibimobiledeviceExceptio
4135
}
4236

4337
@Test
44-
public void getNonce() {
45-
PointerByReference irecvClient = new PointerByReference();
46-
assertEquals(0, Libirecovery.open(irecvClient));
47-
Libirecovery.irecv_device_info deviceInfo = Libirecovery.getDeviceInfo(irecvClient.getValue());
48-
StringBuilder apnonce = new StringBuilder();
49-
System.out.println("deviceInfo.ap_nonce = " + deviceInfo.ap_nonce);
50-
for (byte b : ((Pointer) deviceInfo.readField("ap_nonce")).getByteArray(0, deviceInfo.ap_nonce_size)) {
51-
apnonce.append(String.format("%02x", b));
52-
}
53-
// assertEquals("", apnonce.toString()); // change to your device's apnonce
54-
System.out.println("apnonce = " + apnonce);
55-
assertEquals(0, Libirecovery.setEnv(irecvClient.getValue(), "auto-boot", "true"));
56-
assertEquals(0, Libirecovery.saveEnv(irecvClient.getValue()));
57-
assertEquals(0, Libirecovery.reboot(irecvClient.getValue()));
58-
assertEquals(0, Libirecovery.close(irecvClient.getValue()));
59-
}
60-
61-
@Test
62-
public void mobilegestalt() throws LibimobiledeviceUtil.LibimobiledeviceException {
38+
public void getApNonce() throws LibimobiledeviceUtil.LibimobiledeviceException {
6339
System.out.println(LibimobiledeviceUtil.getApNonceNormalMode());
6440
System.out.println(LibimobiledeviceUtil.getGenerator());
6541
}

0 commit comments

Comments
 (0)