├── .gitignore ├── LICENSE ├── README.md └── main.py /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/** 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2024-2024 Cryptiiiic 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SEPROM Panic Decrypt 2 | 3 | ## Dependencies: 4 | `pip3 install pycryptodome` 5 | 6 | ## Usage: 7 | `python3 main.py ` 8 | 9 | ## Example: 10 | ```bash 11 | panic(cpu 0 caller 0xfffffff0219d867c): "SEP ROM boot panic. 0xB9FD8EA50D398BCBA905C2EC0647846B4F1C4EEAB64B4BE947098F1A0AF1EB23B26493A7A78634E2A05034A5377296A383CBF3165A44861C" @SEPROMPanicBuffer.cpp:71 12 | ``` 13 | 14 | ```bash 15 | ❯ python3 ./SEPROMPanicDecrypt/main.py s8000 0xB9FD8EA50D398BCBA905C2EC0647846B4F1C4EEAB64B4BE947098F1A0AF1EB23B26493A7A78634E2A05034A5377296A383CBF3165A44861C 16 | 0x000000FF 17 | 0x000000A5 18 | 0x100056C3 19 | 0x10007723 20 | 0x100056C3 21 | 0x10007723 22 | 0x10005795 23 | 0x10004D0B 24 | 0x00000000 25 | 0x00000000 26 | 0x00000000 27 | 0x00000000 28 | ❯ 29 | ``` 30 | 31 | ## Supported SoC's: 32 | * a8 33 | * a8x 34 | * a9(Samsung) 35 | * a9x 36 | * a9(TSMC) 37 | * S4/S5 Watch 38 | * S1p/S2 Watch/T1 Chip 39 | * a10 40 | * a10x 41 | * T2 Chip 42 | * a11 43 | * a12 44 | * a12z/x 45 | * a13 46 | * a14 47 | * M1 48 | * a15 49 | * a16(A0) 50 | * a16(B1) 51 | * M2 52 | * a17 53 | * M3 Max(Binning 1) 54 | * M3 Ultra 55 | * M3 Max(Binning 2) 56 | 57 | ## Unsupported SoC's: 58 | * S9/S10 Watch 59 | * M3 60 | * M4 61 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from Crypto.Cipher import AES 4 | from binascii import hexlify, unhexlify 5 | import sys 6 | 7 | 8 | class SEPROMPanicDecrypt: 9 | _soc = "" 10 | _panic = b"" 11 | _keys = [] 12 | _is_32bit = False 13 | _is_old_style_panic = False 14 | 15 | def __init__(self, soc, panic): 16 | 17 | self._soc = soc.lower() 18 | soc_int = int(self._soc[1:], 16) if "-" not in self._soc else int(self._soc[1:5], 16) 19 | if soc_int < 0x8015: 20 | self._is_32bit = True 21 | if soc_int == 0x8006: 22 | self._is_32bit = False 23 | if soc_int < 0x8000: 24 | self._is_old_style_panic = True 25 | self._panic = bytes.fromhex(panic) 26 | self._keys = { 27 | "t7000": bytes.fromhex("1a3f5e7c676ae321cc3d501212c36a21b453f6788dfe32f154a210fa92b36e21"), # a8 28 | "t7001": bytes.fromhex("1a3f5e7c676ae321cc3d501212c36a21b453f6788dfe32f154a210fa92b36e21"), # a8x 29 | "t8002": bytes.fromhex("bc8ec9cd60a3e2fb78973bba741023ec6d65179107145dd392a8dd8a485fc45c"), # S1P/S2 Watch 30 | "t8004": bytes.fromhex("3e652b6cf4dd293105068fb20773fde4eca1a7056dc50c139076b54bd3e51fd9"), # S3 Watch 31 | "s8000": bytes.fromhex("ac884aef3f99476caf8f1254158bbf3dd3e48446c8e906e1c224a8c6318e4589"), # a9(Samsung) 32 | "s8001": bytes.fromhex("ac884aef3f99476caf8f1254158bbf3dd3e48446c8e906e1c224a8c6318e4589"), # a9x 33 | "s8003": bytes.fromhex("ac884aef3f99476caf8f1254158bbf3dd3e48446c8e906e1c224a8c6318e4589"), # a9(TSMC) 34 | "t8006": bytes.fromhex("99f095abe48158ee3a0c72035f06ac3fdd1a5ff66365795ecbbe2e24d35c5315"), # S4/S5 Watch 35 | "t8010": bytes.fromhex("ca80933cb9368b168f5a0699f9eea44079fe9e89f0df5db12dc2fe67cfd8350c"), # a10 36 | "t8011": bytes.fromhex("6f94ca7e9e97e9cdb68099ccd8943937758011a853d2f9be5bedb317357be675"), # a10x 37 | "t8012": bytes.fromhex("8246a778fa535cfe21f754c5298ed043302d2792425597b7cf2c35545a72fe48"), # T2 Chip 38 | "t8015": bytes.fromhex("e5bbbebe5295a205885e6e47362dbb6b25aa66349f0e2b329683a384c724280f"), # a11 39 | "t8020": bytes.fromhex("2e2e535499d89b8f997ebc8dc1e1122b0aa97f9401be4275c10934002d6a779f"), # a12 40 | "t8027": bytes.fromhex("f0ee42ef0504e17258c2379113effe6a8ef3e11a8bec2156c2e88203b6665023"), # a12z/a12x/DTK 41 | "t8030": bytes.fromhex("8d12eb734a8550ad37b68b260ef74211217bddc0a5b09fae09bd26b7b1cfcf68"), # a13 42 | "t8101": bytes.fromhex("79d0ae2369a6dc8866deb5aa19fc696e62eb0d6940677bec25f144dcada93be1"), # a14 43 | "t8103": bytes.fromhex("d3a3e9b2920d8da5767a5a31ebaa1022b2ba25d8dd7df1afea4735b84f46e7fc"), # M1 44 | "t8301": bytes.fromhex("22566afd4748956a7708996b888e2da6c0fe4797da958474cafce1e87dbf31cd"), # S6/S7/S8 Watch 45 | "t8110": bytes.fromhex("ab7be133e8a3a2f7d16bf9a8e6d23c66b86271e0572d47f623e2de4485c674c3"), # a15 46 | "t8112": bytes.fromhex("500e80afe77ededb439cc278dfb018b9a7b14606743baa69d0af9e72b6ac802a"), # M2 47 | "t8120": bytes.fromhex("52013B5E9D455342C0F18A880AE058DCD773DD9DCCD37B999B95F7699429F161"), # a16 48 | "t8120-a0": bytes.fromhex("e8328be4ce028abb239c2ba87297a0a645bddabcce10a3ee3c9b1e3cb92c4bf6"), # a16 49 | "t8120-b1": bytes.fromhex("52013B5E9D455342C0F18A880AE058DCD773DD9DCCD37B999B95F7699429F161"), # a16 50 | # "t8310": bytes.fromhex("?"), # S9/S10 Watch 51 | # "t8122": bytes.fromhex("?"), # M3 52 | "t6031": bytes.fromhex("31e8364be1d086ddb8cd0b23462faf0f21ac7f0f67f30087153631b176b22013"), # M3 Max(Binning 1) 53 | "t6032": bytes.fromhex("90cc983c7fde2b5a94f0b57b09c3041900a24dcf5627b84b6220a90d21104f27"), # M3 Ultra 54 | "t6034": bytes.fromhex("a164a5123d2a9ca2fbfbdd312acfcc10f418a869faddd24ae56c6afda95f5145"), # M3 Max(Binning 2) 55 | "t8130": bytes.fromhex("80176709106178272ee78e1be5717555e9ecbf467541fd6f71990ca04372c4bf"), # a17 56 | # "t8140": bytes.fromhex("?"), # a18 57 | # "t8132": bytes.fromhex("?"), # M4 58 | } 59 | if self._soc not in self._keys: 60 | print(f"\nUnsupported SoC: ({self._soc})!") 61 | exit(-4) 62 | self._key = self._keys[self._soc] 63 | self._iv = bytes.fromhex("".zfill(32)) 64 | self._trng_key = self.trng_key() 65 | 66 | def trng_key(self): 67 | trng_key = self._panic[:8] 68 | self._panic = self._panic[8:] if not self._is_old_style_panic else self._panic 69 | return trng_key 70 | 71 | def create_encrypt_data(self, index): 72 | return index.to_bytes(8, 'little') + self._trng_key 73 | 74 | def decrypt_old(self): 75 | aes = AES.new(self._key, AES.MODE_CBC, self._iv) 76 | decrypted_data = aes.decrypt(self._panic) 77 | for i in range(0, len(self._panic), 4): 78 | result = int.from_bytes(decrypted_data[i:(i + 4)], byteorder="little") 79 | print(f"0x{result:08X}") 80 | 81 | 82 | def decrypt(self): 83 | 84 | if self._is_old_style_panic: 85 | self.decrypt_old() 86 | return 87 | 88 | loop_len = (int((len(self._panic) / 8) / 2)) 89 | for i in range(0, loop_len, 1): 90 | data = self.create_encrypt_data(i) 91 | aes = AES.new(self._key, AES.MODE_CBC, self._iv) 92 | encrypted_data = aes.encrypt(data) 93 | 94 | xor = self._panic[(i * 16):((i * 16) + 16)] 95 | 96 | xor_key1 = int.from_bytes(encrypted_data[:8], byteorder="big") 97 | xor_key2 = int.from_bytes(encrypted_data[8:], byteorder="big") 98 | 99 | xor_int1 = int.from_bytes(xor[:8], byteorder="big") 100 | xor_int2 = int.from_bytes(xor[8:16], byteorder="big") 101 | 102 | result1 = xor_key1 ^ xor_int1 103 | result2 = xor_key2 ^ xor_int2 104 | 105 | result1 = result1.to_bytes(8, "big") 106 | result2 = result2.to_bytes(8, "big") 107 | 108 | if self._is_32bit: 109 | tmp1 = result1 110 | tmp2 = result2 111 | result1 = tmp1[:4] 112 | result2 = tmp1[4:] 113 | result3 = tmp2[:4] 114 | result4 = tmp2[4:] 115 | 116 | result1 = int.from_bytes(result1, "little") 117 | result2 = int.from_bytes(result2, "little") 118 | result3 = int.from_bytes(result3, "little") 119 | result4 = int.from_bytes(result4, "little") 120 | print(f"0x{result1:08X}") 121 | print(f"0x{result2:08X}") 122 | print(f"0x{result3:08X}") 123 | print(f"0x{result4:08X}") 124 | else: 125 | result1 = int.from_bytes(result1, "little") 126 | result2 = int.from_bytes(result2, "little") 127 | print(f"0x{result1:016X}") 128 | print(f"0x{result2:016X}") 129 | del aes 130 | 131 | 132 | def main(): 133 | if len(sys.argv) < 3: 134 | argv0 = sys.argv[0] 135 | print(f"Usage: {argv0} ") 136 | exit(-1) 137 | if len(sys.argv[1]) < 5 or (len(sys.argv[1]) >= 7 and "-" not in sys.argv[1]): 138 | argv1 = sys.argv[1] 139 | print(f"\nInvalid SoC: ({argv1})!") 140 | exit(-2) 141 | if len(sys.argv[2]) > 2 and sys.argv[2][:2] == "0x": 142 | sys.argv[2] = sys.argv[2][2:] 143 | if len(sys.argv[2]) < 64 or len(sys.argv[2]) % 4 != 0: 144 | argv2 = sys.argv[2] 145 | print(f"\nInvalid SEPROM Panic Bytes: ({argv2})!") 146 | exit(-3) 147 | s = SEPROMPanicDecrypt(str(sys.argv[1]), str(sys.argv[2])) 148 | s.decrypt() 149 | return 150 | 151 | 152 | if __name__ == '__main__': 153 | main() 154 | --------------------------------------------------------------------------------