From 6598540ff98472b564cec198e6cdd171101302f7 Mon Sep 17 00:00:00 2001 From: nodemixaholic Date: Tue, 30 Jan 2024 17:31:28 +0000 Subject: [PATCH] Upload files to '' --- albert.py | 33 ++++++++++------- apns.py | 2 +- demo.py | 41 +++++++++++---------- imessage.py | 93 ++++++++++++++++++++++++++++-------------------- requirements.txt | 3 +- 5 files changed, 98 insertions(+), 74 deletions(-) diff --git a/albert.py b/albert.py index ca447ed..f3fdb17 100644 --- a/albert.py +++ b/albert.py @@ -1,7 +1,8 @@ import plistlib import re import uuid -from base64 import b64decode, b64encode +from base64 import b64decode +from pathlib import Path import requests from cryptography import x509 @@ -22,6 +23,11 @@ FAIRPLAY_CERT_CHAIN = b64decode( "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" ) +with open(Path(__file__).parent / "emulated/data.plist", "rb") as f: + DATA_PLIST = plistlib.load(f) + +SERIAL_NUMBER = DATA_PLIST["iokit"]["IOPlatformSerialNumber"] + def _generate_csr(private_key: rsa.RSAPrivateKey) -> str: csr = ( @@ -43,28 +49,31 @@ def _generate_csr(private_key: rsa.RSAPrivateKey) -> str: return csr.public_bytes(serialization.Encoding.PEM).decode("utf-8") -# Generates an APNs push certificate by talking to Albert -# Returns [private key PEM, certificate PEM] def generate_push_cert() -> tuple[str, str]: + """ + Generates an APNs push certificate by talking to Albert. + + Returns [private key PEM, certificate PEM] + """ private_key = rsa.generate_private_key( - public_exponent=65537, key_size=2048, backend=default_backend() + public_exponent=65537, key_size=1024, backend=default_backend() ) csr = _generate_csr(private_key) activation_info = { "ActivationRandomness": str(uuid.uuid4()), "ActivationState": "Unactivated", - "BuildVersion": "10.6.4", + "BuildVersion": "22F82", "DeviceCertRequest": csr.encode("utf-8"), - "DeviceClass": "Windows", - "ProductType": "windows1,1", - "ProductVersion": "10.6.4", - "SerialNumber": "WindowSerial", + "DeviceClass": "MacOS", + "ProductType": "MacBookPro18,3", + "ProductVersion": "13.4.1", + "SerialNumber": SERIAL_NUMBER, "UniqueDeviceID": str(uuid.uuid4()), } logger.debug(f"Generated activation info (with UUID: {activation_info['UniqueDeviceID']})") - + activation_info = plistlib.dumps(activation_info) # Load the private key @@ -83,7 +92,7 @@ def generate_push_cert() -> tuple[str, str]: } resp = requests.post( - "https://albert.apple.com/WebObjects/ALUnbrick.woa/wa/deviceActivation?device=Windows", + "https://albert.apple.com/deviceservices/deviceActivation?device=MacOS", data={"activation-info": plistlib.dumps(body)}, verify=False, ) @@ -110,4 +119,4 @@ def generate_push_cert() -> tuple[str, str]: if __name__ == "__main__": private_key, cert = generate_push_cert() print(private_key) - print(cert) + print(cert) \ No newline at end of file diff --git a/apns.py b/apns.py index 755abf6..a22d468 100644 --- a/apns.py +++ b/apns.py @@ -320,4 +320,4 @@ def _get_field(fields: list[tuple[int, bytes]], id: int) -> bytes: for field_id, value in fields: if field_id == id: return value - return None + return None \ No newline at end of file diff --git a/demo.py b/demo.py index ca48ad3..9767018 100644 --- a/demo.py +++ b/demo.py @@ -178,12 +178,22 @@ while True: if msg == 'help' or msg == 'h': print('help (h): show this message') print('quit (q): quit') - #print('send (s) [recipient] [message]: send a message') - print('filter (f) [recipient]: set the current chat') + print('send (s) [recipient] [message]: send a message') + #print('filter (f) [recipient]: set the current chat') print('effect (e): adds an iMessage effect to the next sent message') print('note: recipient must start with tel: or mailto: and include the country code') print('handle : set the current handle (for sending messages)') print('\\: escape commands (will be removed from message)') + elif msg.startswith('send') or msg.startswith('s'): + msg = msg.split(' ') + if len(msg) < 3: + print('send [recipient] [message]') + else: + im.send(imessage.iMessage( + text=' '.join(msg[2:]), + participants=[msg[1], user.handles[0]], + #sender=user.handles[0] + )) elif msg == 'quit' or msg == 'q': break elif msg == 'effect' or msg == 'e' or msg.startswith("effect ") or msg.startswith("e "): @@ -193,14 +203,14 @@ while True: else: print(f"next message will be sent with [{msg[1]}]") current_effect = msg[1] - elif msg == 'filter' or msg == 'f' or msg.startswith('filter ') or msg.startswith('f '): + #elif msg == 'filter' or msg == 'f' or msg.startswith('filter ') or msg.startswith('f '): # Set the curernt chat - msg = msg.split(' ') - if len(msg) < 2 or msg[1] == '': - print('filter [recipients]') - else: - print(f'Filtering to {[fixup_handle(h) for h in msg[1:]]}') - current_participants = [fixup_handle(h) for h in msg[1:]] + #msg = msg.split(' ') + #if len(msg) < 2 or msg[1] == '': + #print('filter [recipients]') + #else: + #print(f'Filtering to {[fixup_handle(h) for h in msg[1:]]}') + #current_participants = [fixup_handle(h) for h in msg[1:]] elif msg == 'handle' or msg.startswith('handle '): msg = msg.split(' ') if len(msg) < 2 or msg[1] == '': @@ -234,15 +244,4 @@ while True: print('No chat selected, use help for help') time.sleep(0.1) - - # elif msg.startswith('send') or msg.startswith('s'): - # msg = msg.split(' ') - # if len(msg) < 3: - # print('send [recipient] [message]') - # else: - # im.send(imessage.iMessage( - # text=' '.join(msg[2:]), - # participants=[msg[1], user.handles[0]], - # #sender=user.handles[0] - # )) - + diff --git a/imessage.py b/imessage.py index fefabb2..51244d2 100644 --- a/imessage.py +++ b/imessage.py @@ -28,6 +28,7 @@ logger = logging.getLogger("imessage") NORMAL_NONCE = b"\x00" * 15 + b"\x01" # This is always used as the AES nonce +bundled_payloads = [] class BalloonBody: """Represents the special parts of message extensions etc.""" @@ -257,20 +258,34 @@ class iMessageUser: Returns None if no conforming notification is found """ - def check_response(x): - if x[0] != 0x0A: - return False - if apns._get_field(x[1], 2) != sha1("com.apple.madrid".encode()).digest(): - return False - resp_body = apns._get_field(x[1], 3) - if resp_body is None: - # logger.debug("Rejecting madrid message with no body") - return False - resp_body = plistlib.loads(resp_body) - if "P" not in resp_body: - # logger.debug(f"Rejecting madrid message with no payload : {resp_body}") - return False - return True + #def check_response(x): + #if x[0] != 0x0A: + #return False + #if apns._get_field(x[1], 2) != sha1("com.apple.madrid".encode()).digest(): + #return False + #resp_body = apns._get_field(x[1], 3) + #if resp_body is None: + # logger.debug("Rejecting madrid message with no body") + #return False + #resp_body = plistlib.loads(resp_body) + #if "P" not in resp_body: + # logger.debug(f"Rejecting madrid message with no payload : {resp_body}") + #return False + #return True + + def check_response(x): + if x[0] != 0x0A: + return False + if apns._get_field(x[1], 2) != sha1("com.apple.madrid".encode()).digest(): + return False + resp_body = apns._get_field(x[1], 3) + if resp_body is None: + return False + resp_body = plistlib.loads(resp_body) + if "c" not in resp_body or resp_body["c"] != 255: + return False + return True + payload = self.connection.incoming_queue.pop_find(check_response) if payload is None: @@ -494,7 +509,6 @@ class iMessageUser: raw = message.to_raw() import base64 - bundled_payloads = [] for participant in message.participants: participant = participant.lower() for push_token in self.USER_CACHE[participant]: @@ -530,6 +544,7 @@ class iMessageUser: "sP": message.sender, } + body = plistlib.dumps(body, fmt=plistlib.FMT_BINARY) self.connection.send_message("com.apple.madrid", body, msg_id) @@ -537,29 +552,29 @@ class iMessageUser: # This code can check to make sure we got a success response, but waiting for the response is annoying, # so for now we just YOLO it and assume it worked - # def check_response(x): - # if x[0] != 0x0A: - # return False - # if apns._get_field(x[1], 2) != sha1("com.apple.madrid".encode()).digest(): - # return False - # resp_body = apns._get_field(x[1], 3) - # if resp_body is None: - # return False - # resp_body = plistlib.loads(resp_body) - # if "c" not in resp_body or resp_body["c"] != 255: - # return False - # return True - + #def check_response(x): + #if x[0] != 0x0A: + #return False + #if apns._get_field(x[1], 2) != sha1("com.apple.madrid".encode()).digest(): + #return False + #resp_body = apns._get_field(x[1], 3) + #if resp_body is None: + #return False + #resp_body = plistlib.loads(resp_body) + #if "c" not in resp_body or resp_body["c"] != 255: + #return False + #return True - # num_recv = 0 - # while True: - # if num_recv == len(bundled_payloads): - # break - # payload = self.connection.incoming_queue.wait_pop_find(check_response) - # if payload is None: - # continue +num_recv = 0 + +while True: + if num_recv == len(bundled_payloads): + break + payload = self.connection.incoming_queue.wait_pop_find(check_response) + if payload is None: + continue - # resp_body = apns._get_field(payload[1], 3) - # resp_body = plistlib.loads(resp_body) - # logger.error(resp_body) - # num_recv += 1 + resp_body = apns._get_field(payload[1], 3) + resp_body = plistlib.loads(resp_body) + logger.error(resp_body) + num_recv += 1 diff --git a/requirements.txt b/requirements.txt index 3d7c2f4..27bc62e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,4 +6,5 @@ srp pbkdf2 unicorn rich -prompt_toolkit \ No newline at end of file +prompt_toolkit +trio