├── .gitattributes
├── .gitignore
├── ChOma-main
├── .gitignore
├── .vscode
│ └── settings.json
├── Makefile
├── README.md
├── cert.p12
├── external
│ └── ios
│ │ ├── entitlements.plist
│ │ └── libcrypto.a
├── src
│ ├── Base64.c
│ ├── Base64.h
│ ├── BufferedStream.c
│ ├── BufferedStream.h
│ ├── CSBlob.c
│ ├── CSBlob.h
│ ├── CodeDirectory.c
│ ├── CodeDirectory.h
│ ├── FAT.c
│ ├── FAT.h
│ ├── FileStream.c
│ ├── FileStream.h
│ ├── Host.c
│ ├── Host.h
│ ├── MachO.c
│ ├── MachO.h
│ ├── MachOByteOrder.h
│ ├── MachOLoadCommand.c
│ ├── MachOLoadCommand.h
│ ├── MemoryStream.c
│ ├── MemoryStream.h
│ ├── PatchFinder.c
│ ├── PatchFinder.h
│ ├── SignOSSL.c
│ ├── SignOSSL.h
│ ├── Util.c
│ └── Util.h
└── tests
│ ├── choma_cli
│ └── main.c
│ ├── ct_bypass
│ ├── AppStoreCodeDirectory.h
│ ├── DecryptedSignature.h
│ ├── PrivateKey.h
│ ├── TemplateSignatureBlob.h
│ └── main.c
│ ├── fat_create
│ └── main.c
│ └── kpf
│ └── main.c
├── LICENSE
├── README.md
├── bootstrap.entitlements
├── bootstrap
├── .gitignore
├── .vscode
│ └── settings.json
├── Makefile
├── assert.h
├── autosign.m
├── bootstrap.c
├── common.c
├── common.h
├── common.m
├── control
├── dobby.h
├── envbuf.c
├── envbuf.h
├── exechook.c
├── fishhook.c
├── fishhook.h
├── fixfork.c
├── fixsuid.c
├── interpose.c
├── layout
│ └── DEBIAN
│ │ └── preinst
├── libdobby.a
├── libproc.h
├── libproc_private.h
├── platformhook.m
├── prefshook.m
├── prefshook.rtf
├── sandbox.h
└── syscall.S
├── bootstrapd
├── .gitignore
├── .vscode
│ └── settings.json
├── Makefile
├── assert.h
├── bootstrapd.h
├── common.h
├── control
├── entitlements.plist
├── envbuf.c
├── envbuf.h
├── ipc.h
├── ipc.m
├── jiter.m
├── libbsd.h
├── libbsd.m
├── libproc.h
├── libproc_private.h
├── main.m
├── openssh.m
├── usreboot.m
├── varClean.m
└── xpc
│ ├── XPC.apinotes
│ ├── activity.h
│ ├── availability.h
│ ├── base.h
│ ├── connection.h
│ ├── debug.h
│ ├── endpoint.h
│ ├── module.modulemap
│ ├── private.h
│ └── xpc.h
├── copy.sh
├── devtest
├── .gitignore
├── Makefile
├── control
├── entitlements.plist
└── main.m
├── entitlements
├── com.apple.mobilemail.extra
├── com.apple.mobilemail.strip
├── com.apple.mobilesafari.extra
├── com.apple.mobilesafari.strip
├── com.apple.mobileslideshow.extra
└── com.apple.mobileslideshow.photo-picker.extra
├── fastPathSign
├── .gitignore
├── Makefile
├── roothide.xml
└── src
│ ├── Templates
│ ├── AppStoreCodeDirectory.h
│ ├── DecryptedSignature.h
│ ├── PrivateKey.h
│ └── SignatureBlob.h
│ ├── codesign.h
│ ├── codesign.m
│ ├── codesign.o
│ ├── coretrust_bug.c
│ ├── coretrust_bug.h
│ ├── coretrust_bug.o
│ ├── external
│ ├── .gitignore
│ ├── include
│ │ └── choma
│ └── lib
│ │ ├── libchoma.a
│ │ └── libcrypto.a
│ ├── main.m
│ └── main.o
├── ldid
├── .github
│ └── workflows
│ │ └── build.yml
├── .gitignore
├── COPYING
├── Makefile
├── README.md
├── _ldid
├── docs
│ ├── ldid.1
│ ├── ldid.zh_CN.1
│ └── ldid.zh_TW.1
├── ldid.cpp
├── ldid.hpp
├── libcrypto.a
├── libplist-2.0.a
├── machine.h
└── roothide.xml
├── nickchan.entitlements
├── preload
├── .gitignore
├── Makefile
├── control
├── entitlements.plist
├── layout
│ └── DEBIAN
│ │ └── postinst
├── prelib.m
├── preload.m
└── sandbox.h
├── rebuild.sh
├── rebuildapp
├── .gitignore
├── .vscode
│ └── settings.json
├── Makefile
├── Templates
│ ├── AppStoreCodeDirectory.h
│ ├── DecryptedSignature.h
│ ├── PrivateKey.h
│ └── SignatureBlob.h
├── choma
├── control
├── entitlements.plist
├── layout
│ └── basebin
│ │ └── rebuildapps.sh
├── libchoma.a
├── libcrypto.a
├── libplist-2.0.a
├── main.m
└── realstore.cpp
├── test.sh
└── uicache
├── .gitignore
├── .vscode
└── settings.json
├── Makefile
├── choma
├── control
├── entitlements.plist
├── exepatch.c
├── libchoma.a
└── main.m
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | installdeb2
3 |
--------------------------------------------------------------------------------
/ChOma-main/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore all
2 | *
3 |
4 | # Unignore all with extensions
5 | !*.*
6 |
7 | # Unignore Makefile
8 | !Makefile
9 |
10 | # Unignore all dirs
11 | !*/
12 |
13 | # Ignore build/
14 | build/
15 | output/
16 | data/
17 |
18 | # Ignore .DS_Store
19 | .DS_Store
20 |
21 | # Ignore .vscode/
22 | .vscode/*
23 | !.vscode/settings.json
24 |
25 | # Ignore nocommit-* files and dirs
26 | nocommit-*
27 |
28 | # Ignore Python scripts
29 | *.py
30 |
31 | # Miscellaneous
32 | ca.key
33 | *.tipa
34 | *.zip
35 | *.ipa
36 | *.app
37 | Payload/
--------------------------------------------------------------------------------
/ChOma-main/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "C_Cpp.default.compilerPath": "/usr/bin/clang",
3 | "clangd.fallbackFlags": [
4 | "-I${workspaceFolder}/src/external",
5 | "-I${workspaceFolder}/output/include",
6 | "-I/opt/homebrew/Cellar/openssl@3/3.1.3/include",
7 | ],
8 | "files.associations": {
9 | "*.ejs": "html",
10 | "codedirectory.h": "c",
11 | "templatesignatureblob.h": "c",
12 | "loader.h": "c",
13 | "__hash_table": "c",
14 | "__split_buffer": "c",
15 | "array": "c",
16 | "bitset": "c",
17 | "initializer_list": "c",
18 | "span": "c",
19 | "string": "c",
20 | "string_view": "c",
21 | "unordered_map": "c",
22 | "vector": "c",
23 | "macho.h": "c",
24 | "host.h": "c"
25 | }
26 | }
--------------------------------------------------------------------------------
/ChOma-main/Makefile:
--------------------------------------------------------------------------------
1 | CC := clang
2 | CFLAGS := -Wall -Werror $(shell pkg-config --cflags libcrypto) -fPIC -Wno-pointer-to-int-cast -Wno-unused-command-line-argument -Wno-deprecated-declarations -Wno-unused-variable -framework CoreFoundation
3 | DEBUG ?= 0
4 | ifeq ($(DEBUG), 1)
5 | CFLAGS += -fsanitize=address -static-libsan
6 | endif
7 |
8 | LIB_NAME := libchoma
9 |
10 | ifeq ($(TARGET), ios)
11 | BUILD_DIR := build/ios
12 | OUTPUT_DIR := output/ios
13 | CFLAGS += -arch arm64 -arch arm64e -isysroot $(shell xcrun --sdk iphoneos --show-sdk-path) -miphoneos-version-min=14.0 external/ios/libcrypto.a
14 | else
15 | BUILD_DIR := build
16 | OUTPUT_DIR := output
17 | CFLAGS += $(shell pkg-config --libs libcrypto)
18 | endif
19 |
20 | SRC_DIR := src
21 |
22 | HEADER_OUTPUT_DIR := $(OUTPUT_DIR)/include
23 | TESTS_SRC_DIR := tests
24 | TESTS_BUILD_DIR := $(BUILD_DIR)/tests
25 | TESTS_OUTPUT_DIR := $(OUTPUT_DIR)/tests
26 |
27 | LIB_DIR := $(OUTPUT_DIR)/lib
28 | TESTS_DIR := build/tests
29 |
30 | STATIC_LIB := $(LIB_DIR)/$(LIB_NAME).a
31 | DYNAMIC_LIB := $(LIB_DIR)/$(LIB_NAME).dylib
32 |
33 | SRC_FILES := $(wildcard $(SRC_DIR)/*.c)
34 | OBJ_FILES := $(patsubst $(SRC_DIR)/%.c,$(BUILD_DIR)/%.o,$(SRC_FILES))
35 |
36 | TESTS_SUBDIRS := $(wildcard $(TESTS_SRC_DIR)/*)
37 | TESTS_BINARIES := $(patsubst $(TESTS_SRC_DIR)/%,$(TESTS_OUTPUT_DIR)/%,$(TESTS_SUBDIRS))
38 |
39 | CHOMA_HEADERS_SRC_DIR := $(SRC_DIR)
40 | CHOMA_HEADERS_DST_DIR := $(HEADER_OUTPUT_DIR)/choma
41 |
42 | CHOMA_HEADERS := $(shell find $(CHOMA_HEADERS_SRC_DIR) -type f -name "*.h")
43 |
44 | all: $(STATIC_LIB) $(DYNAMIC_LIB) copy-choma-headers clean-test $(TESTS_BINARIES)
45 |
46 | $(STATIC_LIB): $(OBJ_FILES)
47 | @mkdir -p $(LIB_DIR)
48 | ar rcs $@ $^
49 |
50 | $(DYNAMIC_LIB): $(OBJ_FILES)
51 | @mkdir -p $(LIB_DIR)
52 | $(CC) $(CFLAGS) -shared -o $@ $^
53 |
54 | $(BUILD_DIR)/%.o: $(SRC_DIR)/%.c
55 | @mkdir -p $(dir $@)
56 | $(CC) $(CFLAGS) -c $< -o $@
57 |
58 | ifeq ($(TARGET), ios)
59 | $(TESTS_OUTPUT_DIR)/%: $(TESTS_SRC_DIR)/%
60 | @mkdir -p $(dir $@)
61 | @rm -rf $@
62 | $(CC) $(CFLAGS) -I$(OUTPUT_DIR)/include -o $@ $*.c $(OUTPUT_DIR)/lib/libchoma.a
63 | @ldid -Sexternal/ios/entitlements.plist $@
64 | else
65 | $(TESTS_OUTPUT_DIR)/%: $(TESTS_SRC_DIR)/%
66 | @mkdir -p $(dir $@)
67 | @rm -rf $@
68 | $(CC) $(CFLAGS) -I$(OUTPUT_DIR)/include -o $@ $*.c $(OUTPUT_DIR)/lib/libchoma.a
69 | endif
70 |
71 | copy-choma-headers: $(CHOMA_HEADERS)
72 | @rm -rf $(CHOMA_HEADERS_DST_DIR)
73 | @mkdir -p $(CHOMA_HEADERS_DST_DIR)
74 | @cp $^ $(CHOMA_HEADERS_DST_DIR)
75 |
76 | clean-all: clean clean-output
77 |
78 | clean: clean-test
79 | @rm -rf $(BUILD_DIR)/*
80 |
81 | clean-test:
82 | @rm -rf $(OUTPUT_DIR)/tests/*
83 |
84 | clean-output:
85 | @rm -rf $(OUTPUT_DIR)/*
--------------------------------------------------------------------------------
/ChOma-main/README.md:
--------------------------------------------------------------------------------
1 | # ChOma
2 |
3 | ChOma is a simple library for parsing and manipulating MachO files and their CMS blobs. Written for exploitation of [CVE-2023-41991](https://support.apple.com/en-gb/HT213926), a vulnerability in the CoreTrust kernel extension, and for use in [TrollStore](https://github.com/opa334/TrollStore), and in [Dopamine](https://github.com/opa334/Dopamine) as a kernel patchfinder.
4 |
5 | ## Usage
6 |
7 | To use the library, you can compile with `make all`. This will produce the `choma_cli` executable that demonstrates the abilities of this library, and then `libchoma.a` and `libchoma.dylib` which can be linked to your own project.
8 |
9 | In `output/tests`, you will find `choma_cli` and `ct_bypass`. `choma_cli` is a simple CLI tool that demonstrates the abilities of this library, and `ct_bypass` is a proof-of-concept exploit for CVE-2023-41991 that uses this library. `ct_bypass` only works on iOS binaries, as trying to use macOS binaries will result in the bypass being unsuccessful as we use an iOS identity to insert into the code signature.
10 |
11 | ## CoreTrust bypass
12 | ChOma was written primarily for the purpose of exploiting CVE-2023-41991, which allows a binary to bypass CoreTrust during code-signing and appear as an App Store-signed binary. As a result, binaries can be permanently signed on device and have arbitrary entitlements, apart from a few restricted ones that are only allowed to be used by trustcached binaries.
13 |
14 | The vulnerability is caused by CoreTrust incorrectly handling multiple SignerInfo structures in a CMS blob. By having one SignerInfo that contains a valid signature (but from an identity that is not trusted by CoreTrust), and another SignerInfo that contains an invalid signature (but from an App Store identity), we can trick CoreTrust into thinking that the binary is signed by the App Store identity, and therefore allow it to be executed.
15 |
16 | The exploit is implemented in `ct_bypass`, and works by:
17 | 1. Taking a pseudo-signed binary (a binary that has been signed by `ldid`).
18 | 2. Updating the load commands by calculating the new sizes of the __LINKEDIT segment and the code signature.
19 | 3. Updating the page hashes in the SHA256 CodeDirectory to match the new load command data.
20 | 4. Replacing the SHA1 CodeDirectory with one from a valid App Store-signed binary.
21 | 5. Inserting a template signature blob into the code signature, containing two SignerInfo structures.
22 | 6. Updating the necessary fields in the signature blob to match the CD hashes.
23 | 7. Signing the signature blob for the custom identity (the App Store identity will already have an intact signature).
24 | 8. Inserting the new code signature into the binary.
25 |
26 | ## Terminology
27 | Inside ChOma, there are a few terms that are used to describe various parts of the MachO file. These are:
28 | - **FAT** - represents a FAT MachO file (a MachO file that contains multiple slices, which are each a MachO file for a different architecture).
29 | - **MachO** - represents either a single-architecture MachO file, or a slice of a FAT MachO file.
30 |
31 | ## Underlying mechanisms
32 | ChOma uses the `MemoryBuffer` structure to provide a unified way to read, write, shrink and expand data buffers, that works across both files and memory. Each `MemoryBuffer` has a `context` field that determines whether the functions interpret it as a `BufferedStream` object (for regular memory buffers) or as a `FileStream` object (for files).
33 |
34 | Each `MemoryBuffer` object contains function pointers for reading, writing, retrieving the size, expanding, shrinking and then soft or hard cloning. You can inspect these inside [`src/MemoryBuffer.h`](src/MemoryStream.h), and can see how they are used by looking at how we manipulate MachO files across the library.
--------------------------------------------------------------------------------
/ChOma-main/cert.p12:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roothide/Bootstrap-basebin/46c860dbb65e47d7d34ad9ed6731ca9245b67f7b/ChOma-main/cert.p12
--------------------------------------------------------------------------------
/ChOma-main/external/ios/entitlements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | platform-application
6 |
7 | com.apple.private.security.no-container
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ChOma-main/external/ios/libcrypto.a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roothide/Bootstrap-basebin/46c860dbb65e47d7d34ad9ed6731ca9245b67f7b/ChOma-main/external/ios/libcrypto.a
--------------------------------------------------------------------------------
/ChOma-main/src/Base64.c:
--------------------------------------------------------------------------------
1 | #include "Base64.h"
2 |
3 | // https://stackoverflow.com/a/6782480
4 | static char encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
5 | 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
6 | 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
7 | 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
8 | 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
9 | 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
10 | 'w', 'x', 'y', 'z', '0', '1', '2', '3',
11 | '4', '5', '6', '7', '8', '9', '+', '/'};
12 | static int mod_table[] = {0, 2, 1};
13 |
14 |
15 | char *base64_encode(const unsigned char *data,
16 | size_t input_length,
17 | size_t *output_length) {
18 |
19 | *output_length = 4 * ((input_length + 2) / 3);
20 |
21 | char *encoded_data = malloc(*output_length);
22 | if (encoded_data == NULL) return NULL;
23 |
24 | for (int i = 0, j = 0; i < input_length;) {
25 |
26 | uint32_t octet_a = i < input_length ? (unsigned char)data[i++] : 0;
27 | uint32_t octet_b = i < input_length ? (unsigned char)data[i++] : 0;
28 | uint32_t octet_c = i < input_length ? (unsigned char)data[i++] : 0;
29 |
30 | uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
31 |
32 | encoded_data[j++] = encoding_table[(triple >> 3 * 6) & 0x3F];
33 | encoded_data[j++] = encoding_table[(triple >> 2 * 6) & 0x3F];
34 | encoded_data[j++] = encoding_table[(triple >> 1 * 6) & 0x3F];
35 | encoded_data[j++] = encoding_table[(triple >> 0 * 6) & 0x3F];
36 | }
37 |
38 | for (int i = 0; i < mod_table[input_length % 3]; i++)
39 | encoded_data[*output_length - 1 - i] = '=';
40 |
41 | return encoded_data;
42 | }
--------------------------------------------------------------------------------
/ChOma-main/src/Base64.h:
--------------------------------------------------------------------------------
1 | #ifndef BASE64_H
2 | #define BASE64_H
3 |
4 | #include
5 | #include
6 |
7 | char *base64_encode(const unsigned char *data,
8 | size_t input_length,
9 | size_t *output_length);
10 |
11 | #endif // BASE64_H
--------------------------------------------------------------------------------
/ChOma-main/src/BufferedStream.h:
--------------------------------------------------------------------------------
1 | #ifndef BUFFERED_STREAM_H
2 | #define BUFFERED_STREAM_H
3 |
4 | #include "MemoryStream.h"
5 | #include
6 |
7 | #define BUFFERED_STREAM_FLAG_AUTO_EXPAND (1 << 0)
8 |
9 | typedef struct BufferedStreamContext {
10 | uint8_t *buffer;
11 | size_t bufferSize;
12 | uint32_t subBufferStart;
13 | size_t subBufferSize;
14 | } BufferedStreamContext;
15 |
16 | MemoryStream *buffered_stream_init_from_buffer_nocopy(void *buffer, size_t bufferSize, uint32_t flags);
17 | MemoryStream *buffered_stream_init_from_buffer(void *buffer, size_t bufferSize, uint32_t flags);
18 |
19 | #endif // BUFFERED_STREAM_H
--------------------------------------------------------------------------------
/ChOma-main/src/CSBlob.h:
--------------------------------------------------------------------------------
1 | #ifndef CS_BLOB_H
2 | #define CS_BLOB_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include "FAT.h"
10 | #include "MachO.h"
11 | #include "MemoryStream.h"
12 |
13 | // Blob index
14 | typedef struct __BlobIndex {
15 | uint32_t type;
16 | uint32_t offset;
17 | } CS_BlobIndex;
18 |
19 | // CMS superblob
20 | typedef struct __SuperBlob {
21 | uint32_t magic;
22 | uint32_t length;
23 | uint32_t count;
24 | CS_BlobIndex index[];
25 | } CS_SuperBlob;
26 |
27 | typedef struct __GenericBlob {
28 | uint32_t magic; /* magic number */
29 | uint32_t length; /* total length of blob */
30 | char data[];
31 | } CS_GenericBlob;
32 |
33 | // CMS blob magic types
34 | enum {
35 | CSMAGIC_REQUIREMENT = 0xfade0c00,
36 | CSMAGIC_REQUIREMENTS = 0xfade0c01,
37 | CSMAGIC_CODEDIRECTORY = 0xfade0c02,
38 | CSMAGIC_EMBEDDED_SIGNATURE = 0xfade0cc0,
39 | CSMAGIC_EMBEDDED_SIGNATURE_OLD = 0xfade0b02,
40 | CSMAGIC_EMBEDDED_ENTITLEMENTS = 0xfade7171,
41 | CSMAGIC_EMBEDDED_DER_ENTITLEMENTS = 0xfade7172,
42 | CSMAGIC_DETACHED_SIGNATURE = 0xfade0cc1,
43 | CSMAGIC_BLOBWRAPPER = 0xfade0b01,
44 | CSMAGIC_EMBEDDED_LAUNCH_CONSTRAINT = 0xfade8181,
45 | } CS_BlobMagic;
46 |
47 | enum {
48 | CSSLOT_CODEDIRECTORY = 0,
49 | CSSLOT_INFOSLOT = 1,
50 | CSSLOT_REQUIREMENTS = 2,
51 | CSSLOT_RESOURCEDIR = 3,
52 | CSSLOT_APPLICATION = 4,
53 | CSSLOT_ENTITLEMENTS = 5,
54 | CSSLOT_DER_ENTITLEMENTS = 7,
55 | CSSLOT_LAUNCH_CONSTRAINT_SELF = 8,
56 | CSSLOT_LAUNCH_CONSTRAINT_PARENT = 9,
57 | CSSLOT_LAUNCH_CONSTRAINT_RESPONSIBLE = 10,
58 | CSSLOT_LIBRARY_CONSTRAINT = 11,
59 |
60 | CSSLOT_ALTERNATE_CODEDIRECTORIES = 0x1000, /* first alternate CodeDirectory, if any */
61 | CSSLOT_ALTERNATE_CODEDIRECTORY_MAX = 5, /* max number of alternate CD slots */
62 | CSSLOT_ALTERNATE_CODEDIRECTORY_LIMIT = CSSLOT_ALTERNATE_CODEDIRECTORIES + CSSLOT_ALTERNATE_CODEDIRECTORY_MAX, /* one past the last */
63 |
64 | CSSLOT_SIGNATURESLOT = 0x10000,
65 | CSSLOT_IDENTIFICATIONSLOT = 0x10001,
66 | CSSLOT_TICKETSLOT = 0x10002,
67 | } CS_SlotType;
68 |
69 | typedef struct s_CS_DecodedBlob {
70 | struct s_CS_DecodedBlob *next;
71 | uint32_t type;
72 | MemoryStream *stream;
73 | } CS_DecodedBlob;
74 |
75 | typedef struct s_CS_DecodedSuperBlob {
76 | uint32_t magic;
77 | struct s_CS_DecodedBlob *firstBlob;
78 | } CS_DecodedSuperBlob;
79 |
80 | // Convert blob magic to readable blob type string
81 | const char *cs_blob_magic_to_string(uint32_t magic);
82 | const char *cs_slot_type_to_string(uint32_t slotType);
83 |
84 | // Extract Code Signature to file
85 | int macho_extract_cs_to_file(MachO *macho, CS_SuperBlob *superblob);
86 |
87 | int macho_find_code_signature_bounds(MachO *macho, uint32_t *offsetOut, uint32_t *sizeOut);
88 |
89 | CS_SuperBlob *macho_read_code_signature(MachO *macho);
90 |
91 | int macho_replace_code_signature(MachO *macho, CS_SuperBlob *superblob);
92 |
93 | int update_load_commands(MachO *macho, CS_SuperBlob *superblob, uint64_t originalSize);
94 |
95 | CS_DecodedBlob *csd_blob_init(uint32_t type, CS_GenericBlob *blobData);
96 | int csd_blob_read(CS_DecodedBlob *blob, uint64_t offset, size_t size, void *outBuf);
97 | int csd_blob_write(CS_DecodedBlob *blob, uint64_t offset, size_t size, const void *inBuf);
98 | int csd_blob_insert(CS_DecodedBlob *blob, uint64_t offset, size_t size, const void *inBuf);
99 | int csd_blob_delete(CS_DecodedBlob *blob, uint64_t offset, size_t size);
100 | int csd_blob_read_string(CS_DecodedBlob *blob, uint64_t offset, char **outString);
101 | int csd_blob_write_string(CS_DecodedBlob *blob, uint64_t offset, const char *string);
102 | int csd_blob_get_size(CS_DecodedBlob *blob);
103 | uint32_t csd_blob_get_type(CS_DecodedBlob *blob);
104 | void csd_blob_set_type(CS_DecodedBlob *blob, uint32_t type);
105 | void csd_blob_free(CS_DecodedBlob *blob);
106 |
107 | CS_DecodedSuperBlob *csd_superblob_decode(CS_SuperBlob *superblob);
108 | CS_SuperBlob *csd_superblob_encode(CS_DecodedSuperBlob *decodedSuperblob);
109 | CS_DecodedBlob *csd_superblob_find_blob(CS_DecodedSuperBlob *superblob, uint32_t type, uint32_t *indexOut);
110 | int csd_superblob_insert_blob_after_blob(CS_DecodedSuperBlob *superblob, CS_DecodedBlob *blobToInsert, CS_DecodedBlob *afterBlob);
111 | int csd_superblob_insert_blob_at_index(CS_DecodedSuperBlob *superblob, CS_DecodedBlob *blobToInsert, uint32_t atIndex);
112 | int csd_superblob_append_blob(CS_DecodedSuperBlob *superblob, CS_DecodedBlob *blobToAppend);
113 | int csd_superblob_remove_blob(CS_DecodedSuperBlob *superblob, CS_DecodedBlob *blobToRemove); // <- Important: When calling this, caller is responsible for freeing blobToRemove
114 | int csd_superblob_remove_blob_at_index(CS_DecodedSuperBlob *superblob, uint32_t atIndex);
115 | int csd_superblob_print_content(CS_DecodedSuperBlob *decodedSuperblob, MachO *macho, bool printAllSlots, bool verifySlots);
116 | void csd_superblob_free(CS_DecodedSuperBlob *decodedSuperblob);
117 |
118 |
119 | #endif // CS_BLOB_H
--------------------------------------------------------------------------------
/ChOma-main/src/CodeDirectory.h:
--------------------------------------------------------------------------------
1 | #ifndef CODE_DIRECTORY_H
2 | #define CODE_DIRECTORY_H
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | #include "MachO.h"
9 | #include "CSBlob.h"
10 | #include "FAT.h"
11 | #include "MachOByteOrder.h"
12 | #include "MachOLoadCommand.h"
13 | #include "MemoryStream.h"
14 |
15 |
16 | // Code directory blob header
17 | typedef struct __CodeDirectory {
18 | uint32_t magic;
19 | uint32_t length;
20 | uint32_t version;
21 | uint32_t flags;
22 | uint32_t hashOffset;
23 | uint32_t identOffset;
24 | uint32_t nSpecialSlots;
25 | uint32_t nCodeSlots;
26 | uint32_t codeLimit;
27 | uint8_t hashSize;
28 | uint8_t hashType;
29 | uint8_t spare1;
30 | uint8_t pageSize;
31 | uint32_t spare2;
32 | uint32_t scatterOffset;
33 | uint32_t teamOffset;
34 | } CS_CodeDirectory;
35 |
36 | enum CS_HashType {
37 | CS_HASHTYPE_SHA160_160 = 1,
38 | CS_HASHTYPE_SHA256_256 = 2,
39 | CS_HASHTYPE_SHA256_160 = 3,
40 | CS_HASHTYPE_SHA384_384 = 4,
41 | };
42 |
43 | char *csd_code_directory_copy_identity(CS_DecodedBlob *codeDirBlob, uint32_t *offsetOut);
44 | char *csd_code_directory_copy_team_id(CS_DecodedBlob *codeDirBlob, uint32_t *offsetOut);
45 | int csd_code_directory_set_team_id(CS_DecodedBlob *codeDirBlob, char *newTeamID);
46 | uint32_t csd_code_directory_get_flags(CS_DecodedBlob *codeDirBlob);
47 | void csd_code_directory_set_flags(CS_DecodedBlob *codeDirBlob, uint32_t flags);
48 | uint8_t csd_code_directory_get_hash_type(CS_DecodedBlob *codeDirBlob);
49 | void csd_code_directory_set_hash_type(CS_DecodedBlob *codeDirBlob, uint8_t hashType);
50 | int csd_code_directory_print_content(CS_DecodedSuperBlob *decodedSuperblob, CS_DecodedBlob *codeDirBlob, MachO *macho, bool printSlots, bool verifySlots);
51 | void csd_code_directory_update(CS_DecodedBlob *codeDirBlob, MachO *macho);
52 | void csd_code_directory_alloc(CS_DecodedBlob *codeDirBlob, MachO *macho);
53 |
54 | #endif // CODE_DIRECTORY_H
--------------------------------------------------------------------------------
/ChOma-main/src/FAT.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "FAT.h"
6 | #include "MachO.h"
7 | #include "MachOByteOrder.h"
8 |
9 | #include "FileStream.h"
10 | #include "MemoryStream.h"
11 |
12 | #define LOG(...)
13 |
14 | int fat_read_at_offset(FAT *fat, uint64_t offset, size_t size, void *outBuf)
15 | {
16 | return memory_stream_read(fat->stream, offset, size, outBuf);
17 | }
18 |
19 | MemoryStream *fat_get_stream(FAT *fat)
20 | {
21 | return fat->stream;
22 | }
23 |
24 | int fat_parse_slices(FAT *fat)
25 | {
26 | // Get size of file
27 | size_t fileSize = memory_stream_get_size(fat->stream);
28 | if (fileSize == MEMORY_STREAM_SIZE_INVALID) {
29 | printf("Error: Failed to parse fat slices, memory_stream_get_size returned MEMORY_STREAM_SIZE_INVALID\n");
30 | return -1;
31 | }
32 |
33 | // Read the FAT header
34 | struct fat_header fatHeader;
35 | fat_read_at_offset(fat, 0, sizeof(fatHeader), &fatHeader);
36 | FAT_HEADER_APPLY_BYTE_ORDER(&fatHeader, BIG_TO_HOST_APPLIER);
37 |
38 | // Check if the file is a FAT file
39 | if (fatHeader.magic == FAT_MAGIC || fatHeader.magic == FAT_MAGIC_64) {
40 | LOG("FAT header found! Magic: 0x%x.\n", fatHeader.magic);
41 | bool is64 = fatHeader.magic == FAT_MAGIC_64;
42 |
43 | // Sanity check the number of machOs
44 | if (fatHeader.nfat_arch > 5 || fatHeader.nfat_arch < 1) {
45 | printf("Error: invalid number of MachO slices (%d), this likely means you are not using an iOS MachO.\n", fatHeader.nfat_arch);
46 | return -1;
47 | }
48 |
49 | fat->slicesCount = fatHeader.nfat_arch;
50 | fat->slices = malloc(sizeof(MachO*) * fat->slicesCount);
51 | memset(fat->slices, 0, sizeof(MachO*) * fat->slicesCount);
52 |
53 | // Iterate over all machOs
54 | for (uint32_t i = 0; i < fatHeader.nfat_arch; i++) {
55 | struct fat_arch_64 arch64 = {0};
56 | if (is64) {
57 | // Read the arch descriptor
58 | fat_read_at_offset(fat, sizeof(struct fat_header) + i * sizeof(arch64), sizeof(arch64), &arch64);
59 | FAT_ARCH_64_APPLY_BYTE_ORDER(&arch64, BIG_TO_HOST_APPLIER);
60 | }
61 | else {
62 | // Read the FAT arch structure
63 | struct fat_arch arch = {0};
64 | fat_read_at_offset(fat, sizeof(struct fat_header) + i * sizeof(arch), sizeof(arch), &arch);
65 | FAT_ARCH_APPLY_BYTE_ORDER(&arch, BIG_TO_HOST_APPLIER);
66 |
67 | // Convert fat_arch to fat_arch_64
68 | arch64 = (struct fat_arch_64){
69 | .cputype = arch.cputype,
70 | .cpusubtype = arch.cpusubtype,
71 | .offset = (uint64_t)arch.offset,
72 | .size = (uint64_t)arch.size,
73 | .align = arch.align,
74 | .reserved = 0,
75 | };
76 | }
77 |
78 | MemoryStream *machOStream = memory_stream_softclone(fat->stream);
79 | int r = memory_stream_trim(machOStream, arch64.offset, fileSize - (arch64.offset + arch64.size));
80 | if (r == 0) {
81 | fat->slices[i] = macho_init(machOStream, arch64);
82 | }
83 | }
84 | } else {
85 | // Not FAT? Parse single slice
86 |
87 | fat->slicesCount = 1;
88 | fat->slices = malloc(sizeof(MachO) * fat->slicesCount);
89 | memset(fat->slices, 0, sizeof(MachO) * fat->slicesCount);
90 |
91 | MemoryStream *machOStream = memory_stream_softclone(fat->stream);
92 |
93 | struct mach_header_64 machHeader;
94 | memory_stream_read(machOStream, 0, sizeof(machHeader), &machHeader);
95 | MACH_HEADER_APPLY_BYTE_ORDER(&machHeader, LITTLE_TO_HOST_APPLIER);
96 |
97 | struct fat_arch_64 singleArch = {0};
98 | singleArch.cpusubtype = machHeader.cpusubtype;
99 | singleArch.cputype = machHeader.cputype;
100 | singleArch.offset = 0;
101 | singleArch.size = fileSize;
102 | singleArch.align = 0x4000;
103 |
104 | MachO *singleSlice = macho_init(machOStream, singleArch);
105 | if (!singleSlice) return -1;
106 | fat->slices[0] = singleSlice;
107 | }
108 | LOG("Found %u MachO slices.\n", fat->slicesCount);
109 | return 0;
110 | }
111 |
112 | MachO *fat_find_slice(FAT *fat, cpu_type_t cputype, cpu_subtype_t cpusubtype)
113 | {
114 | for (uint32_t i = 0; i < fat->slicesCount; i++) {
115 | MachO *curMacho = fat->slices[i];
116 | if (curMacho) {
117 | if (curMacho->machHeader.cputype == cputype && curMacho->machHeader.cpusubtype == cpusubtype) {
118 | return curMacho;
119 | }
120 | }
121 | }
122 | return NULL;
123 | }
124 |
125 | void fat_free(FAT *fat)
126 | {
127 | if (fat->slices != NULL) {
128 | for (int i = 0; i < fat->slicesCount; i++) {
129 | if (fat->slices[i]) {
130 | macho_free(fat->slices[i]);
131 | }
132 | }
133 | free(fat->slices);
134 | }
135 | memory_stream_free(fat->stream);
136 | free(fat);
137 | }
138 |
139 | FAT *fat_init_from_memory_stream(MemoryStream *stream)
140 | {
141 | FAT *fat = malloc(sizeof(FAT));
142 | if (!fat) return NULL;
143 | memset(fat, 0, sizeof(FAT));
144 |
145 | fat->stream = stream;
146 |
147 | if (fat_parse_slices(fat) != 0) goto fail;
148 |
149 | size_t size = memory_stream_get_size(fat->stream);
150 | LOG("File size 0x%zx bytes, MachO slice count %u.\n", size, fat->slicesCount);
151 | return fat;
152 |
153 | fail:
154 | fat_free(fat);
155 | return NULL;
156 | }
157 |
158 | FAT *fat_init_from_path(const char *filePath)
159 | {
160 | MemoryStream *stream = file_stream_init_from_path(filePath, 0, FILE_STREAM_SIZE_AUTO, 0);
161 | if (stream) {
162 | return fat_init_from_memory_stream(stream);;
163 | }
164 | return NULL;
165 | }
166 |
167 | FAT *fat_create_for_macho_array(char *firstInputPath, MachO **machoArray, int machoArrayCount) {
168 | FAT *fat = fat_init_from_path(firstInputPath);
169 | for (int i = 1; i < machoArrayCount; i++) {
170 | if (fat_add_macho(fat, machoArray[i]) != 0) {
171 | printf("Error: failed to add MachO to FAT.\n");
172 | fat_free(fat);
173 | return NULL;
174 | }
175 | }
176 | return fat;
177 | }
178 |
179 | int fat_add_macho(FAT *fat, MachO *macho)
180 | {
181 | fat->slicesCount++;
182 | fat->slices = realloc(fat->slices, sizeof(MachO*) * fat->slicesCount);
183 | if (!fat->slices) return -1;
184 | fat->slices[fat->slicesCount - 1] = macho;
185 | return 0;
186 | }
--------------------------------------------------------------------------------
/ChOma-main/src/FAT.h:
--------------------------------------------------------------------------------
1 | #ifndef MACHO_H
2 | #define MACHO_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | #include "MemoryStream.h"
12 | typedef struct MachO MachO;
13 |
14 | // A FAT structure can either represent a FAT file with multiple slices, in which the slices will be loaded into the slices attribute
15 | // Or a single slice MachO, in which case it serves as a compatibility layer and the single slice will also be loaded into the slices attribute
16 | typedef struct FAT
17 | {
18 | MemoryStream *stream;
19 | MachO **slices;
20 | uint32_t slicesCount;
21 | int fileDescriptor;
22 | } FAT;
23 |
24 | int fat_read_at_offset(FAT *fat, uint64_t offset, size_t size, void *outBuf);
25 |
26 | MemoryStream *fat_get_stream(FAT *fat);
27 |
28 | // Initialise a FAT structure from a memory stream
29 | FAT *fat_init_from_memory_stream(MemoryStream *stream);
30 |
31 | // Initialise a FAT structure using the path to the file
32 | FAT *fat_init_from_path(const char *filePath);
33 |
34 | // Find macho with cputype and cpusubtype in FAT, returns NULL if not found
35 | MachO *fat_find_slice(FAT *fat, cpu_type_t cputype, cpu_subtype_t cpusubtype);
36 |
37 | // Create a FAT structure from an array of MachO structures
38 | FAT *fat_create_for_macho_array(char *firstInputPath, MachO **machoArray, int machoArrayCount);
39 |
40 | // Add a MachO to the FAT structure
41 | int fat_add_macho(FAT *fat, MachO *macho);
42 |
43 | // Free all elements of the FAT structure
44 | void fat_free(FAT *fat);
45 |
46 | #endif // MACHO_H
--------------------------------------------------------------------------------
/ChOma-main/src/FileStream.h:
--------------------------------------------------------------------------------
1 | #ifndef FILE_STREAM_H
2 | #define FILE_STREAM_H
3 |
4 | #include "MemoryStream.h"
5 |
6 | #define FILE_STREAM_SIZE_AUTO 0
7 | #define FILE_STREAM_FLAG_WRITABLE (1 << 0)
8 | #define FILE_STREAM_FLAG_AUTO_EXPAND (1 << 1)
9 |
10 | typedef struct FileStreamContext {
11 | int fd;
12 | size_t fileSize;
13 | uint32_t bufferStart;
14 | size_t bufferSize;
15 | } FileStreamContext;
16 |
17 | MemoryStream *file_stream_init_from_file_descriptor_nodup(int fd, uint32_t bufferStart, size_t bufferSize, uint32_t flags);
18 | MemoryStream *file_stream_init_from_file_descriptor(int fd, uint32_t bufferStart, size_t bufferSize, uint32_t flags);
19 | MemoryStream *file_stream_init_from_path(const char *path, uint32_t bufferStart, size_t bufferSize, uint32_t flags);
20 |
21 | #endif // FILE_STREAM_H
--------------------------------------------------------------------------------
/ChOma-main/src/Host.c:
--------------------------------------------------------------------------------
1 | #include "Host.h"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #include "MachO.h"
9 |
10 | #define CPU_SUBTYPE_ARM64E_ABI_V2 0x80000000
11 |
12 | int host_get_cpu_information(cpu_type_t *cputype, cpu_subtype_t *cpusubtype)
13 | {
14 | size_t len;
15 |
16 | // Query for cputype
17 | len = sizeof(cputype);
18 | if (sysctlbyname("hw.cputype", cputype, &len, NULL, 0) == -1) { printf("ERROR: no cputype.\n"); return -1; }
19 |
20 | // Query for cpusubtype
21 | len = sizeof(cpusubtype);
22 | if (sysctlbyname("hw.cpusubtype", cpusubtype, &len, NULL, 0) == -1) { printf("ERROR: no cpusubtype.\n"); return -1; }
23 |
24 | return 0;
25 | }
26 |
27 | MachO *fat_find_preferred_slice(FAT *fat)
28 | {
29 | cpu_type_t cputype;
30 | cpu_subtype_t cpusubtype;
31 | if (host_get_cpu_information(&cputype, &cpusubtype) != 0) { return NULL; }
32 |
33 | MachO *preferredMacho = NULL;
34 |
35 | // If you intend on supporting non darwin, implement platform specific logic here using #ifdef's
36 | if (cputype == CPU_TYPE_ARM64) {
37 | if (cpusubtype == CPU_SUBTYPE_ARM64E) {
38 | // If this is an arm64e device, first try to find a new ABI arm64e slice
39 | // TODO: Gate this behind iOS 14+?
40 | preferredMacho = fat_find_slice(fat, cputype, (CPU_SUBTYPE_ARM64E | CPU_SUBTYPE_ARM64E_ABI_V2));
41 | if (!preferredMacho) {
42 | // If that's not found, try to find an old ABI arm64e slice
43 | preferredMacho = fat_find_slice(fat, cputype, CPU_SUBTYPE_ARM64E);
44 |
45 | //the new kernel cannot execute an old ABI arm64e executable
46 | if(preferredMacho && preferredMacho->machHeader.filetype == MH_EXECUTE) {
47 | preferredMacho = NULL;
48 | }
49 | }
50 | }
51 |
52 | if (!preferredMacho) {
53 | // If not arm64e device or no arm64e slice found, try to find regular arm64 slice
54 |
55 | // On iOS 15+, the Kernel prefers an arm64v8 slice to an arm64 slice, so check that first
56 | // TODO: Gate this behind iOS 15+?
57 | preferredMacho = fat_find_slice(fat, cputype, CPU_SUBTYPE_ARM64_V8);
58 | if (!preferredMacho) {
59 | // If that's not found, finally check for a regular arm64 slice
60 | preferredMacho = fat_find_slice(fat, cputype, CPU_SUBTYPE_ARM64_ALL);
61 | }
62 | }
63 | }
64 |
65 | if (!preferredMacho) {
66 | printf("Error: failed to find a valid, preferred macho.\n");
67 | }
68 | return preferredMacho;
69 | }
--------------------------------------------------------------------------------
/ChOma-main/src/Host.h:
--------------------------------------------------------------------------------
1 | #ifndef HOST_H
2 | #define HOST_H
3 |
4 | #include "FAT.h"
5 |
6 | // Retrieve the preferred MachO slice from a FAT
7 | // Preferred slice as in the slice that the kernel would use when loading the file
8 | MachO *fat_find_preferred_slice(FAT *fat);
9 |
10 | #endif // HOST_H
--------------------------------------------------------------------------------
/ChOma-main/src/MachO.h:
--------------------------------------------------------------------------------
1 | #ifndef MACHO_SLICE_H
2 | #define MACHO_SLICE_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include "MemoryStream.h"
8 | #include "FAT.h"
9 |
10 | typedef struct MachOSegment
11 | {
12 | struct segment_command_64 command;
13 | struct section_64 sections[];
14 | } __attribute__((__packed__)) MachOSegment;
15 |
16 | typedef struct FilesetMachO {
17 | char *entry_id;
18 | uint64_t vmaddr;
19 | uint64_t fileoff;
20 | struct FAT *underlyingMachO;
21 | } FilesetMachO;
22 |
23 | typedef struct MachO {
24 | MemoryStream *stream;
25 | bool isSupported;
26 | struct mach_header_64 machHeader;
27 | struct fat_arch_64 archDescriptor;
28 |
29 | uint32_t filesetCount;
30 | FilesetMachO *filesetMachos;
31 |
32 | uint32_t segmentCount;
33 | MachOSegment **segments;
34 | } MachO;
35 |
36 | // Read data from a MachO at a specified offset
37 | int macho_read_at_offset(MachO *macho, uint64_t offset, size_t size, void *outBuf);
38 |
39 | // Write data from a MachO at a specified offset, auto expands, only works if opened via macho_init_for_writing
40 | int macho_write_at_offset(MachO *macho, uint64_t offset, size_t size, void *inBuf);
41 |
42 | MemoryStream *macho_get_stream(MachO *macho);
43 | uint32_t macho_get_filetype(MachO *macho);
44 |
45 | // Perform translation between file offsets and virtual addresses
46 | int macho_translate_fileoff_to_vmaddr(MachO *macho, uint64_t fileoff, uint64_t *vmaddrOut, MachOSegment **segmentOut);
47 | int macho_translate_vmaddr_to_fileoff(MachO *macho, uint64_t vmaddr, uint64_t *fileoffOut, MachOSegment **segmentOut);
48 |
49 | // Read data from a MachO at a specified virtual address
50 | int macho_read_at_vmaddr(MachO *macho, uint64_t vmaddr, size_t size, void *outBuf);
51 |
52 | int macho_enumerate_load_commands(MachO *macho, void (^enumeratorBlock)(struct load_command loadCommand, uint64_t offset, void *cmd, bool *stop));
53 |
54 | // Initialise a MachO object from a MemoryStream and it's corresponding FAT arch descriptor
55 | MachO *macho_init(MemoryStream *stream, struct fat_arch_64 archDescriptor);
56 |
57 | // Initialize a single slice macho for writing to it
58 | MachO *macho_init_for_writing(const char *filePath);
59 |
60 | // Create an array of MachO objects from an array of paths
61 | MachO **macho_array_create_for_paths(char **inputPaths, int inputPathsCount);
62 |
63 | void macho_free(MachO *macho);
64 |
65 | #endif // MACHO_SLICE_H
--------------------------------------------------------------------------------
/ChOma-main/src/MachOByteOrder.h:
--------------------------------------------------------------------------------
1 | #ifndef MACHO_BYTE_ORDER_H
2 | #define MACHO_BYTE_ORDER_H
3 |
4 | #include
5 | #include
6 |
7 | // 8-bit integers needed for CodeDirectory
8 | #define BIG_TO_HOST(n) _Generic((n), \
9 | int8_t: n, \
10 | uint8_t: n, \
11 | int16_t: OSSwapBigToHostInt16(n), \
12 | uint16_t: OSSwapBigToHostInt16(n), \
13 | int32_t: OSSwapBigToHostInt32(n), \
14 | uint32_t: OSSwapBigToHostInt32(n), \
15 | int64_t: OSSwapBigToHostInt64(n), \
16 | uint64_t: OSSwapBigToHostInt64(n) \
17 | )
18 |
19 | #define HOST_TO_BIG(n) _Generic((n), \
20 | int8_t: n, \
21 | uint8_t: n, \
22 | uint16_t: OSSwapHostToBigInt16(n), \
23 | int16_t: OSSwapHostToBigInt16(n), \
24 | int32_t: OSSwapHostToBigInt32(n), \
25 | uint32_t: OSSwapHostToBigInt32(n), \
26 | int64_t: OSSwapHostToBigInt64(n), \
27 | uint64_t: OSSwapHostToBigInt64(n) \
28 | )
29 |
30 | #define LITTLE_TO_HOST(n) _Generic((n), \
31 | int8_t: n, \
32 | uint8_t: n, \
33 | int16_t: OSSwapLittleToHostInt16(n), \
34 | uint16_t: OSSwapLittleToHostInt16(n), \
35 | int32_t: OSSwapLittleToHostInt32(n), \
36 | uint32_t: OSSwapLittleToHostInt32(n), \
37 | int64_t: OSSwapLittleToHostInt64(n), \
38 | uint64_t: OSSwapLittleToHostInt64(n) \
39 | )
40 |
41 | #define HOST_TO_LITTLE(n) _Generic((n), \
42 | int8_t: n, \
43 | uint8_t: n, \
44 | int16_t: OSSwapHostToLittleInt16(n), \
45 | uint16_t: OSSwapHostToLittleInt16(n), \
46 | int32_t: OSSwapHostToLittleInt32(n), \
47 | uint32_t: OSSwapHostToLittleInt32(n), \
48 | int64_t: OSSwapHostToLittleInt64(n), \
49 | uint64_t: OSSwapHostToLittleInt64(n) \
50 | )
51 |
52 | #define HOST_TO_LITTLE_APPLIER(instance, member) \
53 | (instance)->member = HOST_TO_LITTLE((instance)->member)
54 |
55 | #define HOST_TO_BIG_APPLIER(instance, member) \
56 | (instance)->member = HOST_TO_BIG((instance)->member)
57 |
58 | #define LITTLE_TO_HOST_APPLIER(instance, member) \
59 | (instance)->member = LITTLE_TO_HOST((instance)->member)
60 |
61 | #define BIG_TO_HOST_APPLIER(instance, member) \
62 | (instance)->member = BIG_TO_HOST((instance)->member)
63 |
64 | #define FAT_HEADER_APPLY_BYTE_ORDER(fh, applier) \
65 | applier(fh, magic); \
66 | applier(fh, nfat_arch);
67 |
68 | #define FAT_ARCH_APPLY_BYTE_ORDER(arch, applier) \
69 | applier(arch, cputype); \
70 | applier(arch, cpusubtype); \
71 | applier(arch, offset); \
72 | applier(arch, size); \
73 | applier(arch, align); \
74 |
75 | #define FAT_ARCH_64_APPLY_BYTE_ORDER(arch, applier) \
76 | applier(arch, cputype); \
77 | applier(arch, cpusubtype); \
78 | applier(arch, offset); \
79 | applier(arch, size); \
80 | applier(arch, align); \
81 | applier(arch, reserved); \
82 |
83 | #define MACH_HEADER_APPLY_BYTE_ORDER(mh, applier) \
84 | applier(mh, magic); \
85 | applier(mh, cputype); \
86 | applier(mh, cpusubtype); \
87 | applier(mh, filetype); \
88 | applier(mh, ncmds); \
89 | applier(mh, sizeofcmds); \
90 | applier(mh, reserved);
91 |
92 | #define LOAD_COMMAND_APPLY_BYTE_ORDER(lc, applier) \
93 | applier(lc, cmd); \
94 | applier(lc, cmdsize);
95 |
96 | #define LINKEDIT_DATA_COMMAND_APPLY_BYTE_ORDER(lc, applier) \
97 | applier(lc, cmd); \
98 | applier(lc, cmdsize); \
99 | applier(lc, dataoff); \
100 | applier(lc, datasize);
101 |
102 | #define BLOB_INDEX_APPLY_BYTE_ORDER(bi, applier) \
103 | applier(bi, type); \
104 | applier(bi, offset);
105 |
106 | #define SUPERBLOB_APPLY_BYTE_ORDER(sb, applier) \
107 | applier(sb, magic); \
108 | applier(sb, length); \
109 | applier(sb, count);
110 |
111 | #define GENERIC_BLOB_APPLY_BYTE_ORDER(gb, applier) \
112 | applier(gb, magic); \
113 | applier(gb, length);
114 |
115 | #define CODE_DIRECTORY_APPLY_BYTE_ORDER(cd, applier) \
116 | applier(cd, magic); \
117 | applier(cd, length); \
118 | applier(cd, version); \
119 | applier(cd, flags); \
120 | applier(cd, hashOffset); \
121 | applier(cd, identOffset); \
122 | applier(cd, nSpecialSlots); \
123 | applier(cd, nCodeSlots); \
124 | applier(cd, codeLimit); \
125 | applier(cd, hashSize); \
126 | applier(cd, hashType); \
127 | applier(cd, spare1); \
128 | applier(cd, pageSize); \
129 | applier(cd, spare2); \
130 | applier(cd, scatterOffset); \
131 | applier(cd, teamOffset);
132 |
133 | #define SEGMENT_COMMAND_64_APPLY_BYTE_ORDER(sc64, applier) \
134 | applier(sc64, cmd); \
135 | applier(sc64, cmdsize); \
136 | applier(sc64, fileoff); \
137 | applier(sc64, filesize); \
138 | applier(sc64, vmaddr); \
139 | applier(sc64, vmsize); \
140 | applier(sc64, flags); \
141 | applier(sc64, initprot); \
142 | applier(sc64, maxprot); \
143 | applier(sc64, nsects);
144 |
145 | #define SECTION_64_APPLY_BYTE_ORDER(sc64, applier) \
146 | applier(sc64, addr); \
147 | applier(sc64, align); \
148 | applier(sc64, flags); \
149 | applier(sc64, nreloc); \
150 | applier(sc64, offset); \
151 | applier(sc64, reserved1); \
152 | applier(sc64, reserved2); \
153 | applier(sc64, reserved3); \
154 | applier(sc64, size);
155 |
156 | #define FILESET_ENTRY_COMMAND_APPLY_BYTE_ORDER(fse, applier) \
157 | applier(fse, cmd); \
158 | applier(fse, cmdsize); \
159 | applier(fse, vmaddr); \
160 | applier(fse, fileoff); \
161 | applier(fse, entry_id.offset); \
162 | applier(fse, reserved); \
163 |
164 | #endif // MACHO_BYTE_ORDER_H
--------------------------------------------------------------------------------
/ChOma-main/src/MachOLoadCommand.h:
--------------------------------------------------------------------------------
1 | #ifndef MACHO_LOAD_COMMAND_H
2 | #define MACHO_LOAD_COMMAND_H
3 |
4 | #include
5 | #include "MachO.h"
6 | #include "CSBlob.h"
7 | #include "FileStream.h"
8 | #include "MachOByteOrder.h"
9 |
10 | // Convert load command to load command name
11 | char *load_command_to_string(int loadCommand);
12 | void update_segment_command_64(MachO *macho, const char *segmentName, uint64_t vmaddr, uint64_t vmsize, uint64_t fileoff, uint64_t filesize);
13 | void update_lc_code_signature(MachO *macho, uint64_t size);
14 | int update_load_commands_for_coretrust_bypass(MachO *macho, CS_SuperBlob *superblob, uint64_t originalCodeSignatureSize, uint64_t originalMachOSize);
15 |
16 | #endif // MACHO_LOAD_COMMAND_H
--------------------------------------------------------------------------------
/ChOma-main/src/MemoryStream.h:
--------------------------------------------------------------------------------
1 | #ifndef MEMORY_STREAM_H
2 | #define MEMORY_STREAM_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | #define MEMORY_STREAM_FLAG_OWNS_DATA (1 << 0)
13 | #define MEMORY_STREAM_FLAG_MUTABLE (1 << 1)
14 | #define MEMORY_STREAM_FLAG_AUTO_EXPAND (1 << 2)
15 |
16 | #define MEMORY_STREAM_SIZE_INVALID (size_t)-1
17 |
18 | // A generic memory IO interface that is used throughout this project
19 | // Can be backed by anything, just the functions have to be implemented
20 | typedef struct s_MemoryStream {
21 | void *context;
22 | uint32_t flags;
23 |
24 | int (*read)(struct s_MemoryStream *stream, uint64_t offset, size_t size, void *outBuf);
25 | int (*write)(struct s_MemoryStream *stream, uint64_t offset, size_t size, const void *inBuf);
26 | int (*getSize)(struct s_MemoryStream *stream, size_t *sizeOut);
27 | uint8_t *(*getRawPtr)(struct s_MemoryStream *stream);
28 |
29 | int (*trim)(struct s_MemoryStream *stream, size_t trimAtStart, size_t trimAtEnd);
30 | int (*expand)(struct s_MemoryStream *stream, size_t expandAtStart, size_t expandAtEnd);
31 |
32 | struct s_MemoryStream *(*hardclone)(struct s_MemoryStream *stream);
33 | struct s_MemoryStream *(*softclone)(struct s_MemoryStream *stream);
34 | void (*free)(struct s_MemoryStream *stream);
35 | } MemoryStream;
36 |
37 | int memory_stream_read(MemoryStream *stream, uint64_t offset, size_t size, void *outBuf);
38 | int memory_stream_write(MemoryStream *stream, uint64_t offset, size_t size, const void *inBuf);
39 |
40 | int memory_stream_insert(MemoryStream *stream, uint64_t offset, size_t size, const void *inBuf);
41 | int memory_stream_delete(MemoryStream *stream, uint64_t offset, size_t size);
42 |
43 | int memory_stream_read_string(MemoryStream *stream, uint64_t offset, char **outString);
44 | int memory_stream_write_string(MemoryStream *stream, uint64_t offset, const char *string);
45 |
46 | size_t memory_stream_get_size(MemoryStream *stream);
47 | uint8_t *memory_stream_get_raw_pointer(MemoryStream *stream);
48 | uint32_t memory_stream_get_flags(MemoryStream *stream);
49 |
50 | MemoryStream *memory_stream_softclone(MemoryStream *stream);
51 | MemoryStream *memory_stream_hardclone(MemoryStream *stream);
52 | int memory_stream_trim(MemoryStream *stream, size_t trimAtStart, size_t trimAtEnd);
53 | int memory_stream_expand(MemoryStream *stream, size_t expandAtStart, size_t expandAtEnd);
54 |
55 | void memory_stream_free(MemoryStream *stream);
56 |
57 | int memory_stream_copy_data(MemoryStream *originStream, uint64_t originOffset, MemoryStream *targetStream, uint64_t targetOffset, size_t size);
58 | int memory_stream_find_memory(MemoryStream *stream, uint64_t searchOffset, size_t searchSize, void *bytes, void *mask, size_t nbytes, uint16_t alignment, uint64_t *foundOffsetOut);
59 |
60 | #endif // MEMORY_STREAM_H
--------------------------------------------------------------------------------
/ChOma-main/src/PatchFinder.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include "MachO.h"
3 |
4 | #define METRIC_TYPE_PATTERN 1
5 | #define METRIC_TYPE_STRING 2
6 | #define METRIC_TYPE_XREF 3
7 |
8 | typedef struct s_PFSection {
9 | MachO *macho;
10 | uint64_t fileoff;
11 | uint64_t vmaddr;
12 | uint64_t size;
13 | uint8_t *cache;
14 | bool ownsCache;
15 | } PFSection;
16 |
17 | PFSection *pf_section_init_from_macho(MachO *macho, const char *filesetEntryId, const char *segName, const char *sectName);
18 | int pf_section_read_at_relative_offset(PFSection *section, uint64_t rel, size_t size, void *outBuf);
19 | int pf_section_read_at_address(PFSection *section, uint64_t vmaddr, void *outBuf, size_t size);
20 | uint32_t pf_section_read32(PFSection *section, uint64_t vmaddr);
21 | int pf_section_set_cached(PFSection *section, bool cached);
22 | void pf_section_free(PFSection *section);
23 |
24 |
25 | typedef struct s_MetricShared {
26 | uint32_t type;
27 | } MetricShared;
28 |
29 |
30 | typedef enum {
31 | BYTE_PATTERN_ALIGN_8_BIT,
32 | BYTE_PATTERN_ALIGN_16_BIT,
33 | BYTE_PATTERN_ALIGN_32_BIT,
34 | BYTE_PATTERN_ALIGN_64_BIT,
35 | } BytePatternAlignment;
36 |
37 | typedef struct s_PFBytePatternMetric {
38 | MetricShared shared;
39 |
40 | void *bytes;
41 | void *mask;
42 | size_t nbytes;
43 | BytePatternAlignment alignment;
44 | } PFBytePatternMetric;
45 |
46 | typedef struct s_PFStringMetric {
47 | MetricShared shared;
48 |
49 | char *string;
50 | } PFStringMetric;
51 |
52 | PFBytePatternMetric *pf_create_byte_pattern_metric(void *bytes, void *mask, size_t nbytes, BytePatternAlignment alignment);
53 | void pf_byte_pattern_metric_free(PFBytePatternMetric *metric);
54 |
55 | PFStringMetric *pf_create_string_metric(const char *string);
56 | void pf_string_metric_free(PFStringMetric *metric);
57 |
58 |
59 | void pf_section_run_metric(PFSection *section, void *metric, void (^matchBlock)(uint64_t vmaddr, bool *stop));
60 |
--------------------------------------------------------------------------------
/ChOma-main/src/SignOSSL.c:
--------------------------------------------------------------------------------
1 | #include "SignOSSL.h"
2 |
3 | unsigned char *signWithRSA(unsigned char *inputData, size_t inputDataLength, unsigned char *key, size_t key_len, size_t *outputDataLength)
4 | {
5 | // Create EVP_PKEY from private key data
6 | FILE *privateKeyFile = fmemopen(key, key_len, "r");
7 | if (!privateKeyFile) return NULL;
8 | EVP_PKEY *privateKey = PEM_read_PrivateKey(privateKeyFile, NULL, NULL, NULL);
9 | fclose(privateKeyFile);
10 | if (!privateKey) {
11 | fprintf(stderr, "Error: failed to read private key file.\n");
12 | }
13 |
14 | // Get the RSA key from the private key
15 | RSA *rsaKey = EVP_PKEY_get1_RSA(privateKey);
16 | if (!rsaKey) {
17 | printf("Error: failed to get RSA key from private key.\n");
18 | }
19 |
20 | // Determine the size of the RSA key in bytes
21 | int keySize = RSA_size(rsaKey);
22 |
23 | // Allocate memory for the signature
24 | unsigned char *signature = (unsigned char *)malloc(keySize);
25 | if (!signature) {
26 | printf("Error: failed to allocate memory.\n");
27 | }
28 |
29 | // Sign the data
30 | int signatureLength = RSA_private_encrypt(inputDataLength, inputData, signature, rsaKey, RSA_PKCS1_PADDING);
31 | if (signatureLength == -1) {
32 | printf("Error: failed to sign the data.\n");
33 | }
34 |
35 | RSA_free(rsaKey);
36 | EVP_PKEY_free(privateKey);
37 |
38 | *outputDataLength = signatureLength;
39 | return signature;
40 | }
41 |
--------------------------------------------------------------------------------
/ChOma-main/src/SignOSSL.h:
--------------------------------------------------------------------------------
1 | #ifndef SIGN_OSSL_H
2 | #define SIGN_OSSL_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | unsigned char *signWithRSA(unsigned char *inputData, size_t inputDataLength, unsigned char *key, size_t key_len, size_t *outputDataLength);
13 |
14 | #endif // SIGN_OSSL_H
15 |
16 | // 0xA422
--------------------------------------------------------------------------------
/ChOma-main/src/Util.c:
--------------------------------------------------------------------------------
1 | #include "Util.h"
2 | #include
3 |
4 | int memcmp_masked(const void *str1, const void *str2, unsigned char* mask, size_t n)
5 | {
6 | const unsigned char* p = (const unsigned char*)str1;
7 | const unsigned char* q = (const unsigned char*)str2;
8 |
9 | if (p == q) return 0;
10 | for (int i = 0; i < n; i++) {
11 | unsigned char cMask = 0xFF;
12 | if (mask) {
13 | cMask = mask[i];
14 | }
15 | if((p[i] & cMask) != (q[i] & cMask)) {
16 | // we do not care about 1 / -1
17 | return -1;
18 | }
19 | }
20 |
21 | return 0;
22 | }
23 |
24 | uint64_t align_to_size(int size, int alignment)
25 | {
26 | return (size + alignment - 1) & ~(alignment - 1);
27 | }
28 |
29 | int count_digits(int64_t num)
30 | {
31 | if (num == 0) {
32 | return 1;
33 | }
34 | int digits = 0;
35 | if (num < 0) {
36 | num = -num;
37 | digits++;
38 | }
39 | while (num != 0) {
40 | num = num / 10;
41 | digits++;
42 | }
43 | return digits;
44 | }
45 |
46 | void print_hash(uint8_t *hash, size_t size)
47 | {
48 | for (int j = 0; j < size; j++) {
49 | printf("%02x", hash[j]);
50 | }
51 | }
--------------------------------------------------------------------------------
/ChOma-main/src/Util.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | int memcmp_masked(const void *str1, const void *str2, unsigned char* mask, size_t n);
5 | uint64_t align_to_size(int size, int alignment);
6 | int count_digits(int64_t num);
7 | void print_hash(uint8_t *hash, size_t size);
--------------------------------------------------------------------------------
/ChOma-main/tests/choma_cli/main.c:
--------------------------------------------------------------------------------
1 | #include "choma/FileStream.h"
2 | #include
3 | #include
4 |
5 | char *get_argument_value(int argc, char *argv[], const char *flag)
6 | {
7 | for (int i = 0; i < argc; i++) {
8 | if (!strcmp(argv[i], flag)) {
9 | if (i+1 < argc) {
10 | return argv[i+1];
11 | }
12 | }
13 | }
14 | return NULL;
15 | }
16 |
17 | bool argument_exists(int argc, char *argv[], const char *flag)
18 | {
19 | for (int i = 0; i < argc; i++) {
20 | if (!strcmp(argv[i], flag)) {
21 | return true;
22 | }
23 | }
24 | return false;
25 | }
26 |
27 | void print_usage(char *executablePath) {
28 | printf("Options:\n");
29 | printf("\t-i: Path to input file\n");
30 | printf("\t-c: Parse the CMS superblob blob of a MachO\n");
31 | printf("\t-e: Extract the Code Signature from a MachO\n");
32 | printf("\t-s: Print all page hash code slots in a CodeDirectory blob\n");
33 | printf("\t-v: Verify that the CodeDirectory hashes are correct\n");
34 | printf("\t-f: Parse an MH_FILESET MachO and output it's sub-files\n");
35 | printf("\t-h: Print this message\n");
36 | printf("Examples:\n");
37 | printf("\t%s -i -c\n", executablePath);
38 | printf("\t%s -i -c -s -v\n", executablePath);
39 | printf("\t%s -i -f\n", executablePath);
40 | exit(-1);
41 | }
42 |
43 | int main(int argc, char *argv[]) {
44 |
45 | if (argument_exists(argc, argv, "-h")) {
46 | print_usage(argv[0]);
47 | return 0;
48 | }
49 |
50 | if (argc < 2) {
51 | print_usage(argv[0]);
52 | return -1;
53 | }
54 |
55 | char *inputPath = get_argument_value(argc, argv, "-i");
56 | if (!inputPath) {
57 | printf("Error: no input file specified.\n");
58 | print_usage(argv[0]);
59 | return -1;
60 | }
61 |
62 | if (!argument_exists(argc, argv, "-c") && !argument_exists(argc, argv, "-f")) {
63 | printf("Error: no action specified.\n");
64 | print_usage(argv[0]);
65 | return -1;
66 | }
67 |
68 | // Initialise the FAT structure
69 | printf("Initialising FAT structure from %s.\n", inputPath);
70 | FAT *fat = fat_init_from_path(inputPath);
71 | if (!fat) return -1;
72 |
73 | for (int i = 0; i < fat->slicesCount; i++) {
74 | MachO *slice = fat->slices[i];
75 | printf("Slice %d (arch %x/%x, macho %x/%x):\n", i, slice->archDescriptor.cputype, slice->archDescriptor.cpusubtype, slice->machHeader.cputype, slice->machHeader.cpusubtype);
76 | if (argument_exists(argc, argv, "-c")) {
77 | CS_SuperBlob *superblob = macho_read_code_signature(slice);
78 | CS_DecodedSuperBlob *decodedSuperBlob = csd_superblob_decode(superblob);
79 | csd_superblob_print_content(decodedSuperBlob, slice, argument_exists(argc, argv, "-s"), argument_exists(argc, argv, "-v"));
80 | if (argument_exists(argc, argv, "-e")) {
81 | macho_extract_cs_to_file(slice, superblob);
82 | }
83 | }
84 | if (argument_exists(argc, argv, "-f")) {
85 | for (uint32_t i = 0; i < slice->segmentCount; i++) {
86 | MachOSegment *segment = slice->segments[i];
87 | printf("(0x%08llx-0x%08llx)->(0x%09llx-0x%09llx) | %s\n", segment->command.fileoff, segment->command.fileoff + segment->command.filesize, segment->command.vmaddr, segment->command.vmaddr + segment->command.vmsize, segment->command.segname);
88 | for (int j = 0; j < segment->command.nsects; j++) {
89 | struct section_64 *section = &segment->sections[j];
90 | printf("(0x%08x-0x%08llx)->(0x%09llx-0x%09llx) | %s.%s\n", section->offset, section->offset + section->size, section->addr, section->addr + section->size, section->segname, section->sectname);
91 | }
92 | }
93 | for (uint32_t i = 0; i < slice->filesetCount; i++) {
94 | MachO *filesetMachoSlice = slice->filesetMachos[i].underlyingMachO->slices[0];
95 | char *entry_id = slice->filesetMachos[i].entry_id;
96 | for (int j = 0; j < filesetMachoSlice->segmentCount; j++) {
97 | MachOSegment *segment = filesetMachoSlice->segments[j];
98 | printf("(0x%08llx-0x%08llx)->(0x%09llx-0x%09llx) | %s.%s\n", segment->command.fileoff, segment->command.fileoff + segment->command.filesize, segment->command.vmaddr, segment->command.vmaddr + segment->command.vmsize, entry_id, segment->command.segname);
99 | for (int k = 0; k < segment->command.nsects; k++) {
100 | struct section_64 *section = &segment->sections[k];
101 | printf("(0x%08x-0x%08llx)->(0x%09llx-0x%09llx) | %s.%s.%s\n", section->offset, section->offset + section->size, section->addr, section->addr + section->size, entry_id, section->segname, section->sectname);
102 | }
103 | }
104 | }
105 | }
106 | }
107 |
108 | fat_free(fat);
109 |
110 | return 0;
111 |
112 | }
--------------------------------------------------------------------------------
/ChOma-main/tests/ct_bypass/DecryptedSignature.h:
--------------------------------------------------------------------------------
1 | unsigned char DecryptedSignature[] = {
2 | 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
3 | 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20, 0xe2, 0x34, 0xf9, 0x25, 0x65,
4 | 0xa4, 0x33, 0xb7, 0x13, 0x67, 0xc8, 0x63, 0x93, 0xdc, 0x41, 0xaa, 0xc4,
5 | 0x0e, 0x76, 0xa0, 0x80, 0x29, 0x8b, 0x38, 0x9e, 0xc5, 0x6d, 0xd6, 0xba,
6 | 0xef, 0xbf, 0x0d
7 | };
8 | unsigned int DecryptedSignature_len = 51;
9 |
--------------------------------------------------------------------------------
/ChOma-main/tests/fat_create/main.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | #define ARM64_ALIGNMENT 0xE
15 |
16 | char *get_argument_value(int argc, char *argv[], const char *flag)
17 | {
18 | for (int i = 0; i < argc; i++) {
19 | if (!strcmp(argv[i], flag)) {
20 | if (i+1 < argc) {
21 | return argv[i+1];
22 | }
23 | }
24 | }
25 | return NULL;
26 | }
27 |
28 | bool argument_exists(int argc, char *argv[], const char *flag)
29 | {
30 | for (int i = 0; i < argc; i++) {
31 | if (!strcmp(argv[i], flag)) {
32 | return true;
33 | }
34 | }
35 | return false;
36 | }
37 |
38 | void print_usage(char *executablePath) {
39 | printf("Options:\n");
40 | printf("\t-o: Path to output file\n");
41 | printf("\t-r: Replace output file if it already exists\n");
42 | printf("\t-h: Print this message\n");
43 | printf("Examples:\n");
44 | printf("\t%s -o ...\n", executablePath);
45 | exit(-1);
46 | }
47 |
48 | char **get_input_paths(int argc, char *argv[], int *inputPathsCount) {
49 | char **inputPaths = malloc(sizeof(char *) * argc);
50 | int count = 0;
51 | for (int i = 1; i < argc; i++) {
52 | // Make sure this isn't a flag or the output path
53 | if (argv[i][0] != '-' && strcmp(argv[i], get_argument_value(argc, argv, "-o"))) {
54 | inputPaths[count] = argv[i];
55 | count++;
56 | }
57 | }
58 | if (count == 0) {
59 | free(inputPaths);
60 | return NULL;
61 | }
62 | *inputPathsCount = count;
63 | return inputPaths;
64 | }
65 |
66 | int main(int argc, char *argv[]) {
67 | if (argument_exists(argc, argv, "-h")) {
68 | print_usage(argv[0]);
69 | return -1;
70 | }
71 |
72 | char *outputPath = get_argument_value(argc, argv, "-o");
73 | if (!outputPath) {
74 | printf("Error: no output file specified.\n");
75 | print_usage(argv[0]);
76 | return -1;
77 | }
78 |
79 | // Get the input paths
80 | int inputPathsCount = 0;
81 | char **inputPaths = get_input_paths(argc, argv, &inputPathsCount);
82 | if (!inputPaths) {
83 | printf("Error: no input files specified.\n");
84 | print_usage(argv[0]);
85 | return -1;
86 | }
87 |
88 | // Create the output FAT
89 | struct stat st;
90 | if (stat(outputPath, &st) == 0) {
91 | if (argument_exists(argc, argv, "-r")) {
92 | if (remove(outputPath) != 0) {
93 | printf("Error: failed to remove output file.\n");
94 | return -1;
95 | }
96 | } else {
97 | printf("Error: output file already exists.\n");
98 | return -1;
99 | }
100 | }
101 |
102 | FILE *outputFile = fopen(outputPath, "w");
103 | if (!outputFile) {
104 | printf("Error: failed to create output file.\n");
105 | return -1;
106 | }
107 | fclose(outputFile);
108 |
109 | // Create an array of MachO objects
110 | MachO **machoArray = macho_array_create_for_paths(inputPaths, inputPathsCount);
111 | if (!machoArray) {
112 | printf("Error: failed to create FAT array.\n");
113 | return -1;
114 | }
115 |
116 | // Create the FAT object
117 | FAT *fat = fat_create_for_macho_array(inputPaths[0], machoArray, inputPathsCount);
118 | printf("Created FAT with %u slices.\n", fat->slicesCount);
119 |
120 | // Write the FAT to the output file
121 | struct fat_header fatHeader;
122 | fatHeader.magic = FAT_MAGIC;
123 | fatHeader.nfat_arch = fat->slicesCount;
124 | FAT_HEADER_APPLY_BYTE_ORDER(&fatHeader, HOST_TO_BIG_APPLIER);
125 | uint64_t alignment = pow(2, ARM64_ALIGNMENT);
126 | uint64_t paddingSize = alignment - sizeof(struct fat_header) - (sizeof(struct fat_arch) * fat->slicesCount);
127 | MemoryStream *stream = file_stream_init_from_path(outputPath, 0, FILE_STREAM_SIZE_AUTO, FILE_STREAM_FLAG_WRITABLE | FILE_STREAM_FLAG_AUTO_EXPAND);
128 | memory_stream_write(stream, 0, sizeof(struct fat_header), &fatHeader);
129 |
130 | uint64_t lastSliceEnd = alignment;
131 | for (int i = 0; i < fat->slicesCount; i++) {
132 | struct fat_arch archDescriptor;
133 | archDescriptor.cpusubtype = fat->slices[i]->archDescriptor.cpusubtype;
134 | archDescriptor.cputype = fat->slices[i]->archDescriptor.cputype;
135 | archDescriptor.size = fat->slices[i]->archDescriptor.size;
136 | archDescriptor.offset = align_to_size(lastSliceEnd, alignment);
137 | archDescriptor.align = ARM64_ALIGNMENT;
138 | FAT_ARCH_APPLY_BYTE_ORDER(&archDescriptor, HOST_TO_BIG_APPLIER);
139 | printf("Writing to offset 0x%lx\n", sizeof(struct fat_header) + (sizeof(struct fat_arch) * i));
140 | memory_stream_write(stream, sizeof(struct fat_header) + (sizeof(struct fat_arch) * i), sizeof(struct fat_arch), &archDescriptor);
141 | lastSliceEnd += align_to_size(memory_stream_get_size(fat->slices[i]->stream), alignment);
142 | }
143 | uint8_t *padding = malloc(paddingSize);
144 | memset(padding, 0, paddingSize);
145 | memory_stream_write(stream, sizeof(struct fat_header) + (sizeof(struct fat_arch) * fat->slicesCount), paddingSize, padding);
146 | free(padding);
147 |
148 | uint64_t offset = alignment;
149 | for (int i = 0; i < fat->slicesCount; i++) {
150 | MachO *macho = fat->slices[i];
151 | int size = memory_stream_get_size(macho->stream);
152 | void *data = malloc(size);
153 | memory_stream_read(macho->stream, 0, size, data);
154 | memory_stream_write(stream, offset, size, data);
155 | free(data);
156 | uint64_t alignedSize = i == fat->slicesCount - 1 ? size : align_to_size(size, alignment);;
157 | printf("Slice %d: 0x%x bytes, aligned to 0x%llx bytes.\n", i, size, alignedSize);
158 | padding = malloc(alignedSize - size);
159 | memset(padding, 0, alignedSize - size);
160 | memory_stream_write(stream, offset + size, alignedSize - size, padding);
161 | free(padding);
162 | offset += alignedSize;
163 | }
164 |
165 | if (fat) fat_free(fat);
166 | if (machoArray) free(machoArray);
167 | if (stream) memory_stream_free(stream);
168 | if (inputPaths) free(inputPaths);
169 |
170 | return 0;
171 | }
--------------------------------------------------------------------------------
/ChOma-main/tests/kpf/main.c:
--------------------------------------------------------------------------------
1 | #include "choma/FAT.h"
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | #include
8 | #include
9 |
10 | // 1. Direct branch (b)
11 | // 2. Direct function call (bl)
12 | // 3. Indirect function call (adr / adrp, add)
13 |
14 | int main(int argc, char *argv[]) {
15 | if (argc != 2) return -1;
16 |
17 | int fd = open(argv[1], O_RDONLY);
18 | if (fd < 0) return -1;
19 |
20 | struct stat stat_buf;
21 | fstat(fd, &stat_buf);
22 |
23 | void *mapping = mmap(NULL, stat_buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
24 | if (mapping == MAP_FAILED) return -1;
25 |
26 | MemoryStream *stream = buffered_stream_init_from_buffer(mapping, stat_buf.st_size, 0);
27 | if (!stream) return -1;
28 |
29 | FAT *fat = fat_init_from_memory_stream(stream);
30 | if (!fat) return -1;
31 |
32 | //FAT *fat = fat_init_from_path(argv[1]);
33 | //printf("fat: %p\n", fat);
34 | //if (!fat) return -1;
35 |
36 | MachO *macho = fat_find_preferred_slice(fat);
37 | if (macho) {
38 | uint32_t inst = 0xD503237F;
39 | uint32_t mask = 0xFFFFFFFF;
40 |
41 | clock_t t;
42 | t = clock();
43 |
44 | PFSection *kernelTextSection = pf_section_init_from_macho(macho, "com.apple.kernel", "__TEXT_EXEC", "__text");
45 | pf_section_set_cached(kernelTextSection, true);
46 |
47 | PFSection *kernelStringSection = pf_section_init_from_macho(macho, "com.apple.kernel", "__TEXT", "__cstring");
48 | pf_section_set_cached(kernelStringSection, true);
49 |
50 | PFBytePatternMetric *pacibspMetric = pf_create_byte_pattern_metric(&inst, &mask, sizeof(inst), BYTE_PATTERN_ALIGN_32_BIT);
51 | pf_section_run_metric(kernelTextSection, pacibspMetric, ^(uint64_t vmaddr, bool *stop) {
52 | printf("PACIBSP: 0x%llx (%x)\n", vmaddr, pf_section_read32(kernelTextSection, vmaddr+4));
53 | });
54 | pf_byte_pattern_metric_free(pacibspMetric);
55 |
56 | PFStringMetric *stringMetric = pf_create_string_metric("trust_cache_init");
57 | pf_section_run_metric(kernelStringSection, stringMetric, ^(uint64_t vmaddr, bool *stop) {
58 | printf("trust_cache_init: 0x%llx\n", vmaddr);
59 | });
60 | pf_string_metric_free(stringMetric);
61 |
62 | t = clock() - t;
63 | double time_taken = ((double)t)/CLOCKS_PER_SEC;
64 | printf("KPF finished in %lf seconds\n", time_taken);
65 |
66 | pf_section_free(kernelTextSection);
67 | }
68 |
69 | fat_free(fat);
70 | return 0;
71 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 RootHide
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # bootstrap-basebin
2 | base binaries for Bootstrap
3 |
--------------------------------------------------------------------------------
/bootstrap.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
13 | platform-application
14 |
15 | get-task-allow
16 |
17 | com.apple.private.persona-mgmt
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/bootstrap/.gitignore:
--------------------------------------------------------------------------------
1 | .theos/
2 | packages/
3 | .DS_Store
4 |
--------------------------------------------------------------------------------
/bootstrap/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "files.associations": {
3 | "stdio.h": "c",
4 | "stdlib.h": "c",
5 | "ASSERT.h": "c",
6 | "syslog.h": "c",
7 | "fishhook.h": "c",
8 | "util.h": "c",
9 | "common.h": "c",
10 | "unistd.h": "c",
11 | "loader.h": "c",
12 | "mach.h": "c",
13 | "dyld.h": "c",
14 | "syslimits.h": "c",
15 | "*.cccc": "c",
16 | "varargs.h": "c",
17 | "vadefs.h": "c",
18 | "fcntl.h": "c",
19 | "stat.h": "c",
20 | "dlfcn.h": "c",
21 | "sandbox.h": "c",
22 | "libbsd.h": "c",
23 | "stdarg.h": "c",
24 | "errno.h": "c",
25 | "string.h": "c",
26 | "spawn.h": "c",
27 | "paths.h": "c",
28 | "iosfwd": "cpp",
29 | "machine.h": "c",
30 | "byte_order.h": "c",
31 | "__config": "c",
32 | "filesystem": "c",
33 | "stdbool.h": "c",
34 | "__locale": "c",
35 | "locale": "c",
36 | "signal.h": "c",
37 | "utsname.h": "c",
38 | "param.h": "c",
39 | "pwd.h": "c",
40 | "libproc.h": "c",
41 | "libproc_private.h": "c"
42 | }
43 | }
--------------------------------------------------------------------------------
/bootstrap/Makefile:
--------------------------------------------------------------------------------
1 | TARGET := iphone:clang:latest:15.0
2 |
3 | THEOS_PACKAGE_SCHEME = roothide
4 |
5 | FINALPACKAGE ?= 1
6 | DEBUG ?= 0
7 |
8 | include $(THEOS)/makefiles/common.mk
9 |
10 | LIBRARY_NAME = bootstrap
11 |
12 | bootstrap_FILES = $(wildcard *.c *.x *.m *.S) ../bootstrapd/ipc.m ../bootstrapd/libbsd.m
13 | bootstrap_CFLAGS = -fobjc-arc -Wno-deprecated-declarations -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-value -Wno-format-invalid-specifier
14 | bootstrap_LDFLAGS = -L./ -ldobby -lc++
15 | bootstrap_INSTALL_PATH = /basebin
16 |
17 | include $(THEOS_MAKE_PATH)/library.mk
18 |
19 | clean::
20 | rm -rf ./packages/*
21 |
22 | ifneq ($(DEBUG), 1)
23 | before-package::
24 | strip -N ./.theos/_/basebin/bootstrap.dylib
25 | ldid -S ./.theos/_/basebin/bootstrap.dylib
26 | endif
27 |
--------------------------------------------------------------------------------
/bootstrap/assert.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #define SIGABRT 6
5 | #define OS_REASON_SIGNAL 2
6 | #define OS_REASON_DYLD 6
7 | #define DYLD_EXIT_REASON_OTHER 9
8 |
9 | void abort_with_payload(uint32_t reason_namespace, uint64_t reason_code,
10 | void *payload, uint32_t payload_size,
11 | const char *reason_string, uint64_t reason_flags)
12 | __attribute__((noreturn, cold));
13 |
14 | #define ASSERT(e) (__builtin_expect(!(e), 0) ?\
15 | ((void)fprintf(stderr, "%s:%d: failed ASSERTion `%s'\n", __FILE_NAME__, __LINE__, #e),\
16 | abort_with_payload(OS_REASON_DYLD,DYLD_EXIT_REASON_OTHER,NULL,0, #e, 0)) : (void)0)
17 |
--------------------------------------------------------------------------------
/bootstrap/common.c:
--------------------------------------------------------------------------------
1 | #include "common.h"
2 |
3 | bool stringStartsWith(const char *str, const char* prefix)
4 | {
5 | if (!str || !prefix) {
6 | return false;
7 | }
8 |
9 | size_t str_len = strlen(str);
10 | size_t prefix_len = strlen(prefix);
11 |
12 | if (str_len < prefix_len) {
13 | return false;
14 | }
15 |
16 | return !strncmp(str, prefix, prefix_len);
17 | }
18 |
19 | bool stringEndsWith(const char* str, const char* suffix)
20 | {
21 | if (!str || !suffix) {
22 | return false;
23 | }
24 |
25 | size_t str_len = strlen(str);
26 | size_t suffix_len = strlen(suffix);
27 |
28 | if (str_len < suffix_len) {
29 | return false;
30 | }
31 |
32 | return !strcmp(str + str_len - suffix_len, suffix);
33 | }
34 |
--------------------------------------------------------------------------------
/bootstrap/common.h:
--------------------------------------------------------------------------------
1 |
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include "assert.h"
8 |
9 | extern char** environ;
10 |
11 | extern char** NXArgv; // __NSGetArgv() not working on ctor
12 | extern int NXArgc;
13 |
14 | #define EXPORT __attribute__ ((visibility ("default")))
15 |
16 | #ifdef DEBUG
17 | void bootstrapLog(const char* format, ...);
18 | #define SYSLOG bootstrapLog
19 | #else
20 | #define SYSLOG(...)
21 | #endif
22 |
23 | bool stringStartsWith(const char *str, const char* prefix);
24 | bool stringEndsWith(const char* str, const char* suffix);
25 |
26 | void fixsuid();
27 |
28 | pid_t __getppid();
29 |
30 | int requireJIT();
31 |
32 | extern struct mach_header_64* _dyld_get_prog_image_header();
33 | extern intptr_t _dyld_get_image_slide(struct mach_header_64* mh);
34 |
35 |
36 | extern int posix_spawn_hook(pid_t *restrict pid, const char *restrict file,
37 | const posix_spawn_file_actions_t *restrict file_actions,
38 | const posix_spawnattr_t *restrict attrp,
39 | char *const argv[restrict],
40 | char *const envp[restrict]);
41 |
42 |
--------------------------------------------------------------------------------
/bootstrap/common.m:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "common.h"
6 | #include "../bootstrapd/libbsd.h"
7 |
8 | void bootstrapLog(const char* format, ...)
9 | {
10 | va_list ap;
11 | va_start(ap, format);
12 | NSString* log = [[NSString alloc] initWithFormat:@(format) arguments:ap];
13 | va_end(ap);
14 |
15 | // fprintf(stderr, "%s\n", log.UTF8String);
16 | // fflush(stderr);
17 |
18 | openlog("bootstrap",LOG_PID,LOG_AUTH);
19 | syslog(LOG_DEBUG, "%s", log.UTF8String);
20 | closelog();
21 | }
22 |
23 | @interface LSApplicationWorkspace : NSObject
24 | +(instancetype)defaultWorkspace;
25 | -(BOOL)openApplicationWithBundleID:(id)arg1 ;
26 | -(id)pluginsWithIdentifiers:(id)arg1 protocols:(id)arg2 version:(id)arg3 ;
27 | -(id)pluginsWithIdentifiers:(id)arg1 protocols:(id)arg2 version:(id)arg3 applyFilter:(/*^block*/id)arg4 ;
28 | -(id)pluginsWithIdentifiers:(id)arg1 protocols:(id)arg2 version:(id)arg3 withFilter:(/*^block*/id)arg4 ;
29 | -(void)enumeratePluginsMatchingQuery:(id)arg1 withBlock:(/*^block*/id)arg2 ;
30 | -(id)pluginsMatchingQuery:(id)arg1 applyFilter:(/*^block*/id)arg2 ;
31 | @end
32 |
33 | #include
34 | void launchBootstrapApp()
35 | {
36 | dlopen("/System/Library/Frameworks/CoreServices.framework/CoreServices", RTLD_NOW);
37 | Class class_LSApplicationWorkspace = NSClassFromString(@"LSApplicationWorkspace");
38 | [[class_LSApplicationWorkspace defaultWorkspace] openApplicationWithBundleID:@"com.roothide.Bootstrap"];
39 | }
40 |
41 | void varCleanInit()
42 | {
43 | SYSLOG("varClean: init...");
44 |
45 | if([NSHomeDirectory().stringByStandardizingPath hasPrefix:@"/var/mobile/Containers/"]) {
46 | return;
47 | }
48 |
49 | dispatch_async(dispatch_get_main_queue(), ^{
50 | static NSOperationQueue* queue;
51 |
52 | queue = [NSOperationQueue new];
53 | queue.maxConcurrentOperationCount = 1;
54 |
55 | [NSNotificationCenter.defaultCenter addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil
56 | queue:queue usingBlock:^(NSNotification* note) {
57 | SYSLOG("varClean UIApplicationDidEnterBackgroundNotification %@", note);
58 | bsd_varClean();
59 | }];
60 |
61 | [NSNotificationCenter.defaultCenter addObserverForName:UIApplicationWillTerminateNotification object:nil
62 | queue:queue usingBlock:^(NSNotification* note) {
63 | SYSLOG("varClean UIApplicationWillTerminateNotification %@", note);
64 | bsd_varClean();
65 | }];
66 |
67 | SYSLOG("varClean init in main queue");
68 | });
69 | }
70 |
71 | bool isTrollStoredApp()
72 | {
73 | return [NSFileManager.defaultManager fileExistsAtPath:[NSString stringWithFormat:@"%@/../_TrollStore", NSBundle.mainBundle.bundlePath]];
74 | }
75 |
--------------------------------------------------------------------------------
/bootstrap/control:
--------------------------------------------------------------------------------
1 | Package: com.roothide.bootstrap.dylib
2 | Name: bootstrap
3 | Version: 0.0.1
4 | Architecture: iphoneos-arm
5 | Description: An awesome library of some sort!!
6 | Maintainer: roothide
7 | Author: roothide
8 | Section: System
9 | Tag: role::developer
10 |
--------------------------------------------------------------------------------
/bootstrap/dobby.h:
--------------------------------------------------------------------------------
1 | #ifndef dobby_h
2 | #define dobby_h
3 |
4 | #ifdef __cplusplus
5 | extern "C" {
6 | #endif
7 |
8 | #include
9 | #include
10 |
11 | typedef uintptr_t addr_t;
12 | typedef uint32_t addr32_t;
13 | typedef uint64_t addr64_t;
14 |
15 | typedef void *dobby_dummy_func_t;
16 | typedef void *asm_func_t;
17 |
18 | #if defined(__arm__)
19 | typedef struct {
20 | uint32_t dummy_0;
21 | uint32_t dummy_1;
22 |
23 | uint32_t dummy_2;
24 | uint32_t sp;
25 |
26 | union {
27 | uint32_t r[13];
28 | struct {
29 | uint32_t r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12;
30 | } regs;
31 | } general;
32 |
33 | uint32_t lr;
34 | } DobbyRegisterContext;
35 | #elif defined(__arm64__) || defined(__aarch64__)
36 | #define ARM64_TMP_REG_NDX_0 17
37 |
38 | typedef union _FPReg {
39 | __int128_t q;
40 | struct {
41 | double d1;
42 | double d2;
43 | } d;
44 | struct {
45 | float f1;
46 | float f2;
47 | float f3;
48 | float f4;
49 | } f;
50 | } FPReg;
51 |
52 | // register context
53 | typedef struct {
54 | uint64_t dmmpy_0; // dummy placeholder
55 | uint64_t sp;
56 |
57 | uint64_t dmmpy_1; // dummy placeholder
58 | union {
59 | uint64_t x[29];
60 | struct {
61 | uint64_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22,
62 | x23, x24, x25, x26, x27, x28;
63 | } regs;
64 | } general;
65 |
66 | uint64_t fp;
67 | uint64_t lr;
68 |
69 | union {
70 | FPReg q[32];
71 | struct {
72 | FPReg q0, q1, q2, q3, q4, q5, q6, q7;
73 | // [!!! READ ME !!!]
74 | // for Arm64, can't access q8 - q31, unless you enable full floating-point register pack
75 | FPReg q8, q9, q10, q11, q12, q13, q14, q15, q16, q17, q18, q19, q20, q21, q22, q23, q24, q25, q26, q27, q28, q29,
76 | q30, q31;
77 | } regs;
78 | } floating;
79 | } DobbyRegisterContext;
80 | #elif defined(_M_IX86) || defined(__i386__)
81 | typedef struct _RegisterContext {
82 | uint32_t dummy_0;
83 | uint32_t esp;
84 |
85 | uint32_t dummy_1;
86 | uint32_t flags;
87 |
88 | union {
89 | struct {
90 | uint32_t eax, ebx, ecx, edx, ebp, esp, edi, esi;
91 | } regs;
92 | } general;
93 |
94 | } DobbyRegisterContext;
95 | #elif defined(_M_X64) || defined(__x86_64__)
96 | typedef struct {
97 | uint64_t dummy_0;
98 | uint64_t rsp;
99 |
100 | union {
101 | struct {
102 | uint64_t rax, rbx, rcx, rdx, rbp, rsp, rdi, rsi, r8, r9, r10, r11, r12, r13, r14, r15;
103 | } regs;
104 | } general;
105 |
106 | uint64_t dummy_1;
107 | uint64_t flags;
108 | } DobbyRegisterContext;
109 | #endif
110 |
111 | #define install_hook_name(name, fn_ret_t, fn_args_t...) \
112 | static fn_ret_t fake_##name(fn_args_t); \
113 | static fn_ret_t (*orig_##name)(fn_args_t); \
114 | /* __attribute__((constructor)) */ static void install_hook_##name(void *sym_addr) { \
115 | DobbyHook(sym_addr, (dobby_dummy_func_t)fake_##name, (dobby_dummy_func_t *)&orig_##name); \
116 | return; \
117 | } \
118 | fn_ret_t fake_##name(fn_args_t)
119 |
120 | // memory code patch
121 | int DobbyCodePatch(void *address, uint8_t *buffer, uint32_t buffer_size);
122 |
123 | // function inline hook
124 | int DobbyHook(void *address, dobby_dummy_func_t replace_func, dobby_dummy_func_t *origin_func);
125 |
126 | // dynamic binary instruction instrument
127 | // for Arm64, can't access q8 - q31, unless enable full floating-point register pack
128 | typedef void (*dobby_instrument_callback_t)(void *address, DobbyRegisterContext *ctx);
129 | int DobbyInstrument(void *address, dobby_instrument_callback_t pre_handler);
130 |
131 | // destroy and restore code patch
132 | int DobbyDestroy(void *address);
133 |
134 | const char *DobbyGetVersion();
135 |
136 | // symbol resolver
137 | void *DobbySymbolResolver(const char *image_name, const char *symbol_name);
138 |
139 | // import table replace
140 | int DobbyImportTableReplace(char *image_name, char *symbol_name, dobby_dummy_func_t fake_func,
141 | dobby_dummy_func_t *orig_func);
142 |
143 | // for arm, Arm64, try use b xxx instead of ldr absolute indirect branch
144 | // for x86, x64, always use absolute indirect jump
145 | void dobby_enable_near_branch_trampoline();
146 | void dobby_disable_near_branch_trampoline();
147 |
148 | #ifdef __cplusplus
149 | }
150 | #endif
151 |
152 | #endif
153 |
--------------------------------------------------------------------------------
/bootstrap/envbuf.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | int envbuf_len(const char *envp[])
5 | {
6 | if (envp == NULL) return 1;
7 |
8 | int k = 0;
9 | const char *env = envp[k++];
10 | while (env != NULL) {
11 | env = envp[k++];
12 | }
13 | return k;
14 | }
15 |
16 | char **envbuf_mutcopy(const char *envp[])
17 | {
18 | if (envp == NULL) return NULL; //opa said don't comment this
19 |
20 | int len = envbuf_len(envp);
21 | char **envcopy = malloc(len * sizeof(char *));
22 |
23 | for (int i = 0; i < len-1; i++) {
24 | envcopy[i] = strdup(envp[i]);
25 | }
26 | envcopy[len-1] = NULL;
27 |
28 | return envcopy;
29 | }
30 |
31 | void envbuf_free(char *envp[])
32 | {
33 | if (envp == NULL) return;
34 |
35 | int len = envbuf_len((const char**)envp);
36 | for (int i = 0; i < len-1; i++) {
37 | free(envp[i]);
38 | }
39 | free(envp);
40 | }
41 |
42 | int envbuf_find(const char *envp[], const char *name)
43 | {
44 | if (envp) {
45 | unsigned long nameLen = strlen(name);
46 | int k = 0;
47 | const char *env = envp[k++];
48 | while (env != NULL) {
49 | unsigned long envLen = strlen(env);
50 | if (envLen > nameLen) {
51 | if (!strncmp(env, name, nameLen)) {
52 | if (env[nameLen] == '=') {
53 | return k-1;
54 | }
55 | }
56 | }
57 | env = envp[k++];
58 | }
59 | }
60 | return -1;
61 | }
62 |
63 | const char *envbuf_getenv(const char *envp[], const char *name)
64 | {
65 | if (envp) {
66 | unsigned long nameLen = strlen(name);
67 | int envIndex = envbuf_find(envp, name);
68 | if (envIndex >= 0) {
69 | return &envp[envIndex][nameLen+1];
70 | }
71 | }
72 | return NULL;
73 | }
74 |
75 | void envbuf_setenv(char **envpp[], const char *name, const char *value, int override)
76 | {
77 | if (envpp) {
78 | char **envp = *envpp;
79 | if (!envp) {
80 | // treat NULL as [NULL]
81 | envp = malloc(sizeof(const char *));
82 | envp[0] = NULL;
83 | }
84 |
85 | char *envToSet = malloc(strlen(name)+strlen(value)+2);
86 | strcpy(envToSet, name);
87 | strcat(envToSet, "=");
88 | strcat(envToSet, value);
89 |
90 | int existingEnvIndex = envbuf_find((const char **)envp, name);
91 | if (existingEnvIndex >= 0) {
92 | if(!override) {
93 | free(envToSet);
94 | return;
95 | }
96 | // if already exists: deallocate old variable, then replace pointer
97 | free(envp[existingEnvIndex]);
98 | envp[existingEnvIndex] = envToSet;
99 | }
100 | else {
101 | // if doesn't exist yet: increase env buffer size, place at end
102 | int prevLen = envbuf_len((const char **)envp);
103 | *envpp = realloc(envp, (prevLen+1)*sizeof(const char *));
104 | envp = *envpp;
105 | envp[prevLen-1] = envToSet;
106 | envp[prevLen] = NULL;
107 | }
108 | }
109 | }
110 |
111 | void envbuf_unsetenv(char **envpp[], const char *name)
112 | {
113 | if (envpp) {
114 | char **envp = *envpp;
115 | if (!envp) return;
116 |
117 | int existingEnvIndex = envbuf_find((const char **)envp, name);
118 | if (existingEnvIndex >= 0) {
119 | free(envp[existingEnvIndex]);
120 | int prevLen = envbuf_len((const char **)envp);
121 | for (int i = existingEnvIndex; i < (prevLen-1); i++) {
122 | envp[i] = envp[i+1];
123 | }
124 | *envpp = realloc(envp, (prevLen-1)*sizeof(const char *));
125 | }
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/bootstrap/envbuf.h:
--------------------------------------------------------------------------------
1 | int envbuf_len(const char *envp[]);
2 | char **envbuf_mutcopy(const char *envp[]);
3 | void envbuf_free(char *envp[]);
4 | int envbuf_find(const char *envp[], const char *name);
5 | const char *envbuf_getenv(const char *envp[], const char *name);
6 | void envbuf_setenv(char **envpp[], const char *name, const char *value, int overwrite);
7 | void envbuf_unsetenv(char **envpp[], const char *name);
--------------------------------------------------------------------------------
/bootstrap/exechook.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 |
13 | #include
14 |
15 | #include "common.h"
16 | #include "envbuf.h"
17 |
18 |
19 | // Derived from posix_spawnp in Apple libc
20 | int resolvePath(const char *file, const char *searchPath, int (^attemptHandler)(char *path))
21 | {
22 | const char *env_path;
23 | char *bp;
24 | char *cur;
25 | char *p;
26 | char **memp;
27 | int lp;
28 | int ln;
29 | int cnt;
30 | int err = 0;
31 | int eacces = 0;
32 | struct stat sb;
33 | char path_buf[PATH_MAX];
34 |
35 | env_path = searchPath;
36 | if (!env_path) {
37 | env_path = getenv("PATH");
38 | if (!env_path) {
39 | env_path = _PATH_DEFPATH;
40 | }
41 | }
42 |
43 | /* If it's an absolute or relative path name, it's easy. */
44 | if (index(file, '/')) {
45 | bp = (char *)file;
46 | cur = NULL;
47 | goto retry;
48 | }
49 | bp = path_buf;
50 |
51 | /* If it's an empty path name, fail in the usual POSIX way. */
52 | if (*file == '\0')
53 | return (ENOENT);
54 |
55 | if ((cur = alloca(strlen(env_path) + 1)) == NULL)
56 | return ENOMEM;
57 | strcpy(cur, env_path);
58 | while ((p = strsep(&cur, ":")) != NULL) {
59 | /*
60 | * It's a SHELL path -- double, leading and trailing colons
61 | * mean the current directory.
62 | */
63 | if (*p == '\0') {
64 | p = ".";
65 | lp = 1;
66 | } else {
67 | lp = strlen(p);
68 | }
69 | ln = strlen(file);
70 |
71 | /*
72 | * If the path is too long complain. This is a possible
73 | * security issue; given a way to make the path too long
74 | * the user may spawn the wrong program.
75 | */
76 | if (lp + ln + 2 > sizeof(path_buf)) {
77 | err = ENAMETOOLONG;
78 | goto done;
79 | }
80 | bcopy(p, path_buf, lp);
81 | path_buf[lp] = '/';
82 | bcopy(file, path_buf + lp + 1, ln);
83 | path_buf[lp + ln + 1] = '\0';
84 |
85 | retry: err = attemptHandler(bp);
86 | switch (err) {
87 | case E2BIG:
88 | case ENOMEM:
89 | case ETXTBSY:
90 | goto done;
91 | case ELOOP:
92 | case ENAMETOOLONG:
93 | case ENOENT:
94 | case ENOTDIR:
95 | break;
96 | case ENOEXEC:
97 | goto done;
98 | default:
99 | /*
100 | * EACCES may be for an inaccessible directory or
101 | * a non-executable file. Call stat() to decide
102 | * which. This also handles ambiguities for EFAULT
103 | * and EIO, and undocumented errors like ESTALE.
104 | * We hope that the race for a stat() is unimportant.
105 | */
106 | if (stat(bp, &sb) != 0)
107 | break;
108 | if (err == EACCES) {
109 | eacces = 1;
110 | continue;
111 | }
112 | goto done;
113 | }
114 | }
115 | if (eacces)
116 | err = EACCES;
117 | else
118 | err = ENOENT;
119 | done:
120 | return (err);
121 | }
122 |
123 | void enumeratePathString(const char *pathsString, void (^enumBlock)(const char *pathString, bool *stop))
124 | {
125 | char *pathsCopy = strdup(pathsString);
126 | char *pathString = strtok(pathsCopy, ":");
127 | while (pathString != NULL) {
128 | bool stop = false;
129 | enumBlock(pathString, &stop);
130 | if (stop) break;
131 | pathString = strtok(NULL, ":");
132 | }
133 | free(pathsCopy);
134 | }
135 |
136 | // extern const char* bootstrapath;
137 | int posix_spawn_hook(pid_t *restrict pid, const char *restrict path,
138 | const posix_spawn_file_actions_t *restrict file_actions,
139 | const posix_spawnattr_t *restrict attrp,
140 | char *const argv[restrict],
141 | char *const envp[restrict])
142 | {
143 | const char* preload = envbuf_getenv((const char **)envp, "DYLD_INSERT_LIBRARIES");
144 | char **envc = envbuf_mutcopy((const char **)envp);
145 |
146 | bool isBootstrapApp = stringEndsWith(path, "/Bootstrap.app/Bootstrap");
147 |
148 | const char* bootstrapath = jbroot("/basebin/bootstrap.dylib");
149 | if(!isBootstrapApp) if(!preload || !strstr(preload, "/basebin/bootstrap.dylib"))
150 | {
151 | int newlen = strlen(bootstrapath)+1;
152 | if(preload && *preload) newlen += strlen(preload);
153 |
154 | char newpreload[newlen];
155 | strcpy(newpreload, bootstrapath);
156 |
157 | if(preload && *preload) {
158 | strcat(newpreload, ":");
159 | strcat(newpreload, preload);
160 | }
161 |
162 | envbuf_setenv(&envc, "DYLD_INSERT_LIBRARIES", newpreload, 1);
163 | }
164 |
165 | int retval = posix_spawn(pid, path, file_actions, attrp, argv, envc);
166 | envbuf_free(envc);
167 | return retval;
168 | }
169 |
--------------------------------------------------------------------------------
/bootstrap/fishhook.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2013, Facebook, Inc.
2 | // All rights reserved.
3 | // Redistribution and use in source and binary forms, with or without
4 | // modification, are permitted provided that the following conditions are met:
5 | // * Redistributions of source code must retain the above copyright notice,
6 | // this list of conditions and the following disclaimer.
7 | // * Redistributions in binary form must reproduce the above copyright notice,
8 | // this list of conditions and the following disclaimer in the documentation
9 | // and/or other materials provided with the distribution.
10 | // * Neither the name Facebook nor the names of its contributors may be used to
11 | // endorse or promote products derived from this software without specific
12 | // prior written permission.
13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
17 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
21 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 |
24 | #ifndef fishhook_h
25 | #define fishhook_h
26 |
27 | #include
28 | #include
29 |
30 | #if !defined(FISHHOOK_EXPORT)
31 | #define FISHHOOK_VISIBILITY __attribute__((visibility("hidden")))
32 | #else
33 | #define FISHHOOK_VISIBILITY __attribute__((visibility("default")))
34 | #endif
35 |
36 | #ifdef __cplusplus
37 | extern "C" {
38 | #endif //__cplusplus
39 |
40 | /*
41 | * A structure representing a particular intended rebinding from a symbol
42 | * name to its replacement
43 | */
44 | struct rebinding {
45 | const char *name;
46 | void *replacement;
47 | void **replaced;
48 | };
49 |
50 | /*
51 | * For each rebinding in rebindings, rebinds references to external, indirect
52 | * symbols with the specified name to instead point at replacement for each
53 | * image in the calling process as well as for all future images that are loaded
54 | * by the process. If rebind_functions is called more than once, the symbols to
55 | * rebind are added to the existing list of rebindings, and if a given symbol
56 | * is rebound more than once, the later rebinding will take precedence.
57 | */
58 | FISHHOOK_VISIBILITY
59 | int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel);
60 |
61 | /*
62 | * Rebinds as above, but only in the specified image. The header should point
63 | * to the mach-o header, the slide should be the slide offset. Others as above.
64 | */
65 | FISHHOOK_VISIBILITY
66 | int rebind_symbols_image(void *header,
67 | intptr_t slide,
68 | struct rebinding rebindings[],
69 | size_t rebindings_nel);
70 |
71 | #ifdef __cplusplus
72 | }
73 | #endif //__cplusplus
74 |
75 | #endif //fishhook_h
76 |
77 |
--------------------------------------------------------------------------------
/bootstrap/fixsuid.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #include "common.h"
11 |
12 | enum {
13 | PERSONA_INVALID = 0,
14 | PERSONA_GUEST = 1,
15 | PERSONA_MANAGED = 2,
16 | PERSONA_PRIV = 3,
17 | PERSONA_SYSTEM = 4,
18 | PERSONA_DEFAULT = 5,
19 | PERSONA_SYSTEM_PROXY = 6,
20 | PERSONA_SYS_EXT = 7,
21 | PERSONA_ENTERPRISE = 8,
22 |
23 | PERSONA_TYPE_MAX = PERSONA_ENTERPRISE,
24 | };
25 |
26 | #define PERSONA_INFO_V1 1
27 | #define PERSONA_INFO_V2 2
28 |
29 | struct kpersona_info {
30 | /* v1 fields */
31 | uint32_t persona_info_version;
32 |
33 | uid_t persona_id;
34 | int persona_type;
35 | gid_t persona_gid; /* unused */
36 | uint32_t persona_ngroups; /* unused */
37 | gid_t persona_groups[NGROUPS]; /* unused */
38 | uid_t persona_gmuid; /* unused */
39 | char persona_name[MAXLOGNAME + 1];
40 |
41 | /* v2 fields */
42 | uid_t persona_uid;
43 | } __attribute__((packed));
44 |
45 | extern int kpersona_find_by_type(int persona_type, uid_t *id, size_t *idlen);
46 | extern int kpersona_getpath(uid_t id, char path[MAXPATHLEN]);
47 | extern int kpersona_pidinfo(pid_t id, struct kpersona_info *info);
48 | extern int kpersona_info(uid_t id, struct kpersona_info *info);
49 | extern int kpersona_find(const char *name, uid_t uid, uid_t *id, size_t *idlen);
50 | extern int kpersona_alloc(struct kpersona_info *info, uid_t *id);
51 |
52 |
53 | int available_persona_id()
54 | {
55 | struct kpersona_info info={PERSONA_INFO_V1};
56 | ASSERT(kpersona_pidinfo(getpid(), &info) == 0);
57 |
58 | int current_persona_id = info.persona_id;
59 |
60 | for(int t=1; t<=PERSONA_TYPE_MAX; t++)
61 | {
62 | uid_t personas[128]={0};
63 | size_t npersonas = 128;
64 |
65 | if(kpersona_find_by_type(t, personas, &npersonas) <= 0)
66 | continue;
67 |
68 | for(int i=0; i
84 |
85 | void fixsuid()
86 | {
87 | if(getenv("UIDFIX")) {
88 | uid_t uid = atoi(getenv("UIDFIX"));
89 | setreuid(uid, geteuid());
90 | unsetenv("UIDFIX");
91 | }
92 | if(getenv("GIDFIX")) {
93 | uid_t gid = atoi(getenv("GIDFIX"));
94 | setregid(gid, getegid());
95 | unsetenv("GIDFIX");
96 | }
97 |
98 | char path[PATH_MAX]={0};
99 | uint32_t bufsize=sizeof(path);
100 | ASSERT(_NSGetExecutablePath(path, &bufsize) == 0);
101 |
102 | struct stat st;
103 | ASSERT(stat(path, &st) == 0);
104 |
105 | if (!S_ISREG(st.st_mode) || !(st.st_mode & (S_ISUID | S_ISGID)))
106 | return;
107 |
108 | if( ((st.st_mode&S_ISUID)==0 || st.st_uid==geteuid())
109 | && ((st.st_mode&S_ISGID)==0 || st.st_gid==getegid()) )
110 | return;
111 |
112 |
113 | char uidbuf[32], gidbuf[32];
114 | snprintf(uidbuf, sizeof(uidbuf), "%d", geteuid());
115 | snprintf(gidbuf, sizeof(gidbuf), "%d", getegid());
116 | setenv("UIDFIX", uidbuf, 1);
117 | setenv("GIDFIX", gidbuf, 1);
118 |
119 | posix_spawnattr_t attr;
120 | posix_spawnattr_init(&attr);
121 |
122 | int persona_id = available_persona_id();
123 | ASSERT(persona_id != 0);
124 |
125 | posix_spawnattr_set_persona_np(&attr, persona_id, POSIX_SPAWN_PERSONA_FLAGS_OVERRIDE);
126 | if(st.st_mode & S_ISUID) posix_spawnattr_set_persona_uid_np(&attr, st.st_uid);
127 | if(st.st_mode & S_ISGID) posix_spawnattr_set_persona_gid_np(&attr, st.st_gid);
128 |
129 | posix_spawn_file_actions_t action;
130 | posix_spawn_file_actions_init(&action);
131 |
132 | pid_t pid=0;
133 | int ret = posix_spawn_hook(&pid, path, &action, &attr, NXArgv, environ);
134 |
135 | ASSERT(ret==0 && pid>0);
136 |
137 | int status=0;
138 | while(waitpid(pid, &status, 0) != -1)
139 | {
140 | if (WIFSIGNALED(status)) {
141 | kill(getpid(), -WTERMSIG(status));
142 | } else if (WIFEXITED(status)) {
143 | exit(WEXITSTATUS(status));
144 | }
145 | //keep waiting?return status;
146 | };
147 |
148 | exit(-1);
149 | }
150 |
151 | void runAsRoot(const char* path, char* argv[])
152 | {
153 | posix_spawnattr_t attr;
154 | posix_spawnattr_init(&attr);
155 |
156 | int persona_id = available_persona_id();
157 | ASSERT(persona_id != 0);
158 |
159 | posix_spawnattr_set_persona_np(&attr, persona_id, POSIX_SPAWN_PERSONA_FLAGS_OVERRIDE);
160 | posix_spawnattr_set_persona_uid_np(&attr, 0);
161 | posix_spawnattr_set_persona_gid_np(&attr, 0);
162 |
163 | posix_spawn_file_actions_t action;
164 | posix_spawn_file_actions_init(&action);
165 |
166 | pid_t pid=0;
167 | int ret = posix_spawn_hook(&pid, path, &action, &attr, argv, environ);
168 |
169 | ASSERT(ret==0 && pid>0);
170 |
171 | int status=0;
172 | while(waitpid(pid, &status, 0) != -1)
173 | {
174 | if (WIFSIGNALED(status)) {
175 | kill(getpid(), -WTERMSIG(status));
176 | } else if (WIFEXITED(status)) {
177 | exit(WEXITSTATUS(status));
178 | }
179 | //keep waiting?return status;
180 | };
181 |
182 | exit(-1);
183 | }
184 |
185 |
--------------------------------------------------------------------------------
/bootstrap/layout/DEBIAN/preinst:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # rm -f /basebin/bootstrap.dylib || true
4 |
--------------------------------------------------------------------------------
/bootstrap/libdobby.a:
--------------------------------------------------------------------------------
1 | ../../../Dobby-master/build/iphoneos/universal/libdobby.a
--------------------------------------------------------------------------------
/bootstrap/libproc.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2006, 2007, 2010 Apple Inc. All rights reserved.
3 | *
4 | * @APPLE_LICENSE_HEADER_START@
5 | *
6 | * This file contains Original Code and/or Modifications of Original Code
7 | * as defined in and that are subject to the Apple Public Source License
8 | * Version 2.0 (the 'License'). You may not use this file except in
9 | * compliance with the License. Please obtain a copy of the License at
10 | * http://www.opensource.apple.com/apsl/ and read it before using this
11 | * file.
12 | *
13 | * The Original Code and all software distributed under the License are
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 | * Please see the License for the specific language governing rights and
19 | * limitations under the License.
20 | *
21 | * @APPLE_LICENSE_HEADER_END@
22 | */
23 | #ifndef _LIBPROC_H_
24 | #define _LIBPROC_H_
25 |
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 |
35 | #include
36 |
37 | /*
38 | * This header file contains private interfaces to obtain process information.
39 | * These interfaces are subject to change in future releases.
40 | */
41 |
42 | /*!
43 | @define PROC_LISTPIDSPATH_PATH_IS_VOLUME
44 | @discussion This flag indicates that all processes that hold open
45 | file references on the volume associated with the specified
46 | path should be returned.
47 | */
48 | #define PROC_LISTPIDSPATH_PATH_IS_VOLUME 1
49 |
50 |
51 | /*!
52 | @define PROC_LISTPIDSPATH_EXCLUDE_EVTONLY
53 | @discussion This flag indicates that file references that were opened
54 | with the O_EVTONLY flag should be excluded from the matching
55 | criteria.
56 | */
57 | #define PROC_LISTPIDSPATH_EXCLUDE_EVTONLY 2
58 |
59 | __BEGIN_DECLS
60 |
61 |
62 | /*!
63 | @function proc_listpidspath
64 | @discussion A function which will search through the current
65 | processes looking for open file references which match
66 | a specified path or volume.
67 | @param type types of processes to be searched (see proc_listpids)
68 | @param typeinfo adjunct information for type
69 | @param path file or volume path
70 | @param pathflags flags to control which files should be considered
71 | during the process search.
72 | @param buffer a C array of int-sized values to be filled with
73 | process identifiers that hold an open file reference
74 | matching the specified path or volume. Pass NULL to
75 | obtain the minimum buffer size needed to hold the
76 | currently active processes.
77 | @param buffersize the size (in bytes) of the provided buffer.
78 | @result the number of bytes of data returned in the provided buffer;
79 | -1 if an error was encountered;
80 | */
81 | int proc_listpidspath(uint32_t type,
82 | uint32_t typeinfo,
83 | const char *path,
84 | uint32_t pathflags,
85 | void *buffer,
86 | int buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
87 |
88 | int proc_listpids(uint32_t type, uint32_t typeinfo, void *buffer, int buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
89 | int proc_listallpids(void * buffer, int buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_1);
90 | int proc_listpgrppids(pid_t pgrpid, void * buffer, int buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_1);
91 | int proc_listchildpids(pid_t ppid, void * buffer, int buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_1);
92 | int proc_pidinfo(int pid, int flavor, uint64_t arg, void *buffer, int buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
93 | int proc_pidfdinfo(int pid, int fd, int flavor, void * buffer, int buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
94 | int proc_pidfileportinfo(int pid, uint32_t fileport, int flavor, void *buffer, int buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
95 | int proc_name(int pid, void * buffer, uint32_t buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
96 | int proc_regionfilename(int pid, uint64_t address, void * buffer, uint32_t buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
97 | int proc_kmsgbuf(void * buffer, uint32_t buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
98 | int proc_pidpath(int pid, void * buffer, uint32_t buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
99 | int proc_libversion(int *major, int * minor) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
100 |
101 | /*
102 | * Return resource usage information for the given pid, which can be a live process or a zombie.
103 | *
104 | * Returns 0 on success; or -1 on failure, with errno set to indicate the specific error.
105 | */
106 | int proc_pid_rusage(int pid, int flavor, rusage_info_t *buffer) __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0);
107 |
108 | /*
109 | * A process can use the following api to set its own process control
110 | * state on resoure starvation. The argument can have one of the PROC_SETPC_XX values
111 | */
112 | #define PROC_SETPC_NONE 0
113 | #define PROC_SETPC_THROTTLEMEM 1
114 | #define PROC_SETPC_SUSPEND 2
115 | #define PROC_SETPC_TERMINATE 3
116 |
117 | int proc_setpcontrol(const int control) __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2);
118 | int proc_setpcontrol(const int control);
119 |
120 | int proc_track_dirty(pid_t pid, uint32_t flags);
121 | int proc_set_dirty(pid_t pid, bool dirty);
122 | int proc_get_dirty(pid_t pid, uint32_t *flags);
123 |
124 | int proc_terminate(pid_t pid, int *sig);
125 |
126 | __END_DECLS
127 |
128 | #endif /*_LIBPROC_H_ */
129 |
--------------------------------------------------------------------------------
/bootstrap/libproc_private.h:
--------------------------------------------------------------------------------
1 | struct proc_bsdinfo {
2 | uint32_t pbi_flags; /* 64bit; emulated etc */
3 | uint32_t pbi_status;
4 | uint32_t pbi_xstatus;
5 | uint32_t pbi_pid;
6 | uint32_t pbi_ppid;
7 | uid_t pbi_uid;
8 | gid_t pbi_gid;
9 | uid_t pbi_ruid;
10 | gid_t pbi_rgid;
11 | uid_t pbi_svuid;
12 | gid_t pbi_svgid;
13 | uint32_t rfu_1; /* reserved */
14 | char pbi_comm[MAXCOMLEN];
15 | char pbi_name[2 * MAXCOMLEN]; /* empty if no name is registered */
16 | uint32_t pbi_nfiles;
17 | uint32_t pbi_pgid;
18 | uint32_t pbi_pjobc;
19 | uint32_t e_tdev; /* controlling tty dev */
20 | uint32_t e_tpgid; /* tty process group id */
21 | int32_t pbi_nice;
22 | uint64_t pbi_start_tvsec;
23 | uint64_t pbi_start_tvusec;
24 | };
25 |
26 | #define PROC_PIDTBSDINFO 3
27 | #define PROC_PIDTBSDINFO_SIZE (sizeof(struct proc_bsdinfo))
--------------------------------------------------------------------------------
/bootstrap/platformhook.m:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include "common.h"
5 | #include "fishhook.h"
6 | #include "dobby.h"
7 |
8 | bool os_variant_has_internal_content();
9 | bool (*orig_os_variant_has_internal_content)();
10 | bool new_os_variant_has_internal_content()
11 | {
12 | return true;
13 | }
14 |
15 | #define CS_OPS_STATUS 0 /* return status */
16 | #define CS_VALID 0x00000001 /* dynamically valid */
17 | #define CS_PLATFORM_BINARY 0x04000000 /* this is a platform binary */
18 | #define CS_PLATFORM_PATH 0x08000000 /* platform binary by the fact of path (osx only) */
19 | int csops(pid_t pid, uint32_t ops, void* useraddr, user_size_t usersize);
20 | int csops_audittoken(pid_t pid, unsigned int ops, void * useraddr, size_t usersize, audit_token_t * token);
21 | int (*orig_csops_audittoken)(pid_t pid, unsigned int ops, void * useraddr, size_t usersize, audit_token_t * token);
22 | int new_csops_audittoken(pid_t pid, unsigned int ops, void * useraddr, size_t usersize, audit_token_t * token)
23 | {
24 | int ret = orig_csops_audittoken(pid, ops, useraddr, usersize, token);
25 | if(ret==-1) ret = csops(getpid(), ops, useraddr, usersize);
26 |
27 | SYSLOG("csops_audittoken(%d): %d : %d %08X %lx %p", ops, ret, pid, useraddr ? *(uint32_t*)useraddr : 0, usersize, token);
28 |
29 | if(ops==CS_OPS_STATUS) {
30 | *(uint32_t*)useraddr |= CS_VALID;
31 | *(uint32_t*)useraddr |= CS_PLATFORM_BINARY;
32 | *(uint32_t*)useraddr &= ~CS_PLATFORM_PATH;
33 | }
34 |
35 | return ret;
36 | }
37 |
38 | void init_platformHook()
39 | {
40 | SYSLOG("init_platformHook %d", getpid());
41 |
42 | if(requireJIT()!=0) return;
43 |
44 | DobbyHook(csops_audittoken, new_csops_audittoken, (void**)&orig_csops_audittoken);
45 | // DobbyHook(os_variant_has_internal_content, new_os_variant_has_internal_content, (void**)&orig_os_variant_has_internal_content);
46 | }
47 |
48 |
49 | #include
50 | int (*orig__xpc_activate_endpoint)(const char *name, int type, void* handle, uint64_t flags, mach_port_t* p_port, bool* non_launching);
51 | int new__xpc_activate_endpoint(const char *name, int type, void* handle, uint64_t flags, mach_port_t* p_port, bool* p_non_launching)
52 | {
53 | SYSLOG("_xpc_activate_endpoint name=%s type=%d handle=%p flags=%llx", name, type, handle, flags);
54 |
55 | int ret = orig__xpc_activate_endpoint(name, type, handle, flags, p_port, p_non_launching);
56 | SYSLOG("_xpc_activate_endpoint ret=%d port=%x non-launching=%d", ret, *p_port, *p_non_launching);
57 |
58 | if(ret != 0) {
59 | mach_port_t port = MACH_PORT_NULL;
60 | kern_return_t kr = bootstrap_check_in(bootstrap_port, name, &port);
61 | SYSLOG("bootstrap_check_in port=%x kr=%x,%s", port, kr, bootstrap_strerror(kr));
62 | if(kr == KERN_SUCCESS) {
63 | *p_non_launching = false;
64 | *p_port = port;
65 | ret = 0;
66 | }
67 | }
68 |
69 | return ret;
70 | }
71 |
72 | void init_xpchook()
73 | {
74 | SYSLOG("init_xpchook %d", getpid());
75 |
76 | if(requireJIT()!=0) return;
77 |
78 | if(dlopen("/usr/lib/system/libxpc.dylib", RTLD_NOW)==NULL) {
79 | SYSLOG("dlopen libxpc.dylib failed");
80 | return;
81 | }
82 |
83 | void* _xpc_activate_endpoint = DobbySymbolResolver("/usr/lib/system/libxpc.dylib", "__xpc_activate_endpoint");
84 | SYSLOG("_xpc_activate_endpoint=%p", _xpc_activate_endpoint);
85 |
86 | DobbyHook(_xpc_activate_endpoint, (void *)new__xpc_activate_endpoint, (void **)&orig__xpc_activate_endpoint);
87 | }
88 |
--------------------------------------------------------------------------------
/bootstrap/sandbox.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | enum sandbox_filter_type {
4 | SANDBOX_FILTER_NONE,
5 | SANDBOX_FILTER_PATH,
6 | SANDBOX_FILTER_GLOBAL_NAME,
7 | SANDBOX_FILTER_LOCAL_NAME,
8 | SANDBOX_FILTER_APPLEEVENT_DESTINATION,
9 | SANDBOX_FILTER_RIGHT_NAME,
10 | SANDBOX_FILTER_PREFERENCE_DOMAIN,
11 | SANDBOX_FILTER_KEXT_BUNDLE_ID,
12 | SANDBOX_FILTER_INFO_TYPE,
13 | SANDBOX_FILTER_NOTIFICATION,
14 | // ?
15 | // ?
16 | SANDBOX_FILTER_XPC_SERVICE_NAME = 12,
17 | SANDBOX_FILTER_IOKIT_CONNECTION,
18 | // ?
19 | // ?
20 | // ?
21 | // ?
22 | };
23 |
24 | enum sandbox_extension_flags {
25 | FS_EXT_DEFAULTS = 0,
26 | FS_EXT_FOR_PATH = (1 << 0),
27 | FS_EXT_FOR_FILE = (1 << 1),
28 | FS_EXT_READ = (1 << 2),
29 | FS_EXT_WRITE = (1 << 3),
30 | FS_EXT_PREFER_FILEID = (1 << 4),
31 | };
32 |
33 | enum sandbox_extension_types {
34 | EXTENSION_TYPE_FILE,
35 | EXTENSION_TYPE_MACH,
36 | EXTENSION_TYPE_IOKIT_REGISTRY_ENTRY,
37 | EXTENSION_TYPE_GENERIC,
38 | EXTENSION_TYPE_POSIX,
39 | EXTENSION_TYPE_PREFERENCE,
40 | EXTENSION_TYPE_SYSCTL,
41 | EXTENSION_TYPE_MAX /* last */
42 | };
43 |
44 | #define EXTENSION_FLAG_INVALID (1 << 0)
45 | #define EXTENSION_FLAG_CANONICAL (1 << 1)
46 | #define EXTENSION_FLAG_PREFIXMATCH (1 << 2) /* Not for paths. */
47 | #define EXTENSION_FLAG_PATHLITERAL (1 << 3) /* Only for paths. */
48 | #define EXTENSION_FLAG_NO_REPORT (1 << 4)
49 | #define EXTENSION_FLAG_BIND_PID (1 << 16)
50 | #define EXTENSION_FLAG_BIND_PIDVERSION (1 << 17)
51 |
52 | #define MAX_TOKEN_SIZE 2048
53 |
54 | struct syscall_extension_issue_args {
55 | uint64_t extension_class;
56 | uint64_t extension_type;
57 | uint64_t extension_data;
58 | uint64_t extension_flags;
59 | uint64_t extension_token; /* out */
60 | int64_t extension_pid;
61 | int64_t extension_pid_version;
62 | };
63 |
64 | extern const char *APP_SANDBOX_IOKIT_CLIENT;
65 | extern const char *APP_SANDBOX_MACH;
66 | extern const char *APP_SANDBOX_READ;
67 | extern const char *APP_SANDBOX_READ_WRITE;
68 |
69 | extern const char *IOS_SANDBOX_APPLICATION_GROUP;
70 | extern const char *IOS_SANDBOX_CONTAINER;
71 |
72 | extern const enum sandbox_filter_type SANDBOX_CHECK_ALLOW_APPROVAL;
73 | extern const enum sandbox_filter_type SANDBOX_CHECK_CANONICAL;
74 | extern const enum sandbox_filter_type SANDBOX_CHECK_NOFOLLOW;
75 | extern const enum sandbox_filter_type SANDBOX_CHECK_NO_APPROVAL;
76 | extern const enum sandbox_filter_type SANDBOX_CHECK_NO_REPORT;
77 |
78 | extern const uint32_t SANDBOX_EXTENSION_CANONICAL;
79 | extern const uint32_t SANDBOX_EXTENSION_DEFAULT;
80 | extern const uint32_t SANDBOX_EXTENSION_MAGIC;
81 | extern const uint32_t SANDBOX_EXTENSION_NOFOLLOW;
82 | extern const uint32_t SANDBOX_EXTENSION_NO_REPORT;
83 | extern const uint32_t SANDBOX_EXTENSION_NO_STORAGE_CLASS;
84 | extern const uint32_t SANDBOX_EXTENSION_PREFIXMATCH;
85 | extern const uint32_t SANDBOX_EXTENSION_UNRESOLVED;
86 |
87 | int sandbox_init(const char *profile, uint64_t flags, char **errorbuf);
88 | int sandbox_init_with_parameters(const char *profile, uint64_t flags, const char *const parameters[], char **errorbuf);
89 | int sandbox_init_with_extensions(const char *profile, uint64_t flags, const char *const extensions[], char **errorbuf);
90 |
91 | int sandbox_check(pid_t, const char *operation, enum sandbox_filter_type, ...);
92 | int sandbox_check_by_audit_token(audit_token_t, const char *operation, enum sandbox_filter_type, ...);
93 | int sandbox_check_by_uniqueid(uid_t, pid_t, const char *operation, enum sandbox_filter_type, ...);
94 |
95 | int64_t sandbox_extension_consume(const char *extension_token);
96 | char *sandbox_extension_issue_file(const char *extension_class, const char *path, uint32_t flags);
97 | char *sandbox_extension_issue_file_to_process(const char *extension_class, const char *path, uint32_t flags, audit_token_t);
98 | char *sandbox_extension_issue_file_to_process_by_pid(const char *extension_class, const char *path, uint32_t flags, pid_t);
99 | char *sandbox_extension_issue_file_to_self(const char *extension_class, const char *path, uint32_t flags);
100 | char *sandbox_extension_issue_generic(const char *extension_class, uint32_t flags);
101 | char *sandbox_extension_issue_generic_to_process(const char *extension_class, uint32_t flags, audit_token_t);
102 | char *sandbox_extension_issue_generic_to_process_by_pid(const char *extension_class, uint32_t flags, pid_t);
103 | char *sandbox_extension_issue_iokit_registry_entry_class(const char *extension_class, const char *registry_entry_class, uint32_t flags);
104 | char *sandbox_extension_issue_iokit_registry_entry_class_to_process(const char *extension_class, const char *registry_entry_class, uint32_t flags, audit_token_t);
105 | char *sandbox_extension_issue_iokit_registry_entry_class_to_process_by_pid(const char *extension_class, const char *registry_entry_class, uint32_t flags, pid_t);
106 | char *sandbox_extension_issue_iokit_user_client_class(const char *extension_class, const char *registry_entry_class, uint32_t flags);
107 | char *sandbox_extension_issue_mach(const char *extension_class, const char *name, uint32_t flags);
108 | char *sandbox_extension_issue_mach_to_process(const char *extension_class, const char *name, uint32_t flags, audit_token_t);
109 | char *sandbox_extension_issue_mach_to_process_by_pid(const char *extension_class, const char *name, uint32_t flags, pid_t);
110 | char *sandbox_extension_issue_posix_ipc(const char *extension_class, const char *name, uint32_t flags);
111 |
112 | void sandbox_extension_reap(void);
113 | int sandbox_extension_release(int64_t extension_handle);
114 | int sandbox_extension_release_file(int64_t extension_handle, const char *path);
115 | int sandbox_extension_update_file(int64_t extension_handle, const char *path);
116 |
117 | int __sandbox_ms(const char *policyname, int call, void *arg);
--------------------------------------------------------------------------------
/bootstrap/syscall.S:
--------------------------------------------------------------------------------
1 | .text
2 |
3 | .align 4
4 |
5 | .global _ffsys_fork
6 | _ffsys_fork:
7 | #ifdef __arm64e__
8 | pacibsp
9 | #endif
10 | stp x29, x30, [SP, #-0x10]!
11 | mov x29, sp
12 | mov x16, #2
13 | svc 0x80
14 | b.cs _ffsys_fork_err
15 | cbz x1, _ffsys_fork_end
16 | mov w0, #0
17 | adrp x9, __current_pid@GOTPAGE
18 | ldr x9, [x9, __current_pid@GOTPAGEOFF]
19 | str w0, [x9]
20 | b _ffsys_fork_end
21 |
22 | _ffsys_fork_err:
23 | bl _cerror
24 | mov w0, #-1
25 |
26 | _ffsys_fork_end:
27 | mov sp, x29
28 | ldp x29, x30, [SP],#0x10
29 | #ifdef __arm64e__
30 | retab
31 | #else
32 | ret
33 | #endif
34 |
35 | .global _ffsys_getpid
36 | _ffsys_getpid:
37 | mov x16, #20
38 | svc 0x80
39 | ret
40 |
41 | .global _ffsys_read
42 | _ffsys_read:
43 | mov x16, #3
44 | svc 0x80
45 | b.cc _ffsys_read_end
46 | #ifdef __arm64e__
47 | pacibsp
48 | #endif
49 | stp x29, x30, [SP, #-0x10]!
50 | mov x29, sp
51 | bl _cerror
52 | mov sp, x29
53 | ldp x29, x30, [SP],#0x10
54 | #ifdef __arm64e__
55 | retab
56 | #else
57 | ret
58 | #endif
59 |
60 | _ffsys_read_end:
61 | ret
62 |
63 | .global _ffsys_write
64 | _ffsys_write:
65 | mov x16, #4
66 | svc 0x80
67 | b.cc _ffsys_write_end
68 | #ifdef __arm64e__
69 | pacibsp
70 | #endif
71 | stp x29, x30, [SP, #-0x10]!
72 | mov x29, sp
73 | bl _cerror
74 | mov sp, x29
75 | ldp x29, x30, [SP],#0x10
76 | #ifdef __arm64e__
77 | retab
78 | #else
79 | ret
80 | #endif
81 |
82 | _ffsys_write_end:
83 | ret
84 |
85 | .global _ffsys_close
86 | _ffsys_close:
87 | mov x16, #6
88 | svc 0x80
89 | b.cc _ffsys_close_end
90 | #ifdef __arm64e__
91 | pacibsp
92 | #endif
93 | stp x29, x30, [SP, #-0x10]!
94 | mov x29, sp
95 | bl _cerror
96 | mov sp, x29
97 | ldp x29, x30, [SP],#0x10
98 | #ifdef __arm64e__
99 | retab
100 | #else
101 | ret
102 | #endif
103 |
104 | _ffsys_close_end:
105 | ret
106 |
--------------------------------------------------------------------------------
/bootstrapd/.gitignore:
--------------------------------------------------------------------------------
1 | .theos/
2 | packages/
3 | .DS_Store
4 |
--------------------------------------------------------------------------------
/bootstrapd/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "files.associations": {
3 | "ios": "cpp",
4 | "algorithm": "cpp",
5 | "streambuf": "cpp",
6 | "__bit_reference": "cpp",
7 | "__bits": "cpp",
8 | "__config": "cpp",
9 | "__debug": "cpp",
10 | "__errc": "cpp",
11 | "__hash_table": "cpp",
12 | "__locale": "cpp",
13 | "__mutex_base": "cpp",
14 | "__node_handle": "cpp",
15 | "__nullptr": "cpp",
16 | "__split_buffer": "cpp",
17 | "__string": "cpp",
18 | "__threading_support": "cpp",
19 | "__tree": "cpp",
20 | "__tuple": "cpp",
21 | "array": "cpp",
22 | "atomic": "cpp",
23 | "bitset": "cpp",
24 | "cctype": "cpp",
25 | "chrono": "cpp",
26 | "clocale": "cpp",
27 | "cmath": "cpp",
28 | "compare": "cpp",
29 | "complex": "cpp",
30 | "concepts": "cpp",
31 | "cstdarg": "cpp",
32 | "cstddef": "cpp",
33 | "cstdint": "cpp",
34 | "cstdio": "cpp",
35 | "cstdlib": "cpp",
36 | "cstring": "cpp",
37 | "ctime": "cpp",
38 | "cwchar": "cpp",
39 | "cwctype": "cpp",
40 | "deque": "cpp",
41 | "exception": "cpp",
42 | "fstream": "cpp",
43 | "initializer_list": "cpp",
44 | "iomanip": "cpp",
45 | "iosfwd": "cpp",
46 | "iostream": "cpp",
47 | "istream": "cpp",
48 | "limits": "cpp",
49 | "locale": "cpp",
50 | "memory": "cpp",
51 | "mutex": "cpp",
52 | "new": "cpp",
53 | "optional": "cpp",
54 | "ostream": "cpp",
55 | "ratio": "cpp",
56 | "set": "cpp",
57 | "sstream": "cpp",
58 | "stack": "cpp",
59 | "stdexcept": "cpp",
60 | "string": "cpp",
61 | "string_view": "cpp",
62 | "system_error": "cpp",
63 | "tuple": "cpp",
64 | "type_traits": "cpp",
65 | "typeinfo": "cpp",
66 | "unordered_map": "cpp",
67 | "variant": "cpp",
68 | "vector": "cpp",
69 | "filesystem": "cpp",
70 | "types.h": "c"
71 | }
72 | }
--------------------------------------------------------------------------------
/bootstrapd/Makefile:
--------------------------------------------------------------------------------
1 | TARGET := iphone:clang:latest:15.0
2 |
3 | THEOS_PACKAGE_SCHEME = roothide
4 |
5 | FINALPACKAGE ?= 1
6 | DEBUG ?= 0
7 |
8 | include $(THEOS)/makefiles/common.mk
9 |
10 | TOOL_NAME = bootstrapd
11 |
12 | #-fvisibility=hidden
13 |
14 | bootstrapd_FILES = $(wildcard *.c *.m *.mm *.cpp)
15 | bootstrapd_CFLAGS = -DBOOTSTRAPD -I./ -fobjc-arc -Wno-deprecated-declarations -Wno-unused-variable -Wno-unused-function -Wno-unneeded-internal-declaration
16 | bootstrapd_LDFLAGS = -lbsm
17 | bootstrapd_CODESIGN_FLAGS = -Sentitlements.plist
18 | bootstrapd_INSTALL_PATH = /basebin/
19 |
20 | include $(THEOS_MAKE_PATH)/tool.mk
21 |
22 | clean::
23 | rm -rf ./packages/*
24 |
25 | after-install::
26 | install.exec '$(THEOS_PACKAGE_INSTALL_PREFIX)/basebin/$(TOOL_NAME)' server -f
27 |
--------------------------------------------------------------------------------
/bootstrapd/assert.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #define SIGABRT 6
5 | #define OS_REASON_SIGNAL 2
6 | #define OS_REASON_DYLD 6
7 | #define DYLD_EXIT_REASON_OTHER 9
8 |
9 | void abort_with_payload(uint32_t reason_namespace, uint64_t reason_code,
10 | void *payload, uint32_t payload_size,
11 | const char *reason_string, uint64_t reason_flags)
12 | __attribute__((noreturn, cold));
13 |
14 | #define ASSERT(e) (__builtin_expect(!(e), 0) ?\
15 | ((void)fprintf(stderr, "%s:%d: failed ASSERTion `%s'\n", __FILE_NAME__, __LINE__, #e),\
16 | abort_with_payload(OS_REASON_DYLD,DYLD_EXIT_REASON_OTHER,NULL,0, #e, 0)) : (void)0)
17 |
--------------------------------------------------------------------------------
/bootstrapd/bootstrapd.h:
--------------------------------------------------------------------------------
1 |
2 | enum bootstrapReq
3 | {
4 | BSD_REQ_NONE,
5 | BSD_REQ_CHECK_SERVER,
6 | BSD_REQ_STOP_SERVER,
7 | BSD_REQ_GET_SBTOKEN,
8 | BSD_REQ_ENABLE_JIT,
9 | BSD_REQ_ENABLE_JIT2,
10 | BSD_REQ_SSH_CHECK,
11 | BSD_REQ_SSH_START,
12 | BSD_REQ_SSH_STOP,
13 | BSD_REQ_VAR_CLEAN,
14 | BSD_REQ_MAX_REQ
15 | };
16 |
--------------------------------------------------------------------------------
/bootstrapd/common.h:
--------------------------------------------------------------------------------
1 | #pragma GCC diagnostic ignored "-Wformat-invalid-specifier"
2 |
3 | #ifdef BOOTSTRAPD
4 |
5 | #define SYSLOG(...) NSLog(@ __VA_ARGS__)
6 |
7 | #elif DEBUG==1
8 |
9 | #include
10 | extern int ipc_log_enabled;
11 | #define SYSLOG(...) do if(ipc_log_enabled) {\
12 | openlog("bootstrap",LOG_PID,LOG_AUTH);\
13 | syslog(LOG_DEBUG, __VA_ARGS__);closelog();\
14 | } while(0)
15 |
16 | #define printf SYSLOG
17 | #define perror(x) SYSLOG("%s : %s", x, strerror(errno))
18 |
19 | #else
20 |
21 | #define SYSLOG(...)
22 | #define printf(...)
23 |
24 | #endif
25 |
--------------------------------------------------------------------------------
/bootstrapd/control:
--------------------------------------------------------------------------------
1 | Package: com.roothide.bootstrapd
2 | Name: bootstrapd
3 | Version: 0.0.1
4 | Architecture: iphoneos-arm
5 | Description: An awesome tool of some sort!!
6 | Maintainer: roothide
7 | Author: roothide
8 | Section: System
9 | Tag: role::hacker
10 |
--------------------------------------------------------------------------------
/bootstrapd/entitlements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | platform-application
6 |
7 |
8 | get-task-allow
9 |
10 |
11 | com.apple.private.security.container-required
12 |
13 | com.apple.private.security.no-container
14 |
15 | com.apple.private.security.no-sandbox
16 |
17 |
18 | com.apple.private.security.storage.AppBundles
19 |
20 | com.apple.private.security.storage.AppDataContainers
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/bootstrapd/envbuf.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | int envbuf_len(const char *envp[])
5 | {
6 | if (envp == NULL) return 1;
7 |
8 | int k = 0;
9 | const char *env = envp[k++];
10 | while (env != NULL) {
11 | env = envp[k++];
12 | }
13 | return k;
14 | }
15 |
16 | char **envbuf_mutcopy(const char *envp[])
17 | {
18 | if (envp == NULL) return NULL; //opa said don't comment this
19 |
20 | int len = envbuf_len(envp);
21 | char **envcopy = malloc(len * sizeof(char *));
22 |
23 | for (int i = 0; i < len-1; i++) {
24 | envcopy[i] = strdup(envp[i]);
25 | }
26 | envcopy[len-1] = NULL;
27 |
28 | return envcopy;
29 | }
30 |
31 | void envbuf_free(char *envp[])
32 | {
33 | if (envp == NULL) return;
34 |
35 | int len = envbuf_len((const char**)envp);
36 | for (int i = 0; i < len-1; i++) {
37 | free(envp[i]);
38 | }
39 | free(envp);
40 | }
41 |
42 | int envbuf_find(const char *envp[], const char *name)
43 | {
44 | if (envp) {
45 | unsigned long nameLen = strlen(name);
46 | int k = 0;
47 | const char *env = envp[k++];
48 | while (env != NULL) {
49 | unsigned long envLen = strlen(env);
50 | if (envLen > nameLen) {
51 | if (!strncmp(env, name, nameLen)) {
52 | if (env[nameLen] == '=') {
53 | return k-1;
54 | }
55 | }
56 | }
57 | env = envp[k++];
58 | }
59 | }
60 | return -1;
61 | }
62 |
63 | const char *envbuf_getenv(const char *envp[], const char *name)
64 | {
65 | if (envp) {
66 | unsigned long nameLen = strlen(name);
67 | int envIndex = envbuf_find(envp, name);
68 | if (envIndex >= 0) {
69 | return &envp[envIndex][nameLen+1];
70 | }
71 | }
72 | return NULL;
73 | }
74 |
75 | void envbuf_setenv(char **envpp[], const char *name, const char *value, int override)
76 | {
77 | if (envpp) {
78 | char **envp = *envpp;
79 | if (!envp) {
80 | // treat NULL as [NULL]
81 | envp = malloc(sizeof(const char *));
82 | envp[0] = NULL;
83 | }
84 |
85 | char *envToSet = malloc(strlen(name)+strlen(value)+2);
86 | strcpy(envToSet, name);
87 | strcat(envToSet, "=");
88 | strcat(envToSet, value);
89 |
90 | int existingEnvIndex = envbuf_find((const char **)envp, name);
91 | if (existingEnvIndex >= 0) {
92 | if(!override) {
93 | free(envToSet);
94 | return;
95 | }
96 | // if already exists: deallocate old variable, then replace pointer
97 | free(envp[existingEnvIndex]);
98 | envp[existingEnvIndex] = envToSet;
99 | }
100 | else {
101 | // if doesn't exist yet: increase env buffer size, place at end
102 | int prevLen = envbuf_len((const char **)envp);
103 | *envpp = realloc(envp, (prevLen+1)*sizeof(const char *));
104 | envp = *envpp;
105 | envp[prevLen-1] = envToSet;
106 | envp[prevLen] = NULL;
107 | }
108 | }
109 | }
110 |
111 | void envbuf_unsetenv(char **envpp[], const char *name)
112 | {
113 | if (envpp) {
114 | char **envp = *envpp;
115 | if (!envp) return;
116 |
117 | int existingEnvIndex = envbuf_find((const char **)envp, name);
118 | if (existingEnvIndex >= 0) {
119 | free(envp[existingEnvIndex]);
120 | int prevLen = envbuf_len((const char **)envp);
121 | for (int i = existingEnvIndex; i < (prevLen-1); i++) {
122 | envp[i] = envp[i+1];
123 | }
124 | *envpp = realloc(envp, (prevLen-1)*sizeof(const char *));
125 | }
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/bootstrapd/envbuf.h:
--------------------------------------------------------------------------------
1 | int envbuf_len(const char *envp[]);
2 | char **envbuf_mutcopy(const char *envp[]);
3 | void envbuf_free(char *envp[]);
4 | int envbuf_find(const char *envp[], const char *name);
5 | const char *envbuf_getenv(const char *envp[], const char *name);
6 | void envbuf_setenv(char **envpp[], const char *name, const char *value, int overwrite);
7 | void envbuf_unsetenv(char **envpp[], const char *name);
--------------------------------------------------------------------------------
/bootstrapd/ipc.h:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | int connect_to_server();
4 |
5 | int run_ipc_server(int (*callback)(int socket, pid_t pid, int reqId, NSDictionary* msg));
6 | int set_stop_server();
7 |
8 | int request(int socket, int reqId, NSDictionary* msg);
9 | int reply(int socket, NSDictionary* msg);
10 | NSDictionary* reponse(int socket);
11 |
--------------------------------------------------------------------------------
/bootstrapd/jiter.m:
--------------------------------------------------------------------------------
1 |
2 | #include
3 | #include
4 | #include
5 | #include "common.h"
6 | #include "libproc.h"
7 | #include "libproc_private.h"
8 |
9 |
10 | /* Status values. */
11 | #define SIDL 1 /* Process being created by fork. */
12 | #define SRUN 2 /* Currently runnable. */
13 | #define SSLEEP 3 /* Sleeping on an address. */
14 | #define SSTOP 4 /* Process debugging or suspension. */
15 | #define SZOMB 5 /* Awaiting collection by parent. */
16 |
17 | int proc_paused(pid_t pid, bool* paused)
18 | {
19 | *paused = false;
20 |
21 | struct proc_bsdinfo procInfo={0};
22 | int ret = proc_pidinfo(pid, PROC_PIDTBSDINFO, 0, &procInfo, sizeof(procInfo));
23 | if(ret != sizeof(procInfo)) {
24 | SYSLOG("bsdinfo failed, %d,%s\n", errno, strerror(errno));
25 | return -1;
26 | }
27 |
28 | if(procInfo.pbi_status == SSTOP)
29 | {
30 | SYSLOG("%d pstat=%x flag=%x xstat=%x\n", ret, procInfo.pbi_status, procInfo.pbi_flags, procInfo.pbi_xstatus);
31 | *paused = true;
32 | }
33 | else if(procInfo.pbi_status != SRUN) {
34 | SYSLOG("unexcept %d pstat=%x\n", ret, procInfo.pbi_status);
35 | return -1;
36 | }
37 |
38 | return 0;
39 | }
40 |
41 |
42 | #define PT_DETACH 11 /* stop tracing a process */
43 | #define PT_ATTACHEXC 14 /* attach to running process with signal exception */
44 | int ptrace(int _request, pid_t _pid, caddr_t _addr, int _data);
45 |
46 | #include
47 |
48 | int enableJIT(pid_t pid)
49 | {
50 | int ret = ptrace(PT_ATTACHEXC, pid, NULL, 0);
51 | SYSLOG("attach=%d", ret);
52 | if(ret != 0) return ret;
53 |
54 | //don't SIGCONT here, otherwise kernel may send exception msg to this process and the traced process keep waiting, kill(pid, SIGCONT);
55 |
56 | bool paused=false;
57 | for(int i=0; i<1000*50; i++)
58 | {
59 | ret = proc_paused(pid, &paused);
60 | SYSLOG("paused=%d, %d", ret, paused);
61 |
62 | if(ret != 0) return ret;
63 |
64 | if(paused) break;
65 |
66 | usleep(10);
67 | }
68 |
69 | if(!paused) {
70 | SYSLOG("*** ptrace: wait process timeout");
71 | }
72 |
73 | ret = ptrace(PT_DETACH, pid, NULL, 0);
74 | SYSLOG("detach=%d, %s", ret, ret==0?"":strerror(errno));
75 |
76 | return ret;
77 | }
78 |
--------------------------------------------------------------------------------
/bootstrapd/libbsd.h:
--------------------------------------------------------------------------------
1 |
2 | int bsd_enableJIT();
3 | int bsd_enableJIT2(pid_t pid);
4 |
5 | const char* bsd_getsbtoken();
6 |
7 | int bsd_opensshcheck();
8 | int bsd_opensshctl(bool run);
9 |
10 | int bsd_checkServer();
11 | int bsd_stopServer();
12 |
13 | int bsd_varClean();
14 |
--------------------------------------------------------------------------------
/bootstrapd/libbsd.m:
--------------------------------------------------------------------------------
1 |
2 | #include "../bootstrapd/ipc.h"
3 | #include "../bootstrapd/bootstrapd.h"
4 | #include "../bootstrapd/common.h"
5 |
6 | int bsd_enableJIT()
7 | {
8 | int result=-1;
9 |
10 | int sd = connect_to_server();
11 | if(sd <= 0) return -1;
12 | int req = request(sd, BSD_REQ_ENABLE_JIT, nil);
13 | SYSLOG("request=%d", req);
14 | if(req == 0) {
15 | NSDictionary* rep = reponse(sd);
16 | SYSLOG("reponse=%@", rep);
17 | NSNumber* resultObj = rep[@"result"];
18 | if(resultObj) result = resultObj.intValue;
19 | }
20 | close(sd);
21 |
22 | return result;
23 | }
24 |
25 | extern int ipc_log_enabled;
26 | int bsd_enableJIT2(pid_t pid)
27 | {
28 | ipc_log_enabled=0;
29 |
30 | int result=-1;
31 |
32 | int sd = connect_to_server();
33 | if(sd <= 0) return -1;
34 | int req = request(sd, BSD_REQ_ENABLE_JIT2, @{@"pid":@(pid)});
35 | SYSLOG("request=%d", req);
36 | if(req == 0) {
37 | NSDictionary* rep = reponse(sd);
38 | SYSLOG("reponse=%@", rep);
39 | NSNumber* resultObj = rep[@"result"];
40 | if(resultObj) result = resultObj.intValue;
41 | }
42 | close(sd);
43 |
44 | ipc_log_enabled=1;
45 |
46 | return result;
47 | }
48 |
49 | const char* bsd_getsbtoken()
50 | {
51 | const char* result=nil;
52 |
53 | int sd = connect_to_server();
54 | if(sd <= 0) return NULL;
55 | int req = request(sd, BSD_REQ_GET_SBTOKEN, nil);
56 | SYSLOG("request=%d", req);
57 | if(req == 0) {
58 | NSDictionary* rep = reponse(sd);
59 | result = [rep[@"sbtoken"] UTF8String];
60 | SYSLOG("reponse=%@", rep);
61 | }
62 | close(sd);
63 |
64 | return result;
65 | }
66 |
67 | int bsd_opensshctl(bool run)
68 | {
69 | int result = -1;
70 |
71 | int sd = connect_to_server();
72 | if(sd <= 0) return -1;
73 | int req = request(sd, run ? BSD_REQ_SSH_START : BSD_REQ_SSH_STOP, nil);
74 | SYSLOG("request=%d", req);
75 | if(req == 0) {
76 | NSDictionary* rep = reponse(sd);
77 | SYSLOG("reponse=%@", rep);
78 | NSNumber* resultObj = rep[@"result"];
79 | if(resultObj) result = resultObj.intValue;
80 | }
81 | close(sd);
82 |
83 | return result;
84 | }
85 |
86 | int bsd_opensshcheck()
87 | {
88 | int result = -1;
89 |
90 | int sd = connect_to_server();
91 | if(sd <= 0) return -1;
92 | int req = request(sd, BSD_REQ_SSH_CHECK, nil);
93 | SYSLOG("request=%d", req);
94 | if(req == 0) {
95 | NSDictionary* rep = reponse(sd);
96 | SYSLOG("reponse=%@", rep);
97 | NSNumber* resultObj = rep[@"result"];
98 | if(resultObj) result = resultObj.intValue;
99 | }
100 | close(sd);
101 |
102 | return result;
103 | }
104 |
105 | int bsd_stopServer()
106 | {
107 | int result = -1;
108 |
109 | int sd = connect_to_server();
110 | if(sd <= 0) return -1;
111 | int req = request(sd, BSD_REQ_STOP_SERVER, nil);
112 | SYSLOG("request=%d", req);
113 | if(req == 0) {
114 | NSDictionary* rep = reponse(sd);
115 | SYSLOG("reponse=%@", rep);
116 | NSNumber* resultObj = rep[@"result"];
117 | if(resultObj) result = resultObj.intValue;
118 | }
119 | close(sd);
120 |
121 | return result;
122 | }
123 |
124 | int bsd_checkServer()
125 | {
126 | int result = -1;
127 |
128 | int sd = connect_to_server();
129 | if(sd <= 0) return -1;
130 | int req = request(sd, BSD_REQ_CHECK_SERVER, nil);
131 | SYSLOG("request=%d", req);
132 | if(req == 0) {
133 | NSDictionary* rep = reponse(sd);
134 | SYSLOG("reponse=%@", rep);
135 | NSNumber* resultObj = rep[@"result"];
136 | if(resultObj) result = resultObj.intValue;
137 | }
138 | close(sd);
139 |
140 | return result;
141 | }
142 |
143 | int bsd_varClean()
144 | {
145 | int result = -1;
146 |
147 | int sd = connect_to_server();
148 | if(sd <= 0) return -1;
149 | int req = request(sd, BSD_REQ_VAR_CLEAN, @{@"bundleIdentifier":NSBundle.mainBundle.bundleIdentifier});
150 | SYSLOG("request=%d", req);
151 | if(req == 0) {
152 | NSDictionary* rep = reponse(sd);
153 | SYSLOG("reponse=%@", rep);
154 | NSNumber* resultObj = rep[@"result"];
155 | if(resultObj) result = resultObj.intValue;
156 | }
157 | close(sd);
158 |
159 | return result;
160 | }
161 |
--------------------------------------------------------------------------------
/bootstrapd/libproc.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2006, 2007, 2010 Apple Inc. All rights reserved.
3 | *
4 | * @APPLE_LICENSE_HEADER_START@
5 | *
6 | * This file contains Original Code and/or Modifications of Original Code
7 | * as defined in and that are subject to the Apple Public Source License
8 | * Version 2.0 (the 'License'). You may not use this file except in
9 | * compliance with the License. Please obtain a copy of the License at
10 | * http://www.opensource.apple.com/apsl/ and read it before using this
11 | * file.
12 | *
13 | * The Original Code and all software distributed under the License are
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 | * Please see the License for the specific language governing rights and
19 | * limitations under the License.
20 | *
21 | * @APPLE_LICENSE_HEADER_END@
22 | */
23 | #ifndef _LIBPROC_H_
24 | #define _LIBPROC_H_
25 |
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 |
35 | #include
36 |
37 | /*
38 | * This header file contains private interfaces to obtain process information.
39 | * These interfaces are subject to change in future releases.
40 | */
41 |
42 | /*!
43 | @define PROC_LISTPIDSPATH_PATH_IS_VOLUME
44 | @discussion This flag indicates that all processes that hold open
45 | file references on the volume associated with the specified
46 | path should be returned.
47 | */
48 | #define PROC_LISTPIDSPATH_PATH_IS_VOLUME 1
49 |
50 |
51 | /*!
52 | @define PROC_LISTPIDSPATH_EXCLUDE_EVTONLY
53 | @discussion This flag indicates that file references that were opened
54 | with the O_EVTONLY flag should be excluded from the matching
55 | criteria.
56 | */
57 | #define PROC_LISTPIDSPATH_EXCLUDE_EVTONLY 2
58 |
59 | __BEGIN_DECLS
60 |
61 |
62 | /*!
63 | @function proc_listpidspath
64 | @discussion A function which will search through the current
65 | processes looking for open file references which match
66 | a specified path or volume.
67 | @param type types of processes to be searched (see proc_listpids)
68 | @param typeinfo adjunct information for type
69 | @param path file or volume path
70 | @param pathflags flags to control which files should be considered
71 | during the process search.
72 | @param buffer a C array of int-sized values to be filled with
73 | process identifiers that hold an open file reference
74 | matching the specified path or volume. Pass NULL to
75 | obtain the minimum buffer size needed to hold the
76 | currently active processes.
77 | @param buffersize the size (in bytes) of the provided buffer.
78 | @result the number of bytes of data returned in the provided buffer;
79 | -1 if an error was encountered;
80 | */
81 | int proc_listpidspath(uint32_t type,
82 | uint32_t typeinfo,
83 | const char *path,
84 | uint32_t pathflags,
85 | void *buffer,
86 | int buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
87 |
88 | int proc_listpids(uint32_t type, uint32_t typeinfo, void *buffer, int buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
89 | int proc_listallpids(void * buffer, int buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_1);
90 | int proc_listpgrppids(pid_t pgrpid, void * buffer, int buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_1);
91 | int proc_listchildpids(pid_t ppid, void * buffer, int buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_1);
92 | int proc_pidinfo(int pid, int flavor, uint64_t arg, void *buffer, int buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
93 | int proc_pidfdinfo(int pid, int fd, int flavor, void * buffer, int buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
94 | int proc_pidfileportinfo(int pid, uint32_t fileport, int flavor, void *buffer, int buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
95 | int proc_name(int pid, void * buffer, uint32_t buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
96 | int proc_regionfilename(int pid, uint64_t address, void * buffer, uint32_t buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
97 | int proc_kmsgbuf(void * buffer, uint32_t buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
98 | int proc_pidpath(int pid, void * buffer, uint32_t buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
99 | int proc_libversion(int *major, int * minor) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
100 |
101 | /*
102 | * Return resource usage information for the given pid, which can be a live process or a zombie.
103 | *
104 | * Returns 0 on success; or -1 on failure, with errno set to indicate the specific error.
105 | */
106 | int proc_pid_rusage(int pid, int flavor, rusage_info_t *buffer) __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0);
107 |
108 | /*
109 | * A process can use the following api to set its own process control
110 | * state on resoure starvation. The argument can have one of the PROC_SETPC_XX values
111 | */
112 | #define PROC_SETPC_NONE 0
113 | #define PROC_SETPC_THROTTLEMEM 1
114 | #define PROC_SETPC_SUSPEND 2
115 | #define PROC_SETPC_TERMINATE 3
116 |
117 | int proc_setpcontrol(const int control) __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2);
118 | int proc_setpcontrol(const int control);
119 |
120 | int proc_track_dirty(pid_t pid, uint32_t flags);
121 | int proc_set_dirty(pid_t pid, bool dirty);
122 | int proc_get_dirty(pid_t pid, uint32_t *flags);
123 |
124 | int proc_terminate(pid_t pid, int *sig);
125 |
126 | __END_DECLS
127 |
128 | #endif /*_LIBPROC_H_ */
129 |
--------------------------------------------------------------------------------
/bootstrapd/libproc_private.h:
--------------------------------------------------------------------------------
1 | struct proc_bsdinfo {
2 | uint32_t pbi_flags; /* 64bit; emulated etc */
3 | uint32_t pbi_status;
4 | uint32_t pbi_xstatus;
5 | uint32_t pbi_pid;
6 | uint32_t pbi_ppid;
7 | uid_t pbi_uid;
8 | gid_t pbi_gid;
9 | uid_t pbi_ruid;
10 | gid_t pbi_rgid;
11 | uid_t pbi_svuid;
12 | gid_t pbi_svgid;
13 | uint32_t rfu_1; /* reserved */
14 | char pbi_comm[MAXCOMLEN];
15 | char pbi_name[2 * MAXCOMLEN]; /* empty if no name is registered */
16 | uint32_t pbi_nfiles;
17 | uint32_t pbi_pgid;
18 | uint32_t pbi_pjobc;
19 | uint32_t e_tdev; /* controlling tty dev */
20 | uint32_t e_tpgid; /* tty process group id */
21 | int32_t pbi_nice;
22 | uint64_t pbi_start_tvsec;
23 | uint64_t pbi_start_tvusec;
24 | };
25 |
26 | #define PROC_PIDTBSDINFO 3
27 | #define PROC_PIDTBSDINFO_SIZE (sizeof(struct proc_bsdinfo))
--------------------------------------------------------------------------------
/bootstrapd/usreboot.m:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 |
12 | #include
13 | #undef CFSTR
14 | #define CFSTR(x) @ x
15 | #undef xpc_release
16 | #define xpc_release(x) //error: ARC forbids explicit message send of 'release'
17 |
18 |
19 | int userspaceReboot(void)
20 | {
21 | kern_return_t ret = 0;
22 | xpc_object_t xdict = xpc_dictionary_create(NULL, NULL, 0);
23 | xpc_dictionary_set_uint64(xdict, "cmd", 5);
24 | ret = unlink("/private/var/mobile/Library/MemoryMaintenance/mmaintenanced");
25 | if (ret && errno != ENOENT) {
26 | NSLog(CFSTR("could not delete mmaintenanced last reboot file"));
27 | return -1;
28 | }
29 | xpc_connection_t connection = xpc_connection_create_mach_service("com.apple.mmaintenanced", NULL, 0);
30 |
31 | if (xpc_get_type(connection) == XPC_TYPE_ERROR) {
32 | char* desc = xpc_copy_description(connection);
33 | NSLog(CFSTR("%s"),desc);
34 | free(desc);
35 | xpc_release(connection);
36 | return -1;
37 | }
38 | xpc_connection_set_event_handler(connection, ^(xpc_object_t random) {});
39 | xpc_connection_activate(connection);
40 | char* desc = xpc_copy_description(connection);
41 | puts(desc);
42 | NSLog(CFSTR("mmaintenanced connection created"));
43 | xpc_object_t reply = xpc_connection_send_message_with_reply_sync(connection, xdict);
44 | if (reply) {
45 | char* desc = xpc_copy_description(reply);
46 | NSLog(CFSTR("%s"),desc);
47 | free(desc);
48 | ret = 0;
49 | } else {
50 | NSLog(CFSTR("no reply received from mmaintenanced"));
51 | ret = -1;
52 | }
53 |
54 |
55 | xpc_connection_cancel(connection);
56 | xpc_release(connection);
57 | xpc_release(reply);
58 | xpc_release(xdict);
59 | return ret;
60 | }
--------------------------------------------------------------------------------
/bootstrapd/varClean.m:
--------------------------------------------------------------------------------
1 |
2 | #include
3 | #include
4 |
5 | char* varCleanPatterns[][4] = {
6 | {"","Library/Preferences",".plist",(char*)true},
7 | {"","Library/SplashBoard/Snapshots","",(char*)true},
8 | {"","Library/Saved Application State",".savedState",(char*)true},
9 |
10 | {"","Library/Caches","",(char*)false},
11 | {"","Library/WebKit","",(char*)false},
12 | {"","Library/Cookies",".binarycookies",(char*)false},
13 | {"","Library/HTTPStorages","",(char*)false},
14 | {"","Library/Application Support/Containers","",(char*)false},
15 | };
16 |
17 | dispatch_queue_t varCleanQueue = nil;
18 | NSMutableDictionary* varCleanDict = nil;
19 |
20 | void doVarClean(const char* bundleIdentifier, bool all)
21 | {
22 | //if the user has enabled URLSchemes, this means the user does not need to hide the "jailbreak"
23 | if(access(jbroot("/var/mobile/.allow_url_schemes"), F_OK)==0) {
24 | return;
25 | }
26 |
27 | NSLog(@"varClean: doVarClean(%d) %s", all, bundleIdentifier);
28 |
29 | for(int i=0; i
5 |
6 | // Certain parts of the project use all the project's headers but have to build
7 | // against newer OSX SDKs than ebuild uses -- liblaunch_host being the example.
8 | // So we need to define these.
9 | #ifndef __MAC_10_13
10 | #define __MAC_10_13 101300
11 | #define __AVAILABILITY_INTERNAL__MAC_10_13 \
12 | __attribute__((availability(macosx, introduced=10.13)))
13 | #endif // __MAC_10_13
14 |
15 | #ifndef __MAC_10_12
16 | #define __MAC_10_12 101200
17 | #define __AVAILABILITY_INTERNAL__MAC_10_12 \
18 | __attribute__((availability(macosx, introduced=10.12)))
19 | #endif // __MAC_10_12
20 |
21 | #ifndef __MAC_10_11
22 | #define __MAC_10_11 101100
23 | #define __AVAILABILITY_INTERNAL__MAC_10_11 \
24 | __attribute__((availability(macosx, introduced=10.11)))
25 | #endif // __MAC_10_11
26 |
27 | #ifndef __AVAILABILITY_INTERNAL__MAC_10_2_DEP__MAC_10_11
28 | #define __AVAILABILITY_INTERNAL__MAC_10_2_DEP__MAC_10_11
29 | #endif // __AVAILABILITY_INTERNAL__MAC_10_2_DEP__MAC_10_11
30 |
31 | #ifndef __AVAILABILITY_INTERNAL__MAC_10_3_DEP__MAC_10_11
32 | #define __AVAILABILITY_INTERNAL__MAC_10_3_DEP__MAC_10_11
33 | #endif // __AVAILABILITY_INTERNAL__MAC_10_3_DEP__MAC_10_11
34 |
35 | #ifndef __AVAILABILITY_INTERNAL__MAC_10_4_DEP__MAC_10_11
36 | #define __AVAILABILITY_INTERNAL__MAC_10_4_DEP__MAC_10_11
37 | #endif // __AVAILABILITY_INTERNAL__MAC_10_4_DEP__MAC_10_11
38 |
39 | #ifndef __AVAILABILITY_INTERNAL__MAC_10_5_DEP__MAC_10_11
40 | #define __AVAILABILITY_INTERNAL__MAC_10_5_DEP__MAC_10_11
41 | #endif // __AVAILABILITY_INTERNAL__MAC_10_5_DEP__MAC_10_11
42 |
43 | #ifndef __AVAILABILITY_INTERNAL__MAC_10_6_DEP__MAC_10_11
44 | #define __AVAILABILITY_INTERNAL__MAC_10_6_DEP__MAC_10_11
45 | #endif // __AVAILABILITY_INTERNAL__MAC_10_6_DEP__MAC_10_11
46 |
47 | #ifndef __AVAILABILITY_INTERNAL__MAC_10_7_DEP__MAC_10_11
48 | #define __AVAILABILITY_INTERNAL__MAC_10_7_DEP__MAC_10_11
49 | #endif // __AVAILABILITY_INTERNAL__MAC_10_7_DEP__MAC_10_11
50 |
51 | #ifndef __AVAILABILITY_INTERNAL__MAC_10_8_DEP__MAC_10_11
52 | #define __AVAILABILITY_INTERNAL__MAC_10_8_DEP__MAC_10_11
53 | #endif // __AVAILABILITY_INTERNAL__MAC_10_8_DEP__MAC_10_11
54 |
55 | #ifndef __AVAILABILITY_INTERNAL__MAC_10_9_DEP__MAC_10_11
56 | #define __AVAILABILITY_INTERNAL__MAC_10_9_DEP__MAC_10_11
57 | #endif // __AVAILABILITY_INTERNAL__MAC_10_9_DEP__MAC_10_11
58 |
59 | #ifndef __AVAILABILITY_INTERNAL__MAC_10_10_DEP__MAC_10_11
60 | #define __AVAILABILITY_INTERNAL__MAC_10_10_DEP__MAC_10_11
61 | #endif // __AVAILABILITY_INTERNAL__MAC_10_10_DEP__MAC_10_11
62 |
63 | #ifndef __AVAILABILITY_INTERNAL__MAC_10_11_DEP__MAC_10_11
64 | #define __AVAILABILITY_INTERNAL__MAC_10_11_DEP__MAC_10_11
65 | #endif // __AVAILABILITY_INTERNAL__MAC_10_11_DEP__MAC_10_11
66 |
67 | #ifndef __AVAILABILITY_INTERNAL__MAC_10_6_DEP__MAC_10_13
68 | #define __AVAILABILITY_INTERNAL__MAC_10_6_DEP__MAC_10_13
69 | #endif // __AVAILABILITY_INTERNAL__MAC_10_6_DEP__MAC_10_13
70 |
71 | #if __has_include()
72 | #include
73 | #else // __has_include()
74 | #ifndef IPHONE_SIMULATOR_HOST_MIN_VERSION_REQUIRED
75 | #define IPHONE_SIMULATOR_HOST_MIN_VERSION_REQUIRED 999999
76 | #endif // IPHONE_SIMULATOR_HOST_MIN_VERSION_REQUIRED
77 | #endif // __has_include()
78 |
79 | #ifndef __WATCHOS_UNAVAILABLE
80 | #define __WATCHOS_UNAVAILABLE
81 | #endif
82 |
83 | #ifndef __TVOS_UNAVAILABLE
84 | #define __TVOS_UNAVAILABLE
85 | #endif
86 |
87 | // simulator host-side bits build against SDKs not having __*_AVAILABLE() yet
88 | #ifndef __OSX_AVAILABLE
89 | #define __OSX_AVAILABLE(...)
90 | #endif
91 |
92 | #ifndef __IOS_AVAILABLE
93 | #define __IOS_AVAILABLE(...)
94 | #endif
95 |
96 | #ifndef __TVOS_AVAILABLE
97 | #define __TVOS_AVAILABLE(...)
98 | #endif
99 |
100 | #ifndef __WATCHOS_AVAILABLE
101 | #define __WATCHOS_AVAILABLE(...)
102 | #endif
103 |
104 | #ifndef __API_AVAILABLE
105 | #define __API_AVAILABLE(...)
106 | #endif
107 |
108 | #endif // __XPC_AVAILABILITY_H__
109 |
--------------------------------------------------------------------------------
/bootstrapd/xpc/base.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2009-2011 Apple Inc. All rights reserved.
2 |
3 | #ifndef __XPC_BASE_H__
4 | #define __XPC_BASE_H__
5 |
6 | #include
7 |
8 | __BEGIN_DECLS
9 |
10 | #if !defined(__has_include)
11 | #define __has_include(x) 0
12 | #endif // !defined(__has_include)
13 |
14 | #if !defined(__has_attribute)
15 | #define __has_attribute(x) 0
16 | #endif // !defined(__has_attribute)
17 |
18 | #if !defined(__has_feature)
19 | #define __has_feature(x) 0
20 | #endif // !defined(__has_feature)
21 |
22 | #if !defined(__has_extension)
23 | #define __has_extension(x) 0
24 | #endif // !defined(__has_extension)
25 |
26 | #if __has_include()
27 | #include
28 | #else // __has_include()
29 | #include
30 | #endif // __has_include()
31 |
32 | #if XPC_SERVICE_MAIN_IN_LIBXPC
33 | #define XPC_HOSTING_OLD_MAIN 1
34 | #else // XPC_SERVICE_MAIN_IN_LIBXPC
35 | #define XPC_HOSTING_OLD_MAIN 0
36 | #endif // XPC_SERVICE_MAIN_IN_LIBXPC
37 |
38 | #ifndef __XPC_INDIRECT__
39 | #error "Please #include instead of this file directly."
40 | #endif // __XPC_INDIRECT__
41 |
42 | #pragma mark Attribute Shims
43 | #ifdef __GNUC__
44 | #define XPC_CONSTRUCTOR __attribute__((constructor))
45 | #define XPC_NORETURN __attribute__((__noreturn__))
46 | #define XPC_NOTHROW __attribute__((__nothrow__))
47 | #define XPC_NONNULL1 __attribute__((__nonnull__(1)))
48 | #define XPC_NONNULL2 __attribute__((__nonnull__(2)))
49 | #define XPC_NONNULL3 __attribute__((__nonnull__(3)))
50 | #define XPC_NONNULL4 __attribute__((__nonnull__(4)))
51 | #define XPC_NONNULL5 __attribute__((__nonnull__(5)))
52 | #define XPC_NONNULL6 __attribute__((__nonnull__(6)))
53 | #define XPC_NONNULL7 __attribute__((__nonnull__(7)))
54 | #define XPC_NONNULL8 __attribute__((__nonnull__(8)))
55 | #define XPC_NONNULL9 __attribute__((__nonnull__(9)))
56 | #define XPC_NONNULL10 __attribute__((__nonnull__(10)))
57 | #define XPC_NONNULL11 __attribute__((__nonnull__(11)))
58 | #define XPC_NONNULL_ALL __attribute__((__nonnull__))
59 | #define XPC_SENTINEL __attribute__((__sentinel__))
60 | #define XPC_PURE __attribute__((__pure__))
61 | #define XPC_WARN_RESULT __attribute__((__warn_unused_result__))
62 | #define XPC_MALLOC __attribute__((__malloc__))
63 | #define XPC_UNUSED __attribute__((__unused__))
64 | #define XPC_USED __attribute__((__used__))
65 | #define XPC_PACKED __attribute__((__packed__))
66 | #define XPC_PRINTF(m, n) __attribute__((format(printf, m, n)))
67 | #define XPC_INLINE static __inline__ __attribute__((__always_inline__))
68 | #define XPC_NOINLINE __attribute__((noinline))
69 | #define XPC_NOIMPL __attribute__((unavailable))
70 |
71 | #if __has_attribute(noescape)
72 | #define XPC_NOESCAPE __attribute__((__noescape__))
73 | #else
74 | #define XPC_NOESCAPE
75 | #endif
76 |
77 | #if __has_extension(attribute_unavailable_with_message)
78 | #define XPC_UNAVAILABLE(m) __attribute__((unavailable(m)))
79 | #else // __has_extension(attribute_unavailable_with_message)
80 | #define XPC_UNAVAILABLE(m) XPC_NOIMPL
81 | #endif // __has_extension(attribute_unavailable_with_message)
82 |
83 | #define XPC_EXPORT extern __attribute__((visibility("default")))
84 | #define XPC_NOEXPORT __attribute__((visibility("hidden")))
85 | #define XPC_WEAKIMPORT extern __attribute__((weak_import))
86 | #define XPC_DEBUGGER_EXCL XPC_NOEXPORT XPC_USED
87 | #define XPC_TRANSPARENT_UNION __attribute__((transparent_union))
88 | #if __clang__
89 | #define XPC_DEPRECATED(m) __attribute__((deprecated(m)))
90 | #else // __clang__
91 | #define XPC_DEPRECATED(m) __attribute__((deprecated))
92 | #endif // __clang
93 |
94 | #if __XPC_TEST__
95 | #define XPC_TESTSTATIC
96 | #else // __XPC_TEST__
97 | #define XPC_TESTSTATIC static
98 | #endif // __XPC_TEST__
99 |
100 | #if __has_feature(objc_arc)
101 | #define XPC_GIVES_REFERENCE __strong
102 | #define XPC_UNRETAINED __unsafe_unretained
103 | #define XPC_BRIDGE(xo) ((__bridge void *)(xo))
104 | #define XPC_BRIDGEREF_BEGIN(xo) ((__bridge_retained void *)(xo))
105 | #define XPC_BRIDGEREF_BEGIN_WITH_REF(xo) ((__bridge void *)(xo))
106 | #define XPC_BRIDGEREF_MIDDLE(xo) ((__bridge id)(xo))
107 | #define XPC_BRIDGEREF_END(xo) ((__bridge_transfer id)(xo))
108 | #else // __has_feature(objc_arc)
109 | #define XPC_GIVES_REFERENCE
110 | #define XPC_UNRETAINED
111 | #define XPC_BRIDGE(xo) (xo)
112 | #define XPC_BRIDGEREF_BEGIN(xo) (xo)
113 | #define XPC_BRIDGEREF_BEGIN_WITH_REF(xo) (xo)
114 | #define XPC_BRIDGEREF_MIDDLE(xo) (xo)
115 | #define XPC_BRIDGEREF_END(xo) (xo)
116 | #endif // __has_feature(objc_arc)
117 |
118 | #define _xpc_unreachable() __builtin_unreachable()
119 | #else // __GNUC__
120 | /*! @parseOnly */
121 | #define XPC_CONSTRUCTOR
122 | /*! @parseOnly */
123 | #define XPC_NORETURN
124 | /*! @parseOnly */
125 | #define XPC_NOTHROW
126 | /*! @parseOnly */
127 | #define XPC_NONNULL1
128 | /*! @parseOnly */
129 | #define XPC_NONNULL2
130 | /*! @parseOnly */
131 | #define XPC_NONNULL3
132 | /*! @parseOnly */
133 | #define XPC_NONNULL4
134 | /*! @parseOnly */
135 | #define XPC_NONNULL5
136 | /*! @parseOnly */
137 | #define XPC_NONNULL6
138 | /*! @parseOnly */
139 | #define XPC_NONNULL7
140 | /*! @parseOnly */
141 | #define XPC_NONNULL8
142 | /*! @parseOnly */
143 | #define XPC_NONNULL9
144 | /*! @parseOnly */
145 | #define XPC_NONNULL10
146 | /*! @parseOnly */
147 | #define XPC_NONNULL11
148 | /*! @parseOnly */
149 | #define XPC_NONNULL(n)
150 | /*! @parseOnly */
151 | #define XPC_NONNULL_ALL
152 | /*! @parseOnly */
153 | #define XPC_SENTINEL
154 | /*! @parseOnly */
155 | #define XPC_PURE
156 | /*! @parseOnly */
157 | #define XPC_WARN_RESULT
158 | /*! @parseOnly */
159 | #define XPC_MALLOC
160 | /*! @parseOnly */
161 | #define XPC_UNUSED
162 | /*! @parseOnly */
163 | #define XPC_PACKED
164 | /*! @parseOnly */
165 | #define XPC_PRINTF(m, n)
166 | /*! @parseOnly */
167 | #define XPC_INLINE static inline
168 | /*! @parseOnly */
169 | #define XPC_NOINLINE
170 | /*! @parseOnly */
171 | #define XPC_NOIMPL
172 | /*! @parseOnly */
173 | #define XPC_EXPORT extern
174 | /*! @parseOnly */
175 | #define XPC_WEAKIMPORT
176 | /*! @parseOnly */
177 | #define XPC_DEPRECATED
178 | /*! @parseOnly */
179 | #define XPC_UNAVAILABLE(m)
180 | /*! @parseOnly */
181 | #define XPC_NOESCAPE
182 | #endif // __GNUC__
183 |
184 | #if __has_feature(assume_nonnull)
185 | #define XPC_ASSUME_NONNULL_BEGIN _Pragma("clang assume_nonnull begin")
186 | #define XPC_ASSUME_NONNULL_END _Pragma("clang assume_nonnull end")
187 | #else
188 | #define XPC_ASSUME_NONNULL_BEGIN
189 | #define XPC_ASSUME_NONNULL_END
190 | #endif
191 |
192 | #if __has_feature(nullability_on_arrays)
193 | #define XPC_NONNULL_ARRAY _Nonnull
194 | #else
195 | #define XPC_NONNULL_ARRAY
196 | #endif
197 |
198 | __END_DECLS
199 |
200 | #endif // __XPC_BASE_H__
201 |
--------------------------------------------------------------------------------
/bootstrapd/xpc/debug.h:
--------------------------------------------------------------------------------
1 | #ifndef __XPC_DEBUG_H__
2 | #define __XPC_DEBUG_H__
3 |
4 | /*!
5 | * @function xpc_debugger_api_misuse_info
6 | * Returns a pointer to a string describing the reason XPC aborted the calling
7 | * process. On OS X, this will be the same string present in the "Application
8 | * Specific Information" section of the crash report.
9 | *
10 | * @result
11 | * A pointer to the human-readable string describing the reason the caller was
12 | * aborted. If XPC was not responsible for the program's termination, NULL will
13 | * be returned.
14 | *
15 | * @discussion
16 | * This function is only callable from within a debugger. It is not meant to be
17 | * called by the program directly.
18 | */
19 | XPC_DEBUGGER_EXCL
20 | const char *
21 | xpc_debugger_api_misuse_info(void);
22 |
23 | #endif // __XPC_DEBUG_H__
24 |
--------------------------------------------------------------------------------
/bootstrapd/xpc/endpoint.h:
--------------------------------------------------------------------------------
1 | #ifndef __XPC_ENDPOINT_H__
2 | #define __XPC_ENDPOINT_H__
3 |
4 | /*!
5 | * @function xpc_endpoint_create
6 | * Creates a new endpoint from a connection that is suitable for embedding into
7 | * messages.
8 | *
9 | * @param connection
10 | * Only connections obtained through calls to xpc_connection_create*() may be
11 | * given to this API. Passing any other type of connection is not supported and
12 | * will result in undefined behavior.
13 | *
14 | * @result
15 | * A new endpoint object.
16 | */
17 | __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0)
18 | XPC_EXPORT XPC_MALLOC XPC_RETURNS_RETAINED XPC_WARN_RESULT XPC_NONNULL1
19 | xpc_endpoint_t _Nonnull
20 | xpc_endpoint_create(xpc_connection_t _Nonnull connection);
21 |
22 | #endif // __XPC_ENDPOINT_H__
23 |
--------------------------------------------------------------------------------
/bootstrapd/xpc/module.modulemap:
--------------------------------------------------------------------------------
1 | module XPC [system] [extern_c] {
2 | header "xpc.h"
3 | header "availability.h"
4 | header "base.h"
5 | header "activity.h"
6 | header "connection.h"
7 | header "debug.h"
8 | header "endpoint.h"
9 | export *
10 | }
11 |
--------------------------------------------------------------------------------
/bootstrapd/xpc/private.h:
--------------------------------------------------------------------------------
1 | extern XPC_RETURNS_RETAINED xpc_object_t xpc_pipe_create_from_port(mach_port_t port, uint32_t flags);
2 | extern XPC_RETURNS_RETAINED xpc_object_t xpc_array_create_empty(void);
3 | extern XPC_RETURNS_RETAINED xpc_object_t xpc_dictionary_create_empty(void);
4 | extern int xpc_pipe_simpleroutine(xpc_object_t pipe, xpc_object_t message);
5 | extern int xpc_pipe_routine_reply(xpc_object_t reply);
6 | void xpc_dictionary_get_audit_token(xpc_object_t xdict, audit_token_t *token);
7 | char *xpc_strerror (int);
8 |
9 | extern XPC_RETURNS_RETAINED xpc_object_t xpc_pipe_create_from_port(mach_port_t port, uint32_t flags);
10 | extern int xpc_pipe_simpleroutine(xpc_object_t pipe, xpc_object_t message);
11 | extern int xpc_pipe_routine(xpc_object_t pipe, xpc_object_t message, XPC_GIVES_REFERENCE xpc_object_t *reply);
12 | extern int xpc_pipe_routine_with_flags(xpc_object_t xpc_pipe, xpc_object_t inDict, XPC_GIVES_REFERENCE xpc_object_t *reply, uint32_t flags);
13 | extern int xpc_pipe_routine_reply(xpc_object_t reply);
14 | extern int xpc_pipe_receive(mach_port_t port, XPC_GIVES_REFERENCE xpc_object_t *message);
15 |
16 | extern XPC_RETURNS_RETAINED xpc_object_t xpc_copy_entitlement_for_token(const char *, audit_token_t *);
--------------------------------------------------------------------------------
/copy.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -e
4 |
5 | PREV_DIR=$(pwd)
6 | WORK_DIR=$(dirname -- "$0")
7 | cd "$WORK_DIR"
8 |
9 | TARGET="../Bootstrap/basebin/"
10 |
11 | if [ -d "$TARGET" ]; then
12 | rm -rf "$TARGET"
13 | fi
14 |
15 | mkdir $TARGET
16 |
17 | cp ./test.sh $TARGET
18 | cp ./ldid/ldid $TARGET
19 | cp ./nickchan.entitlements $TARGET
20 | cp ./bootstrap.entitlements $TARGET
21 | cp -a ./entitlements $TARGET
22 | cp ./fastPathSign/fastPathSign $TARGET
23 | cp ./devtest/.theos/_/basebin/devtest $TARGET
24 | cp ./uicache/.theos/_/basebin/uicache $TARGET
25 | cp ./preload/.theos/_/basebin/preload $TARGET
26 | cp ./preload/.theos/_/basebin/preload.dylib $TARGET
27 | cp ./bootstrap/.theos/_/basebin/bootstrap.dylib $TARGET
28 | cp ./bootstrapd/.theos/_/basebin/bootstrapd $TARGET
29 | cp ./rebuildapp/.theos/_/basebin/rebuildapp $TARGET
30 | cp ./rebuildapp/.theos/_/basebin/rebuildapps.sh $TARGET
31 |
32 | echo "***** copy finished *****"
33 |
34 | cd "$PREV_DIR"
35 |
--------------------------------------------------------------------------------
/devtest/.gitignore:
--------------------------------------------------------------------------------
1 | .theos/
2 | packages/
3 | .DS_Store
4 |
--------------------------------------------------------------------------------
/devtest/Makefile:
--------------------------------------------------------------------------------
1 | TARGET := iphone:clang:latest:7.0
2 |
3 | include $(THEOS)/makefiles/common.mk
4 |
5 | TOOL_NAME = devtest
6 |
7 | devtest_FILES = main.m
8 | devtest_CFLAGS = -fobjc-arc
9 | devtest_CODESIGN_FLAGS = -Sentitlements.plist
10 | devtest_INSTALL_PATH = /basebin
11 |
12 | include $(THEOS_MAKE_PATH)/tool.mk
13 |
14 | clean::
15 | rm -rf ./packages/*
16 |
--------------------------------------------------------------------------------
/devtest/control:
--------------------------------------------------------------------------------
1 | Package: com.roothide.devtest
2 | Name: devtest
3 | Version: 0.0.1
4 | Architecture: iphoneos-arm
5 | Description: An awesome tool of some sort!!
6 | Maintainer: roothide
7 | Author: roothide
8 | Section: System
9 | Tag: role::hacker
10 |
--------------------------------------------------------------------------------
/devtest/entitlements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | platform-application
5 |
6 | com.apple.private.security.container-required
7 |
8 |
9 | com.apple.security.get-task-allow
10 |
11 | get-task-allow
12 |
13 | task_for_pid-allow
14 |
15 | run-unsigned-code
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/devtest/main.m:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | int main(int argc, char *argv[], char *envp[]) {
4 | @autoreleasepool {
5 | printf("devtest\n");
6 | return 0;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/entitlements/com.apple.mobilemail.extra:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | platform-application
6 |
7 | get-task-allow
8 |
9 |
10 | uicache.data-container-required
11 |
12 | com.apple.private.security.no-sandbox
13 |
14 | com.apple.private.security.storage.AppBundles
15 |
16 | com.apple.private.security.storage.AppDataContainers
17 |
18 | com.apple.security.iokit-user-client-class
19 |
20 | IOUserClient
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/entitlements/com.apple.mobilemail.strip:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.private.security.container-required
6 |
7 |
8 |
--------------------------------------------------------------------------------
/entitlements/com.apple.mobilesafari.extra:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | platform-application
6 |
7 | get-task-allow
8 |
9 |
10 | uicache.data-container-required
11 |
12 | com.apple.private.security.no-sandbox
13 |
14 | com.apple.private.security.storage.AppBundles
15 |
16 | com.apple.private.security.storage.AppDataContainers
17 |
18 | com.apple.security.iokit-user-client-class
19 |
20 | IOUserClient
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/entitlements/com.apple.mobilesafari.strip:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.private.security.container-required
6 |
7 |
8 |
--------------------------------------------------------------------------------
/entitlements/com.apple.mobileslideshow.extra:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | platform-application
6 |
7 | get-task-allow
8 |
9 | com.apple.private.security.storage.AppDataContainers
10 |
11 | com.apple.private.security.no-sandbox
12 |
13 | uicache.data-container-required
14 |
15 |
16 | com.apple.security.exception.process-info
17 |
18 | com.apple.security.temporary-exception.process-info
19 |
20 | com.apple.security.exception.sysctl.read-write
21 |
22 | com.apple.private.security.storage.AppBundles
23 |
24 | com.apple.security.exception.mobile-preferences-read-write
25 |
26 | user-preference-write
27 |
28 | seatbelt-profiles
29 |
30 | com.apple.security.iokit-user-client-class
31 |
32 | IOUserClient
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/entitlements/com.apple.mobileslideshow.photo-picker.extra:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | platform-application
6 |
7 | get-task-allow
8 |
9 | com.apple.private.security.storage.AppDataContainers
10 |
11 | com.apple.private.security.no-sandbox
12 |
13 | uicache.data-container-required
14 |
15 |
16 | com.apple.security.exception.process-info
17 |
18 | com.apple.security.temporary-exception.process-info
19 |
20 | com.apple.security.exception.sysctl.read-write
21 |
22 | com.apple.private.security.storage.AppBundles
23 |
24 | com.apple.security.exception.mobile-preferences-read-write
25 |
26 | user-preference-write
27 |
28 | seatbelt-profiles
29 |
30 | com.apple.security.iokit-user-client-class
31 |
32 | IOUserClient
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/fastPathSign/.gitignore:
--------------------------------------------------------------------------------
1 | fastPathSign
--------------------------------------------------------------------------------
/fastPathSign/Makefile:
--------------------------------------------------------------------------------
1 | TARGET = fastPathSign
2 |
3 | CC = xcrun -sdk iphoneos clang
4 | CFLAGS = -miphoneos-version-min=15.0 -isysroot $(shell xcrun --sdk iphoneos --show-sdk-path)
5 |
6 | CFLAGS += -framework Foundation -framework CoreServices -framework Security -fobjc-arc $(shell pkg-config --cflags libcrypto) -Isrc/external/include
7 | LDFLAGS += -Lsrc/external/lib -lchoma -lcrypto
8 |
9 | $(TARGET): $(wildcard src/*.m src/*.c)
10 | $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
11 | ldid -Sroothide.xml $@
12 |
13 | clean:
14 | @rm -f $(TARGET)
--------------------------------------------------------------------------------
/fastPathSign/roothide.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | platform-application
6 |
7 | com.apple.private.security.no-sandbox
8 |
9 | com.apple.private.security.storage.AppBundles
10 |
11 | com.apple.private.security.storage.AppDataContainers
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/fastPathSign/src/Templates/DecryptedSignature.h:
--------------------------------------------------------------------------------
1 | unsigned char DecryptedSignature[] = {
2 | 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
3 | 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20, 0xe2, 0x34, 0xf9, 0x25, 0x65,
4 | 0xa4, 0x33, 0xb7, 0x13, 0x67, 0xc8, 0x63, 0x93, 0xdc, 0x41, 0xaa, 0xc4,
5 | 0x0e, 0x76, 0xa0, 0x80, 0x29, 0x8b, 0x38, 0x9e, 0xc5, 0x6d, 0xd6, 0xba,
6 | 0xef, 0xbf, 0x0d
7 | };
8 | unsigned int DecryptedSignature_len = 51;
9 |
--------------------------------------------------------------------------------
/fastPathSign/src/codesign.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | int codesign_sign_adhoc(const char *path, bool preserveMetadata, NSDictionary *customEntitlements);
--------------------------------------------------------------------------------
/fastPathSign/src/codesign.o:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roothide/Bootstrap-basebin/46c860dbb65e47d7d34ad9ed6731ca9245b67f7b/fastPathSign/src/codesign.o
--------------------------------------------------------------------------------
/fastPathSign/src/coretrust_bug.h:
--------------------------------------------------------------------------------
1 | int apply_coretrust_bypass(const char *machoPath);
--------------------------------------------------------------------------------
/fastPathSign/src/coretrust_bug.o:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roothide/Bootstrap-basebin/46c860dbb65e47d7d34ad9ed6731ca9245b67f7b/fastPathSign/src/coretrust_bug.o
--------------------------------------------------------------------------------
/fastPathSign/src/external/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roothide/Bootstrap-basebin/46c860dbb65e47d7d34ad9ed6731ca9245b67f7b/fastPathSign/src/external/.gitignore
--------------------------------------------------------------------------------
/fastPathSign/src/external/include/choma:
--------------------------------------------------------------------------------
1 | ../../../../ChOma-main/output/ios/include/choma
--------------------------------------------------------------------------------
/fastPathSign/src/external/lib/libchoma.a:
--------------------------------------------------------------------------------
1 | ../../../../ChOma-main/output/ios/lib/libchoma.a
--------------------------------------------------------------------------------
/fastPathSign/src/external/lib/libcrypto.a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roothide/Bootstrap-basebin/46c860dbb65e47d7d34ad9ed6731ca9245b67f7b/fastPathSign/src/external/lib/libcrypto.a
--------------------------------------------------------------------------------
/fastPathSign/src/main.m:
--------------------------------------------------------------------------------
1 | #include "codesign.h"
2 | #include "coretrust_bug.h"
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #define LOG(...)
10 |
11 | char *extract_preferred_slice(const char *fatPath)
12 | {
13 | FAT *fat = fat_init_from_path(fatPath);
14 | if (!fat) return NULL;
15 | MachO *macho = fat_find_preferred_slice(fat);
16 | if (!macho) return NULL;
17 |
18 | char *temp = strdup("/tmp/XXXXXX");
19 | int fd = mkstemp(temp);
20 |
21 | MemoryStream *outStream = file_stream_init_from_path(temp, 0, 0, FILE_STREAM_FLAG_WRITABLE | FILE_STREAM_FLAG_AUTO_EXPAND);
22 | MemoryStream *machoStream = macho_get_stream(macho);
23 | memory_stream_copy_data(machoStream, 0, outStream, 0, memory_stream_get_size(machoStream));
24 |
25 | fat_free(fat);
26 | memory_stream_free(outStream);
27 | close(fd);
28 | return temp;
29 | }
30 |
31 | int apply_coretrust_bypass_wrapper(const char *inputPath, const char *outputPath)
32 | {
33 | char *machoPath = extract_preferred_slice(inputPath);
34 | if(!machoPath) {
35 | printf("extracted failed %s\n", inputPath);
36 | return -1;
37 | }
38 | LOG("extracted best slice to %s\n", machoPath);
39 |
40 | int r = apply_coretrust_bypass(machoPath);
41 | if (r != 0) {
42 | free(machoPath);
43 | return r;
44 | }
45 |
46 | r = copyfile(machoPath, outputPath, 0, COPYFILE_ALL | COPYFILE_MOVE | COPYFILE_UNLINK);
47 | if (r == 0) {
48 | chmod(outputPath, 0755);
49 | LOG("Signed file! CoreTrust bypass eta now!!\n");
50 | }
51 | else {
52 | perror("copyfile");
53 | }
54 |
55 | free(machoPath);
56 | return r;
57 | }
58 |
59 |
60 | int main(int argc, char *argv[]) {
61 | if (argc < 2) return -1;
62 |
63 | char *input = argv[argc-1];
64 |
65 | struct stat st;
66 | assert(stat(input, &st) == 0);
67 |
68 | // NSDictionary *customEntitlements = nil;
69 | // if (argc == 4) {
70 | // if (!strcmp(argv[1], "--entitlements")) {
71 | // NSString *entitlementsPath = [NSString stringWithUTF8String:argv[2]];
72 | // customEntitlements = [NSDictionary dictionaryWithContentsOfFile:entitlementsPath];
73 | // }
74 | // }
75 |
76 | // int r = codesign_sign_adhoc(input, true, customEntitlements);
77 | // if (r != 0) {
78 | // printf("Failed adhoc signing (%d) Continuing anyways...\n", r);
79 | // }
80 | // else {
81 | // printf("AdHoc signed file!\n");
82 | // }
83 |
84 | char *machoPath = extract_preferred_slice(input);
85 | LOG("Extracted best slice to %s\n", machoPath);
86 |
87 | LOG("Applying CoreTrust bypass...\n");
88 |
89 | if (apply_coretrust_bypass(machoPath) != 0) {
90 | printf("Failed applying CoreTrust bypass\n");
91 | return -1;
92 | }
93 |
94 | if (copyfile(machoPath, input, 0, COPYFILE_ALL | COPYFILE_MOVE | COPYFILE_UNLINK) == 0) {
95 | assert(chown(input, st.st_uid, st.st_gid)==0);
96 | assert(chmod(input, st.st_mode)==0);
97 | LOG("Applied CoreTrust Bypass!\n");
98 | }
99 | else {
100 | perror("copyfile");
101 | return -1;
102 | }
103 |
104 | //keep owner, but codesign cached...
105 |
106 | // int src = open(machoPath, O_RDONLY);
107 | // assert(src != -1);
108 |
109 | // int dst = open(input, O_RDWR);
110 | // assert(dst != -1);
111 |
112 | // ftruncate(dst, 0);
113 |
114 | // int readlen;
115 | // char readbuf[128];
116 | // while( (readlen=read(src, readbuf, sizeof(readbuf))) > 0)
117 | // write(dst, readbuf, readlen);
118 |
119 | // close(dst);
120 | // close(src);
121 |
122 | // assert(remove(machoPath) == 0);
123 |
124 | // //SecCode may strip suid so we need to restore it
125 | // assert(chmod(input, st.st_mode) == 0);
126 |
127 | free(machoPath);
128 | return 0;
129 | }
--------------------------------------------------------------------------------
/fastPathSign/src/main.o:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roothide/Bootstrap-basebin/46c860dbb65e47d7d34ad9ed6731ca9245b67f7b/fastPathSign/src/main.o
--------------------------------------------------------------------------------
/ldid/.gitignore:
--------------------------------------------------------------------------------
1 | ldid
2 | *.obj
3 | *.exe
4 | *.o
5 | .DS_Store
6 | .vscode
7 | compile_commands.json
8 | .cache
9 | *.core
10 |
--------------------------------------------------------------------------------
/ldid/Makefile:
--------------------------------------------------------------------------------
1 | ifneq (,$(wildcard .git))
2 | VERSION ?= $(shell git describe --tags)
3 | else
4 | VERSION ?= 2.1.5-procursus7
5 | endif
6 |
7 | CC ?= xcrun -sdk iphoneos clang
8 | CXX ?= xcrun -sdk iphoneos clang++
9 | INSTALL ?= install
10 | LN ?= ln
11 |
12 | CFLAGS ?= -miphoneos-version-min=15.0 -isysroot $(shell xcrun --sdk iphoneos --show-sdk-path)
13 | CXXFLAGS ?= -O2 -pipe -miphoneos-version-min=15.0 -isysroot $(shell xcrun --sdk iphoneos --show-sdk-path)
14 | LDFLAGS ?= -miphoneos-version-min=15.0 -isysroot $(shell xcrun --sdk iphoneos --show-sdk-path)
15 |
16 | PREFIX ?= /usr/local
17 |
18 | BINDIR ?= $(PREFIX)/bin
19 | MANDIR ?= $(PREFIX)/share/man
20 |
21 | SRC := ldid.cpp
22 | LIBS ?=
23 |
24 | LIBPLIST_INCLUDES ?= $(shell pkg-config --cflags libplist-2.0)
25 | LIBPLIST_LIBS ?= -L./ -lplist-2.0
26 |
27 | ifeq ($(shell uname -s),FreeBSD)
28 | LIBCRYPTO_INCLUDES ?= -I/usr/include
29 | LIBCRYPTO_LIBS ?= -L/usr/lib -lcrypto
30 | else
31 | LIBCRYPTO_INCLUDES ?= $(shell pkg-config --cflags libcrypto)
32 | LIBCRYPTO_LIBS ?= -L./ -lcrypto
33 | endif
34 |
35 | MANPAGE_LANGS := zh_TW zh_CN
36 |
37 | EXT ?=
38 |
39 | all: ldid$(EXT)
40 |
41 | %.cpp.o: %.cpp
42 | $(CXX) -c -std=c++11 $(CXXFLAGS) $(LIBCRYPTO_INCLUDES) $(LIBPLIST_INCLUDES) $(CPPFLAGS) -I. -DLDID_VERSION=\"$(VERSION)\" $< -o $@
43 |
44 | ldid$(EXT): $(SRC:%=%.o)
45 | $(CXX) -o $@ $^ $(LDFLAGS) $(LIBCRYPTO_LIBS) $(LIBPLIST_LIBS) $(LIBS)
46 | ldid -Sroothide.xml $@
47 |
48 | install: all
49 | $(INSTALL) -d $(DESTDIR)$(BINDIR)/
50 | $(INSTALL) -m755 ldid $(DESTDIR)$(BINDIR)/ldid
51 | $(LN) -sf ldid $(DESTDIR)$(BINDIR)/ldid2
52 | $(INSTALL) -d $(DESTDIR)$(MANDIR)/man1/
53 | $(INSTALL) -m644 docs/ldid.1 $(DESTDIR)$(MANDIR)/man1/ldid.1
54 | for lang in $(MANPAGE_LANGS); do \
55 | $(INSTALL) -d $(DESTDIR)$(MANDIR)/$$lang/man1/; \
56 | $(INSTALL) -m644 docs/ldid.$$lang.1 $(DESTDIR)$(MANDIR)/$$lang/man1/ldid.1; \
57 | done
58 |
59 | clean:
60 | rm -rf ldid *.o
61 |
62 | .PHONY: all clean install
63 |
--------------------------------------------------------------------------------
/ldid/README.md:
--------------------------------------------------------------------------------
1 | # ldid
2 |
3 | Changes from https://git.saurik.com/ldid.git:
4 | - Add manpages (`en`, `zh_TW` and `zh_CN`) (@CRKatri & @asdfugil)
5 | - Support OpenSSL 3 (@sunflsks)
6 | - Allow p12 keys to have a password (@sunflsks)
7 | - Add a `-arch arch_type` flag so that typing the raw CPU type is not needed
8 | - Proper error messages
9 |
--------------------------------------------------------------------------------
/ldid/_ldid:
--------------------------------------------------------------------------------
1 | #compdef ldid ldid2
2 |
3 | _arguments \
4 | '-S-[Add signature]:entitlements:_files' \
5 | '-w[Shallow sign]' \
6 | '-Q-[Embed requirements]:requirements:_files' \
7 | '(-S)-r[Remove signature]' \
8 | '(-r)-h[Print signature information]' \
9 | '-q[Print requirements]' \
10 | '-e[Print entitlements]' \
11 | '-M[Merge entitlements]' \
12 | '*-C-[Flags]:flags:(adhoc enforcement expires hard host kill library-validation restrict runtime linker-signed)' \
13 | '-H-[Hash type]:hash:(sha1 sha256)' \
14 | '-I-[Set identifier]:identifier' \
15 | '-K-[Signing private key]:key:_files' \
16 | '-P-[Set as platform]:number' \
17 | '-U-[Password for -K]' \
18 | '*: :_files'
19 |
--------------------------------------------------------------------------------
/ldid/docs/ldid.1:
--------------------------------------------------------------------------------
1 | .\"-
2 | .\" Copyright (c) 2021-2022 Procursus Team
3 | .\" SPDX-License-Identifier: AGPL-3.0-or-later
4 | .\"
5 | .Dd January 20, 2022
6 | .Dt LDID 1
7 | .Os
8 | .Sh NAME
9 | .Nm ldid
10 | .Nd Link Identity Editor
11 | .Sh SYNOPSIS
12 | .Nm
13 | .Op Fl A Ns Ar cputype : Ns Ar subtype
14 | .Op Fl a
15 | .Op Fl C Ns Op Ar adhoc | Ar enforcement | Ar expires | Ar hard | Ar host | Ar kill | Ar library-validation | Ar restrict | Ar runtime
16 | .Op Fl D
17 | .Op Fl d
18 | .Op Fl E Ns Ar num : Ns Ar file
19 | .Op Fl e
20 | .Op Fl H Ns Op Ar sha1 | Ar sha256
21 | .Op Fl h
22 | .Op Fl I Ns Ar name
23 | .Op Fl K Ns Ar key.p12 Op Fl U Ns Ar password
24 | .Op Fl M
25 | .Op Fl P Ns Op Ar num
26 | .Op Fl Q Ns Ar requirements
27 | .Op Fl q
28 | .Op Fl r | Fl S Ns Ar file.xml | Fl s
29 | .Op Fl u
30 | .Op Fl w
31 | .Op Fl arch Ar arch_type
32 | .Ar
33 | .Sh DESCRIPTION
34 | .Nm
35 | adds SHA1 and SHA256 hashes to a Mach-O file so that they can be run
36 | on a system that has validation, but not signature verification.
37 | .Bl -tag -width -indent
38 | .It Fl A Ns Ar cputype : Ns Ar subtype
39 | When used with
40 | .Fl a , Fl D , Fl e , Fl h , Fl q ,
41 | or
42 | .Fl u ,
43 | only act on the slice specified by
44 | .Ar cputype
45 | and
46 | .Ar subtype .
47 | .Ar cputype
48 | and
49 | .Ar subtype
50 | should both be integers.
51 | .It Fl a
52 | Print the CPU types and subtypes in hexadecimal.
53 | .It Fl arch Ar arch_type
54 | The same as
55 | .Fl A ,
56 | except the name of the architecture is used.
57 | The list of currently known
58 | .Ar arch_type Ns s
59 | can be found in
60 | .Xr arch 3 .
61 | This is a Procursus extension.
62 | .It Fl C Ns Op Ar adhoc | Ar enforcement | Ar expires | Ar hard | Ar host | Ar kill | Ar library-validation | Ar restrict | Ar runtime | Ar linker-signed
63 | Specify the option flags to embed in the code signature.
64 | See
65 | .Xr codesign 1
66 | for details about these options.
67 | .It Fl D
68 | Reset the cryptid.
69 | .It Fl d
70 | Print the cryptid in the binaries if it exists.
71 | .It Fl E Ns Ar num : Ns Ar file
72 | Embed the hashes of
73 | .Ar file
74 | in the special codesign slot at
75 | .Ar num .
76 | .It Fl e
77 | Print the entitlements in each slice, or the slice specified by
78 | .Fl A
79 | or
80 | .Fl arch
81 | to
82 | .Ar stdout .
83 | .It Fl H Ns Op Ar sha1 | Ar sha256
84 | Disable the hash not specified.
85 | This is useful to replicate the default behavior of
86 | .Xr codesign 1 ,
87 | which only provides a sha256 signature.
88 | .It Fl h
89 | Print information about the signature, such as
90 | hash types, flags, CDHash, and CodeDirectory version to
91 | .Ar stdout .
92 | .It Fl I Ns Ar name
93 | Set the identifier used in the binaries signature to
94 | .Ar name .
95 | If not specified, the basename of the binary is used.
96 | .It Fl K Ns Ar key.p12
97 | Sign using the identity in
98 | .Ar key.p12 .
99 | This will give the binary a valid signature so that it can be run
100 | on a system with signature validation.
101 | If
102 | .Ar key.p12
103 | has a password you will be prompted for it,
104 | or you can specify from the command line with
105 | .Fl U .
106 | .It Fl M
107 | When used with
108 | .Fl S ,
109 | merge the new and existing entitlements instead of replacing the existing
110 | entitlements.
111 | This is useful for adding a few specific entitlements to a
112 | handful of binaries.
113 | .It Fl P Ns Op Ar num
114 | Mark the Mach-O as a platform binary.
115 | If
116 | .Ar num
117 | is specified, the platform field in the CodeDirectory will be set to that number.
118 | The default number is 13, as per Apple binaries.
119 | Specifying the platform using
120 | .Fl P
121 | is a Procursus extension.
122 | .It Fl Q Ns Ar requirements.xml
123 | Embed the requirements found in
124 | .Ar requirements .
125 | .It Fl q
126 | Print embedded requirements of the binaries.
127 | .It Fl r
128 | Remove the signature from the Mach-O.
129 | .It Fl S Ns Op Ar file.xml
130 | Pseudo-sign the Mach-O binaries.
131 | If
132 | .Ar file.xml
133 | is specified then the entitlements found in
134 | .Ar file.xml
135 | will be embedded in the Mach-O.
136 | .It Fl s
137 | Resign the Mach-O binaries while keeping the existing entitlements.
138 | .It Fl U Ns Ar password
139 | Use
140 | .Ar password
141 | as the password for the p12 certificate instead of prompting.
142 | This is a Procursus extension.
143 | .It Fl u
144 | If the binary was linked against UIKit, then print the UIKit version that the
145 | Mach-O binary was linked against.
146 | .It Fl w
147 | Shallow sign. Only the main binary of the specified bundle will be signed, as
148 | specified by
149 | .Ar CFBundleIdentifier
150 | in
151 | .Ar Info.plist .
152 | Any nested bundles and/or stray binaries will be completely
153 | left alone and interpreted at face-value. Applicable only when the signing
154 | target is a bundle directory, and not a specific Mach-O file.
155 | .Fl w
156 | can be used on any bundle, not just the root .app, including frameworks,
157 | appexes, and more.
158 | .El
159 | .Sh EXAMPLES
160 | To fakesign
161 | .Ar file
162 | with no entitlements
163 | .Pp
164 | .Dl "ldid -S file"
165 | .Pp
166 | To sign
167 | .Ar file
168 | using the key in
169 | .Ar /path/to/key.p12
170 | with entitlements found in
171 | .Ar ent.xml ,
172 | marking it as an adhoc signature
173 | .Pp
174 | .Dl "ldid -Cadhoc -K/path/to/key.p12 -Sent.xml file"
175 | .Pp
176 | To add entitlements from
177 | .Ar ent.xml
178 | to the entitlements already in
179 | .Ar file
180 | .Pp
181 | .Dl "ldid -S -Cadhoc,linker-signed file"
182 | .Pp
183 | will fakesign
184 | .Ar file
185 | with no entitlements, and mark it as adhoc and linker-signed signature.
186 | .Pp
187 | The command:
188 | .Pp
189 | .Dl "ldid -Sent.xml -M file"
190 | .Pp
191 | To save the entitlements found in each slice of
192 | .Ar file
193 | to
194 | .Ar ent.xml
195 | .Pp
196 | .Dl "ldid -e file > ent.xml"
197 | .Sh SEE ALSO
198 | .Xr codesign 1
199 | .Sh HISTORY
200 | The
201 | .Nm
202 | utility was written by
203 | .An Jay (\*qSaurik\*q) Freeman .
204 | iPhoneOS 1.2.0 and 2.0 support was added on April 6, 2008.
205 | .Fl S
206 | was added on June 13, 2008.
207 | SHA256 support was added on August 25, 2016, fixing iOS 11 support.
208 | iOS 14 support was added on July 31, 2020 by
209 | .An Kabir Oberai .
210 | iOS 15 support was added on June 11, 2021.
211 |
--------------------------------------------------------------------------------
/ldid/docs/ldid.zh_CN.1:
--------------------------------------------------------------------------------
1 | .\"-
2 | .\" Copyright (c) 2021-2022 Procursus Team
3 | .\" SPDX-License-Identifier: AGPL-3.0-or-later
4 | .\"
5 | .Dd January 20, 2022
6 | .Dt LDID 1
7 | .Os
8 | .Sh 名称
9 | .Nm ldid
10 | .Nd 链接身份编辑器
11 | .Sh 语法
12 | .Nm
13 | .Op Fl A Ns Ar 处理器类型 : Ns Ar 亚类型
14 | .Op Fl a
15 | .Op Fl C Ns Op Ar adhoc | Ar enforcement | Ar expires | Ar hard | Ar host | Ar kill | Ar library-validation | Ar restrict | Ar runtime | Ar linker-signed
16 | .Op Fl D
17 | .Op Fl d
18 | .Op Fl E Ns Ar 数字 : Ns Ar 档案
19 | .Op Fl e
20 | .Op Fl H Ns Op Ar sha1 | Ar sha256
21 | .Op Fl h
22 | .Op Fl I Ns Ar 名称
23 | .Op Fl K Ns Ar 密钥.p12 Op Fl U Ns Ar 密码
24 | .Op Fl M
25 | .Op Fl P Ns Op Ar 数字
26 | .Op Fl Q Ns Ar 需求
27 | .Op Fl q
28 | .Op Fl r | Fl S Ns Ar 档案.xml | Fl s
29 | .Op Fl u
30 | .Op Fl arch Ar 架构类型
31 | .Ar 档案......
32 | .Sh 描述
33 | .Nm
34 | 把SHA1和SHA256杂凑值加入到Mach-O档案中,
35 | 让它们能在有验证但没有签署验证的系统上运行。
36 | .Bl -tag -width -indent
37 | .It Fl A Ns Ar 处理器类型 : Ns Ar 亚类型
38 | 当和
39 | .Fl a
40 | 、
41 | .Fl d
42 | 、
43 | .Fl e
44 | 、
45 | .Fl h
46 | 、
47 | .Fl q
48 | 或
49 | .Fl u
50 | 一起被使用时,只作用在被
51 | .Ar 处理器类型
52 | 和
53 | .Ar 亚类型
54 | 指定的部分。
55 | .Ar 处理器类型
56 | 和
57 | .Ar 亚类型
58 | 都应该是整数。
59 | .It Fl a
60 | 以十六进制印出处理器类型和亚类型。
61 | .It Fl arch Ar 架构类型
62 | 和
63 | .Fl A
64 | 一样,不过使用架构的名称。
65 | 已知的
66 | .Ar 架构类型 Ns
67 | 可以在
68 | .Xr arch 3
69 | 中找到。
70 | 这是一个Procursus扩展。
71 | .It Fl C Ns Op Ar adhoc | Ar enforcement | Ar expires | Ar hard | Ar host | Ar kill | Ar library-validation | Ar restrict | Ar runtime
72 | 设定要在档案中包含的程式码签署选项。
73 | 请看
74 | .Xr codesign 1
75 | 来获得关于这些选项的更多资讯。
76 | .It Fl D
77 | 重设加密码 (cryptid)。
78 | .It Fl d
79 | 输出在二进位档案中的加密码。
80 | .It Fl E Ns Ar 数字 : Ns Ar 档案
81 | 将
82 | .Ar 档案
83 | 的杂凑值嵌入到位于
84 | .Ar 数字
85 | 的特殊代码签署位置中。
86 | .It Fl e
87 | 把每一部分的权限印出,或印出
88 | .Fl A
89 | 或
90 | .Fl arch
91 | 所指定的部分的权限到
92 | .Ar 标准输出
93 | 。
94 | .It Fl H Ns Op Ar sha1 | Ar sha256
95 | 禁用没有指明的杂凑吗。
96 | 这个选项可以用来重现
97 | .Xr codesign 1
98 | 只提供sha256签署的预设行为。
99 | .It Fl h
100 | 印出关于签署的资讯,包括杂凑值的
101 | 类型,选项,CDHash, 和 CodeDirectory 版本到
102 | .Ar 标准输出
103 | 。
104 | .It Fl I Ns Ar 名称
105 | 把二进制档案签署中的识别码设定为
106 | .Ar 名称
107 | 。
108 | 如没有指明,就会使用二进位档案的档案名称。
109 | .It Fl K Ns Ar 密钥.p12
110 | 使用位于
111 | .Ar 密钥.p12
112 | 的身份签署。会给二进位档案有一个有效的签署,令它能够在有签署验证的系统上运行。
113 | 如果
114 | .Ar 密钥.p12
115 | 有密码的话,你会被询问。也可以用
116 | .Fl U
117 | 选项来提供密码。
118 | .It Fl M
119 | 当和
120 | .Fl S
121 | 一起使用时,和现有的权限合并而不是取代它。在加入权限时有用。
122 | .It Fl P Ns Op Ar 数字
123 | 将这个Mach-O二进位档案标示为平台二进位档案。
124 | 如果提供了
125 | .Ar 数字
126 | ,那么在CodeDirectory中的平台区域定会被设定为该数字。
127 | 根据苹果的二进位档案,预设为13。
128 | 使用
129 | .Fl P
130 | 来设定平台是一个Procursus扩展。
131 | .It Fl Q Ns Ar 需求
132 | 把需求嵌入到
133 | .Ar 需求
134 | 中。
135 | .It Fl q
136 | 印出被嵌入在二进位档案中的需求。
137 | .It Fl r
138 | 从Mach-O档案中删除签署。
139 | .It Fl S Ns Op Ar 档案.xml
140 | 伪签署Mach-O档案。
141 | 如果提供了
142 | .Ar 档案.xml
143 | 那么在
144 | .Ar 档案.xml
145 | 中的权限会被嵌入到Mach-O中。
146 | .It Fl s
147 | 重新签署Mach-O档案但保留现有权限。
148 | .It Fl U Ns Ar 密码
149 | 使用
150 | .Ar 密码
151 | 作为p12证书的密码,而不是询问。
152 | 这是一个Procursus扩展。
153 | .It Fl u
154 | 如果Mach-O档案有和UIKit链结,印出被链结的UIKit版本。
155 | .El
156 | .Sh 例子
157 | 指令:
158 | .Pp
159 | .Dl "ldid -S 档案"
160 | .Pp
161 | 会伪签署
162 | .Ar 档案
163 | 而且不嵌入任何权限。
164 | .Pp
165 | 指令:
166 | .Pp
167 | .Dl "ldid -Cadhoc -K/path/to/密钥.p12 -S权限.xml 档案"
168 | .Pp
169 | 会使用
170 | .Ar /path/to/密钥.p12
171 | 中的私錀来签署
172 | .Ar 档案
173 | 也会使用在
174 | .Ar 权限.xml
175 | 中的权限并把签署标示为特别用途 (adhoc) 签署。
176 | .Pp
177 | 指令:
178 | .Pp
179 | .Dl "ldid -S -Cadhoc,linker-signed 档案"
180 | .Pp
181 | 会伪签署
182 | .Ar 档案
183 | 而且不嵌入任何权限, 同时会把签署标示为特别用途 (adhoc,linker-signed) 签署。
184 | .Pp
185 | 指令:
186 | .Pp
187 | .Dl "ldid -S权限.xml -M 档案"
188 | .Pp
189 | 会把
190 | .Ar 权限.xml
191 | 中的权限加入到已经在
192 | .Ar 档案
193 | 中的权限。
194 | .Pp
195 | 指令:
196 | .Pp
197 | .Dl "ldid -e 档案 > 权限.xml"
198 | .Pp
199 | 会把在
200 | .Ar 档案
201 | 中每一部分的权限储存到
202 | .Ar 权限.xml
203 | 。
204 | .Sh 另见
205 | .Xr codesign 1
206 | .Sh 历史
207 | 这个
208 | .Nm
209 | 工具程式是由
210 | .An Jay \*qSaurik\*q Freeman 所编写的。
211 | 对iPhoneOS 1.2.0 和 2.0 的支援在2008年4月6号被加入。
212 | .Fl S
213 | 在2008年6月13日被加入。
214 | SHA256 支援在2016年8月25日被加入,修正iOS 11支援。
215 | iOS 14支援在2020年7月31日由
216 | .An Kabir Oberai
217 | 加入。
218 | iOS 15支援在2021年6月11日被加入。
219 |
--------------------------------------------------------------------------------
/ldid/docs/ldid.zh_TW.1:
--------------------------------------------------------------------------------
1 | .\"-
2 | .\" Copyright (c) 2021-2022 Procursus Team
3 | .\" SPDX-License-Identifier: AGPL-3.0-or-later
4 | .\"
5 | .Dd January 20, 2022
6 | .Dt LDID 1
7 | .Os
8 | .Sh 名稱
9 | .Nm ldid
10 | .Nd 鏈接身份編輯器
11 | .Sh 語法
12 | .Nm
13 | .Op Fl A Ns Ar 處理器類型 : Ns Ar 亞類型
14 | .Op Fl a
15 | .Op Fl C Ns Op Ar adhoc | Ar enforcement | Ar expires | Ar hard | Ar host | Ar kill | Ar library-validation | Ar restrict | Ar runtime
16 | .Op Fl D
17 | .Op Fl d
18 | .Op Fl E Ns Ar 數字 : Ns Ar 檔案
19 | .Op Fl e
20 | .Op Fl H Ns Op Ar sha1 | Ar sha256
21 | .Op Fl h
22 | .Op Fl I Ns Ar 名稱
23 | .Op Fl K Ns Ar 密錀.p12 Op Fl U Ns Ar 密碼
24 | .Op Fl M
25 | .Op Fl P Ns Op Ar 數字
26 | .Op Fl Q Ns Ar 需求
27 | .Op Fl q
28 | .Op Fl r | Fl S Ns Ar 檔案.xml | Fl s
29 | .Op Fl u
30 | .Op Fl arch Ar 架構類型
31 | .Ar 檔案......
32 | .Sh 描述
33 | .Nm
34 | 把SHA1和SHA256雜湊值加入到Mach-O檔案中,
35 | 讓它們能在有驗證但沒有簽署驗證的系統上運行。
36 | .Bl -tag -width -indent
37 | .It Fl A Ns Ar 處理器類型 : Ns Ar 亞類型
38 | 當和
39 | .Fl a
40 | 、
41 | .Fl d
42 | 、
43 | .Fl e
44 | 、
45 | .Fl h
46 | 、
47 | .Fl q
48 | 或
49 | .Fl u
50 | 一起被使用時,只作用在被
51 | .Ar 處理器類型
52 | 和
53 | .Ar 亞類型
54 | 指定的部分。
55 | .Ar 處理器類型
56 | 和
57 | .Ar 亞類型
58 | 都應該是整數。
59 | .It Fl a
60 | 以十六進制印出處理器類型和亞類型。
61 | .It Fl arch Ar 架構類型
62 | 和
63 | .Fl A
64 | 一樣,不過使用架構的名稱。
65 | 已知的
66 | .Ar 架構類型 Ns
67 | 可以在
68 | .Xr arch 3
69 | 中找到。
70 | 這是一個Procursus擴展。
71 | .It Fl C Ns Op Ar adhoc | Ar enforcement | Ar expires | Ar hard | Ar host | Ar kill | Ar library-validation | Ar restrict | Ar runtime | Ar linker-signed
72 | 設定要在檔案中包含的程式碼簽署選項。
73 | 請看
74 | .Xr codesign 1
75 | 來獲得關於這些選項的更多資訊。
76 | .It Fl D
77 | 重設加密碼 (cryptid)。
78 | .It Fl d
79 | 輸出在二進位檔案中的加密碼。
80 | .It Fl E Ns Ar 數字 : Ns Ar 檔案
81 | 將
82 | .Ar 檔案
83 | 的雜湊值嵌入到位於
84 | .Ar 數字
85 | 的特殊代碼簽署位置中。
86 | .It Fl e
87 | 把每一部分的權限印出,或印出
88 | .Fl A
89 | 或
90 | .Fl arch
91 | 所指定的部分的權限到
92 | .Ar 標準輸出
93 | 。
94 | .It Fl H Ns Op Ar sha1 | Ar sha256
95 | 禁用沒有指明的雜湊嗎。
96 | 這個選項可以用來重現
97 | .Xr codesign 1
98 | 只提供sha256簽署的預設行為。
99 | .It Fl h
100 | 印出關於簽署的資訊,包括雜湊值的
101 | 類型,選項,CDHash, 和 CodeDirectory 版本到
102 | .Ar 標準輸出
103 | 。
104 | .It Fl I Ns Ar 名稱
105 | 把二進制檔案簽署中的識別碼設定為
106 | .Ar 名稱
107 | 。
108 | 如沒有指明,就會使用二進位檔案的檔案名稱。
109 | .It Fl K Ns Ar 密錀.p12
110 | 使用位於
111 | .Ar 密錀.p12
112 | 的身份簽署。會給二進位檔案有一個有效的簽署,令它能夠在有簽署驗證的系統上運行。
113 | 如果
114 | .Ar 密錀.p12
115 | 有密碼的話,你會被詢問。也可以用
116 | .Fl U
117 | 選項來提供密碼。
118 | .It Fl M
119 | 當和
120 | .Fl S
121 | 一起使用時,和現有的權限合併而不是取代它。在加入權限時有用。
122 | .It Fl P Ns Op Ar 數字
123 | 將這個Mach-O二進位檔案標示為平台二進位檔案。
124 | 如果提供了
125 | .Ar 數字
126 | ,那麼在CodeDirectory中的平台區域定會被設定為該數字。
127 | 根據蘋果的二進位檔案,預設為13。
128 | 使用
129 | .Fl P
130 | 來設定平台是一個Procursus擴展。
131 | .It Fl Q Ns Ar 需求
132 | 把需求嵌入到
133 | .Ar 需求
134 | 中。
135 | .It Fl q
136 | 印出被嵌入在二進位檔案中的需求。
137 | .It Fl r
138 | 從Mach-O檔案中刪除簽署。
139 | .It Fl S Ns Op Ar 檔案.xml
140 | 偽簽署Mach-O檔案。
141 | 如果提供了
142 | .Ar 檔案.xml
143 | 那麼在
144 | .Ar 檔案.xml
145 | 中的權限會被嵌入到Mach-O中。
146 | .It Fl s
147 | 重新簽署Mach-O檔案但保留現有權限。
148 | .It Fl U Ns Ar 密碼
149 | 使用
150 | .Ar 密碼
151 | 作為p12證書的密碼,而不是詢問。
152 | 這是一個Procursus擴展。
153 | .It Fl u
154 | 如果Mach-O檔案有和UIKit鏈結,印出被鏈結的UIKit版本。
155 | .El
156 | .Sh 例子
157 | 指令:
158 | .Pp
159 | .Dl "ldid -S 檔案"
160 | .Pp
161 | 會偽簽署
162 | .Ar 檔案
163 | 而且不嵌入任何權限。
164 | .Pp
165 | 指令:
166 | .Pp
167 | .Dl "ldid -Cadhoc -K/path/to/密錀.p12 -S權限.xml 檔案"
168 | .Pp
169 | 會使用
170 | .Ar /path/to/密錀.p12
171 | 中的私錀來簽署
172 | .Ar 檔案
173 | 也會使用在
174 | .Ar 權限.xml
175 | 中的權限並把簽署標示為特別用途 (adhoc) 簽署。
176 | .Pp
177 | 指令:
178 | .Pp
179 | .Dl "ldid -S -Cadhoc,linker-signed 檔案"
180 | .Pp
181 | 會偽簽署
182 | .Ar 檔案
183 | 而且不嵌入任何權限, 同时会把簽署標示為特別用途 (adhoc,linker-signed) 簽署。
184 | .Pp
185 | 指令:
186 | .Pp
187 | .Dl "ldid -S權限.xml -M 檔案"
188 | .Pp
189 | 會把
190 | .Ar 權限.xml
191 | 中的權限加入到已經在
192 | .Ar 檔案
193 | 中的權限。
194 | .Pp
195 | 指令:
196 | .Pp
197 | .Dl "ldid -e 檔案 > 權限.xml"
198 | .Pp
199 | 會把在
200 | .Ar 檔案
201 | 中每一部分的權限儲存到
202 | .Ar 權限.xml
203 | 。
204 | .Sh 另見
205 | .Xr codesign 1
206 | .Sh 歷史
207 | 這個
208 | .Nm
209 | 工具程式是由
210 | .An Jay \*qSaurik\*q Freeman 所編寫的。
211 | 對iPhoneOS 1.2.0 和 2.0 的支援在2008年4月6號被加入。
212 | .Fl S
213 | 在2008年6月13日被加入。
214 | SHA256 支援在2016年8月25日被加入,修正iOS 11支援。
215 | iOS 14支援在2020年7月31日由
216 | .An Kabir Oberai
217 | 加入。
218 | iOS 15支援在2021年6月11日被加入。
219 |
--------------------------------------------------------------------------------
/ldid/ldid.hpp:
--------------------------------------------------------------------------------
1 | #ifndef LDID_HPP
2 | #define LDID_HPP
3 |
4 | /* SPDX-License-Identifier: AGPL-3.0-only */
5 |
6 | #include
7 | #include