Quellcode durchsuchen

added electra binaries source for jailbreakd 1131, these files havent been pulled for a bit from their repo so im likely out of sync. they seem to work okay right now

Kevin Bradley vor 8 Jahren
Ursprung
Commit
0bc2c3cf47
100 geänderte Dateien mit 7268 neuen und 0 gelöschten Zeilen
  1. 2 0
      Meridian/meridianTV/electra_extras/basebinaries/.gitignore
  2. 28 0
      Meridian/meridianTV/electra_extras/basebinaries/Makefile
  3. 29 0
      Meridian/meridianTV/electra_extras/basebinaries/amfid_payload/Makefile
  4. 220 0
      Meridian/meridianTV/electra_extras/basebinaries/amfid_payload/amfid_payload.m
  5. 117 0
      Meridian/meridianTV/electra_extras/basebinaries/amfid_payload/cs_blobs.h
  6. 1 0
      Meridian/meridianTV/electra_extras/basebinaries/amfid_payload/fishhook.c
  7. 1 0
      Meridian/meridianTV/electra_extras/basebinaries/amfid_payload/fishhook.h
  8. 3 0
      Meridian/meridianTV/electra_extras/basebinaries/apple_include/.gitignore
  9. 18 0
      Meridian/meridianTV/electra_extras/basebinaries/createSnapshot/Ent.plist
  10. 28 0
      Meridian/meridianTV/electra_extras/basebinaries/createSnapshot/Makefile
  11. 28 0
      Meridian/meridianTV/electra_extras/basebinaries/createSnapshot/Makefile--
  12. 28 0
      Meridian/meridianTV/electra_extras/basebinaries/createSnapshot/Makefile----
  13. 37 0
      Meridian/meridianTV/electra_extras/basebinaries/createSnapshot/main.c
  14. 210 0
      Meridian/meridianTV/electra_extras/basebinaries/fishhook/fishhook.c
  15. 76 0
      Meridian/meridianTV/electra_extras/basebinaries/fishhook/fishhook.h
  16. 8 0
      Meridian/meridianTV/electra_extras/basebinaries/helloworld/Ent.plist
  17. 26 0
      Meridian/meridianTV/electra_extras/basebinaries/helloworld/Makefile
  18. 8 0
      Meridian/meridianTV/electra_extras/basebinaries/helloworld/main.c
  19. 14 0
      Meridian/meridianTV/electra_extras/basebinaries/inject_criticald/Ent.plist
  20. 29 0
      Meridian/meridianTV/electra_extras/basebinaries/inject_criticald/Makefile
  21. 539 0
      Meridian/meridianTV/electra_extras/basebinaries/inject_criticald/inject_criticald.m
  22. 16 0
      Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/Ent.plist
  23. 34 0
      Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/Makefile
  24. 81 0
      Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/kern_utils.h
  25. 362 0
      Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/kern_utils.m
  26. 121 0
      Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/kexecute.c
  27. 6 0
      Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/kexecute.h
  28. 123 0
      Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/kmem.c
  29. 16 0
      Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/kmem.h
  30. 403 0
      Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/launch.h
  31. 226 0
      Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/mach/jailbreak_daemonServer.c
  32. 198 0
      Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/mach/jailbreak_daemonServer.h
  33. 249 0
      Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/mach/jailbreak_daemonUser.c
  34. 183 0
      Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/mach/jailbreak_daemonUser.h
  35. 12 0
      Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/mach/mig.defs
  36. 216 0
      Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/main.m
  37. 42 0
      Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/offsetof.c
  38. 41 0
      Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/offsetof.h
  39. 168 0
      Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/osobject.c
  40. 24 0
      Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/osobject.h
  41. 831 0
      Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/patchfinder64.c
  42. 27 0
      Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/patchfinder64.h
  43. 254 0
      Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/sandbox.c
  44. 6 0
      Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/sandbox.h
  45. 8 0
      Meridian/meridianTV/electra_extras/basebinaries/jailbreakd_client/Ent.plist
  46. 27 0
      Meridian/meridianTV/electra_extras/basebinaries/jailbreakd_client/Makefile
  47. 43 0
      Meridian/meridianTV/electra_extras/basebinaries/jailbreakd_client/jailbreakd_client.m
  48. 1 0
      Meridian/meridianTV/electra_extras/basebinaries/jailbreakd_client/libjailbreak_mig.h
  49. 1 0
      Meridian/meridianTV/electra_extras/basebinaries/jailbreakd_client/libjailbreak_mig.m
  50. 1 0
      Meridian/meridianTV/electra_extras/basebinaries/jailbreakd_client/mach
  51. 29 0
      Meridian/meridianTV/electra_extras/basebinaries/libjailbreak_mig/Makefile
  52. 29 0
      Meridian/meridianTV/electra_extras/basebinaries/libjailbreak_mig/Makefile--
  53. 29 0
      Meridian/meridianTV/electra_extras/basebinaries/libjailbreak_mig/Makefile----
  54. 36 0
      Meridian/meridianTV/electra_extras/basebinaries/libjailbreak_mig/libjailbreak_mig.h
  55. 75 0
      Meridian/meridianTV/electra_extras/basebinaries/libjailbreak_mig/libjailbreak_mig.m
  56. 1 0
      Meridian/meridianTV/electra_extras/basebinaries/libjailbreak_mig/mach
  57. 29 0
      Meridian/meridianTV/electra_extras/basebinaries/pspawn_payload/Makefile
  58. 1 0
      Meridian/meridianTV/electra_extras/basebinaries/pspawn_payload/apple_include
  59. 1 0
      Meridian/meridianTV/electra_extras/basebinaries/pspawn_payload/fishhook.c
  60. 1 0
      Meridian/meridianTV/electra_extras/basebinaries/pspawn_payload/fishhook.h
  61. 1 0
      Meridian/meridianTV/electra_extras/basebinaries/pspawn_payload/mach
  62. 298 0
      Meridian/meridianTV/electra_extras/basebinaries/pspawn_payload/pspawn_payload.m
  63. 8 0
      Meridian/meridianTV/electra_extras/libsubstrate/Makefile
  64. 10 0
      Meridian/meridianTV/electra_extras/libsubstrate/control
  65. 52 0
      Meridian/meridianTV/electra_extras/libsubstrate/libsubstrate.c
  66. 11 0
      Meridian/meridianTV/electra_extras/sbinject/.theos/_/DEBIAN/control
  67. BIN
      Meridian/meridianTV/electra_extras/sbinject/.theos/_/usr/lib/TweakInject.dylib
  68. 0 0
      Meridian/meridianTV/electra_extras/sbinject/.theos/build_session
  69. BIN
      Meridian/meridianTV/electra_extras/sbinject/.theos/fakeroot
  70. 1 0
      Meridian/meridianTV/electra_extras/sbinject/.theos/last_package
  71. 0 0
      Meridian/meridianTV/electra_extras/sbinject/.theos/obj/appletv/debug/.stamp
  72. BIN
      Meridian/meridianTV/electra_extras/sbinject/.theos/obj/appletv/debug/TweakInject.dylib
  73. BIN
      Meridian/meridianTV/electra_extras/sbinject/.theos/obj/appletv/debug/arm64/SBInject.x.09271890.o
  74. BIN
      Meridian/meridianTV/electra_extras/sbinject/.theos/obj/appletv/debug/arm64/SBInject.x.cb64146a.o
  75. BIN
      Meridian/meridianTV/electra_extras/sbinject/.theos/obj/appletv/debug/arm64/TweakInject.dylib
  76. 1 0
      Meridian/meridianTV/electra_extras/sbinject/.theos/packages/com.yourcompany.sbinject-0.0.1
  77. 10 0
      Meridian/meridianTV/electra_extras/sbinject/Makefile
  78. 253 0
      Meridian/meridianTV/electra_extras/sbinject/SBInject.x
  79. BIN
      Meridian/meridianTV/electra_extras/sbinject/TweakInject.dylib
  80. BIN
      Meridian/meridianTV/electra_extras/sbinject/TweakInject.tar
  81. 10 0
      Meridian/meridianTV/electra_extras/sbinject/control
  82. BIN
      Meridian/meridianTV/electra_extras/sbinject/debs/com.yourcompany.sbinject_0.0.1-1_appletvos-arm64.deb
  83. BIN
      Meridian/meridianTV/electra_extras/sbinject/debs/com.yourcompany.sbinject_0.0.1-2_appletvos-arm64.deb
  84. BIN
      Meridian/meridianTV/electra_extras/sbinject/debs/com.yourcompany.sbinject_0.0.1-3_appletvos-arm64.deb
  85. BIN
      Meridian/meridianTV/electra_extras/sbinject/debs/com.yourcompany.sbinject_0.0.1-4_appletvos-arm64.deb
  86. 1 0
      Meridian/meridianTV/electra_extras/sbinject/theos/Defines.h
  87. 609 0
      Meridian/meridianTV/electra_extras/sbinject/theos/LICENSE.md
  88. 55 0
      Meridian/meridianTV/electra_extras/sbinject/theos/Prefix.pch
  89. 6 0
      Meridian/meridianTV/electra_extras/sbinject/theos/README.md
  90. 31 0
      Meridian/meridianTV/electra_extras/sbinject/theos/bin/deb_build_num.sh
  91. 48 0
      Meridian/meridianTV/electra_extras/sbinject/theos/bin/denicify.pl
  92. 200 0
      Meridian/meridianTV/electra_extras/sbinject/theos/bin/dm.pl
  93. 1 0
      Meridian/meridianTV/electra_extras/sbinject/theos/bin/dm.pl.txt
  94. 46 0
      Meridian/meridianTV/electra_extras/sbinject/theos/bin/fakeroot.sh
  95. 6 0
      Meridian/meridianTV/electra_extras/sbinject/theos/bin/install.copyFile
  96. 19 0
      Meridian/meridianTV/electra_extras/sbinject/theos/bin/install.exec
  97. 4 0
      Meridian/meridianTV/electra_extras/sbinject/theos/bin/install.mergeDir
  98. 122 0
      Meridian/meridianTV/electra_extras/sbinject/theos/bin/lib/Logos/Class.pm
  99. 64 0
      Meridian/meridianTV/electra_extras/sbinject/theos/bin/lib/Logos/Function.pm
  100. 0 0
      Meridian/meridianTV/electra_extras/sbinject/theos/bin/lib/Logos/Generator.pm

+ 2 - 0
Meridian/meridianTV/electra_extras/basebinaries/.gitignore

@@ -0,0 +1,2 @@
+bin/
+

+ 28 - 0
Meridian/meridianTV/electra_extras/basebinaries/Makefile

@@ -0,0 +1,28 @@
+TARGET  = basebinaries.tar
+OUTDIR ?= bin
+
+.PHONY: all clean
+
+SUBPRJ = amfid_payload inject_criticald jailbreakd jailbreakd_client pspawn_payload libjailbreak_mig helloworld createSnapshot
+all: $(OUTDIR)/$(TARGET)
+
+MFLAGS = OUTDIR=$(abspath $(OUTDIR))
+
+DEBUG ?= 0
+ifeq ($(DEBUG), 1)
+    MFLAGS += DEBUG=1
+endif
+
+$(OUTDIR):
+	mkdir -p $(OUTDIR)
+
+$(OUTDIR)/$(TARGET): $(addprefix $(OUTDIR)/, $(SUBPRJ)) | $(OUTDIR)
+	#tar -cvf $@ $^
+	rm -f $@
+	cd $(OUTDIR); gtar -pcvf $(abspath $@) $(notdir bin/*)
+
+$(OUTDIR)/%: | $(OUTDIR)
+	$(MAKE) -C $(notdir $@) $(MFLAGS)
+
+clean:
+	rm -rf $(OUTDIR)

+ 29 - 0
Meridian/meridianTV/electra_extras/basebinaries/amfid_payload/Makefile

@@ -0,0 +1,29 @@
+TARGET  = amfid_payload.dylib
+OUTDIR ?= bin
+
+CC      = xcrun -sdk appletvos cc -arch arm64
+# it is injected into trust cache by code
+# which only supports sha-256 signatures
+LDID    = ldid2
+CFLAGS  = -Wall
+
+.PHONY: all clean
+
+all: $(OUTDIR)/$(TARGET)
+
+DEBUG ?= 0
+ifeq ($(DEBUG), 1)
+    CFLAGS += -DAMFID_PAYLOAD_DEBUG
+else
+    CFLAGS += -O2
+endif
+
+$(OUTDIR):
+	mkdir -p $(OUTDIR)
+
+$(OUTDIR)/$(TARGET): *.m *.c | $(OUTDIR)
+	$(CC) -dynamiclib -o $@ $^ -framework Foundation $(CFLAGS)
+	$(LDID) -S $@
+
+clean:
+	rm -f $(OUTDIR)/$(TARGET)

+ 220 - 0
Meridian/meridianTV/electra_extras/basebinaries/amfid_payload/amfid_payload.m

@@ -0,0 +1,220 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <mach-o/loader.h>
+#include <mach/error.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+
+#import <Foundation/Foundation.h>
+#include <CommonCrypto/CommonDigest.h>
+
+#include "fishhook.h"
+#include "cs_blobs.h"
+
+static unsigned int
+hash_rank(const CodeDirectory *cd)
+{
+    uint32_t type = cd->hashType;
+    unsigned int n;
+    
+    for (n = 0; n < sizeof(hashPriorities) / sizeof(hashPriorities[0]); ++n)
+        if (hashPriorities[n] == type)
+            return n + 1;
+    return 0;    /* not supported */
+}
+
+// 0 on success
+int get_hash(const CodeDirectory* directory, uint8_t dst[CS_CDHASH_LEN]) {
+    uint32_t realsize = ntohl(directory->length);
+    
+    if (ntohl(directory->magic) != CSMAGIC_CODEDIRECTORY) {
+        NSLog(@"[get_hash] wtf, not CSMAGIC_CODEDIRECTORY?!");
+        return 1;
+    }
+    
+    uint8_t out[CS_HASH_MAX_SIZE];
+    uint8_t hash_type = directory->hashType;
+
+    switch (hash_type) {
+        case CS_HASHTYPE_SHA1:
+            CC_SHA1(directory, realsize, out);
+            break;
+
+        case CS_HASHTYPE_SHA256:
+        case CS_HASHTYPE_SHA256_TRUNCATED:
+            CC_SHA256(directory, realsize, out);
+            break;
+
+        case CS_HASHTYPE_SHA384:
+            CC_SHA384(directory, realsize, out);
+            break;
+
+        default:
+            NSLog(@"[get_hash] Unknown hash type: 0x%x", hash_type);
+            return 2;
+    }
+
+    memcpy(dst, out, CS_CDHASH_LEN);
+    return 0;
+}
+
+// see cs_validate_csblob in xnu bsd/kern/ubc_subr.c
+// 0 on success
+int parse_superblob(uint8_t *code_dir, uint8_t dst[CS_CDHASH_LEN]) {
+    int ret = 1;
+    const CS_SuperBlob *sb = (const CS_SuperBlob *)code_dir;
+    uint8_t highest_cd_hash_rank = 0;
+    
+    for (int n = 0; n < ntohl(sb->count); n++){
+        const CS_BlobIndex *blobIndex = &sb->index[n];
+        uint32_t type = ntohl(blobIndex->type);
+        uint32_t offset = ntohl(blobIndex->offset);
+        if (ntohl(sb->length) < offset) {
+            NSLog(@"offset of blob #%d overflows superblob length", n);
+            return 1;
+        }
+        
+        const CodeDirectory *subBlob = (const CodeDirectory *)(code_dir + offset);
+        // size_t subLength = ntohl(subBlob->length);
+        
+        if (type == CSSLOT_CODEDIRECTORY || (type >= CSSLOT_ALTERNATE_CODEDIRECTORIES && type < CSSLOT_ALTERNATE_CODEDIRECTORY_LIMIT)) {
+            uint8_t rank = hash_rank(subBlob);
+            
+            if (rank > highest_cd_hash_rank) {
+                ret = get_hash(subBlob, dst);
+                highest_cd_hash_rank = rank;
+            }
+        }
+    }
+
+    return ret;
+}
+
+uint8_t *get_code_directory(const char* name, uint64_t file_off) {
+    // XXX use mmap
+    FILE* fd = fopen(name, "r");
+    uint8_t *rv = NULL;
+
+    if (fd == NULL) {
+        NSLog(@"Couldn't open file");
+        return NULL;
+    }
+
+    fseek(fd, 0L, SEEK_END);
+    uint64_t file_len = ftell(fd);
+    fseek(fd, 0L, SEEK_SET);
+
+    if (file_off > file_len){
+        NSLog(@"Error: File offset greater than length.");
+        goto out;
+    }
+
+    uint64_t off = file_off;
+    fseek(fd, off, SEEK_SET);
+
+    struct mach_header_64 mh;
+    fread(&mh, sizeof(struct mach_header_64), 1, fd);
+
+    if (mh.magic != MH_MAGIC_64){
+        NSLog(@"Error: Invalid magic");
+        goto out;
+    }
+
+    off += sizeof(struct mach_header_64);
+    if (off > file_len){
+        NSLog(@"Error: Unexpected end of file");
+        goto out;
+    }
+    for (int i = 0; i < mh.ncmds; i++) {
+        if (off + sizeof(struct load_command) > file_len){
+            NSLog(@"Error: Unexpected end of file");
+            goto out;
+        }
+
+        const struct load_command cmd;
+        fseek(fd, off, SEEK_SET);
+        fread((void*)&cmd, sizeof(struct load_command), 1, fd);
+        if (cmd.cmd == 0x1d) {
+            uint32_t off_cs;
+            fread(&off_cs, sizeof(uint32_t), 1, fd);
+            uint32_t size_cs;
+            fread(&size_cs, sizeof(uint32_t), 1, fd);
+
+            if (off_cs+file_off+size_cs > file_len){
+                NSLog(@"Error: Unexpected end of file");
+                goto out;
+            }
+
+            rv = malloc(size_cs);
+            if (rv != NULL) {
+                fseek(fd, off_cs+file_off, SEEK_SET);
+                fread(rv, size_cs, 1, fd);
+            }
+            goto out;
+        } else {
+            off += cmd.cmdsize;
+            if (off > file_len){
+                NSLog(@"Error: Unexpected end of file");
+                goto out;
+            }
+        }
+    }
+    NSLog(@"Didnt find the code signature");
+
+out:;
+    fclose(fd);
+    return rv;
+}
+
+int (*old_MISValidateSignatureAndCopyInfo)(NSString* file, NSDictionary* options, NSMutableDictionary** info);
+int (*old_MISValidateSignatureAndCopyInfo_broken)(NSString* file, NSDictionary* options, NSMutableDictionary** info);
+
+int fake_MISValidateSignatureAndCopyInfo(NSString* file, NSDictionary* options, NSMutableDictionary** info) {
+    // NSString *file = (__bridge NSString *)fileStr;
+    // NSDictionary *options = (__bridge NSDictionary*)opts;
+    NSLog(@"We got called! %@ with %@ (info: %@)", file, options, *info);
+
+    int origret = old_MISValidateSignatureAndCopyInfo(file, options, info);
+    NSLog(@"We got called! AFTER ACTUAL %@ with %@ (info: %@)", file, options, *info);
+
+    if (![*info objectForKey:@"CdHash"]) {
+        NSNumber* file_offset = [options objectForKey:@"UniversalFileOffset"];
+        uint64_t file_off = [file_offset unsignedLongLongValue];
+
+        uint8_t* code_directory = get_code_directory([file UTF8String], file_off);
+        if (!code_directory) {
+            NSLog(@"Can't get code_directory");
+            return origret;
+        }
+
+        uint8_t cd_hash[CS_CDHASH_LEN];
+
+        if (parse_superblob(code_directory, cd_hash)) {
+            NSLog(@"Ours failed");
+            return origret;
+        }
+
+        *info = [[NSMutableDictionary alloc] init];
+        [*info setValue:[[NSData alloc] initWithBytes:cd_hash length:sizeof(cd_hash)] forKey:@"CdHash"];
+        NSLog(@"ours: %@", *info);
+    }
+
+    return 0;
+}
+
+void rebind_mis(void) {
+    void *libmis = dlopen("/usr/lib/libmis.dylib", RTLD_NOW); //Force binding now
+    old_MISValidateSignatureAndCopyInfo = dlsym(libmis, "MISValidateSignatureAndCopyInfo");
+    struct rebinding rebindings[] = {
+        {"MISValidateSignatureAndCopyInfo", (void *)fake_MISValidateSignatureAndCopyInfo, (void **)&old_MISValidateSignatureAndCopyInfo_broken},
+    };
+
+    rebind_symbols(rebindings, 1);
+}
+
+__attribute__ ((constructor))
+static void ctor(void) {
+    rebind_mis();
+}

+ 117 - 0
Meridian/meridianTV/electra_extras/basebinaries/amfid_payload/cs_blobs.h

@@ -0,0 +1,117 @@
+//from: xnu osfmk/kern/cs_blobs.h
+
+typedef struct __attribute__((packed)) {
+    uint32_t magic;                    /* magic number (CSMAGIC_CODEDIRECTORY) */
+    uint32_t length;                /* total length of CodeDirectory blob */
+    uint32_t version;                /* compatibility version */
+    uint32_t flags;                    /* setup and mode flags */
+    uint32_t hashOffset;            /* offset of hash slot element at index zero */
+    uint32_t identOffset;            /* offset of identifier string */
+    uint32_t nSpecialSlots;            /* number of special hash slots */
+    uint32_t nCodeSlots;            /* number of ordinary (code) hash slots */
+    uint32_t codeLimit;                /* limit to main image signature range */
+    uint8_t hashSize;                /* size of each hash in bytes */
+    uint8_t hashType;                /* type of hash (cdHashType* constants) */
+    uint8_t platform;                /* platform identifier; zero if not platform binary */
+    uint8_t    pageSize;                /* log2(page size in bytes); 0 => infinite */
+    uint32_t spare2;                /* unused (must be zero) */
+    
+    char end_earliest[0];
+    
+    /* Version 0x20100 */
+    uint32_t scatterOffset;            /* offset of optional scatter vector */
+    char end_withScatter[0];
+    
+    /* Version 0x20200 */
+    uint32_t teamOffset;            /* offset of optional team identifier */
+    char end_withTeam[0];
+    
+    /* Version 0x20300 */
+    uint32_t spare3;                /* unused (must be zero) */
+    uint64_t codeLimit64;            /* limit to main image signature range, 64 bits */
+    char end_withCodeLimit64[0];
+    
+    /* Version 0x20400 */
+    uint64_t execSegBase;            /* offset of executable segment */
+    uint64_t execSegLimit;            /* limit of executable segment */
+    uint64_t execSegFlags;            /* executable segment flags */
+    char end_withExecSeg[0];
+} CodeDirectory;
+
+typedef struct __attribute__((packed)) {
+    uint32_t type;                    /* type of entry */
+    uint32_t offset;                /* offset of entry */
+} CS_BlobIndex;
+
+typedef struct __attribute__((packed)) {
+    uint32_t magic;                    /* magic number */
+    uint32_t length;                /* total length of SuperBlob */
+    uint32_t count;                    /* number of index entries following */
+    CS_BlobIndex index[];            /* (count) entries */
+    /* followed by Blobs in no particular order as indicated by offsets in index */
+} CS_SuperBlob;
+
+/*
+ * Magic numbers used by Code Signing
+ */
+enum {
+    CSMAGIC_REQUIREMENT = 0xfade0c00,        /* single Requirement blob */
+    CSMAGIC_REQUIREMENTS = 0xfade0c01,        /* Requirements vector (internal requirements) */
+    CSMAGIC_CODEDIRECTORY = 0xfade0c02,        /* CodeDirectory blob */
+    CSMAGIC_EMBEDDED_SIGNATURE = 0xfade0cc0, /* embedded form of signature data */
+    CSMAGIC_EMBEDDED_SIGNATURE_OLD = 0xfade0b02,    /* XXX */
+    CSMAGIC_EMBEDDED_ENTITLEMENTS = 0xfade7171,    /* embedded entitlements */
+    CSMAGIC_DETACHED_SIGNATURE = 0xfade0cc1, /* multi-arch collection of embedded signatures */
+    CSMAGIC_BLOBWRAPPER = 0xfade0b01,    /* CMS Signature, among other things */
+    
+    CS_SUPPORTSSCATTER = 0x20100,
+    CS_SUPPORTSTEAMID = 0x20200,
+    CS_SUPPORTSCODELIMIT64 = 0x20300,
+    CS_SUPPORTSEXECSEG = 0x20400,
+    
+    CSSLOT_CODEDIRECTORY = 0,                /* slot index for CodeDirectory */
+    CSSLOT_INFOSLOT = 1,
+    CSSLOT_REQUIREMENTS = 2,
+    CSSLOT_RESOURCEDIR = 3,
+    CSSLOT_APPLICATION = 4,
+    CSSLOT_ENTITLEMENTS = 5,
+    
+    CSSLOT_ALTERNATE_CODEDIRECTORIES = 0x1000, /* first alternate CodeDirectory, if any */
+    CSSLOT_ALTERNATE_CODEDIRECTORY_MAX = 5,        /* max number of alternate CD slots */
+    CSSLOT_ALTERNATE_CODEDIRECTORY_LIMIT = CSSLOT_ALTERNATE_CODEDIRECTORIES + CSSLOT_ALTERNATE_CODEDIRECTORY_MAX, /* one past the last */
+    
+    CSSLOT_SIGNATURESLOT = 0x10000,            /* CMS Signature */
+    
+    CSTYPE_INDEX_REQUIREMENTS = 0x00000002,        /* compat with amfi */
+    CSTYPE_INDEX_ENTITLEMENTS = 0x00000005,        /* compat with amfi */
+    
+    CS_HASHTYPE_SHA1 = 1,
+    CS_HASHTYPE_SHA256 = 2,
+    CS_HASHTYPE_SHA256_TRUNCATED = 3,
+    CS_HASHTYPE_SHA384 = 4,
+    
+    CS_SHA1_LEN = 20,
+    CS_SHA256_LEN = 32,
+    CS_SHA256_TRUNCATED_LEN = 20,
+    
+    CS_CDHASH_LEN = 20,                        /* always - larger hashes are truncated */
+    CS_HASH_MAX_SIZE = 48, /* max size of the hash we'll support */
+    
+    /*
+     * Currently only to support Legacy VPN plugins,
+     * but intended to replace all the various platform code, dev code etc. bits.
+     */
+    CS_SIGNER_TYPE_UNKNOWN = 0,
+    CS_SIGNER_TYPE_LEGACYVPN = 5,
+};
+
+/*
+ * Choose among different hash algorithms.
+ * Higher is better, 0 => don't use at all.
+ */
+static const uint32_t hashPriorities[] = {
+    CS_HASHTYPE_SHA1,
+    CS_HASHTYPE_SHA256_TRUNCATED,
+    CS_HASHTYPE_SHA256,
+    CS_HASHTYPE_SHA384,
+};

+ 1 - 0
Meridian/meridianTV/electra_extras/basebinaries/amfid_payload/fishhook.c

@@ -0,0 +1 @@
+../fishhook/fishhook.c

+ 1 - 0
Meridian/meridianTV/electra_extras/basebinaries/amfid_payload/fishhook.h

@@ -0,0 +1 @@
+../fishhook/fishhook.h

+ 3 - 0
Meridian/meridianTV/electra_extras/basebinaries/apple_include/.gitignore

@@ -0,0 +1,3 @@
+launch.h
+xpc
+

+ 18 - 0
Meridian/meridianTV/electra_extras/basebinaries/createSnapshot/Ent.plist

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>platform-application</key>
+	<true/>
+	<key>com.apple.private.apfs.revert-to-snapshot</key>
+	<true/>
+	<key>com.apple.private.vfs.snapshot</key>
+	<true/>
+	<key>com.apple.private.security.disk-device-access</key>
+	<true/>
+	<key>com.apple.keystore.device</key>
+	<true/>
+	<key>com.apple.keystore.devicebackup</key>
+	<true/>
+</dict>
+</plist>

+ 28 - 0
Meridian/meridianTV/electra_extras/basebinaries/createSnapshot/Makefile

@@ -0,0 +1,28 @@
+TARGET  = createSnapshot
+OUTDIR ?= bin
+
+CC      = xcrun -sdk appletvos cc -arch arm64
+# it is injected into trust cache by code
+# which only supports sha-256 signatures
+LDID    = ldid
+CFLAGS  = -Wall
+
+.PHONY: all clean
+
+DEBUG ?= 0
+ifeq ($(DEBUG), 1)
+else
+    CFLAGS += -O2
+endif
+
+all: $(OUTDIR)/$(TARGET)
+
+$(OUTDIR):
+	mkdir -p $(OUTDIR)
+
+$(OUTDIR)/$(TARGET): *.c | $(OUTDIR)
+	$(CC) -o $@ $^ $(CFLAGS)
+	$(LDID) -SEnt.plist $@
+
+clean:
+	rm -f $(OUTDIR)/$(TARGET)

+ 28 - 0
Meridian/meridianTV/electra_extras/basebinaries/createSnapshot/Makefile--

@@ -0,0 +1,28 @@
+TARGET  = createSnapshot
+OUTDIR ?= bin
+
+CC      = xcrun -sdk appletvos cc -arch arm64
+# it is injected into trust cache by code
+# which only supports sha-256 signatures
+LDID    = ldid
+CFLAGS  = -Wall
+
+.PHONY: all clean
+
+DEBUG ?= 0
+ifeq ($(DEBUG), 1)
+else
+    CFLAGS += -O2
+endif
+
+all: $(OUTDIR)/$(TARGET)
+
+$(OUTDIR):
+	mkdir -p $(OUTDIR)
+
+$(OUTDIR)/$(TARGET): *.c | $(OUTDIR)
+	$(CC) -o $@ $^ $(CFLAGS)
+	$(LDID) -SEnt.plist $@
+
+clean:
+	rm -f $(OUTDIR)/$(TARGET)

+ 28 - 0
Meridian/meridianTV/electra_extras/basebinaries/createSnapshot/Makefile----

@@ -0,0 +1,28 @@
+TARGET  = createSnapshot
+OUTDIR ?= bin
+
+CC      = xcrun -sdk iphoneos cc -arch arm64
+# it is injected into trust cache by code
+# which only supports sha-256 signatures
+LDID    = ldid
+CFLAGS  = -Wall
+
+.PHONY: all clean
+
+DEBUG ?= 0
+ifeq ($(DEBUG), 1)
+else
+    CFLAGS += -O2
+endif
+
+all: $(OUTDIR)/$(TARGET)
+
+$(OUTDIR):
+	mkdir -p $(OUTDIR)
+
+$(OUTDIR)/$(TARGET): *.c | $(OUTDIR)
+	$(CC) -o $@ $^ $(CFLAGS)
+	$(LDID) -SEnt.plist $@
+
+clean:
+	rm -f $(OUTDIR)/$(TARGET)

+ 37 - 0
Meridian/meridianTV/electra_extras/basebinaries/createSnapshot/main.c

@@ -0,0 +1,37 @@
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/syscall.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <unistd.h>
+#include <errno.h>
+#include <sys/attr.h>
+#include <sys/snapshot.h>
+
+int
+do_create(const char *vol, const char *snap)
+{
+    int dirfd = open(vol, O_RDONLY, 0);
+    if (dirfd < 0) {
+        perror("open");
+        exit(1);
+    }
+    
+    int ret = fs_snapshot_create(dirfd, snap, 0);
+    if (ret != 0)
+        perror("fs_snapshot_create");
+    return (ret);
+}
+
+
+int
+main(int argc, char **argv)
+{
+    unlink("/createSnapshot");
+    do_create("/", "electra-prejailbreak");
+    
+    return (0);
+}
+

+ 210 - 0
Meridian/meridianTV/electra_extras/basebinaries/fishhook/fishhook.c

@@ -0,0 +1,210 @@
+// Copyright (c) 2013, Facebook, Inc.
+// All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//   * Redistributions of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//   * Redistributions in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//   * Neither the name Facebook nor the names of its contributors may be used to
+//     endorse or promote products derived from this software without specific
+//     prior written permission.
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "fishhook.h"
+
+#import <dlfcn.h>
+#import <stdlib.h>
+#import <string.h>
+#import <sys/types.h>
+#import <mach-o/dyld.h>
+#import <mach-o/loader.h>
+#import <mach-o/nlist.h>
+
+#ifdef __LP64__
+typedef struct mach_header_64 mach_header_t;
+typedef struct segment_command_64 segment_command_t;
+typedef struct section_64 section_t;
+typedef struct nlist_64 nlist_t;
+#define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT_64
+#else
+typedef struct mach_header mach_header_t;
+typedef struct segment_command segment_command_t;
+typedef struct section section_t;
+typedef struct nlist nlist_t;
+#define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT
+#endif
+
+#ifndef SEG_DATA_CONST
+#define SEG_DATA_CONST  "__DATA_CONST"
+#endif
+
+struct rebindings_entry {
+  struct rebinding *rebindings;
+  size_t rebindings_nel;
+  struct rebindings_entry *next;
+};
+
+static struct rebindings_entry *_rebindings_head;
+
+static int prepend_rebindings(struct rebindings_entry **rebindings_head,
+                              struct rebinding rebindings[],
+                              size_t nel) {
+  struct rebindings_entry *new_entry = (struct rebindings_entry *) malloc(sizeof(struct rebindings_entry));
+  if (!new_entry) {
+    return -1;
+  }
+  new_entry->rebindings = (struct rebinding *) malloc(sizeof(struct rebinding) * nel);
+  if (!new_entry->rebindings) {
+    free(new_entry);
+    return -1;
+  }
+  memcpy(new_entry->rebindings, rebindings, sizeof(struct rebinding) * nel);
+  new_entry->rebindings_nel = nel;
+  new_entry->next = *rebindings_head;
+  *rebindings_head = new_entry;
+  return 0;
+}
+
+static void perform_rebinding_with_section(struct rebindings_entry *rebindings,
+                                           section_t *section,
+                                           intptr_t slide,
+                                           nlist_t *symtab,
+                                           char *strtab,
+                                           uint32_t *indirect_symtab) {
+  uint32_t *indirect_symbol_indices = indirect_symtab + section->reserved1;
+  void **indirect_symbol_bindings = (void **)((uintptr_t)slide + section->addr);
+  for (uint i = 0; i < section->size / sizeof(void *); i++) {
+    uint32_t symtab_index = indirect_symbol_indices[i];
+    if (symtab_index == INDIRECT_SYMBOL_ABS || symtab_index == INDIRECT_SYMBOL_LOCAL ||
+        symtab_index == (INDIRECT_SYMBOL_LOCAL   | INDIRECT_SYMBOL_ABS)) {
+      continue;
+    }
+    uint32_t strtab_offset = symtab[symtab_index].n_un.n_strx;
+    char *symbol_name = strtab + strtab_offset;
+    if (strnlen(symbol_name, 2) < 2) {
+      continue;
+    }
+    struct rebindings_entry *cur = rebindings;
+    while (cur) {
+      for (uint j = 0; j < cur->rebindings_nel; j++) {
+        if (strcmp(&symbol_name[1], cur->rebindings[j].name) == 0) {
+          if (cur->rebindings[j].replaced != NULL &&
+              indirect_symbol_bindings[i] != cur->rebindings[j].replacement) {
+            *(cur->rebindings[j].replaced) = indirect_symbol_bindings[i];
+          }
+          indirect_symbol_bindings[i] = cur->rebindings[j].replacement;
+          goto symbol_loop;
+        }
+      }
+      cur = cur->next;
+    }
+  symbol_loop:;
+  }
+}
+
+static void rebind_symbols_for_image(struct rebindings_entry *rebindings,
+                                     const struct mach_header *header,
+                                     intptr_t slide) {
+  Dl_info info;
+  if (dladdr(header, &info) == 0) {
+    return;
+  }
+
+  segment_command_t *cur_seg_cmd;
+  segment_command_t *linkedit_segment = NULL;
+  struct symtab_command* symtab_cmd = NULL;
+  struct dysymtab_command* dysymtab_cmd = NULL;
+
+  uintptr_t cur = (uintptr_t)header + sizeof(mach_header_t);
+  for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) {
+    cur_seg_cmd = (segment_command_t *)cur;
+    if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) {
+      if (strcmp(cur_seg_cmd->segname, SEG_LINKEDIT) == 0) {
+        linkedit_segment = cur_seg_cmd;
+      }
+    } else if (cur_seg_cmd->cmd == LC_SYMTAB) {
+      symtab_cmd = (struct symtab_command*)cur_seg_cmd;
+    } else if (cur_seg_cmd->cmd == LC_DYSYMTAB) {
+      dysymtab_cmd = (struct dysymtab_command*)cur_seg_cmd;
+    }
+  }
+
+  if (!symtab_cmd || !dysymtab_cmd || !linkedit_segment ||
+      !dysymtab_cmd->nindirectsyms) {
+    return;
+  }
+
+  // Find base symbol/string table addresses
+  uintptr_t linkedit_base = (uintptr_t)slide + linkedit_segment->vmaddr - linkedit_segment->fileoff;
+  nlist_t *symtab = (nlist_t *)(linkedit_base + symtab_cmd->symoff);
+  char *strtab = (char *)(linkedit_base + symtab_cmd->stroff);
+
+  // Get indirect symbol table (array of uint32_t indices into symbol table)
+  uint32_t *indirect_symtab = (uint32_t *)(linkedit_base + dysymtab_cmd->indirectsymoff);
+
+  cur = (uintptr_t)header + sizeof(mach_header_t);
+  for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) {
+    cur_seg_cmd = (segment_command_t *)cur;
+    if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) {
+      if (strcmp(cur_seg_cmd->segname, SEG_DATA) != 0 &&
+          strcmp(cur_seg_cmd->segname, SEG_DATA_CONST) != 0) {
+        continue;
+      }
+      for (uint j = 0; j < cur_seg_cmd->nsects; j++) {
+        section_t *sect =
+          (section_t *)(cur + sizeof(segment_command_t)) + j;
+        if ((sect->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS) {
+          perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab);
+        }
+        if ((sect->flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS) {
+          perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab);
+        }
+      }
+    }
+  }
+}
+
+static void _rebind_symbols_for_image(const struct mach_header *header,
+                                      intptr_t slide) {
+    rebind_symbols_for_image(_rebindings_head, header, slide);
+}
+
+int rebind_symbols_image(void *header,
+                         intptr_t slide,
+                         struct rebinding rebindings[],
+                         size_t rebindings_nel) {
+    struct rebindings_entry *rebindings_head = NULL;
+    int retval = prepend_rebindings(&rebindings_head, rebindings, rebindings_nel);
+    rebind_symbols_for_image(rebindings_head, (const struct mach_header *) header, slide);
+    free(rebindings_head);
+    return retval;
+}
+
+int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel) {
+  int retval = prepend_rebindings(&_rebindings_head, rebindings, rebindings_nel);
+  if (retval < 0) {
+    return retval;
+  }
+  // If this was the first call, register callback for image additions (which is also invoked for
+  // existing images, otherwise, just run on existing images
+  if (!_rebindings_head->next) {
+    _dyld_register_func_for_add_image(_rebind_symbols_for_image);
+  } else {
+    uint32_t c = _dyld_image_count();
+    for (uint32_t i = 0; i < c; i++) {
+      _rebind_symbols_for_image(_dyld_get_image_header(i), _dyld_get_image_vmaddr_slide(i));
+    }
+  }
+  return retval;
+}

