diff --git a/.gitignore b/.gitignore index 6044614..4cc67ba 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,3 @@ build/ .DS_Store -src/exploit/payloads/ -src/exploit/userland/ -src/exploit/logo.h +src/gen/ diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..9365698 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "cmake.loadCompileCommands": true, + "cmake.configureOnOpen": true, + "cmake.buildDirectory": "${workspaceFolder}/build", + "cmake.copyCompileCommands": "${workspaceFolder}/build/compile_commands.json", +} diff --git a/CMakeLists.txt b/CMakeLists.txt index 13c4532..a7de087 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,62 +1,359 @@ -# Project cmake_minimum_required(VERSION 3.10) project(palera1n VERSION 3.0) + include(FetchContent) +include(ExternalProject) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED True) -set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG") -set(CMAKE_CXX_FLAGS_DEBUG "-g -Wall -Wextra -DWX_PRECOMP") -# Option for GUI (wxWidgets) option(WITH_GUI "Build with wxWidgets GUI" OFF) -option(WITH_STATIC "Build with static wxWidgets" OFF) +option(WITH_STATIC "Build with static wxWidgets / deps" OFF) -# Architectures set(CMAKE_OSX_ARCHITECTURES "arm64") set(CMAKE_OSX_DEPLOYMENT_TARGET "10.13") +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -# Deps +set(DEPS_PREFIX ${CMAKE_BINARY_DIR}/deps) + +# ========================= +# wxWidgets +# ========================= if(WITH_GUI) -if(WITH_STATIC) - set(wxBUILD_SHARED OFF) - FetchContent_Declare( - wxWidgets - GIT_REPOSITORY https://github.com/wxWidgets/wxWidgets.git - GIT_SHALLOW ON - ) - FetchContent_MakeAvailable(wxWidgets) - set(WX_LIBRARIES wxWidgets::core wxWidgets::base wxWidgets::net) -else() - find_package(wxWidgets REQUIRED COMPONENTS core base net) - include(${wxWidgets_USE_FILE}) - set(WX_LIBRARIES ${wxWidgets_LIBRARIES}) -endif() + if(WITH_STATIC) + set(wxBUILD_SHARED OFF CACHE BOOL "" FORCE) + + FetchContent_Declare( + wxWidgets + GIT_REPOSITORY https://github.com/wxWidgets/wxWidgets.git + GIT_SHALLOW ON + ) + + FetchContent_MakeAvailable(wxWidgets) + + set(WX_LIBRARIES wxcore wxbase wxnet) + + else() + find_package(wxWidgets REQUIRED COMPONENTS core base net) + include(${wxWidgets_USE_FILE}) + set(WX_LIBRARIES ${wxWidgets_LIBRARIES}) + endif() endif() -# Files -file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS "src/*.cpp" "src/*.c" "src/*.h" "src/*.hpp") +# ========================= +# JSON +# ========================= +include(FetchContent) + +FetchContent_Declare( + nlohmann_json + GIT_REPOSITORY https://github.com/nlohmann/json.git + GIT_TAG v3.11.3 +) + +FetchContent_MakeAvailable(nlohmann_json) + +# ========================= +# SOURCES +# ========================= +file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS + "src/*.cpp" + "src/*.c" + "src/*.h" + "src/*.hpp" +) + +# ========================= +# TARGET +# ========================= if(APPLE AND WITH_GUI) + set(APP_ICON ${CMAKE_CURRENT_SOURCE_DIR}/resources/palera1n.icns) + add_executable(palera1n MACOSX_BUNDLE ${SOURCES}) - set_target_properties(palera1n PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/resources/Info.plist) -elseif(APPLE) - add_executable(palera1n ${SOURCES}) + + target_sources(palera1n PRIVATE ${APP_ICON}) + + set_source_files_properties(${APP_ICON} PROPERTIES + MACOSX_PACKAGE_LOCATION "Resources" + ) + + set_target_properties(palera1n PROPERTIES + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/resources/Info.plist + MACOSX_BUNDLE_ICON_FILE palera1n.icns + ) else() - add_executable(palera1n WIN32 ${SOURCES} resources/main.exe.manifest) + add_executable(palera1n ${SOURCES}) endif() +include_directories(${DEPS_PREFIX}/include) +link_directories(${DEPS_PREFIX}/lib) + +# ========================= +# APPLE FRAMEWORKS +# ========================= if(APPLE) find_library(IOKIT IOKit) find_library(COREFOUNDATION CoreFoundation) - target_link_libraries(palera1n PRIVATE ${IOKIT} ${COREFOUNDATION}) + + target_link_libraries(palera1n PRIVATE + ${IOKIT} + ${COREFOUNDATION} + ) endif() +# ========================= +# wxWidgets +# ========================= if(WITH_GUI) -if(WITH_STATIC) - target_link_libraries(palera1n PRIVATE wxcore wxnet) -else() - target_link_libraries(palera1n PRIVATE ${wxWidgets_LIBRARIES}) + target_link_libraries(palera1n PRIVATE ${WX_LIBRARIES}) + target_compile_definitions(palera1n PRIVATE WITH_GUI) endif() -target_compile_definitions(palera1n PRIVATE WITH_GUI) + +target_link_libraries(palera1n PRIVATE nlohmann_json::nlohmann_json) + +# ========================= +# libimobiledevice +# ========================= +if(WITH_GUI) + if(WITH_STATIC) + include(ExternalProject) + + find_program(PKG_CONFIG_EXECUTABLE NAMES pkg-config REQUIRED) + + set(PKG_ENV + env + PKG_CONFIG=${PKG_CONFIG_EXECUTABLE} + PKG_CONFIG_PATH=${DEPS_PREFIX}/lib/pkgconfig:${DEPS_PREFIX}/share/pkgconfig + PKG_CONFIG_LIBDIR=${DEPS_PREFIX}/lib/pkgconfig:${DEPS_PREFIX}/share/pkgconfig + + CPPFLAGS=-I${DEPS_PREFIX}/include + LDFLAGS=-L${DEPS_PREFIX}/lib + + C_INCLUDE_PATH=${DEPS_PREFIX}/include + CPLUS_INCLUDE_PATH=${DEPS_PREFIX}/include + + libcurl_CFLAGS=-I/Applications/Xcode-26.2.0.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX26.2.sdk/usr/include + libcurl_LIBS=-lcurl + + mbedtls_INCLUDES=${DEPS_PREFIX}/include + mbedtls_LIBDIR=${DEPS_PREFIX}/lib + mbedtls_LIBS=-lmbedtls\ -lmbedx509\ -lmbedcrypto + ) + + # ========================= + # mbedTLS + # ========================= + ExternalProject_Add(mbedtls_ep + GIT_REPOSITORY https://github.com/Mbed-TLS/mbedtls.git + GIT_TAG mbedtls-3.5.2 + UPDATE_COMMAND "" + + PATCH_COMMAND patch -p1 < ${CMAKE_SOURCE_DIR}/patches/0001-Allow-empty-x509-cert-issuer.patch + + CMAKE_ARGS + -DCMAKE_INSTALL_PREFIX=${DEPS_PREFIX} + -DENABLE_TESTING=OFF + -DENABLE_PROGRAMS=OFF + -DBUILD_SHARED_LIBS=OFF + + INSTALL_DIR ${DEPS_PREFIX} + ) + + # ========================= + # libplist + # ========================= + ExternalProject_Add(libplist_ep + GIT_REPOSITORY https://github.com/libimobiledevice/libplist.git + GIT_TAG 2117b8fdb6b4096455bd2041a63e59a028120136 + UPDATE_COMMAND "" + + CONFIGURE_COMMAND + ${PKG_ENV} + ./autogen.sh + --prefix=${DEPS_PREFIX} + --enable-static + --disable-shared + + BUILD_COMMAND make -j + INSTALL_COMMAND make install + BUILD_IN_SOURCE 1 + ) + + # ========================= + # libimobiledevice-glue + # ========================= + ExternalProject_Add(limd_glue_ep + GIT_REPOSITORY https://github.com/libimobiledevice/libimobiledevice-glue.git + GIT_TAG 362f7848ac89b74d9dd113b38b51ecb601f76094 + UPDATE_COMMAND "" + + CONFIGURE_COMMAND + ${PKG_ENV} + ./autogen.sh + --prefix=${DEPS_PREFIX} + --enable-static + --disable-shared + + BUILD_COMMAND make -j + INSTALL_COMMAND make install + BUILD_IN_SOURCE 1 + + DEPENDS libplist_ep + ) + + # ========================= + # libusbmuxd + # ========================= + ExternalProject_Add(libusbmuxd_ep + GIT_REPOSITORY https://github.com/libimobiledevice/libusbmuxd.git + GIT_TAG a7f0543fb1ecb20ac7121c0fd77297200e0e43fc + UPDATE_COMMAND "" + + CONFIGURE_COMMAND + ${PKG_ENV} + ./autogen.sh + --prefix=${DEPS_PREFIX} + --enable-static + --disable-shared + + BUILD_COMMAND make -j + INSTALL_COMMAND make install + BUILD_IN_SOURCE 1 + + DEPENDS libplist_ep limd_glue_ep + ) + + # ========================= + # libtatsu + # ========================= + ExternalProject_Add(libtatsu_ep + GIT_REPOSITORY https://github.com/libimobiledevice/libtatsu.git + GIT_SHALLOW 1 + UPDATE_COMMAND "" + + CONFIGURE_COMMAND + ${PKG_ENV} + ./autogen.sh + --prefix=${DEPS_PREFIX} + --enable-static + --disable-shared + + BUILD_COMMAND make -j + INSTALL_COMMAND make install + BUILD_IN_SOURCE 1 + + DEPENDS libplist_ep + ) + + # ========================= + # libimobiledevice + # ========================= + ExternalProject_Add(libimobiledevice_ep + GIT_REPOSITORY https://github.com/libimobiledevice/libimobiledevice.git + GIT_TAG ed0d66d0341562731bb19928dfe48155509fa7a7 + UPDATE_COMMAND "" + + CONFIGURE_COMMAND + ${PKG_ENV} + ./autogen.sh + --prefix=${DEPS_PREFIX} + --with-mbedtls + --enable-static + --disable-shared + + BUILD_COMMAND make -j + INSTALL_COMMAND make install + BUILD_IN_SOURCE 1 + + DEPENDS mbedtls_ep libplist_ep libusbmuxd_ep limd_glue_ep libtatsu_ep + ) + + # ========================= + # libirecovery + # ========================= + ExternalProject_Add(libirecovery_ep + GIT_REPOSITORY https://github.com/libimobiledevice/libirecovery.git + GIT_TAG 7ce02c347b7c26e59498e6af31c9da51018d0fa1 + UPDATE_COMMAND "" + + CONFIGURE_COMMAND + ${PKG_ENV} + ./autogen.sh + --prefix=${DEPS_PREFIX} + --enable-static + --disable-shared + + BUILD_COMMAND make -j + INSTALL_COMMAND make install + BUILD_IN_SOURCE 1 + + DEPENDS libplist_ep libusbmuxd_ep limd_glue_ep libtatsu_ep + ) + + set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0") + + target_include_directories(palera1n PRIVATE + ${DEPS_PREFIX}/include + ) + + if(APPLE) + find_library(IOKIT IOKit) + find_library(COREFOUNDATION CoreFoundation) + find_library(SECURITY Security) + + target_link_libraries(palera1n PRIVATE + ${IOKIT} + ${COREFOUNDATION} + ${SECURITY} + ) + endif() + + target_link_libraries(palera1n PRIVATE + ${DEPS_PREFIX}/lib/libimobiledevice-1.0.a + ${DEPS_PREFIX}/lib/libirecovery-1.0.a + ${DEPS_PREFIX}/lib/libusbmuxd-2.0.a + ${DEPS_PREFIX}/lib/libplist-2.0.a + ${DEPS_PREFIX}/lib/libimobiledevice-glue-1.0.a + ${DEPS_PREFIX}/lib/libtatsu.a + ) + + target_link_libraries(palera1n PRIVATE + ${DEPS_PREFIX}/lib/libmbedtls.a + ${DEPS_PREFIX}/lib/libmbedx509.a + ${DEPS_PREFIX}/lib/libmbedcrypto.a + ) + + target_link_libraries(palera1n PRIVATE + curl + ) + else() + find_package(PkgConfig REQUIRED) + + pkg_check_modules(IMD REQUIRED libimobiledevice-1.0) + pkg_check_modules(IRECOVERY REQUIRED libirecovery-1.0) + pkg_check_modules(PLIST REQUIRED libplist-2.0) + pkg_check_modules(USBMUXD REQUIRED libusbmuxd-2.0) + + target_include_directories(palera1n PRIVATE + ${IMD_INCLUDE_DIRS} + ${IRECOVERY_INCLUDE_DIRS} + ${PLIST_INCLUDE_DIRS} + ${USBMUXD_INCLUDE_DIRS} + ) + + target_link_libraries(palera1n PRIVATE + ${IMD_LIBRARIES} + ${IRECOVERY_LIBRARIES} + ${PLIST_LIBRARIES} + ${USBMUXD_LIBRARIES} + ) + + target_compile_options(palera1n PRIVATE + ${IMD_CFLAGS_OTHER} + ${IRECOVERY_INCLUDE_DIRS} + ${PLIST_CFLAGS_OTHER} + ${USBMUXD_CFLAGS_OTHER} + ) + endif() endif() diff --git a/Makefile b/Makefile index b240319..f09db29 100644 --- a/Makefile +++ b/Makefile @@ -5,19 +5,21 @@ WITH_STATIC ?= 0 BUILD_TYPE ?= Debug payloads: - @mkdir -p src/exploit/payloads - @for file in payloads/*; do \ + @for file in images/*; do \ + name=$$(basename "$$file"); \ + name=$${name%.*}; \ echo " XXD $$file"; \ - xxd -i $$file > src/exploit/$$file.h; \ + xxd -i -n "$$name" "$$file" > "src/gen/images/$$name.h"; \ done - xxd -i resources/logo.png > src/exploit/logo.h + + xxd -i -n "DFUHelperDeviceInfo" resources/DFUHelperDeviceInfo.json > src/gen/DFUHelperDeviceInfo.h palera1n: payloads @cmake -S . -B build \ -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) \ -DWITH_GUI=$(WITH_GUI) \ -DWITH_STATIC=$(WITH_STATIC) && \ - cmake --build build -- -j$(sysctl -n hw.ncpu) + cmake --build build -- -j4 palera1n_xcode: payloads @cmake -S . -B build \ diff --git a/images/atv_std_brd.png b/images/atv_std_brd.png new file mode 100755 index 0000000..03c71aa Binary files /dev/null and b/images/atv_std_brd.png differ diff --git a/images/ipad.png b/images/ipad.png new file mode 100755 index 0000000..2adaafe Binary files /dev/null and b/images/ipad.png differ diff --git a/images/ipadmini.png b/images/ipadmini.png new file mode 100755 index 0000000..88d06cd Binary files /dev/null and b/images/ipadmini.png differ diff --git a/images/iphone6s.png b/images/iphone6s.png new file mode 100755 index 0000000..b5feeb7 Binary files /dev/null and b/images/iphone6s.png differ diff --git a/images/iphone7.png b/images/iphone7.png new file mode 100755 index 0000000..1c106d5 Binary files /dev/null and b/images/iphone7.png differ diff --git a/images/iphone8.png b/images/iphone8.png new file mode 100755 index 0000000..3e9b122 Binary files /dev/null and b/images/iphone8.png differ diff --git a/images/iphonese.png b/images/iphonese.png new file mode 100755 index 0000000..179fc53 Binary files /dev/null and b/images/iphonese.png differ diff --git a/images/iphonex.png b/images/iphonex.png new file mode 100755 index 0000000..512b69a Binary files /dev/null and b/images/iphonex.png differ diff --git a/images/ipodtouch.png b/images/ipodtouch.png new file mode 100755 index 0000000..16081f6 Binary files /dev/null and b/images/ipodtouch.png differ diff --git a/images/logo.png b/images/logo.png new file mode 100644 index 0000000..643d8a4 Binary files /dev/null and b/images/logo.png differ diff --git a/images/siriremote.png b/images/siriremote.png new file mode 100755 index 0000000..5868c7b Binary files /dev/null and b/images/siriremote.png differ diff --git a/patches/0001-Allow-empty-x509-cert-issuer.patch b/patches/0001-Allow-empty-x509-cert-issuer.patch new file mode 100644 index 0000000..4516290 --- /dev/null +++ b/patches/0001-Allow-empty-x509-cert-issuer.patch @@ -0,0 +1,33 @@ +From a2d012f3ba459f6debe636b576ad9aeab7b3c2aa Mon Sep 17 00:00:00 2001 +From: Nick Chan +Date: Sat, 27 May 2023 23:50:23 +0800 +Subject: [PATCH] Allow empty x509 cert issuer + +--- + library/x509_crt.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/library/x509_crt.c b/library/x509_crt.c +index cf62532f2..ef25b3d77 100644 +--- a/library/x509_crt.c ++++ b/library/x509_crt.c +@@ -1061,13 +1061,13 @@ static int x509_crt_parse_der_core(mbedtls_x509_crt *crt, + + if ((ret = mbedtls_asn1_get_tag(&p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { +- mbedtls_x509_crt_free(crt); +- return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret); ++ /*mbedtls_x509_crt_free(crt); ++ return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret);*/ + } + + if ((ret = mbedtls_x509_get_name(&p, p + len, &crt->issuer)) != 0) { +- mbedtls_x509_crt_free(crt); +- return ret; ++ /*mbedtls_x509_crt_free(crt); ++ return ret;*/ + } + + crt->issuer_raw.len = p - crt->issuer_raw.p; +-- +2.39.1 diff --git a/payloads/Pongo.bin b/payloads/Pongo.bin deleted file mode 100644 index 490b1aa..0000000 Binary files a/payloads/Pongo.bin and /dev/null differ diff --git a/payloads/shellcode.bin b/payloads/shellcode.bin deleted file mode 100644 index 14c424e..0000000 Binary files a/payloads/shellcode.bin and /dev/null differ diff --git a/payloads/yolo_s8000.bin b/payloads/yolo_s8000.bin deleted file mode 100644 index bce02a2..0000000 Binary files a/payloads/yolo_s8000.bin and /dev/null differ diff --git a/payloads/yolo_s8001.bin b/payloads/yolo_s8001.bin deleted file mode 100644 index 8e6abfc..0000000 Binary files a/payloads/yolo_s8001.bin and /dev/null differ diff --git a/payloads/yolo_s8003.bin b/payloads/yolo_s8003.bin deleted file mode 100644 index 9e812e5..0000000 Binary files a/payloads/yolo_s8003.bin and /dev/null differ diff --git a/payloads/yolo_t7000.bin b/payloads/yolo_t7000.bin deleted file mode 100644 index dc12d93..0000000 Binary files a/payloads/yolo_t7000.bin and /dev/null differ diff --git a/payloads/yolo_t7001.bin b/payloads/yolo_t7001.bin deleted file mode 100644 index 262f4df..0000000 Binary files a/payloads/yolo_t7001.bin and /dev/null differ diff --git a/payloads/yolo_t8010.bin b/payloads/yolo_t8010.bin deleted file mode 100644 index 6fb0107..0000000 Binary files a/payloads/yolo_t8010.bin and /dev/null differ diff --git a/payloads/yolo_t8011.bin b/payloads/yolo_t8011.bin deleted file mode 100644 index 6e557bd..0000000 Binary files a/payloads/yolo_t8011.bin and /dev/null differ diff --git a/payloads/yolo_t8015.bin b/payloads/yolo_t8015.bin deleted file mode 100644 index d76d511..0000000 Binary files a/payloads/yolo_t8015.bin and /dev/null differ diff --git a/resources/DFUHelperDeviceInfo.json b/resources/DFUHelperDeviceInfo.json new file mode 100644 index 0000000..dcf9666 --- /dev/null +++ b/resources/DFUHelperDeviceInfo.json @@ -0,0 +1,452 @@ +{ + "devicemap":{ + "iPhone6,1":"iphonese", + "iPhone6,2":"iphonese", + "iPhone7,1":"iphone6s", + "iPhone7,2":"iphone6s", + "iPhone8,1":"iphone6s", + "iPhone8,2":"iphone6s", + "iPhone8,4":"iphonese", + "iPhone9,1":"iphone7", + "iPhone9,2":"iphone7", + "iPhone9,3":"iphone7", + "iPhone9,4":"iphone7", + "iPhone10,1":"iphone8", + "iPhone10,2":"iphone8", + "iPhone10,4":"iphone8", + "iPhone10,5":"iphone8", + "iPhone10,3":"iphonex", + "iPhone10,6":"iphonex", + + "iPhone11,2":"iphonex", + "iPhone11,4":"iphonex", + "iPhone11,6":"iphonex", + "iPhone11,8":"iphonex", + "iPhone12,1":"iphonex", + "iPhone12,3":"iphonex", + "iPhone12,5":"iphonex", + "iPhone12,8":"iphone8", + + "iPad4,1":"ipad", + "iPad4,2":"ipad", + "iPad4,3":"ipad", + "iPad5,3":"ipad", + "iPad5,4":"ipad", + "iPad6,3":"ipad", + "iPad6,4":"ipad", + "iPad6,7":"ipad", + "iPad6,8":"ipad", + "iPad6,11":"ipad", + "iPad6,12":"ipad", + "iPad7,1":"ipad", + "iPad7,2":"ipad", + "iPad7,3":"ipad", + "iPad7,4":"ipad", + "iPad7,5":"ipad", + "iPad7,6":"ipad", + "iPad7,11":"ipad", + "iPad7,12":"ipad", + + "iPad8,1":"ipad", + "iPad8,2":"ipad", + "iPad8,3":"ipad", + "iPad8,4":"ipad", + "iPad8,5":"ipad", + "iPad8,6":"ipad", + "iPad8,7":"ipad", + "iPad8,8":"ipad", + "iPad8,9":"ipad", + "iPad8,10":"ipad", + "iPad8,11":"ipad", + "iPad8,12":"ipad", + "iPad11,3":"ipad", + "iPad11,4":"ipad", + "iPad11,6":"ipad", + "iPad11,7":"ipad", + + "iPad4,4":"ipadmini", + "iPad4,5":"ipadmini", + "iPad4,6":"ipadmini", + "iPad4,7":"ipadmini", + "iPad4,8":"ipadmini", + "iPad4,9":"ipadmini", + "iPad5,1":"ipadmini", + "iPad5,2":"ipadmini", + "iPod7,1":"ipodtouch", + "iPod9,1":"ipodtouch7", + "AppleTV5,3":"appletv4", + "AppleTV6,2":"appletv4k" + }, + "devicelayout":{ + "ipodtouch7":{ + "image_name":"ipodtouch", + "image_width":116, + "image_height":240, + "image_offset_x":100, + "buttons":{ + "top":{ + "name":"– Top button", + "x":192, + "y":-4 + }, + "vol_down":{ + "name":"Volume down –", + "x":8, + "y":62 + } + }, + "sequence":"ipodtouch7" + }, + "ipodtouch":{ + "image_name":"ipodtouch", + "image_width":116, + "image_height":240, + "image_offset_x":100, + "buttons":{ + "top":{ + "name":"– Top button", + "x":196, + "y":-4 + }, + "home":{ + "name":"Home button –", + "x":50, + "y":210 + } + }, + "sequence":"iphone-old" + }, + "iphonese":{ + "image_name":"iphonese", + "image_width":119, + "image_height":240, + "image_offset_x":100, + "buttons":{ + "top":{ + "name":"– Top button", + "x":200, + "y":-4 + }, + "home":{ + "name":"Home button –", + "x":56, + "y":210 + } + }, + "sequence":"iphone-old" + }, + "iphone6s":{ + "image_name":"iphone6s", + "image_width":123, + "image_height":240, + "image_offset_x":100, + "buttons":{ + "side":{ + "name":"– Side button", + "x":224, + "y":58 + }, + "home":{ + "name":"Home button –", + "x":60, + "y":210 + } + }, + "sequence":"iphone6" + }, + "iphone7":{ + "image_name":"iphone7", + "image_width":123, + "image_height":240, + "image_offset_x":100, + "buttons":{ + "side":{ + "name":"– Side button", + "x":224, + "y":58 + }, + "vol_down":{ + "name":"Volume down –", + "x":14, + "y":78 + } + }, + "sequence":"iphone7" + }, + "iphone8":{ + "image_name":"iphone8", + "image_width":120, + "image_height":240, + "image_offset_x":100, + "buttons":{ + "side":{ + "name":"– Side button", + "x":220, + "y":58 + }, + "vol_down":{ + "name":"Volume down –", + "x":10, + "y":78 + } + }, + "sequence":"iphone8" + }, + "iphonex":{ + "image_name":"iphonex", + "image_width":121, + "image_height":240, + "image_offset_x":100, + "buttons":{ + "side":{ + "name":"– Side button", + "x":220, + "y":68 + }, + "vol_down":{ + "name":"Volume down –", + "x":10, + "y":75 + } + }, + "sequence":"iphone8" + }, + "ipad":{ + "image_name":"ipad", + "image_width":170, + "image_height":240, + "buttons":{ + "top":{ + "name":"Top button", + "x":149, + "y":5 + }, + "home":{ + "name":"Home button", + "x":89, + "y":225 + } + }, + "sequence":"iphone-old" + }, + "ipadmini":{ + "image_name":"ipadmini", + "image_width":163, + "image_height":240, + "buttons":{ + "top":{ + "name":"Top button", + "x":140, + "y":4 + }, + "home":{ + "name":"Home button", + "x":86, + "y":224 + } + }, + "sequence":"iphone-old" + }, + "appletv4":{ + "image_name":"siriremote", + "image_width":79, + "image_height":240, + "image_offset_x":120, + "buttons":{ + "menu":{ + "name":"Menu –", + "x":84, + "y":84 + }, + "playpause":{ + "name":"Play/Pause –", + "x":52, + "y":146 + } + }, + "sequence":"appletv4" + }, + "appletv4k":{ + "image_name":"atv_std_brd", + "image_width":300, + "image_height":240, + "image_offset_x":0, + "buttons":{ + "dfu":{ + "name":"-- DFU button", + "x":120, + "y":48 + } + }, + "sequence":"atv_standard_breakout" + } + }, + "sequences":{ + "ipodtouch7":[ + { + "buttons":[ + + ], + "description":"Click Start", + "duration":0 + }, + { + "buttons":[ + "top", + "vol_down" + ], + "description":"Press and hold the Top and Volume down buttons together", + "duration":4, + "action":"reboot" + }, + { + "buttons":[ + "vol_down" + ], + "description":"Release the Top button BUT KEEP HOLDING the Volume down button", + "duration":10 + } + ], + "iphone-old":[ + { + "buttons":[ + + ], + "description":"Click Start", + "duration":0 + }, + { + "buttons":[ + "top", + "home" + ], + "description":"Press and hold the Top\n and Home buttons\n together", + "duration":4, + "action":"reboot" + }, + { + "buttons":[ + "home" + ], + "description":"Release the Top button\n BUT KEEP HOLDING the\n Home button", + "duration":10 + } + ], + "iphone6":[ + { + "buttons":[ + + ], + "description":"Click Start", + "duration":0 + }, + { + "buttons":[ + "side", + "home" + ], + "description":"Press and hold the Side\n and Home buttons\n together", + "duration":4, + "action":"reboot" + }, + { + "buttons":[ + "home" + ], + "description":"Release the Side button\n BUT KEEP HOLDING the\n Home button", + "duration":10 + } + ], + "iphone7":[ + { + "buttons":[ + + ], + "description":"Click Start", + "duration":0 + }, + { + "buttons":[ + "side", + "vol_down" + ], + "description":"Press and hold the Side\n and Volume down\n buttons together", + "duration":4, + "action":"reboot" + }, + { + "buttons":[ + "vol_down" + ], + "description":"Release the Side button\n BUT KEEP HOLDING the\n Volume down button", + "duration":10 + } + ], + "iphone8":[ + { + "buttons":[ + + ], + "description":"Click Start", + "duration":0 + }, + { + "buttons":[ + "side", + "vol_down" + ], + "description":"Press and hold the Side\n and Volume down\n buttons together", + "duration":4, + "action":"reboot" + }, + { + "buttons":[ + "vol_down" + ], + "description":"Release the Side button\n BUT KEEP HOLDING the\n Volume down button", + "duration":10 + } + ], + "appletv4":[ + { + "buttons":[ + + ], + "description":"Get Ready", + "duration":3 + }, + { + "buttons":[ + "menu", + "playpause" + ], + "description":"Press and hold Menu\n and Play/Pause together\n ", + "duration":7 + }, + { + "buttons":[ + + ], + "description":"Release the buttons", + "duration":2 + } + ], + "atv_standard_breakout":[ + { + "buttons":[ + + ], + "description":"Get Ready", + "duration":3 + }, + { + "buttons":[ + "dfu" + ], + "description":"Press and hold the DFU\n button", + "duration":10, + "action":"reboot" + } + ] + } +} diff --git a/resources/Info.plist b/resources/Info.plist index 11254bc..11ca933 100644 --- a/resources/Info.plist +++ b/resources/Info.plist @@ -1,16 +1,24 @@ - - CFBundleIdentifier - palera.in.palera1n - CFBundleDevelopmentRegion - English - CFBundlePackageType - APPL - NSPrincipalClass - NSApplication - NSHighResolutionCapable - - + + CFBundleDevelopmentRegion + English + CFBundleExecutable + palera1n + CFBundleIconFile + palera1n.icns + CFBundleIdentifier + palera1n + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + palera1n + CFBundlePackageType + APPL + NSHumanReadableCopyright + (c) 2026 palera1n + NSHighResolutionCapable + + diff --git a/resources/ios-entitlements.xml b/resources/ios-entitlements.xml deleted file mode 100644 index f7077f9..0000000 --- a/resources/ios-entitlements.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - platform-application - - com.apple.private.security.no-container - - com.apple.security.iokit-user-client-class - - IOUserClient - - - diff --git a/resources/logo.png b/resources/logo.png deleted file mode 100644 index c79e828..0000000 Binary files a/resources/logo.png and /dev/null differ diff --git a/resources/palera1n.icns b/resources/palera1n.icns new file mode 100644 index 0000000..b55e466 Binary files /dev/null and b/resources/palera1n.icns differ diff --git a/src/event.cpp b/src/event.cpp new file mode 100644 index 0000000..edc1d7e --- /dev/null +++ b/src/event.cpp @@ -0,0 +1,186 @@ +#ifdef WITH_GUI + +#include "event.hpp" + +#include "wx/AppFrame.hpp" +#include "state.hpp" +#include "sequence.hpp" +#include "utils/log.h" + +#include +#include + +#include +#include +#include + +static inline DeviceState make_fresh_state() +{ + return DeviceState{}; +} + +void normal_device_event_cb( + const idevice_event_t* event, + void* user_data) +{ + #ifdef WITH_GUI + auto* frame = static_cast(user_data); + if (!frame || !event) + return; + #endif + + DeviceState state = make_fresh_state(); + + if (event->event == IDEVICE_DEVICE_REMOVE) + { + #ifdef WITH_GUI + send_device_state(frame, state); + #endif + return; + } + + if (event->event != IDEVICE_DEVICE_ADD) + return; + + idevice_t device = nullptr; + if (idevice_new(&device, event->udid) != IDEVICE_E_SUCCESS) + return; + + state.connected = true; + state.mode = DeviceMode::Normal; + state.udid = event->udid ? event->udid : ""; + + lockdownd_client_t client = nullptr; + + if (lockdownd_client_new_with_handshake(device, &client, "palera1n") == LOCKDOWN_E_SUCCESS) + { + plist_t product = nullptr; + plist_t version = nullptr; + plist_t ecid = nullptr; + + char *p = nullptr, *v = nullptr; + uint64_t ecid_val = 0; + + lockdownd_get_value(client, nullptr, "ProductType", &product); + lockdownd_get_value(client, nullptr, "ProductVersion", &version); + lockdownd_get_value(client, nullptr, "UniqueChipID", &ecid); + + if (product) plist_get_string_val(product, &p); + if (version) plist_get_string_val(version, &v); + if (ecid) plist_get_uint_val(ecid, &ecid_val); + + state.productType = p ? p : ""; + state.productVersion = v ? v : ""; + state.ecid = ecid_val; + + free(p); + free(v); + + if (product) plist_free(product); + if (version) plist_free(version); + if (ecid) plist_free(ecid); + + lockdownd_client_free(client); + } + + idevice_free(device); + + state.isSupported = SequenceIsSupported(state.productType); + + #ifdef WITH_GUI + send_device_state(frame, state); + #endif +} + +void recovery_device_event_cb( + const irecv_device_event_t* event, + void* user_data) +{ + #ifdef WITH_GUI + auto* frame = static_cast(user_data); + if (!frame || !event) + return; + #endif + + DeviceState state = make_fresh_state(); + + if (event->type == IRECV_DEVICE_REMOVE) + { + #ifdef WITH_GUI + send_device_state(frame, state); + #endif + return; + } + + if (event->type != IRECV_DEVICE_ADD) + return; + + state.connected = true; + + if (event->mode == IRECV_K_DFU_MODE) + { + state.mode = DeviceMode::DFU; + #ifdef WITH_GUI + send_device_state(frame, state); + #endif + return; + } + + if (!(event->mode == IRECV_K_RECOVERY_MODE_1 || + event->mode == IRECV_K_RECOVERY_MODE_2 || + event->mode == IRECV_K_RECOVERY_MODE_3 || + event->mode == IRECV_K_RECOVERY_MODE_4)) + { + return; + } + + state.mode = DeviceMode::Recovery; + + uint64_t ecid_val = 0; + if (event->device_info && event->device_info->ecid) + ecid_val = event->device_info->ecid; + state.ecid = ecid_val; + + irecv_client_t client = nullptr; + + int attempts = 0; + const int max_attempts = 10; + + while (attempts < max_attempts) + { + if (irecv_open_with_ecid(&client, state.ecid) == IRECV_E_SUCCESS) + break; + + attempts++; + std::this_thread::sleep_for(std::chrono::milliseconds(300)); + } + + if (client) + { + LOG("Opened client after %d attempts", attempts); + + irecv_device_t device = nullptr; + if (irecv_devices_get_device_by_client(client, &device) == IRECV_E_SUCCESS && device) + { + LOG("device product type: %s", device->product_type); + LOG("device display name: %s", device->display_name); + + state.productType = device->product_type ? device->product_type : ""; + state.displayName = device->display_name ? device->display_name : ""; + } + + irecv_close(client); + } + else + { + LOG("Failed to open irecv client after retries"); + } + + state.isSupported = SequenceIsSupported(state.productType); + + #ifdef WITH_GUI + send_device_state(frame, state); + #endif +} + +#endif // WITH_GUI diff --git a/src/event.hpp b/src/event.hpp new file mode 100644 index 0000000..078c620 --- /dev/null +++ b/src/event.hpp @@ -0,0 +1,21 @@ +#ifdef WITH_GUI + +#ifndef EVENT_H +#define EVENT_H + +#include "state.hpp" + +#include + +#include +#include +#include + +class MainFrame; + +void normal_device_event_cb(const idevice_event_t* event, void* user_data); +void recovery_device_event_cb(const irecv_device_event_t* event, void* user_data); + +#endif // EVENT_H + +#endif // WITH_GUI diff --git a/src/main.cpp b/src/main.cpp index 2f8024b..dcc72f5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,12 +5,6 @@ #include #include -#if defined(__APPLE__) -#include -#include -#include -#endif - #ifdef WITH_GUI # include #endif @@ -21,9 +15,16 @@ void print_credits() { printf( - ":: ========================== ::\n" - ":: palera1n: " PALERAIN_VERSION "\n" - ":: ========================== ::\n\n" + "#\n" + "# palera1n: " PALERAIN_VERSION "\n" + "#\n" + "# ======== Made by =======\n" + "# Made by: asdfugil, kok3shidoll, claration, mineek, staturnz\n" + "# ======== Thanks to =======\n" + "# Thanks to: llsc12, Nebula, Lrdsnow, nikias (libimobiledevice),\n" + "# checkra1n team (Siguza, axi0mx, littlelailo et al.),\n" + "# Procursus Team (Hayden Seay, Cameron Katri, Keto et.al)\n" + "# ==========================\n\n" ); } diff --git a/src/sequence.cpp b/src/sequence.cpp new file mode 100644 index 0000000..e49c6f9 --- /dev/null +++ b/src/sequence.cpp @@ -0,0 +1,88 @@ +#ifdef WITH_GUI + +#include +#include "gen/DFUHelperDeviceInfo.h" +#include "sequence.hpp" + +DfuSequence ParseSequence(const std::string& deviceKey) +{ + DfuSequence seq; + + static nlohmann::json j = nlohmann::json::parse( + DFUHelperDeviceInfo, + DFUHelperDeviceInfo + DFUHelperDeviceInfo_len + ); + + auto itMap = j["devicemap"].find(deviceKey); + if (itMap == j["devicemap"].end()) + return seq; + + const std::string deviceType = itMap.value(); + + auto itLayout = j["devicelayout"].find(deviceType); + if (itLayout == j["devicelayout"].end()) + return seq; + + const auto& layout = itLayout.value(); + + seq.imageName = layout.value("image_name", ""); + seq.imageWidth = layout.value("image_width", 0); + seq.imageHeight = layout.value("image_height", 0); + seq.imageOffsetX = layout.value("image_offset_x", 0); + + if (layout.contains("buttons")) + { + for (auto it = layout["buttons"].begin(); + it != layout["buttons"].end(); + ++it) + { + DfuButton btn; + + btn.id = it.key(); + + const auto& b = it.value(); + + btn.name = b.value("name", ""); + btn.x = b.value("x", 0); + btn.y = b.value("y", 0); + + seq.buttons.push_back(std::move(btn)); + } + } + + const std::string sequenceKey = + layout.value("sequence", ""); + + auto itSeq = j["sequences"].find(sequenceKey); + if (itSeq == j["sequences"].end()) + return seq; + + for (const auto& s : itSeq.value()) + { + DfuStep step; + + step.description = s.value("description", ""); + step.duration = s.value("duration", 0); + step.action = s.value("action", ""); + + if (s.contains("buttons")) + { + for (const auto& b : s["buttons"]) + step.activeButtons.push_back( + b.get() + ); + } + + seq.steps.push_back(std::move(step)); + } + + return seq; +} + +bool SequenceIsSupported(const std::string& deviceKey) +{ + DfuSequence seq = ParseSequence(deviceKey); + return !seq.steps.empty(); +} + +#endif // WITH_GUI diff --git a/src/sequence.hpp b/src/sequence.hpp new file mode 100644 index 0000000..2817635 --- /dev/null +++ b/src/sequence.hpp @@ -0,0 +1,40 @@ +#ifdef WITH_GUI + +#ifndef SEQUENCE_H +#define SEQUENCE_H + +#include + +struct DfuButton +{ + std::string id; + std::string name; + int x = 0; + int y = 0; +}; + +struct DfuStep +{ + std::string description; + int duration = 0; + std::vector activeButtons; + std::string action; +}; + +struct DfuSequence +{ + std::string imageName; + int imageWidth = 0; + int imageHeight = 0; + int imageOffsetX = 0; + + std::vector buttons; + std::vector steps; +}; + +DfuSequence ParseSequence(const std::string& deviceKey); +bool SequenceIsSupported(const std::string& deviceKey); + +#endif // SEQUENCE_H + +#endif // WITH_GUI diff --git a/src/state.hpp b/src/state.hpp new file mode 100644 index 0000000..2a3d27e --- /dev/null +++ b/src/state.hpp @@ -0,0 +1,26 @@ +#ifndef STATE_H +#define STATE_H + +#include + +enum class DeviceMode +{ + None, + Normal, + Recovery, + DFU +}; + +struct DeviceState +{ + bool connected = false; + bool isSupported = false; + DeviceMode mode = DeviceMode::None; + std::string productVersion; + std::string productType; + std::string displayName; + std::string udid; + uint64_t ecid; +}; + +#endif // STATE_H diff --git a/src/ui/app.cpp b/src/ui/app.cpp deleted file mode 100644 index 1720476..0000000 --- a/src/ui/app.cpp +++ /dev/null @@ -1,209 +0,0 @@ -#ifdef WITH_GUI - -#include "app.hpp" -#include -#include -#include -#include -#include -#include -#include "../utils/constants.h" -#include "../utils/paleinfo.h" -#include "../utils/log.h" -#include "../exploit/logo.h" - -class MainFrame; - -class MainPanel : public wxPanel -{ -public: - explicit MainPanel(MainFrame* frame, wxWindow* parent); -}; - -class SettingsPanel : public wxPanel -{ -public: - explicit SettingsPanel(MainFrame* frame, wxWindow* parent); -}; - -class MainFrame : public wxFrame -{ -public: - MainFrame() - : wxFrame( - nullptr, - wxID_ANY, - "palera1n – Version beta " + wxString(PALERAIN_VERSION), - wxDefaultPosition, - wxSize(480, 360), - wxDEFAULT_FRAME_STYLE & ~(wxMAXIMIZE_BOX | wxRESIZE_BORDER)) - { - auto* root = new wxBoxSizer(wxVERTICAL); - - m_main = new MainPanel(this, this); - m_settings = new SettingsPanel(this, this); - - root->Add(m_main, 1, wxEXPAND); - root->Add(m_settings, 1, wxEXPAND); - - SetSizer(root); - - ShowMain(); - } - - void ShowMain() - { - m_main->Show(); - m_settings->Hide(); - Layout(); - } - - void ShowSettings() - { - m_main->Hide(); - m_settings->Show(); - Layout(); - } - -private: - MainPanel* m_main; - SettingsPanel* m_settings; -}; - -MainPanel::MainPanel(MainFrame* frame, wxWindow* parent) - : wxPanel(parent) -{ - auto* root = new wxBoxSizer(wxVERTICAL); - - wxInitAllImageHandlers(); - - wxMemoryInputStream stream(resources_logo_png, resources_logo_png_len); - wxImage img(stream, wxBITMAP_TYPE_PNG); - wxBitmap bmp(img); - auto* logo = new wxStaticBitmap(this, wxID_ANY, bmp); - - auto* titletext = new wxStaticText(this, wxID_ANY, "Welcome to palera1n!"); - wxFont titlefont = titletext->GetFont(); - titlefont.SetWeight(wxFONTWEIGHT_BOLD); - titletext->SetFont(titlefont); - - auto* left = new wxBoxSizer(wxVERTICAL); - left->Add(titletext, 0, wxTOP | wxLEFT, 10); - - auto* row = new wxBoxSizer(wxHORIZONTAL); - row->Add(left, 0, wxALIGN_TOP); - row->AddStretchSpacer(); - row->Add(logo, 0, wxTOP | wxRIGHT, 10); - root->Add(row, 0, wxEXPAND); - - root->Add(new wxStaticLine(this), 0, wxEXPAND | wxALL, 10); - - auto* credtext = new wxStaticText(this, wxID_ANY, "Made by: asdfugil, kok3shidoll, claration, mineek, staturnz\n\nThanks to: itsnebulalol, llsc12, lrdsnow, nikias (libimobiledevice), Checkra1n\n(Siguza, axi0mx, littlelailo et al.), Procursus (Hayden Seay, Cameron Katri,\nKeto et al.)\n\nWith 💖 from C (claration)"); - root->Add(credtext, 0, wxLEFT | wxRIGHT, 10); - - root->Add(new wxStaticLine(this), 0, wxEXPAND | wxALL, 10); - - auto* notetext = new wxStaticText(this, wxID_ANY, "NOTE: Please ensure you have a backup of your device before applying the\njailbreak. While data loss is unlikely, we won't be responsible if something goes\nwrong. Use at your own risk."); - wxFont notefont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); - notefont.SetPointSize(12); - notefont.SetStyle(wxFONTSTYLE_ITALIC); - notetext->SetFont(notefont); - root->Add(notetext, 0, wxLEFT | wxRIGHT, 10); - - root->AddStretchSpacer(); - - auto* btn = new wxButton(this, wxID_ANY, "Options"); - auto* sbtn = new wxButton(this, wxID_ANY, "Start"); - sbtn->Disable(); - btn->Bind(wxEVT_BUTTON, [frame](wxCommandEvent&) - { - frame->ShowSettings(); - }); - auto* bottomRow = new wxBoxSizer(wxHORIZONTAL); - bottomRow->AddStretchSpacer(); - bottomRow->Add(btn, 0, wxALL, 10); - bottomRow->Add(sbtn, 0, wxALL, 10); - root->Add(bottomRow, 0, wxEXPAND); - - SetSizer(root); -} - -SettingsPanel::SettingsPanel(MainFrame* frame, wxWindow* parent) - : wxPanel(parent) -{ - auto* root = new wxBoxSizer(wxVERTICAL); - - root->Add(new wxStaticText(this, wxID_ANY, - "You may set the following options. If you don't know what they mean you'll\n" - "probably have no reason to set them."), 0, wxALL, 10); - - auto* option_safemode = new wxCheckBox(this, wxID_ANY, "Safe Mode"); - auto* option_verbose = new wxCheckBox(this, wxID_ANY, "Verbose Boot"); - auto* option_revert = new wxCheckBox(this, wxID_ANY, "Restore System"); - auto* option_dark_blockchain = new wxCheckBox(this, wxID_ANY, "Dark Blockchain"); - - option_safemode->SetValue(palerain_flags & palerain_option_safemode); - option_verbose->SetValue(palerain_flags & palerain_option_verbose_boot); - option_revert->SetValue(palerain_flags & palerain_option_force_revert); - option_dark_blockchain->SetValue(true); - - option_safemode->Bind(wxEVT_CHECKBOX, [&](wxCommandEvent& e) - { - if (e.IsChecked()) - palerain_flags |= palerain_option_safemode; - else - palerain_flags &= ~palerain_option_safemode; - }); - option_verbose->Bind(wxEVT_CHECKBOX, [&](wxCommandEvent& e) - { - if (e.IsChecked()) - palerain_flags |= palerain_option_verbose_boot; - else - palerain_flags &= ~palerain_option_verbose_boot; - }); - option_revert->Bind(wxEVT_CHECKBOX, [&](wxCommandEvent& e) - { - if (e.IsChecked()) - palerain_flags |= palerain_option_force_revert; - else - palerain_flags &= ~palerain_option_force_revert; - }); - - root->Add(option_safemode, 0, wxLEFT | wxRIGHT, 10); - root->Add(option_verbose, 0, wxLEFT | wxRIGHT | wxTOP, 10); - - root->Add(new wxStaticText(this, wxID_ANY, "Boot Arguments:"), 0, wxALL, 10); - auto* bootArgs = new wxTextCtrl(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize); - root->Add(bootArgs, 0, wxLEFT | wxRIGHT | wxEXPAND, 30); - - root->Add(option_revert, 0, wxLEFT | wxRIGHT | wxTOP, 10); - root->Add(option_dark_blockchain, 0, wxLEFT | wxRIGHT | wxTOP, 10); - - root->AddStretchSpacer(); - - auto* back = new wxButton(this, wxID_ANY, "Back"); - - back->Bind(wxEVT_BUTTON, [frame](wxCommandEvent&) - { - frame->ShowMain(); - }); - - auto* bottomRow = new wxBoxSizer(wxHORIZONTAL); - bottomRow->AddStretchSpacer(); - bottomRow->Add(back, 0, wxALL, 10); - - root->Add(bottomRow, 0, wxEXPAND); - - SetSizer(root); -} - -bool PalerainApp::OnInit() -{ - auto* frame = new MainFrame(); - frame->Show(true); - return true; -} - -wxIMPLEMENT_APP_NO_MAIN(PalerainApp); - -#endif // WITH_GUI diff --git a/src/ui/app.hpp b/src/ui/app.hpp deleted file mode 100644 index 4d70423..0000000 --- a/src/ui/app.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#ifdef WITH_GUI -#pragma once -#include - -class PalerainApp : public wxApp { -public: - bool OnInit() override; -}; - -#endif // WITH_GUI diff --git a/src/utils/constants.h b/src/utils/constants.h index 777e5fc..1cb9f67 100644 --- a/src/utils/constants.h +++ b/src/utils/constants.h @@ -1,7 +1,7 @@ #ifndef CONSTANTS_H #define CONSTANTS_H -#define PALERAIN_VERSION "2.4.0" +#define PALERAIN_VERSION "3.0.0" #include diff --git a/src/wx/AppFrame.cpp b/src/wx/AppFrame.cpp new file mode 100644 index 0000000..2fb590a --- /dev/null +++ b/src/wx/AppFrame.cpp @@ -0,0 +1,165 @@ +#ifdef WITH_GUI + +#include "AppFrame.hpp" + +#include +#include "../utils/constants.h" +#include "../event.hpp" + +#include + +#include +#include +#include + +wxDEFINE_EVENT(EVT_DEVICE_STATE_UPDATE, wxCommandEvent); + +void send_device_state(MainFrame* frame, const DeviceState& state) +{ + wxTheApp->CallAfter([frame, state]() { + auto* evt = new wxCommandEvent(EVT_DEVICE_STATE_UPDATE); + evt->SetClientData(new DeviceState(state)); + wxPostEvent(frame, *evt); + }); +} + +MainFrame::MainFrame() + : wxFrame(nullptr, + wxID_ANY, + "palera1n – Version beta " + wxString(PALERAIN_VERSION), + wxDefaultPosition, + wxSize(480, 360), + wxDEFAULT_FRAME_STYLE & ~(wxMAXIMIZE_BOX | wxRESIZE_BORDER)) +{ + auto* root = new wxBoxSizer(wxVERTICAL); + + m_main = new MainPanel(this, this); + m_settings = new SettingsPanel(this, this); + m_recovery = new RecoveryPanel(this, this); + m_dfu = new DfuPanel(this, this); + m_exploit = new ExploitPanel(this, this); + + root->Add(m_main, 1, wxEXPAND); + root->Add(m_settings, 1, wxEXPAND); + root->Add(m_recovery, 1, wxEXPAND); + root->Add(m_dfu, 1, wxEXPAND); + root->Add(m_exploit, 1, wxEXPAND); + + SetSizer(root); + + Bind(EVT_DEVICE_STATE_UPDATE, [this](wxCommandEvent& e) + { + auto* state = static_cast(e.GetClientData()); + + if (!state) + return; + + UpdateDeviceState(*state); + + delete state; + }); + + ShowMain(); + + std::thread([this]() + { + idevice_event_subscribe(normal_device_event_cb, this); + + while (true) + sleep(1); + }).detach(); + + std::thread([this]() + { + static irecv_device_event_context_t ctx = nullptr; + + irecv_device_event_subscribe( + &ctx, + recovery_device_event_cb, + this + ); + + while (true) + sleep(1); + }).detach(); +} + +void MainFrame::ShowMain() +{ + m_main->Show(); + m_settings->Hide(); + m_recovery->Hide(); + m_dfu->Hide(); + m_exploit->Hide(); + Layout(); +} + +void MainFrame::ShowSettings() +{ + m_main->Hide(); + m_settings->Show(); + m_recovery->Hide(); + m_dfu->Hide(); + m_exploit->Hide(); + Layout(); +} + +void MainFrame::ShowRecovery() +{ + m_main->Hide(); + m_settings->Hide(); + m_recovery->Show(); + m_dfu->Hide(); + m_exploit->Hide(); + Layout(); +} + +void MainFrame::ShowDfu() +{ + m_main->Hide(); + m_settings->Hide(); + m_recovery->Hide(); + m_dfu->Show(); + m_dfu->LoadDevice(m_state.productType); + m_exploit->Hide(); + Layout(); +} + +void MainFrame::ShowExploit() +{ + m_main->Hide(); + m_settings->Hide(); + m_recovery->Hide(); + m_dfu->Hide(); + m_exploit->Show(); + m_exploit->StartExploit(); + Layout(); +} + +void MainFrame::UpdateDeviceState(const DeviceState& state) +{ + m_state = state; + + if (m_main) + m_main->SetDeviceState(m_state); + + if (m_recovery) + m_recovery->SetDeviceState(m_state); + + if (m_dfu) + m_dfu->SetDeviceState(m_state); + + if (m_exploit) + m_exploit->SetDeviceState(m_state); +} + +bool PalerainApp::OnInit() +{ + auto* frame = new MainFrame(); + frame->Show(true); + return true; +} + +wxIMPLEMENT_APP_NO_MAIN(PalerainApp); + +#endif diff --git a/src/wx/AppFrame.hpp b/src/wx/AppFrame.hpp new file mode 100644 index 0000000..bb80348 --- /dev/null +++ b/src/wx/AppFrame.hpp @@ -0,0 +1,53 @@ +#ifndef APPFRAME_H +#define APPFRAME_H + +#ifdef WITH_GUI + +#include +#include "../state.hpp" + +#include "MainPanel.hpp" +#include "SettingsPanel.hpp" +#include "RecoveryPanel.hpp" +#include "DfuPanel.hpp" +#include "ExploitPanel.hpp" + +void send_device_state(MainFrame* frame, const DeviceState& state); + +class MainFrame : public wxFrame +{ +public: + MainFrame(); + + void ShowMain(); + void ShowSettings(); + void ShowRecovery(); + void ShowDfu(); + void ShowExploit(); + + const DeviceState& GetDeviceState() const { return m_state; } + void UpdateDeviceState(const DeviceState& state); + + MainPanel* GetMainPanel() const { return m_main; } + SettingsPanel* GetSettingsPanel() const { return m_settings; } + RecoveryPanel* GetRecoveryPanel() const { return m_recovery; } + DfuPanel* GetDfuPanel() const { return m_dfu; } + ExploitPanel* GetExploitPanel() const { return m_exploit; } +private: + MainPanel* m_main = nullptr; + SettingsPanel* m_settings = nullptr; + RecoveryPanel* m_recovery = nullptr; + DfuPanel* m_dfu = nullptr; + ExploitPanel* m_exploit = nullptr; + + DeviceState m_state; +}; + +class PalerainApp : public wxApp { +public: + bool OnInit() override; +}; + +#endif // WITH_GUI + +#endif // APPFRAME_H diff --git a/src/wx/DevicePanel.hpp b/src/wx/DevicePanel.hpp new file mode 100644 index 0000000..a43dfaa --- /dev/null +++ b/src/wx/DevicePanel.hpp @@ -0,0 +1,38 @@ +#ifndef DEVICEPANEL_H +#define DEVICEPANEL_H + +#include +#include "../state.hpp" + +class MainFrame; +class DevicePanel : public wxPanel +{ +public: + DevicePanel(MainFrame* frame, wxWindow* parent) + : wxPanel(parent), + m_frame(frame) + { + } + + virtual void SetDeviceState(const DeviceState& state) + { + m_deviceState = state; + } + +protected: + MainFrame* GetMainFrame() const + { + return m_frame; + } + + const DeviceState& GetDeviceState() const + { + return m_deviceState; + } + +private: + MainFrame* m_frame; + DeviceState m_deviceState; +}; + +#endif // DEVICEPANEL_H diff --git a/src/wx/DfuPanel.cpp b/src/wx/DfuPanel.cpp new file mode 100644 index 0000000..89eea93 --- /dev/null +++ b/src/wx/DfuPanel.cpp @@ -0,0 +1,427 @@ +#ifdef WITH_GUI + +#include "DfuPanel.hpp" + +#include "AppFrame.hpp" +#include "DevicePanel.hpp" +#include "../state.hpp" +#include "../sequence.hpp" +#include "../utils/log.h" + +#include + +#include +#include +#include +#include + +#include "../gen/images/atv_std_brd.h" +#include "../gen/images/ipad.h" +#include "../gen/images/ipadmini.h" +#include "../gen/images/iphone6s.h" +#include "../gen/images/iphone7.h" +#include "../gen/images/iphone8.h" +#include "../gen/images/iphonese.h" +#include "../gen/images/iphonex.h" +#include "../gen/images/ipodtouch.h" +#include "../gen/images/siriremote.h" + +#include + +static const wxColour kActive = + wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); + +static const wxColour kInactive = + wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT); + +DfuPanel::DfuPanel(MainFrame* frame, wxWindow* parent) + : DevicePanel(frame, parent) +{ + auto* root = new wxBoxSizer(wxVERTICAL); + + m_headerText = new wxStaticText(this, wxID_ANY, "Time to put the device into DFU mode. Locate the buttons as marked below\non your device and check the instructions on the right."); + root->Add(m_headerText, 0, wxALL, 10); + + auto* contentRow = new wxBoxSizer(wxHORIZONTAL); + + m_devicePanel = new wxPanel(this); + m_devicePanel->SetMinSize(wxSize(310, 260)); + + m_deviceImage = new wxStaticBitmap( + m_devicePanel, + wxID_ANY, + wxBitmap() + ); + + contentRow->Add(m_devicePanel, 1, wxTOP, 10); + m_stepsSizer = new wxBoxSizer(wxVERTICAL); + contentRow->Add(m_stepsSizer, 2, wxEXPAND | wxALL, 0); + + root->Add(contentRow, 1, wxEXPAND); + + m_backButton = new wxButton(this, wxID_ANY, "Back"); + m_startButton = new wxButton(this, wxID_ANY, "Start"); + + m_backButton->Bind(wxEVT_BUTTON, [frame](wxCommandEvent&) + { + frame->ShowMain(); + }); + + m_startButton->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) + { + m_isEnteringDfu = true; + m_backButton->Disable(); + m_startButton->Disable(); + + StartSequence(m_sequence); + }); + + m_timer.Bind(wxEVT_TIMER, [this](wxTimerEvent&) + { + RunStep(); + }); + + m_stagnentTimer.Bind(wxEVT_TIMER, [this](wxTimerEvent&) + { + m_backButton->Enable(); + m_startButton->Enable(); + GetMainFrame()->ShowExploit(); + }); + + auto* bottomRow = new wxBoxSizer(wxHORIZONTAL); + + bottomRow->AddStretchSpacer(); + bottomRow->Add(m_backButton, 0, wxALL, 10); + bottomRow->Add(m_startButton, 0, wxALL, 10); + + root->Add(bottomRow, 0, wxEXPAND); + + SetSizer(root); +} + +void DfuPanel::SetDeviceState(const DeviceState& state) +{ + DevicePanel::SetDeviceState(state); + + if (!(this->IsShown())) + return; + + if (m_isEnteringDfu && state.mode == DeviceMode::DFU) + { + m_isEnteringDfu = false; + m_headerText->SetLabel("Device entered DFU mode successfully.\n"); + + if (!m_stagnentTimer.IsRunning()) + m_stagnentTimer.StartOnce(3000); + } + + if (m_isEnteringDfu && state.mode == DeviceMode::Normal) + { + m_isEnteringDfu = false; + m_backButton->Enable(); + m_startButton->Enable(); + GetMainFrame()->ShowRecovery(); + GetMainFrame()->GetRecoveryPanel()->SetStatusText("Hmm... It seems like the device didn't enter DFU mode."); + } + + if (m_isEnteringDfu && state.mode == DeviceMode::Recovery) + { + m_isEnteringDfu = false; + m_backButton->Enable(); + m_startButton->Enable(); + GetMainFrame()->ShowMain(); + } +} + +void DfuPanel::LoadDevice(const std::string& productType) +{ + m_sequence = ParseSequence(productType); + m_index = 0; + + m_deviceImage->SetBitmap(wxBitmap()); + + for (auto* lbl : m_stepLabels) + lbl->Destroy(); + + m_stepLabels.clear(); + m_stepsSizer->Clear(false); + + for (auto* lbl : m_buttonLabels) + lbl->Destroy(); + + m_buttonLabels.clear(); + + const unsigned char* imageData = nullptr; + size_t imageSize = 0; + + if (m_sequence.imageName == "ipadmini") + { + imageData = ipadmini; + imageSize = ipadmini_len; + } + else if (m_sequence.imageName == "ipad") + { + imageData = ipad; + imageSize = ipad_len; + } + else if (m_sequence.imageName == "iphonese") + { + imageData = iphonese; + imageSize = iphonese_len; + } + else if (m_sequence.imageName == "iphone6s") + { + imageData = iphone6s; + imageSize = iphone6s_len; + } + else if (m_sequence.imageName == "iphone7") + { + imageData = iphone7; + imageSize = iphone7_len; + } + else if (m_sequence.imageName == "iphone8") + { + imageData = iphone8; + imageSize = iphone8_len; + } + else if (m_sequence.imageName == "iphonex") + { + imageData = iphonex; + imageSize = iphonex_len; + } + else if (m_sequence.imageName == "ipodtouch") + { + imageData = ipodtouch; + imageSize = ipodtouch_len; + } + else if (m_sequence.imageName == "siriremote") + { + imageData = siriremote; + imageSize = siriremote_len; + } + else if (m_sequence.imageName == "atv_std_brd") + { + imageData = atv_std_brd; + imageSize = atv_std_brd_len; + } + + if (imageData) + { + wxMemoryInputStream stream(imageData, imageSize); + + wxImage img(stream, wxBITMAP_TYPE_PNG); + + if (img.IsOk()) + { + img = img.Scale( + m_sequence.imageWidth, + m_sequence.imageHeight, + wxIMAGE_QUALITY_HIGH + ); + + m_deviceImage->SetBitmap(wxBitmap(img)); + m_deviceImage->SetPosition(wxPoint(m_sequence.imageOffsetX, 0)); + } + } + + for (const auto& button : m_sequence.buttons) + { + auto* lbl = new wxStaticText( + m_devicePanel, + wxID_ANY, + button.name + ); + + lbl->SetPosition(wxPoint(button.x, button.y)); + + m_buttonLabels.push_back(lbl); + } + + for (size_t i = 0; i < m_sequence.steps.size(); i++) + { + const auto& step = m_sequence.steps[i]; + + wxString label = wxString::Format( + "%zu. %s (%d)", + i + 1, + step.description, + step.duration + ); + + auto* lbl = new wxStaticText( + this, + wxID_ANY, + label + ); + + lbl->SetForegroundColour(i == 0 ? kActive : kInactive); + + m_stepsSizer->Add(lbl, 0, wxBOTTOM, 5); + m_stepLabels.push_back(lbl); + } + + m_devicePanel->Layout(); + m_stepsSizer->Layout(); + + Layout(); + Fit(); + Refresh(); +} + +void DfuPanel::StartSequence(const DfuSequence& seq) +{ + m_sequence = seq; + m_index = 0; + m_stepRemaining = -1; + m_actionExecutedIndex = -1; + + RunStep(); + m_timer.StartOnce(1000); +} + +void DfuPanel::RunStep() +{ + if (m_sequence.steps.empty()) + return; + + if (m_index >= m_sequence.steps.size()) + { + for (auto* lbl : m_stepLabels) + lbl->SetForegroundColour(kInactive); + + Layout(); + Refresh(); + + m_timer.Stop(); + return; + } + + const auto& step = m_sequence.steps[m_index]; + + if (m_stepRemaining < 0) + m_stepRemaining = step.duration; + + if (m_stepRemaining > 0) + --m_stepRemaining; + + bool finished = (m_stepRemaining == 0); + size_t completedIndex = m_index; + + if (finished) + { + ++m_index; + m_stepRemaining = -1; + } + + for (size_t i = 0; i < m_stepLabels.size(); i++) + { + auto* lbl = m_stepLabels[i]; + + if (i == m_index) + { + lbl->SetForegroundColour(kActive); + + lbl->SetLabel(wxString::Format( + "%zu. %s (%d)", + i + 1, + m_sequence.steps[i].description, + m_stepRemaining < 0 ? m_sequence.steps[i].duration : m_stepRemaining + )); + } + else if (finished && i == completedIndex) + { + lbl->SetForegroundColour(kInactive); + + lbl->SetLabel(wxString::Format( + "%zu. %s (0)", + i + 1, + m_sequence.steps[i].description + )); + } + else + { + lbl->SetForegroundColour(kInactive); + } + } + + for (auto* lbl : m_buttonLabels) + lbl->SetForegroundColour(kInactive); + + const auto& activeStep = + (m_index < m_sequence.steps.size()) + ? m_sequence.steps[m_index] + : m_sequence.steps.back(); + + for (const auto& buttonId : activeStep.activeButtons) + { + for (const auto& btn : m_sequence.buttons) + { + if (btn.id == buttonId) + { + for (auto* lbl : m_buttonLabels) + { + if (lbl->GetLabel() == btn.name) + lbl->SetForegroundColour(kActive); + } + } + } + } + + if (m_index < m_sequence.steps.size()) + { + const auto& activeStep = m_sequence.steps[m_index]; + + if (!activeStep.action.empty() && m_actionExecutedIndex != m_index) + { + m_actionExecutedIndex = m_index; + + if (activeStep.action == "reboot") + { + Reboot(); + } + } + } + + Layout(); + Refresh(); + Update(); + + m_timer.StartOnce(1000); +} + +void DfuPanel::Reboot() +{ + std::thread([this]() + { + const auto state = GetDeviceState(); + + if (!state.connected || state.mode != DeviceMode::Recovery) + return; + + irecv_client_t client = nullptr; + + int attempts = 0; + const int max_attempts = 8; + + while (attempts < max_attempts) + { + if (irecv_open_with_ecid(&client, state.ecid) == IRECV_E_SUCCESS) + break; + + attempts++; + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + } + + if (!client) + { + return; + } + irecv_setenv(client, "auto-boot", "true"); + irecv_saveenv(client); + irecv_reboot(client); + + irecv_close(client); + }).detach(); +} + +#endif // WITH_GUI diff --git a/src/wx/DfuPanel.hpp b/src/wx/DfuPanel.hpp new file mode 100644 index 0000000..2aca382 --- /dev/null +++ b/src/wx/DfuPanel.hpp @@ -0,0 +1,47 @@ +#ifndef DFUPANEL_H +#define DFUPANEL_H + +#ifdef WITH_GUI + +#include +#include "DevicePanel.hpp" +#include "../state.hpp" +#include "../sequence.hpp" + +class DfuPanel; +class DfuPanel : public DevicePanel +{ +public: + explicit DfuPanel(MainFrame* frame, wxWindow* parent); + void SetDeviceState(const DeviceState& state) override; + void LoadDevice(const std::string& productType); + void StartSequence(const DfuSequence& seq); + void RunStep(); + void Reboot(); +private: + wxStaticText* m_headerText = nullptr; + wxButton* m_backButton = nullptr; + wxButton* m_startButton = nullptr; + + wxBoxSizer* m_stepsSizer = nullptr; + + std::vector m_stepLabels; + + DfuSequence m_sequence; + size_t m_index = 0; + int m_stepRemaining = 0; + + wxTimer m_timer; + wxTimer m_stagnentTimer; + bool m_isEnteringDfu = false; + + wxPanel* m_devicePanel = nullptr; + wxStaticBitmap* m_deviceImage = nullptr; + std::vector m_buttonLabels; + size_t m_actionExecutedIndex = std::numeric_limits::max(); +}; + + +#endif // WITH_GUI + +#endif // DFUPANEL_H diff --git a/src/wx/ExploitPanel.cpp b/src/wx/ExploitPanel.cpp new file mode 100644 index 0000000..62a5449 --- /dev/null +++ b/src/wx/ExploitPanel.cpp @@ -0,0 +1,72 @@ +#ifdef WITH_GUI + +#include "ExploitPanel.hpp" + +#include + +#include + +#include "AppFrame.hpp" +#include "DevicePanel.hpp" +#include "../state.hpp" +#include "../utils/log.h" + +ExploitPanel::ExploitPanel(MainFrame* frame, wxWindow* parent) + : DevicePanel(frame, parent) +{ + auto* root = new wxBoxSizer(wxVERTICAL); + auto* text = new wxStaticText(this, wxID_ANY, + "Installing jailbreak, this will take a moment. If the device asks for a passcode\nplease enter it. Do not disconnect the device until finished."); + + m_statusText = new wxStaticText(this, wxID_ANY, ""); + + root->Add(text, 0, wxALL, 10); + root->Add(m_statusText, 0, wxALL, 10); + + m_backButton = new wxButton(this, wxID_ANY, "Back"); + m_backButton->Disable(); + m_backButton->Bind(wxEVT_BUTTON, [frame](wxCommandEvent&) + { + frame->ShowMain(); + }); + + auto* bottomRow = new wxBoxSizer(wxHORIZONTAL); + bottomRow->AddStretchSpacer(); + bottomRow->Add(m_backButton, 0, wxALL, 10); + + root->AddStretchSpacer(); + root->Add(bottomRow, 0, wxEXPAND); + + SetSizer(root); +} + +void ExploitPanel::SetDeviceState(const DeviceState& state) +{ + DevicePanel::SetDeviceState(state); + + if (!(this->IsShown())) + return; + + if (state.mode == DeviceMode::Normal) + { + m_statusText->SetLabel("Done."); + m_backButton->Enable(); + } +} + +void ExploitPanel::StartExploit() +{ + m_statusText->SetLabel("Exploiting device..."); + m_backButton->Disable(); + + std::thread([this]() + { + const auto state = GetDeviceState(); + if (!state.connected || state.mode != DeviceMode::DFU) + return; + + LOG("Starting exploit on worker thread..."); + }).detach(); +} + +#endif // WITH_GUI diff --git a/src/wx/ExploitPanel.hpp b/src/wx/ExploitPanel.hpp new file mode 100644 index 0000000..0a9921f --- /dev/null +++ b/src/wx/ExploitPanel.hpp @@ -0,0 +1,24 @@ +#ifndef EXPLOITPANEL_HPP +#define EXPLOITPANEL_HPP + +#ifdef WITH_GUI + +#include +#include "DevicePanel.hpp" +#include "../state.hpp" + +class ExploitPanel; +class ExploitPanel : public DevicePanel +{ +public: + explicit ExploitPanel(MainFrame* frame, wxWindow* parent); + void SetDeviceState(const DeviceState& state) override; + void StartExploit(); +private: + wxButton* m_backButton = nullptr; + wxStaticText* m_statusText = nullptr; +}; + +#endif // WITH_GUI + +#endif // EXPLOITPANEL_HPP diff --git a/src/wx/MainPanel.cpp b/src/wx/MainPanel.cpp new file mode 100644 index 0000000..a25acdf --- /dev/null +++ b/src/wx/MainPanel.cpp @@ -0,0 +1,164 @@ +#ifdef WITH_GUI + +#include "MainPanel.hpp" + +#include +#include +#include +#include +#include + +#include "AppFrame.hpp" +#include "DevicePanel.hpp" +#include "../state.hpp" + +#include "../gen/images/logo.h" + +const char* deviceTextString = "Connect your iPhone, iPod touch, iPad, or AppleTV to begin."; + +MainPanel::MainPanel(MainFrame* frame, wxWindow* parent) + : DevicePanel(frame, parent) +{ + auto* root = new wxBoxSizer(wxVERTICAL); + + wxInitAllImageHandlers(); + + wxMemoryInputStream stream(logo, logo_len); + wxImage img(stream, wxBITMAP_TYPE_PNG); + wxBitmap bmp(img); + + auto* logo = new wxStaticBitmap(this, wxID_ANY, bmp); + + auto* titletext = new wxStaticText(this, wxID_ANY, "Welcome to palera1n!"); + wxFont titlefont = titletext->GetFont(); + titlefont.SetWeight(wxFONTWEIGHT_BOLD); + titletext->SetFont(titlefont); + + m_deviceText = new wxStaticText( + this, + wxID_ANY, + deviceTextString + ); + + auto* left = new wxBoxSizer(wxVERTICAL); + left->Add(titletext, 0, wxTOP | wxLEFT, 10); + left->Add(m_deviceText, 0, wxTOP | wxLEFT, 10); + + auto* row = new wxBoxSizer(wxHORIZONTAL); + row->Add(left, 0, wxALIGN_TOP); + row->AddStretchSpacer(); + row->Add(logo, 0, wxTOP | wxRIGHT, 10); + + root->Add(row, 0, wxEXPAND); + + root->Add(new wxStaticLine(this), 0, wxEXPAND | wxALL, 10); + + auto* credtext = new wxStaticText(this, wxID_ANY, + "Made by: asdfugil, kok3shidoll, claration, mineek, staturnz\n\n" + "Thanks to: itsnebulalol, llsc12, lrdsnow, nikias (libimobiledevice), Checkra1n\n" + "(Siguza, axi0mx, littlelailo et al.), Procursus (Hayden Seay, Cameron Katri,\n" + "Keto et al.)\n\n" + "With 💖 from C (claration)"); + + root->Add(credtext, 0, wxLEFT | wxRIGHT, 10); + + root->Add(new wxStaticLine(this), 0, wxEXPAND | wxALL, 10); + + auto* notetext = new wxStaticText(this, wxID_ANY, + "NOTE: Please ensure you have a backup of your device before applying the\n" + "jailbreak. While data loss is unlikely, we won't be responsible if something goes\n" + "wrong. Use at your own risk."); + + wxFont notefont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); + notefont.SetPointSize(12); + notefont.SetStyle(wxFONTSTYLE_ITALIC); + notetext->SetFont(notefont); + + root->Add(notetext, 0, wxLEFT | wxRIGHT, 10); + + root->AddStretchSpacer(); + + auto* btn = new wxButton(this, wxID_ANY, "Options"); + m_startButton = new wxButton(this, wxID_ANY, "Start"); + m_startButton->Disable(); + + btn->Bind(wxEVT_BUTTON, [frame](wxCommandEvent&) + { + frame->ShowSettings(); + }); + + m_startButton->Bind(wxEVT_BUTTON, [frame](wxCommandEvent&) + { + if (frame->GetDeviceState().mode == DeviceMode::Normal) + { + frame->ShowRecovery(); + } + else if (frame->GetDeviceState().mode == DeviceMode::Recovery) + { + frame->ShowDfu(); + } + }); + + auto* bottomRow = new wxBoxSizer(wxHORIZONTAL); + bottomRow->AddStretchSpacer(); + bottomRow->Add(btn, 0, wxALL, 10); + bottomRow->Add(m_startButton, 0, wxALL, 10); + + root->Add(bottomRow, 0, wxEXPAND); + + SetSizer(root); +} + +void MainPanel::SetDeviceState(const DeviceState& state) +{ + DevicePanel::SetDeviceState(state); + + if (m_deviceText) + { + if (!state.connected) + { + m_deviceText->SetLabel(deviceTextString); + m_startButton->Enable(false); + } + else + { + const std::string versionString = + state.productVersion.empty() ? "Unknown" : state.productVersion; + const std::string productString = + state.productType.empty() ? "Unknown" : state.productType; + const std::string ecidString = state.ecid != 0 ? ("ECID: " + std::to_string(state.ecid)) : "ECID: Unknown"; + + switch (state.mode) + { + case DeviceMode::Normal: + if (state.isSupported) { + m_deviceText->SetLabel("Connected " + productString + " (iOS " + versionString + ") in normal mode.\n" + ecidString); + m_startButton->Enable(); + } else { + m_deviceText->SetLabel("Sorry, " + productString + " (iOS " + versionString + ") is not supported.\n" + ecidString); + m_startButton->Enable(false); + } + break; + case DeviceMode::Recovery: + if (state.isSupported) { + m_deviceText->SetLabel("Connected " + productString + " in recovery mode.\n" + ecidString); + m_startButton->Enable(); + } else { + m_deviceText->SetLabel("Sorry, " + productString + " is not supported.\n" + ecidString); + m_startButton->Enable(false); + } + break; + case DeviceMode::DFU: + m_deviceText->SetLabel("Sorry, DFU mode is not supported."); + m_startButton->Enable(false); + break; + case DeviceMode::None: + m_deviceText->SetLabel(deviceTextString); + m_startButton->Enable(false); + break; + } + } + } +} + +#endif diff --git a/src/wx/MainPanel.hpp b/src/wx/MainPanel.hpp new file mode 100644 index 0000000..dd958ae --- /dev/null +++ b/src/wx/MainPanel.hpp @@ -0,0 +1,23 @@ +#ifndef MAINPANEL_H +#define MAINPANEL_H + +#ifdef WITH_GUI + +#include +#include "DevicePanel.hpp" +#include "../state.hpp" + +class MainPanel; +class MainPanel : public DevicePanel +{ +public: + explicit MainPanel(MainFrame* frame, wxWindow* parent); + void SetDeviceState(const DeviceState& state) override; +private: + wxStaticText* m_deviceText = nullptr; + wxButton* m_startButton = nullptr; +}; + +#endif // WITH_GUI + +#endif // MAINPANEL_H diff --git a/src/wx/RecoveryPanel.cpp b/src/wx/RecoveryPanel.cpp new file mode 100644 index 0000000..703eb4a --- /dev/null +++ b/src/wx/RecoveryPanel.cpp @@ -0,0 +1,130 @@ +#ifdef WITH_GUI + +#include "RecoveryPanel.hpp" + +#include + +#include "AppFrame.hpp" +#include "DevicePanel.hpp" +#include "../state.hpp" + +#include +#include +#include + +RecoveryPanel::RecoveryPanel(MainFrame* frame, wxWindow* parent) + : DevicePanel(frame, parent) +{ + auto* root = new wxBoxSizer(wxVERTICAL); + + root->Add(new wxStaticText(this, wxID_ANY, + "The device needs to be put into DFU mode to apply the jailbreak. This is a\n" + "manual process and we will guide you through it.\n\n" + "In order to prevent filesystem corruption through hard reset, the device will\n" + "be put into recovery mode first. Click next when you are ready."), 0, wxALL, 10); + + m_statusText = new wxStaticText(this, wxID_ANY, ""); + root->Add(m_statusText, 0, wxALL, 10); + + m_backButton = new wxButton(this, wxID_ANY, "Back"); + m_nextButton = new wxButton(this, wxID_ANY, "Next"); + + m_backButton->Bind(wxEVT_BUTTON, [frame](wxCommandEvent&) + { + frame->ShowMain(); + }); + + m_nextButton->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) + { + m_statusText->SetLabel("Entering recovery mode..."); + m_backButton->Disable(); + m_nextButton->Disable(); + EnterRecoveryMode(); + }); + + m_timer.Bind(wxEVT_TIMER, [this](wxTimerEvent&) + { + m_backButton->Enable(); + m_nextButton->Enable(); + m_isEnteringRecovery = false; + + GetMainFrame()->ShowDfu(); + m_statusText->SetLabel(""); + }); + + auto* bottomRow = new wxBoxSizer(wxHORIZONTAL); + bottomRow->AddStretchSpacer(); + bottomRow->Add(m_backButton, 0, wxALL, 10); + bottomRow->Add(m_nextButton, 0, wxALL, 10); + + root->AddStretchSpacer(); + root->Add(bottomRow, 0, wxEXPAND); + + SetSizer(root); +} + +void RecoveryPanel::SetDeviceState(const DeviceState& state) +{ + DevicePanel::SetDeviceState(state); + + if (!(this->IsShown())) + return; + + if (m_isEnteringRecovery && state.mode == DeviceMode::Recovery) + { + m_statusText->SetLabel("Device is now in recovery mode."); + m_timer.StartOnce(3000); + } + + if (m_isEnteringRecovery && state.mode == DeviceMode::Normal) + { + m_isEnteringRecovery = false; + m_statusText->SetLabel("Hmm... It seems like the device didn't enter recovery mode. Please try again."); + m_backButton->Enable(); + m_nextButton->Enable(); + } + + if (!m_isEnteringRecovery && state.mode == DeviceMode::None) + { + m_backButton->Enable(); + m_nextButton->Enable(); + GetMainFrame()->ShowMain(); + } +} + +void RecoveryPanel::EnterRecoveryMode() +{ + const auto& state = GetDeviceState(); + + if (!state.connected) + return; + + idevice_t device = nullptr; + lockdownd_client_t client = nullptr; + + if (idevice_new(&device, state.udid.c_str()) != IDEVICE_E_SUCCESS) + return; + + if (lockdownd_client_new_with_handshake( + device, + &client, + "palera1n") != LOCKDOWN_E_SUCCESS) + { + idevice_free(device); + return; + } + + m_isEnteringRecovery = true; + + lockdownd_enter_recovery(client); + + lockdownd_client_free(client); + idevice_free(device); +} + +void RecoveryPanel::SetStatusText(const wxString& text) +{ + m_statusText->SetLabel(text); +} + +#endif diff --git a/src/wx/RecoveryPanel.hpp b/src/wx/RecoveryPanel.hpp new file mode 100644 index 0000000..def9019 --- /dev/null +++ b/src/wx/RecoveryPanel.hpp @@ -0,0 +1,28 @@ +#ifndef RECOVERYPANEL_H +#define RECOVERYPANEL_H + +#ifdef WITH_GUI + +#include +#include "DevicePanel.hpp" + +class RecoveryPanel; +class RecoveryPanel : public DevicePanel +{ +public: + explicit RecoveryPanel(MainFrame* frame, wxWindow* parent); + void SetDeviceState(const DeviceState& state) override; + void SetStatusText(const wxString& text); + void EnterRecoveryMode(); +private: + wxButton* m_backButton = nullptr; + wxButton* m_nextButton = nullptr; + wxStaticText* m_statusText = nullptr; + wxTimer m_timer; + bool m_isEnteringRecovery = false; +}; + + +#endif // WITH_GUI + +#endif // RECOVERYPANEL_H diff --git a/src/wx/SettingsPanel.cpp b/src/wx/SettingsPanel.cpp new file mode 100644 index 0000000..c4f7a9b --- /dev/null +++ b/src/wx/SettingsPanel.cpp @@ -0,0 +1,84 @@ +#ifdef WITH_GUI + +#include "SettingsPanel.hpp" + +#include + +#include "AppFrame.hpp" +#include "DevicePanel.hpp" +#include "../utils/constants.h" +#include "../utils/paleinfo.h" + +SettingsPanel::SettingsPanel(MainFrame* frame, wxWindow* parent) + : DevicePanel(frame, parent) +{ + auto* root = new wxBoxSizer(wxVERTICAL); + + root->Add(new wxStaticText(this, wxID_ANY, + "You may set the following options. If you don't know what they mean you'll\n" + "probably have no reason to set them."), 0, wxALL, 10); + + auto* option_safemode = new wxCheckBox(this, wxID_ANY, "Safe Mode"); + auto* option_verbose = new wxCheckBox(this, wxID_ANY, "Verbose Boot"); + auto* option_revert = new wxCheckBox(this, wxID_ANY, "Restore System"); + auto* option_dark_blockchain = new wxCheckBox(this, wxID_ANY, "Dark Blockchain"); + + option_safemode->SetValue(palerain_flags & palerain_option_safemode); + option_verbose->SetValue(palerain_flags & palerain_option_verbose_boot); + option_revert->SetValue(palerain_flags & palerain_option_force_revert); + option_dark_blockchain->SetValue(true); + + option_safemode->Bind(wxEVT_CHECKBOX, [&](wxCommandEvent& e) + { + if (e.IsChecked()) + palerain_flags |= palerain_option_safemode; + else + palerain_flags &= ~palerain_option_safemode; + }); + + option_verbose->Bind(wxEVT_CHECKBOX, [&](wxCommandEvent& e) + { + if (e.IsChecked()) + palerain_flags |= palerain_option_verbose_boot; + else + palerain_flags &= ~palerain_option_verbose_boot; + }); + + option_revert->Bind(wxEVT_CHECKBOX, [&](wxCommandEvent& e) + { + if (e.IsChecked()) + palerain_flags |= palerain_option_force_revert; + else + palerain_flags &= ~palerain_option_force_revert; + }); + + root->Add(option_safemode, 0, wxLEFT | wxRIGHT, 10); + root->Add(option_verbose, 0, wxLEFT | wxRIGHT | wxTOP, 10); + + root->Add(new wxStaticText(this, wxID_ANY, "Boot Arguments:"), 0, wxALL, 10); + + auto* bootArgs = new wxTextCtrl(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize); + root->Add(bootArgs, 0, wxLEFT | wxRIGHT | wxEXPAND, 30); + + root->Add(option_revert, 0, wxLEFT | wxRIGHT | wxTOP, 10); + root->Add(option_dark_blockchain, 0, wxLEFT | wxRIGHT | wxTOP, 10); + + root->AddStretchSpacer(); + + auto* back = new wxButton(this, wxID_ANY, "Back"); + + back->Bind(wxEVT_BUTTON, [frame](wxCommandEvent&) + { + frame->ShowMain(); + }); + + auto* bottomRow = new wxBoxSizer(wxHORIZONTAL); + bottomRow->AddStretchSpacer(); + bottomRow->Add(back, 0, wxALL, 10); + + root->Add(bottomRow, 0, wxEXPAND); + + SetSizer(root); +} + +#endif // WITH_GUI diff --git a/src/wx/SettingsPanel.hpp b/src/wx/SettingsPanel.hpp new file mode 100644 index 0000000..c7c5b6c --- /dev/null +++ b/src/wx/SettingsPanel.hpp @@ -0,0 +1,18 @@ +#ifndef SETTINGSPANEL_H +#define SETTINGSPANEL_H + +#ifdef WITH_GUI + +#include +#include "DevicePanel.hpp" + +class SettingsPanel; +class SettingsPanel : public DevicePanel +{ +public: + explicit SettingsPanel(MainFrame* frame, wxWindow* parent); +}; + +#endif // WITH_GUI + +#endif // SETTINGSPANEL_H