+ 76 - 0
Meridian/meridianTV/electra_extras/basebinaries/fishhook/fishhook.h

@@ -0,0 +1,76 @@
+// Copyright (c) 2013, Facebook, Inc.
+// All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//   * Redistributions of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//   * Redistributions in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//   * Neither the name Facebook nor the names of its contributors may be used to
+//     endorse or promote products derived from this software without specific
+//     prior written permission.
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef fishhook_h
+#define fishhook_h
+
+#include <stddef.h>
+#include <stdint.h>
+
+#if !defined(FISHHOOK_EXPORT)
+#define FISHHOOK_VISIBILITY __attribute__((visibility("hidden")))
+#else
+#define FISHHOOK_VISIBILITY __attribute__((visibility("default")))
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif //__cplusplus
+
+/*
+ * A structure representing a particular intended rebinding from a symbol
+ * name to its replacement
+ */
+struct rebinding {
+  const char *name;
+  void *replacement;
+  void **replaced;
+};
+
+/*
+ * For each rebinding in rebindings, rebinds references to external, indirect
+ * symbols with the specified name to instead point at replacement for each
+ * image in the calling process as well as for all future images that are loaded
+ * by the process. If rebind_functions is called more than once, the symbols to
+ * rebind are added to the existing list of rebindings, and if a given symbol
+ * is rebound more than once, the later rebinding will take precedence.
+ */
+FISHHOOK_VISIBILITY
+int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel);
+
+/*
+ * Rebinds as above, but only in the specified image. The header should point
+ * to the mach-o header, the slide should be the slide offset. Others as above.
+ */
+FISHHOOK_VISIBILITY
+int rebind_symbols_image(void *header,
+                         intptr_t slide,
+                         struct rebinding rebindings[],
+                         size_t rebindings_nel);
+
+#ifdef __cplusplus
+}
+#endif //__cplusplus
+
+#endif //fishhook_h
+

+ 8 - 0
Meridian/meridianTV/electra_extras/basebinaries/helloworld/Ent.plist

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>platform-application</key>
+	<true/>
+</dict>
+</plist>

+ 26 - 0
Meridian/meridianTV/electra_extras/basebinaries/helloworld/Makefile

@@ -0,0 +1,26 @@
+TARGET  = helloworld
+OUTDIR ?= bin
+
+CC      = xcrun -sdk appletvos cc -arch arm64
+LDID    = ldid
+CFLAGS  = -Wall
+
+.PHONY: all clean
+
+all: $(OUTDIR)/$(TARGET)
+
+DEBUG ?= 0
+ifeq ($(DEBUG), 1)
+else
+    CFLAGS += -O2
+endif
+
+$(OUTDIR):
+	mkdir -p $(OUTDIR)
+
+$(OUTDIR)/$(TARGET): *.c | $(OUTDIR)
+	$(CC) -o $@ $^ $(CFLAGS)
+	$(LDID) -SEnt.plist $@
+
+clean:
+	rm -f $(OUTDIR)/$(TARGET)

+ 8 - 0
Meridian/meridianTV/electra_extras/basebinaries/helloworld/main.c

@@ -0,0 +1,8 @@
+#import <stdio.h>
+
+int main(){
+    FILE *f = fopen("/.amfid_success", "w");
+    fprintf(f,"Hello World!\n");
+    fclose(f);
+    return 0;
+}

+ 14 - 0
Meridian/meridianTV/electra_extras/basebinaries/inject_criticald/Ent.plist

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>platform-application</key>
+	<true/>
+	<key>get-task-allow</key>
+	<true/>
+	<key>com.apple.system-task-ports</key>
+	<true/>
+	<key>task_for_pid-allow</key>
+	<true/>
+</dict>
+</plist>

+ 29 - 0
Meridian/meridianTV/electra_extras/basebinaries/inject_criticald/Makefile

@@ -0,0 +1,29 @@
+TARGET  = inject_criticald
+OUTDIR ?= bin
+
+CC      = xcrun -sdk appletvos cc -arch arm64
+# it is injected into trust cache by code
+# which only supports sha-256 signatures
+LDID    = ldid2
+CFLAGS  = -Wall
+
+.PHONY: all clean
+
+DEBUG ?= 0
+ifeq ($(DEBUG), 1)
+    CFLAGS += -DINJECT_CRITICALD_DEBUG
+else
+    CFLAGS += -O2
+endif
+
+all: $(OUTDIR)/$(TARGET)
+
+$(OUTDIR):
+	mkdir -p $(OUTDIR)
+
+$(OUTDIR)/$(TARGET): *.m | $(OUTDIR)
+	$(CC) -o $@ $^ -framework Foundation -framework IOKit $(CFLAGS)
+	$(LDID) -SEnt.plist $@
+
+clean:
+	rm -f $(OUTDIR)/$(TARGET)

+ 539 - 0
Meridian/meridianTV/electra_extras/basebinaries/inject_criticald/inject_criticald.m

@@ -0,0 +1,539 @@
+/* code comes from IB's triple_fetch inject_amfid.c */
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <mach/mach.h>
+#include <mach-o/loader.h>
+#include <mach/error.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/sysctl.h>
+#include <dlfcn.h>
+#include <sys/mman.h>
+#include <spawn.h>
+#include <sys/stat.h>
+#include <pthread.h>
+#include <signal.h>
+
+#import <Foundation/Foundation.h>
+
+kern_return_t mach_vm_allocate
+(
+ vm_map_t target,
+ mach_vm_address_t *address,
+ mach_vm_size_t size,
+ int flags
+ );
+
+kern_return_t mach_vm_write
+(
+ vm_map_t target_task,
+ mach_vm_address_t address,
+ vm_offset_t data,
+ mach_msg_type_number_t dataCnt
+ );
+
+ extern kern_return_t mach_vm_deallocate
+(
+ vm_map_t target,
+ mach_vm_address_t address,
+ mach_vm_size_t size
+);
+
+
+kern_return_t mach_vm_read_overwrite(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, mach_vm_address_t data, mach_vm_size_t *outsize);
+kern_return_t mach_vm_region(vm_map_t target_task, mach_vm_address_t *address, mach_vm_size_t *size, vm_region_flavor_t flavor, vm_region_info_t info, mach_msg_type_number_t *infoCnt, mach_port_t *object_name);
+
+
+mach_port_t tfpzero = 0;
+
+uint64_t kalloc(vm_size_t size) {
+	mach_vm_address_t address = 0;
+	mach_vm_allocate(tfpzero, (mach_vm_address_t *)&address, size, VM_FLAGS_ANYWHERE);
+	return address;
+}
+
+
+
+size_t kread(uint64_t where, void *p, size_t size) {
+	int rv;
+	size_t offset = 0;
+	while (offset < size) {
+		mach_vm_size_t sz, chunk = 2048;
+		if (chunk > size - offset) {
+			chunk = size - offset;
+		}
+		rv = mach_vm_read_overwrite(tfpzero, where + offset, chunk, (mach_vm_address_t)p + offset, &sz);
+		if (rv || sz == 0) {
+			printf("[fun_utils] error on kread(0x%016llx)\n", (offset + where));
+			break;
+		}
+		offset += sz;
+	}
+	return offset;
+}
+
+uint32_t kread32(uint64_t where) {
+	uint32_t out;
+	kread(where, &out, sizeof(uint32_t));
+	return out;
+}
+
+uint64_t kread64(uint64_t where) {
+	uint64_t out;
+	kread(where, &out, sizeof(uint64_t));
+	return out;
+}
+
+size_t kwrite(uint64_t where, const void *p, size_t size) {
+	int rv;
+	size_t offset = 0;
+	while (offset < size) {
+		size_t chunk = 2048;
+		if (chunk > size - offset) {
+			chunk = size - offset;
+		}
+		rv = mach_vm_write(tfpzero, where + offset, (mach_vm_offset_t)p + offset, chunk);
+		if (rv) {
+			printf("[fun_utils] error on kwrite(0x%016llx)\n", (offset + where));
+			break;
+		}
+		offset += chunk;
+	}
+	return offset;
+}
+
+void kwrite32(uint64_t where, uint32_t what) {
+	uint32_t _what = what;
+	kwrite(where, &_what, sizeof(uint32_t));
+}
+
+
+void kwrite64(uint64_t where, uint64_t what) {
+	uint64_t _what = what;
+	kwrite(where, &_what, sizeof(uint64_t));
+}
+
+uint64_t
+remote_alloc(mach_port_t task_port,
+             uint64_t size)
+{
+  kern_return_t err;
+
+  mach_vm_offset_t remote_addr = 0;
+  mach_vm_size_t remote_size = (mach_vm_size_t)size;
+  err = mach_vm_allocate(task_port, &remote_addr, remote_size, 1); // ANYWHERE
+  if (err != KERN_SUCCESS){
+    NSLog(@"unable to allocate buffer in remote process\n");
+    return 0;
+  }
+  return (uint64_t)remote_addr;
+}
+
+void
+remote_free(mach_port_t task_port,
+            uint64_t base,
+            uint64_t size)
+{
+  kern_return_t err;
+
+  err = mach_vm_deallocate(task_port, (mach_vm_address_t)base, (mach_vm_size_t)size);
+  if (err !=  KERN_SUCCESS){
+    NSLog(@"unabble to deallocate remote buffer\n");
+    return;
+  }
+  return;
+}
+
+uint64_t
+alloc_and_fill_remote_buffer(mach_port_t task_port,
+                             uint64_t local_address,
+                             uint64_t length)
+{
+  kern_return_t err;
+
+  uint64_t remote_address = remote_alloc(task_port, length);
+
+  err = mach_vm_write(task_port, remote_address, (mach_vm_offset_t)local_address, (mach_msg_type_number_t)length);
+  if (err != KERN_SUCCESS){
+    NSLog(@"unable to write to remote memory\n");
+    return 0;
+  }
+
+  return remote_address;
+}
+
+void
+remote_read_overwrite(mach_port_t task_port,
+                      uint64_t remote_address,
+                      uint64_t local_address,
+                      uint64_t length)
+{
+  kern_return_t err;
+
+  mach_vm_size_t outsize = 0;
+  err = mach_vm_read_overwrite(task_port, (mach_vm_address_t)remote_address, (mach_vm_size_t)length, (mach_vm_address_t)local_address, &outsize);
+  if (err != KERN_SUCCESS){
+    NSLog(@"remote read failed\n");
+    return;
+  }
+
+  if (outsize != length){
+    NSLog(@"remote read was short (expected %llx, got %llx\n", length, outsize);
+    return;
+  }
+}
+
+void
+remote_write(mach_port_t remote_task_port,
+             uint64_t remote_address,
+             uint64_t local_address,
+             uint64_t length)
+{
+  kern_return_t err = mach_vm_write(remote_task_port,
+                                    (mach_vm_address_t)remote_address,
+                                    (vm_offset_t)local_address,
+                                    (mach_msg_type_number_t)length);
+  if (err != KERN_SUCCESS) {
+    NSLog(@"remote write failed: %s %x\n", mach_error_string(err), err);
+    return;
+  }
+}
+
+ enum arg_type {
+  ARG_LITERAL,
+  ARG_BUFFER,
+  ARG_BUFFER_PERSISTENT, // don't free the buffer after the call
+  ARG_OUT_BUFFER,
+  ARG_INOUT_BUFFER
+};
+
+typedef struct _arg_desc {
+  uint64_t type;
+  uint64_t value;
+  uint64_t length;
+} arg_desc;
+
+#define REMOTE_LITERAL(val) &(arg_desc){ARG_LITERAL, (uint64_t)val, (uint64_t)0}
+#define REMOTE_BUFFER(ptr, size) &(arg_desc){ARG_BUFFER, (uint64_t)ptr, (uint64_t)size}
+#define REMOTE_CSTRING(str) &(arg_desc){ARG_BUFFER, (uint64_t)str, (uint64_t)(strlen(str)+1)}
+#define REMOTE_BUFFER_PERSISTENT(ptr, size) &(arg_desc){ARG_BUFFER_PERSISTENT, (uint64_t)ptr, (uint64_t)size}
+#define REMOTE_CSTRING_PERSISTENT(str) &(arg_desc){ARG_BUFFER_PERSISTENT, (uint64_t)str, (uint64_t)(strlen(str)+1)}
+#define REMOTE_OUT_BUFFER(ptr, size) &(arg_desc){ARG_OUT_BUFFER, (uint64_t)ptr, (uint64_t)size}
+#define REMOTE_INOUT_BUFFER(ptr, size) &(arg_desc){ARG_INOUT_BUFFER, (uint64_t)ptr, (uint64_t)size}
+
+
+ uint64_t
+find_gadget_candidate(
+  char** alternatives,
+  size_t gadget_length)
+{
+  void* haystack_start = (void*)atoi;    // will do...
+  size_t haystack_size = 100*1024*1024; // likewise...
+
+  for (char* candidate = *alternatives; candidate != NULL; alternatives++) {
+    void* found_at = memmem(haystack_start, haystack_size, candidate, gadget_length);
+    if (found_at != NULL){
+      NSLog(@"found at: %llx\n", (uint64_t)found_at);
+      return (uint64_t)found_at;
+    }
+  }
+
+  return 0;
+}
+
+uint64_t blr_x19_addr = 0;
+uint64_t
+find_blr_x19_gadget()
+{
+  if (blr_x19_addr != 0){
+    return blr_x19_addr;
+  }
+  char* blr_x19 = "\x60\x02\x3f\xd6";
+  char* candidates[] = {blr_x19, NULL};
+  blr_x19_addr = find_gadget_candidate(candidates, 4);
+  return blr_x19_addr;
+}
+
+// no support for non-register args
+#define MAX_REMOTE_ARGS 8
+
+// not in iOS SDK headers:
+extern void
+_pthread_set_self(
+                  pthread_t p);
+
+uint64_t call_remote(mach_port_t task_port, void* fptr, int n_params, ...)
+{
+  if (n_params > MAX_REMOTE_ARGS || n_params < 0){
+    NSLog(@"unsupported number of arguments to remote function (%d)\n", n_params);
+    return 0;
+  }
+
+  kern_return_t err;
+
+  uint64_t remote_stack_base = 0;
+  uint64_t remote_stack_size = 4*1024*1024;
+
+  remote_stack_base = remote_alloc(task_port, remote_stack_size);
+
+  uint64_t remote_stack_middle = remote_stack_base + (remote_stack_size/2);
+
+  // create a new thread in the target
+  // just using the mach thread API doesn't initialize the pthread thread-local-storage
+  // which means that stuff which relies on that will crash
+  // we can sort-of make that work by calling _pthread_set_self(NULL) in the target process
+  // which will give the newly created thread the same TLS region as the main thread
+
+
+  _STRUCT_ARM_THREAD_STATE64 thread_state = {{0}};
+  mach_msg_type_number_t thread_stateCnt = sizeof(thread_state)/4;
+
+  // we'll start the thread running and call _pthread_set_self first:
+  thread_state.__sp = remote_stack_middle;
+  thread_state.__pc = (uint64_t)_pthread_set_self;
+
+  // set these up to put us into a predictable state we can monitor for:
+  uint64_t loop_lr = find_blr_x19_gadget();
+  thread_state.__x[19] = loop_lr;
+  thread_state.__lr = loop_lr;
+
+  // set the argument to NULL:
+  thread_state.__x[0] = 0;
+
+  mach_port_t thread_port = MACH_PORT_NULL;
+
+  err = thread_create_running(task_port, ARM_THREAD_STATE64, (thread_state_t)&thread_state, thread_stateCnt, &thread_port);
+  if (err != KERN_SUCCESS){
+    NSLog(@"error creating thread in child: %s\n", mach_error_string(err));
+    return 0;
+  }
+  // NSLog(@"new thread running in child: %x\n", thread_port);
+
+  // wait for it to hit the loop:
+  while(1){
+    // monitor the thread until we see it's in the infinite loop indicating it's done:
+    err = thread_get_state(thread_port, ARM_THREAD_STATE64, (thread_state_t)&thread_state, &thread_stateCnt);
+    if (err != KERN_SUCCESS){
+      NSLog(@"error getting thread state: %s\n", mach_error_string(err));
+      return 0;
+    }
+
+    if (thread_state.__pc == loop_lr && thread_state.__x[19] == loop_lr){
+      // thread has returned from the target function
+      break;
+    }
+  }
+
+  // the thread should now have pthread local storage
+  // pause it:
+
+  err = thread_suspend(thread_port);
+  if (err != KERN_SUCCESS){
+    NSLog(@"unable to suspend target thread\n");
+    return 0;
+  }
+
+  /*
+   err = thread_abort(thread_port);
+   if (err != KERN_SUCCESS){
+   NSLog(@"unable to get thread out of any traps\n");
+   return 0;
+   }
+   */
+
+  // set up for the actual target call:
+  thread_state.__sp = remote_stack_middle;
+  thread_state.__pc = (uint64_t)fptr;
+
+  // set these up to put us into a predictable state we can monitor for:
+  thread_state.__x[19] = loop_lr;
+  thread_state.__lr = loop_lr;
+
+  va_list ap;
+  va_start(ap, n_params);
+
+  arg_desc* args[MAX_REMOTE_ARGS] = {0};
+
+  uint64_t remote_buffers[MAX_REMOTE_ARGS] = {0};
+  //uint64_t remote_buffer_sizes[MAX_REMOTE_ARGS] = {0};
+
+  for (int i = 0; i < n_params; i++){
+    arg_desc* arg = va_arg(ap, arg_desc*);
+
+    args[i] = arg;
+
+    switch(arg->type){
+      case ARG_LITERAL:
+      {
+        thread_state.__x[i] = arg->value;
+        break;
+      }
+
+      case ARG_BUFFER:
+      case ARG_BUFFER_PERSISTENT:
+      case ARG_INOUT_BUFFER:
+      {
+        uint64_t remote_buffer = alloc_and_fill_remote_buffer(task_port, arg->value, arg->length);
+        remote_buffers[i] = remote_buffer;
+        thread_state.__x[i] = remote_buffer;
+        break;
+      }
+
+      case ARG_OUT_BUFFER:
+      {
+        uint64_t remote_buffer = remote_alloc(task_port, arg->length);
+        // NSLog(@"allocated a remote out buffer: %llx\n", remote_buffer);
+        remote_buffers[i] = remote_buffer;
+        thread_state.__x[i] = remote_buffer;
+        break;
+      }
+
+      default:
+      {
+        NSLog(@"invalid argument type!\n");
+      }
+    }
+  }
+
+  va_end(ap);
+
+  err = thread_set_state(thread_port, ARM_THREAD_STATE64, (thread_state_t)&thread_state, thread_stateCnt);
+  if (err != KERN_SUCCESS){
+    NSLog(@"error setting new thread state: %s\n", mach_error_string(err));
+    return 0;
+  }
+  // NSLog(@"thread state updated in target: %x\n", thread_port);
+
+  err = thread_resume(thread_port);
+  if (err != KERN_SUCCESS){
+    NSLog(@"unable to resume target thread\n");
+    return 0;
+  }
+
+  while(1){
+    // monitor the thread until we see it's in the infinite loop indicating it's done:
+    err = thread_get_state(thread_port, ARM_THREAD_STATE64, (thread_state_t)&thread_state, &thread_stateCnt);
+    if (err != KERN_SUCCESS){
+      NSLog(@"error getting thread state: %s\n", mach_error_string(err));
+      return 0;
+    }
+
+    if (thread_state.__pc == loop_lr/*&& thread_state.__x[19] == loop_lr*/){
+      // thread has returned from the target function
+      break;
+    }
+
+    // thread isn't in the infinite loop yet, let it continue
+  }
+
+  // deallocate the remote thread
+  err = thread_terminate(thread_port);
+  if (err != KERN_SUCCESS){
+    NSLog(@"failed to terminate thread\n");
+    return 0;
+  }
+  mach_port_deallocate(mach_task_self(), thread_port);
+
+  // handle post-call argument cleanup/copying:
+  for (int i = 0; i < MAX_REMOTE_ARGS; i++){
+    arg_desc* arg = args[i];
+    if (arg == NULL){
+      break;
+    }
+    switch (arg->type){
+      case ARG_BUFFER:
+      {
+        remote_free(task_port, remote_buffers[i], arg->length);
+        break;
+      }
+
+      case ARG_INOUT_BUFFER:
+      case ARG_OUT_BUFFER:
+      {
+        // copy the contents back:
+        remote_read_overwrite(task_port, remote_buffers[i], arg->value, arg->length);
+        remote_free(task_port, remote_buffers[i], arg->length);
+        break;
+      }
+    }
+  }
+
+  uint64_t ret_val = thread_state.__x[0];
+
+  // NSLog(@"remote function call return value: %llx\n", ret_val);
+
+  // deallocate the stack in the target:
+  remote_free(task_port, remote_stack_base, remote_stack_size);
+
+  return ret_val;
+}
+
+uint64_t binary_load_address(mach_port_t tp) {
+  kern_return_t err;
+  mach_msg_type_number_t region_count = VM_REGION_BASIC_INFO_COUNT_64;
+  memory_object_name_t object_name = MACH_PORT_NULL; /* unused */
+  mach_vm_size_t target_first_size = 0x1000;
+  mach_vm_address_t target_first_addr = 0x0;
+  struct vm_region_basic_info_64 region = {0};
+  err = mach_vm_region(tp,
+                       &target_first_addr,
+                       &target_first_size,
+                       VM_REGION_BASIC_INFO_64,
+                       (vm_region_info_t)&region,
+                       &region_count,
+                       &object_name);
+
+  if (err != KERN_SUCCESS) {
+    printf("failed to get the region\n");
+    return -1;
+  }
+
+  return target_first_addr;
+}
+
+int main(int argc, char* argv[]) {
+	uint32_t pid = atoi(argv[1]);
+	char *loaded_dylib = argv[2];
+
+	task_t remoteTask;
+	kern_return_t kr = task_for_pid(mach_task_self(), pid, &remoteTask);
+	if (kr != KERN_SUCCESS) {
+		NSLog(@"Failed to get task for pid %u!", pid);
+		return -1;
+	}
+
+	tfpzero = (mach_port_t)remoteTask;
+
+	// NSLog(@"Trying to find the start of the main binary!");
+
+	uint64_t actual_addr = binary_load_address(remoteTask);
+
+	if (actual_addr == -1) {
+		NSLog(@"Couldn't find the address");
+		return -1;
+	}
+
+	NSLog(@"Address is at %016llx", actual_addr);
+
+    uint64_t handler = call_remote(remoteTask, dlopen, 2, REMOTE_CSTRING(loaded_dylib), REMOTE_LITERAL(RTLD_NOW));
+    if (handler != 0) {
+        NSLog(@"No error occured!");
+    } else {
+      uint64_t error = call_remote(remoteTask, dlerror, 0);
+      if (error == 0) {
+        NSLog(@"Error occured, but dlerror returned NULL!");
+      } else {
+          uint64_t len = call_remote(remoteTask, strlen, 1, REMOTE_LITERAL(error));
+          char* local_cstring = malloc(len+1);
+          remote_read_overwrite(remoteTask, error, (uint64_t)local_cstring, len+1);
+
+          NSLog(@"Error is %s", local_cstring);
+      }
+      return -1;
+    }
+
+	return 0;
+}

+ 16 - 0
Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/Ent.plist

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>platform-application</key>
+	<true/>
+	<key>get-task-allow</key>
+	<true/>
+	<key>com.apple.system-task-ports</key>
+	<true/>
+	<key>task_for_pid-allow</key>
+	<true/>
+	<key>com.apple.private.memorystatus</key>
+	<true/>
+</dict>
+</plist>

+ 34 - 0
Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/Makefile

@@ -0,0 +1,34 @@
+TARGET  = jailbreakd
+OUTDIR ?= bin
+
+CC      = xcrun -sdk appletvos cc -arch arm64
+LDID    = ldid
+CFLAGS  = -Wall -Wno-unused-variable -Wno-unused-function
+
+.PHONY: all clean
+
+all: $(OUTDIR)/$(TARGET)
+
+DEBUG ?= 1
+ifeq ($(DEBUG), 1)
+    CFLAGS += -DJAILBREAKDDEBUG
+else
+    CFLAGS += -O2
+endif
+
+mach/jailbreak_daemonServer.c:
+	rm -f mach/jailbreak_daemonServer.c
+	rm -f mach/jailbreak_daemonUser.c
+	mig -sheader mach/jailbreak_daemonServer.h -header mach/jailbreak_daemonUser.h mach/mig.defs
+	mv jailbreak_daemonServer.c mach/
+	mv jailbreak_daemonUser.c mach/
+
+$(OUTDIR):
+	mkdir -p $(OUTDIR)
+
+$(OUTDIR)/$(TARGET): mach/jailbreak_daemonServer.c *.c *.m | $(OUTDIR)
+	$(CC) -o $@ $^ -framework Foundation -framework IOKit $(CFLAGS)
+	$(LDID) -SEnt.plist $@
+
+clean:
+	rm -f $(OUTDIR)/$(TARGET)

+ 81 - 0
Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/kern_utils.h

@@ -0,0 +1,81 @@
+#import <stdio.h>
+#import <mach/mach.h>
+#import <mach/error.h>
+#import <mach/message.h>
+#import <CoreFoundation/CoreFoundation.h>
+
+kern_return_t mach_vm_read(
+						   vm_map_t target_task,
+						   mach_vm_address_t address,
+						   mach_vm_size_t size,
+						   vm_offset_t *data,
+						   mach_msg_type_number_t *dataCnt);
+
+/****** IOKit/IOKitLib.h *****/
+typedef mach_port_t io_service_t;
+typedef mach_port_t io_connect_t;
+
+extern const mach_port_t kIOMasterPortDefault;
+#define IO_OBJECT_NULL (0)
+
+kern_return_t
+IOConnectCallAsyncMethod(
+						 mach_port_t     connection,
+						 uint32_t        selector,
+						 mach_port_t     wakePort,
+						 uint64_t*       reference,
+						 uint32_t        referenceCnt,
+						 const uint64_t* input,
+						 uint32_t        inputCnt,
+						 const void*     inputStruct,
+						 size_t          inputStructCnt,
+						 uint64_t*       output,
+						 uint32_t*       outputCnt,
+						 void*           outputStruct,
+						 size_t*         outputStructCntP);
+
+kern_return_t
+IOConnectCallMethod(
+					mach_port_t     connection,
+					uint32_t        selector,
+					const uint64_t* input,
+					uint32_t        inputCnt,
+					const void*     inputStruct,
+					size_t          inputStructCnt,
+					uint64_t*       output,
+					uint32_t*       outputCnt,
+					void*           outputStruct,
+					size_t*         outputStructCntP);
+
+io_service_t
+IOServiceGetMatchingService(
+							mach_port_t  _masterPort,
+							CFDictionaryRef  matching);
+
+CFMutableDictionaryRef
+IOServiceMatching(
+				  const char* name);
+
+kern_return_t
+IOServiceOpen(
+			  io_service_t  service,
+			  task_port_t   owningTask,
+			  uint32_t      type,
+			  io_connect_t* connect );
+
+kern_return_t IOConnectTrap6(io_connect_t connect, uint32_t index, uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4, uintptr_t p5, uintptr_t p6);
+kern_return_t mach_vm_read_overwrite(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, mach_vm_address_t data, mach_vm_size_t *outsize);
+kern_return_t mach_vm_write(vm_map_t target_task, mach_vm_address_t address, vm_offset_t data, mach_msg_type_number_t dataCnt);
+kern_return_t mach_vm_allocate(vm_map_t target, mach_vm_address_t *address, mach_vm_size_t size, int flags);
+kern_return_t mach_vm_deallocate(vm_map_t target, mach_vm_address_t address, mach_vm_size_t size);
+
+uint64_t find_port(mach_port_name_t port);
+
+void fixupsetuid(int pid);
+
+int setcsflagsandplatformize(int pd);
+
+extern mach_port_t tfpzero;
+extern uint64_t kernel_base;
+extern uint64_t kernel_slide;
+

+ 362 - 0
Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/kern_utils.m

@@ -0,0 +1,362 @@
+#import <Foundation/Foundation.h>
+#import <sys/stat.h>
+#import "kern_utils.h"
+#import "kmem.h"
+#import "patchfinder64.h"
+#import "kexecute.h"
+#import "offsetof.h"
+#import "osobject.h"
+#import "sandbox.h"
+
+#define PROC_PIDPATHINFO_MAXSIZE  (4*MAXPATHLEN)
+int proc_pidpath(pid_t pid, void *buffer, uint32_t buffersize);
+
+#define TF_PLATFORM 0x400
+
+#define	CS_VALID		0x0000001	/* dynamically valid */
+#define CS_ADHOC		0x0000002	/* ad hoc signed */
+#define CS_GET_TASK_ALLOW	0x0000004	/* has get-task-allow entitlement */
+#define CS_INSTALLER		0x0000008	/* has installer entitlement */
+
+#define	CS_HARD			0x0000100	/* don't load invalid pages */
+#define	CS_KILL			0x0000200	/* kill process if it becomes invalid */
+#define CS_CHECK_EXPIRATION	0x0000400	/* force expiration checking */
+#define CS_RESTRICT		0x0000800	/* tell dyld to treat restricted */
+#define CS_ENFORCEMENT		0x0001000	/* require enforcement */
+#define CS_REQUIRE_LV		0x0002000	/* require library validation */
+#define CS_ENTITLEMENTS_VALIDATED	0x0004000
+
+#define	CS_ALLOWED_MACHO	0x00ffffe
+
+#define CS_EXEC_SET_HARD	0x0100000	/* set CS_HARD on any exec'ed process */
+#define CS_EXEC_SET_KILL	0x0200000	/* set CS_KILL on any exec'ed process */
+#define CS_EXEC_SET_ENFORCEMENT	0x0400000	/* set CS_ENFORCEMENT on any exec'ed process */
+#define CS_EXEC_SET_INSTALLER	0x0800000	/* set CS_INSTALLER on any exec'ed process */
+
+#define CS_KILLED		0x1000000	/* was killed by kernel for invalidity */
+#define CS_DYLD_PLATFORM	0x2000000	/* dyld used to load this is a platform binary */
+#define CS_PLATFORM_BINARY	0x4000000	/* this is a platform binary */
+#define CS_PLATFORM_PATH	0x8000000	/* platform binary by the fact of path (osx only) */
+
+#define CS_DEBUGGED         0x10000000  /* process is currently or has previously been debugged and allowed to run with invalid pages */
+#define CS_SIGNED         0x20000000  /* process has a signature (may have gone invalid) */
+#define CS_DEV_CODE         0x40000000  /* code is dev signed, cannot be loaded into prod signed code (will go away with rdar://problem/28322552) */
+
+uint64_t proc_find(int pd, int tries) {
+  // TODO use kcall(proc_find) + ZM_FIX_ADDR
+  while (tries-- > 0) {
+    uint64_t proc = rk64(find_allproc());
+    while (proc) {
+      uint32_t pid = rk32(proc + offsetof_p_pid);
+      if (pid == pd) {
+        return proc;
+      }
+      proc = rk64(proc);
+    }
+  }
+  return 0;
+}
+
+CACHED_FIND(uint64_t, our_task_addr) {
+  uint64_t our_proc = proc_find(getpid(), 1);
+
+  if (our_proc == 0) {
+    fprintf(stderr,"failed to find our_task_addr!\n");
+    exit(EXIT_FAILURE);
+  }
+
+  uint64_t addr = rk64(our_proc + offsetof_task);
+  fprintf(stderr,"our_task_addr: 0x%llx\n", addr);
+  return addr;
+}
+
+uint64_t find_port(mach_port_name_t port){
+  uint64_t task_addr = our_task_addr();
+  
+  uint64_t itk_space = rk64(task_addr + offsetof_itk_space);
+  
+  uint64_t is_table = rk64(itk_space + offsetof_ipc_space_is_table);
+  
+  uint32_t port_index = port >> 8;
+  const int sizeof_ipc_entry_t = 0x18;
+  
+  uint64_t port_addr = rk64(is_table + (port_index * sizeof_ipc_entry_t));
+  return port_addr;
+}
+
+void fixupsetuid(int pid){
+    char pathbuf[PROC_PIDPATHINFO_MAXSIZE];
+    bzero(pathbuf, sizeof(pathbuf));
+    
+    int ret = proc_pidpath(pid, pathbuf, sizeof(pathbuf));
+    if (ret < 0){
+        fprintf(stderr,"Unable to get path for PID %d\n", pid);
+        return;
+    }
+    struct stat file_st;
+    if (lstat(pathbuf, &file_st) == -1){
+#ifdef JAILBREAKDDEBUG
+        fprintf(stderr,"Unable to get stat for file %s\n", pathbuf);
+#endif
+        return;
+    }
+    if (file_st.st_mode & S_ISUID){
+        uid_t fileUID = file_st.st_uid;
+#ifdef JAILBREAKDDEBUG
+        fprintf(stderr,"Fixing up setuid for file owned by %u\n", fileUID);
+#endif
+        
+        uint64_t proc = proc_find(pid, 3);
+        if (proc != 0) {
+            uint64_t ucred = rk64(proc + offsetof_p_ucred);
+            
+            uid_t cr_svuid = rk32(ucred + offsetof_ucred_cr_svuid);
+#ifdef JAILBREAKDDEBUG
+            fprintf(stderr,"Original sv_uid: %u\n", cr_svuid);
+#endif
+            wk32(ucred + offsetof_ucred_cr_svuid, fileUID);
+#ifdef JAILBREAKDDEBUG
+            fprintf(stderr,"New sv_uid: %u\n", fileUID);
+#endif
+        }
+    } else {
+#ifdef JAILBREAKDDEBUG
+        fprintf(stderr,"File %s is not setuid!\n", pathbuf);
+#endif
+        return;
+    }
+}
+
+void set_csflags(uint64_t proc) {
+    uint32_t csflags = rk32(proc + offsetof_p_csflags);
+#ifdef JAILBREAKDDEBUG
+    fprintf(stderr,"Previous CSFlags: 0x%x\n", csflags);
+#endif
+    csflags = (csflags | CS_PLATFORM_BINARY | CS_INSTALLER | CS_GET_TASK_ALLOW | CS_DEBUGGED) & ~(CS_RESTRICT | CS_HARD | CS_KILL);
+#ifdef JAILBREAKDDEBUG
+    fprintf(stderr,"New CSFlags: 0x%x\n", csflags);
+#endif
+    wk32(proc + offsetof_p_csflags, csflags);
+}
+
+void set_tfplatform(uint64_t proc) {
+    // task.t_flags & TF_PLATFORM
+    uint64_t task = rk64(proc + offsetof_task);
+    uint32_t t_flags = rk32(task + offsetof_t_flags);
+#ifdef JAILBREAKDDEBUG
+    fprintf(stderr,"Old t_flags: 0x%x\n", t_flags);
+#endif
+    t_flags |= TF_PLATFORM;
+    wk32(task+offsetof_t_flags, t_flags);
+#ifdef JAILBREAKDDEBUG
+    fprintf(stderr,"New t_flags: 0x%x\n", t_flags);
+#endif
+}
+
+void set_csblob(uint64_t proc) {
+    uint64_t textvp = rk64(proc + offsetof_p_textvp); //vnode of executable
+    off_t textoff = rk64(proc + offsetof_p_textoff);
+    
+#ifdef JAILBREAKDDEBUG
+    fprintf(stderr,"\t__TEXT at 0x%llx. Offset: 0x%llx\n", textvp, textoff);
+#endif
+    if (textvp != 0){
+      uint32_t vnode_type_tag = rk32(textvp + offsetof_v_type);
+      uint16_t vnode_type = vnode_type_tag & 0xffff;
+      uint16_t vnode_tag = (vnode_type_tag >> 16);
+#ifdef JAILBREAKDDEBUG
+      fprintf(stderr,"\tVNode Type: 0x%x. Tag: 0x%x.\n", vnode_type, vnode_tag);
+#endif
+      
+      if (vnode_type == 1){
+          uint64_t ubcinfo = rk64(textvp + offsetof_v_ubcinfo);
+#ifdef JAILBREAKDDEBUG
+          fprintf(stderr,"\t\tUBCInfo at 0x%llx.\n\n", ubcinfo);
+#endif
+          
+          uint64_t csblobs = rk64(ubcinfo + offsetof_ubcinfo_csblobs);
+          while (csblobs != 0){
+#ifdef JAILBREAKDDEBUG
+              fprintf(stderr,"\t\t\tCSBlobs at 0x%llx.\n", csblobs);
+#endif
+              
+              cpu_type_t csblob_cputype = rk32(csblobs + offsetof_csb_cputype);
+              unsigned int csblob_flags = rk32(csblobs + offsetof_csb_flags);
+              off_t csb_base_offset = rk64(csblobs + offsetof_csb_base_offset);
+              uint64_t csb_entitlements = rk64(csblobs + offsetof_csb_entitlements_offset);
+              unsigned int csb_signer_type = rk32(csblobs + offsetof_csb_signer_type);
+              unsigned int csb_platform_binary = rk32(csblobs + offsetof_csb_platform_binary);
+              unsigned int csb_platform_path = rk32(csblobs + offsetof_csb_platform_path);
+
+#ifdef JAILBREAKDDEBUG
+              fprintf(stderr,"\t\t\tCSBlob CPU Type: 0x%x. Flags: 0x%x. Offset: 0x%llx\n", csblob_cputype, csblob_flags, csb_base_offset);
+              fprintf(stderr,"\t\t\tCSBlob Signer Type: 0x%x. Platform Binary: %d Path: %d\n", csb_signer_type, csb_platform_binary, csb_platform_path);
+#endif
+              wk32(csblobs + offsetof_csb_platform_binary, 1);
+
+              csb_platform_binary = rk32(csblobs + offsetof_csb_platform_binary);
+#ifdef JAILBREAKDDEBUG
+              fprintf(stderr,"\t\t\tCSBlob Signer Type: 0x%x. Platform Binary: %d Path: %d\n", csb_signer_type, csb_platform_binary, csb_platform_path);
+              
+              fprintf(stderr,"\t\t\t\tEntitlements at 0x%llx.\n", csb_entitlements);
+#endif
+              csblobs = rk64(csblobs);
+          }
+      }
+    }
+}
+
+const char* abs_path_exceptions[] = {
+  "/Library",
+  // XXX there's some weird stuff about linking and special
+  // handling for /private/var/mobile/* in sandbox
+  "/private/var/mobile/Library",
+  "/private/var/mnt",
+  "/private/var/db",
+  "/private/var/stash",
+  NULL
+};
+
+uint64_t get_exception_osarray(void) {
+  static uint64_t cached = 0;
+
+  if (cached == 0) {
+    // XXX use abs_path_exceptions
+    cached = OSUnserializeXML("<array>"
+    "<string>/Library/</string>"
+    "<string>/private/var/mobile/Library/</string>"
+    "<string>/private/var/mnt/</string>"
+    "<string>/private/var/db/</string>"
+    "<string>/private/var/stash/</string>"
+    "</array>");
+  }
+
+  return cached;
+}
+
+static const char *exc_key = "com.apple.security.exception.files.absolute-path.read-only";
+
+void set_sandbox_extensions(uint64_t proc) {
+  uint64_t proc_ucred = rk64(proc+0x100);
+  uint64_t sandbox = rk64(rk64(proc_ucred+0x78) + 8 + 8);
+
+#ifdef JAILBREAKDDEBUG
+  fprintf(stderr,"proc = 0x%llx & proc_ucred = 0x%llx & sandbox = 0x%llx\n", proc, proc_ucred, sandbox);
+#endif
+    
+  if (sandbox == 0) {
+#ifdef JAILBREAKDDEBUG
+    fprintf(stderr,"no sandbox, skipping\n");
+#endif
+    return;
+  }
+
+  if (has_file_extension(sandbox, abs_path_exceptions[0])) {
+#ifdef JAILBREAKDDEBUG
+    fprintf(stderr,"already has '%s', skipping\n", abs_path_exceptions[0]);
+#endif
+    return;
+  }
+
+  uint64_t ext = 0;
+  const char** path = abs_path_exceptions;
+  while (*path != NULL) {
+    ext = extension_create_file(*path, ext);
+    if (ext == 0) {
+      fprintf(stderr,"extension_create_file(%s) failed, panic!\n", *path);
+    }
+    ++path;
+  }
+
+#ifdef JAILBREAKDDEBUG
+  fprintf(stderr,"last extension_create_file ext: 0x%llx\n", ext);
+#endif
+
+  if (ext != 0) {
+    extension_add(ext, sandbox, exc_key);
+  }
+}
+
+void set_amfi_entitlements(uint64_t proc) {
+    // AMFI entitlements
+#ifdef JAILBREAKDDEBUG
+    fprintf(stderr,"AMFI:\n");
+#endif
+    uint64_t proc_ucred = rk64(proc+0x100);
+    uint64_t amfi_entitlements = rk64(rk64(proc_ucred+0x78)+0x8);
+#ifdef JAILBREAKDDEBUG
+    fprintf(stderr,"Setting Entitlements...\n");
+#endif
+
+    OSDictionary_SetItem(amfi_entitlements, "get-task-allow", find_OSBoolean_True());
+    OSDictionary_SetItem(amfi_entitlements, "com.apple.private.skip-library-validation", find_OSBoolean_True());
+
+    uint64_t present = OSDictionary_GetItem(amfi_entitlements, exc_key);
+
+    int rv = 0;
+
+    if (present == 0) {
+      rv = OSDictionary_SetItem(amfi_entitlements, exc_key, get_exception_osarray());
+    } else if (present != get_exception_osarray()) {
+        unsigned int itemCount = OSArray_ItemCount(present);
+#ifdef JAILBREAKDDEBUG
+        fprintf(stderr,"present != 0 (0x%llx)! item count: %d\n", present, itemCount);
+#endif
+        BOOL foundEntitlements = NO;
+        
+        uint64_t itemBuffer = OSArray_ItemBuffer(present);
+        
+        for (int i = 0; i < itemCount; i++){
+            uint64_t item = rk64(itemBuffer + (i * sizeof(void *)));
+#ifdef JAILBREAKDDEBUG
+            fprintf(stderr,"Item %d: 0x%llx\n", i, item);
+#endif
+            char *entitlementString = OSString_CopyString(item);
+            if (strcmp(entitlementString, "/bootstrap/") == 0){
+                foundEntitlements = YES;
+                free(entitlementString);
+                break;
+            }
+            free(entitlementString);
+        }
+        
+        if (!foundEntitlements){
+            rv = OSArray_Merge(present, get_exception_osarray());
+        } else {
+            rv = 1;
+        }
+    } else {
+#ifdef JAILBREAKDDEBUG
+      fprintf(stderr,"Not going to merge array with itself :P\n");
+#endif
+      rv = 1;
+    }
+
+    if (rv != 1) {
+      fprintf(stderr,"Setting exc FAILED! amfi_entitlements: 0x%llx present: 0x%llx\n", amfi_entitlements, present);
+    }
+}
+
+int setcsflagsandplatformize(int pid){
+  uint64_t proc = proc_find(pid, 3);
+  if (proc != 0) {
+#ifdef JAILBREAKDDEBUG
+    fprintf(stderr,"setcsflagsandplatformize start on PID %d\n", pid);
+    char name[40] = {0};
+    kread(proc+0x268, name, 20);
+    fprintf(stderr,"PID %d name is %s\n", pid, name);
+#endif
+      
+    set_csflags(proc);
+    set_tfplatform(proc);
+    set_amfi_entitlements(proc);
+    set_sandbox_extensions(proc);
+    set_csblob(proc);
+#ifdef JAILBREAKDDEBUG
+    fprintf(stderr,"setcsflagsandplatformize done on PID %d\n", pid);
+#endif
+    return 0;
+  }
+  fprintf(stderr,"Unable to find PID %d to entitle!\n", pid);
+  return 1;
+}

+ 121 - 0
Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/kexecute.c

@@ -0,0 +1,121 @@
+#include <pthread.h>
+#include "kmem.h"
+#include "kexecute.h"
+#include "kern_utils.h"
+#include "patchfinder64.h"
+#include "offsetof.h"
+
+mach_port_t prepare_user_client(void) {
+  kern_return_t err;
+  mach_port_t user_client;
+  io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOSurfaceRoot"));
+
+  if (service == IO_OBJECT_NULL){
+    printf(" [-] unable to find service\n");
+    exit(EXIT_FAILURE);
+  }
+
+  err = IOServiceOpen(service, mach_task_self(), 0, &user_client);
+  if (err != KERN_SUCCESS){
+    printf(" [-] unable to get user client connection\n");
+    exit(EXIT_FAILURE);
+  }
+
+
+  printf("got user client: 0x%x\n", user_client);
+  return user_client;
+}
+
+// TODO: Consider removing this - jailbreakd runs all kernel ops on the main thread
+pthread_mutex_t kexecute_lock;
+static mach_port_t user_client;
+static uint64_t IOSurfaceRootUserClient_port;
+static uint64_t IOSurfaceRootUserClient_addr;
+static uint64_t fake_vtable;
+static uint64_t fake_client;
+const int fake_kalloc_size = 0x1000;
+
+void init_kexecute(void) {
+    user_client = prepare_user_client();
+
+    // From v0rtex - get the IOSurfaceRootUserClient port, and then the address of the actual client, and vtable
+    IOSurfaceRootUserClient_port = find_port(user_client); // UserClients are just mach_ports, so we find its address
+    printf("Found port: 0x%llx\n", IOSurfaceRootUserClient_port);
+
+    IOSurfaceRootUserClient_addr = rk64(IOSurfaceRootUserClient_port + offsetof_ip_kobject); // The UserClient itself (the C++ object) is at the kobject field
+    printf("Found addr: 0x%llx\n", IOSurfaceRootUserClient_addr);
+
+    uint64_t IOSurfaceRootUserClient_vtab = rk64(IOSurfaceRootUserClient_addr); // vtables in C++ are at *object
+    printf("Found vtab: 0x%llx\n", IOSurfaceRootUserClient_vtab);
+
+    // The aim is to create a fake client, with a fake vtable, and overwrite the existing client with the fake one
+    // Once we do that, we can use IOConnectTrap6 to call functions in the kernel as the kernel
+
+
+    // Create the vtable in the kernel memory, then copy the existing vtable into there
+    fake_vtable = kalloc(fake_kalloc_size);
+    printf("Created fake_vtable at %016llx\n", fake_vtable);
+
+    for (int i = 0; i < 0x200; i++) {
+        wk64(fake_vtable+i*8, rk64(IOSurfaceRootUserClient_vtab+i*8));
+    }
+
+    printf("Copied some of the vtable over\n");
+
+    // Create the fake user client
+    fake_client = kalloc(fake_kalloc_size);
+    printf("Created fake_client at %016llx\n", fake_client);
+
+    for (int i = 0; i < 0x200; i++) {
+        wk64(fake_client+i*8, rk64(IOSurfaceRootUserClient_addr+i*8));
+    }
+
+    printf("Copied the user client over\n");
+
+    // Write our fake vtable into the fake user client
+    wk64(fake_client, fake_vtable);
+
+    // Replace the user client with ours
+    wk64(IOSurfaceRootUserClient_port + offsetof_ip_kobject, fake_client);
+
+    // Now the userclient port we have will look into our fake user client rather than the old one
+
+    // Replace IOUserClient::getExternalTrapForIndex with our ROP gadget (add x0, x0, #0x40; ret;)
+    wk64(fake_vtable+8*0xB7, find_add_x0_x0_0x40_ret());
+
+    printf("Wrote the `add x0, x0, #0x40; ret;` gadget over getExternalTrapForIndex");
+
+    pthread_mutex_init(&kexecute_lock, NULL);
+}
+
+void term_kexecute(void) {
+    wk64(IOSurfaceRootUserClient_port + offsetof_ip_kobject, IOSurfaceRootUserClient_addr);
+    kfree(fake_vtable, fake_kalloc_size);
+    kfree(fake_client, fake_kalloc_size);
+}
+
+uint64_t kexecute(uint64_t addr, uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6) {
+    pthread_mutex_lock(&kexecute_lock);
+
+    // When calling IOConnectTrapX, this makes a call to iokit_user_client_trap, which is the user->kernel call (MIG). This then calls IOUserClient::getTargetAndTrapForIndex
+    // to get the trap struct (which contains an object and the function pointer itself). This function calls IOUserClient::getExternalTrapForIndex, which is expected to return a trap.
+    // This jumps to our gadget, which returns +0x40 into our fake user_client, which we can modify. The function is then called on the object. But how C++ actually works is that the
+    // function is called with the first arguement being the object (referenced as `this`). Because of that, the first argument of any function we call is the object, and everything else is passed
+    // through like normal.
+
+    // Because the gadget gets the trap at user_client+0x40, we have to overwrite the contents of it
+    // We will pull a switch when doing so - retrieve the current contents, call the trap, put back the contents
+    // (i'm not actually sure if the switch back is necessary but meh)
+
+    uint64_t offx20 = rk64(fake_client+0x40);
+    uint64_t offx28 = rk64(fake_client+0x48);
+    wk64(fake_client+0x40, x0);
+    wk64(fake_client+0x48, addr);
+    uint64_t returnval = IOConnectTrap6(user_client, 0, (uint64_t)(x1), (uint64_t)(x2), (uint64_t)(x3), (uint64_t)(x4), (uint64_t)(x5), (uint64_t)(x6));
+    wk64(fake_client+0x40, offx20);
+    wk64(fake_client+0x48, offx28);
+
+    pthread_mutex_unlock(&kexecute_lock);
+
+    return returnval;
+}

+ 6 - 0
Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/kexecute.h

@@ -0,0 +1,6 @@
+#include <mach/mach.h>
+#include <inttypes.h>
+
+uint64_t kexecute(uint64_t addr, uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6);
+void init_kexecute(void);
+void term_kexecute(void);

+ 123 - 0
Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/kmem.c

@@ -0,0 +1,123 @@
+#import "kern_utils.h"
+#import "patchfinder64.h"
+#import "kmem.h"
+
+#define MAX_CHUNK_SIZE 0xFFF
+
+size_t kread(uint64_t where, void *p, size_t size) {
+	int rv;
+	size_t offset = 0;
+	while (offset < size) {
+		mach_vm_size_t sz, chunk = MAX_CHUNK_SIZE;
+		if (chunk > size - offset) {
+			chunk = size - offset;
+		}
+		rv = mach_vm_read_overwrite(tfpzero, where + offset, chunk, (mach_vm_address_t)p + offset, &sz);
+		if (rv || sz == 0) {
+			fprintf(stderr, "[e] error reading kernel @%p\n", (void *)(offset + where));
+			break;
+		}
+		offset += sz;
+	}
+	return offset;
+}
+
+size_t kwrite(uint64_t where, const void *p, size_t size) {
+	int rv;
+	size_t offset = 0;
+	while (offset < size) {
+		size_t chunk = MAX_CHUNK_SIZE;
+		if (chunk > size - offset) {
+			chunk = size - offset;
+		}
+		rv = mach_vm_write(tfpzero, where + offset, (mach_vm_offset_t)p + offset, chunk);
+		if (rv) {
+			fprintf(stderr, "[e] error writing kernel @%p\n", (void *)(offset + where));
+			break;
+		}
+		offset += chunk;
+	}
+	return offset;
+}
+
+uint64_t kalloc(vm_size_t size){
+	mach_vm_address_t address = 0;
+	mach_vm_allocate(tfpzero, (mach_vm_address_t *)&address, size, VM_FLAGS_ANYWHERE);
+	return address;
+}
+
+void kfree(mach_vm_address_t address, vm_size_t size){
+  mach_vm_deallocate(tfpzero, address, size);
+}
+
+uint32_t rk32(uint64_t kaddr) {
+  uint32_t val = 0;
+  kread(kaddr, &val, sizeof(val));
+  return val;
+}
+
+uint64_t rk64(uint64_t kaddr) {
+  uint64_t val = 0;
+  kread(kaddr, &val, sizeof(val));
+  return val;
+}
+
+void wk32(uint64_t kaddr, uint32_t val) {
+  kwrite(kaddr, &val, sizeof(val));
+}
+
+void wk64(uint64_t kaddr, uint64_t val) {
+  kwrite(kaddr, &val, sizeof(val));
+}
+
+// thx Siguza
+typedef struct {
+  uint64_t prev;
+  uint64_t next;
+  uint64_t start;
+  uint64_t end;
+} kmap_hdr_t;
+
+uint64_t zm_fix_addr(uint64_t addr) {
+  static kmap_hdr_t zm_hdr = {0, 0, 0, 0};
+
+  if (zm_hdr.start == 0) {
+	// xxx rk64(0) ?!
+	uint64_t zone_map = rk64(find_zone_map_ref());
+	// hdr is at offset 0x10, mutexes at start
+	size_t r = kread(zone_map + 0x10, &zm_hdr, sizeof(zm_hdr));
+	printf("zm_range: 0x%llx - 0x%llx (read 0x%zx, exp 0x%zx)\n", zm_hdr.start, zm_hdr.end, r, sizeof(zm_hdr));
+
+	if (r != sizeof(zm_hdr) || zm_hdr.start == 0 || zm_hdr.end == 0) {
+	  printf("kread of zone_map failed!\n");
+	  exit(1);
+	}
+
+	if (zm_hdr.end - zm_hdr.start > 0x100000000) {
+		printf("zone_map is too big, sorry.\n");
+		exit(1);
+	}
+  }
+
+  uint64_t zm_tmp = (zm_hdr.start & 0xffffffff00000000) | ((addr) & 0xffffffff);
+
+  return zm_tmp < zm_hdr.start ? zm_tmp + 0x100000000 : zm_tmp;
+}
+
+int kstrcmp(uint64_t kstr, const char* str) {
+	// XXX be safer, dont just assume you wont cause any
+	// page faults by this
+	size_t len = strlen(str) + 1;
+	char *local = malloc(len + 1);
+	local[len] = '\0';
+
+	int ret = 1;
+
+	if (kread(kstr, local, len) == len) {
+		ret = strcmp(local, str);
+	}
+
+	free(local);
+
+	return ret;
+}

+ 16 - 0
Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/kmem.h

@@ -0,0 +1,16 @@
+#include <mach/mach.h>
+
+uint64_t kalloc(vm_size_t size);
+void kfree(mach_vm_address_t address, vm_size_t size);
+
+size_t kread(uint64_t where, void *p, size_t size);
+uint32_t rk32(uint64_t kaddr);
+uint64_t rk64(uint64_t kaddr);
+
+size_t kwrite(uint64_t where, const void *p, size_t size);
+void wk32(uint64_t kaddr, uint32_t val);
+void wk64(uint64_t kaddr, uint64_t val);
+
+uint64_t zm_fix_addr(uint64_t addr);
+
+int kstrcmp(uint64_t kstr, const char* str);

+ 403 - 0
Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/launch.h

@@ -0,0 +1,403 @@
+#ifndef __XPC_LAUNCH_H__
+#define __XPC_LAUNCH_H__
+
+/*!
+ * @header
+ * These interfaces were only ever documented for the purpose of allowing a
+ * launchd job to obtain file descriptors associated with the sockets it
+ * advertised in its launchd.plist(5). That functionality is now available in a
+ * much more straightforward fashion through the {@link launch_activate_socket}
+ * API.
+ *
+ * There are currently no replacements for other uses of the {@link launch_msg}
+ * API, including submitting, removing, starting, stopping and listing jobs.
+ */
+
+#include <os/base.h>
+#include <Availability.h>
+
+#include <mach/mach.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <sys/cdefs.h>
+
+#if __has_feature(assume_nonnull)
+_Pragma("clang assume_nonnull begin")
+#endif
+__BEGIN_DECLS
+
+#define LAUNCH_KEY_SUBMITJOB "SubmitJob"
+#define LAUNCH_KEY_REMOVEJOB "RemoveJob"
+#define LAUNCH_KEY_STARTJOB "StartJob"
+#define LAUNCH_KEY_STOPJOB "StopJob"
+#define LAUNCH_KEY_GETJOB "GetJob"
+#define LAUNCH_KEY_GETJOBS "GetJobs"
+#define LAUNCH_KEY_CHECKIN "CheckIn"
+
+#define LAUNCH_JOBKEY_LABEL "Label"
+#define LAUNCH_JOBKEY_DISABLED "Disabled"
+#define LAUNCH_JOBKEY_USERNAME "UserName"
+#define LAUNCH_JOBKEY_GROUPNAME "GroupName"
+#define LAUNCH_JOBKEY_TIMEOUT "TimeOut"
+#define LAUNCH_JOBKEY_EXITTIMEOUT "ExitTimeOut"
+#define LAUNCH_JOBKEY_INITGROUPS "InitGroups"
+#define LAUNCH_JOBKEY_SOCKETS "Sockets"
+#define LAUNCH_JOBKEY_MACHSERVICES "MachServices"
+#define LAUNCH_JOBKEY_MACHSERVICELOOKUPPOLICIES "MachServiceLookupPolicies"
+#define LAUNCH_JOBKEY_INETDCOMPATIBILITY "inetdCompatibility"
+#define LAUNCH_JOBKEY_ENABLEGLOBBING "EnableGlobbing"
+#define LAUNCH_JOBKEY_PROGRAMARGUMENTS "ProgramArguments"
+#define LAUNCH_JOBKEY_PROGRAM "Program"
+#define LAUNCH_JOBKEY_ONDEMAND "OnDemand"
+#define LAUNCH_JOBKEY_KEEPALIVE "KeepAlive"
+#define LAUNCH_JOBKEY_LIMITLOADTOHOSTS "LimitLoadToHosts"
+#define LAUNCH_JOBKEY_LIMITLOADFROMHOSTS "LimitLoadFromHosts"
+#define LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE "LimitLoadToSessionType"
+#define LAUNCH_JOBKEY_LIMITLOADTOHARDWARE "LimitLoadToHardware"
+#define LAUNCH_JOBKEY_LIMITLOADFROMHARDWARE "LimitLoadFromHardware"
+#define LAUNCH_JOBKEY_RUNATLOAD "RunAtLoad"
+#define LAUNCH_JOBKEY_ROOTDIRECTORY "RootDirectory"
+#define LAUNCH_JOBKEY_WORKINGDIRECTORY "WorkingDirectory"
+#define LAUNCH_JOBKEY_ENVIRONMENTVARIABLES "EnvironmentVariables"
+#define LAUNCH_JOBKEY_USERENVIRONMENTVARIABLES "UserEnvironmentVariables"
+#define LAUNCH_JOBKEY_UMASK "Umask"
+#define LAUNCH_JOBKEY_NICE "Nice"
+#define LAUNCH_JOBKEY_HOPEFULLYEXITSFIRST "HopefullyExitsFirst"
+#define LAUNCH_JOBKEY_HOPEFULLYEXITSLAST "HopefullyExitsLast"
+#define LAUNCH_JOBKEY_LOWPRIORITYIO "LowPriorityIO"
+#define LAUNCH_JOBKEY_LOWPRIORITYBACKGROUNDIO "LowPriorityBackgroundIO"
+#define LAUNCH_JOBKEY_SESSIONCREATE "SessionCreate"
+#define LAUNCH_JOBKEY_STARTONMOUNT "StartOnMount"
+#define LAUNCH_JOBKEY_SOFTRESOURCELIMITS "SoftResourceLimits"
+#define LAUNCH_JOBKEY_HARDRESOURCELIMITS "HardResourceLimits"
+#define LAUNCH_JOBKEY_STANDARDINPATH "StandardInPath"
+#define LAUNCH_JOBKEY_STANDARDOUTPATH "StandardOutPath"
+#define LAUNCH_JOBKEY_STANDARDERRORPATH "StandardErrorPath"
+#define LAUNCH_JOBKEY_DEBUG "Debug"
+#define LAUNCH_JOBKEY_WAITFORDEBUGGER "WaitForDebugger"
+#define LAUNCH_JOBKEY_QUEUEDIRECTORIES "QueueDirectories"
+#define LAUNCH_JOBKEY_WATCHPATHS "WatchPaths"
+#define LAUNCH_JOBKEY_STARTINTERVAL "StartInterval"
+#define LAUNCH_JOBKEY_STARTCALENDARINTERVAL "StartCalendarInterval"
+#define LAUNCH_JOBKEY_BONJOURFDS "BonjourFDs"
+#define LAUNCH_JOBKEY_LASTEXITSTATUS "LastExitStatus"
+#define LAUNCH_JOBKEY_PID "PID"
+#define LAUNCH_JOBKEY_THROTTLEINTERVAL "ThrottleInterval"
+#define LAUNCH_JOBKEY_LAUNCHONLYONCE "LaunchOnlyOnce"
+#define LAUNCH_JOBKEY_ABANDONPROCESSGROUP "AbandonProcessGroup"
+#define LAUNCH_JOBKEY_IGNOREPROCESSGROUPATSHUTDOWN \
+	"IgnoreProcessGroupAtShutdown"
+#define LAUNCH_JOBKEY_LEGACYTIMERS "LegacyTimers"
+#define LAUNCH_JOBKEY_ENABLEPRESSUREDEXIT "EnablePressuredExit"
+#define LAUNCH_JOBKEY_DRAINMESSAGESONFAILEDINIT "DrainMessagesOnFailedInit"
+
+#define LAUNCH_JOBKEY_POLICIES "Policies"
+#define LAUNCH_JOBKEY_ENABLETRANSACTIONS "EnableTransactions"
+
+#define LAUNCH_JOBPOLICY_DENYCREATINGOTHERJOBS "DenyCreatingOtherJobs"
+
+#define LAUNCH_JOBINETDCOMPATIBILITY_WAIT "Wait"
+#define LAUNCH_JOBINETDCOMPATIBILITY_INSTANCES "Instances"
+
+#define LAUNCH_JOBKEY_MACH_RESETATCLOSE "ResetAtClose"
+#define LAUNCH_JOBKEY_MACH_HIDEUNTILCHECKIN "HideUntilCheckIn"
+#define LAUNCH_JOBKEY_MACH_DRAINMESSAGESONCRASH "DrainMessagesOnCrash"
+#define LAUNCH_JOBKEY_MACH_PINGEVENTUPDATES "PingEventUpdates"
+
+#define LAUNCH_JOBKEY_KEEPALIVE_SUCCESSFULEXIT "SuccessfulExit"
+#define LAUNCH_JOBKEY_KEEPALIVE_NETWORKSTATE "NetworkState"
+#define LAUNCH_JOBKEY_KEEPALIVE_PATHSTATE "PathState"
+#define LAUNCH_JOBKEY_KEEPALIVE_OTHERJOBACTIVE "OtherJobActive"
+#define LAUNCH_JOBKEY_KEEPALIVE_OTHERJOBENABLED "OtherJobEnabled"
+#define LAUNCH_JOBKEY_KEEPALIVE_AFTERINITIALDEMAND	"AfterInitialDemand"
+#define LAUNCH_JOBKEY_KEEPALIVE_CRASHED "Crashed"
+
+#define LAUNCH_JOBKEY_LAUNCHEVENTS "LaunchEvents"
+
+#define LAUNCH_JOBKEY_CAL_MINUTE "Minute"
+#define LAUNCH_JOBKEY_CAL_HOUR "Hour"
+#define LAUNCH_JOBKEY_CAL_DAY "Day"
+#define LAUNCH_JOBKEY_CAL_WEEKDAY "Weekday"
+#define LAUNCH_JOBKEY_CAL_MONTH "Month"
+
+#define LAUNCH_JOBKEY_RESOURCELIMIT_CORE "Core"
+#define LAUNCH_JOBKEY_RESOURCELIMIT_CPU "CPU"
+#define LAUNCH_JOBKEY_RESOURCELIMIT_DATA "Data"
+#define LAUNCH_JOBKEY_RESOURCELIMIT_FSIZE "FileSize"
+#define LAUNCH_JOBKEY_RESOURCELIMIT_MEMLOCK "MemoryLock"
+#define LAUNCH_JOBKEY_RESOURCELIMIT_NOFILE "NumberOfFiles"
+#define LAUNCH_JOBKEY_RESOURCELIMIT_NPROC "NumberOfProcesses"
+#define LAUNCH_JOBKEY_RESOURCELIMIT_RSS "ResidentSetSize"
+#define LAUNCH_JOBKEY_RESOURCELIMIT_STACK "Stack"
+
+#define LAUNCH_JOBKEY_DISABLED_MACHINETYPE "MachineType"
+#define LAUNCH_JOBKEY_DISABLED_MODELNAME "ModelName"
+
+#define LAUNCH_JOBSOCKETKEY_TYPE "SockType"
+#define LAUNCH_JOBSOCKETKEY_PASSIVE "SockPassive"
+#define LAUNCH_JOBSOCKETKEY_BONJOUR "Bonjour"
+#define LAUNCH_JOBSOCKETKEY_SECUREWITHKEY "SecureSocketWithKey"
+#define LAUNCH_JOBSOCKETKEY_PATHNAME "SockPathName"
+#define LAUNCH_JOBSOCKETKEY_PATHMODE "SockPathMode"
+#define LAUNCH_JOBSOCKETKEY_PATHOWNER "SockPathOwner"
+#define LAUNCH_JOBSOCKETKEY_PATHGROUP "SockPathGroup"
+#define LAUNCH_JOBSOCKETKEY_NODENAME "SockNodeName"
+#define LAUNCH_JOBSOCKETKEY_SERVICENAME "SockServiceName"
+#define LAUNCH_JOBSOCKETKEY_FAMILY "SockFamily"
+#define LAUNCH_JOBSOCKETKEY_PROTOCOL "SockProtocol"
+#define LAUNCH_JOBSOCKETKEY_MULTICASTGROUP "MulticastGroup"
+
+#define LAUNCH_JOBKEY_PROCESSTYPE "ProcessType"
+#define LAUNCH_KEY_PROCESSTYPE_APP "App"
+#define LAUNCH_KEY_PROCESSTYPE_STANDARD "Standard"
+#define LAUNCH_KEY_PROCESSTYPE_BACKGROUND "Background"
+#define LAUNCH_KEY_PROCESSTYPE_INTERACTIVE "Interactive"
+#define LAUNCH_KEY_PROCESSTYPE_ADAPTIVE "Adaptive"
+
+/*!
+ * @function launch_activate_socket
+ *
+ * @abstract
+ * Retrieves the file descriptors for sockets specified in the process'
+ * launchd.plist(5).
+ *
+ * @param name
+ * The name of the socket entry in the service's Sockets dictionary.
+ *
+ * @param fds
+ * On return, this parameter will be populated with an array of file
+ * descriptors. One socket can have many descriptors associated with it
+ * depending on the characteristics of the network interfaces on the system.
+ * The descriptors in this array are the results of calling getaddrinfo(3) with
+ * the parameters described in launchd.plist(5).
+ *
+ * The caller is responsible for calling free(3) on the returned pointer.
+ *
+ * @param cnt
+ * The number of file descriptor entries in the returned array.
+ *
+ * @result
+ * On success, zero is returned. Otherwise, an appropriate POSIX-domain is
+ * returned. Possible error codes are:
+ *
+ * ENOENT -> There was no socket of the specified name owned by the caller.
+ * ESRCH -> The caller is not a process managed by launchd.
+ * EALREADY -> The socket has already been activated by the caller.
+ */
+__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0)
+OS_EXPORT OS_WARN_RESULT OS_NONNULL1 OS_NONNULL2 OS_NONNULL3
+int
+launch_activate_socket(const char *name,
+	int * _Nonnull * _Nullable fds, size_t *cnt);
+
+typedef struct _launch_data *launch_data_t;
+typedef void (*launch_data_dict_iterator_t)(const launch_data_t lval,
+	const char *key, void * _Nullable ctx);
+
+typedef enum {
+	LAUNCH_DATA_DICTIONARY = 1,
+	LAUNCH_DATA_ARRAY,
+	LAUNCH_DATA_FD,
+	LAUNCH_DATA_INTEGER,
+	LAUNCH_DATA_REAL,
+	LAUNCH_DATA_BOOL,
+	LAUNCH_DATA_STRING,
+	LAUNCH_DATA_OPAQUE,
+	LAUNCH_DATA_ERRNO,
+	LAUNCH_DATA_MACHPORT,
+} launch_data_type_t;
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_MALLOC OS_WARN_RESULT
+launch_data_t
+launch_data_alloc(launch_data_type_t type);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_MALLOC OS_WARN_RESULT OS_NONNULL1
+launch_data_t
+launch_data_copy(launch_data_t ld);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_WARN_RESULT OS_NONNULL1
+launch_data_type_t
+launch_data_get_type(const launch_data_t ld);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_NONNULL1
+void
+launch_data_free(launch_data_t ld);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_NONNULL1 OS_NONNULL2 OS_NONNULL3
+bool
+launch_data_dict_insert(launch_data_t ldict, const launch_data_t lval,
+	const char *key);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_WARN_RESULT OS_NONNULL1 OS_NONNULL2
+launch_data_t _Nullable
+launch_data_dict_lookup(const launch_data_t ldict, const char *key);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_NONNULL1 OS_NONNULL2
+bool
+launch_data_dict_remove(launch_data_t ldict, const char *key);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_NONNULL1 OS_NONNULL2
+void
+launch_data_dict_iterate(const launch_data_t ldict,
+	launch_data_dict_iterator_t iterator, void * _Nullable ctx);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_WARN_RESULT OS_NONNULL1
+size_t
+launch_data_dict_get_count(const launch_data_t ldict);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_NONNULL1 OS_NONNULL2
+bool
+launch_data_array_set_index(launch_data_t larray, const launch_data_t lval,
+	size_t idx);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_WARN_RESULT OS_NONNULL1
+launch_data_t
+launch_data_array_get_index(const launch_data_t larray, size_t idx);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_WARN_RESULT OS_NONNULL1
+size_t
+launch_data_array_get_count(const launch_data_t larray);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_MALLOC OS_WARN_RESULT
+launch_data_t
+launch_data_new_fd(int fd);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_MALLOC OS_WARN_RESULT
+launch_data_t
+launch_data_new_machport(mach_port_t val);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_MALLOC OS_WARN_RESULT
+launch_data_t
+launch_data_new_integer(long long val);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_MALLOC OS_WARN_RESULT
+launch_data_t
+launch_data_new_bool(bool val);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_MALLOC OS_WARN_RESULT
+launch_data_t
+launch_data_new_real(double val);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_MALLOC OS_WARN_RESULT
+launch_data_t
+launch_data_new_string(const char *val);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_MALLOC OS_WARN_RESULT
+launch_data_t
+launch_data_new_opaque(const void *bytes, size_t sz);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_NONNULL1
+bool
+launch_data_set_fd(launch_data_t ld, int fd);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_NONNULL1
+bool
+launch_data_set_machport(launch_data_t ld, mach_port_t mp);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_NONNULL1
+bool
+launch_data_set_integer(launch_data_t ld, long long val);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_NONNULL1
+bool
+launch_data_set_bool(launch_data_t ld, bool val);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_NONNULL1
+bool
+launch_data_set_real(launch_data_t ld, double val);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_NONNULL1
+bool
+launch_data_set_string(launch_data_t ld, const char *val);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_NONNULL1
+bool
+launch_data_set_opaque(launch_data_t ld, const void *bytes, size_t sz);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_WARN_RESULT OS_NONNULL1
+int
+launch_data_get_fd(const launch_data_t ld);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_WARN_RESULT OS_NONNULL1
+mach_port_t
+launch_data_get_machport(const launch_data_t ld);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_WARN_RESULT OS_NONNULL1
+long long
+launch_data_get_integer(const launch_data_t ld);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_WARN_RESULT OS_NONNULL1
+bool
+launch_data_get_bool(const launch_data_t ld);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_WARN_RESULT OS_NONNULL1
+double
+launch_data_get_real(const launch_data_t ld);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_WARN_RESULT OS_NONNULL1
+const char *
+launch_data_get_string(const launch_data_t ld);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_WARN_RESULT OS_NONNULL1
+void *
+launch_data_get_opaque(const launch_data_t ld);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_WARN_RESULT OS_NONNULL1
+size_t
+launch_data_get_opaque_size(const launch_data_t ld);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_WARN_RESULT OS_NONNULL1
+int
+launch_data_get_errno(const launch_data_t ld);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_WARN_RESULT
+int
+launch_get_fd(void);
+
+__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0)
+OS_EXPORT OS_MALLOC OS_WARN_RESULT OS_NONNULL1
+launch_data_t
+launch_msg(const launch_data_t request);
+
+__END_DECLS
+#if __has_feature(assume_nonnull)
+_Pragma("clang assume_nonnull end")
+#endif
+
+#endif // __XPC_LAUNCH_H__

+ 226 - 0
Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/mach/jailbreak_daemonServer.c

@@ -0,0 +1,226 @@
+/*
+ * IDENTIFICATION:
+ * stub generated Thu Mar  8 12:11:20 2018
+ * with a MiG generated by bootstrap_cmds-96.20.2
+ * OPTIONS: 
+ */
+
+/* Module jailbreak_daemon */
+
+#define	__MIG_check__Request__jailbreak_daemon_subsystem__ 1
+
+#include "jailbreak_daemonServer.h"
+
+#ifndef	mig_internal
+#define	mig_internal	static __inline__
+#endif	/* mig_internal */
+
+#ifndef	mig_external
+#define mig_external
+#endif	/* mig_external */
+
+#if	!defined(__MigTypeCheck) && defined(TypeCheck)
+#define	__MigTypeCheck		TypeCheck	/* Legacy setting */
+#endif	/* !defined(__MigTypeCheck) */
+
+#if	!defined(__MigKernelSpecificCode) && defined(_MIG_KERNEL_SPECIFIC_CODE_)
+#define	__MigKernelSpecificCode	_MIG_KERNEL_SPECIFIC_CODE_	/* Legacy setting */
+#endif	/* !defined(__MigKernelSpecificCode) */
+
+#ifndef	LimitCheck
+#define	LimitCheck 0
+#endif	/* LimitCheck */
+
+#ifndef	min
+#define	min(a,b)  ( ((a) < (b))? (a): (b) )
+#endif	/* min */
+
+#if !defined(_WALIGN_)
+#define _WALIGN_(x) (((x) + 3) & ~3)
+#endif /* !defined(_WALIGN_) */
+
+#if !defined(_WALIGNSZ_)
+#define _WALIGNSZ_(x) _WALIGN_(sizeof(x))
+#endif /* !defined(_WALIGNSZ_) */
+
+#ifndef	UseStaticTemplates
+#define	UseStaticTemplates	0
+#endif	/* UseStaticTemplates */
+
+#ifndef	__DeclareRcvRpc
+#define	__DeclareRcvRpc(_NUM_, _NAME_)
+#endif	/* __DeclareRcvRpc */
+
+#ifndef	__BeforeRcvRpc
+#define	__BeforeRcvRpc(_NUM_, _NAME_)
+#endif	/* __BeforeRcvRpc */
+
+#ifndef	__AfterRcvRpc
+#define	__AfterRcvRpc(_NUM_, _NAME_)
+#endif	/* __AfterRcvRpc */
+
+#ifndef	__DeclareRcvSimple
+#define	__DeclareRcvSimple(_NUM_, _NAME_)
+#endif	/* __DeclareRcvSimple */
+
+#ifndef	__BeforeRcvSimple
+#define	__BeforeRcvSimple(_NUM_, _NAME_)
+#endif	/* __BeforeRcvSimple */
+
+#ifndef	__AfterRcvSimple
+#define	__AfterRcvSimple(_NUM_, _NAME_)
+#endif	/* __AfterRcvSimple */
+
+#define novalue void
+
+#define msgh_request_port	msgh_local_port
+#define MACH_MSGH_BITS_REQUEST(bits)	MACH_MSGH_BITS_LOCAL(bits)
+#define msgh_reply_port		msgh_remote_port
+#define MACH_MSGH_BITS_REPLY(bits)	MACH_MSGH_BITS_REMOTE(bits)
+
+#define MIG_RETURN_ERROR(X, code)	{\
+				((mig_reply_error_t *)X)->RetCode = code;\
+				((mig_reply_error_t *)X)->NDR = NDR_record;\
+				return;\
+				}
+
+/* Forward Declarations */
+
+
+mig_internal novalue _Xcall
+	(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP);
+
+
+#if ( __MigTypeCheck )
+#if __MIG_check__Request__jailbreak_daemon_subsystem__
+#if !defined(__MIG_check__Request__call_t__defined)
+#define __MIG_check__Request__call_t__defined
+
+mig_internal kern_return_t __MIG_check__Request__call_t(__attribute__((__unused__)) __Request__call_t *In0P)
+{
+
+	typedef __Request__call_t __Request;
+#if	__MigTypeCheck
+	if ((In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||
+	    (In0P->Head.msgh_size != (mach_msg_size_t)sizeof(__Request)))
+		return MIG_BAD_ARGUMENTS;
+#endif	/* __MigTypeCheck */
+
+	return MACH_MSG_SUCCESS;
+}
+#endif /* !defined(__MIG_check__Request__call_t__defined) */
+#endif /* __MIG_check__Request__jailbreak_daemon_subsystem__ */
+#endif /* ( __MigTypeCheck ) */
+
+
+/* Routine call */
+mig_internal novalue _Xcall
+	(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)
+{
+
+#ifdef  __MigPackStructs
+#pragma pack(4)
+#endif
+	typedef struct {
+		mach_msg_header_t Head;
+		NDR_record_t NDR;
+		uint8_t command;
+		char commandPad[3];
+		uint32_t pid;
+		mach_msg_trailer_t trailer;
+	} Request __attribute__((unused));
+#ifdef  __MigPackStructs
+#pragma pack()
+#endif
+	typedef __Request__call_t __Request;
+	typedef __Reply__call_t Reply __attribute__((unused));
+
+	/*
+	 * typedef struct {
+	 * 	mach_msg_header_t Head;
+	 * 	NDR_record_t NDR;
+	 * 	kern_return_t RetCode;
+	 * } mig_reply_error_t;
+	 */
+
+	Request *In0P = (Request *) InHeadP;
+	Reply *OutP = (Reply *) OutHeadP;
+#ifdef	__MIG_check__Request__call_t__defined
+	kern_return_t check_result;
+#endif	/* __MIG_check__Request__call_t__defined */
+
+	__DeclareRcvRpc(500, "call")
+	__BeforeRcvRpc(500, "call")
+
+#if	defined(__MIG_check__Request__call_t__defined)
+	check_result = __MIG_check__Request__call_t((__Request *)In0P);
+	if (check_result != MACH_MSG_SUCCESS)
+		{ MIG_RETURN_ERROR(OutP, check_result); }
+#endif	/* defined(__MIG_check__Request__call_t__defined) */
+
+	OutP->RetCode = jbd_call(In0P->Head.msgh_request_port, In0P->command, In0P->pid);
+
+	OutP->NDR = NDR_record;
+
+
+	__AfterRcvRpc(500, "call")
+}
+
+
+
+/* Description of this subsystem, for use in direct RPC */
+const struct jbd_jailbreak_daemon_subsystem jbd_jailbreak_daemon_subsystem = {
+	jailbreak_daemon_server_routine,
+	500,
+	501,
+	(mach_msg_size_t)sizeof(union __ReplyUnion__jbd_jailbreak_daemon_subsystem),
+	(vm_address_t)0,
+	{
+          { (mig_impl_routine_t) 0,
+          (mig_stub_routine_t) _Xcall, 3, 0, (routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply__call_t)},
+	}
+};
+
+mig_external boolean_t jailbreak_daemon_server
+	(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)
+{
+	/*
+	 * typedef struct {
+	 * 	mach_msg_header_t Head;
+	 * 	NDR_record_t NDR;
+	 * 	kern_return_t RetCode;
+	 * } mig_reply_error_t;
+	 */
+
+	register mig_routine_t routine;
+
+	OutHeadP->msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REPLY(InHeadP->msgh_bits), 0);
+	OutHeadP->msgh_remote_port = InHeadP->msgh_reply_port;
+	/* Minimal size: routine() will update it if different */
+	OutHeadP->msgh_size = (mach_msg_size_t)sizeof(mig_reply_error_t);
+	OutHeadP->msgh_local_port = MACH_PORT_NULL;
+	OutHeadP->msgh_id = InHeadP->msgh_id + 100;
+	OutHeadP->msgh_reserved = 0;
+
+	if ((InHeadP->msgh_id > 500) || (InHeadP->msgh_id < 500) ||
+	    ((routine = jbd_jailbreak_daemon_subsystem.routine[InHeadP->msgh_id - 500].stub_routine) == 0)) {
+		((mig_reply_error_t *)OutHeadP)->NDR = NDR_record;
+		((mig_reply_error_t *)OutHeadP)->RetCode = MIG_BAD_ID;
+		return FALSE;
+	}
+	(*routine) (InHeadP, OutHeadP);
+	return TRUE;
+}
+
+mig_external mig_routine_t jailbreak_daemon_server_routine
+	(mach_msg_header_t *InHeadP)
+{
+	register int msgh_id;
+
+	msgh_id = InHeadP->msgh_id - 500;
+
+	if ((msgh_id > 0) || (msgh_id < 0))
+		return 0;
+
+	return jbd_jailbreak_daemon_subsystem.routine[msgh_id].stub_routine;
+}

+ 198 - 0
Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/mach/jailbreak_daemonServer.h

@@ -0,0 +1,198 @@
+#ifndef	_jailbreak_daemon_server_
+#define	_jailbreak_daemon_server_
+
+/* Module jailbreak_daemon */
+
+#include <string.h>
+#include <mach/ndr.h>
+#include <mach/boolean.h>
+#include <mach/kern_return.h>
+#include <mach/notify.h>
+#include <mach/mach_types.h>
+#include <mach/message.h>
+#include <mach/mig_errors.h>
+#include <mach/port.h>
+	
+/* BEGIN VOUCHER CODE */
+
+#ifndef KERNEL
+#if defined(__has_include)
+#if __has_include(<mach/mig_voucher_support.h>)
+#ifndef USING_VOUCHERS
+#define USING_VOUCHERS
+#endif
+#ifndef __VOUCHER_FORWARD_TYPE_DECLS__
+#define __VOUCHER_FORWARD_TYPE_DECLS__
+#ifdef __cplusplus
+extern "C" {
+#endif
+	extern boolean_t voucher_mach_msg_set(mach_msg_header_t *msg) __attribute__((weak_import));
+#ifdef __cplusplus
+}
+#endif
+#endif // __VOUCHER_FORWARD_TYPE_DECLS__
+#endif // __has_include(<mach/mach_voucher_types.h>)
+#endif // __has_include
+#endif // !KERNEL
+	
+/* END VOUCHER CODE */
+
+	
+/* BEGIN MIG_STRNCPY_ZEROFILL CODE */
+
+#if defined(__has_include)
+#if __has_include(<mach/mig_strncpy_zerofill_support.h>)
+#ifndef USING_MIG_STRNCPY_ZEROFILL
+#define USING_MIG_STRNCPY_ZEROFILL
+#endif
+#ifndef __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__
+#define __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__
+#ifdef __cplusplus
+extern "C" {
+#endif
+	extern int mig_strncpy_zerofill(char *dest, const char *src, int len) __attribute__((weak_import));
+#ifdef __cplusplus
+}
+#endif
+#endif /* __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__ */
+#endif /* __has_include(<mach/mig_strncpy_zerofill_support.h>) */
+#endif /* __has_include */
+	
+/* END MIG_STRNCPY_ZEROFILL CODE */
+
+
+#ifdef AUTOTEST
+#ifndef FUNCTION_PTR_T
+#define FUNCTION_PTR_T
+typedef void (*function_ptr_t)(mach_port_t, char *, mach_msg_type_number_t);
+typedef struct {
+        char            *name;
+        function_ptr_t  function;
+} function_table_entry;
+typedef function_table_entry   *function_table_t;
+#endif /* FUNCTION_PTR_T */
+#endif /* AUTOTEST */
+
+#ifndef	jailbreak_daemon_MSG_COUNT
+#define	jailbreak_daemon_MSG_COUNT	1
+#endif	/* jailbreak_daemon_MSG_COUNT */
+
+#include <mach/std_types.h>
+#include <mach/mig.h>
+#include <mach/mig.h>
+#include <mach/mach_types.h>
+
+#ifdef __BeforeMigServerHeader
+__BeforeMigServerHeader
+#endif /* __BeforeMigServerHeader */
+
+
+/* Routine call */
+#ifdef	mig_external
+mig_external
+#else
+extern
+#endif	/* mig_external */
+kern_return_t jbd_call
+(
+	mach_port_t server_port,
+	uint8_t command,
+	uint32_t pid
+);
+
+#ifdef	mig_external
+mig_external
+#else
+extern
+#endif	/* mig_external */
+boolean_t jailbreak_daemon_server(
+		mach_msg_header_t *InHeadP,
+		mach_msg_header_t *OutHeadP);
+
+#ifdef	mig_external
+mig_external
+#else
+extern
+#endif	/* mig_external */
+mig_routine_t jailbreak_daemon_server_routine(
+		mach_msg_header_t *InHeadP);
+
+
+/* Description of this subsystem, for use in direct RPC */
+extern const struct jbd_jailbreak_daemon_subsystem {
+	mig_server_routine_t	server;	/* Server routine */
+	mach_msg_id_t	start;	/* Min routine number */
+	mach_msg_id_t	end;	/* Max routine number + 1 */
+	unsigned int	maxsize;	/* Max msg size */
+	vm_address_t	reserved;	/* Reserved */
+	struct routine_descriptor	/*Array of routine descriptors */
+		routine[1];
+} jbd_jailbreak_daemon_subsystem;
+
+/* typedefs for all requests */
+
+#ifndef __Request__jailbreak_daemon_subsystem__defined
+#define __Request__jailbreak_daemon_subsystem__defined
+
+#ifdef  __MigPackStructs
+#pragma pack(4)
+#endif
+	typedef struct {
+		mach_msg_header_t Head;
+		NDR_record_t NDR;
+		uint8_t command;
+		char commandPad[3];
+		uint32_t pid;
+	} __Request__call_t __attribute__((unused));
+#ifdef  __MigPackStructs
+#pragma pack()
+#endif
+#endif /* !__Request__jailbreak_daemon_subsystem__defined */
+
+
+/* union of all requests */
+
+#ifndef __RequestUnion__jbd_jailbreak_daemon_subsystem__defined
+#define __RequestUnion__jbd_jailbreak_daemon_subsystem__defined
+union __RequestUnion__jbd_jailbreak_daemon_subsystem {
+	__Request__call_t Request_call;
+};
+#endif /* __RequestUnion__jbd_jailbreak_daemon_subsystem__defined */
+/* typedefs for all replies */
+
+#ifndef __Reply__jailbreak_daemon_subsystem__defined
+#define __Reply__jailbreak_daemon_subsystem__defined
+
+#ifdef  __MigPackStructs
+#pragma pack(4)
+#endif
+	typedef struct {
+		mach_msg_header_t Head;
+		NDR_record_t NDR;
+		kern_return_t RetCode;
+	} __Reply__call_t __attribute__((unused));
+#ifdef  __MigPackStructs
+#pragma pack()
+#endif
+#endif /* !__Reply__jailbreak_daemon_subsystem__defined */
+
+
+/* union of all replies */
+
+#ifndef __ReplyUnion__jbd_jailbreak_daemon_subsystem__defined
+#define __ReplyUnion__jbd_jailbreak_daemon_subsystem__defined
+union __ReplyUnion__jbd_jailbreak_daemon_subsystem {
+	__Reply__call_t Reply_call;
+};
+#endif /* __RequestUnion__jbd_jailbreak_daemon_subsystem__defined */
+
+#ifndef subsystem_to_name_map_jailbreak_daemon
+#define subsystem_to_name_map_jailbreak_daemon \
+    { "call", 500 }
+#endif
+
+#ifdef __AfterMigServerHeader
+__AfterMigServerHeader
+#endif /* __AfterMigServerHeader */
+
+#endif	 /* _jailbreak_daemon_server_ */

+ 249 - 0
Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/mach/jailbreak_daemonUser.c

@@ -0,0 +1,249 @@
+/*
+ * IDENTIFICATION:
+ * stub generated Thu Mar  8 12:11:20 2018
+ * with a MiG generated by bootstrap_cmds-96.20.2
+ * OPTIONS: 
+ */
+#define	__MIG_check__Reply__jailbreak_daemon_subsystem__ 1
+
+#include "jailbreak_daemonUser.h"
+
+
+#ifndef	mig_internal
+#define	mig_internal	static __inline__
+#endif	/* mig_internal */
+
+#ifndef	mig_external
+#define mig_external
+#endif	/* mig_external */
+
+#if	!defined(__MigTypeCheck) && defined(TypeCheck)
+#define	__MigTypeCheck		TypeCheck	/* Legacy setting */
+#endif	/* !defined(__MigTypeCheck) */
+
+#if	!defined(__MigKernelSpecificCode) && defined(_MIG_KERNEL_SPECIFIC_CODE_)
+#define	__MigKernelSpecificCode	_MIG_KERNEL_SPECIFIC_CODE_	/* Legacy setting */
+#endif	/* !defined(__MigKernelSpecificCode) */
+
+#ifndef	LimitCheck
+#define	LimitCheck 0
+#endif	/* LimitCheck */
+
+#ifndef	min
+#define	min(a,b)  ( ((a) < (b))? (a): (b) )
+#endif	/* min */
+
+#if !defined(_WALIGN_)
+#define _WALIGN_(x) (((x) + 3) & ~3)
+#endif /* !defined(_WALIGN_) */
+
+#if !defined(_WALIGNSZ_)
+#define _WALIGNSZ_(x) _WALIGN_(sizeof(x))
+#endif /* !defined(_WALIGNSZ_) */
+
+#ifndef	UseStaticTemplates
+#define	UseStaticTemplates	0
+#endif	/* UseStaticTemplates */
+
+#ifndef	__MachMsgErrorWithTimeout
+#define	__MachMsgErrorWithTimeout(_R_) { \
+	switch (_R_) { \
+	case MACH_SEND_INVALID_DATA: \
+	case MACH_SEND_INVALID_DEST: \
+	case MACH_SEND_INVALID_HEADER: \
+		mig_put_reply_port(InP->Head.msgh_reply_port); \
+		break; \
+	case MACH_SEND_TIMED_OUT: \
+	case MACH_RCV_TIMED_OUT: \
+	default: \
+		mig_dealloc_reply_port(InP->Head.msgh_reply_port); \
+	} \
+}
+#endif	/* __MachMsgErrorWithTimeout */
+
+#ifndef	__MachMsgErrorWithoutTimeout
+#define	__MachMsgErrorWithoutTimeout(_R_) { \
+	switch (_R_) { \
+	case MACH_SEND_INVALID_DATA: \
+	case MACH_SEND_INVALID_DEST: \
+	case MACH_SEND_INVALID_HEADER: \
+		mig_put_reply_port(InP->Head.msgh_reply_port); \
+		break; \
+	default: \
+		mig_dealloc_reply_port(InP->Head.msgh_reply_port); \
+	} \
+}
+#endif	/* __MachMsgErrorWithoutTimeout */
+
+#ifndef	__DeclareSendRpc
+#define	__DeclareSendRpc(_NUM_, _NAME_)
+#endif	/* __DeclareSendRpc */
+
+#ifndef	__BeforeSendRpc
+#define	__BeforeSendRpc(_NUM_, _NAME_)
+#endif	/* __BeforeSendRpc */
+
+#ifndef	__AfterSendRpc
+#define	__AfterSendRpc(_NUM_, _NAME_)
+#endif	/* __AfterSendRpc */
+
+#ifndef	__DeclareSendSimple
+#define	__DeclareSendSimple(_NUM_, _NAME_)
+#endif	/* __DeclareSendSimple */
+
+#ifndef	__BeforeSendSimple
+#define	__BeforeSendSimple(_NUM_, _NAME_)
+#endif	/* __BeforeSendSimple */
+
+#ifndef	__AfterSendSimple
+#define	__AfterSendSimple(_NUM_, _NAME_)
+#endif	/* __AfterSendSimple */
+
+#define msgh_request_port	msgh_remote_port
+#define msgh_reply_port		msgh_local_port
+
+
+
+#if ( __MigTypeCheck )
+#if __MIG_check__Reply__jailbreak_daemon_subsystem__
+#if !defined(__MIG_check__Reply__call_t__defined)
+#define __MIG_check__Reply__call_t__defined
+
+mig_internal kern_return_t __MIG_check__Reply__call_t(__Reply__call_t *Out0P)
+{
+
+	typedef __Reply__call_t __Reply __attribute__((unused));
+	if (Out0P->Head.msgh_id != 600) {
+	    if (Out0P->Head.msgh_id == MACH_NOTIFY_SEND_ONCE)
+		{ return MIG_SERVER_DIED; }
+	    else
+		{ return MIG_REPLY_MISMATCH; }
+	}
+
+#if	__MigTypeCheck
+	if ((Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||
+	    (Out0P->Head.msgh_size != (mach_msg_size_t)sizeof(__Reply)))
+		{ return MIG_TYPE_ERROR ; }
+#endif	/* __MigTypeCheck */
+
+	{
+		return Out0P->RetCode;
+	}
+}
+#endif /* !defined(__MIG_check__Reply__call_t__defined) */
+#endif /* __MIG_check__Reply__jailbreak_daemon_subsystem__ */
+#endif /* ( __MigTypeCheck ) */
+
+
+/* Routine call */
+mig_external kern_return_t jbd_call
+(
+	mach_port_t server_port,
+	uint8_t command,
+	uint32_t pid
+)
+{
+
+#ifdef  __MigPackStructs
+#pragma pack(4)
+#endif
+	typedef struct {
+		mach_msg_header_t Head;
+		NDR_record_t NDR;
+		uint8_t command;
+		char commandPad[3];
+		uint32_t pid;
+	} Request __attribute__((unused));
+#ifdef  __MigPackStructs
+#pragma pack()
+#endif
+
+#ifdef  __MigPackStructs
+#pragma pack(4)
+#endif
+	typedef struct {
+		mach_msg_header_t Head;
+		NDR_record_t NDR;
+		kern_return_t RetCode;
+		mach_msg_trailer_t trailer;
+	} Reply __attribute__((unused));
+#ifdef  __MigPackStructs
+#pragma pack()
+#endif
+
+#ifdef  __MigPackStructs
+#pragma pack(4)
+#endif
+	typedef struct {
+		mach_msg_header_t Head;
+		NDR_record_t NDR;
+		kern_return_t RetCode;
+	} __Reply __attribute__((unused));
+#ifdef  __MigPackStructs
+#pragma pack()
+#endif
+	/*
+	 * typedef struct {
+	 * 	mach_msg_header_t Head;
+	 * 	NDR_record_t NDR;
+	 * 	kern_return_t RetCode;
+	 * } mig_reply_error_t;
+	 */
+
+	union {
+		Request In;
+		Reply Out;
+	} Mess;
+
+	Request *InP = &Mess.In;
+	Reply *Out0P = &Mess.Out;
+
+	mach_msg_return_t msg_result;
+
+#ifdef	__MIG_check__Reply__call_t__defined
+	kern_return_t check_result;
+#endif	/* __MIG_check__Reply__call_t__defined */
+
+	__DeclareSendRpc(500, "call")
+
+	InP->NDR = NDR_record;
+
+	InP->command = command;
+
+	InP->pid = pid;
+
+	InP->Head.msgh_bits =
+		MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);
+	/* msgh_size passed as argument */
+	InP->Head.msgh_request_port = server_port;
+	InP->Head.msgh_reply_port = mig_get_reply_port();
+	InP->Head.msgh_id = 500;
+	InP->Head.msgh_reserved = 0;
+	
+/* BEGIN VOUCHER CODE */
+
+#ifdef USING_VOUCHERS
+	if (voucher_mach_msg_set != NULL) {
+		voucher_mach_msg_set(&InP->Head);
+	}
+#endif // USING_VOUCHERS
+	
+/* END VOUCHER CODE */
+
+	__BeforeSendRpc(500, "call")
+	msg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, (mach_msg_size_t)sizeof(Request), (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+	__AfterSendRpc(500, "call")
+	if (msg_result != MACH_MSG_SUCCESS) {
+		__MachMsgErrorWithoutTimeout(msg_result);
+		{ return msg_result; }
+	}
+
+
+#if	defined(__MIG_check__Reply__call_t__defined)
+	check_result = __MIG_check__Reply__call_t((__Reply__call_t *)Out0P);
+	if (check_result != MACH_MSG_SUCCESS)
+		{ return check_result; }
+#endif	/* defined(__MIG_check__Reply__call_t__defined) */
+
+	return KERN_SUCCESS;
+}

+ 183 - 0
Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/mach/jailbreak_daemonUser.h

@@ -0,0 +1,183 @@
+#ifndef	_jailbreak_daemon_user_
+#define	_jailbreak_daemon_user_
+
+/* Module jailbreak_daemon */
+
+#include <string.h>
+#include <mach/ndr.h>
+#include <mach/boolean.h>
+#include <mach/kern_return.h>
+#include <mach/notify.h>
+#include <mach/mach_types.h>
+#include <mach/message.h>
+#include <mach/mig_errors.h>
+#include <mach/port.h>
+	
+/* BEGIN VOUCHER CODE */
+
+#ifndef KERNEL
+#if defined(__has_include)
+#if __has_include(<mach/mig_voucher_support.h>)
+#ifndef USING_VOUCHERS
+#define USING_VOUCHERS
+#endif
+#ifndef __VOUCHER_FORWARD_TYPE_DECLS__
+#define __VOUCHER_FORWARD_TYPE_DECLS__
+#ifdef __cplusplus
+extern "C" {
+#endif
+	extern boolean_t voucher_mach_msg_set(mach_msg_header_t *msg) __attribute__((weak_import));
+#ifdef __cplusplus
+}
+#endif
+#endif // __VOUCHER_FORWARD_TYPE_DECLS__
+#endif // __has_include(<mach/mach_voucher_types.h>)
+#endif // __has_include
+#endif // !KERNEL
+	
+/* END VOUCHER CODE */
+
+	
+/* BEGIN MIG_STRNCPY_ZEROFILL CODE */
+
+#if defined(__has_include)
+#if __has_include(<mach/mig_strncpy_zerofill_support.h>)
+#ifndef USING_MIG_STRNCPY_ZEROFILL
+#define USING_MIG_STRNCPY_ZEROFILL
+#endif
+#ifndef __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__
+#define __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__
+#ifdef __cplusplus
+extern "C" {
+#endif
+	extern int mig_strncpy_zerofill(char *dest, const char *src, int len) __attribute__((weak_import));
+#ifdef __cplusplus
+}
+#endif
+#endif /* __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__ */
+#endif /* __has_include(<mach/mig_strncpy_zerofill_support.h>) */
+#endif /* __has_include */
+	
+/* END MIG_STRNCPY_ZEROFILL CODE */
+
+
+#ifdef AUTOTEST
+#ifndef FUNCTION_PTR_T
+#define FUNCTION_PTR_T
+typedef void (*function_ptr_t)(mach_port_t, char *, mach_msg_type_number_t);
+typedef struct {
+        char            *name;
+        function_ptr_t  function;
+} function_table_entry;
+typedef function_table_entry   *function_table_t;
+#endif /* FUNCTION_PTR_T */
+#endif /* AUTOTEST */
+
+#ifndef	jailbreak_daemon_MSG_COUNT
+#define	jailbreak_daemon_MSG_COUNT	1
+#endif	/* jailbreak_daemon_MSG_COUNT */
+
+#include <mach/std_types.h>
+#include <mach/mig.h>
+#include <mach/mig.h>
+#include <mach/mach_types.h>
+
+#ifdef __BeforeMigUserHeader
+__BeforeMigUserHeader
+#endif /* __BeforeMigUserHeader */
+
+#include <sys/cdefs.h>
+__BEGIN_DECLS
+
+
+/* Routine call */
+#ifdef	mig_external
+mig_external
+#else
+extern
+#endif	/* mig_external */
+kern_return_t jbd_call
+(
+	mach_port_t server_port,
+	uint8_t command,
+	uint32_t pid
+);
+
+__END_DECLS
+
+/********************** Caution **************************/
+/* The following data types should be used to calculate  */
+/* maximum message sizes only. The actual message may be */
+/* smaller, and the position of the arguments within the */
+/* message layout may vary from what is presented here.  */
+/* For example, if any of the arguments are variable-    */
+/* sized, and less than the maximum is sent, the data    */
+/* will be packed tight in the actual message to reduce  */
+/* the presence of holes.                                */
+/********************** Caution **************************/
+
+/* typedefs for all requests */
+
+#ifndef __Request__jailbreak_daemon_subsystem__defined
+#define __Request__jailbreak_daemon_subsystem__defined
+
+#ifdef  __MigPackStructs
+#pragma pack(4)
+#endif
+	typedef struct {
+		mach_msg_header_t Head;
+		NDR_record_t NDR;
+		uint8_t command;
+		char commandPad[3];
+		uint32_t pid;
+	} __Request__call_t __attribute__((unused));
+#ifdef  __MigPackStructs
+#pragma pack()
+#endif
+#endif /* !__Request__jailbreak_daemon_subsystem__defined */
+
+/* union of all requests */
+
+#ifndef __RequestUnion__jbd_jailbreak_daemon_subsystem__defined
+#define __RequestUnion__jbd_jailbreak_daemon_subsystem__defined
+union __RequestUnion__jbd_jailbreak_daemon_subsystem {
+	__Request__call_t Request_jbd_call;
+};
+#endif /* !__RequestUnion__jbd_jailbreak_daemon_subsystem__defined */
+/* typedefs for all replies */
+
+#ifndef __Reply__jailbreak_daemon_subsystem__defined
+#define __Reply__jailbreak_daemon_subsystem__defined
+
+#ifdef  __MigPackStructs
+#pragma pack(4)
+#endif
+	typedef struct {
+		mach_msg_header_t Head;
+		NDR_record_t NDR;
+		kern_return_t RetCode;
+	} __Reply__call_t __attribute__((unused));
+#ifdef  __MigPackStructs
+#pragma pack()
+#endif
+#endif /* !__Reply__jailbreak_daemon_subsystem__defined */
+
+/* union of all replies */
+
+#ifndef __ReplyUnion__jbd_jailbreak_daemon_subsystem__defined
+#define __ReplyUnion__jbd_jailbreak_daemon_subsystem__defined
+union __ReplyUnion__jbd_jailbreak_daemon_subsystem {
+	__Reply__call_t Reply_jbd_call;
+};
+#endif /* !__RequestUnion__jbd_jailbreak_daemon_subsystem__defined */
+
+#ifndef subsystem_to_name_map_jailbreak_daemon
+#define subsystem_to_name_map_jailbreak_daemon \
+    { "call", 500 }
+#endif
+
+#ifdef __AfterMigUserHeader
+__AfterMigUserHeader
+#endif /* __AfterMigUserHeader */
+
+#endif	 /* _jailbreak_daemon_user_ */

+ 12 - 0
Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/mach/mig.defs

@@ -0,0 +1,12 @@
+// mig -sheader jailbreak_daemonServer.h -header jailbreak_daemonUser.h mig.defs
+
+subsystem jailbreak_daemon 500;
+userprefix jbd_;
+serverprefix jbd_;
+
+#include <mach/std_types.defs>
+#include <mach/mach_types.defs>
+
+routine call(server_port : mach_port_t;
+             in command: uint8_t;
+             in pid: uint32_t);

+ 216 - 0
Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/main.m

@@ -0,0 +1,216 @@
+#import <Foundation/Foundation.h>
+#import <os/log.h>
+#include <pthread.h>
+#include <mach/mach.h>
+#include <mach/error.h>
+#include <mach/message.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "kexecute.h"
+#include "kern_utils.h"
+#include "patchfinder64.h"
+#include "mach/jailbreak_daemonServer.h"
+
+#define JAILBREAKDDEBUG 1
+
+#define CS_OPS_STATUS       0   /* return status */
+
+#define CS_GET_TASK_ALLOW    0x0000004    /* has get-task-allow entitlement */
+#define CS_INSTALLER        0x0000008    /* has installer entitlement */
+
+#define    CS_HARD            0x0000100    /* don't load invalid pages */
+#define    CS_KILL            0x0000200    /* kill process if it becomes invalid */
+#define CS_RESTRICT        0x0000800    /* tell dyld to treat restricted */
+
+#define CS_PLATFORM_BINARY    0x4000000    /* this is a platform binary */
+
+#define CS_DEBUGGED         0x10000000  /* process is currently or has previously been debugged and allowed to run with invalid pages */
+
+int csops(pid_t pid, unsigned int  ops, void * useraddr, size_t usersize);
+
+#define PROC_PIDPATHINFO_MAXSIZE  (1024)
+int proc_pidpath(pid_t pid, void *buffer, uint32_t buffersize);
+
+typedef boolean_t (*dispatch_mig_callback_t)(mach_msg_header_t *message, mach_msg_header_t *reply);
+mach_msg_return_t dispatch_mig_server(dispatch_source_t ds, size_t maxmsgsz, dispatch_mig_callback_t callback);
+kern_return_t bootstrap_check_in(mach_port_t bootstrap_port, const char *service, mach_port_t *server_port);
+
+#define MEMORYSTATUS_CMD_SET_JETSAM_TASK_LIMIT 6
+int memorystatus_control(uint32_t command, int32_t pid, uint32_t flags, void *buffer, size_t buffersize);
+
+int remove_memory_limit(void) {
+    // daemons run under launchd have a very stingy memory limit by default, we need
+    // quite a bit more for patchfinder so disable it here
+    // (note that we need the com.apple.private.memorystatus entitlement to do so)
+    pid_t my_pid = getpid();
+    return memorystatus_control(MEMORYSTATUS_CMD_SET_JETSAM_TASK_LIMIT, my_pid, 0, NULL, 0);
+}
+
+#define JAILBREAKD_COMMAND_ENTITLE 1
+#define JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT 2
+#define JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT_FROM_XPCPROXY 3
+#define JAILBREAKD_COMMAND_FIXUP_SETUID 4
+
+int is_valid_command(uint8_t command) {
+    return (command == JAILBREAKD_COMMAND_ENTITLE ||
+            command == JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT ||
+            command == JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT_FROM_XPCPROXY ||
+            command == JAILBREAKD_COMMAND_FIXUP_SETUID);
+}
+
+int handle_command(uint8_t command, uint32_t pid) {
+    if (!is_valid_command(command)) {
+        fprintf(stderr,"Invalid command recieved.\n");
+        return 1;
+    }
+    
+    if (command == JAILBREAKD_COMMAND_ENTITLE) {
+#ifdef JAILBREAKDDEBUG
+        fprintf(stderr,"JAILBREAKD_COMMAND_ENTITLE PID: %d\n", pid);
+#endif
+        setcsflagsandplatformize(pid);
+    }
+    
+    if (command == JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT) {
+#ifdef JAILBREAKDDEBUG
+        fprintf(stderr,"JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT PID: %d\n", pid);
+#endif
+        setcsflagsandplatformize(pid);
+        kill(pid, SIGCONT);
+    }
+    
+    if (command == JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT_FROM_XPCPROXY) {
+#ifdef JAILBREAKDDEBUG
+        fprintf(stderr,"JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT_FROM_XPCPROXY PID: %d\n", pid);
+#endif
+        __block int PID = pid;
+        
+        dispatch_queue_t queue = dispatch_queue_create("org.coolstar.jailbreakd.delayqueue", NULL);
+        dispatch_async(queue, ^{
+            char pathbuf[PROC_PIDPATHINFO_MAXSIZE];
+            bzero(pathbuf, sizeof(pathbuf));
+            
+            int tries = 0;
+            int ret = proc_pidpath(PID, pathbuf, sizeof(pathbuf));
+            while (ret > 0 && strcmp(pathbuf, "/usr/libexec/xpcproxy") == 0 && tries < 5000){
+                proc_pidpath(PID, pathbuf, sizeof(pathbuf));
+                usleep(100);
+                tries++;
+            }
+            if (tries >= 5000){
+                fprintf(stderr, "Warning: xpcproxy timer timed out for PID %d\n", pid);
+            }
+            
+            uint32_t flags;
+            csops(pid, CS_OPS_STATUS, &flags, 0);
+#ifdef JAILBREAKDDEBUG
+            fprintf(stderr, "Waiting for CSFlags to reset for PID %d...\n", pid);
+#endif
+            
+            tries = 0;
+            while ((flags & (CS_PLATFORM_BINARY | CS_INSTALLER | CS_GET_TASK_ALLOW | CS_DEBUGGED)) != 0 &&
+                   (flags & (CS_RESTRICT | CS_HARD | CS_KILL)) == 0 &&
+                   tries < 5000){
+                csops(pid, CS_OPS_STATUS, &flags, 0);
+                usleep(100);
+                tries++;
+            }
+            
+            if (tries >= 5000){
+                fprintf(stderr, "Warning: CSFlag timer timed out for PID %d\n", pid);
+            }
+            
+            setcsflagsandplatformize(PID);
+            kill(PID, SIGCONT);
+#ifdef JAILBREAKDDEBUG
+            fprintf(stderr,"Called SIGCONT on pid %d from ENTITLE_AND_SIGCONT_FROM_XPCPROXY\n", PID);
+#endif
+        });
+        dispatch_release(queue);
+    }
+    
+    if (command == JAILBREAKD_COMMAND_FIXUP_SETUID) {
+#ifdef JAILBREAKDDEBUG
+        fprintf(stderr,"JAILBREAKD_FIXUP_SETUID PID: %d\n", pid);
+#endif
+        fixupsetuid(pid);
+    }
+    return 0;
+}
+
+kern_return_t jbd_call(mach_port_t server_port, uint8_t command, uint32_t pid) {
+#ifdef JAILBREAKDDEBUG
+    fprintf(stderr,"[Mach] New call from %llx: command %x, pid %d\n", server_port, command, pid);
+#endif
+    return (handle_command(command, pid) == 0) ? KERN_SUCCESS : KERN_FAILURE;
+}
+
+mach_port_t tfpzero;
+uint64_t kernel_base;
+uint64_t kernel_slide;
+extern unsigned offsetof_ip_kobject;
+
+int main(int argc, char **argv, char **envp) {
+    fprintf(stderr,"jailbreakd: start\n");
+
+    unlink("/var/run/jailbreakd.pid");
+
+    kernel_base = strtoull(getenv("KernelBase"), NULL, 16);
+    remove_memory_limit();
+
+    kern_return_t err = host_get_special_port(mach_host_self(), HOST_LOCAL_NODE, 4, &tfpzero);
+    if (err != KERN_SUCCESS) {
+        fprintf(stderr,"host_get_special_port 4: %s\n", mach_error_string(err));
+        return 5;
+    }
+
+    init_kernel(kernel_base, NULL);
+    // Get the slide
+    kernel_slide = kernel_base - 0xFFFFFFF007004000;
+    fprintf(stderr,"jailbreakd: slide: 0x%016llx\n", kernel_slide);
+
+    // prime offset caches
+    find_allproc();
+    find_add_x0_x0_0x40_ret();
+    find_OSBoolean_True();
+    find_OSBoolean_False();
+    find_zone_map_ref();
+    find_osunserializexml();
+    find_smalloc();
+    init_kexecute();
+
+    term_kernel();
+    
+    @autoreleasepool {
+        // set up mach stuff
+        mach_port_t server_port;
+        
+        if ((err = bootstrap_check_in(bootstrap_port, "org.coolstar.jailbreakd", &server_port))) {
+            fprintf(stderr,"Failed to check in: %s\n", mach_error_string(err));
+            return -1;
+        }
+        
+        dispatch_source_t server = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, server_port, 0, dispatch_get_main_queue());
+        dispatch_source_set_event_handler(server, ^{
+            dispatch_mig_server(server, jbd_jailbreak_daemon_subsystem.maxsize, jailbreak_daemon_server);
+        });
+        dispatch_resume(server);
+        
+        fprintf(stderr,"it never fails to strike its target, and the wounds it causes do not heal\n");
+        fprintf(stderr,"in other words, MIG is online\n");
+        
+        int fd = open("/var/run/jailbreakd.pid", O_WRONLY | O_CREAT, 0600);
+        char mmmm[8] = {0};
+        int sz = snprintf(mmmm, 8, "%d", getpid());
+        write(fd, mmmm, sz);
+        close(fd);
+        
+        fprintf(stderr,"jailbreakd: dumped pid\n");
+        
+        dispatch_main();
+    }
+
+    return EXIT_FAILURE;
+}

+ 42 - 0
Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/offsetof.c

@@ -0,0 +1,42 @@
+
+unsigned offsetof_p_pid = 0x10;               // proc_t::p_pid
+unsigned offsetof_task = 0x18;                // proc_t::task
+unsigned offsetof_p_uid = 0x30;               // proc_t::p_uid
+unsigned offsetof_p_gid = 0x34;               // proc_t::p_uid
+unsigned offsetof_p_ruid = 0x38;              // proc_t::p_uid
+unsigned offsetof_p_rgid = 0x3c;              // proc_t::p_uid
+unsigned offsetof_p_ucred = 0x100;            // proc_t::p_ucred
+unsigned offsetof_p_csflags = 0x2a8;          // proc_t::p_csflags
+unsigned offsetof_itk_self = 0xD8;            // task_t::itk_self (convert_task_to_port)
+unsigned offsetof_itk_sself = 0xE8;           // task_t::itk_sself (task_get_special_port)
+unsigned offsetof_itk_bootstrap = 0x2b8;      // task_t::itk_bootstrap (task_get_special_port)
+unsigned offsetof_itk_space = 0x308;          // task_t::itk_space
+unsigned offsetof_ip_mscount = 0x9C;          // ipc_port_t::ip_mscount (ipc_port_make_send)
+unsigned offsetof_ip_srights = 0xA0;          // ipc_port_t::ip_srights (ipc_port_make_send)
+unsigned offsetof_ip_kobject = 0x68;          // ipc_port_t::ip_kobject
+unsigned offsetof_p_textvp = 0x248;           // proc_t::p_textvp
+unsigned offsetof_p_textoff = 0x250;          // proc_t::p_textoff
+unsigned offsetof_p_cputype = 0x2c0;          // proc_t::p_cputype
+unsigned offsetof_p_cpu_subtype = 0x2c4;      // proc_t::p_cpu_subtype
+unsigned offsetof_special = 2 * sizeof(long); // host::special
+unsigned offsetof_ipc_space_is_table = 0x20;  // ipc_space::is_table?..
+
+unsigned offsetof_ucred_cr_uid = 0x18;        // ucred::cr_uid
+unsigned offsetof_ucred_cr_ruid = 0x1c;       // ucred::cr_ruid
+unsigned offsetof_ucred_cr_svuid = 0x20;      // ucred::cr_svuid
+
+unsigned offsetof_v_type = 0x70;              // vnode::v_type
+unsigned offsetof_v_id = 0x74;                // vnode::v_id
+unsigned offsetof_v_ubcinfo = 0x78;           // vnode::v_ubcinfo
+
+unsigned offsetof_ubcinfo_csblobs = 0x50;     // ubc_info::csblobs
+
+unsigned offsetof_csb_cputype = 0x8;          // cs_blob::csb_cputype
+unsigned offsetof_csb_flags = 0x12;           // cs_blob::csb_flags
+unsigned offsetof_csb_base_offset = 0x16;     // cs_blob::csb_base_offset
+unsigned offsetof_csb_entitlements_offset = 0x98; // cs_blob::csb_entitlements
+unsigned offsetof_csb_signer_type = 0xA0;     // cs_blob::csb_signer_type
+unsigned offsetof_csb_platform_binary = 0xA4; // cs_blob::csb_platform_binary
+unsigned offsetof_csb_platform_path = 0xA8;   // cs_blob::csb_platform_path
+
+unsigned offsetof_t_flags = 0x3a0; // task::t_flags

+ 41 - 0
Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/offsetof.h

@@ -0,0 +1,41 @@
+extern unsigned offsetof_p_pid;
+extern unsigned offsetof_task;
+extern unsigned offsetof_p_uid;
+extern unsigned offsetof_p_gid;
+extern unsigned offsetof_p_ruid;
+extern unsigned offsetof_p_rgid;
+extern unsigned offsetof_p_ucred;
+extern unsigned offsetof_p_csflags;
+extern unsigned offsetof_itk_self;
+extern unsigned offsetof_itk_sself;
+extern unsigned offsetof_itk_bootstrap;
+extern unsigned offsetof_itk_space;
+extern unsigned offsetof_ip_mscount;
+extern unsigned offsetof_ip_srights;
+extern unsigned offsetof_ip_kobject;
+extern unsigned offsetof_p_textvp;
+extern unsigned offsetof_p_textoff;
+extern unsigned offsetof_p_cputype;
+extern unsigned offsetof_p_cpu_subtype;
+extern unsigned offsetof_special;
+extern unsigned offsetof_ipc_space_is_table;
+
+extern unsigned offsetof_ucred_cr_uid;
+extern unsigned offsetof_ucred_cr_ruid;
+extern unsigned offsetof_ucred_cr_svuid;
+
+extern unsigned offsetof_v_type;
+extern unsigned offsetof_v_id;
+extern unsigned offsetof_v_ubcinfo;
+
+extern unsigned offsetof_ubcinfo_csblobs;
+
+extern unsigned offsetof_csb_cputype;
+extern unsigned offsetof_csb_flags;
+extern unsigned offsetof_csb_base_offset;
+extern unsigned offsetof_csb_entitlements_offset;
+extern unsigned offsetof_csb_signer_type;
+extern unsigned offsetof_csb_platform_binary;
+extern unsigned offsetof_csb_platform_path;
+
+extern unsigned offsetof_t_flags;

+ 168 - 0
Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/osobject.c

@@ -0,0 +1,168 @@
+#include <stdlib.h>
+#include "kexecute.h"
+#include "kmem.h"
+#include "patchfinder64.h"
+#include "osobject.h"
+
+// offsets in vtable:
+static uint32_t off_OSDictionary_SetObjectWithCharP = sizeof(void*) * 0x1F;
+static uint32_t off_OSDictionary_GetObjectWithCharP = sizeof(void*) * 0x26;
+static uint32_t off_OSDictionary_Merge              = sizeof(void*) * 0x23;
+
+static uint32_t off_OSArray_Merge                   = sizeof(void*) * 0x1E;
+static uint32_t off_OSArray_RemoveObject            = sizeof(void*) * 0x20;
+static uint32_t off_OSArray_GetObject               = sizeof(void*) * 0x22;
+
+static uint32_t off_OSObject_Release                = sizeof(void*) * 0x05;
+static uint32_t off_OSObject_GetRetainCount         = sizeof(void*) * 0x03;
+static uint32_t off_OSObject_Retain                 = sizeof(void*) * 0x04;
+
+static uint32_t off_OSString_GetLength              = sizeof(void*) * 0x11;
+
+// 1 on success, 0 on error
+int OSDictionary_SetItem(uint64_t dict, const char *key, uint64_t val) {
+	size_t len = strlen(key) + 1;
+
+	uint64_t ks = kalloc(len);
+	kwrite(ks, key, len);
+
+	uint64_t vtab = rk64(dict);
+	uint64_t f = rk64(vtab + off_OSDictionary_SetObjectWithCharP);
+
+	int rv = (int) kexecute(f, dict, ks, val, 0, 0, 0, 0);
+
+	kfree(ks, len);
+
+	return rv;
+}
+
+// XXX it can return 0 in lower 32 bits but still be valid
+// fix addr of returned value and check if rk64 gives ptr
+// to vtable addr saved before
+
+// address if exists, 0 if not
+uint64_t _OSDictionary_GetItem(uint64_t dict, const char *key) {
+	size_t len = strlen(key) + 1;
+
+	uint64_t ks = kalloc(len);
+	kwrite(ks, key, len);
+
+	uint64_t vtab = rk64(dict);
+	uint64_t f = rk64(vtab + off_OSDictionary_GetObjectWithCharP);
+
+	int rv = (int) kexecute(f, dict, ks, 0, 0, 0, 0, 0);
+
+	kfree(ks, len);
+
+	return rv;
+}
+
+uint64_t OSDictionary_GetItem(uint64_t dict, const char *key) {
+	uint64_t ret = _OSDictionary_GetItem(dict, key);
+	
+	if (ret != 0) {
+		// XXX can it be not in zalloc?..
+		ret = zm_fix_addr(ret);
+	}
+
+	return ret;
+}
+
+// 1 on success, 0 on error
+int OSDictionary_Merge(uint64_t dict, uint64_t aDict) {
+	uint64_t vtab = rk64(dict);
+	uint64_t f = rk64(vtab + off_OSDictionary_Merge);
+
+	return (int) kexecute(f, dict, aDict, 0, 0, 0, 0, 0);
+}
+
+// 1 on success, 0 on error
+int OSArray_Merge(uint64_t array, uint64_t aArray) {
+	uint64_t vtab = rk64(array);
+	uint64_t f = rk64(vtab + off_OSArray_Merge);
+
+	return (int) kexecute(f, array, aArray, 0, 0, 0, 0, 0);
+}
+
+uint64_t _OSArray_GetObject(uint64_t array, unsigned int idx){
+    uint64_t vtab = rk64(array);
+    uint64_t f = rk64(vtab + off_OSArray_GetObject);
+    
+    return kexecute(f, array, idx, 0, 0, 0, 0, 0);
+}
+
+uint64_t OSArray_GetObject(uint64_t array, unsigned int idx){
+    uint64_t ret = _OSArray_GetObject(array, idx);
+    
+    if (ret != 0){
+        // XXX can it be not in zalloc?..
+        ret = zm_fix_addr(ret);
+    }
+    return ret;
+}
+
+void OSArray_RemoveObject(uint64_t array, unsigned int idx){
+    uint64_t vtab = rk64(array);
+    uint64_t f = rk64(vtab + off_OSArray_RemoveObject);
+    
+    (void)kexecute(f, array, idx, 0, 0, 0, 0, 0);
+}
+
+// XXX error handling just for fun? :)
+uint64_t _OSUnserializeXML(const char* buffer) {
+	size_t len = strlen(buffer) + 1;
+
+	uint64_t ks = kalloc(len);
+	kwrite(ks, buffer, len);
+
+	uint64_t errorptr = 0;
+
+	uint64_t rv = kexecute(find_osunserializexml(), ks, errorptr, 0, 0, 0, 0, 0);
+	kfree(ks, len);
+
+	return rv;
+}
+
+uint64_t OSUnserializeXML(const char* buffer) {
+	uint64_t ret = _OSUnserializeXML(buffer);
+	
+	if (ret != 0) {
+		// XXX can it be not in zalloc?..
+		ret = zm_fix_addr(ret);
+	}
+
+	return ret;
+}
+
+void OSObject_Release(uint64_t osobject) {
+	uint64_t vtab = rk64(osobject);
+	uint64_t f = rk64(vtab + off_OSObject_Release);
+	(void) kexecute(f, osobject, 0, 0, 0, 0, 0, 0);
+}
+
+void OSObject_Retain(uint64_t osobject) {
+	uint64_t vtab = rk64(osobject);
+	uint64_t f = rk64(vtab + off_OSObject_Release);
+	(void) kexecute(f, osobject, 0, 0, 0, 0, 0, 0);
+}
+
+uint32_t OSObject_GetRetainCount(uint64_t osobject) {
+	uint64_t vtab = rk64(osobject);
+	uint64_t f = rk64(vtab + off_OSObject_Release);
+	return (uint32_t) kexecute(f, osobject, 0, 0, 0, 0, 0, 0);
+}
+
+unsigned int OSString_GetLength(uint64_t osstring){
+    uint64_t vtab = rk64(osstring);
+    uint64_t f = rk64(vtab + off_OSString_GetLength);
+    return (unsigned int)kexecute(f, osstring, 0, 0, 0, 0, 0, 0);
+}
+
+char *OSString_CopyString(uint64_t osstring){
+    unsigned int length = OSString_GetLength(osstring);
+    char *str = malloc(length + 1);
+    str[length] = 0;
+    
+    kread(OSString_CStringPtr(osstring), str, length);
+    return str;
+}

+ 24 - 0
Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/osobject.h

@@ -0,0 +1,24 @@
+#define OSDictionary_ItemCount(dict) rk32(dict+20)
+#define OSDictionary_ItemBuffer(dict) rk64(dict+32)
+#define OSDictionary_ItemKey(buffer, idx) rk64(buffer+16*idx)
+#define OSDictionary_ItemValue(buffer, idx) rk64(buffer+16*idx+8)
+#define OSString_CStringPtr(str) rk64(str + 0x10)
+#define OSArray_ItemCount(arr) rk32(arr+0x14)
+#define OSArray_ItemBuffer(arr) rk64(arr+32)
+
+// see osobject.c for info
+
+int OSDictionary_SetItem(uint64_t dict, const char *key, uint64_t val);
+uint64_t OSDictionary_GetItem(uint64_t dict, const char *key);
+int OSDictionary_Merge(uint64_t dict, uint64_t aDict);
+void OSArray_RemoveObject(uint64_t array, unsigned int idx);
+uint64_t OSArray_GetObject(uint64_t array, unsigned int idx);
+int OSArray_Merge(uint64_t array, uint64_t aArray);
+uint64_t OSUnserializeXML(const char* buffer);
+
+void OSObject_Release(uint64_t osobject);
+void OSObject_Retain(uint64_t osobject);
+uint32_t OSObject_GetRetainCount(uint64_t osobject);
+
+unsigned int OSString_GetLength(uint64_t osstring);
+char *OSString_CopyString(uint64_t osstring);

+ 831 - 0
Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/patchfinder64.c

@@ -0,0 +1,831 @@
+//
+//  patchfinder64.c
+//  extra_recipe
+//
+//  Created by xerub on 06/06/2017.
+//  Copyright © 2017 xerub. All rights reserved.
+//
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+#include "patchfinder64.h"
+#include "kmem.h"
+
+#define CACHED_FIND_UINT64(name) CACHED_FIND(uint64_t, name)
+
+typedef uint64_t addr_t;
+
+#define IS64(image) (*(uint8_t *)(image) & 1)
+
+#define MACHO(p) ((*(unsigned int *)(p) & ~1) == 0xfeedface)
+
+/* generic stuff *************************************************************/
+
+#define UCHAR_MAX 255
+
+static unsigned char *
+boyermoore_horspool_memmem(const unsigned char* haystack, size_t hlen,
+                           const unsigned char* needle,   size_t nlen)
+{
+    size_t last, scan = 0;
+    size_t bad_char_skip[UCHAR_MAX + 1]; /* Officially called:
+                                          * bad character shift */
+
+    /* Sanity checks on the parameters */
+    if (nlen <= 0 || !haystack || !needle)
+        return NULL;
+
+    /* ---- Preprocess ---- */
+    /* Initialize the table to default value */
+    /* When a character is encountered that does not occur
+     * in the needle, we can safely skip ahead for the whole
+     * length of the needle.
+     */
+    for (scan = 0; scan <= UCHAR_MAX; scan = scan + 1)
+        bad_char_skip[scan] = nlen;
+
+    /* C arrays have the first byte at [0], therefore:
+     * [nlen - 1] is the last byte of the array. */
+    last = nlen - 1;
+
+    /* Then populate it with the analysis of the needle */
+    for (scan = 0; scan < last; scan = scan + 1)
+        bad_char_skip[needle[scan]] = last - scan;
+
+    /* ---- Do the matching ---- */
+
+    /* Search the haystack, while the needle can still be within it. */
+    while (hlen >= nlen)
+    {
+        /* scan from the end of the needle */
+        for (scan = last; haystack[scan] == needle[scan]; scan = scan - 1)
+            if (scan == 0) /* If the first byte matches, we've found it. */
+                return (void *)haystack;
+
+        /* otherwise, we need to skip some bytes and start again.
+           Note that here we are getting the skip value based on the last byte
+           of needle, no matter where we didn't match. So if needle is: "abcd"
+           then we are skipping based on 'd' and that value will be 4, and
+           for "abcdd" we again skip on 'd' but the value will be only 1.
+           The alternative of pretending that the mismatched character was
+           the last character is slower in the normal case (E.g. finding
+           "abcd" in "...azcd..." gives 4 by using 'd' but only
+           4-2==2 using 'z'. */
+        hlen     -= bad_char_skip[haystack[last]];
+        haystack += bad_char_skip[haystack[last]];
+    }
+
+    return NULL;
+}
+
+/* disassembler **************************************************************/
+
+static int HighestSetBit(int N, uint32_t imm)
+{
+	int i;
+	for (i = N - 1; i >= 0; i--) {
+		if (imm & (1 << i)) {
+			return i;
+		}
+	}
+	return -1;
+}
+
+static uint64_t ZeroExtendOnes(unsigned M, unsigned N)	// zero extend M ones to N width
+{
+	(void)N;
+	return ((uint64_t)1 << M) - 1;
+}
+
+static uint64_t RORZeroExtendOnes(unsigned M, unsigned N, unsigned R)
+{
+	uint64_t val = ZeroExtendOnes(M, N);
+	if (R == 0) {
+		return val;
+	}
+	return ((val >> R) & (((uint64_t)1 << (N - R)) - 1)) | ((val & (((uint64_t)1 << R) - 1)) << (N - R));
+}
+
+static uint64_t Replicate(uint64_t val, unsigned bits)
+{
+	uint64_t ret = val;
+	unsigned shift;
+	for (shift = bits; shift < 64; shift += bits) {	// XXX actually, it is either 32 or 64
+		ret |= (val << shift);
+	}
+	return ret;
+}
+
+static int DecodeBitMasks(unsigned immN, unsigned imms, unsigned immr, int immediate, uint64_t *newval)
+{
+	unsigned levels, S, R, esize;
+	int len = HighestSetBit(7, (immN << 6) | (~imms & 0x3F));
+	if (len < 1) {
+		return -1;
+	}
+	levels = ZeroExtendOnes(len, 6);
+	if (immediate && (imms & levels) == levels) {
+		return -1;
+	}
+	S = imms & levels;
+	R = immr & levels;
+	esize = 1 << len;
+	*newval = Replicate(RORZeroExtendOnes(S + 1, esize, R), esize);
+	return 0;
+}
+
+static int DecodeMov(uint32_t opcode, uint64_t total, int first, uint64_t *newval)
+{
+	unsigned o = (opcode >> 29) & 3;
+	unsigned k = (opcode >> 23) & 0x3F;
+	unsigned rn, rd;
+	uint64_t i;
+
+	if (k == 0x24 && o == 1) {			// MOV (bitmask imm) <=> ORR (immediate)
+		unsigned s = (opcode >> 31) & 1;
+		unsigned N = (opcode >> 22) & 1;
+		if (s == 0 && N != 0) {
+			return -1;
+		}
+		rn = (opcode >> 5) & 0x1F;
+		if (rn == 31) {
+			unsigned imms = (opcode >> 10) & 0x3F;
+			unsigned immr = (opcode >> 16) & 0x3F;
+			return DecodeBitMasks(N, imms, immr, 1, newval);
+		}
+	} else if (k == 0x25) {				// MOVN/MOVZ/MOVK
+		unsigned s = (opcode >> 31) & 1;
+		unsigned h = (opcode >> 21) & 3;
+		if (s == 0 && h > 1) {
+			return -1;
+		}
+		i = (opcode >> 5) & 0xFFFF;
+		h *= 16;
+		i <<= h;
+		if (o == 0) {				// MOVN
+			*newval = ~i;
+			return 0;
+		} else if (o == 2) {			// MOVZ
+			*newval = i;
+			return 0;
+		} else if (o == 3 && !first) {		// MOVK
+			*newval = (total & ~((uint64_t)0xFFFF << h)) | i;
+			return 0;
+		}
+	} else if ((k | 1) == 0x23 && !first) {		// ADD (immediate)
+		unsigned h = (opcode >> 22) & 3;
+		if (h > 1) {
+			return -1;
+		}
+		rd = opcode & 0x1F;
+		rn = (opcode >> 5) & 0x1F;
+		if (rd != rn) {
+			return -1;
+		}
+		i = (opcode >> 10) & 0xFFF;
+		h *= 12;
+		i <<= h;
+		if (o & 2) {				// SUB
+			*newval = total - i;
+			return 0;
+		} else {				// ADD
+			*newval = total + i;
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+/* patchfinder ***************************************************************/
+
+static addr_t
+step64(const uint8_t *buf, addr_t start, size_t length, uint32_t what, uint32_t mask)
+{
+    addr_t end = start + length;
+    while (start < end) {
+        uint32_t x = *(uint32_t *)(buf + start);
+        if ((x & mask) == what) {
+            return start;
+        }
+        start += 4;
+    }
+    return 0;
+}
+
+// str8 = step64_back(kernel, ref, ref - bof, INSN_STR8);
+static addr_t
+step64_back(const uint8_t *buf, addr_t start, size_t length, uint32_t what, uint32_t mask)
+{
+    addr_t end = start - length;
+    while (start >= end) {
+        uint32_t x = *(uint32_t *)(buf + start);
+        if ((x & mask) == what) {
+            return start;
+        }
+        start -= 4;
+    }
+    return 0;
+}
+
+// Finds start of function
+static addr_t
+bof64(const uint8_t *buf, addr_t start, addr_t where)
+{
+    for (; where >= start; where -= 4) {
+        uint32_t op = *(uint32_t *)(buf + where);
+        if ((op & 0xFFC003FF) == 0x910003FD) {
+            unsigned delta = (op >> 10) & 0xFFF;
+            //printf("%x: ADD X29, SP, #0x%x\n", where, delta);
+            if ((delta & 0xF) == 0) {
+                addr_t prev = where - ((delta >> 4) + 1) * 4;
+                uint32_t au = *(uint32_t *)(buf + prev);
+                if ((au & 0xFFC003E0) == 0xA98003E0) {
+                    //printf("%x: STP x, y, [SP,#-imm]!\n", prev);
+                    return prev;
+                }
+            }
+        }
+    }
+    return 0;
+}
+
+static addr_t
+xref64(const uint8_t *buf, addr_t start, addr_t end, addr_t what)
+{
+    addr_t i;
+    uint64_t value[32];
+
+    memset(value, 0, sizeof(value));
+
+    end &= ~3;
+    for (i = start & ~3; i < end; i += 4) {
+        uint32_t op = *(uint32_t *)(buf + i);
+        unsigned reg = op & 0x1F;
+        if ((op & 0x9F000000) == 0x90000000) {
+            signed adr = ((op & 0x60000000) >> 18) | ((op & 0xFFFFE0) << 8);
+            //printf("%llx: ADRP X%d, 0x%llx\n", i, reg, ((long long)adr << 1) + (i & ~0xFFF));
+            value[reg] = ((long long)adr << 1) + (i & ~0xFFF);
+        /*} else if ((op & 0xFFE0FFE0) == 0xAA0003E0) {
+            unsigned rd = op & 0x1F;
+            unsigned rm = (op >> 16) & 0x1F;
+            //printf("%llx: MOV X%d, X%d\n", i, rd, rm);
+            value[rd] = value[rm];*/
+        } else if ((op & 0xFF000000) == 0x91000000) {
+            unsigned rn = (op >> 5) & 0x1F;
+            unsigned shift = (op >> 22) & 3;
+            unsigned imm = (op >> 10) & 0xFFF;
+            if (shift == 1) {
+                imm <<= 12;
+            } else {
+                //assert(shift == 0);
+                if (shift > 1) continue;
+            }
+            //printf("%llx: ADD X%d, X%d, 0x%x\n", i, reg, rn, imm);
+            value[reg] = value[rn] + imm;
+        } else if ((op & 0xF9C00000) == 0xF9400000) {
+            unsigned rn = (op >> 5) & 0x1F;
+            unsigned imm = ((op >> 10) & 0xFFF) << 3;
+            //printf("%llx: LDR X%d, [X%d, 0x%x]\n", i, reg, rn, imm);
+            if (!imm) continue;			// XXX not counted as true xref
+            value[reg] = value[rn] + imm;	// XXX address, not actual value
+        /*} else if ((op & 0xF9C00000) == 0xF9000000) {
+            unsigned rn = (op >> 5) & 0x1F;
+            unsigned imm = ((op >> 10) & 0xFFF) << 3;
+            //printf("%llx: STR X%d, [X%d, 0x%x]\n", i, reg, rn, imm);
+            if (!imm) continue;			// XXX not counted as true xref
+            value[rn] = value[rn] + imm;	// XXX address, not actual value*/
+        } else if ((op & 0x9F000000) == 0x10000000) {
+            signed adr = ((op & 0x60000000) >> 18) | ((op & 0xFFFFE0) << 8);
+            //printf("%llx: ADR X%d, 0x%llx\n", i, reg, ((long long)adr >> 11) + i);
+            value[reg] = ((long long)adr >> 11) + i;
+        } else if ((op & 0xFF000000) == 0x58000000) {
+            unsigned adr = (op & 0xFFFFE0) >> 3;
+            //printf("%llx: LDR X%d, =0x%llx\n", i, reg, adr + i);
+            value[reg] = adr + i;		// XXX address, not actual value
+        }
+        if (value[reg] == what) {
+            return i;
+        }
+    }
+    return 0;
+}
+
+static addr_t
+calc64(const uint8_t *buf, addr_t start, addr_t end, int which)
+{
+    addr_t i;
+    uint64_t value[32];
+
+    memset(value, 0, sizeof(value));
+
+    end &= ~3;
+    for (i = start & ~3; i < end; i += 4) {
+        uint32_t op = *(uint32_t *)(buf + i);
+        unsigned reg = op & 0x1F;
+        if ((op & 0x9F000000) == 0x90000000) {
+            signed adr = ((op & 0x60000000) >> 18) | ((op & 0xFFFFE0) << 8);
+            //printf("%llx: ADRP X%d, 0x%llx\n", i, reg, ((long long)adr << 1) + (i & ~0xFFF));
+            value[reg] = ((long long)adr << 1) + (i & ~0xFFF);
+        /*} else if ((op & 0xFFE0FFE0) == 0xAA0003E0) {
+            unsigned rd = op & 0x1F;
+            unsigned rm = (op >> 16) & 0x1F;
+            //printf("%llx: MOV X%d, X%d\n", i, rd, rm);
+            value[rd] = value[rm];*/
+        } else if ((op & 0xFF000000) == 0x91000000) {
+            unsigned rn = (op >> 5) & 0x1F;
+            unsigned shift = (op >> 22) & 3;
+            unsigned imm = (op >> 10) & 0xFFF;
+            if (shift == 1) {
+                imm <<= 12;
+            } else {
+                //assert(shift == 0);
+                if (shift > 1) continue;
+            }
+            //printf("%llx: ADD X%d, X%d, 0x%x\n", i, reg, rn, imm);
+            value[reg] = value[rn] + imm;
+        } else if ((op & 0xF9C00000) == 0xF9400000) {
+            unsigned rn = (op >> 5) & 0x1F;
+            unsigned imm = ((op >> 10) & 0xFFF) << 3;
+            //printf("%llx: LDR X%d, [X%d, 0x%x]\n", i, reg, rn, imm);
+            if (!imm) continue;			// XXX not counted as true xref
+            value[reg] = value[rn] + imm;	// XXX address, not actual value
+        } else if ((op & 0xF9C00000) == 0xF9000000) {
+            unsigned rn = (op >> 5) & 0x1F;
+            unsigned imm = ((op >> 10) & 0xFFF) << 3;
+            //printf("%llx: STR X%d, [X%d, 0x%x]\n", i, reg, rn, imm);
+            if (!imm) continue;			// XXX not counted as true xref
+            value[rn] = value[rn] + imm;	// XXX address, not actual value
+        } else if ((op & 0x9F000000) == 0x10000000) {
+            signed adr = ((op & 0x60000000) >> 18) | ((op & 0xFFFFE0) << 8);
+            //printf("%llx: ADR X%d, 0x%llx\n", i, reg, ((long long)adr >> 11) + i);
+            value[reg] = ((long long)adr >> 11) + i;
+        } else if ((op & 0xFF000000) == 0x58000000) {
+            unsigned adr = (op & 0xFFFFE0) >> 3;
+            //printf("%llx: LDR X%d, =0x%llx\n", i, reg, adr + i);
+            value[reg] = adr + i;		// XXX address, not actual value
+        }
+    }
+    return value[which];
+}
+
+static addr_t
+calc64mov(const uint8_t *buf, addr_t start, addr_t end, int which)
+{
+    addr_t i;
+    uint64_t value[32];
+
+    memset(value, 0, sizeof(value));
+
+    end &= ~3;
+    for (i = start & ~3; i < end; i += 4) {
+        uint32_t op = *(uint32_t *)(buf + i);
+        unsigned reg = op & 0x1F;
+        uint64_t newval;
+        int rv = DecodeMov(op, value[reg], 0, &newval);
+        if (rv == 0) {
+            if (((op >> 31) & 1) == 0) {
+                newval &= 0xFFFFFFFF;
+            }
+            value[reg] = newval;
+        }
+    }
+    return value[which];
+}
+
+static addr_t
+find_call64(const uint8_t *buf, addr_t start, size_t length)
+{
+    return step64(buf, start, length, 0x94000000, 0xFC000000);
+}
+
+static addr_t
+follow_call64(const uint8_t *buf, addr_t call)
+{
+    long long w;
+    w = *(uint32_t *)(buf + call) & 0x3FFFFFF;
+    w <<= 64 - 26;
+    w >>= 64 - 26 - 2;
+    return call + w;
+}
+
+static addr_t
+follow_cbz(const uint8_t *buf, addr_t cbz)
+{
+    return cbz + ((*(int *)(buf + cbz) & 0x3FFFFE0) << 10 >> 13);
+}
+
+/* kernel iOS10 **************************************************************/
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <mach-o/loader.h>
+
+#ifndef __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__
+    #define __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__
+#endif
+
+#ifdef __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__
+#include <mach/mach.h>
+size_t kread(uint64_t where, void *p, size_t size);
+#endif
+
+static uint8_t *kernel = NULL;
+static size_t kernel_size = 0;
+
+static addr_t xnucore_base = 0;
+static addr_t xnucore_size = 0;
+static addr_t prelink_base = 0;
+static addr_t prelink_size = 0;
+static addr_t cstring_base = 0;
+static addr_t cstring_size = 0;
+static addr_t pstring_base = 0;
+static addr_t pstring_size = 0;
+static addr_t kerndumpbase = -1;
+static addr_t kernel_entry = 0;
+static void *kernel_mh = 0;
+static addr_t kernel_delta = 0;
+
+int
+init_kernel(addr_t base, const char *filename)
+{
+    size_t rv;
+    uint8_t buf[0x4000];
+    unsigned i, j;
+    const struct mach_header *hdr = (struct mach_header *)buf;
+    const uint8_t *q;
+    addr_t min = -1;
+    addr_t max = 0;
+    int is64 = 0;
+
+#ifdef __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__
+#define close(f)
+    rv = kread(base, buf, sizeof(buf));
+
+    for (int i = 0; i < 10; i++){
+        printf("0x%x ", buf[i]);
+    }
+    printf("\n");
+
+    if (rv != sizeof(buf)) {
+        return -1;
+    }
+#else	/* __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ */
+    int fd = open(filename, O_RDONLY);
+    if (fd < 0) {
+        return -1;
+    }
+
+    rv = read(fd, buf, sizeof(buf));
+    if (rv != sizeof(buf)) {
+        close(fd);
+        return -1;
+    }
+#endif	/* __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ */
+
+    if (!MACHO(buf)) {
+        close(fd);
+        return -1;
+    }
+
+    if (IS64(buf)) {
+        is64 = 4;
+    }
+
+    q = buf + sizeof(struct mach_header) + is64;
+    for (i = 0; i < hdr->ncmds; i++) {
+        const struct load_command *cmd = (struct load_command *)q;
+        if (cmd->cmd == LC_SEGMENT_64) {
+            const struct segment_command_64 *seg = (struct segment_command_64 *)q;
+            if (min > seg->vmaddr) {
+                min = seg->vmaddr;
+            }
+            if (max < seg->vmaddr + seg->vmsize) {
+                max = seg->vmaddr + seg->vmsize;
+            }
+            if (!strcmp(seg->segname, "__TEXT_EXEC")) {
+                xnucore_base = seg->vmaddr;
+                xnucore_size = seg->filesize;
+            }
+            if (!strcmp(seg->segname, "__PLK_TEXT_EXEC")) {
+                prelink_base = seg->vmaddr;
+                prelink_size = seg->filesize;
+            }
+            if (!strcmp(seg->segname, "__TEXT")) {
+                const struct section_64 *sec = (struct section_64 *)(seg + 1);
+                for (j = 0; j < seg->nsects; j++) {
+                    if (!strcmp(sec[j].sectname, "__cstring")) {
+                        cstring_base = sec[j].addr;
+                        cstring_size = sec[j].size;
+                    }
+                }
+            }
+            if (!strcmp(seg->segname, "__PRELINK_TEXT")) {
+                const struct section_64 *sec = (struct section_64 *)(seg + 1);
+                for (j = 0; j < seg->nsects; j++) {
+                    if (!strcmp(sec[j].sectname, "__text")) {
+                        pstring_base = sec[j].addr;
+                        pstring_size = sec[j].size;
+                    }
+                }
+            }
+			if (!strcmp(seg->segname, "__LINKEDIT")) {
+				kernel_delta = seg->vmaddr - min - seg->fileoff;
+			}
+        }
+        if (cmd->cmd == LC_UNIXTHREAD) {
+            uint32_t *ptr = (uint32_t *)(cmd + 1);
+            uint32_t flavor = ptr[0];
+            struct {
+                uint64_t x[29];	/* General purpose registers x0-x28 */
+                uint64_t fp;	/* Frame pointer x29 */
+                uint64_t lr;	/* Link register x30 */
+                uint64_t sp;	/* Stack pointer x31 */
+                uint64_t pc; 	/* Program counter */
+                uint32_t cpsr;	/* Current program status register */
+            } *thread = (void *)(ptr + 2);
+            if (flavor == 6) {
+                kernel_entry = thread->pc;
+            }
+        }
+        q = q + cmd->cmdsize;
+    }
+
+    kerndumpbase = min;
+    xnucore_base -= kerndumpbase;
+    prelink_base -= kerndumpbase;
+    cstring_base -= kerndumpbase;
+    pstring_base -= kerndumpbase;
+    kernel_size = max - min;
+
+#ifdef __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__
+    kernel = malloc(kernel_size);
+    if (!kernel) {
+        return -1;
+    }
+    rv = kread(kerndumpbase, kernel, kernel_size);
+    if (rv != kernel_size) {
+        free(kernel);
+        return -1;
+    }
+
+    kernel_mh = kernel + base - min;
+
+    (void)filename;
+#undef close
+#else	/* __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ */
+    kernel = calloc(1, kernel_size);
+    if (!kernel) {
+        close(fd);
+        return -1;
+    }
+
+    q = buf + sizeof(struct mach_header) + is64;
+    for (i = 0; i < hdr->ncmds; i++) {
+        const struct load_command *cmd = (struct load_command *)q;
+        if (cmd->cmd == LC_SEGMENT_64) {
+            const struct segment_command_64 *seg = (struct segment_command_64 *)q;
+            size_t sz = pread(fd, kernel + seg->vmaddr - min, seg->filesize, seg->fileoff);
+            if (sz != seg->filesize) {
+                close(fd);
+                free(kernel);
+                return -1;
+            }
+            if (!kernel_mh) {
+                kernel_mh = kernel + seg->vmaddr - min;
+            }
+			printf("%s\n", seg->segname);
+            if (!strcmp(seg->segname, "__LINKEDIT")) {
+                kernel_delta = seg->vmaddr - min - seg->fileoff;
+            }
+        }
+        q = q + cmd->cmdsize;
+    }
+
+    close(fd);
+
+    (void)base;
+#endif	/* __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ */
+    return 0;
+}
+
+void
+term_kernel(void)
+{
+    free(kernel);
+}
+
+/* these operate on VA ******************************************************/
+
+#define INSN_RET  0xD65F03C0, 0xFFFFFFFF
+#define INSN_CALL 0x94000000, 0xFC000000
+#define INSN_B    0x14000000, 0xFC000000
+#define INSN_CBZ  0x34000000, 0xFC000000
+#define INSN_ADRP 0x90000000, 0x9F000000
+
+addr_t
+find_register_value(addr_t where, int reg)
+{
+    addr_t val;
+    addr_t bof = 0;
+    where -= kerndumpbase;
+    if (where > xnucore_base) {
+        bof = bof64(kernel, xnucore_base, where);
+        if (!bof) {
+            bof = xnucore_base;
+        }
+    } else if (where > prelink_base) {
+        bof = bof64(kernel, prelink_base, where);
+        if (!bof) {
+            bof = prelink_base;
+        }
+    }
+    val = calc64(kernel, bof, where, reg);
+    if (!val) {
+        return 0;
+    }
+    return val + kerndumpbase;
+}
+
+addr_t
+find_reference(addr_t to, int n, int prelink)
+{
+    addr_t ref, end;
+    addr_t base = xnucore_base;
+    addr_t size = xnucore_size;
+    if (prelink) {
+        base = prelink_base;
+        size = prelink_size;
+    }
+    if (n <= 0) {
+        n = 1;
+    }
+    end = base + size;
+    to -= kerndumpbase;
+    do {
+        ref = xref64(kernel, base, end, to);
+        if (!ref) {
+            return 0;
+        }
+        base = ref + 4;
+    } while (--n > 0);
+    return ref + kerndumpbase;
+}
+
+addr_t
+find_strref(const char *string, int n, int prelink)
+{
+    uint8_t *str;
+    addr_t base = cstring_base;
+    addr_t size = cstring_size;
+    if (prelink) {
+        base = pstring_base;
+        size = pstring_size;
+    }
+    str = boyermoore_horspool_memmem(kernel + base, size, (uint8_t *)string, strlen(string));
+    if (!str) {
+        return 0;
+    }
+    return find_reference(str - kernel + kerndumpbase, n, prelink);
+}
+
+/****** fun *******/
+
+CACHED_FIND_UINT64(find_add_x0_x0_0x40_ret) {
+	addr_t off;
+	uint32_t *k;
+	k = (uint32_t *)(kernel + xnucore_base);
+	for (off = 0; off < xnucore_size - 4; off += 4, k++) {
+		if (k[0] == 0x91010000 && k[1] == 0xD65F03C0) {
+			return off + xnucore_base + kerndumpbase;
+		}
+	}
+	k = (uint32_t *)(kernel + prelink_base);
+	for (off = 0; off < prelink_size - 4; off += 4, k++) {
+		if (k[0] == 0x91010000 && k[1] == 0xD65F03C0) {
+			return off + prelink_base + kerndumpbase;
+		}
+	}
+	return 0;
+}
+
+CACHED_FIND_UINT64(find_allproc) {
+	// Find the first reference to the string
+	addr_t ref = find_strref("\"pgrp_add : pgrp is dead adding process\"", 1, 0);
+	if (!ref) {
+		return 0;
+	}
+	ref -= kerndumpbase;
+	
+	uint64_t start = bof64(kernel, xnucore_base, ref);
+	if (!start) {
+		return 0;
+	}
+	
+	// Find AND W8, W8, #0xFFFFDFFF - it's a pretty distinct instruction
+	addr_t weird_instruction = 0;
+	for (int i = 4; i < 4*0x100; i+=4) {
+		uint32_t op = *(uint32_t *)(kernel + ref + i);
+		if (op == 0x12127908) {
+			weird_instruction = ref+i;
+			break;
+		}
+	}
+	if (!weird_instruction) {
+		return 0;
+	}
+	
+	uint64_t val = calc64(kernel, start, weird_instruction - 8, 8);
+	if (!val) {
+		printf("Failed to calculate x8");
+		return 0;
+	}
+	
+	return val + kerndumpbase;
+}
+
+CACHED_FIND_UINT64(find_OSBoolean_True) {
+    addr_t val;
+    addr_t ref = find_strref("Delay Autounload", 0, 0);
+    if (!ref) {
+        return 0;
+    }
+    ref -= kerndumpbase;
+    
+    addr_t weird_instruction = 0;
+    for (int i = 4; i < 4*0x100; i+=4) {
+        uint32_t op = *(uint32_t *)(kernel + ref + i);
+        if (op == 0x320003E0) {
+            weird_instruction = ref+i;
+            break;
+        }
+    }
+    if (!weird_instruction) {
+        return 0;
+    }
+    
+    val = calc64(kernel, ref, weird_instruction, 8);
+    if (!val) {
+        return 0;
+    }
+    
+    return rk64(val + kerndumpbase);
+}
+
+CACHED_FIND_UINT64(find_OSBoolean_False) {
+    return find_OSBoolean_True()+8;
+}
+
+CACHED_FIND_UINT64(find_zone_map_ref) {
+    // \"Nothing being freed to the zone_map. start = end = %p\\n\"
+    uint64_t val = kerndumpbase;
+
+    addr_t ref = find_strref("\"Nothing being freed to the zone_map. start = end = %p\\n\"", 1, 0);
+    ref -= kerndumpbase;
+
+    // skip add & adrp for panic str
+    ref -= 8;
+
+    // adrp xX, #_zone_map@PAGE
+    ref = step64_back(kernel, ref, 30, INSN_ADRP);
+
+    uint32_t *insn = (uint32_t*)(kernel+ref);
+    // get pc
+    val += ((uint8_t*)(insn) - kernel) & ~0xfff;
+    uint8_t xm = *insn & 0x1f;
+
+    // don't ask, I wrote this at 5am
+    val += (*insn<<9 & 0x1ffffc000) | (*insn>>17 & 0x3000);
+
+    // ldr x, [xX, #_zone_map@PAGEOFF]
+    ++insn;
+    if ((*insn & 0xF9C00000) != 0xF9400000) {
+        return 0;
+    }
+
+    // xd == xX, xn == xX,
+    if ((*insn&0x1f) != xm || ((*insn>>5)&0x1f) != xm) {
+        return 0;
+    }
+
+    val += ((*insn >> 10) & 0xFFF) << 3;
+
+    return val;
+}
+
+CACHED_FIND_UINT64(find_osunserializexml) {
+    addr_t ref = find_strref("OSUnserializeXML: %s near line %d\n", 1, 0);
+    ref -= kerndumpbase;
+    uint64_t start = bof64(kernel, xnucore_base, ref);
+    return start + kerndumpbase;
+}
+
+CACHED_FIND_UINT64(find_smalloc) {
+    addr_t ref = find_strref("sandbox memory allocation failure", 1, 1);
+    ref -= kerndumpbase;
+    uint64_t start = bof64(kernel, prelink_base, ref);
+    return start + kerndumpbase;
+}

+ 27 - 0
Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/patchfinder64.h

@@ -0,0 +1,27 @@
+#ifndef PATCHFINDER64_H_
+#define PATCHFINDER64_H_
+
+#define CACHED_FIND(type, name) \
+	type __##name(void);\
+	type name(void) { \
+		static type cached = 0; \
+		if (cached == 0) { \
+			cached = __##name(); \
+		} \
+		return cached; \
+	} \
+	type __##name(void)
+
+int init_kernel(uint64_t base, const char *filename);
+void term_kernel(void);
+
+// Fun part
+uint64_t find_allproc(void);
+uint64_t find_add_x0_x0_0x40_ret(void);
+uint64_t find_OSBoolean_True(void);
+uint64_t find_OSBoolean_False(void);
+uint64_t find_zone_map_ref(void);
+uint64_t find_osunserializexml(void);
+uint64_t find_smalloc(void);
+
+#endif

+ 254 - 0
Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/sandbox.c

@@ -0,0 +1,254 @@
+#include "kmem.h"
+#include "kern_utils.h"
+#include "sandbox.h"
+#include "patchfinder64.h"
+#include "kexecute.h"
+
+
+typedef uint64_t extension_hdr_t;
+typedef uint64_t extension_t;
+
+struct extension_hdr {
+/* 0x00 */	extension_hdr_t next;
+/* 0x08 */	uint64_t desc;
+/* 0x10 */	extension_t ext_lst;
+/* 0x18 */
+};
+
+struct extension {
+/* 0x00 */	extension_t next;
+/* 0x08 */	uint64_t desc; // always 0xffffffffffffffff
+/* 0x10 */	uint64_t ext_lst; // zero, since it's extension and not a header
+/* 0x18 */	uint8_t something[32]; // zeroed from what I've seen
+/* 0x38 */	uint32_t type; // see ext_type enum
+/* 0x3c */	uint32_t subtype; // either 0 or 4 (or whatever unhex gave?..)
+/* 0x40 */	uint64_t data; // a c string, meaning depends on type and hdr which had this extension
+/* 0x48 */	uint64_t data_len; // strlen(data)
+/* 0x50 */	uint64_t unk0; // always 0
+/* 0x58 */	uint64_t unk1; // always 0xdeadbeefdeadbeef
+/* 0x60 */
+};
+
+uint64_t _smalloc(uint64_t size) {
+	return kexecute(find_smalloc(), size, 0, 0, 0, 0, 0, 0);
+}
+
+uint64_t smalloc(uint64_t size) {
+	uint64_t ret = _smalloc(size);
+	
+	if (ret != 0) {
+		// IOAlloc's of small size go to zalloc
+		ret = zm_fix_addr(ret);
+	}
+
+	return ret;
+}
+
+uint64_t sstrdup(const char* s) {
+	size_t slen = strlen(s) + 1;
+
+	uint64_t ks = smalloc(slen);
+	if (ks) {
+		kwrite(ks, s, slen);
+	}
+
+	return ks;
+}
+
+// Notice: path should *not* end with '/' !
+uint64_t extension_create_file(const char* path, uint64_t nextptr) {
+	size_t slen = strlen(path);
+
+	if (path[slen - 1] == '/') {
+		fprintf(stderr, "No traling slash in path pls\n");
+		return 0;
+	}
+
+	uint64_t ext_p = smalloc(sizeof(struct extension));
+	uint64_t ks = sstrdup(path);
+
+	if (ext_p && ks) {
+		struct extension ext;
+		bzero(&ext, sizeof(ext));
+		ext.next = nextptr;
+		ext.desc = 0xffffffffffffffff;
+		
+		// ext.type = 0;
+		// ext.subtype = 0;
+
+		ext.data = ks;
+		ext.data_len = slen;
+
+		kwrite(ext_p, &ext, sizeof(ext));
+	} else {
+		// XXX oh no a leak
+	}
+
+	return ext_p;
+}
+
+
+// get 64 higher bits of 64bit int multiplication
+// https://stackoverflow.com/a/28904636
+// ofc in asm it's done with 1 instruction huh
+// XXX there has to be a cleaner way utilizing hardware support
+uint64_t mulhi(uint64_t a, uint64_t b) {
+	uint64_t    a_lo = (uint32_t)a;
+	uint64_t    a_hi = a >> 32;
+	uint64_t    b_lo = (uint32_t)b;
+	uint64_t    b_hi = b >> 32;
+
+	uint64_t    a_x_b_hi =  a_hi * b_hi;
+	uint64_t    a_x_b_mid = a_hi * b_lo;
+	uint64_t    b_x_a_mid = b_hi * a_lo;
+	uint64_t    a_x_b_lo =  a_lo * b_lo;
+
+	uint64_t    carry_bit = ((uint64_t)(uint32_t)a_x_b_mid +
+	                         (uint64_t)(uint32_t)b_x_a_mid +
+	                         (a_x_b_lo >> 32) ) >> 32;
+
+	uint64_t    multhi = a_x_b_hi +
+	                     (a_x_b_mid >> 32) + (b_x_a_mid >> 32) +
+	                     carry_bit;
+
+	return multhi;
+}
+
+int hashing_magic(const char *desc) {
+	// inlined into exception_add
+	uint64_t hashed = 0x1505;
+
+	// if desc == NULL, then returned value would be 8
+	// APPL optimizes it for some reason
+	// but meh, desc should never be NULL or you get
+	// null dereference in exception_add
+	// if (desc == NULL) return 8;
+
+	if (desc != NULL) {
+		for (const char* dp = desc; *dp != '\0'; ++dp) {
+			hashed += hashed << 5;
+			hashed += (int64_t) *dp;
+		}
+	}
+
+	uint64_t magic = 0xe38e38e38e38e38f;
+
+	uint64_t hi = mulhi(hashed, magic);
+	hi >>= 3;
+	hi = (hi<<3) + hi;
+
+	hashed -= hi;
+
+	return hashed;
+}
+
+static const char *ent_key = "com.apple.security.exception.files.absolute-path.read-only";
+
+uint64_t make_ext_hdr(const char* key, uint64_t ext_lst) {
+	struct extension_hdr hdr;
+
+	uint64_t khdr = smalloc(sizeof(hdr));
+
+	if (khdr) {
+		// we add headers to end
+		hdr.next = 0;
+		hdr.desc = sstrdup(key);
+		if (hdr.desc == 0) {
+			// XXX leak
+			return 0;
+		}
+
+		hdr.ext_lst = ext_lst;
+		kwrite(khdr, &hdr, sizeof(hdr));
+	}
+
+	return khdr;
+}
+
+void extension_add(uint64_t ext, uint64_t sb, const char* desc) {
+	// XXX patchfinder + kexecute would be way better
+
+	int slot = hashing_magic(ent_key);
+	uint64_t insert_at_p = sb + sizeof(void*) + slot * sizeof(void*);
+	uint64_t insert_at = rk64(insert_at_p);
+
+	while (insert_at != 0) {
+		uint64_t kdsc = rk64(insert_at + offsetof(struct extension_hdr, desc));
+
+		if (kstrcmp(kdsc, desc) == 0) {
+			break;
+		}
+
+		insert_at_p = insert_at;
+		insert_at = rk64(insert_at);
+	}
+
+	if (insert_at == 0) {
+		insert_at = make_ext_hdr(ent_key, ext);
+		wk64(insert_at_p, insert_at);
+	} else {
+		// XXX no duplicate check
+		uint64_t ext_lst_p = insert_at + offsetof(struct extension_hdr, ext_lst);
+		uint64_t ext_lst = rk64(ext_lst_p);
+
+		while (ext_lst != 0) {
+			fprintf(stderr, "ext_lst_p = 0x%llx ext_lst = 0x%llx\n", ext_lst_p, ext_lst);
+			ext_lst_p = ext_lst + offsetof(struct extension, next);
+			ext_lst = rk64(ext_lst_p);
+		}
+
+		fprintf(stderr, "ext_lst_p = 0x%llx ext_lst = 0x%llx\n", ext_lst_p, ext_lst);
+
+		wk64(ext_lst_p, ext);
+	}
+}
+
+// 1 if yes
+int has_file_extension(uint64_t sb, const char* path) {
+	const char* desc = ent_key;
+	int found = 0;
+
+	int slot = hashing_magic(ent_key);
+	uint64_t insert_at_p = sb + sizeof(void*) + slot * sizeof(void*);
+	uint64_t insert_at = rk64(insert_at_p);
+
+	while (insert_at != 0) {
+		uint64_t kdsc = rk64(insert_at + offsetof(struct extension_hdr, desc));
+
+		if (kstrcmp(kdsc, desc) == 0) {
+			break;
+		}
+
+		insert_at_p = insert_at;
+		insert_at = rk64(insert_at);
+	}
+
+	if (insert_at != 0) {
+		uint64_t ext_lst = rk64(insert_at + offsetof(struct extension_hdr, ext_lst));
+
+		uint64_t plen = strlen(path);
+		char *exist = malloc(plen + 1);
+		exist[plen] = '\0';
+
+		while (ext_lst != 0) {
+			// XXX no type/subtype check
+			uint64_t data_len = rk64(ext_lst + offsetof(struct extension, data_len));
+			if (data_len == plen) {
+				uint64_t data = rk64(ext_lst + offsetof(struct extension, data));
+				kread(data, exist, plen);
+
+				if (strcmp(path, exist) == 0) {
+					found = 1;
+					break;
+				}
+			}
+
+			ext_lst = rk64(ext_lst);
+		}
+		
+
+		free(exist);
+	}
+
+	return found;
+}

+ 6 - 0
Meridian/meridianTV/electra_extras/basebinaries/jailbreakd/sandbox.h

@@ -0,0 +1,6 @@
+
+// see https://stek29.rocks/2018/01/26/sandbox.html
+
+void extension_add(uint64_t ext, uint64_t sb, const char* desc);
+uint64_t extension_create_file(const char* path, uint64_t nextptr);
+int has_file_extension(uint64_t sb, const char* path);

+ 8 - 0
Meridian/meridianTV/electra_extras/basebinaries/jailbreakd_client/Ent.plist

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>platform-application</key>
+	<true/>
+</dict>
+</plist>

+ 27 - 0
Meridian/meridianTV/electra_extras/basebinaries/jailbreakd_client/Makefile

@@ -0,0 +1,27 @@
+TARGET  = jailbreakd_client
+OUTDIR ?= bin
+
+CC      = xcrun -sdk appletvos cc -arch arm64
+LDID    = ldid
+CFLAGS  = -Wall
+
+.PHONY: all clean
+
+all: $(OUTDIR)/$(TARGET)
+
+DEBUG ?= 0
+ifeq ($(DEBUG), 1)
+    CFLAGS += -DJAILBREAKD_CLIENT_DEBUG
+else
+    CFLAGS += -O2
+endif
+
+$(OUTDIR):
+	mkdir -p $(OUTDIR)
+
+$(OUTDIR)/$(TARGET): jailbreakd_client.m libjailbreak_mig.m mach/jailbreak_daemonUser.c | $(OUTDIR)
+	$(CC) -o $@ $^ -framework Foundation $(CFLAGS)
+	$(LDID) -SEnt.plist $@
+
+clean:
+	rm -f $(OUTDIR)/$(TARGET)

+ 43 - 0
Meridian/meridianTV/electra_extras/basebinaries/jailbreakd_client/jailbreakd_client.m

@@ -0,0 +1,43 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include "libjailbreak_mig.h"
+
+int main(int argc, char **argv, char **envp) {
+    if (argc < 3){
+        printf("Usage: \n");
+        printf("jailbreakd_client <pid> <1 | 2 | 6>\n");
+        printf("\t1 = entitle+platformize the target PID\n");
+        printf("\t2 = entitle+platformize the target PID and subsequently sent SIGCONT\n");
+        printf("\t6 = fixup setuid in the target PID\n");
+        return 0;
+    }
+    if (atoi(argv[2]) != 1 && atoi(argv[2]) != 2 && atoi(argv[2]) != 6){
+        printf("Usage: \n");
+        printf("jailbreakd_client <pid> <1 | 2 | 6>\n");
+        printf("\t1 = entitle the target PID\n");
+        printf("\t2 = entitle+platformize the target PID and subsequently sent SIGCONT\n");
+        printf("\t6 = fixup setuid in the target PID\n");
+        return 0;
+    }
+
+    jb_connection_t jbc = jb_connect();
+
+    pid_t pid = atoi(argv[1]);
+    int arg = atoi(argv[2]);
+    int ret = 0;
+
+    if (arg == 1) {
+        ret = jb_entitle_now(jbc, pid, 7 | FLAG_WAIT_EXEC);
+    } else if (arg == 2) {
+        ret = jb_entitle_now(jbc, pid, 15);
+    } else if (arg == 6) {
+        ret = jb_fix_setuid_now(jbc, pid);
+    }
+    jb_disconnect(jbc);
+    return ret;
+}
+
+// vim:ft=objc

+ 1 - 0
Meridian/meridianTV/electra_extras/basebinaries/jailbreakd_client/libjailbreak_mig.h

@@ -0,0 +1 @@
+../libjailbreak_mig/libjailbreak_mig.h

+ 1 - 0
Meridian/meridianTV/electra_extras/basebinaries/jailbreakd_client/libjailbreak_mig.m

@@ -0,0 +1 @@
+../libjailbreak_mig/libjailbreak_mig.m

+ 1 - 0
Meridian/meridianTV/electra_extras/basebinaries/jailbreakd_client/mach

@@ -0,0 +1 @@
+../jailbreakd/mach

+ 29 - 0
Meridian/meridianTV/electra_extras/basebinaries/libjailbreak_mig/Makefile

@@ -0,0 +1,29 @@
+TARGET  = libjailbreak.dylib
+OUTDIR ?= bin
+
+CC      = xcrun -sdk appletvos cc -arch arm64
+# it is injected into trust cache by code
+# which only supports sha-256 signatures
+LDID    = ldid2
+CFLAGS  = -Wall
+
+.PHONY: all clean
+
+all: $(OUTDIR)/$(TARGET)
+
+DEBUG ?= 0
+ifeq ($(DEBUG), 1)
+    CFLAGS += -DLIBJAILBREAK_DEBUG
+else
+    CFLAGS += -O2
+endif
+
+$(OUTDIR):
+	mkdir -p $(OUTDIR)
+
+$(OUTDIR)/$(TARGET): mach/jailbreak_daemonUser.c libjailbreak_mig.m | $(OUTDIR)
+	$(CC) -dynamiclib -o $@ $^ $(CFLAGS)
+	$(LDID) -S $@
+
+clean:
+	rm -f $(OUTDIR)/$(TARGET)

+ 29 - 0
Meridian/meridianTV/electra_extras/basebinaries/libjailbreak_mig/Makefile--

@@ -0,0 +1,29 @@
+TARGET  = libjailbreak.dylib
+OUTDIR ?= bin
+
+CC      = xcrun -sdk appletvos cc -arch arm64
+# it is injected into trust cache by code
+# which only supports sha-256 signatures
+LDID    = ldid2
+CFLAGS  = -Wall
+
+.PHONY: all clean
+
+all: $(OUTDIR)/$(TARGET)
+
+DEBUG ?= 0
+ifeq ($(DEBUG), 1)
+    CFLAGS += -DLIBJAILBREAK_DEBUG
+else
+    CFLAGS += -O2
+endif
+
+$(OUTDIR):
+	mkdir -p $(OUTDIR)
+
+$(OUTDIR)/$(TARGET): mach/jailbreak_daemonUser.c libjailbreak_mig.m | $(OUTDIR)
+	$(CC) -dynamiclib -o $@ $^ $(CFLAGS)
+	$(LDID) -S $@
+
+clean:
+	rm -f $(OUTDIR)/$(TARGET)

+ 29 - 0
Meridian/meridianTV/electra_extras/basebinaries/libjailbreak_mig/Makefile----

@@ -0,0 +1,29 @@
+TARGET  = libjailbreak.dylib
+OUTDIR ?= bin
+
+CC      = xcrun -sdk iphoneos cc -arch arm64
+# it is injected into trust cache by code
+# which only supports sha-256 signatures
+LDID    = ldid2
+CFLAGS  = -Wall
+
+.PHONY: all clean
+
+all: $(OUTDIR)/$(TARGET)
+
+DEBUG ?= 0
+ifeq ($(DEBUG), 1)
+    CFLAGS += -DLIBJAILBREAK_DEBUG
+else
+    CFLAGS += -O2
+endif
+
+$(OUTDIR):
+	mkdir -p $(OUTDIR)
+
+$(OUTDIR)/$(TARGET): mach/jailbreak_daemonUser.c libjailbreak_mig.m | $(OUTDIR)
+	$(CC) -dynamiclib -o $@ $^ $(CFLAGS)
+	$(LDID) -S $@
+
+clean:
+	rm -f $(OUTDIR)/$(TARGET)

+ 36 - 0
Meridian/meridianTV/electra_extras/basebinaries/libjailbreak_mig/libjailbreak_mig.h

@@ -0,0 +1,36 @@
+#include <sys/types.h>
+#include <stdint.h>
+
+/* Flags for entp command. Any combination or none can be specified. */
+/* Wait for xpcproxy to exec before continuing */
+#define FLAG_WAIT_EXEC   (1 << 5)
+/* Wait for 0.5 sec after acting */
+#define FLAG_DELAY       (1 << 4)
+/* Send SIGCONT after acting */
+#define FLAG_SIGCONT     (1 << 3)
+/* Set sandbox exception */
+#define FLAG_SANDBOX     (1 << 2)
+/* Set platform binary flag */
+#define FLAG_PLATFORMIZE (1 << 1)
+/* Set basic entitlements */
+#define FLAG_ENTITLE     (1)
+
+typedef void *jb_connection_t;
+
+#if __BLOCKS__
+typedef void (^jb_callback_t)(int result);
+
+/* These ones run asynchronously. Callbacks take 1 on success, 0 on failure.
+   The queue which they run on is undefined. */
+extern void jb_entitle(jb_connection_t connection, pid_t pid, uint32_t what, jb_callback_t done);
+extern void jb_fix_setuid(jb_connection_t connection, pid_t pid, jb_callback_t done);
+#endif
+
+extern jb_connection_t jb_connect(void);
+extern void jb_disconnect(jb_connection_t connection);
+
+extern int jb_entitle_now(jb_connection_t connection, pid_t pid, uint32_t what);
+extern int jb_fix_setuid_now(jb_connection_t connection, pid_t pid);
+
+extern void jb_oneshot_entitle_now(pid_t pid, uint32_t what);
+extern void jb_oneshot_fix_setuid_now(pid_t pid);

+ 75 - 0
Meridian/meridianTV/electra_extras/basebinaries/libjailbreak_mig/libjailbreak_mig.m

@@ -0,0 +1,75 @@
+#include "libjailbreak_mig.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <mach/mach.h>
+#include "mach/jailbreak_daemonUser.h"
+#include <dispatch/dispatch.h>
+
+kern_return_t bootstrap_look_up(mach_port_t port, const char *service, mach_port_t *server_port);
+
+#define JAILBREAKD_COMMAND_ENTITLE 1
+#define JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT 2
+#define JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT_FROM_XPCPROXY 3
+#define JAILBREAKD_COMMAND_FIXUP_SETUID 4
+struct __attribute__((__packed__)) jb_connection {
+    mach_port_t jbd_port;
+};
+
+typedef void *jb_connection_t;
+
+jb_connection_t jb_connect(void) {
+    mach_port_t jbd_port;
+    if (bootstrap_look_up(bootstrap_port, "org.coolstar.jailbreakd", &jbd_port) == 0) {
+        struct jb_connection *conn = malloc(sizeof(struct jb_connection));
+        conn->jbd_port = jbd_port;
+        return (jb_connection_t)conn;
+    }
+    return NULL;
+}
+
+void jb_disconnect(jb_connection_t connection) {
+    struct jb_connection *conn = (struct jb_connection *)connection;
+    mach_port_deallocate(mach_task_self(), conn->jbd_port);
+    free(conn);
+}
+
+void jb_entitle(jb_connection_t connection, pid_t pid, uint32_t what, jb_callback_t done) {
+    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0UL), ^{
+        struct jb_connection *conn = (struct jb_connection *)connection;
+        int response = jbd_call(conn->jbd_port, JAILBREAKD_COMMAND_ENTITLE, pid);
+        done(response);
+    });
+}
+
+void jb_fix_setuid(jb_connection_t connection, pid_t pid, jb_callback_t done) {
+    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0UL), ^{
+        struct jb_connection *conn = (struct jb_connection *)connection;
+        int response = jbd_call(conn->jbd_port, JAILBREAKD_COMMAND_FIXUP_SETUID, pid);
+
+        done(response);
+    });
+}
+
+int jb_entitle_now(jb_connection_t connection, pid_t pid, uint32_t what) {
+    struct jb_connection *conn = (struct jb_connection *)connection;
+    return jbd_call(conn->jbd_port, JAILBREAKD_COMMAND_ENTITLE, pid);
+}
+
+int jb_fix_setuid_now(jb_connection_t connection, pid_t pid) {   
+    struct jb_connection *conn = (struct jb_connection *)connection;
+    return jbd_call(conn->jbd_port, JAILBREAKD_COMMAND_FIXUP_SETUID, pid);
+}
+
+void jb_oneshot_entitle_now(pid_t pid, uint32_t what) {
+    jb_connection_t c = jb_connect();
+    jb_entitle_now(c, pid, what);
+    jb_disconnect(c);
+}
+
+void jb_oneshot_fix_setuid_now(pid_t pid) {
+    jb_connection_t c = jb_connect();
+    jb_fix_setuid_now(c, pid);
+    jb_disconnect(c);
+}

+ 1 - 0
Meridian/meridianTV/electra_extras/basebinaries/libjailbreak_mig/mach

@@ -0,0 +1 @@
+../jailbreakd/mach

+ 29 - 0
Meridian/meridianTV/electra_extras/basebinaries/pspawn_payload/Makefile

@@ -0,0 +1,29 @@
+TARGET  = pspawn_payload.dylib
+OUTDIR ?= bin
+
+CC      = xcrun -sdk appletvos cc -arch arm64
+# it is injected into trust cache by code
+# which only supports sha-256 signatures
+LDID    = ldid2
+CFLAGS  = -Wall -I./apple_include
+
+.PHONY: all clean
+
+all: $(OUTDIR)/$(TARGET)
+
+DEBUG ?= 1
+ifeq ($(DEBUG), 1)
+    CFLAGS += -DPSPAWN_PAYLOAD_DEBUG
+else
+    CFLAGS += -O2
+endif
+
+$(OUTDIR):
+	mkdir -p $(OUTDIR)
+
+$(OUTDIR)/$(TARGET): mach/jailbreak_daemonUser.c pspawn_payload.m fishhook.c | $(OUTDIR)
+	$(CC) -dynamiclib -o $@ $^ -framework Foundation $(CFLAGS)
+	$(LDID) -S $@
+
+clean:
+	rm -f $(OUTDIR)/$(TARGET)

+ 1 - 0
Meridian/meridianTV/electra_extras/basebinaries/pspawn_payload/apple_include

@@ -0,0 +1 @@
+../apple_include

+ 1 - 0
Meridian/meridianTV/electra_extras/basebinaries/pspawn_payload/fishhook.c

@@ -0,0 +1 @@
+../fishhook/fishhook.c

+ 1 - 0
Meridian/meridianTV/electra_extras/basebinaries/pspawn_payload/fishhook.h

@@ -0,0 +1 @@
+../fishhook/fishhook.h

+ 1 - 0
Meridian/meridianTV/electra_extras/basebinaries/pspawn_payload/mach

@@ -0,0 +1 @@
+../jailbreakd/mach

+ 298 - 0
Meridian/meridianTV/electra_extras/basebinaries/pspawn_payload/pspawn_payload.m

@@ -0,0 +1,298 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <mach/mach.h>
+#include <mach/error.h>
+#include <mach/message.h>
+#include <string.h>
+#include <unistd.h>
+#include <spawn.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/sysctl.h>
+#include <dlfcn.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <pthread.h>
+#include <Foundation/Foundation.h>
+#include "fishhook.h"
+#include "mach/jailbreak_daemonUser.h"
+
+int file_exist(const char *filename) {
+    struct stat buffer;
+    int r = stat(filename, &buffer);
+    return (r == 0);
+}
+
+#define PSPAWN_PAYLOAD_DEBUG 1
+
+//#ifdef PSPAWN_PAYLOAD_DEBUG
+#define LAUNCHD_LOG_PATH "/var/log/pspawn_payload_launchd.log"
+// XXX multiple xpcproxies opening same file
+// XXX not closing logfile before spawn
+#define XPCPROXY_LOG_PATH "/var/log//pspawn_payload_xpcproxy.log"
+FILE *log_file;
+#define DEBUGLOG(fmt, args...)\
+do {\
+if (log_file == NULL) {\
+log_file = fopen((current_process == PROCESS_LAUNCHD) ? LAUNCHD_LOG_PATH : XPCPROXY_LOG_PATH, "a"); \
+if (log_file == NULL) break; \
+} \
+fprintf(log_file, fmt "\n", ##args); \
+fflush(log_file); \
+} while(0)
+/*
+#else
+#define DEBUGLOG(fmt, args...)
+#endif
+*/
+#define PSPAWN_PAYLOAD_DYLIB "/electra/pspawn_payload.dylib"
+#define AMFID_PAYLOAD_DYLIB "/electra/amfid_payload.dylib"
+#define SBINJECT_PAYLOAD_DYLIB "/usr/lib/TweakInject.dylib"
+
+// since this dylib should only be loaded into launchd and xpcproxy
+// it's safe to assume that we're in xpcproxy if getpid() != 1
+enum currentprocess {
+    PROCESS_LAUNCHD,
+    PROCESS_XPCPROXY,
+};
+
+int current_process = PROCESS_XPCPROXY;
+
+#define JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT 2
+#define JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT_FROM_XPCPROXY 3
+
+kern_return_t bootstrap_look_up(mach_port_t port, const char *service, mach_port_t *server_port);
+
+mach_port_t jbd_port;
+
+const char* xpcproxy_blacklist[] = {
+    "com.apple.diagnosticd",  // syslog
+    "MTLCompilerService",     // ?_?
+    "mapspushd",              // stupid Apple Maps
+    "OTAPKIAssetTool",        // h_h
+    "cfprefsd",               // o_o
+    "jailbreakd",             // don't inject into jbd since we'd have to call to it
+    //"com.nito.nitoTV4",
+    //"com.nito.nitoTV4.nitoTVTopShelf",
+    /*
+    "PineBoard",              // for now
+    "com.apple.PineBoard",
+    "com.apple.HeadBoard",
+    "HeadBoard",
+    "com.firecore.infuse.pro",
+    "com.apple.accessibility.AccessibilityUIServer",
+    "com.apple.TVAirPlay",
+    "com.apple.mediaserverd",
+    "com.apple.SiriViewService",
+    "com.apple.syncdefaultsd",
+    "com.apple.TVWatchList",
+    "com.apple.TVAppStore",
+    "com.apple.TVIdleScreen",
+    "com.apple.TVSettings",
+     */
+    NULL
+};
+
+typedef int (*pspawn_t)(pid_t * pid, const char* path, const posix_spawn_file_actions_t *file_actions, posix_spawnattr_t *attrp, char const* argv[], const char* envp[]);
+
+pspawn_t old_pspawn, old_pspawnp;
+
+int fake_posix_spawn_common(pid_t * pid, const char* path, const posix_spawn_file_actions_t *file_actions, posix_spawnattr_t *attrp, char const* argv[], const char* envp[], pspawn_t old) {
+    DEBUGLOG("We got called (fake_posix_spawn)! %s", path);
+    
+    const char *inject_me = NULL;
+    
+    if (current_process == PROCESS_LAUNCHD) {
+        if (strcmp(path, "/usr/libexec/xpcproxy") == 0) {
+            inject_me = PSPAWN_PAYLOAD_DYLIB;
+            
+            const char* startd = argv[1];
+            if (startd != NULL) {
+                const char **blacklist = xpcproxy_blacklist;
+                
+                while (*blacklist) {
+                    if (strstr(startd, *blacklist)) {
+                        DEBUGLOG("xpcproxy for '%s' which is in blacklist, not injecting", startd);
+                        inject_me = NULL;
+                        break;
+                    }
+                    
+                    ++blacklist;
+                }
+            }
+        }
+    } else if (current_process == PROCESS_XPCPROXY) {
+        // XXX inject both SBInject & amfid payload into amfid?
+        // note: DYLD_INSERT_LIBRARIES=libfoo1.dylib:libfoo2.dylib
+        if (strcmp(path, "/usr/libexec/amfid") == 0) {
+            DEBUGLOG("Starting amfid -- special handling");
+            inject_me = AMFID_PAYLOAD_DYLIB;
+        } else {
+            inject_me = SBINJECT_PAYLOAD_DYLIB;
+        }
+    }
+    
+    // XXX log different err on inject_me == NULL and nonexistent inject_me
+    if (inject_me == NULL || !file_exist(inject_me)) {
+        DEBUGLOG("Nothing to inject");
+        return old(pid, path, file_actions, attrp, argv, envp);
+    }
+    
+    DEBUGLOG("Injecting %s into %s", inject_me, path);
+    
+#ifdef PSPAWN_PAYLOAD_DEBUG
+    if (argv != NULL){
+        DEBUGLOG("Args: ");
+        const char** currentarg = argv;
+        while (*currentarg != NULL){
+            DEBUGLOG("\t%s", *currentarg);
+            currentarg++;
+        }
+    }
+#endif
+    
+    int envcount = 0;
+    
+    if (envp != NULL){
+        DEBUGLOG("Env: ");
+        const char** currentenv = envp;
+        while (*currentenv != NULL){
+            DEBUGLOG("\t%s", *currentenv);
+            if (strstr(*currentenv, "DYLD_INSERT_LIBRARIES") == NULL) {
+                envcount++;
+            }
+            currentenv++;
+        }
+    }
+    
+    char const** newenvp = malloc((envcount+2) * sizeof(char **));
+    int j = 0;
+    for (int i = 0; i < envcount; i++){
+        if (strstr(envp[j], "DYLD_INSERT_LIBRARIES") != NULL){
+            continue;
+        }
+        newenvp[i] = envp[j];
+        j++;
+    }
+    
+    char *envp_inject = malloc(strlen("DYLD_INSERT_LIBRARIES=") + strlen(inject_me) + 1);
+    
+    envp_inject[0] = '\0';
+    strcat(envp_inject, "DYLD_INSERT_LIBRARIES=");
+    strcat(envp_inject, inject_me);
+    
+    newenvp[j] = envp_inject;
+    newenvp[j+1] = NULL;
+    
+#if PSPAWN_PAYLOAD_DEBUG
+    DEBUGLOG("New Env:");
+    const char** currentenv = newenvp;
+    while (*currentenv != NULL){
+        DEBUGLOG("\t%s", *currentenv);
+        currentenv++;
+    }
+#endif
+    
+    posix_spawnattr_t attr;
+    
+    posix_spawnattr_t *newattrp = &attr;
+    
+    if (attrp) {
+        
+        DEBUGLOG("attrp!\n");
+        
+        newattrp = attrp;
+        short flags;
+        posix_spawnattr_getflags(attrp, &flags);
+        flags |= POSIX_SPAWN_START_SUSPENDED;
+        posix_spawnattr_setflags(attrp, flags);
+    } else {
+        
+        DEBUGLOG("attrp else\n");
+        posix_spawnattr_init(&attr);
+        posix_spawnattr_setflags(&attr, POSIX_SPAWN_START_SUSPENDED);
+    }
+    
+    int origret;
+    
+#define FLAG_ATTRIBUTE_XPCPROXY (1 << 17)
+    
+    if (current_process == PROCESS_XPCPROXY) {
+        // dont leak logging fd into execd process
+        
+         DEBUGLOG("dont leak logging fd into execd process\n");
+#ifdef PSPAWN_PAYLOAD_DEBUG
+        if (log_file != NULL) {
+            fclose(log_file);
+            log_file = NULL;
+        }
+#endif
+        jbd_call(jbd_port, JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT_FROM_XPCPROXY, getpid());
+        
+        
+        // dont leak jbd fd into execd process
+        origret = old(pid, path, file_actions, newattrp, argv, newenvp);
+        DEBUGLOG("origret %i for xpcproxy\n", origret);
+    } else {
+        int gotpid;
+        origret = old(&gotpid, path, file_actions, newattrp, argv, newenvp);
+        DEBUGLOG("origret %i for not xpcproxy\n", origret);
+        if (origret == 0) {
+            if (pid != NULL) *pid = gotpid;
+            DEBUGLOG("we in here\n");
+            jbd_call(jbd_port, JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT, gotpid);
+        }
+    }
+    
+    return origret;
+}
+
+
+int fake_posix_spawn(pid_t * pid, const char* file, const posix_spawn_file_actions_t *file_actions, posix_spawnattr_t *attrp, const char* argv[], const char* envp[]) {
+    return fake_posix_spawn_common(pid, file, file_actions, attrp, argv, envp, old_pspawn);
+}
+
+int fake_posix_spawnp(pid_t * pid, const char* file, const posix_spawn_file_actions_t *file_actions, posix_spawnattr_t *attrp, const char* argv[], const char* envp[]) {
+    return fake_posix_spawn_common(pid, file, file_actions, attrp, argv, envp, old_pspawnp);
+}
+
+
+void rebind_pspawns(void) {
+    struct rebinding rebindings[] = {
+        {"posix_spawn", (void *)fake_posix_spawn, (void **)&old_pspawn},
+        {"posix_spawnp", (void *)fake_posix_spawnp, (void **)&old_pspawnp},
+    };
+    
+    rebind_symbols(rebindings, 2);
+}
+
+void* thd_func(void* arg){
+    NSLog(@"In a new thread!");
+    rebind_pspawns();
+    return NULL;
+}
+
+__attribute__ ((constructor))
+static void ctor(void) {
+    if (getpid() == 1) {
+        if (host_get_special_port(mach_host_self(), HOST_LOCAL_NODE, 15, &jbd_port)) {
+            DEBUGLOG("Can't get hgsp15 :(");
+            return;
+        }
+        DEBUGLOG("Got jbd port: %llx", jbd_port);
+        
+        current_process = PROCESS_LAUNCHD;
+        pthread_t thd;
+        pthread_create(&thd, NULL, thd_func, NULL);
+    } else {
+        if (bootstrap_look_up(bootstrap_port, "org.coolstar.jailbreakd", &jbd_port)) {
+            DEBUGLOG("Can't get bootstrap port :(");
+            return;
+        }
+        DEBUGLOG("Got jbd port: %llx", jbd_port);
+        
+        current_process = PROCESS_XPCPROXY;
+        rebind_pspawns();
+    }
+}

+ 8 - 0
Meridian/meridianTV/electra_extras/libsubstrate/Makefile

@@ -0,0 +1,8 @@
+ARCHS=arm64
+include $(THEOS)/makefiles/common.mk
+
+LIBRARY_NAME = libsubstrate
+libsubstrate_FILES = libsubstrate.c
+libsubstrate_LIBRARIES = substitute objc
+
+include $(THEOS_MAKE_PATH)/library.mk

+ 10 - 0
Meridian/meridianTV/electra_extras/libsubstrate/control

@@ -0,0 +1,10 @@
+Package: org.coolstar.substrate-substitute-shim
+Name: libsubstrate
+Depends: 
+Version: 0.0.1
+Architecture: appletvos-arm64
+Description: An awesome library of some sort!!
+Maintainer: CoolStar
+Author: CoolStar
+Section: System
+Tag: role::developer

+ 52 - 0
Meridian/meridianTV/electra_extras/libsubstrate/libsubstrate.c

@@ -0,0 +1,52 @@
+#include <objc/runtime.h>
+#include <substitute.h>
+#include <os/log.h>
+
+extern void *SubGetImageByName(const char *filename) __asm__("SubGetImageByName");;
+void *MSGetImageByName(const char *filename) {
+    return SubGetImageByName(filename);
+}
+
+extern void *SubFindSymbol(void *image, const char *name) __asm__("SubFindSymbol");
+void *MSFindSymbol(void *image, const char *name) {
+	return SubFindSymbol(image, name);
+}
+
+extern void SubHookFunction(void *symbol, void *replace, void **result) __asm__("SubHookFunction");
+void MSHookFunction(void *symbol, void *replace, void **result) {
+	SubHookFunction(symbol, replace, result);
+}
+
+extern void SubHookMessageEx(Class _class, SEL sel, IMP imp, IMP *result) __asm__("SubHookMessageEx");
+void MSHookMessageEx(Class _class, SEL sel, IMP imp, IMP *result) {
+	if (class_getInstanceMethod(_class, sel) || class_getClassMethod(_class, sel)) {
+		SubHookMessageEx(_class, sel, imp, result);
+	} else {
+		os_log_error(OS_LOG_DEFAULT, "libsubstrate-shim: Tried to hook non-existent selector %s on class %s",
+			sel_getName(sel), class_getName(_class));
+			if (result) *result = NULL;
+	}
+}
+
+// i don't think anyone uses this function anymore, but it's here for completeness
+void MSHookClassPair(Class _class, Class hook, Class old) {
+    unsigned int n_methods = 0;
+    Method *hooks = class_copyMethodList(hook, &n_methods);
+    
+    for (unsigned int i = 0; i < n_methods; ++i) {
+        SEL selector = method_getName(hooks[i]);
+        const char *what = method_getTypeEncoding(hooks[i]);
+        
+        Method old_mptr = class_getInstanceMethod(old, selector);
+        Method cls_mptr = class_getInstanceMethod(_class, selector);
+        
+        if (cls_mptr) {
+            class_addMethod(old, selector, method_getImplementation(hooks[i]), what);
+            method_exchangeImplementations(cls_mptr, old_mptr);
+        } else {
+            class_addMethod(_class, selector, method_getImplementation(hooks[i]), what);
+        }
+    }
+    
+    free(hooks);
+}

+ 11 - 0
Meridian/meridianTV/electra_extras/sbinject/.theos/_/DEBIAN/control

@@ -0,0 +1,11 @@
+Package: com.yourcompany.sbinject
+Name: SBInject
+Depends: 
+Architecture: appletvos-arm64
+Description: An awesome library of some sort!!
+Maintainer: CoolStar
+Author: CoolStar
+Section: System
+Tag: role::developer
+Version: 0.0.1-4
+Installed-Size: 88

BIN
Meridian/meridianTV/electra_extras/sbinject/.theos/_/usr/lib/TweakInject.dylib


+ 0 - 0
Meridian/meridianTV/electra_extras/sbinject/.theos/build_session


BIN
Meridian/meridianTV/electra_extras/sbinject/.theos/fakeroot


+ 1 - 0
Meridian/meridianTV/electra_extras/sbinject/.theos/last_package

@@ -0,0 +1 @@
+./debs/com.yourcompany.sbinject_0.0.1-4_appletvos-arm64.deb

+ 0 - 0
Meridian/meridianTV/electra_extras/sbinject/.theos/obj/appletv/debug/.stamp


BIN
Meridian/meridianTV/electra_extras/sbinject/.theos/obj/appletv/debug/TweakInject.dylib


BIN
Meridian/meridianTV/electra_extras/sbinject/.theos/obj/appletv/debug/arm64/SBInject.x.09271890.o


BIN
Meridian/meridianTV/electra_extras/sbinject/.theos/obj/appletv/debug/arm64/SBInject.x.cb64146a.o


BIN
Meridian/meridianTV/electra_extras/sbinject/.theos/obj/appletv/debug/arm64/TweakInject.dylib


+ 1 - 0
Meridian/meridianTV/electra_extras/sbinject/.theos/packages/com.yourcompany.sbinject-0.0.1

@@ -0,0 +1 @@
+4

+ 10 - 0
Meridian/meridianTV/electra_extras/sbinject/Makefile

@@ -0,0 +1,10 @@
+ARCHS=arm64
+TARGET = appletv
+include theos/makefiles/common.mk
+
+LIBRARY_NAME = TweakInject
+TweakInject_LIBRARIES = substrate
+TweakInject_FILES = SBInject.x
+#SBInject_USE_SUBSTRATE=0
+
+include $(THEOS_MAKE_PATH)/library.mk

+ 253 - 0
Meridian/meridianTV/electra_extras/sbinject/SBInject.x

@@ -0,0 +1,253 @@
+#import <dlfcn.h>
+#import <objc/runtime.h>
+#import <stdlib.h>
+#import <stdio.h>
+#import <unistd.h>
+#import <pthread.h>
+#import <sys/stat.h>
+#import <sys/types.h>
+#import <CommonCrypto/CommonDigest.h>
+#include <syslog.h>
+
+#define PROC_PIDPATHINFO_MAXSIZE  (1024)
+int proc_pidpath(pid_t pid, void *buffer, uint32_t buffersize);
+
+#define dylibDir @"/Library/MobileSubstrate/DynamicLibraries/"
+
+NSArray *sbinjectGenerateDylibList() {
+
+    HBLogInfo(@"### TEST LOG");
+
+    NSString *processName = [[NSProcessInfo processInfo] processName];
+    // launchctl, amfid you are special cases
+    if ([processName isEqualToString:@"launchctl"]) {
+        HBLogInfo(@"launchctl exit");
+        return nil;
+    }
+    if ([processName isEqualToString:@"amfid"]) {
+        HBLogInfo(@"amfid exit");
+        return nil;
+    }
+    // Create an array containing all the filenames in dylibDir (/opt/simject)
+    NSError *e = nil;
+    NSArray *dylibDirContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:dylibDir error:&e];
+    if (e) {
+        return nil;
+    }
+    // Read current bundle identifier
+    //NSString *bundleIdentifier = NSBundle.mainBundle.bundleIdentifier;
+    // We're only interested in the plist files
+    NSArray *plists = [dylibDirContents filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"SELF ENDSWITH %@", @"plist"]];
+    // Create an empty mutable array that will contain a list of dylib paths to be injected into the target process
+    NSMutableArray *dylibsToInject = [NSMutableArray array];
+    // Loop through the list of plists
+    for (NSString *plist in plists) {
+        // We'll want to deal with absolute paths, so append the filename to dylibDir
+        NSString *plistPath = [dylibDir stringByAppendingPathComponent:plist];
+        NSDictionary *filter = [NSDictionary dictionaryWithContentsOfFile:plistPath];
+        // This boolean indicates whether or not the dylib has already been injected
+        BOOL isInjected = NO;
+        // If supported iOS versions are specified within the plist, we check those first
+        NSArray *supportedVersions = filter[@"CoreFoundationVersion"];
+        if (supportedVersions) {
+            if (supportedVersions.count != 1 && supportedVersions.count != 2) {
+                continue; // Supported versions are in the wrong format, we should skip
+            }
+            if (supportedVersions.count == 1 && [supportedVersions[0] doubleValue] > kCFCoreFoundationVersionNumber) {
+                continue; // Doesn't meet lower bound
+            }
+            if (supportedVersions.count == 2 && ([supportedVersions[0] doubleValue] > kCFCoreFoundationVersionNumber || [supportedVersions[1] doubleValue] <= kCFCoreFoundationVersionNumber)) {
+                continue; // Outside bounds
+            }
+        }
+        // Decide whether or not to load the dylib based on the Bundles values
+        for (NSString *entry in filter[@"Filter"][@"Bundles"]) {
+            // Check to see whether or not this bundle is actually loaded in this application or not
+            if (!CFBundleGetBundleWithIdentifier((CFStringRef)entry)) {
+                // If not, skip it
+                continue;
+            }
+            [dylibsToInject addObject:[[plistPath stringByDeletingPathExtension] stringByAppendingString:@".dylib"]];
+            isInjected = YES;
+            break;
+        }
+        if (!isInjected) {
+            // Decide whether or not to load the dylib based on the Executables values
+            for (NSString *process in filter[@"Filter"][@"Executables"]) {
+                if ([process isEqualToString:processName]) {
+                    [dylibsToInject addObject:[[plistPath stringByDeletingPathExtension] stringByAppendingString:@".dylib"]];
+                    isInjected = YES;
+                    break;
+                }
+            }
+        }
+        if (!isInjected) {
+            // Decide whether or not to load the dylib based on the Classes values
+            for (NSString *clazz in filter[@"Filter"][@"Classes"]) {
+                // Also check if this class is loaded in this application or not
+                if (!NSClassFromString(clazz)) {
+                    // This class couldn't be loaded, skip
+                    continue;
+                }
+                // It's fine to add this dylib at this point
+                [dylibsToInject addObject:[[plistPath stringByDeletingPathExtension] stringByAppendingString:@".dylib"]];
+                isInjected = YES;
+                break;
+            }
+        }
+    }
+    [dylibsToInject sortUsingSelector:@selector(caseInsensitiveCompare:)];
+    return dylibsToInject;
+}
+
+int file_exist(char *filename) {
+    struct stat buffer;
+    int r = stat(filename, &buffer);
+    return (r == 0);
+}
+
+
+
+@interface SpringBoard : NSObject
+- (BOOL)launchApplicationWithIdentifier:(NSString *)identifier suspended:(BOOL)suspended;
+- (id)sharedApplication;
+@end
+
+%group SafeMode
+%hook FBApplicationInfo
+- (NSDictionary *)environmentVariables {
+    NSDictionary *originalVariables = %orig;
+    NSMutableDictionary *newVariables = [originalVariables mutableCopy];
+    [newVariables setObject:@1 forKey:@"_SafeMode"];
+    return [newVariables autorelease];
+}
+%end
+/*
+%hook SBLockScreenManager
+-(BOOL)_finishUIUnlockFromSource:(int)arg1 withOptions:(id)arg2 {
+    BOOL ret = %orig;
+    [(SpringBoard *)[%c(UIApplication) sharedApplication] launchApplicationWithIdentifier:@"org.coolstar.SafeMode" suspended:NO];
+    return ret;
+}
+
+// Necessary on iPhone X to show after swipe unlock gesture
+-(void)lockScreenViewControllerDidDismiss {
+    %orig;
+    [(SpringBoard *)[%c(UIApplication) sharedApplication] launchApplicationWithIdentifier:@"org.coolstar.SafeMode" suspended:NO];
+}
+%end
+*/
+%end
+
+static BOOL isSpringBoardOrBackboard = NO;
+static NSString *processHash = @"";
+BOOL safeMode = false;
+
+void SpringBoardSigHandler(int signo, siginfo_t *info, void *uap){
+    if (isSpringBoardOrBackboard){
+        FILE *f = fopen("/var/mobile/Library/.sbinjectSafeMode", "w");
+        fprintf(f, "Hello World\n");
+        fclose(f);
+    }
+    FILE *f = fopen([[NSString stringWithFormat:@"%@/.safeMode-%@", NSTemporaryDirectory(), processHash] UTF8String], "w");
+    fprintf(f, "Hello World!\n");
+    fclose(f);
+
+    raise(signo);
+}
+
+__attribute__ ((constructor))
+static void ctor(void) {
+    @autoreleasepool {
+        if (NSBundle.mainBundle.bundleIdentifier == nil || ![NSBundle.mainBundle.bundleIdentifier isEqualToString:@"org.coolstar.SafeMode"]){
+            char pathbuf[PROC_PIDPATHINFO_MAXSIZE] = {0};
+            int ret = proc_pidpath(getpid(), pathbuf, sizeof(pathbuf));
+            if (ret > 0){
+                uint8_t digest[CC_SHA1_DIGEST_LENGTH];
+
+                CC_SHA1(pathbuf, ret, digest);
+
+                NSMutableString *output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
+
+                for (int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++)
+                {
+                    [output appendFormat:@"%02x", digest[i]];
+                }
+                processHash = [[NSString alloc] initWithString:output];
+            }
+
+            safeMode = false;
+            NSString *processName = [[NSProcessInfo processInfo] processName];
+
+            struct sigaction action;
+            memset(&action, 0, sizeof(action));
+            action.sa_sigaction = &SpringBoardSigHandler;
+            action.sa_flags = SA_SIGINFO | SA_RESETHAND;
+            sigemptyset(&action.sa_mask);
+
+            sigaction(SIGQUIT, &action, NULL);
+            sigaction(SIGILL, &action, NULL);
+            sigaction(SIGTRAP, &action, NULL);
+            sigaction(SIGABRT, &action, NULL);
+            sigaction(SIGEMT, &action, NULL);
+            sigaction(SIGFPE, &action, NULL);
+            sigaction(SIGBUS, &action, NULL);
+            sigaction(SIGSEGV, &action, NULL);
+            sigaction(SIGSYS, &action, NULL);
+
+            if ([processName isEqualToString:@"backboardd"] || [NSBundle.mainBundle.bundleIdentifier isEqualToString:@"com.apple.springboard"]){
+                isSpringBoardOrBackboard = YES;
+                if (file_exist("/var/mobile/Library/.sbinjectSafeMode")){
+                    safeMode = true;
+                    if ([NSBundle.mainBundle.bundleIdentifier isEqualToString:@"com.apple.springboard"]){
+                        unlink("/var/mobile/Library/.sbinjectSafeMode");
+                        NSLog(@"Entering Safe Mode!");
+                        %init(SafeMode);
+                    }
+                }
+            }
+
+            if ([NSBundle.mainBundle.bundleIdentifier isEqualToString:@"com.apple.springboard"]){
+                dlopen("/usr/lib/TweakInjectMapsCheck.dylib", RTLD_LAZY | RTLD_GLOBAL);
+            }
+
+            const char *safeModeByProcPath = [[NSString stringWithFormat:@"%@/.safeMode-%@", NSTemporaryDirectory(), processHash] UTF8String];
+            if (file_exist((char *)safeModeByProcPath)){
+                safeMode = true;
+                unlink(safeModeByProcPath);
+            }
+
+            if (getenv("_MSSafeMode")){
+                if (strcmp(getenv("_MSSafeMode"),"1") == 0){
+                    safeMode = true;
+                }
+            }
+            if (getenv("_SafeMode")){
+                if (strcmp(getenv("_SafeMode"),"1") == 0){
+                    safeMode = true;
+                }
+            }
+            if (getenv("_SubstituteSafeMode")){
+                if (strcmp(getenv("_SubstituteSafeMode"),"1") == 0){
+                    safeMode = true;
+                }
+            }
+
+            if (!safeMode){
+
+                HBLogInfo(@"### TEST LOG");
+
+                for (NSString *dylib in sbinjectGenerateDylibList()) {
+                    NSLog(@"Injecting %@", dylib);
+                    void *dl = dlopen([dylib UTF8String], RTLD_LAZY | RTLD_GLOBAL);
+
+                    if (dl == NULL) {
+                        NSLog(@"Injection failed: '%s'", dlerror());
+                    }
+                }
+            } else {
+                NSLog(@"TweakInject: Entering Safe Mode!");
+            }
+        }
+    }
+}

BIN
Meridian/meridianTV/electra_extras/sbinject/TweakInject.dylib


BIN
Meridian/meridianTV/electra_extras/sbinject/TweakInject.tar


+ 10 - 0
Meridian/meridianTV/electra_extras/sbinject/control

@@ -0,0 +1,10 @@
+Package: com.yourcompany.sbinject
+Name: SBInject
+Depends: 
+Version: 0.0.1
+Architecture: appletvos-arm64
+Description: An awesome library of some sort!!
+Maintainer: CoolStar
+Author: CoolStar
+Section: System
+Tag: role::developer

BIN
Meridian/meridianTV/electra_extras/sbinject/debs/com.yourcompany.sbinject_0.0.1-1_appletvos-arm64.deb


BIN
Meridian/meridianTV/electra_extras/sbinject/debs/com.yourcompany.sbinject_0.0.1-2_appletvos-arm64.deb


BIN
Meridian/meridianTV/electra_extras/sbinject/debs/com.yourcompany.sbinject_0.0.1-3_appletvos-arm64.deb


BIN
Meridian/meridianTV/electra_extras/sbinject/debs/com.yourcompany.sbinject_0.0.1-4_appletvos-arm64.deb


+ 1 - 0
Meridian/meridianTV/electra_extras/sbinject/theos/Defines.h

@@ -0,0 +1 @@
+../Defines.h

+ 609 - 0
Meridian/meridianTV/electra_extras/sbinject/theos/LICENSE.md

@@ -0,0 +1,609 @@
+Theos (and by extension, Logos) is available under the provisions of the GNU
+General Public License, version 3 (or later), available here:
+http://www.gnu.org/licenses/gpl-3.0.html.
+
+Projects created using Theos and/or Logos are not considered derivative works
+(from a licensing standpoint, or, for that matter, any other standpoint) and
+are, as such, not required to be licensed under the GNU GPL.
+
+The included project templates are license-free. The use of a template does
+not confer a license to your project.
+
+----
+
+GNU GENERAL PUBLIC LICENSE
+==========================
+
+Version 3, 29 June 2007
+
+Copyright © 2007 Free Software Foundation, Inc. &lt;<http://fsf.org/>&gt;
+
+Everyone is permitted to copy and distribute verbatim copies of this license
+document, but changing it is not allowed.
+
+## Preamble
+
+The GNU General Public License is a free, copyleft license for software and other
+kinds of works.
+
+The licenses for most software and other practical works are designed to take away
+your freedom to share and change the works. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change all versions of a
+program--to make sure it remains free software for all its users. We, the Free
+Software Foundation, use the GNU General Public License for most of our software; it
+applies also to any other work released this way by its authors. You can apply it to
+your programs, too.
+
+When we speak of free software, we are referring to freedom, not price. Our General
+Public Licenses are designed to make sure that you have the freedom to distribute
+copies of free software (and charge for them if you wish), that you receive source
+code or can get it if you want it, that you can change the software or use pieces of
+it in new free programs, and that you know you can do these things.
+
+To protect your rights, we need to prevent others from denying you these rights or
+asking you to surrender the rights. Therefore, you have certain responsibilities if
+you distribute copies of the software, or if you modify it: responsibilities to
+respect the freedom of others.
+
+For example, if you distribute copies of such a program, whether gratis or for a fee,
+you must pass on to the recipients the same freedoms that you received. You must make
+sure that they, too, receive or can get the source code. And you must show them these
+terms so they know their rights.
+
+Developers that use the GNU GPL protect your rights with two steps: (1) assert
+copyright on the software, and (2) offer you this License giving you legal permission
+to copy, distribute and/or modify it.
+
+For the developers' and authors' protection, the GPL clearly explains that there is
+no warranty for this free software. For both users' and authors' sake, the GPL
+requires that modified versions be marked as changed, so that their problems will not
+be attributed erroneously to authors of previous versions.
+
+Some devices are designed to deny users access to install or run modified versions of
+the software inside them, although the manufacturer can do so. This is fundamentally
+incompatible with the aim of protecting users' freedom to change the software. The
+systematic pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we have designed
+this version of the GPL to prohibit the practice for those products. If such problems
+arise substantially in other domains, we stand ready to extend this provision to
+those domains in future versions of the GPL, as needed to protect the freedom of
+users.
+
+Finally, every program is threatened constantly by software patents. States should
+not allow patents to restrict development and use of software on general-purpose
+computers, but in those that do, we wish to avoid the special danger that patents
+applied to a free program could make it effectively proprietary. To prevent this, the
+GPL assures that patents cannot be used to render the program non-free.
+
+The precise terms and conditions for copying, distribution and modification follow.
+
+## TERMS AND CONDITIONS
+
+### 0. Definitions.
+
+“This License” refers to version 3 of the GNU General Public License.
+
+“Copyright” also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+“The Program” refers to any copyrightable work licensed under this
+License. Each licensee is addressed as “you”. “Licensees” and
+“recipients” may be individuals or organizations.
+
+To “modify” a work means to copy from or adapt all or part of the work in
+a fashion requiring copyright permission, other than the making of an exact copy. The
+resulting work is called a “modified version” of the earlier work or a
+work “based on” the earlier work.
+
+A “covered work” means either the unmodified Program or a work based on
+the Program.
+
+To “propagate” a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for infringement under
+applicable copyright law, except executing it on a computer or modifying a private
+copy. Propagation includes copying, distribution (with or without modification),
+making available to the public, and in some countries other activities as well.
+
+To “convey” a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through a computer
+network, with no transfer of a copy, is not conveying.
+
+An interactive user interface displays “Appropriate Legal Notices” to the
+extent that it includes a convenient and prominently visible feature that (1)
+displays an appropriate copyright notice, and (2) tells the user that there is no
+warranty for the work (except to the extent that warranties are provided), that
+licensees may convey the work under this License, and how to view a copy of this
+License. If the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+### 1. Source Code.
+
+The “source code” for a work means the preferred form of the work for
+making modifications to it. “Object code” means any non-source form of a
+work.
+
+A “Standard Interface” means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of interfaces
+specified for a particular programming language, one that is widely used among
+developers working in that language.
+
+The “System Libraries” of an executable work include anything, other than
+the work as a whole, that (a) is included in the normal form of packaging a Major
+Component, but which is not part of that Major Component, and (b) serves only to
+enable use of the work with that Major Component, or to implement a Standard
+Interface for which an implementation is available to the public in source code form.
+A “Major Component”, in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system (if any) on which
+the executable work runs, or a compiler used to produce the work, or an object code
+interpreter used to run it.
+
+The “Corresponding Source” for a work in object code form means all the
+source code needed to generate, install, and (for an executable work) run the object
+code and to modify the work, including scripts to control those activities. However,
+it does not include the work's System Libraries, or general-purpose tools or
+generally available free programs which are used unmodified in performing those
+activities but which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for the work, and
+the source code for shared libraries and dynamically linked subprograms that the work
+is specifically designed to require, such as by intimate data communication or
+control flow between those subprograms and other parts of the work.
+
+The Corresponding Source need not include anything that users can regenerate
+automatically from other parts of the Corresponding Source.
+
+The Corresponding Source for a work in source code form is that same work.
+
+### 2. Basic Permissions.
+
+All rights granted under this License are granted for the term of copyright on the
+Program, and are irrevocable provided the stated conditions are met. This License
+explicitly affirms your unlimited permission to run the unmodified Program. The
+output from running a covered work is covered by this License only if the output,
+given its content, constitutes a covered work. This License acknowledges your rights
+of fair use or other equivalent, as provided by copyright law.
+
+You may make, run and propagate covered works that you do not convey, without
+conditions so long as your license otherwise remains in force. You may convey covered
+works to others for the sole purpose of having them make modifications exclusively
+for you, or provide you with facilities for running those works, provided that you
+comply with the terms of this License in conveying all material for which you do not
+control copyright. Those thus making or running the covered works for you must do so
+exclusively on your behalf, under your direction and control, on terms that prohibit
+them from making any copies of your copyrighted material outside their relationship
+with you.
+
+Conveying under any other circumstances is permitted solely under the conditions
+stated below. Sublicensing is not allowed; section 10 makes it unnecessary.
+
+### 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+No covered work shall be deemed part of an effective technological measure under any
+applicable law fulfilling obligations under article 11 of the WIPO copyright treaty
+adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention
+of such measures.
+
+When you convey a covered work, you waive any legal power to forbid circumvention of
+technological measures to the extent such circumvention is effected by exercising
+rights under this License with respect to the covered work, and you disclaim any
+intention to limit operation or modification of the work as a means of enforcing,
+against the work's users, your or third parties' legal rights to forbid circumvention
+of technological measures.
+
+### 4. Conveying Verbatim Copies.
+
+You may convey verbatim copies of the Program's source code as you receive it, in any
+medium, provided that you conspicuously and appropriately publish on each copy an
+appropriate copyright notice; keep intact all notices stating that this License and
+any non-permissive terms added in accord with section 7 apply to the code; keep
+intact all notices of the absence of any warranty; and give all recipients a copy of
+this License along with the Program.
+
+You may charge any price or no price for each copy that you convey, and you may offer
+support or warranty protection for a fee.
+
+### 5. Conveying Modified Source Versions.
+
+You may convey a work based on the Program, or the modifications to produce it from
+the Program, in the form of source code under the terms of section 4, provided that
+you also meet all of these conditions:
+
+* **a)** The work must carry prominent notices stating that you modified it, and giving a
+relevant date.
+* **b)** The work must carry prominent notices stating that it is released under this
+License and any conditions added under section 7. This requirement modifies the
+requirement in section 4 to “keep intact all notices”.
+* **c)** You must license the entire work, as a whole, under this License to anyone who
+comes into possession of a copy. This License will therefore apply, along with any
+applicable section 7 additional terms, to the whole of the work, and all its parts,
+regardless of how they are packaged. This License gives no permission to license the
+work in any other way, but it does not invalidate such permission if you have
+separately received it.
+* **d)** If the work has interactive user interfaces, each must display Appropriate Legal
+Notices; however, if the Program has interactive interfaces that do not display
+Appropriate Legal Notices, your work need not make them do so.
+
+A compilation of a covered work with other separate and independent works, which are
+not by their nature extensions of the covered work, and which are not combined with
+it such as to form a larger program, in or on a volume of a storage or distribution
+medium, is called an “aggregate” if the compilation and its resulting
+copyright are not used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work in an aggregate
+does not cause this License to apply to the other parts of the aggregate.
+
+### 6. Conveying Non-Source Forms.
+
+You may convey a covered work in object code form under the terms of sections 4 and
+5, provided that you also convey the machine-readable Corresponding Source under the
+terms of this License, in one of these ways:
+
+* **a)** Convey the object code in, or embodied in, a physical product (including a
+physical distribution medium), accompanied by the Corresponding Source fixed on a
+durable physical medium customarily used for software interchange.
+* **b)** Convey the object code in, or embodied in, a physical product (including a
+physical distribution medium), accompanied by a written offer, valid for at least
+three years and valid for as long as you offer spare parts or customer support for
+that product model, to give anyone who possesses the object code either (1) a copy of
+the Corresponding Source for all the software in the product that is covered by this
+License, on a durable physical medium customarily used for software interchange, for
+a price no more than your reasonable cost of physically performing this conveying of
+source, or (2) access to copy the Corresponding Source from a network server at no
+charge.
+* **c)** Convey individual copies of the object code with a copy of the written offer to
+provide the Corresponding Source. This alternative is allowed only occasionally and
+noncommercially, and only if you received the object code with such an offer, in
+accord with subsection 6b.
+* **d)** Convey the object code by offering access from a designated place (gratis or for
+a charge), and offer equivalent access to the Corresponding Source in the same way
+through the same place at no further charge. You need not require recipients to copy
+the Corresponding Source along with the object code. If the place to copy the object
+code is a network server, the Corresponding Source may be on a different server
+(operated by you or a third party) that supports equivalent copying facilities,
+provided you maintain clear directions next to the object code saying where to find
+the Corresponding Source. Regardless of what server hosts the Corresponding Source,
+you remain obligated to ensure that it is available for as long as needed to satisfy
+these requirements.
+* **e)** Convey the object code using peer-to-peer transmission, provided you inform
+other peers where the object code and Corresponding Source of the work are being
+offered to the general public at no charge under subsection 6d.
+
+A separable portion of the object code, whose source code is excluded from the
+Corresponding Source as a System Library, need not be included in conveying the
+object code work.
+
+A “User Product” is either (1) a “consumer product”, which
+means any tangible personal property which is normally used for personal, family, or
+household purposes, or (2) anything designed or sold for incorporation into a
+dwelling. In determining whether a product is a consumer product, doubtful cases
+shall be resolved in favor of coverage. For a particular product received by a
+particular user, “normally used” refers to a typical or common use of
+that class of product, regardless of the status of the particular user or of the way
+in which the particular user actually uses, or expects or is expected to use, the
+product. A product is a consumer product regardless of whether the product has
+substantial commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+“Installation Information” for a User Product means any methods,
+procedures, authorization keys, or other information required to install and execute
+modified versions of a covered work in that User Product from a modified version of
+its Corresponding Source. The information must suffice to ensure that the continued
+functioning of the modified object code is in no case prevented or interfered with
+solely because modification has been made.
+
+If you convey an object code work under this section in, or with, or specifically for
+use in, a User Product, and the conveying occurs as part of a transaction in which
+the right of possession and use of the User Product is transferred to the recipient
+in perpetuity or for a fixed term (regardless of how the transaction is
+characterized), the Corresponding Source conveyed under this section must be
+accompanied by the Installation Information. But this requirement does not apply if
+neither you nor any third party retains the ability to install modified object code
+on the User Product (for example, the work has been installed in ROM).
+
+The requirement to provide Installation Information does not include a requirement to
+continue to provide support service, warranty, or updates for a work that has been
+modified or installed by the recipient, or for the User Product in which it has been
+modified or installed. Access to a network may be denied when the modification itself
+materially and adversely affects the operation of the network or violates the rules
+and protocols for communication across the network.
+
+Corresponding Source conveyed, and Installation Information provided, in accord with
+this section must be in a format that is publicly documented (and with an
+implementation available to the public in source code form), and must require no
+special password or key for unpacking, reading or copying.
+
+### 7. Additional Terms.
+
+“Additional permissions” are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions. Additional
+permissions that are applicable to the entire Program shall be treated as though they
+were included in this License, to the extent that they are valid under applicable
+law. If additional permissions apply only to part of the Program, that part may be
+used separately under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+When you convey a copy of a covered work, you may at your option remove any
+additional permissions from that copy, or from any part of it. (Additional
+permissions may be written to require their own removal in certain cases when you
+modify the work.) You may place additional permissions on material, added by you to a
+covered work, for which you have or can give appropriate copyright permission.
+
+Notwithstanding any other provision of this License, for material you add to a
+covered work, you may (if authorized by the copyright holders of that material)
+supplement the terms of this License with terms:
+
+* **a)** Disclaiming warranty or limiting liability differently from the terms of
+sections 15 and 16 of this License; or
+* **b)** Requiring preservation of specified reasonable legal notices or author
+attributions in that material or in the Appropriate Legal Notices displayed by works
+containing it; or
+* **c)** Prohibiting misrepresentation of the origin of that material, or requiring that
+modified versions of such material be marked in reasonable ways as different from the
+original version; or
+* **d)** Limiting the use for publicity purposes of names of licensors or authors of the
+material; or
+* **e)** Declining to grant rights under trademark law for use of some trade names,
+trademarks, or service marks; or
+* **f)** Requiring indemnification of licensors and authors of that material by anyone
+who conveys the material (or modified versions of it) with contractual assumptions of
+liability to the recipient, for any liability that these contractual assumptions
+directly impose on those licensors and authors.
+
+All other non-permissive additional terms are considered “further
+restrictions” within the meaning of section 10. If the Program as you received
+it, or any part of it, contains a notice stating that it is governed by this License
+along with a term that is a further restriction, you may remove that term. If a
+license document contains a further restriction but permits relicensing or conveying
+under this License, you may add to a covered work material governed by the terms of
+that license document, provided that the further restriction does not survive such
+relicensing or conveying.
+
+If you add terms to a covered work in accord with this section, you must place, in
+the relevant source files, a statement of the additional terms that apply to those
+files, or a notice indicating where to find the applicable terms.
+
+Additional terms, permissive or non-permissive, may be stated in the form of a
+separately written license, or stated as exceptions; the above requirements apply
+either way.
+
+### 8. Termination.
+
+You may not propagate or modify a covered work except as expressly provided under
+this License. Any attempt otherwise to propagate or modify it is void, and will
+automatically terminate your rights under this License (including any patent licenses
+granted under the third paragraph of section 11).
+
+However, if you cease all violation of this License, then your license from a
+particular copyright holder is reinstated (a) provisionally, unless and until the
+copyright holder explicitly and finally terminates your license, and (b) permanently,
+if the copyright holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+Moreover, your license from a particular copyright holder is reinstated permanently
+if the copyright holder notifies you of the violation by some reasonable means, this
+is the first time you have received notice of violation of this License (for any
+work) from that copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+Termination of your rights under this section does not terminate the licenses of
+parties who have received copies or rights from you under this License. If your
+rights have been terminated and not permanently reinstated, you do not qualify to
+receive new licenses for the same material under section 10.
+
+### 9. Acceptance Not Required for Having Copies.
+
+You are not required to accept this License in order to receive or run a copy of the
+Program. Ancillary propagation of a covered work occurring solely as a consequence of
+using peer-to-peer transmission to receive a copy likewise does not require
+acceptance. However, nothing other than this License grants you permission to
+propagate or modify any covered work. These actions infringe copyright if you do not
+accept this License. Therefore, by modifying or propagating a covered work, you
+indicate your acceptance of this License to do so.
+
+### 10. Automatic Licensing of Downstream Recipients.
+
+Each time you convey a covered work, the recipient automatically receives a license
+from the original licensors, to run, modify and propagate that work, subject to this
+License. You are not responsible for enforcing compliance by third parties with this
+License.
+
+An “entity transaction” is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an organization, or
+merging organizations. If propagation of a covered work results from an entity
+transaction, each party to that transaction who receives a copy of the work also
+receives whatever licenses to the work the party's predecessor in interest had or
+could give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if the predecessor
+has it or can get it with reasonable efforts.
+
+You may not impose any further restrictions on the exercise of the rights granted or
+affirmed under this License. For example, you may not impose a license fee, royalty,
+or other charge for exercise of rights granted under this License, and you may not
+initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging
+that any patent claim is infringed by making, using, selling, offering for sale, or
+importing the Program or any portion of it.
+
+### 11. Patents.
+
+A “contributor” is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The work thus
+licensed is called the contributor's “contributor version”.
+
+A contributor's “essential patent claims” are all patent claims owned or
+controlled by the contributor, whether already acquired or hereafter acquired, that
+would be infringed by some manner, permitted by this License, of making, using, or
+selling its contributor version, but do not include claims that would be infringed
+only as a consequence of further modification of the contributor version. For
+purposes of this definition, “control” includes the right to grant patent
+sublicenses in a manner consistent with the requirements of this License.
+
+Each contributor grants you a non-exclusive, worldwide, royalty-free patent license
+under the contributor's essential patent claims, to make, use, sell, offer for sale,
+import and otherwise run, modify and propagate the contents of its contributor
+version.
+
+In the following three paragraphs, a “patent license” is any express
+agreement or commitment, however denominated, not to enforce a patent (such as an
+express permission to practice a patent or covenant not to sue for patent
+infringement). To “grant” such a patent license to a party means to make
+such an agreement or commitment not to enforce a patent against the party.
+
+If you convey a covered work, knowingly relying on a patent license, and the
+Corresponding Source of the work is not available for anyone to copy, free of charge
+and under the terms of this License, through a publicly available network server or
+other readily accessible means, then you must either (1) cause the Corresponding
+Source to be so available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner consistent with
+the requirements of this License, to extend the patent license to downstream
+recipients. “Knowingly relying” means you have actual knowledge that, but
+for the patent license, your conveying the covered work in a country, or your
+recipient's use of the covered work in a country, would infringe one or more
+identifiable patents in that country that you have reason to believe are valid.
+
+If, pursuant to or in connection with a single transaction or arrangement, you
+convey, or propagate by procuring conveyance of, a covered work, and grant a patent
+license to some of the parties receiving the covered work authorizing them to use,
+propagate, modify or convey a specific copy of the covered work, then the patent
+license you grant is automatically extended to all recipients of the covered work and
+works based on it.
+
+A patent license is “discriminatory” if it does not include within the
+scope of its coverage, prohibits the exercise of, or is conditioned on the
+non-exercise of one or more of the rights that are specifically granted under this
+License. You may not convey a covered work if you are a party to an arrangement with
+a third party that is in the business of distributing software, under which you make
+payment to the third party based on the extent of your activity of conveying the
+work, and under which the third party grants, to any of the parties who would receive
+the covered work from you, a discriminatory patent license (a) in connection with
+copies of the covered work conveyed by you (or copies made from those copies), or (b)
+primarily for and in connection with specific products or compilations that contain
+the covered work, unless you entered into that arrangement, or that patent license
+was granted, prior to 28 March 2007.
+
+Nothing in this License shall be construed as excluding or limiting any implied
+license or other defenses to infringement that may otherwise be available to you
+under applicable patent law.
+
+### 12. No Surrender of Others' Freedom.
+
+If conditions are imposed on you (whether by court order, agreement or otherwise)
+that contradict the conditions of this License, they do not excuse you from the
+conditions of this License. If you cannot convey a covered work so as to satisfy
+simultaneously your obligations under this License and any other pertinent
+obligations, then as a consequence you may not convey it at all. For example, if you
+agree to terms that obligate you to collect a royalty for further conveying from
+those to whom you convey the Program, the only way you could satisfy both those terms
+and this License would be to refrain entirely from conveying the Program.
+
+### 13. Use with the GNU Affero General Public License.
+
+Notwithstanding any other provision of this License, you have permission to link or
+combine any covered work with a work licensed under version 3 of the GNU Affero
+General Public License into a single combined work, and to convey the resulting work.
+The terms of this License will continue to apply to the part which is the covered
+work, but the special requirements of the GNU Affero General Public License, section
+13, concerning interaction through a network will apply to the combination as such.
+
+### 14. Revised Versions of this License.
+
+The Free Software Foundation may publish revised and/or new versions of the GNU
+General Public License from time to time. Such new versions will be similar in spirit
+to the present version, but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program specifies that
+a certain numbered version of the GNU General Public License “or any later
+version” applies to it, you have the option of following the terms and
+conditions either of that numbered version or of any later version published by the
+Free Software Foundation. If the Program does not specify a version number of the GNU
+General Public License, you may choose any version ever published by the Free
+Software Foundation.
+
+If the Program specifies that a proxy can decide which future versions of the GNU
+General Public License can be used, that proxy's public statement of acceptance of a
+version permanently authorizes you to choose that version for the Program.
+
+Later license versions may give you additional or different permissions. However, no
+additional obligations are imposed on any author or copyright holder as a result of
+your choosing to follow a later version.
+
+### 15. Disclaimer of Warranty.
+
+THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER
+EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE
+QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
+DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+### 16. Limitation of Liability.
+
+IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY
+COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS
+PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL,
+INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE
+OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE
+WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+### 17. Interpretation of Sections 15 and 16.
+
+If the disclaimer of warranty and limitation of liability provided above cannot be
+given local legal effect according to their terms, reviewing courts shall apply local
+law that most closely approximates an absolute waiver of all civil liability in
+connection with the Program, unless a warranty or assumption of liability accompanies
+a copy of the Program in return for a fee.
+
+END OF TERMS AND CONDITIONS
+
+## How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest possible use to
+the public, the best way to achieve this is to make it free software which everyone
+can redistribute and change under these terms.
+
+To do so, attach the following notices to the program. It is safest to attach them
+to the start of each source file to most effectively state the exclusion of warranty;
+and each file should have at least the “copyright” line and a pointer to
+where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program does terminal interaction, make it output a short notice like this
+when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type 'show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type 'show c' for details.
+
+The hypothetical commands 'show w' and 'show c' should show the appropriate parts of
+the General Public License. Of course, your program's commands might be different;
+for a GUI interface, you would use an “about box”.
+
+You should also get your employer (if you work as a programmer) or school, if any, to
+sign a “copyright disclaimer” for the program, if necessary. For more
+information on this, and how to apply and follow the GNU GPL, see
+&lt;<http://www.gnu.org/licenses/>&gt;.
+
+The GNU General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may consider it
+more useful to permit linking proprietary applications with the library. If this is
+what you want to do, use the GNU Lesser General Public License instead of this
+License. But first, please read
+&lt;<http://www.gnu.org/philosophy/why-not-lgpl.html>&gt;.

+ 55 - 0
Meridian/meridianTV/electra_extras/sbinject/theos/Prefix.pch

@@ -0,0 +1,55 @@
+#ifdef DEBUG
+	#define __DEBUG__
+#endif
+
+#ifdef __OBJC__
+	#import <_Prefix/NullabilityCompat.h>
+
+	#if __has_feature(modules)
+		@import Foundation;
+	#else
+		#import <Foundation/Foundation.h>
+	#endif
+
+	#ifdef TARGET_OS_SIMULATOR
+		#define _THEOS_IS_SIMULATOR TARGET_OS_SIMULATOR
+	#else
+		#define _THEOS_IS_SIMULATOR TARGET_IPHONE_SIMULATOR
+	#endif
+
+	#if TARGET_IPHONE || _THEOS_IS_SIMULATOR
+		#if __has_feature(modules)
+			@import UIKit;
+		#else
+			#import <UIKit/UIKit.h>
+			
+		#endif
+
+		#import <_Prefix/IOSWebKitCompatHacks.h>
+	#endif
+
+	#if TARGET_MACOSX
+		#if __has_feature(modules)
+			@import Cocoa;
+			@import AppKit;
+		#else
+			#import <Cocoa/Cocoa.h>
+			#import <AppKit/AppKit.h>
+		#endif
+	#endif
+
+	#import <_Prefix/HBLog.h>
+	#import <_Prefix/IOSMacros.h>
+	#define NB [NSBundle mainBundle]
+	#define UD [NSUserDefaults standardUserDefaults]
+	#define FM [NSFileManager defaultManager]
+#endif
+
+#ifndef __clang__
+#import <Availability.h>
+#undef NS_AVAILABLE
+#define NS_AVAILABLE(osx, ios)
+#undef __OSX_AVAILABLE_STARTING
+#define __OSX_AVAILABLE_STARTING(osx, ios)
+#include <stdbool.h>
+#endif

+ 6 - 0
Meridian/meridianTV/electra_extras/sbinject/theos/README.md

@@ -0,0 +1,6 @@
+# Theos
+**Unified cross-platform Makefile system.**
+
+See [LICENSE.md](LICENSE.md) for licensing information.
+
+To learn more, including how to install or switch to this fork of Theos, visit [**the wiki**](https://github.com/kirb/theos/wiki).

+ 31 - 0
Meridian/meridianTV/electra_extras/sbinject/theos/bin/deb_build_num.sh

@@ -0,0 +1,31 @@
+#!/bin/bash
+GETONLY=0
+if [[ $1 == "-g" ]]; then
+	GETONLY=1
+	shift
+fi
+
+if [[ $# -lt 2 ]]; then
+	echo "Syntax: $0 [-g] packagename versionname" >&2
+	exit 1
+fi
+
+if [[ ! -d $TOP_DIR/.debmake ]]; then
+	mkdir $TOP_DIR/.debmake
+fi
+
+PACKAGE=$1
+VERSION=$2
+INFOFILE=$TOP_DIR/.debmake/$PACKAGE-$VERSION
+if [[ ! -e $INFOFILE ]]; then
+	echo -n 1 > $INFOFILE
+	echo -n 1
+	exit 0
+else
+	CURNUM=$(cat $INFOFILE)
+	if [[ $GETONLY -eq 0 ]]; then
+		let CURNUM++
+		echo -n $CURNUM > $INFOFILE
+	fi
+	echo $CURNUM
+fi

+ 48 - 0
Meridian/meridianTV/electra_extras/sbinject/theos/bin/denicify.pl

@@ -0,0 +1,48 @@
+#!/usr/bin/perl
+
+use warnings;
+use FindBin;
+use lib "$FindBin::Bin/lib";
+
+use NIC::NICBase;
+
+use Module::Load::Conditional 'can_load';
+
+$nicfile = $ARGV[0] if($ARGV[0]);
+$outputdir = $ARGV[1];
+if(!$nicfile || !$outputdir) {
+	exitWithError("Syntax: $0 nicfile outputdir");
+}
+
+### LOAD THE NICFILE! ###
+open(my $nichandle, "<", $nicfile);
+my $line = <$nichandle>;
+my $nicversion = 1;
+if($line =~ /^nic (\w+)$/) {
+	$nicversion = $1;
+} elsif($nicfile =~ /\.tar$/) {
+	$nicversion = "Tar";
+}
+seek($nichandle, 0, 0);
+
+my $NICPackage = "NIC$nicversion";
+exitWithError("I don't understand NIC version $nicversion!") if(!can_load(modules => {"NIC::Formats::$NICPackage" => undef}));
+
+{
+	no warnings 'redefine';
+	sub NIC::NICBase::_meetsConstraints { return 1; }
+}
+
+my $NIC = "NIC::Formats::$NICPackage"->new($nichandle);
+$NIC->addConstraint("package");
+close($nichandle);
+### YAY! ###
+
+$NIC->build($outputdir);
+$NIC->dumpPreamble("pre.NIC");
+
+sub exitWithError {
+	my $error = shift;
+	print STDERR "[error] ", $error, $/;
+	exit 1;
+}

+ 200 - 0
Meridian/meridianTV/electra_extras/sbinject/theos/bin/dm.pl

@@ -0,0 +1,200 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+use File::Find;
+use File::Spec;
+use Cwd;
+use Getopt::Long;
+use Pod::Usage;
+use Archive::Tar;
+use IO::Compress::Gzip;
+use IO::Compress::Bzip2;
+
+package NIC::Archive::Tar::File;
+use parent "Archive::Tar::File";
+sub new {
+	my $class = shift;
+	my $self = Archive::Tar::File->new(@_);
+	bless($self, $class);
+	return $self;
+}
+
+sub full_path {
+	my $self = shift;
+	my $full_path = $self->SUPER::full_path(); $full_path = '' unless defined $full_path;
+	$full_path =~ s#^#./# if $full_path ne "" && $full_path ne "." && $full_path !~ m#^\./#;
+	return $full_path;
+}
+1;
+package main;
+
+our $VERSION = '2.0';
+
+our $_PROGNAME = "dm.pl";
+
+my $ADMINARCHIVENAME = "control.tar.gz";
+my $DATAARCHIVENAME = "data.tar";
+my $ARCHIVEVERSION = "2.0";
+
+$Archive::Tar::DO_NOT_USE_PREFIX = 1; # use GNU extensions (not POSIX prefix)
+
+our $compression = "gzip";
+Getopt::Long::Configure("bundling", "auto_version");
+GetOptions('compression|Z=s' => \$compression,
+	'build|b' => sub { },
+	'help|?' => sub { pod2usage(1); },
+	'man' => sub { pod2usage(-exitstatus => 0, -verbose => 2); })
+	or pod2usage(2);
+
+pod2usage(1) if(@ARGV < 2);
+
+my $pwd = Cwd::cwd();
+my $indir = File::Spec->rel2abs($ARGV[0]);
+my $outfile = $ARGV[1];
+
+die "ERROR: '$indir' is not a directory or does not exist.\n" unless -d $indir;
+
+my $controldir = File::Spec->catpath("", $indir, "DEBIAN");
+
+die "ERROR: control directory '$controldir' is not a directory or does not exist.\n" unless -d $controldir;
+my $mode = (lstat($controldir))[2];
+die sprintf("ERROR: control directory has bad permissions %03lo (must be >=0755 and <=0775)\n", $mode & 07777) if(($mode & 07757) != 0755);
+
+my $controlfile = File::Spec->catfile($controldir, "control");
+die "ERROR: control file '$controlfile' is not a plain file\n" unless -f $controlfile;
+my %control_data = read_control_file($controlfile);
+
+die "ERROR: package name has characters that aren't alphanumueric or '-+.'.\n" if($control_data{"package"} =~ m/[^a-zA-Z0-9+-.]/);
+die "ERROR: package version ".$control_data{"version"}." doesn't contain any digits.\n" if($control_data{"version"} !~ m/[0-9]/);
+
+foreach my $m ("preinst", "postinst", "prerm", "postrm", "extrainst_") {
+	$_ = File::Spec->catfile($controldir, $m);
+	next unless -e $_;
+	die "ERROR: maintainer script '$m' is not a plain file or symlink\n" unless(-f $_ || -l $_);
+	$mode = (lstat)[2];
+	die sprintf("ERROR: maintainer script '$m' has bad permissions %03lo (must be >=0555 and <=0775)\n", $mode & 07777) if(($mode & 07557) != 0555)
+}
+
+print "$_PROGNAME: building package `".$control_data{"package"}.":".$control_data{"architecture"}."' in `$outfile'\n";
+
+open(my $ar, '>', $outfile) or die $!;
+
+print $ar "!<arch>\n";
+print_ar_record($ar, "debian-binary", time, 0, 0, 0100644, 4);
+print_ar_file($ar, "$ARCHIVEVERSION\n", 4);
+
+{
+	my $tar = Archive::Tar->new();
+	$tar->add_files(tar_filelist($controldir));
+	my $comp;
+	my $zFd = IO::Compress::Gzip->new(\$comp, -Level => 9);
+	$tar->write($zFd);
+	$zFd->close();
+	print_ar_record($ar, $ADMINARCHIVENAME, time, 0, 0, 0100644, length($comp));
+	print_ar_file($ar, $comp, length($comp));
+} {
+	my $tar = Archive::Tar->new();
+	$tar->add_files(tar_filelist($indir));
+	my $comp;
+	my $zFd = compressed_fd(\$comp);
+	$tar->write($zFd);
+	$zFd->close();
+	print_ar_record($ar, compressed_filename($DATAARCHIVENAME), time, 0, 0, 0100644, length($comp));
+	print_ar_file($ar, $comp, length($comp));
+}
+
+close $ar;
+
+sub print_ar_record {
+	my ($fh, $filename, $timestamp, $uid, $gid, $mode, $size) = @_;
+	printf $fh "%-16s%-12lu%-6lu%-6lu%-8lo%-10ld`\n", $filename, $timestamp, $uid, $gid, $mode, $size;
+	$fh->flush();
+}
+
+sub print_ar_file {
+	my ($fh, $data, $size) = @_;
+	syswrite $fh, $data;
+	print $fh "\n" if($size % 2 == 1);
+	$fh->flush();
+}
+
+sub tar_filelist {
+	chdir(shift);
+	my @filelist;
+	my @symlinks;
+
+	find({wanted => sub {
+		return if m#^./DEBIAN#;
+		my $tf = NIC::Archive::Tar::File->new(file=>$_);
+		push @symlinks, $tf if -l;
+		push @filelist, $tf if ! -l;
+	}, no_chdir => 1}, ".");
+	return (@filelist, @symlinks);
+}
+
+sub read_control_file {
+	my $filename = shift;
+	open(my $fh, '<', $filename) or die "ERROR: can't open control file '$filename'\n";
+	my %data;
+	while(<$fh>) {
+		if(m/^(.*?): (.*)/) {
+			$data{lc($1)} = $2;
+		}
+	}
+	close $fh;
+	return %data;
+}
+
+sub compressed_fd {
+	my $sref = shift;
+	return IO::Compress::Gzip->new($sref, -Level => 9) if $::compression eq "gzip";
+	return IO::Compress::Bzip2->new($sref) if $::compression eq "bzip2";
+	open my $fh, ">", $sref;
+	return $fh;
+}
+
+sub compressed_filename {
+	my $fn = shift;
+	my $suffix = "";
+	$suffix = ".gz" if $::compression eq "gzip";
+	$suffix = ".bz2" if $::compression eq "bzip2";
+	return $fn.$suffix;
+}
+
+__END__
+
+=head1 NAME
+
+dm.pl
+
+=head1 SYNOPSIS
+
+dm.pl [options] <directory> <package>
+
+=head1 OPTIONS
+
+=over 8
+
+=item B<-b>
+
+This option exists solely for compatibility with dpkg-deb.
+
+=item B<-ZE<lt>compressionE<gt>>
+
+Specify the package compression type. Valid values are gzip (default), bzip2 and cat (no compression.)
+
+=item B<--help>, B<-?>
+
+Print a brief help message and exit.
+
+=item B<--man>
+
+Print a manual page and exit.
+
+=back
+
+=head1 DESCRIPTION
+
+B<This program> creates Debian software packages (.deb files) and is a drop-in replacement for dpkg-deb.
+
+=cut

+ 1 - 0
Meridian/meridianTV/electra_extras/sbinject/theos/bin/dm.pl.txt

@@ -0,0 +1 @@
+dm.pl is at revision ac95b88a5c84747b1c40c3456525efeb3a750eed

+ 46 - 0
Meridian/meridianTV/electra_extras/sbinject/theos/bin/fakeroot.sh

@@ -0,0 +1,46 @@
+#!/bin/bash
+required=0
+persistence=/tmp/dhbxxx
+
+while getopts ":p:rc" flag; do
+	case "$flag" in
+		:)	echo "$0: Option -$OPTARG requires an argument." 1>&2
+			exit 1
+			;;
+		\?)	echo "$0: Option -$OPTARG unrecognized." 1>&2
+			exit 1
+			;;
+		p)	persistence="$OPTARG" ;;
+		r)	required=1 ;;
+		c)	delpersistence=1 ;;
+	esac
+done
+shift $((OPTIND-1))
+cmd=$*
+
+mkdir -p $(dirname $persistence)
+touch $persistence
+
+if [[ $delpersistence -eq 1 ]]; then
+	rm -f $persistence
+	exit 0
+fi
+
+if [[ "$USER" == "root" ]]; then
+	fakeroot=""
+elif type fauxsu &> /dev/null; then
+	fakeroot="fauxsu -p $persistence -- "
+elif type fakeroot-ng &> /dev/null; then
+	fakeroot="fakeroot-ng -p $persistence -- "
+elif type fakeroot &> /dev/null; then
+	fakeroot="fakeroot -i $persistence -s $persistence -- "
+else
+	if [[ $required -eq 1 ]]; then
+		fakeroot=""
+	else
+		fakeroot=": "
+	fi
+fi
+
+#echo $fakeroot $cmd
+$fakeroot $cmd

+ 6 - 0
Meridian/meridianTV/electra_extras/sbinject/theos/bin/install.copyFile

@@ -0,0 +1,6 @@
+#!/bin/bash
+if [[ TARGET_INSTALL_REMOTE -eq 1 ]]; then
+	scp -P $THEOS_DEVICE_PORT "$1" $THEOS_DEVICE_USER@$THEOS_DEVICE_IP:$2
+else
+	cp "$1" "$2"
+fi

+ 19 - 0
Meridian/meridianTV/electra_extras/sbinject/theos/bin/install.exec

@@ -0,0 +1,19 @@
+#!/bin/bash
+if [[ TARGET_INSTALL_REMOTE -eq 1 ]]; then
+	args=(ssh)
+
+	if [[ ! -z "$THEOS_DEVICE_PORT" ]]; then
+		args+=(-p "$THEOS_DEVICE_PORT")
+	fi
+
+	if [[ ! -z "$THEOS_DEVICE_USER" ]]; then
+		args+=(-l "$THEOS_DEVICE_USER")
+	fi
+
+	args+=($THEOS_DEVICE_IP)
+	args+=("$@")
+
+	exec ${args[@]}
+else
+	exec su -c "$@"
+fi

+ 4 - 0
Meridian/meridianTV/electra_extras/sbinject/theos/bin/install.mergeDir

@@ -0,0 +1,4 @@
+#!/bin/bash
+cd "$1"
+# Use fakeroot.sh to ensure that permissions are preserved, and install.exec to ensure that we are running tar -x on the right system.
+fakeroot.sh -r tar -c . | install.exec "tar -x -C \"$2\""

+ 122 - 0
Meridian/meridianTV/electra_extras/sbinject/theos/bin/lib/Logos/Class.pm

@@ -0,0 +1,122 @@
+package Logos::Class;
+use strict;
+
+sub new {
+	my $proto = shift;
+	my $class = ref($proto) || $proto;
+	my $self = {};
+	$self->{NAME} = undef;
+	$self->{EXPR} = undef;
+	$self->{METAEXPR} = undef;
+	$self->{TYPE} = undef;
+	$self->{META} = 0;
+	$self->{INST} = 0;
+	$self->{OVERRIDDEN} = 0;
+	$self->{REQUIRED} = 0;
+	$self->{METHODS} = [];
+	$self->{NUM_METHODS} = 0;
+	$self->{PROPERTIES} = [];
+	$self->{NUM_PROPERTIES} = 0;
+	$self->{GROUP} = undef;
+	bless($self, $class);
+	return $self;
+}
+
+##################### #
+# Setters and Getters #
+# #####################
+sub name {
+	my $self = shift;
+	if(@_) { $self->{NAME} = shift; }
+	return $self->{NAME};
+}
+
+sub expression {
+	my $self = shift;
+	if(@_) {
+		$self->{EXPR} = shift;
+		$self->type("id");
+		$self->{OVERRIDDEN} = 1;
+	}
+	return $self->{EXPR};
+}
+
+sub metaexpression {
+	my $self = shift;
+	if(@_) {
+		$self->{METAEXPR} = shift;
+		$self->{OVERRIDDEN} = 1;
+	}
+	return $self->{METAEXPR};
+}
+
+sub type {
+	my $self = shift;
+	if(@_) { $self->{TYPE} = shift; }
+	return $self->{TYPE} if $self->{TYPE};
+	return $self->{NAME}."*";
+}
+
+sub hasmetahooks {
+	my $self = shift;
+	if(@_) { $self->{META} = shift; }
+	return $self->{META};
+}
+
+sub hasinstancehooks {
+	my $self = shift;
+	if(@_) { $self->{INST} = shift; }
+	return $self->{INST};
+}
+
+sub group {
+	my $self = shift;
+	if(@_) { $self->{GROUP} = shift; }
+	return $self->{GROUP};
+}
+
+sub required {
+	my $self = shift;
+	if(@_) { $self->{REQUIRED} = shift; }
+	return $self->{REQUIRED};
+}
+
+sub overridden {
+	my $self = shift;
+	return $self->{OVERRIDDEN};
+}
+
+sub methods {
+	my $self = shift;
+	return $self->{METHODS};
+}
+
+sub properties {
+	my $self = shift;
+	return $self->{PROPERTIES};
+}
+
+sub initRequired {
+	my $self = shift;
+	return $self->required || scalar @{$self->{METHODS}} > 0;
+}
+
+##### #
+# END #
+# #####
+
+sub addMethod {
+	my $self = shift;
+	my $hook = shift;
+	push(@{$self->{METHODS}}, $hook);
+	$self->{NUM_METHODS}++;
+}
+
+sub addProperty {
+	my $self = shift;
+	my $property = shift;
+	push(@{$self->{PROPERTIES}}, $property);
+	$self->{NUM_PROPERTIES}++;
+}
+
+1;

+ 64 - 0
Meridian/meridianTV/electra_extras/sbinject/theos/bin/lib/Logos/Function.pm

@@ -0,0 +1,64 @@
+package Logos::Function;
+use strict;
+
+sub new {
+	my $proto = shift;
+	my $function = ref($proto) || $proto;
+	my $self = {};
+	$self->{NAME} = undef;
+	$self->{RETVAL} = undef;
+	$self->{ARGS} = [];
+	$self->{GROUP} = undef;
+	$self->{REQUIRED} = 0;
+	bless($self, $function);
+	return $self;
+}
+
+##################### #
+# Setters and Getters #
+# #####################
+sub name {
+	my $self = shift;
+	if(@_) { $self->{NAME} = shift; }
+	return $self->{NAME};
+}
+
+sub retval {
+	my $self = shift;
+	if(@_) { $self->{RETVAL} = shift; }
+	return $self->{RETVAL};
+}
+
+sub args {
+	my $self = shift;
+	return $self->{ARGS};
+}
+
+sub group {
+	my $self = shift;
+	if(@_) { $self->{GROUP} = shift; }
+	return $self->{GROUP};
+}
+
+sub required {
+	my $self = shift;
+	if(@_) { $self->{REQUIRED} = shift; }
+	return $self->{REQUIRED};
+}
+
+sub initRequired {
+	my $self = shift;
+	return 1;
+}
+
+##### #
+# END #
+# #####
+
+sub addArg {
+	my $self = shift;
+	my $arg = shift;
+	push(@{$self->{ARGS}}, $arg);
+}
+
+1;

+ 0 - 0
Meridian/meridianTV/electra_extras/sbinject/theos/bin/lib/Logos/Generator.pm


Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.