├── README.md ├── aleph_bdev_drv ├── .gitignore ├── Makefile ├── README.md ├── flat.ld ├── getsymbols.py └── src │ ├── aleph_bdev_mclass.c │ ├── aleph_bdev_mclass.h │ ├── aleph_block_dev.c │ ├── aleph_block_dev.h │ ├── aleph_fb_dev.c │ ├── aleph_fb_dev.h │ ├── aleph_fb_mclass.c │ ├── aleph_fb_mclass.h │ ├── aleph_fbuc_dev.c │ ├── aleph_fbuc_dev.h │ ├── aleph_fbuc_mclass.c │ ├── aleph_fbuc_mclass.h │ ├── kern_funcs.h │ ├── main.c │ ├── mclass_reg.c │ ├── mclass_reg.h │ ├── qemu-guest-services │ ├── file.c │ └── general.c │ ├── utils.c │ └── utils.h ├── bootstrap_scripts ├── README.md ├── asn1dtredecode.py ├── asn1kerneldecode.py ├── asn1rdskdecode.py ├── create_trustcache.py ├── decompress_lzss.py └── kernelcompressedextractmonitor.py ├── common_hooks ├── include │ ├── ipc-obj.h │ ├── kern_funcs.h │ ├── qemu-guest-services.h │ └── utils.h └── src │ ├── ipc-obj.c │ ├── qemu-guest-services │ ├── file.c │ └── general.c │ └── utils.c ├── function-hooks ├── ipc_kmsg_send │ ├── Makefile │ ├── flat.ld │ ├── getsymbols.py │ ├── kernel.ld │ └── src │ │ └── main.c └── ipc_mqueue_send │ ├── Makefile │ ├── flat.ld │ ├── getsymbols.py │ ├── kernel.ld │ └── src │ └── main.c ├── gdb ├── README.md ├── load.py └── xnu │ ├── KnownLables │ ├── SymbolsNew │ ├── __init__.py │ ├── constants.py │ ├── sys_info.py │ ├── tasks.py │ ├── utils.py │ ├── xnu_types.py │ └── zone.py ├── ghidra ├── ColorAddress.java └── README.md ├── pic-binary ├── .gitignore ├── Makefile ├── README.md ├── flat.ld ├── getsymbols.py └── src │ └── main.c ├── tcp-tunnel ├── .gitignore ├── Makefile ├── README.md ├── ent.xml └── src │ ├── main.c │ └── qemu-guest-services │ ├── fds.c │ ├── general.c │ └── socket.c └── xnu-kvm-lkm ├── Makefile ├── xnu-kvm.c └── xnu-kvm.h /README.md: -------------------------------------------------------------------------------- 1 | 2 | # xnu-qemu-arm64-tools 3 | 4 | 5 | *This repository includes the tools we use to boot/debug iOS kernel above QEMU.* 6 | 7 | ## bootstrap_scripts ## 8 | Python scripts used for extract, decode, decompress the needed files to load the iOS kernel on QEMU. 9 | 10 | ## gdb ## 11 | GDB-Python scripts that enable analysis of the kernel in run time (print threads, tasks, etc) 12 | 13 | ## ghidra ## 14 | Ghidra scripts that we wrote to ease the reverse engineering process. 15 | 16 | ## pic-binary ## 17 | A sample PIC (position-independent code) binary, that can be loaded into kernel memory for execution. 18 | 19 | ## aleph_bdev_drv ## 20 | Custom Block Device Driver that is used to mount two block devices into iOS. 21 | 22 | ## tcp-tunnel ## 23 | Used for tunneling TCP connections into and out of an iOS system emulated on QEMU. 24 | 25 | ## xnu-kvm-lkm ## 26 | Linux kernel module that can be used to run QEMU with KVM, without using a custom kernel with IDSR exits support. 27 | -------------------------------------------------------------------------------- /aleph_bdev_drv/.gitignore: -------------------------------------------------------------------------------- 1 | bin/* 2 | .vscode 3 | kernel.ld 4 | *.swp 5 | *.un~ 6 | -------------------------------------------------------------------------------- /aleph_bdev_drv/Makefile: -------------------------------------------------------------------------------- 1 | src := $(wildcard src/*.c) $(wildcard src/**/*.c) 2 | 3 | ifndef XNU_SOURCES 4 | $(error XNU_SOURCES not set!) 5 | endif 6 | 7 | ifndef KERNEL_SYMBOLS_FILE 8 | $(error KERNEL_SYMBOLS_FILE not set!) 9 | endif 10 | 11 | ifndef QEMU_DIR 12 | $(error QEMU_DIR is not set) 13 | endif 14 | 15 | ifndef NUM_BLOCK_DEVS 16 | $(error NUM_BLOCK_DEVS is not set) 17 | endif 18 | 19 | MKDIR_P = mkdir -p 20 | TARGET_DIR=bin 21 | TARGET = $(TARGET_DIR)/aleph_bdev_drv 22 | CROSS = aarch64-none-elf- 23 | CC = $(CROSS)gcc 24 | OBJCOPY = $(CROSS)objcopy 25 | LDFLAGS = -Wl,-T,flat.ld,-N 26 | DEFINES = -DOUT_OF_TREE_BUILD -DBCM2837 -DKERNEL -DXNU_KERNEL_PRIVATE -D__arm64__ -D__LITTLE_ENDIAN__ -DNUM_BLOCK_DEVS=$(NUM_BLOCK_DEVS) 27 | INCLUDES = -I$(XNU_SOURCES)/bsd \ 28 | -I$(XNU_SOURCES)/osfmk \ 29 | -I$(XNU_SOURCES)/osfmk/libsa \ 30 | -I$(XNU_SOURCES)/libkern \ 31 | -I$(XNU_SOURCES)/pexpert \ 32 | -I$(XNU_SOURCES)/EXTERNAL_HEADERS \ 33 | -I$(QEMU_DIR)/include 34 | CFLAGS = -fpie -flto -fwhole-program -fno-plt -nostdlib -nostartfiles $(DEFINES) $(LDFLAGS) $(INCLUDES) 35 | 36 | default: $(TARGET_DIR) $(TARGET).bin 37 | 38 | $(TARGET_DIR): 39 | @${MKDIR_P} $@ 40 | 41 | $(TARGET).bin: $(TARGET).elf 42 | @echo "Creating a flat binary..." 43 | @$(OBJCOPY) -O binary $^ $@ 44 | 45 | $(TARGET).elf: $(src) kernel.ld 46 | @echo "Building elf from source..." 47 | @$(CC) -o $@ $(CFLAGS) $(src) 48 | 49 | kernel.ld: 50 | @echo "Generating symbols for linker..." 51 | @python3 getsymbols.py $(KERNEL_SYMBOLS_FILE) $@ 52 | 53 | .PHONY: clean 54 | clean: 55 | rm kernel.ld 56 | rm -rf $(TARGET_DIR)* 57 | -------------------------------------------------------------------------------- /aleph_bdev_drv/README.md: -------------------------------------------------------------------------------- 1 | # Custom Block Device Driver for iOS Kernel 2 | 3 | Up until now, we used the Ramdisk as the root mount. The ramdisk block device has two big disadvantages: 4 | 1. No support for disk larger than 1.5 GB. 5 | 2. We have only 1 block device in the system with the Ramdisk, but we need 2: one for the read only root mount and another for the r/w data mount. 6 | 7 | So we decided to write a block device driver by ourselves 8 | 9 | To execute the driver we will hook one of the kernel's functions. 10 | 11 | We will use the same technique that was described in [pic-binary](https://github.com/alephsecurity/xnu-qemu-arm64-tools/blob/master/pic-binary/README.md). 12 | 13 | ### Instructions 14 | 15 | 1. Get the XNU sources from Apple's Github: 16 | ``` 17 | $ git clone https://github.com/apple/darwin-xnu.git 18 | ``` 19 | 2. Get the xnu-qemu-arm64 sources from Aleph: 20 | ``` 21 | $ git clone git@github.com:alephsecurity/xnu-qemu-arm64.git 22 | ``` 23 | 3. Get the xnu-qemu-arm64-tools sources: 24 | ``` 25 | $ git clone git@github.com:alephsecurity/xnu-qemu-arm64-tools.git 26 | ``` 27 | 4. Get the Cross Compiler for AARCH64. We will use the toolchain provided by @github/SergioBenitez: 28 | ``` 29 | $ brew tap SergioBenitez/osxct 30 | $ brew install aarch64-none-elf 31 | ``` 32 | 5. To be able to use the functions from the iOS Kernel within the driver code, we need to link the driver along with the symbols from the kernel. We can extract the symbols with `nm` and use them for this linkage process. 33 | ``` 34 | $ nm kernelcache.release.n66.out > symbols.nm 35 | ``` 36 | 37 | 6. Create the Environment Variables 38 | ``` 39 | $ export XNU_SOURCES=full_path_to_darwin-xnu 40 | $ export KERNEL_SYMBOLS_FILE=full_path_to_symbols.nm 41 | $ export QEMU_DIR=full_path_to_xnu-qemu-arm64 42 | $ export NUM_BLOCK_DEVS=2 43 | ``` 44 | 7. Build 45 | ``` 46 | $ make -C xnu-qemu-arm64-tools/aleph_bdev_drv 47 | ``` 48 | 49 | The compilation process generates a flat `bin/aleph_bdev_drv.bin` binary, the compiled code of the driver. 50 | 51 | Now that we have the driver compiled we can use it with the hook mechanism implemented in the [alephsecurity/xnu-qemu-arm64](https://github.com/alephsecurity/xnu-qemu-arm64) 52 | -------------------------------------------------------------------------------- /aleph_bdev_drv/flat.ld: -------------------------------------------------------------------------------- 1 | PHDRS 2 | { 3 | text PT_LOAD; 4 | } 5 | 6 | ENTRY(_start) 7 | 8 | SECTIONS 9 | { 10 | /* Kernel functions */ 11 | INCLUDE kernel.ld 12 | 13 | .start : { *(.start) } :text 14 | .text : { *(.text) } 15 | } -------------------------------------------------------------------------------- /aleph_bdev_drv/getsymbols.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import csv 4 | import sys 5 | 6 | def nm2ld(in_file, out_file): 7 | symbols = open(in_file).read() 8 | writer = open(out_file, 'wt') 9 | 10 | for symbol in symbols.splitlines(): 11 | name = symbol.split(" ")[2] 12 | location = symbol.split(" ")[0] 13 | 14 | if name.startswith('_'): 15 | name = name[1:] 16 | 17 | print(f"PROVIDE ({name} = 0x{location});", file=writer) 18 | 19 | def main(): 20 | if len(sys.argv) not in (2, 3): 21 | print("Usage: python3 getsymbols.py [kernel-symbols-ld-provider]") 22 | sys.exit(1) 23 | 24 | in_file = sys.argv[1] 25 | out_file = sys.argv[2] if len(sys.argv) == 3 else "kernel.ld" 26 | 27 | nm2ld(in_file, out_file) 28 | 29 | if __name__ == "__main__": 30 | main() 31 | -------------------------------------------------------------------------------- /aleph_bdev_drv/src/aleph_bdev_mclass.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jonathan Afek 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | #include "aleph_bdev_mclass.h" 27 | #include "kern_funcs.h" 28 | #include "aleph_block_dev.h" 29 | #include "utils.h" 30 | #include "mclass_reg.h" 31 | 32 | #include "hw/arm/guest-services/general.h" 33 | 34 | static void *bdev_vtable[BDEV_VTABLE_SIZE]; 35 | static MetaClassVTable bdev_meta_class_vtable; 36 | 37 | 38 | void create_bdev_vtable(void) 39 | { 40 | memcpy(&bdev_vtable[0], 41 | (void *)IOBLOCKSTORAGEDEVICE_VTABLE_PTR, 42 | sizeof(bdev_vtable)); 43 | bdev_vtable[IOSERVICE_GETMCLASS_INDEX] = 44 | &AlephBlockDevice_getMetaClass; 45 | bdev_vtable[IOSTORAGEBDEV_GETVENDORSTRING_INDEX] = 46 | &AlephBlockDevice_getVendorString; 47 | bdev_vtable[IOSTORAGEBDEV_GETPRODUCTSTRING_INDEX] = 48 | &AlephBlockDevice_getProductString; 49 | bdev_vtable[IOSTORAGEBDEV_REPORTBSIZE_INDEX] = 50 | &AlephBlockDevice_reportBlockSize; 51 | bdev_vtable[IOSTORAGEBDEV_REPORTMAXVALIDBLOCK_INDEX] = 52 | &AlephBlockDevice_reportMaxValidBlock; 53 | bdev_vtable[IOSTORAGEBDEV_REPORTMEDIASTATE_INDEX] = 54 | &AlephBlockDevice_reportMediaState; 55 | bdev_vtable[IOSTORAGEBDEV_REPORTREMOVABILITY_INDEX] = 56 | &AlephBlockDevice_reportRemovability; 57 | bdev_vtable[IOSTORAGEBDEV_SOMEFUNC3_INDEX] = 58 | &AlephBlockDevice_somefunc3; 59 | bdev_vtable[IOSTORAGEBDEV_DOASYNCREADWRITE_INDEX] = 60 | &AlephBlockDevice_doAsyncReadWrite; 61 | } 62 | 63 | void *bdev_alloc(void) 64 | { 65 | ObjConstructor ioblockstoragedevice_constructor; 66 | ioblockstoragedevice_constructor = 67 | (ObjConstructor)IOBLOCKSTORAGEDEVICE_CONSTRUCTOR_FUNC_PTR; 68 | 69 | void **obj = OSObject_new(ALEPH_BDEV_SIZE); 70 | ioblockstoragedevice_constructor(obj); 71 | obj[0] = &bdev_vtable[0]; 72 | OSMetaClass_instanceConstructed(get_bdev_mclass_inst()); 73 | return obj; 74 | } 75 | 76 | void create_bdev_metaclass_vtable(void) 77 | { 78 | memcpy(&bdev_meta_class_vtable, 79 | (void *)IOBLOCKSTORAGEDEVICE_MCLASS_VTABLE_PTR, 80 | sizeof(MetaClassVTable)); 81 | bdev_meta_class_vtable.alloc = bdev_alloc; 82 | } 83 | 84 | void register_bdev_meta_class() 85 | { 86 | mclass_reg_slock_lock(); 87 | 88 | create_bdev_vtable(); 89 | create_bdev_metaclass_vtable(); 90 | 91 | void **mc = OSMetaClass_OSMetaClass(get_bdev_mclass_inst(), 92 | BDEV_CLASS_NAME, 93 | (void *)IOBLOCKSTORAGEDEVICE_MCLASS_INST_PTR, 94 | ALEPH_BDEV_SIZE); 95 | if (NULL == mc) { 96 | cancel(); 97 | } 98 | mc[0] = &bdev_meta_class_vtable; 99 | 100 | mclass_reg_alock_lock(); 101 | 102 | add_to_classes_dict(BDEV_CLASS_NAME, mc); 103 | 104 | mclass_reg_alock_unlock(); 105 | mclass_reg_slock_unlock(); 106 | 107 | } 108 | -------------------------------------------------------------------------------- /aleph_bdev_drv/src/aleph_bdev_mclass.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jonathan Afek 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef ALEPH_BDEV_MCLASS_H 24 | #define ALEPH_BDEV_MCLASS_H 25 | 26 | //not sure what the original vtable size is, use this for now 27 | #define BDEV_VTABLE_SIZE (0x1000) 28 | 29 | void create_bdev_vtable(void); 30 | void create_bdev_metaclass_vtable(void); 31 | void register_bdev_meta_class(); 32 | 33 | //our driver metaclass virtual functions 34 | void *bdev_alloc(void); 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /aleph_bdev_drv/src/aleph_block_dev.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jonathan Afek 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | #include "aleph_block_dev.h" 27 | #include "aleph_bdev_mclass.h" 28 | #include "kern_funcs.h" 29 | #include "utils.h" 30 | #include "mclass_reg.h" 31 | 32 | #include "hw/arm/guest-services/general.h" 33 | 34 | static uint8_t aleph_bdev_meta_class_inst[ALEPH_MCLASS_SIZE]; 35 | 36 | AlephBDevMembers *get_bdev_members(void *bdev) 37 | { 38 | AlephBDevMembers *members; 39 | members = (AlephBDevMembers *)&((uint8_t *)bdev)[ALEPH_BDEV_MEMBERS_OFFSET]; 40 | return members; 41 | } 42 | 43 | void *get_bdev_buffer(void *bdev) 44 | { 45 | return (void *)&(((uint8_t *)bdev)[ALEPH_BDEV_BUFFER_OFFSET]); 46 | } 47 | 48 | void *get_bdev_mclass_inst(void) 49 | { 50 | return (void *)&aleph_bdev_meta_class_inst[0]; 51 | } 52 | 53 | //virtual functions of our driver 54 | 55 | void *AlephBlockDevice_getMetaClass(void *this) 56 | { 57 | return get_bdev_mclass_inst(); 58 | } 59 | 60 | uint64_t AlephBlockDevice_reportRemovability(void *this, char *isRemovable) 61 | { 62 | *isRemovable = 0; 63 | return 0; 64 | } 65 | 66 | uint64_t AlephBlockDevice_reportMediaState(void *this, 67 | char *mediaPresent, 68 | char *changedState) 69 | { 70 | *mediaPresent = 1; 71 | *changedState = 0; 72 | return 0; 73 | } 74 | 75 | uint64_t AlephBlockDevice_reportBlockSize(void *this, uint64_t *param) 76 | { 77 | *param = BLOCK_SIZE; 78 | return 0; 79 | } 80 | 81 | uint64_t AlephBlockDevice_reportMaxValidBlock(void *this, uint64_t *param) 82 | { 83 | AlephBDevMembers *members = get_bdev_members(this); 84 | *param = members->block_count - 1; 85 | return 0; 86 | } 87 | 88 | //could be reportLockability or reportWriteProtection? 89 | uint64_t AlephBlockDevice_somefunc3(void *this, char *param) 90 | { 91 | *param = 0; 92 | return 0; 93 | } 94 | 95 | char *AlephBlockDevice_getVendorString(void *this) 96 | { 97 | AlephBDevMembers *members = get_bdev_members(this); 98 | return &members->vendor_name[0]; 99 | } 100 | 101 | char *AlephBlockDevice_getProductString(void *this) 102 | { 103 | AlephBDevMembers *members = get_bdev_members(this); 104 | return &members->product_name[0]; 105 | } 106 | 107 | uint64_t AlephBlockDevice_doAsyncReadWrite(void *this, void **buffer, 108 | uint64_t block, uint64_t nblks, 109 | void *attrs, void **completion) 110 | { 111 | uint64_t i = 0; 112 | void *dev_buf = get_bdev_buffer(this); 113 | AlephBDevMembers *members = get_bdev_members(this); 114 | 115 | lck_mtx_lock(members->lck_mtx); 116 | 117 | void **buffer_vtable = buffer[0]; 118 | FuncIOMemDescGetDirection get_dir_f = 119 | (FuncIOMemDescGetDirection)buffer_vtable[IOMEMDESCGETDIRECTION_INDEX]; 120 | FuncIOMemDescReadBytes read_bytes_f = 121 | (FuncIOMemDescReadBytes)buffer_vtable[IOMEMDESCREADBYTES_INDEX]; 122 | FuncIOMemDescWriteBytes write_bytes_f = 123 | (FuncIOMemDescWriteBytes)buffer_vtable[IOMEMDESCWRITEBYTES_INDEX]; 124 | 125 | uint64_t direction = get_dir_f(buffer); 126 | 127 | uint64_t byte_count = 0; 128 | uint64_t offset = 0; 129 | uint64_t length = 0; 130 | 131 | if (kIODirectionIn == direction) { 132 | for (i = 0; i < nblks; i++) { 133 | offset = BLOCK_SIZE * (i + block); 134 | length = BLOCK_SIZE; 135 | if ((offset + length) > members->size) { 136 | length = members->size - offset; 137 | } 138 | if ((offset + length) >= members->size + BLOCK_SIZE) { 139 | cancel(); 140 | } 141 | 142 | qc_read_file(dev_buf, length, offset, members->qc_file_index); 143 | byte_count += write_bytes_f(buffer, (i * BLOCK_SIZE), 144 | dev_buf, length); 145 | } 146 | } else if (kIODirectionOut == direction) { 147 | for (i = 0; i < nblks; i++) { 148 | offset = BLOCK_SIZE * (i + block); 149 | length = BLOCK_SIZE; 150 | if ((offset + length) > members->size) { 151 | length = members->size - offset; 152 | } 153 | if ((offset + length) >= members->size + BLOCK_SIZE) { 154 | cancel(); 155 | } 156 | 157 | byte_count += read_bytes_f(buffer, (i * BLOCK_SIZE), 158 | dev_buf, length); 159 | qc_write_file(dev_buf, length, offset, members->qc_file_index); 160 | } 161 | } else { 162 | cancel(); 163 | } 164 | 165 | if (NULL != completion) { 166 | FuncCompletionAction comp_act_f = (FuncCompletionAction)completion[1]; 167 | comp_act_f((uint64_t)completion[0], (uint64_t)completion[2], 0, 168 | byte_count); 169 | } 170 | 171 | lck_mtx_unlock(members->lck_mtx); 172 | return 0; 173 | } 174 | 175 | void create_new_aleph_bdev(const char *prod_name, const char *vendor_name, 176 | const char *mutex_name, uint64_t bdev_file_index, 177 | void *parent_service) 178 | { 179 | //TODO: release this object ref? 180 | void *bdev = OSMetaClass_allocClassWithName(BDEV_CLASS_NAME); 181 | if (NULL == bdev) { 182 | cancel(); 183 | } 184 | void **vtable_ptr = (void **)*(uint64_t *)bdev; 185 | 186 | FuncIOServiceInit vfunc_init = 187 | (FuncIOServiceInit)vtable_ptr[IOSERVICE_INIT_INDEX]; 188 | vfunc_init(bdev, NULL); 189 | 190 | AlephBDevMembers *members = get_bdev_members(bdev); 191 | members->qc_file_index = bdev_file_index; 192 | strncpy(&members->product_name[0], prod_name, VENDOR_NAME_SIZE); 193 | strncpy(&members->vendor_name[0], vendor_name, VENDOR_NAME_SIZE); 194 | members->vendor_name[0] += bdev_file_index; 195 | strncpy(&members->mutex_name[0], mutex_name, VENDOR_NAME_SIZE); 196 | members->mutex_name[0] += bdev_file_index; 197 | members->mtx_grp = lck_grp_alloc_init(&members->mutex_name[0], NULL); 198 | members->lck_mtx = lck_mtx_alloc_init(members->mtx_grp, NULL); 199 | members->size = qc_size_file(bdev_file_index); 200 | members->block_count = (members->size + BLOCK_SIZE - 1) / BLOCK_SIZE; 201 | 202 | if (NULL == parent_service) { 203 | cancel(); 204 | } 205 | 206 | FuncIOServiceAttach vfunc_attach = 207 | (FuncIOServiceAttach)vtable_ptr[IOSERVICE_ATTACH_INDEX]; 208 | vfunc_attach(bdev, parent_service); 209 | 210 | FuncIOSerivceRegisterService vfunc_reg_service = 211 | (FuncIOSerivceRegisterService)vtable_ptr[IOSERVICE_REG_SERVICE_INDEX]; 212 | vfunc_reg_service(bdev, 0); 213 | } 214 | -------------------------------------------------------------------------------- /aleph_bdev_drv/src/aleph_block_dev.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jonathan Afek 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef ALEPH_BLOCK_DEV_H 24 | #define ALEPH_BLOCK_DEV_H 25 | 26 | #define ALEPH_BDEV_MEMBERS_OFFSET (0x800) 27 | #define ALEPH_BDEV_BUFFER_OFFSET (0x1000) 28 | #define ALEPH_BDEV_BUFFER_SIZE (0x1000) 29 | //just in case. IOBlockStorageDevice is of size 0x90 30 | #define ALEPH_BDEV_SIZE (0x2000) 31 | 32 | #define BLOCK_SIZE (0x1000) 33 | 34 | #define BDEV_CLASS_NAME "AlephStorageBlockDevice" 35 | 36 | #define VENDOR_NAME_SIZE (64) 37 | 38 | typedef struct { 39 | void *mtx_grp; 40 | void *lck_mtx; 41 | uint64_t size; 42 | uint64_t block_count; 43 | uint64_t qc_file_index; 44 | char vendor_name[VENDOR_NAME_SIZE]; 45 | char product_name[VENDOR_NAME_SIZE]; 46 | char mutex_name[VENDOR_NAME_SIZE]; 47 | } AlephBDevMembers; 48 | 49 | AlephBDevMembers *get_bdev_members(void *bdev); 50 | void *get_bdev_buffer(void *bdev); 51 | void *get_bdev_mclass_inst(void); 52 | 53 | //our driver virtual functions 54 | void *AlephBlockDevice_getMetaClass(void *this); 55 | uint64_t AlephBlockDevice_reportRemovability(void *this, char *isRemovable); 56 | uint64_t AlephBlockDevice_reportMediaState(void *this, 57 | char *mediaPresent, 58 | char *changedState); 59 | uint64_t AlephBlockDevice_reportBlockSize(void *this, uint64_t *param); 60 | uint64_t AlephBlockDevice_reportMaxValidBlock(void *this, uint64_t *param); 61 | uint64_t AlephBlockDevice_somefunc3(void *this, char *param); 62 | char *AlephBlockDevice_getVendorString(void *this); 63 | char *AlephBlockDevice_getProductString(void *this); 64 | uint64_t AlephBlockDevice_doAsyncReadWrite(void *this, void **buffer, 65 | uint64_t block, uint64_t nblks, 66 | void *attrs, void **completion); 67 | 68 | //used for the last param of the AlephBlockDevice_doAsyncReadWrite() func 69 | typedef void (*FuncCompletionAction)(uint64_t p1, uint64_t p2, 70 | uint64_t p3, uint64_t p4); 71 | 72 | //IOStorageBlockDevice virtual function indices 73 | 74 | #define IOSTORAGEBDEV_GETVENDORSTRING_INDEX (171) 75 | #define IOSTORAGEBDEV_GETPRODUCTSTRING_INDEX (172) 76 | #define IOSTORAGEBDEV_REPORTBSIZE_INDEX (175) 77 | #define IOSTORAGEBDEV_REPORTMAXVALIDBLOCK_INDEX (177) 78 | #define IOSTORAGEBDEV_REPORTMEDIASTATE_INDEX (178) 79 | #define IOSTORAGEBDEV_REPORTREMOVABILITY_INDEX (179) 80 | #define IOSTORAGEBDEV_SOMEFUNC3_INDEX (180) 81 | #define IOSTORAGEBDEV_DOASYNCREADWRITE_INDEX (183) 82 | 83 | void create_new_aleph_bdev(const char *prod_name, const char *vendor_name, 84 | const char *mutex_name, uint64_t bdev_file_index, 85 | void *parent_service); 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /aleph_bdev_drv/src/aleph_fb_dev.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jonathan Afek 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | #include "aleph_fb_dev.h" 27 | #include "aleph_fb_mclass.h" 28 | #include "aleph_fbuc_dev.h" 29 | #include "kern_funcs.h" 30 | #include "utils.h" 31 | #include "mclass_reg.h" 32 | 33 | #include "hw/arm/guest-services/general.h" 34 | 35 | static uint8_t aleph_fb_meta_class_inst[ALEPH_MCLASS_SIZE]; 36 | 37 | //typedef struct { 38 | // void *fbdev; 39 | // void *parent_service; 40 | //} StartFBParams; 41 | // 42 | //static StartFBParams start_fb_params; 43 | 44 | void *get_fb_mclass_inst(void) 45 | { 46 | return (void *)&aleph_fb_meta_class_inst[0]; 47 | } 48 | 49 | //TODO: for the UC class override the external method method just for printing 50 | //can debug with setting bp on memory access to UC vtable and return the 51 | //usermode afterwards in GDB 52 | 53 | //TODO: understand the process of inheritance from UC - probably the same or similar but must review first 54 | 55 | //TODO: should probably get the IOSurfaceRoot service, save it and return it in the relevant external method/trap 56 | 57 | //virtual functions of our driver 58 | void *AlephFramebufferDevice_getMetaClass(void *this) 59 | { 60 | return get_fb_mclass_inst(); 61 | } 62 | 63 | 64 | //void start_new_aleph_fbdev(StartFBParams *sfb_params) 65 | //{ 66 | // void **vtable_ptr = (void **)*(uint64_t *)sfb_params->fbdev; 67 | // FuncIOSerivceStart vfunc_start = 68 | // (FuncIOSerivceStart)vtable_ptr[IOSERVICE_START_INDEX]; 69 | // vfunc_start(sfb_params->fbdev, sfb_params->parent_service); 70 | //} 71 | 72 | void create_new_aleph_fbdev(void *parent_service) 73 | { 74 | //TODO: release this object ref? 75 | void *fbdev = OSMetaClass_allocClassWithName(FBDEV_CLASS_NAME); 76 | if (NULL == fbdev) { 77 | cancel(); 78 | } 79 | void **vtable_ptr = (void **)*(uint64_t *)fbdev; 80 | 81 | FuncIOServiceInit vfunc_init = 82 | (FuncIOServiceInit)vtable_ptr[IOSERVICE_INIT_INDEX]; 83 | vfunc_init(fbdev, NULL); 84 | 85 | if (NULL == parent_service) { 86 | cancel(); 87 | } 88 | FuncIOServiceSetProperty vfunc_sprop = 89 | (FuncIOServiceSetProperty)vtable_ptr[IOSERVICE_SET_PROPERTY_INDEX]; 90 | vfunc_sprop(fbdev, "IOUserClientClass", FBUC_CLASS_NAME); 91 | 92 | FuncIOServiceAttach vfunc_attach = 93 | (FuncIOServiceAttach)vtable_ptr[IOSERVICE_ATTACH_INDEX]; 94 | vfunc_attach(fbdev, parent_service); 95 | 96 | //FuncIOSerivceStart vfunc_start = 97 | // (FuncIOSerivceStart)vtable_ptr[IOSERVICE_START_INDEX]; 98 | //vfunc_start(fbdev, parent_service); 99 | FuncIOSerivceRegisterService vfunc_reg_service = 100 | (FuncIOSerivceRegisterService)vtable_ptr[IOSERVICE_REG_SERVICE_INDEX]; 101 | vfunc_reg_service(fbdev, 0); 102 | 103 | //uint64_t unused; 104 | //start_fb_params.fbdev = fbdev; 105 | //start_fb_params.parent_service = parent_service; 106 | //kernel_thread_start(&start_new_aleph_fbdev, &start_fb_params, &unused); 107 | } 108 | -------------------------------------------------------------------------------- /aleph_bdev_drv/src/aleph_fb_dev.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jonathan Afek 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef ALEPH_FB_DEV_H 24 | #define ALEPH_FB_DEV_H 25 | 26 | //just in case. 27 | #define ALEPH_FBDEV_SIZE (0x2000) 28 | 29 | #define FBDEV_CLASS_NAME "IOMobileFramebuffer" 30 | 31 | void *get_fb_mclass_inst(void); 32 | 33 | //our driver virtual functions 34 | void *AlephFramebufferDevice_getMetaClass(void *this); 35 | 36 | void create_new_aleph_fbdev(void *parent_service); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /aleph_bdev_drv/src/aleph_fb_mclass.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jonathan Afek 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | #include "aleph_fb_mclass.h" 27 | #include "kern_funcs.h" 28 | #include "aleph_fb_dev.h" 29 | #include "utils.h" 30 | #include "mclass_reg.h" 31 | 32 | #include "hw/arm/guest-services/general.h" 33 | 34 | static void *fb_vtable[FB_VTABLE_SIZE]; 35 | static MetaClassVTable fb_meta_class_vtable; 36 | 37 | void create_fb_vtable(void) 38 | { 39 | memcpy(&fb_vtable[0], 40 | (void *)IOSERVICE_VTABLE_PTR, 41 | sizeof(fb_vtable)); 42 | fb_vtable[IOSERVICE_GETMCLASS_INDEX] = &AlephFramebufferDevice_getMetaClass; 43 | } 44 | 45 | void *fb_alloc(void) 46 | { 47 | void **obj = OSObject_new(ALEPH_FBDEV_SIZE); 48 | IOService_IOService(obj, get_fb_mclass_inst()); 49 | obj[0] = &fb_vtable[0]; 50 | OSMetaClass_instanceConstructed(get_fb_mclass_inst()); 51 | return obj; 52 | } 53 | 54 | void create_fb_metaclass_vtable(void) 55 | { 56 | memcpy(&fb_meta_class_vtable, (void *)IOSERVICE_MCLASS_VTABLE_PTR, 57 | sizeof(MetaClassVTable)); 58 | fb_meta_class_vtable.alloc = fb_alloc; 59 | } 60 | 61 | void register_fb_meta_class() 62 | { 63 | mclass_reg_slock_lock(); 64 | 65 | create_fb_vtable(); 66 | create_fb_metaclass_vtable(); 67 | 68 | void **mc = OSMetaClass_OSMetaClass(get_fb_mclass_inst(), 69 | FBDEV_CLASS_NAME, 70 | (void *)IOSERVICE_MCLASS_INST_PTR, 71 | ALEPH_FBDEV_SIZE); 72 | if (NULL == mc) { 73 | cancel(); 74 | } 75 | mc[0] = &fb_meta_class_vtable; 76 | 77 | mclass_reg_alock_lock(); 78 | 79 | add_to_classes_dict(FBDEV_CLASS_NAME, mc); 80 | 81 | mclass_reg_alock_unlock(); 82 | mclass_reg_slock_unlock(); 83 | } 84 | -------------------------------------------------------------------------------- /aleph_bdev_drv/src/aleph_fb_mclass.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jonathan Afek 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef ALEPH_FB_MCLASS_H 24 | #define ALEPH_FB_MCLASS_H 25 | 26 | //not sure what the original vtable size is, use this for now 27 | #define FB_VTABLE_SIZE (0x1000) 28 | 29 | void create_fb_vtable(void); 30 | void create_fb_metaclass_vtable(void); 31 | void register_fb_meta_class(); 32 | 33 | //our driver metaclass virtual functions 34 | void *fb_alloc(void); 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /aleph_bdev_drv/src/aleph_fbuc_dev.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jonathan Afek 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | #include "aleph_fbuc_dev.h" 27 | #include "aleph_fbuc_mclass.h" 28 | #include "kern_funcs.h" 29 | #include "utils.h" 30 | #include "mclass_reg.h" 31 | 32 | #include "hw/arm/guest-services/general.h" 33 | 34 | 35 | static uint8_t aleph_fbuc_meta_class_inst[ALEPH_MCLASS_SIZE]; 36 | 37 | void *get_fbuc_mclass_inst(void) 38 | { 39 | return (void *)&aleph_fbuc_meta_class_inst[0]; 40 | } 41 | 42 | static FBUCMembers *get_fbuc_members(void *fbuc) 43 | { 44 | FBUCMembers *members; 45 | members = (FBUCMembers *)&((uint8_t *)fbuc)[FBUC_MEMBERS_OFFSET]; 46 | return members; 47 | } 48 | 49 | static void fbuc_install_external_method(void *fbuc, 50 | IOExternalMethodAction func, 51 | uint64_t index, 52 | uint32_t scic, 53 | uint32_t stic, 54 | uint32_t scoc, 55 | uint32_t stoc) 56 | { 57 | if (index >= FBUC_MAX_EXT_FUNCS) { 58 | cancel(); 59 | } 60 | FBUCMembers *members = get_fbuc_members(fbuc); 61 | members->fbuc_external_methods[index].function = func; 62 | members->fbuc_external_methods[index].checkScalarInputCount = scic; 63 | members->fbuc_external_methods[index].checkStructureInputSize = stic; 64 | members->fbuc_external_methods[index].checkScalarOutputCount = scoc; 65 | members->fbuc_external_methods[index].checkStructureOutputSize = stoc; 66 | } 67 | 68 | static uint64_t fbuc_ext_meth_get_layer_default_sur(void *target, 69 | void *reference, 70 | IOExternalMethodArguments *arguments) 71 | { 72 | arguments->scalarOutput[0] = 1; 73 | return 0; 74 | } 75 | 76 | static uint64_t fbuc_ext_meth_swap_begin(void *target, void *reference, 77 | IOExternalMethodArguments *arguments) 78 | { 79 | arguments->scalarOutput[0] = 1; 80 | return 0; 81 | } 82 | 83 | static uint64_t fbuc_ext_meth_swap_end(void *target, void *reference, 84 | IOExternalMethodArguments *arguments) 85 | { 86 | return 0; 87 | } 88 | 89 | static uint64_t fbuc_ext_meth_swap_wait(void *target, void *reference, 90 | IOExternalMethodArguments *arguments) 91 | { 92 | return 0; 93 | } 94 | 95 | static uint64_t fbuc_ext_meth_get_id(void *target, void *reference, 96 | IOExternalMethodArguments *arguments) 97 | { 98 | arguments->scalarOutput[0] = 2; 99 | return 0; 100 | } 101 | 102 | static uint64_t fbuc_ext_meth_get_disp_size(void *target, void *reference, 103 | IOExternalMethodArguments *arguments) 104 | { 105 | //TODO: get this input somehow 106 | arguments->scalarOutput[0] = 600; 107 | arguments->scalarOutput[1] = 800; 108 | return 0; 109 | } 110 | 111 | static uint64_t fbuc_ext_meth_req_power_change(void *target, void *reference, 112 | IOExternalMethodArguments *arguments) 113 | { 114 | return 0; 115 | } 116 | 117 | static uint64_t fbuc_ext_meth_set_debug_flags(void *target, void *reference, 118 | IOExternalMethodArguments *arguments) 119 | { 120 | arguments->scalarOutput[0] = 1; 121 | return 0; 122 | } 123 | 124 | static uint64_t fbuc_ext_meth_set_gamma_table(void *target, 125 | void *reference, 126 | IOExternalMethodArguments *arguments) 127 | { 128 | return 0; 129 | } 130 | 131 | static uint64_t fbuc_ext_meth_is_main_disp(void *target, void *reference, 132 | IOExternalMethodArguments *arguments) 133 | { 134 | arguments->scalarOutput[0] = 1; 135 | return 0; 136 | } 137 | 138 | static uint64_t fbuc_ext_meth_set_display_dev(void *target, void *reference, 139 | IOExternalMethodArguments *arguments) 140 | { 141 | return 0; 142 | } 143 | 144 | static uint64_t fbuc_ext_meth_get_gamma_table(void *target, 145 | void *reference, 146 | IOExternalMethodArguments *arguments) 147 | { 148 | for (int i = 0; i < arguments->structureOutputSize; i++) { 149 | ((uint8_t *)arguments->structureOutput)[i] = 0x7f; 150 | } 151 | return 0; 152 | } 153 | 154 | static uint64_t fbuc_ext_meth_get_dot_pitch(void *target, 155 | void *reference, 156 | IOExternalMethodArguments *arguments) 157 | { 158 | //arguments->scalarOutput[0] = 152; 159 | arguments->scalarOutput[0] = 0; 160 | //TODO: get this input somehow 161 | return 0; 162 | } 163 | 164 | static uint64_t fbuc_ext_meth_en_dis_vid_power_save(void *target, 165 | void *reference, 166 | IOExternalMethodArguments *arguments) 167 | { 168 | return 0; 169 | } 170 | 171 | static uint64_t fbuc_ext_meth_surface_is_rep(void *target, 172 | void *reference, 173 | IOExternalMethodArguments *arguments) 174 | { 175 | arguments->scalarOutput[0] = 1; 176 | return 0; 177 | } 178 | 179 | static uint64_t fbuc_ext_meth_set_bright_corr(void *target, 180 | void *reference, 181 | IOExternalMethodArguments *arguments) 182 | { 183 | return 0; 184 | } 185 | 186 | static uint64_t fbuc_ext_meth_set_matrix(void *target, 187 | void *reference, 188 | IOExternalMethodArguments *arguments) 189 | { 190 | return 0; 191 | } 192 | 193 | static uint64_t fbuc_ext_meth_get_color_remap_mode(void *target, 194 | void *reference, 195 | IOExternalMethodArguments *arguments) 196 | { 197 | arguments->scalarOutput[0] = 6; 198 | //TODO: this might need to be changed. not sure what the numbers mean 199 | //arguments->scalarOutput[0] = 6; 200 | return 0; 201 | } 202 | 203 | static uint64_t fbuc_ext_meth_set_parameter(void *target, 204 | void *reference, 205 | IOExternalMethodArguments *arguments) 206 | { 207 | return 0; 208 | } 209 | 210 | static uint64_t fbuc_ext_meth_enable_notifications(void *target, 211 | void *reference, 212 | IOExternalMethodArguments *arguments) 213 | { 214 | //TODO: actually implement this to enable tofications 215 | FBUCMembers *members = get_fbuc_members(target); 216 | uint64_t cb = arguments->scalarInput[0]; 217 | uint64_t ref = arguments->scalarInput[1]; 218 | uint64_t type = arguments->scalarInput[2]; 219 | IOUserClient_setAsyncReference64(&members->notif_ports[type].asnyc_ref64[0], 220 | members->notif_ports[type].port, 221 | cb, ref, members->task); 222 | return 0; 223 | } 224 | 225 | static uint64_t fbuc_ext_meth_change_frame_info(void *target, 226 | void *reference, 227 | IOExternalMethodArguments *arguments) 228 | { 229 | //TODO: actually implement this 230 | FBUCMembers *members = get_fbuc_members(target); 231 | 232 | //uint64_t args[2]; 233 | //uint64_t type = arguments->scalarInput[0]; 234 | //args[0] = type; 235 | //args[1] = arguments->scalarInput[1]; 236 | //IOUserClient_sendAsyncResult64(&members->notif_ports[type].asnyc_ref64[0], 237 | // 0, &args[0], 2); 238 | uint64_t args[6]; 239 | uint64_t type = arguments->scalarInput[0]; 240 | args[0] = 5; 241 | args[1] = 6; 242 | args[2] = 7; 243 | args[3] = 8; 244 | args[4] = 9; 245 | args[5] = 10; 246 | IOUserClient_sendAsyncResult64(&members->notif_ports[type].asnyc_ref64[0], 247 | 0, &args[0], 6); 248 | return 0; 249 | } 250 | 251 | static uint64_t fbuc_ext_meth_supported_frame_info(void *target, 252 | void *reference, 253 | IOExternalMethodArguments *arguments) 254 | { 255 | 256 | //Ugly trick we have to do because of how we compile this code 257 | switch (arguments->scalarInput[0]) 258 | { 259 | case 0: 260 | strncpy(arguments->structureOutput, "Blend_CRC", 261 | arguments->structureOutputSize); 262 | break; 263 | case 1: 264 | strncpy(arguments->structureOutput, "Dither_CRC", 265 | arguments->structureOutputSize); 266 | break; 267 | case 2: 268 | strncpy(arguments->structureOutput, "Presentation_time", 269 | arguments->structureOutputSize); 270 | break; 271 | case 3: 272 | strncpy(arguments->structureOutput, "Presentation_delta", 273 | arguments->structureOutputSize); 274 | break; 275 | case 4: 276 | strncpy(arguments->structureOutput, "Requested_presentation", 277 | arguments->structureOutputSize); 278 | break; 279 | case 5: 280 | strncpy(arguments->structureOutput, "Performance_headroom", 281 | arguments->structureOutputSize); 282 | break; 283 | case 6: 284 | strncpy(arguments->structureOutput, "Thermal_throttle", 285 | arguments->structureOutputSize); 286 | break; 287 | case 7: 288 | strncpy(arguments->structureOutput, "Flags", 289 | arguments->structureOutputSize); 290 | break; 291 | default: 292 | cancel(); 293 | } 294 | 295 | arguments->scalarOutput[0] = 8; 296 | return 0; 297 | } 298 | 299 | //virtual functions of our driver 300 | void *fbuc_getMetaClass(void *this) 301 | { 302 | return get_fbuc_mclass_inst(); 303 | } 304 | 305 | uint64_t fbuc_start(void *this) 306 | { 307 | fbuc_install_external_method(this, &fbuc_ext_meth_get_layer_default_sur, 308 | 3, 2, 0, 1, 0); 309 | fbuc_install_external_method(this, &fbuc_ext_meth_swap_begin, 310 | 4, 0, 0, 1, 0); 311 | fbuc_install_external_method(this, &fbuc_ext_meth_swap_end, 312 | 5, 0, -1, 0, 0); 313 | fbuc_install_external_method(this, &fbuc_ext_meth_swap_wait, 314 | 6, 3, 0, 0, 0); 315 | fbuc_install_external_method(this, &fbuc_ext_meth_get_id, 7, 0, 0, 1, 0); 316 | fbuc_install_external_method(this, &fbuc_ext_meth_get_disp_size, 317 | 8, 0, 0, 2, 0); 318 | fbuc_install_external_method(this, &fbuc_ext_meth_req_power_change, 319 | 12, 1, 0, 0, 0); 320 | fbuc_install_external_method(this, &fbuc_ext_meth_set_debug_flags, 321 | 15, 2, 0, 1, 0); 322 | fbuc_install_external_method(this, &fbuc_ext_meth_set_gamma_table, 323 | 17, 0, 3084, 0, 0); 324 | fbuc_install_external_method(this, &fbuc_ext_meth_is_main_disp, 325 | 18, 0, 0, 1, 0); 326 | fbuc_install_external_method(this, &fbuc_ext_meth_set_display_dev, 327 | 22, 1, 0, 0, 0); 328 | fbuc_install_external_method(this, &fbuc_ext_meth_get_gamma_table, 329 | 27, 0, 0, 0, 3084); 330 | fbuc_install_external_method(this, &fbuc_ext_meth_get_dot_pitch, 331 | 28, 0, 0, 1, 0); 332 | fbuc_install_external_method(this, &fbuc_ext_meth_en_dis_vid_power_save, 333 | 33, 1, 0, 0, 0); 334 | fbuc_install_external_method(this, &fbuc_ext_meth_surface_is_rep, 335 | 49, 1, 0, 1, 0); 336 | fbuc_install_external_method(this, &fbuc_ext_meth_set_bright_corr, 337 | 50, 1, 0, 0, 0); 338 | fbuc_install_external_method(this, &fbuc_ext_meth_set_matrix, 339 | 55, 1, 72, 0, 0); 340 | fbuc_install_external_method(this, &fbuc_ext_meth_get_color_remap_mode, 341 | 57, 0, 0, 1, 0); 342 | fbuc_install_external_method(this, &fbuc_ext_meth_set_parameter, 343 | 68, 1, 8, 0, 0); 344 | fbuc_install_external_method(this, &fbuc_ext_meth_enable_notifications, 345 | 72, 4, 0, 0, 0); 346 | fbuc_install_external_method(this, &fbuc_ext_meth_change_frame_info, 347 | 73, 2, 0, 0, 0); 348 | fbuc_install_external_method(this, &fbuc_ext_meth_supported_frame_info, 349 | 74, 1, 0, 1, 64); 350 | return IOService_start(this); 351 | } 352 | 353 | uint64_t fbuc_externalMethod(void *this, uint32_t selector, 354 | IOExternalMethodArguments *args, 355 | IOExternalMethodDispatch *dispatch, 356 | void *target, void *reference) 357 | { 358 | IOExternalMethodDispatch *new_dispatch; 359 | FBUCMembers *members = get_fbuc_members(this); 360 | 361 | 362 | if ((selector >= FBUC_MAX_EXT_FUNCS) || 363 | (0 == members->fbuc_external_methods[selector].function)) { 364 | cancel(); 365 | } 366 | new_dispatch = &members->fbuc_external_methods[selector]; 367 | return IOUserClient_externalMethod(this, selector, args, new_dispatch, 368 | this, reference); 369 | } 370 | 371 | uint64_t fbuc_clientClose(void *this) 372 | { 373 | void **vtable_ptr = (void **)*(uint64_t *)this; 374 | FuncIOSerivceTerminate vfunc_terminate = 375 | (FuncIOSerivceTerminate)vtable_ptr[IOSERVICE_TERMINATE_INDEX]; 376 | vfunc_terminate(this, 0); 377 | return 0; 378 | } 379 | 380 | uint64_t fbuc_connectClient(void *this, void *user_client) 381 | { 382 | cancel(); 383 | return 0; 384 | } 385 | 386 | uint64_t fbuc_getNotificationSemaphore(void *this, uint64_t type, void *sem) 387 | { 388 | cancel(); 389 | return 0; 390 | } 391 | 392 | uint64_t fbuc_clientMemoryForType(void *this, uint64_t type, void *opts, 393 | void **mem) 394 | { 395 | cancel(); 396 | return 0; 397 | } 398 | 399 | uint64_t fbuc_registerNotificationPort(void *this, void *port, 400 | uint64_t type, uint64_t ref) 401 | { 402 | FBUCMembers *members = get_fbuc_members(this); 403 | if (type >= FBUC_MAX_NOTIF_PORTS) { 404 | cancel(); 405 | } 406 | members->notif_ports[type].type = type; 407 | members->notif_ports[type].port = port; 408 | members->notif_ports[type].ref = ref; 409 | return 0; 410 | } 411 | 412 | uint64_t fbuc_initWithTask(void *this, void *task, void *sid, uint64_t type) 413 | { 414 | FBUCMembers *members = get_fbuc_members(this); 415 | members->task = task; 416 | return IOUserClient_initWithTask(this, task, sid, type); 417 | } 418 | 419 | uint64_t fbuc_destructor(void *this) 420 | { 421 | void *obj = IOUserClient_destructor(this); 422 | OSObject_delete(obj, ALEPH_FBUC_SIZE); 423 | return 0; 424 | } 425 | -------------------------------------------------------------------------------- /aleph_bdev_drv/src/aleph_fbuc_dev.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jonathan Afek 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include "mclass_reg.h" 24 | 25 | #ifndef ALEPH_FBUC_DEV_H 26 | #define ALEPH_FBUC_DEV_H 27 | 28 | //just in case. 29 | #define ALEPH_FBUC_SIZE (0x2000) 30 | #define FBUC_MEMBERS_OFFSET (0x800) 31 | #define FBUC_MAX_EXT_FUNCS (0x60) 32 | #define FBUC_MAX_NOTIF_PORTS (8) 33 | 34 | #define FBUC_CLASS_NAME "IOMobileFramebufferDeviceUserClient" 35 | 36 | 37 | typedef struct { 38 | uint64_t type; 39 | uint64_t ref; 40 | void *port; 41 | uint64_t asnyc_ref64[8]; 42 | } NotifPortInfo; 43 | 44 | typedef struct { 45 | void *task; 46 | NotifPortInfo notif_ports[FBUC_MAX_NOTIF_PORTS]; 47 | IOExternalMethodDispatch fbuc_external_methods[FBUC_MAX_EXT_FUNCS]; 48 | 49 | } FBUCMembers; 50 | 51 | void *get_fbuc_mclass_inst(void); 52 | 53 | //our driver virtual functions 54 | void *fbuc_getMetaClass(void *this); 55 | uint64_t fbuc_externalMethod(void *this, uint32_t selector, 56 | IOExternalMethodArguments *args, 57 | IOExternalMethodDispatch *dispatch, 58 | void *target, void *reference); 59 | uint64_t fbuc_start(void *this); 60 | uint64_t fbuc_clientClose(void *this); 61 | uint64_t fbuc_connectClient(void *this, void *user_client); 62 | uint64_t fbuc_getNotificationSemaphore(void *this, uint64_t type, void *sem); 63 | uint64_t fbuc_clientMemoryForType(void *this, uint64_t type, void *opts, 64 | void **mem); 65 | uint64_t fbuc_registerNotificationPort(void *this, void *port, 66 | uint64_t type, uint64_t ref); 67 | uint64_t fbuc_initWithTask(void *this, void *task, void *sid, uint64_t type); 68 | uint64_t fbuc_destructor(void *this); 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /aleph_bdev_drv/src/aleph_fbuc_mclass.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jonathan Afek 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | #include "aleph_fbuc_mclass.h" 27 | #include "kern_funcs.h" 28 | #include "aleph_fbuc_dev.h" 29 | #include "utils.h" 30 | #include "mclass_reg.h" 31 | 32 | #include "hw/arm/guest-services/general.h" 33 | 34 | static void *fbuc_vtable[FBUC_VTABLE_SIZE]; 35 | static MetaClassVTable fbuc_meta_class_vtable; 36 | 37 | void create_fbuc_vtable(void) 38 | { 39 | memcpy(&fbuc_vtable[0], 40 | (void *)IOUC_VTABLE_PTR, 41 | sizeof(fbuc_vtable)); 42 | fbuc_vtable[IOSERVICE_DESTRUCTOR_INDEX] = &fbuc_destructor; 43 | fbuc_vtable[IOSERVICE_GETMCLASS_INDEX] = &fbuc_getMetaClass; 44 | fbuc_vtable[IOUC_EXTERNAL_METHOD_INDEX] = &fbuc_externalMethod; 45 | fbuc_vtable[IOUC_INIT_WITH_TASK_INDEX] = &fbuc_initWithTask; 46 | fbuc_vtable[IOUC_CLIENT_CLOSE_INDEX] = &fbuc_clientClose; 47 | fbuc_vtable[IOUC_REG_NOTIF_PORT_INDEX] = &fbuc_registerNotificationPort; 48 | fbuc_vtable[IOUC_GET_NOTIFICATION_SEMAPHORE_INDEX] = 49 | &fbuc_getNotificationSemaphore; 50 | fbuc_vtable[IOUC_CONNECT_CLIENT_INDEX] = &fbuc_connectClient; 51 | fbuc_vtable[IOUC_CLIENT_MEM_FOR_TYPE_INDEX] = &fbuc_clientMemoryForType; 52 | fbuc_vtable[IOSERVICE_START_INDEX] = &fbuc_start; 53 | } 54 | 55 | void *fbuc_alloc(void) 56 | { 57 | void **obj = OSObject_new(ALEPH_FBUC_SIZE); 58 | IOUserClient_IOUserClient(obj, get_fbuc_mclass_inst()); 59 | obj[0] = &fbuc_vtable[0]; 60 | OSMetaClass_instanceConstructed(get_fbuc_mclass_inst()); 61 | return obj; 62 | } 63 | 64 | void create_fbuc_metaclass_vtable(void) 65 | { 66 | memcpy(&fbuc_meta_class_vtable, (void *)IOUC_MCLASS_VTABLE_PTR, 67 | sizeof(MetaClassVTable)); 68 | fbuc_meta_class_vtable.alloc = fbuc_alloc; 69 | } 70 | 71 | void register_fbuc_meta_class() 72 | { 73 | mclass_reg_slock_lock(); 74 | 75 | create_fbuc_vtable(); 76 | create_fbuc_metaclass_vtable(); 77 | 78 | void **mc = OSMetaClass_OSMetaClass(get_fbuc_mclass_inst(), 79 | FBUC_CLASS_NAME, 80 | (void *)IOUC_MCLASS_INST_PTR, 81 | ALEPH_FBUC_SIZE); 82 | if (NULL == mc) { 83 | cancel(); 84 | } 85 | mc[0] = &fbuc_meta_class_vtable; 86 | 87 | mclass_reg_alock_lock(); 88 | 89 | add_to_classes_dict(FBUC_CLASS_NAME, mc); 90 | 91 | mclass_reg_alock_unlock(); 92 | mclass_reg_slock_unlock(); 93 | } 94 | -------------------------------------------------------------------------------- /aleph_bdev_drv/src/aleph_fbuc_mclass.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jonathan Afek 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef ALEPH_FBUC_MCLASS_H 24 | #define ALEPH_FBUC_MCLASS_H 25 | 26 | //not sure what the original vtable size is, use this for now 27 | #define FBUC_VTABLE_SIZE (0x1000) 28 | 29 | void create_fbuc_vtable(void); 30 | void create_fbuc_metaclass_vtable(void); 31 | void register_fbuc_meta_class(); 32 | 33 | //our driver metaclass virtual functions 34 | void *fbuc_alloc(void); 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /aleph_bdev_drv/src/kern_funcs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jonathan Afek 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef KERN_FUNCS_H 24 | #define KERN_FUNCS_H 25 | 26 | enum IODirection 27 | { 28 | kIODirectionNone = 0x0,// same as VM_PROT_NONE 29 | kIODirectionIn = 0x1,// User land 'read', same as VM_PROT_READ 30 | kIODirectionOut = 0x2,// User land 'write', same as VM_PROT_WRITE 31 | }; 32 | 33 | #define IOBLOCKSTORAGEDEVICE_MCLASS_INST_PTR (0xfffffff0076f6e58) 34 | #define IOBLOCKSTORAGEDEVICE_MCLASS_VTABLE_PTR (0xfffffff006e14200) 35 | #define IOBLOCKSTORAGEDEVICE_VTABLE_PTR (0xfffffff006e13c00) 36 | #define IOBLOCKSTORAGEDEVICE_CONSTRUCTOR_FUNC_PTR (0xfffffff00619ad80) 37 | 38 | #define IOMFB_MCLASS_INST_PTR (0xfffffff00771b408) 39 | #define IOMFB_MCLASS_VTABLE_PTR (0xfffffff006e8d4b8) 40 | #define IOMFB_VTABLE_PTR (0xfffffff006e8ca10) 41 | #define IOMFB_CONSTRUCTOR_FUNC_PTR (0xfffffff00636a660) 42 | 43 | #define IOSERVICE_MCLASS_INST_PTR (0xfffffff007602b68) 44 | #define IOSERVICE_MCLASS_VTABLE_PTR (0xfffffff007086e80) 45 | #define IOSERVICE_VTABLE_PTR (0xfffffff007086300) 46 | 47 | #define IOUC_MCLASS_INST_PTR (0xfffffff0076033f8) 48 | #define IOUC_MCLASS_VTABLE_PTR (0xfffffff007091058) 49 | #define IOUC_VTABLE_PTR (0xfffffff007090a78) 50 | 51 | #define SALLCLASSESDICT_PTR (0xfffffff007672e00) 52 | #define SALLCLASSESLOCK_PTR (0xfffffff007672dc0) 53 | #define SSTALLEDCLASSESLOCK_PTR (0xfffffff007672dd0) 54 | 55 | //OSMetaClass::instanceConstructed() const 56 | void _ZNK11OSMetaClass19instanceConstructedEv(void *meta_class_inst_ptr); 57 | #define OSMetaClass_instanceConstructed(x) \ 58 | _ZNK11OSMetaClass19instanceConstructedEv(x) 59 | 60 | //OSMetaClass::allocClassWithName(char const*) 61 | void *_ZN11OSMetaClass18allocClassWithNameEPKc(char *name); 62 | #define OSMetaClass_allocClassWithName(x) \ 63 | _ZN11OSMetaClass18allocClassWithNameEPKc(x) 64 | 65 | //OSObject::operator new(unsigned long) 66 | void *_ZN8OSObjectnwEm(uint64_t size); 67 | #define OSObject_new(x) _ZN8OSObjectnwEm(x) 68 | 69 | //OSMetaClass::OSMetaClass(char const*, OSMetaClass const*, unsigned int) 70 | void *_ZN11OSMetaClassC2EPKcPKS_j(void *meta_class_inst_ptr, char *class_name, 71 | void *parent_meta_class_inst_ptr, 72 | uint64_t size); 73 | #define OSMetaClass_OSMetaClass(w, x, y, z) \ 74 | _ZN11OSMetaClassC2EPKcPKS_j(w, x, y, z) 75 | 76 | //OSSymbol::withCStringNoCopy(char const*) 77 | void *_ZN8OSSymbol17withCStringNoCopyEPKc(char *str); 78 | #define OSSymbol_withCStringNoCopy(x) _ZN8OSSymbol17withCStringNoCopyEPKc(x) 79 | 80 | //OSDictionary::setObject(OSSymbol const*, OSMetaClassBase const*) 81 | void _ZN12OSDictionary9setObjectEPK8OSSymbolPK15OSMetaClassBase(void *dict, 82 | void *sym, 83 | void *obj); 84 | #define OSDictionary_setObject(x, y, z) \ 85 | _ZN12OSDictionary9setObjectEPK8OSSymbolPK15OSMetaClassBase(x, y, z) 86 | 87 | //IOService::serviceMatching(char const*, OSDictionary*) 88 | void *_ZN9IOService15serviceMatchingEPKcP12OSDictionary(char *class_name, 89 | void *dict); 90 | #define IOService_serviceMatching(x, y) \ 91 | _ZN9IOService15serviceMatchingEPKcP12OSDictionary(x, y) 92 | 93 | //IOService::nameMatching(char const*, OSDictionary*) 94 | void *_ZN9IOService12nameMatchingEPKcP12OSDictionary(char *name, 95 | void *dict); 96 | #define IOService_nameMatching(x, y) \ 97 | _ZN9IOService12nameMatchingEPKcP12OSDictionary(x, y) 98 | 99 | //OSDictionary * waitForMatchingService(OSDictionary *param_1,long_long param_2) 100 | void *_ZN9IOService22waitForMatchingServiceEP12OSDictionaryy(void *dict, 101 | uint64_t timeout); 102 | #define waitForMatchingService(x, y) \ 103 | _ZN9IOService22waitForMatchingServiceEP12OSDictionaryy(x, y) 104 | 105 | //IOService::IOService(OSMetaClass*) 106 | void _ZN9IOServiceC1EPK11OSMetaClass(void *this, void *metaclass); 107 | #define IOService_IOService(x, y) _ZN9IOServiceC1EPK11OSMetaClass(x, y) 108 | 109 | //IOService::start(IOService*) 110 | uint64_t _ZN9IOService5startEPS_(void *this); 111 | #define IOService_start(x) _ZN9IOService5startEPS_(x) 112 | 113 | //IOUserClient::IOUserClient(OSMetaClass const* 114 | void _ZN12IOUserClientC2EPK11OSMetaClass(void *this, void *metaclass); 115 | #define IOUserClient_IOUserClient(x, y) \ 116 | _ZN12IOUserClientC2EPK11OSMetaClass(x, y) 117 | 118 | //IOUserClient::externalMethod 119 | uint64_t 120 | _ZN12IOUserClient14externalMethodEjP25IOExternalMethodArgumentsP24IOExternalMethodDispatchP8OSObjectPv( 121 | void *this, uint32_t selector, void *args, 122 | void *dispatch, void *target, void *reference); 123 | #define IOUserClient_externalMethod(a, b, c, d, e, f) \ 124 | _ZN12IOUserClient14externalMethodEjP25IOExternalMethodArgumentsP24IOExternalMethodDispatchP8OSObjectPv(a, b, c, d, e, f) 125 | 126 | //IOUserClient::~IOUserClient() 127 | void *_ZN12IOUserClientD2Ev(void *this); 128 | #define IOUserClient_destructor(x) _ZN12IOUserClientD2Ev(x) 129 | 130 | //OSObject::operator delete(void*, unsigned long 131 | void _ZN8OSObjectdlEPvm(void *obj, uint64_t size); 132 | #define OSObject_delete(x, y) _ZN8OSObjectdlEPvm(x, y) 133 | 134 | //IOUserClient::initWithTask(task*, void*, unsigned int) 135 | uint64_t _ZN12IOUserClient12initWithTaskEP4taskPvj(void *this, void *task, 136 | void *sid, uint64_t type); 137 | #define IOUserClient_initWithTask(a, b, c, d) \ 138 | _ZN12IOUserClient12initWithTaskEP4taskPvj(a, b, c, d) 139 | 140 | //IOUserClient::setAsyncReference64(unsigned long long*, ipc_port*, unsigned long long, unsigned, long long, task*) 141 | void _ZN12IOUserClient19setAsyncReference64EPyP8ipc_portyyP4task(void *aref, 142 | void *port, 143 | uint64_t cb, 144 | uint64_t ref, 145 | void *task); 146 | #define IOUserClient_setAsyncReference64(a, b, c, d, e) \ 147 | _ZN12IOUserClient19setAsyncReference64EPyP8ipc_portyyP4task(a, b, c, d, e) 148 | 149 | //IOUserClient::sendAsyncResult64(unsigned long long*, int, unsigned long long*, unsigned int) 150 | void _ZN12IOUserClient17sendAsyncResult64EPyiS0_j(void *aref, uint64_t res, 151 | uint64_t *args, uint64_t cnt); 152 | #define IOUserClient_sendAsyncResult64(a, b, c, d) \ 153 | _ZN12IOUserClient17sendAsyncResult64EPyiS0_j(a, b, c, d) 154 | 155 | //void _IOLog(undefined8 param_1) 156 | void IOLog(const char* fmt, ...); 157 | 158 | //void _IOSleep(undefined8 param_1) 159 | void IOSleep(uint64_t millisecs); 160 | 161 | void lck_mtx_lock(void *lck_mtx); 162 | void lck_mtx_unlock(void *lck_mtx); 163 | void *lck_grp_alloc_init(char *name, void *p2); 164 | void *lck_mtx_alloc_init(void *mtx_grp, void *p2); 165 | 166 | void kernel_thread_start(void *code, void *param, void *new_thread); 167 | 168 | #endif 169 | -------------------------------------------------------------------------------- /aleph_bdev_drv/src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jonathan Afek 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | #include "kern_funcs.h" 27 | #include "utils.h" 28 | #include "aleph_block_dev.h" 29 | #include "aleph_bdev_mclass.h" 30 | #include "aleph_fb_dev.h" 31 | #include "aleph_fb_mclass.h" 32 | #include "aleph_fbuc_dev.h" 33 | #include "aleph_fbuc_mclass.h" 34 | 35 | #include "hw/arm/guest-services/general.h" 36 | 37 | #define NUM_BLOCK_DEVS_MAX (10) 38 | 39 | #ifndef NUM_BLOCK_DEVS 40 | #define NUM_BLOCK_DEVS (2) 41 | #endif 42 | 43 | void _start() __attribute__((section(".start"))); 44 | 45 | static uint8_t executed = 0; 46 | 47 | void _start() { 48 | uint64_t i = 0; 49 | //in case the hook gets called more than once we want to make sure 50 | //it starts only once 51 | if (executed) { 52 | return; 53 | } 54 | executed = 1; 55 | 56 | if (NUM_BLOCK_DEVS > NUM_BLOCK_DEVS_MAX) { 57 | cancel(); 58 | } 59 | 60 | register_bdev_meta_class(); 61 | register_fb_meta_class(); 62 | register_fbuc_meta_class(); 63 | 64 | //TODO: release this object ref 65 | void *match_dict = IOService_serviceMatching("AppleARMPE", NULL); 66 | //TODO: release this object ref 67 | void *service = waitForMatchingService(match_dict, -1); 68 | //TODO: release this object ref 69 | if (0 == service) { 70 | cancel(); 71 | } 72 | 73 | //TODO: release this object ref 74 | void *match_dict_disp = IOService_nameMatching("disp0", NULL); 75 | //TODO: release this object ref 76 | void *service_disp = waitForMatchingService(match_dict_disp, -1); 77 | 78 | if (0 == service_disp) { 79 | cancel(); 80 | } 81 | 82 | char bdev_prod_name[] = "0AlephBDev"; 83 | char bdev_vendor_name[] = "0Aleph"; 84 | char bdev_mutex_name[] = "0AM"; 85 | 86 | for (i = 0; i < NUM_BLOCK_DEVS; i++) { 87 | //TODO: release this object ref? 88 | bdev_prod_name[0]++; 89 | bdev_vendor_name[0]++; 90 | bdev_mutex_name[0]++; 91 | create_new_aleph_bdev(bdev_prod_name, bdev_vendor_name, 92 | bdev_mutex_name, i, service); 93 | 94 | //TODO: hack for now to make the first registered bdev disk0 instead 95 | //of having the system change the order 96 | IOSleep(1000); 97 | ////wait for the first disk to be loaded as disk0 98 | //if (0 == i) { 99 | // void *match_dict_first = IOService_serviceMatching("IOMediaBSDClient", NULL); 100 | // void *service_first = waitForMatchingService(match_dict_first, -1); 101 | //} 102 | } 103 | 104 | create_new_aleph_fbdev(service_disp); 105 | } 106 | -------------------------------------------------------------------------------- /aleph_bdev_drv/src/mclass_reg.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jonathan Afek 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | #include "mclass_reg.h" 27 | #include "kern_funcs.h" 28 | #include "aleph_block_dev.h" 29 | #include "utils.h" 30 | 31 | #include "hw/arm/guest-services/general.h" 32 | 33 | void add_to_classes_dict(char *name, void **mc) 34 | { 35 | uint32_t *dict = *(uint32_t **)SALLCLASSESDICT_PTR; 36 | if (NULL == dict) { 37 | cancel(); 38 | } 39 | 40 | //fOptions =& ~kImmutable 41 | dict[4] = dict[4] & ~(uint32_t)1; 42 | void *sym = OSSymbol_withCStringNoCopy(name); 43 | OSDictionary_setObject((void *)dict, sym, mc); 44 | 45 | char *c_class_name = (char *)mc[3]; 46 | if (NULL != c_class_name) { 47 | mc[3] = OSSymbol_withCStringNoCopy(c_class_name); 48 | } 49 | } 50 | 51 | void mclass_reg_alock_lock() 52 | { 53 | if (NULL == *(void **)SALLCLASSESLOCK_PTR) { 54 | cancel(); 55 | } 56 | lck_mtx_lock(*(void **)SALLCLASSESLOCK_PTR); 57 | } 58 | 59 | void mclass_reg_alock_unlock() 60 | { 61 | lck_mtx_unlock(*(void **)SALLCLASSESLOCK_PTR); 62 | } 63 | 64 | void mclass_reg_slock_lock() 65 | { 66 | if (NULL == *(void **)SSTALLEDCLASSESLOCK_PTR) { 67 | cancel(); 68 | } 69 | lck_mtx_lock(*(void **)SSTALLEDCLASSESLOCK_PTR); 70 | } 71 | 72 | void mclass_reg_slock_unlock() 73 | { 74 | lck_mtx_unlock(*(void **)SSTALLEDCLASSESLOCK_PTR); 75 | } 76 | 77 | -------------------------------------------------------------------------------- /aleph_bdev_drv/src/mclass_reg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jonathan Afek 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef ALEPH_MCLASS_REG_H 24 | #define ALEPH_MCLASS_REG_H 25 | 26 | //just in case not sure how much is required 27 | #define ALEPH_MCLASS_SIZE (0x1000) 28 | 29 | typedef void (*VoidFunc)(void); 30 | typedef void* (*AllocFunc)(void); 31 | typedef void (*ObjConstructor)(void *); 32 | 33 | typedef struct { 34 | VoidFunc destructor1; VoidFunc destructor2; 35 | VoidFunc release1; 36 | VoidFunc getRetainCount; 37 | VoidFunc retain; 38 | VoidFunc release2; 39 | VoidFunc serialize; 40 | VoidFunc getMetaClass; 41 | VoidFunc isEqualTo; 42 | VoidFunc taggedRetain; 43 | VoidFunc taggedRelease1; 44 | VoidFunc taggedRelease2; 45 | AllocFunc alloc; 46 | } MetaClassVTable; 47 | 48 | typedef struct 49 | { 50 | uint32_t version; 51 | uint32_t selector; 52 | uint64_t unknown1[3]; 53 | 54 | uint64_t *scalarInput; 55 | uint32_t scalarInputCount; 56 | uint32_t align1; 57 | 58 | void *structureInput; 59 | uint32_t structureInputSize; 60 | uint32_t align2; 61 | 62 | void *structureInputDescriptor; 63 | 64 | uint64_t *scalarOutput; 65 | uint32_t scalarOutputCount; 66 | uint32_t align3; 67 | 68 | void *structureOutput; 69 | uint32_t structureOutputSize; 70 | uint32_t align4; 71 | 72 | void *structureOutputDescriptor; 73 | } __attribute__((packed)) IOExternalMethodArguments; 74 | 75 | typedef uint64_t (*IOExternalMethodAction)(void* target, void* reference, 76 | IOExternalMethodArguments *arguments); 77 | typedef struct 78 | { 79 | IOExternalMethodAction function; 80 | uint32_t checkScalarInputCount; 81 | uint32_t checkStructureInputSize; 82 | uint32_t checkScalarOutputCount; 83 | uint32_t checkStructureOutputSize; 84 | } IOExternalMethodDispatch; 85 | 86 | void add_to_classes_dict(char *name, void **mc); 87 | void mclass_reg_alock_lock(); 88 | void mclass_reg_alock_unlock(); 89 | void mclass_reg_slock_lock(); 90 | void mclass_reg_slock_unlock(); 91 | 92 | //IOService virtual function defs 93 | typedef void (*FuncIOServiceInit)(void *this, void *dict); 94 | typedef void (*FuncIOSerivceRegisterService)(void *this, uint64_t opts); 95 | typedef void (*FuncIOSerivceStart)(void *this, void *provider); 96 | typedef void (*FuncIOSerivceTerminate)(void *this, uint64_t opts); 97 | typedef uint64_t (*FuncIOServiceAttach)(void *this, void *parent); 98 | typedef uint64_t (*FuncIOServiceSetProperty)(void *this, char *key, char *val); 99 | 100 | //IOService virtual function indices 101 | 102 | #define IOSERVICE_DESTRUCTOR_INDEX (1) 103 | #define IOSERVICE_GETMCLASS_INDEX (7) 104 | #define IOSERVICE_INIT_INDEX (20) 105 | #define IOSERVICE_SET_PROPERTY_INDEX (25) 106 | #define IOSERVICE_REG_SERVICE_INDEX (83) 107 | #define IOSERVICE_START_INDEX (85) 108 | #define IOSERVICE_TERMINATE_INDEX (93) 109 | #define IOSERVICE_ATTACH_INDEX (107) 110 | 111 | //IOUserClient virtual function indices 112 | 113 | #define IOUC_EXTERNAL_METHOD_INDEX (167) 114 | #define IOUC_INIT_WITH_TASK_INDEX (170) 115 | #define IOUC_CLIENT_CLOSE_INDEX (171) 116 | #define IOUC_REG_NOTIF_PORT_INDEX (174) 117 | #define IOUC_GET_NOTIFICATION_SEMAPHORE_INDEX (175) 118 | #define IOUC_CONNECT_CLIENT_INDEX (176) 119 | #define IOUC_CLIENT_MEM_FOR_TYPE_INDEX (177) 120 | 121 | #endif 122 | -------------------------------------------------------------------------------- /aleph_bdev_drv/src/qemu-guest-services/file.c: -------------------------------------------------------------------------------- 1 | /* 2 | * QEMU Guest Services - Socket API 3 | * 4 | * Copyright (c) 2019 Lev Aronsky 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without retvaltriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPretvalS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #include "hw/arm/guest-services/general.h" 26 | 27 | static int64_t qemu_file_call(qemu_call_t *qcall) 28 | { 29 | qemu_call(qcall); 30 | 31 | guest_svcs_errno = qcall->error; 32 | return qcall->retval; 33 | } 34 | int64_t qc_size_file(uint64_t index) 35 | { 36 | qemu_call_t qcall = { 37 | .call_number = QC_SIZE_FILE, 38 | .args.size_file.index = index, 39 | }; 40 | 41 | return qemu_file_call(&qcall); 42 | } 43 | 44 | int64_t qc_write_file(void *buffer_guest_ptr, uint64_t length, 45 | uint64_t offset, uint64_t index) 46 | { 47 | qemu_call_t qcall = { 48 | .call_number = QC_WRITE_FILE, 49 | .args.write_file.buffer_guest_ptr = (uint64_t)buffer_guest_ptr, 50 | .args.write_file.length = length, 51 | .args.write_file.offset = offset, 52 | .args.write_file.index = index, 53 | }; 54 | 55 | return qemu_file_call(&qcall); 56 | } 57 | 58 | int64_t qc_read_file(void *buffer_guest_ptr, uint64_t length, 59 | uint64_t offset, uint64_t index) 60 | { 61 | qemu_call_t qcall = { 62 | .call_number = QC_READ_FILE, 63 | .args.read_file.buffer_guest_ptr = (uint64_t)buffer_guest_ptr, 64 | .args.read_file.length = length, 65 | .args.read_file.offset = offset, 66 | .args.read_file.index = index, 67 | }; 68 | 69 | return qemu_file_call(&qcall); 70 | } 71 | -------------------------------------------------------------------------------- /aleph_bdev_drv/src/qemu-guest-services/general.c: -------------------------------------------------------------------------------- 1 | /* 2 | * QEMU Guest Services - General 3 | * 4 | * Copyright (c) 2019 Lev Aronsky 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without retvaltriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPretvalS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #include "hw/arm/guest-services/general.h" 26 | 27 | int32_t guest_svcs_errno = 0; 28 | 29 | void qemu_call(qemu_call_t *qcall) 30 | { 31 | asm volatile ("mov x0, %[addr]"::[addr] "r" (qcall)); 32 | asm volatile (".byte 0x00"); 33 | asm volatile (".byte 0xff"); 34 | asm volatile (".byte 0x1b"); 35 | asm volatile (".byte 0xd5"); 36 | } 37 | -------------------------------------------------------------------------------- /aleph_bdev_drv/src/utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jonathan Afek 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | #include "utils.h" 27 | #include "kern_funcs.h" 28 | 29 | void cancel() 30 | { 31 | *(uint64_t *)(0) = 0xffffffffffffffff; 32 | } 33 | 34 | char *my_itoa(uint64_t num, char *str) 35 | { 36 | char digits[64]; 37 | char *dp; 38 | char *cp = str; 39 | 40 | if (num == 0) { 41 | *cp++ = '0'; 42 | } 43 | else { 44 | dp = digits; 45 | while (num) { 46 | *dp++ = '0' + num % 10; 47 | num /= 10; 48 | } 49 | while (dp != digits) { 50 | *cp++ = *--dp; 51 | } 52 | } 53 | *cp++ = '\0'; 54 | 55 | return str; 56 | } 57 | 58 | //Print to console 59 | void log_uint64(const char *name, uint64_t num) 60 | { 61 | char str[1024]; 62 | 63 | IOLog(name); 64 | my_itoa((uint64_t)num, &str[0]); 65 | IOLog(&str[0]); 66 | IOLog("\n"); 67 | } 68 | -------------------------------------------------------------------------------- /aleph_bdev_drv/src/utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jonathan Afek 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef UTILS_H 24 | #define UTILS_H 25 | 26 | void cancel(); 27 | 28 | char *my_itoa(uint64_t num, char *str); 29 | void log_uint64(const char *name, uint64_t num); 30 | 31 | //IOMemoryDescriptor virtual function defs 32 | 33 | typedef uint64_t (*FuncIOMemDescGetDirection)(void *this); 34 | typedef uint64_t (*FuncIOMemDescReadBytes)(void *this, uint64_t offset, 35 | void *bytes, uint64_t length); 36 | typedef uint64_t (*FuncIOMemDescWriteBytes)(void *this, uint64_t offset, 37 | void *bytes, uint64_t length); 38 | 39 | //IOMemoryDescriptor virtual function indices 40 | 41 | #define IOMEMDESCGETDIRECTION_INDEX (20) 42 | #define IOMEMDESCREADBYTES_INDEX (24) 43 | #define IOMEMDESCWRITEBYTES_INDEX (25) 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /bootstrap_scripts/README.md: -------------------------------------------------------------------------------- 1 | # iOS Kernel Bootstrap Scripts 2 | 3 | Those scripts are used to exctract, decode, decompress the needed files to load the iOS kernel on QEMU. 4 | 5 | --- 6 | - asn1dtredecode.py - *extract the ASN1 encoded device tree:* 7 | ``` 8 | $ python asn1dtredecode.py encoded_device_tree_input_filename device_tree_output_filename 9 | ``` 10 | --- 11 | - asn1kerneldecode.py - *extract the ASN1 encoded kernel image:* 12 | ``` 13 | $ python asn1kerneldecode.py encoded_kernel_image_input_filename kernel_image_output_filename 14 | ``` 15 | --- 16 | - decompress_lzss.py - *decompress the ASN1 decoded kernel image:* 17 | ``` 18 | $ python decompress_lzss.py compressed_decoded_kernel_image_filename kernel_image_output_filename 19 | ``` 20 | --- 21 | - asn1rdskdecode.py - *extract the ASN1 encoded ramdisk image:* 22 | ``` 23 | $ python asn1rdskdecode.py ramdisk_image_input_filename ramdisk_image_output_filename 24 | ``` 25 | --- 26 | - create_trustcache.py - *given a list of hashes (each of which represents a signed executable), 27 | separated by a new line, create a static trust cache file (binary):* 28 | ``` 29 | $ python create_trustcache.py list_of_hashes_filename output_tc_filename 30 | ``` 31 | --- 32 | - kernelcompressedextractmonitor.py - *extract the secure monitor from the compressed kernel image:* 33 | ``` 34 | $ python kernelcompressedextractmonitor.py compressed_decoded_kernel_image_filename secure_monitor_output_filename 35 | ``` 36 | -------------------------------------------------------------------------------- /bootstrap_scripts/asn1dtredecode.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from pyasn1.codec.der.decoder import decode as der_decoder 3 | 4 | def decode(data): 5 | try: 6 | decoded = der_decoder(data) 7 | except Exception as e: 8 | print( "can't asn1 decode the file given: " + str(e)) 9 | try: 10 | if "IM4P" != str(decoded[0][0]): 11 | print( "failed: unexpected element: " + str(decoded[0][0])) 12 | return "" 13 | if "dtre" != str(decoded[0][1]): 14 | print( "failed: unexpected element: " + str(decoded[0][1])) 15 | return "" 16 | return decoded[0][3] 17 | except Exception as e: 18 | print( "unexpected exception: " + str(e)) 19 | 20 | if __name__ == "__main__": 21 | data = open(sys.argv[1], "rb").read() 22 | out_data = decode(data) 23 | open(sys.argv[2], "wb").write(bytearray(out_data)) 24 | -------------------------------------------------------------------------------- /bootstrap_scripts/asn1kerneldecode.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from pyasn1.codec.der.decoder import decode as der_decoder 3 | 4 | def decode(data): 5 | try: 6 | decoded = der_decoder(data) 7 | except Exception as e: 8 | print ("can't asn1 decode the file given: " + str(e)) 9 | try: 10 | if "IM4P" != str(decoded[0][0]): 11 | print ("failed: unexpected element: " + str(decoded[0][0])) 12 | return "" 13 | if "krnl" != str(decoded[0][1]): 14 | print ("failed: unexpected element: " + str(decoded[0][1])) 15 | return "" 16 | return decoded[0][3] 17 | except Exception as e: 18 | print ("unexpected exception: " + str(e)) 19 | 20 | if __name__ == "__main__": 21 | data = open(sys.argv[1], "rb").read() 22 | out_data = decode(data) 23 | open(sys.argv[2], "wb").write(bytearray(out_data)) -------------------------------------------------------------------------------- /bootstrap_scripts/asn1rdskdecode.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2 2 | 3 | import sys 4 | from pyasn1.codec.der.decoder import decode as der_decoder 5 | 6 | def decode(data): 7 | try: 8 | decoded = der_decoder(data) 9 | except Exception as e: 10 | print ("can't asn1 decode the file given: " + str(e)) 11 | try: 12 | if "IM4P" != str(decoded[0][0]): 13 | print ("failed: unexpected element: " + str(decoded[0][0])) 14 | return "" 15 | if "rdsk" != str(decoded[0][1]): 16 | print ("failed: unexpected element: " + str(decoded[0][1])) 17 | return "" 18 | return (decoded[0][3]) 19 | except Exception as e: 20 | print ("unexpected exception: " + str(e)) 21 | 22 | if __name__ == "__main__": 23 | data = open(sys.argv[1], "rb").read() 24 | out_data = decode(data) 25 | open(sys.argv[2], "wb").write(bytearray(out_data)) 26 | -------------------------------------------------------------------------------- /bootstrap_scripts/create_trustcache.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | import struct 5 | import urllib 6 | 7 | def create_tc(hashes): 8 | tc = b"" 9 | 10 | #number of trustcaches in the trust cache buffer 11 | tc += struct.pack("= 40) 34 | 35 | hash_txt = hash_txt[:40] 36 | 37 | #write the hash itself 38 | for i in range(5): 39 | four_bytes = hash_txt[i * 8 : (i + 1) * 8] 40 | number = int(four_bytes, 16) 41 | tc += struct.pack(">I", number) 42 | 43 | #hash type 44 | tc += struct.pack("B", 0) 45 | #hash flags 46 | tc += struct.pack("B", 0) 47 | return tc 48 | 49 | if __name__ == "__main__": 50 | hashes_txt = open(sys.argv[1], "rb").read() 51 | hashes = hashes_txt.splitlines() 52 | hashes = [hash.strip() for hash in hashes] 53 | #the kernel does a binary search for the hash so they must be sorted 54 | hashes = sorted(hashes) 55 | tc = create_tc(hashes) 56 | open(sys.argv[2], "wb").write(tc) 57 | -------------------------------------------------------------------------------- /bootstrap_scripts/decompress_lzss.py: -------------------------------------------------------------------------------- 1 | """ 2 | /************************************************************** 3 | LZSS.C -- A Data Compression Program 4 | *************************************************************** 5 | 4/6/1989 Haruhiko Okumura 6 | Use, distribute, and modify this program freely. 7 | Please send me your improved versions. 8 | PC-VAN SCIENCE 9 | NIFTY-Serve PAF01022 10 | CompuServe 74050,1022 11 | **************************************************************/ 12 | /* 13 | * lzss.c - Package for decompressing lzss compressed objects 14 | * 15 | * Copyright (c) 2003 Apple Computer, Inc. 16 | * 17 | * DRI: Josh de Cesare 18 | */ 19 | """ 20 | 21 | from array import array 22 | import struct 23 | import sys 24 | 25 | N = 4096 26 | F = 18 27 | THRESHOLD = 2 28 | NIL = N 29 | 30 | 31 | def decompress_lzss(data): 32 | if data[:8] != b"complzss": 33 | print('decompress_lzss: complzss magic missing') 34 | return 35 | decompsize = struct.unpack(">L", data[12:16])[0] 36 | text_buf = array("B", b" " * (N + F - 1)) 37 | src = array("B", data[0x180:]) 38 | # srclen = len(src) 39 | srclen = struct.unpack(">L", data[16:20])[0] 40 | dst = array("B", b" " * decompsize) 41 | r = N - F 42 | srcidx, dstidx, flags, c = 0, 0, 0, 0 43 | 44 | while True: 45 | flags >>= 1 46 | if ((flags & 0x100) == 0): 47 | if (srcidx >= srclen): 48 | break 49 | c = src[srcidx] 50 | srcidx += 1 51 | flags = c | 0xFF00 52 | 53 | if (flags & 1): 54 | if (srcidx >= srclen): 55 | break 56 | c = src[srcidx] 57 | srcidx += 1 58 | dst[dstidx] = c 59 | dstidx += 1 60 | text_buf[r] = c 61 | r += 1 62 | r &= (N - 1) 63 | else: 64 | if (srcidx >= srclen): 65 | break 66 | i = src[srcidx] 67 | srcidx += 1 68 | if (srcidx >= srclen): 69 | break 70 | j = src[srcidx] 71 | srcidx += 1 72 | i |= ((j & 0xF0) << 4) 73 | j = (j & 0x0F) + THRESHOLD 74 | for k in range(j + 1): 75 | c = text_buf[(i + k) & (N - 1)] 76 | dst[dstidx] = c 77 | dstidx += 1 78 | text_buf[r] = c 79 | r += 1 80 | r &= (N - 1) 81 | return dst.tobytes() 82 | 83 | 84 | if __name__ == "__main__": 85 | data = decompress_lzss(open(sys.argv[1], "rb").read()) 86 | if data: 87 | open(sys.argv[2], "wb").write(data) 88 | -------------------------------------------------------------------------------- /bootstrap_scripts/kernelcompressedextractmonitor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2 2 | 3 | import sys 4 | import struct 5 | 6 | def decode(data): 7 | if data[0:8] != "complzss": 8 | print "error: unsupported format: " + str(data[0:7]) 9 | return "" 10 | compressed_size = struct.unpack(">I", data[16:20]) 11 | 12 | end_of_compressed_data = compressed_size[0] + 0x180 #size of compression header 13 | 14 | return data[end_of_compressed_data:] 15 | 16 | if __name__ == "__main__": 17 | data = open(sys.argv[1], "rb").read() 18 | out_data = decode(data) 19 | open(sys.argv[2], "wb").write(out_data) 20 | -------------------------------------------------------------------------------- /common_hooks/include/ipc-obj.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jonathan Afek 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef IPC_OBJ_H 24 | #define IPC_OBJ_H 25 | 26 | struct ipc_object { 27 | uint32_t io_bits; 28 | uint32_t io_references; 29 | uint64_t io_lock_data; 30 | } __attribute__((packed)); 31 | 32 | typedef struct bsd_info { 33 | char reserved[0x60]; 34 | uint32_t p_pid; 35 | char reserved1[0x1FD]; 36 | char p_name[256]; //TODO: verify size 37 | 38 | } __attribute__((packed)) bsd_info_t; 39 | 40 | typedef struct task { 41 | char reserved[0x358]; 42 | bsd_info_t *bsd_info; 43 | 44 | } __attribute__((packed)) task_t; 45 | typedef struct ipc_space { 46 | char is_lock_data[0x10]; //verify size? 47 | char is_bits[4]; /* holds refs, active, growing */ //verify size? 48 | uint32_t is_table_size; /* current size of table */ 49 | uint32_t is_table_free; /* count of free elements */ 50 | uint32_t reserved; 51 | void *is_table; /* an array of entries */ 52 | task_t *is_task; /* associated task */ 53 | 54 | } __attribute__((packed)) ipc_space_t; 55 | 56 | typedef struct { 57 | struct ipc_object ip_object; 58 | char reserved[0x50]; 59 | struct ipc_space *receiver; 60 | } __attribute__((packed)) ipc_port_t; 61 | 62 | #define MACH_MSGH_BITS_ZERO (0x00000000) 63 | 64 | #define MACH_MSGH_BITS_REMOTE_MASK (0x0000001f) 65 | #define MACH_MSGH_BITS_LOCAL_MASK (0x00001f00) 66 | #define MACH_MSGH_BITS_VOUCHER_MASK (0x001f0000) 67 | 68 | #define MACH_MSGH_BITS_PORTS_MASK \ 69 | ((MACH_MSGH_BITS_REMOTE_MASK) | \ 70 | (MACH_MSGH_BITS_LOCAL_MASK) | \ 71 | (MACH_MSGH_BITS_VOUCHER_MASK)) 72 | 73 | #define MACH_MSGH_BITS_COMPLEX (0x80000000U) /* message is complex */ 74 | 75 | #define MACH_MSGH_BITS_USER (0x801f1f1fU) /* allowed bits user->kernel */ 76 | 77 | #define MACH_MSGH_BITS_RAISEIMP (0x20000000U) /* importance raised due to msg */ 78 | #define MACH_MSGH_BITS_DENAP (MACH_MSGH_BITS_RAISEIMP) 79 | 80 | #define MACH_MSGH_BITS_IMPHOLDASRT (0x10000000U) /* assertion help, userland private */ 81 | #define MACH_MSGH_BITS_DENAPHOLDASRT (MACH_MSGH_BITS_IMPHOLDASRT) 82 | 83 | #define MACH_MSGH_BITS_CIRCULAR (0x10000000U) /* message circular, kernel private */ 84 | 85 | #define MACH_MSGH_BITS_USED (0xb01f1f1fU) 86 | 87 | /* setter macros for the bits */ 88 | #define MACH_MSGH_BITS(remote, local) /* legacy */ \ 89 | ((remote) | ((local) << 8)) 90 | #define MACH_MSGH_BITS_SET_PORTS(remote, local, voucher) \ 91 | (((remote) & MACH_MSGH_BITS_REMOTE_MASK) | \ 92 | (((local) << 8) & MACH_MSGH_BITS_LOCAL_MASK) | \ 93 | (((voucher) << 16) & MACH_MSGH_BITS_VOUCHER_MASK)) 94 | #define MACH_MSGH_BITS_SET(remote, local, voucher, other) \ 95 | (MACH_MSGH_BITS_SET_PORTS((remote), (local), (voucher)) \ 96 | | ((other) &~ MACH_MSGH_BITS_PORTS_MASK)) 97 | 98 | /* getter macros for pulling values out of the bits field */ 99 | #define MACH_MSGH_BITS_REMOTE(bits) \ 100 | ((bits) & MACH_MSGH_BITS_REMOTE_MASK) 101 | #define MACH_MSGH_BITS_LOCAL(bits) \ 102 | (((bits) & MACH_MSGH_BITS_LOCAL_MASK) >> 8) 103 | #define MACH_MSGH_BITS_VOUCHER(bits) \ 104 | (((bits) & MACH_MSGH_BITS_VOUCHER_MASK) >> 16) 105 | #define MACH_MSGH_BITS_PORTS(bits) \ 106 | ((bits) & MACH_MSGH_BITS_PORTS_MASK) 107 | #define MACH_MSGH_BITS_OTHER(bits) \ 108 | ((bits) &~ MACH_MSGH_BITS_PORTS_MASK) 109 | 110 | /* checking macros */ 111 | #define MACH_MSGH_BITS_HAS_REMOTE(bits) \ 112 | (MACH_MSGH_BITS_REMOTE(bits) != MACH_MSGH_BITS_ZERO) 113 | #define MACH_MSGH_BITS_HAS_LOCAL(bits) \ 114 | (MACH_MSGH_BITS_LOCAL(bits) != MACH_MSGH_BITS_ZERO) 115 | #define MACH_MSGH_BITS_HAS_VOUCHER(bits) \ 116 | (MACH_MSGH_BITS_VOUCHER(bits) != MACH_MSGH_BITS_ZERO) 117 | #define MACH_MSGH_BITS_IS_COMPLEX(bits) \ 118 | (((bits) & MACH_MSGH_BITS_COMPLEX) != MACH_MSGH_BITS_ZERO) 119 | 120 | /* importance checking macros */ 121 | #define MACH_MSGH_BITS_RAISED_IMPORTANCE(bits) \ 122 | (((bits) & MACH_MSGH_BITS_RAISEIMP) != MACH_MSGH_BITS_ZERO) 123 | #define MACH_MSGH_BITS_HOLDS_IMPORTANCE_ASSERTION(bits) \ 124 | (((bits) & MACH_MSGH_BITS_IMPHOLDASRT) != MACH_MSGH_BITS_ZERO) 125 | 126 | 127 | #define MACH_MSGH_BITS_IS_CIRCULAR(bits) \ 128 | (((bits) & MACH_MSGH_BITS_CIRCULAR) != MACH_MSGH_BITS_ZERO) 129 | 130 | #define MACH_MSG_TYPE_MOVE_RECEIVE 16 /* Must hold receive right */ 131 | #define MACH_MSG_TYPE_MOVE_SEND 17 /* Must hold send right(s) */ 132 | #define MACH_MSG_TYPE_MOVE_SEND_ONCE 18 /* Must hold sendonce right */ 133 | #define MACH_MSG_TYPE_COPY_SEND 19 /* Must hold send right(s) */ 134 | #define MACH_MSG_TYPE_MAKE_SEND 20 /* Must hold receive right */ 135 | #define MACH_MSG_TYPE_MAKE_SEND_ONCE 21 /* Must hold receive right */ 136 | #define MACH_MSG_TYPE_COPY_RECEIVE 22 /* NOT VALID */ 137 | #define MACH_MSG_TYPE_DISPOSE_RECEIVE 24 /* must hold receive right */ 138 | #define MACH_MSG_TYPE_DISPOSE_SEND 25 /* must hold send right(s) */ 139 | #define MACH_MSG_TYPE_DISPOSE_SEND_ONCE 26 /* must hold sendonce right */ 140 | 141 | typedef struct { 142 | uint32_t msgh_bits; 143 | uint32_t size; 144 | ipc_port_t *msgh_remote_port; 145 | ipc_port_t *msgh_local_port; 146 | uint32_t msgh_voucher_port_name; 147 | uint32_t msgh_id; 148 | uint64_t reserved3; 149 | uint64_t reserved4; 150 | uint64_t reserved5; 151 | uint64_t reserved6; 152 | uint64_t reserved7; 153 | uint64_t reserved8; 154 | } __attribute__((packed)) mach_msg_header_t; 155 | 156 | typedef struct { 157 | uint32_t size; 158 | uint32_t reserved; 159 | void *next; 160 | void *prev; 161 | mach_msg_header_t *hdr; 162 | } __attribute__((packed)) ipc_kmsg; 163 | 164 | void print_task(task_t *task, char *message, size_t size); 165 | void print_ipc_space(ipc_space_t *space, char *message, size_t size); 166 | void print_ipc_port(ipc_port_t *port, char *message, size_t size); 167 | void print_port_bits_text(uint64_t bits, char *message, size_t size); 168 | void print_ipc_kmsg(ipc_kmsg *kmsg, char *message, size_t size); 169 | 170 | #endif 171 | -------------------------------------------------------------------------------- /common_hooks/include/kern_funcs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jonathan Afek 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef KERN_FUNCS_H 24 | #define KERN_FUNCS_H 25 | 26 | enum IODirection 27 | { 28 | kIODirectionNone = 0x0,// same as VM_PROT_NONE 29 | kIODirectionIn = 0x1,// User land 'read', same as VM_PROT_READ 30 | kIODirectionOut = 0x2,// User land 'write', same as VM_PROT_WRITE 31 | }; 32 | 33 | #define IOBLOCKSTORAGEDEVICE_MCLASS_INST_PTR (0xfffffff0076f6e58) 34 | #define IOBLOCKSTORAGEDEVICE_MCLASS_VTABLE_PTR (0xfffffff006e14200) 35 | #define IOBLOCKSTORAGEDEVICE_VTABLE_PTR (0xfffffff006e13c00) 36 | #define IOBLOCKSTORAGEDEVICE_CONSTRUCTOR_FUNC_PTR (0xfffffff00619ad80) 37 | 38 | #define IOMFB_MCLASS_INST_PTR (0xfffffff00771b408) 39 | #define IOMFB_MCLASS_VTABLE_PTR (0xfffffff006e8d4b8) 40 | #define IOMFB_VTABLE_PTR (0xfffffff006e8ca10) 41 | #define IOMFB_CONSTRUCTOR_FUNC_PTR (0xfffffff00636a660) 42 | 43 | #define IOSERVICE_MCLASS_INST_PTR (0xfffffff007602b68) 44 | #define IOSERVICE_MCLASS_VTABLE_PTR (0xfffffff007086e80) 45 | #define IOSERVICE_VTABLE_PTR (0xfffffff007086300) 46 | 47 | #define IOUC_MCLASS_INST_PTR (0xfffffff0076033f8) 48 | #define IOUC_MCLASS_VTABLE_PTR (0xfffffff007091058) 49 | #define IOUC_VTABLE_PTR (0xfffffff007090a78) 50 | 51 | #define SALLCLASSESDICT_PTR (0xfffffff007672e00) 52 | #define SALLCLASSESLOCK_PTR (0xfffffff007672dc0) 53 | #define SSTALLEDCLASSESLOCK_PTR (0xfffffff007672dd0) 54 | 55 | //OSMetaClass::instanceConstructed() const 56 | void _ZNK11OSMetaClass19instanceConstructedEv(void *meta_class_inst_ptr); 57 | #define OSMetaClass_instanceConstructed(x) \ 58 | _ZNK11OSMetaClass19instanceConstructedEv(x) 59 | 60 | //OSMetaClass::allocClassWithName(char const*) 61 | void *_ZN11OSMetaClass18allocClassWithNameEPKc(char *name); 62 | #define OSMetaClass_allocClassWithName(x) \ 63 | _ZN11OSMetaClass18allocClassWithNameEPKc(x) 64 | 65 | //OSObject::operator new(unsigned long) 66 | void *_ZN8OSObjectnwEm(uint64_t size); 67 | #define OSObject_new(x) _ZN8OSObjectnwEm(x) 68 | 69 | //OSMetaClass::OSMetaClass(char const*, OSMetaClass const*, unsigned int) 70 | void *_ZN11OSMetaClassC2EPKcPKS_j(void *meta_class_inst_ptr, char *class_name, 71 | void *parent_meta_class_inst_ptr, 72 | uint64_t size); 73 | #define OSMetaClass_OSMetaClass(w, x, y, z) \ 74 | _ZN11OSMetaClassC2EPKcPKS_j(w, x, y, z) 75 | 76 | //OSSymbol::withCStringNoCopy(char const*) 77 | void *_ZN8OSSymbol17withCStringNoCopyEPKc(char *str); 78 | #define OSSymbol_withCStringNoCopy(x) _ZN8OSSymbol17withCStringNoCopyEPKc(x) 79 | 80 | //OSDictionary::setObject(OSSymbol const*, OSMetaClassBase const*) 81 | void _ZN12OSDictionary9setObjectEPK8OSSymbolPK15OSMetaClassBase(void *dict, 82 | void *sym, 83 | void *obj); 84 | #define OSDictionary_setObject(x, y, z) \ 85 | _ZN12OSDictionary9setObjectEPK8OSSymbolPK15OSMetaClassBase(x, y, z) 86 | 87 | //IOService::serviceMatching(char const*, OSDictionary*) 88 | void *_ZN9IOService15serviceMatchingEPKcP12OSDictionary(char *class_name, 89 | void *dict); 90 | #define IOService_serviceMatching(x, y) \ 91 | _ZN9IOService15serviceMatchingEPKcP12OSDictionary(x, y) 92 | 93 | //IOService::nameMatching(char const*, OSDictionary*) 94 | void *_ZN9IOService12nameMatchingEPKcP12OSDictionary(char *name, 95 | void *dict); 96 | #define IOService_nameMatching(x, y) \ 97 | _ZN9IOService12nameMatchingEPKcP12OSDictionary(x, y) 98 | 99 | //OSDictionary * waitForMatchingService(OSDictionary *param_1,long_long param_2) 100 | void *_ZN9IOService22waitForMatchingServiceEP12OSDictionaryy(void *dict, 101 | uint64_t timeout); 102 | #define waitForMatchingService(x, y) \ 103 | _ZN9IOService22waitForMatchingServiceEP12OSDictionaryy(x, y) 104 | 105 | //IOService::IOService(OSMetaClass*) 106 | void _ZN9IOServiceC1EPK11OSMetaClass(void *this, void *metaclass); 107 | #define IOService_IOService(x, y) _ZN9IOServiceC1EPK11OSMetaClass(x, y) 108 | 109 | //IOService::start(IOService*) 110 | uint64_t _ZN9IOService5startEPS_(void *this); 111 | #define IOService_start(x) _ZN9IOService5startEPS_(x) 112 | 113 | //IOUserClient::IOUserClient(OSMetaClass const* 114 | void _ZN12IOUserClientC2EPK11OSMetaClass(void *this, void *metaclass); 115 | #define IOUserClient_IOUserClient(x, y) \ 116 | _ZN12IOUserClientC2EPK11OSMetaClass(x, y) 117 | 118 | //IOUserClient::externalMethod 119 | uint64_t 120 | _ZN12IOUserClient14externalMethodEjP25IOExternalMethodArgumentsP24IOExternalMethodDispatchP8OSObjectPv( 121 | void *this, uint32_t selector, void *args, 122 | void *dispatch, void *target, void *reference); 123 | #define IOUserClient_externalMethod(a, b, c, d, e, f) \ 124 | _ZN12IOUserClient14externalMethodEjP25IOExternalMethodArgumentsP24IOExternalMethodDispatchP8OSObjectPv(a, b, c, d, e, f) 125 | 126 | //IOUserClient::~IOUserClient() 127 | void *_ZN12IOUserClientD2Ev(void *this); 128 | #define IOUserClient_destructor(x) _ZN12IOUserClientD2Ev(x) 129 | 130 | //OSObject::operator delete(void*, unsigned long 131 | void _ZN8OSObjectdlEPvm(void *obj, uint64_t size); 132 | #define OSObject_delete(x, y) _ZN8OSObjectdlEPvm(x, y) 133 | 134 | //IOUserClient::initWithTask(task*, void*, unsigned int) 135 | uint64_t _ZN12IOUserClient12initWithTaskEP4taskPvj(void *this, void *task, 136 | void *sid, uint64_t type); 137 | #define IOUserClient_initWithTask(a, b, c, d) \ 138 | _ZN12IOUserClient12initWithTaskEP4taskPvj(a, b, c, d) 139 | 140 | //IOUserClient::setAsyncReference64(unsigned long long*, ipc_port*, unsigned long long, unsigned, long long, task*) 141 | void _ZN12IOUserClient19setAsyncReference64EPyP8ipc_portyyP4task(void *aref, 142 | void *port, 143 | uint64_t cb, 144 | uint64_t ref, 145 | void *task); 146 | #define IOUserClient_setAsyncReference64(a, b, c, d, e) \ 147 | _ZN12IOUserClient19setAsyncReference64EPyP8ipc_portyyP4task(a, b, c, d, e) 148 | 149 | //IOUserClient::sendAsyncResult64(unsigned long long*, int, unsigned long long*, unsigned int) 150 | void _ZN12IOUserClient17sendAsyncResult64EPyiS0_j(void *aref, uint64_t res, 151 | uint64_t *args, uint64_t cnt); 152 | #define IOUserClient_sendAsyncResult64(a, b, c, d) \ 153 | _ZN12IOUserClient17sendAsyncResult64EPyiS0_j(a, b, c, d) 154 | 155 | //void _IOLog(undefined8 param_1) 156 | void IOLog(const char* fmt, ...); 157 | 158 | //void _IOSleep(undefined8 param_1) 159 | void IOSleep(uint64_t millisecs); 160 | 161 | void *current_task(); 162 | 163 | void lck_mtx_lock(void *lck_mtx); 164 | void lck_mtx_unlock(void *lck_mtx); 165 | void *lck_grp_alloc_init(char *name, void *p2); 166 | void *lck_mtx_alloc_init(void *mtx_grp, void *p2); 167 | 168 | void kernel_thread_start(void *code, void *param, void *new_thread); 169 | 170 | char *strncat(char *destination, const char *source, size_t size); 171 | 172 | void *kern_os_malloc(size_t size); 173 | void kern_os_free(void *buf); 174 | 175 | #endif 176 | -------------------------------------------------------------------------------- /common_hooks/include/qemu-guest-services.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jonathan Afek 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef QEMU_GUEST_SERVICES_H 24 | #define QEMU_GUEST_SERVICES_H 25 | 26 | int64_t qc_size_file(uint64_t index); 27 | int64_t qc_write_file(void *buffer_guest_ptr, uint64_t length, 28 | uint64_t offset, uint64_t index); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /common_hooks/include/utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jonathan Afek 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef UTILS_H 24 | #define UTILS_H 25 | 26 | void cancel(); 27 | 28 | char *my_itoa(uint64_t num, char *str); 29 | void log_uint64(const char *name, uint64_t num); 30 | char *strncat_int64(char *destination, const char *source, size_t size, 31 | uint64_t num); 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /common_hooks/src/ipc-obj.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jonathan Afek 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | #include "utils.h" 27 | #include "kern_funcs.h" 28 | #include "ipc-obj.h" 29 | 30 | void print_task(task_t *task, char *message, size_t size) 31 | { 32 | strncat(message, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n", size); 33 | strncat_int64(message, "task->bsd_info: ", size, (uint64_t)task->bsd_info); 34 | //sanity 35 | if (NULL != task->bsd_info) { 36 | strncat_int64(message, "task->bsd_info->p_pid: ", size, (uint64_t)task->bsd_info->p_pid); 37 | strncat(message, "task name: ", size); 38 | strncat(message, &task->bsd_info->p_name[0], size); 39 | strncat(message, "\n", size); 40 | } 41 | strncat(message, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n", size); 42 | } 43 | 44 | void print_ipc_space(ipc_space_t *space, char *message, size_t size) 45 | { 46 | strncat(message, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n", size); 47 | strncat_int64(message, "space->is_table_size: ", size, (uint64_t)space->is_table_size); 48 | strncat_int64(message, "space->is_table_free: ", size, (uint64_t)space->is_table_free); 49 | strncat_int64(message, "space->is_table: ", size, (uint64_t)space->is_table); 50 | strncat_int64(message, "space->is_task: ", size, (uint64_t)space->is_task); 51 | //kernel ipc_space doesn't point to the kernel task so it is NULL 52 | if (NULL != space->is_task) { 53 | print_task(space->is_task, message, size); 54 | } 55 | strncat(message, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n", size); 56 | } 57 | 58 | void print_ipc_port(ipc_port_t *port, char *message, size_t size) 59 | { 60 | uint32_t is_active = (port->ip_object.io_bits >> 31) & 1; 61 | uint32_t otype = (port->ip_object.io_bits >> 16) & 0x7FFF; 62 | uint32_t is_preallocated = (port->ip_object.io_bits >> 15) & 1; 63 | uint32_t kotype = port->ip_object.io_bits & 0xFFF; 64 | 65 | strncat(message, "===========================================================\n", size); 66 | 67 | strncat_int64(message, "port->ip_object.io_bits: ", size, (uint64_t)port->ip_object.io_bits); 68 | strncat_int64(message, "is_active: ", size, (uint64_t)is_active); 69 | //strncat(message, "otype map: \n" 70 | // "#define IOT_PORT 0\n" 71 | // "#define IOT_PORT_SET 1\n" 72 | // "#define IOT_NUMBER 2 /* number of types used */\n" 73 | // "" 74 | // , 75 | // size); 76 | strncat_int64(message, "otype: ", size, (uint64_t)otype); 77 | switch (otype) { 78 | case 0: 79 | strncat(message, "(IOT_PORT)\n", size); 80 | break; 81 | case 1: 82 | strncat(message, "(IOT_PORT_SET)\n", size); 83 | break; 84 | case 2: 85 | strncat(message, "(IOT_NUMBER)\n", size); 86 | break; 87 | default: 88 | strncat(message, "(OTHER TYPE)\n", size); 89 | break; 90 | } 91 | strncat_int64(message, "is_preallocated: ", size, (uint64_t)is_preallocated); 92 | //strncat(message, "kotype map: \n" 93 | // "#define IKOT_NONE 0\n" 94 | // "#define IKOT_THREAD 1\n" 95 | // "#define IKOT_TASK 2\n" 96 | // "#define IKOT_HOST 3\n" 97 | // "#define IKOT_HOST_PRIV 4\n" 98 | // "#define IKOT_PROCESSOR 5\n" 99 | // "#define IKOT_PSET 6\n" 100 | // "#define IKOT_PSET_NAME 7\n" 101 | // "#define IKOT_TIMER 8\n" 102 | // "#define IKOT_PAGING_REQUEST 9\n" 103 | // "#define IKOT_MIG 10\n" 104 | // "#define IKOT_MEMORY_OBJECT 11\n" 105 | // "#define IKOT_XMM_PAGER 12\n" 106 | // "#define IKOT_XMM_KERNEL 13\n" 107 | // "#define IKOT_XMM_REPLY 14\n" 108 | // "#define IKOT_UND_REPLY 15\n" 109 | // "#define IKOT_HOST_NOTIFY 16\n" 110 | // "#define IKOT_HOST_SECURITY 17\n" 111 | // "#define IKOT_LEDGER 18\n" 112 | // "#define IKOT_MASTER_DEVICE 19\n" 113 | // "#define IKOT_TASK_NAME 20\n" 114 | // "#define IKOT_SUBSYSTEM 21\n" 115 | // "#define IKOT_IO_DONE_QUEUE 22\n" 116 | // "#define IKOT_SEMAPHORE 23\n" 117 | // "#define IKOT_LOCK_SET 24\n" 118 | // "#define IKOT_CLOCK 25\n" 119 | // "#define IKOT_CLOCK_CTRL 26\n" 120 | // "#define IKOT_IOKIT_IDENT 27\n" 121 | // "#define IKOT_NAMED_ENTRY 28\n" 122 | // "#define IKOT_IOKIT_CONNECT 29\n" 123 | // "#define IKOT_IOKIT_OBJECT 30\n" 124 | // "#define IKOT_UPL 31\n" 125 | // "#define IKOT_MEM_OBJ_CONTROL 32\n" 126 | // "#define IKOT_AU_SESSIONPORT 33\n" 127 | // "#define IKOT_FILEPORT 34\n" 128 | // "#define IKOT_LABELH 35\n" 129 | // "#define IKOT_TASK_RESUME 36\n" 130 | // "#define IKOT_VOUCHER 37\n" 131 | // "#define IKOT_VOUCHER_ATTR_CONTROL 38\n" 132 | // "#define IKOT_WORK_INTERVAL 39\n" 133 | // "#define IKOT_UX_HANDLER 40\n" 134 | // "#define IKOT_UNKNOWN 41\n" 135 | // "" 136 | // , size); 137 | strncat_int64(message, "kotype: ", size, (uint64_t)kotype); 138 | switch (kotype) { 139 | case 0: 140 | strncat(message, "(IKOT_NONE)\n", size); 141 | break; 142 | case 1: 143 | strncat(message, "(IKOT_THREAD)\n", size); 144 | break; 145 | case 2: 146 | strncat(message, "(IKOT_TASK)\n", size); 147 | break; 148 | case 3: 149 | strncat(message, "(IKOT_HOST)\n", size); 150 | break; 151 | case 4: 152 | strncat(message, "(IKOT_HOST_PRIV)\n", size); 153 | break; 154 | case 41: 155 | strncat(message, "(IKOT_UNKNOWN)\n", size); 156 | break; 157 | default: 158 | strncat(message, "(OTHER TYPE)\n", size); 159 | break; 160 | } 161 | strncat_int64(message, "port->ip_object.io_references: ", size, (uint64_t)port->ip_object.io_references); 162 | strncat_int64(message, "port->ip_object.io_lock_data: ", size, (uint64_t)port->ip_object.io_lock_data); 163 | strncat_int64(message, "port->receiver: ", size, (uint64_t)port->receiver); 164 | //TODO: JONATHANA make sure it is both active and not in transfer... 165 | if (is_active && (NULL != port->receiver)) { 166 | print_ipc_space(port->receiver, message, size); 167 | } 168 | strncat(message, "===========================================================\n", size); 169 | } 170 | 171 | void print_port_bits_text(uint64_t bits, char *message, size_t size) 172 | { 173 | switch (bits) { 174 | case 16: 175 | strncat(message, "(MACH_MSG_TYPE_MOVE_RECEIVE)\n", size); 176 | break; 177 | case 17: 178 | strncat(message, "(MACH_MSG_TYPE_MOVE_SEND)\n", size); 179 | break; 180 | case 18: 181 | strncat(message, "(MACH_MSG_TYPE_MOVE_SEND_ONCE)\n", size); 182 | break; 183 | case 19: 184 | strncat(message, "(MACH_MSG_TYPE_COPY_SEND)\n", size); 185 | break; 186 | case 20: 187 | strncat(message, "(MACH_MSG_TYPE_MAKE_SEND)\n", size); 188 | break; 189 | case 21: 190 | strncat(message, "(MACH_MSG_TYPE_MAKE_SEND_ONCE)\n", size); 191 | break; 192 | case 22: 193 | strncat(message, "(MACH_MSG_TYPE_COPY_RECEIVE)\n", size); 194 | break; 195 | case 24: 196 | strncat(message, "(MACH_MSG_TYPE_DISPOSE_RECEIVE)\n", size); 197 | break; 198 | case 25: 199 | strncat(message, "(MACH_MSG_TYPE_DISPOSE_SEND)\n", size); 200 | break; 201 | case 26: 202 | strncat(message, "(MACH_MSG_TYPE_DISPOSE_SEND_ONCE)\n", size); 203 | break; 204 | default: 205 | strncat(message, "(OTHER TYPE)\n", size); 206 | break; 207 | } 208 | } 209 | 210 | void print_ipc_kmsg(ipc_kmsg *kmsg, char *message, size_t size) 211 | { 212 | strncat(message, "*********************************************************************************************\n", size); 213 | task_t *cur_task = (task_t *)current_task(); 214 | strncat_int64(message, "current task: ", size, (uint64_t)cur_task); 215 | print_task(cur_task, message, size); 216 | strncat_int64(message, "ipc_kmsg_send() kmsg: ", size, (uint64_t)kmsg); 217 | strncat_int64(message, "kmsg->size: ", size, (uint64_t)kmsg->size); 218 | strncat_int64(message, "kmsg->next: ", size, (uint64_t)kmsg->next); 219 | strncat_int64(message, "kmsg->prev: ", size, (uint64_t)kmsg->prev); 220 | strncat_int64(message, "kmsg->hdr: ", size, (uint64_t)kmsg->hdr); 221 | 222 | uint64_t local_bits = (uint64_t)MACH_MSGH_BITS_LOCAL(kmsg->hdr->msgh_bits); 223 | uint64_t remote_bits = (uint64_t)MACH_MSGH_BITS_REMOTE(kmsg->hdr->msgh_bits); 224 | uint64_t voucher_bits = (uint64_t)MACH_MSGH_BITS_VOUCHER(kmsg->hdr->msgh_bits); 225 | uint64_t is_complex_bits = (uint64_t)MACH_MSGH_BITS_IS_COMPLEX(kmsg->hdr->msgh_bits); 226 | uint64_t is_raiseimp_bits = (uint64_t)MACH_MSGH_BITS_RAISED_IMPORTANCE(kmsg->hdr->msgh_bits); 227 | uint64_t is_impholdasrt_bits = (uint64_t)MACH_MSGH_BITS_HOLDS_IMPORTANCE_ASSERTION(kmsg->hdr->msgh_bits); 228 | uint64_t is_circular_bits = (uint64_t)MACH_MSGH_BITS_IS_CIRCULAR(kmsg->hdr->msgh_bits); 229 | //strncat(message, "bit rights map: \n" 230 | // "#define MACH_MSG_TYPE_MOVE_RECEIVE 16 /* Must hold receive right */\n" 231 | // "#define MACH_MSG_TYPE_MOVE_SEND 17 /* Must hold send right(s) */\n" 232 | // "#define MACH_MSG_TYPE_MOVE_SEND_ONCE 18 /* Must hold sendonce right */\n" 233 | // "#define MACH_MSG_TYPE_COPY_SEND 19 /* Must hold send right(s) */\n" 234 | // "#define MACH_MSG_TYPE_MAKE_SEND 20 /* Must hold receive right */\n" 235 | // "#define MACH_MSG_TYPE_MAKE_SEND_ONCE 21 /* Must hold receive right */\n" 236 | // "#define MACH_MSG_TYPE_COPY_RECEIVE 22 /* NOT VALID */\n" 237 | // "#define MACH_MSG_TYPE_DISPOSE_RECEIVE 24 /* must hold receive right */\n" 238 | // "#define MACH_MSG_TYPE_DISPOSE_SEND 25 /* must hold send right(s) */\n" 239 | // "#define MACH_MSG_TYPE_DISPOSE_SEND_ONCE 26 /* must hold sendonce right */\n" 240 | // "" 241 | // , size); 242 | strncat_int64(message, "kmsg->hdr->msgh_bits(local): ", size, (uint64_t)local_bits); 243 | print_port_bits_text((uint64_t)local_bits, message, size); 244 | strncat_int64(message, "kmsg->hdr->msgh_bits(remote): ", size, (uint64_t)remote_bits); 245 | print_port_bits_text((uint64_t)remote_bits, message, size); 246 | strncat_int64(message, "kmsg->hdr->msgh_bits(voucher): ", size, (uint64_t)voucher_bits); 247 | print_port_bits_text((uint64_t)voucher_bits, message, size); 248 | strncat_int64(message, "kmsg->hdr->msgh_bits(is_complex): ", size, (uint64_t)is_complex_bits); 249 | strncat_int64(message, "kmsg->hdr->msgh_bits(is_raiseimp_bits): ", size, (uint64_t)is_raiseimp_bits); 250 | strncat_int64(message, "kmsg->hdr->msgh_bits(is_impholdasrt_bits): ", size, (uint64_t)is_impholdasrt_bits); 251 | strncat_int64(message, "kmsg->hdr->msgh_bits(is_circular_bits): ", size, (uint64_t)is_circular_bits); 252 | strncat_int64(message, "kmsg->hdr->size: ", size, (uint64_t)kmsg->hdr->size); 253 | strncat_int64(message, "kmsg->hdr->msgh_remote_port: ", size, (uint64_t)kmsg->hdr->msgh_remote_port); 254 | strncat_int64(message, "kmsg->hdr->msgh_local_port: ", size, (uint64_t)kmsg->hdr->msgh_local_port); 255 | strncat_int64(message, "kmsg->hdr->msgh_voucher_port_name: ", size, (uint64_t)kmsg->hdr->msgh_voucher_port_name); 256 | strncat_int64(message, "kmsg->hdr->msgh_id: ", size, (uint64_t)kmsg->hdr->msgh_id); 257 | if (0 != remote_bits) { 258 | strncat(message, "kmsg->hdr->msgh_remote_port CONTENT: \n", size); 259 | print_ipc_port(kmsg->hdr->msgh_remote_port, message, size); 260 | } 261 | if (0 != local_bits) { 262 | strncat(message, "kmsg->hdr->msgh_local_port CONTENT: \n", size); 263 | print_ipc_port(kmsg->hdr->msgh_local_port, message, size); 264 | } 265 | strncat(message, "*********************************************************************************************\n", size); 266 | } 267 | -------------------------------------------------------------------------------- /common_hooks/src/qemu-guest-services/file.c: -------------------------------------------------------------------------------- 1 | /* 2 | * QEMU Guest Services - Socket API 3 | * 4 | * Copyright (c) 2019 Lev Aronsky 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without retvaltriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPretvalS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #include "hw/arm/guest-services/general.h" 26 | 27 | static int64_t qemu_file_call(qemu_call_t *qcall) 28 | { 29 | qemu_call(qcall); 30 | 31 | guest_svcs_errno = qcall->error; 32 | return qcall->retval; 33 | } 34 | int64_t qc_size_file(uint64_t index) 35 | { 36 | qemu_call_t qcall = { 37 | .call_number = QC_SIZE_FILE, 38 | .args.size_file.index = index, 39 | }; 40 | 41 | return qemu_file_call(&qcall); 42 | } 43 | 44 | int64_t qc_write_file(void *buffer_guest_ptr, uint64_t length, 45 | uint64_t offset, uint64_t index) 46 | { 47 | qemu_call_t qcall = { 48 | .call_number = QC_WRITE_FILE, 49 | .args.write_file.buffer_guest_ptr = (uint64_t)buffer_guest_ptr, 50 | .args.write_file.length = length, 51 | .args.write_file.offset = offset, 52 | .args.write_file.index = index, 53 | }; 54 | 55 | return qemu_file_call(&qcall); 56 | } 57 | 58 | int64_t qc_read_file(void *buffer_guest_ptr, uint64_t length, 59 | uint64_t offset, uint64_t index) 60 | { 61 | qemu_call_t qcall = { 62 | .call_number = QC_READ_FILE, 63 | .args.read_file.buffer_guest_ptr = (uint64_t)buffer_guest_ptr, 64 | .args.read_file.length = length, 65 | .args.read_file.offset = offset, 66 | .args.read_file.index = index, 67 | }; 68 | 69 | return qemu_file_call(&qcall); 70 | } 71 | -------------------------------------------------------------------------------- /common_hooks/src/qemu-guest-services/general.c: -------------------------------------------------------------------------------- 1 | /* 2 | * QEMU Guest Services - General 3 | * 4 | * Copyright (c) 2019 Lev Aronsky 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without retvaltriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPretvalS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #include "hw/arm/guest-services/general.h" 26 | 27 | int32_t guest_svcs_errno = 0; 28 | 29 | void qemu_call(qemu_call_t *qcall) 30 | { 31 | asm volatile ("mov x0, %[addr]"::[addr] "r" (qcall)); 32 | asm volatile (".byte 0x00"); 33 | asm volatile (".byte 0xff"); 34 | asm volatile (".byte 0x1b"); 35 | asm volatile (".byte 0xd5"); 36 | } 37 | -------------------------------------------------------------------------------- /common_hooks/src/utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jonathan Afek 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | #include "utils.h" 27 | #include "kern_funcs.h" 28 | 29 | char *strncat_int64(char *destination, const char *source, size_t size, 30 | uint64_t num) 31 | { 32 | char str[1024]; 33 | strncat(destination, source, size); 34 | my_itoa((uint64_t)num, &str[0]); 35 | strncat(destination, str, size); 36 | strncat(destination, "\n", size); 37 | } 38 | 39 | void cancel() 40 | { 41 | *(uint64_t *)(0) = 0xffffffffffffffff; 42 | } 43 | 44 | char *my_itoa(uint64_t num, char *str) 45 | { 46 | char digits[64]; 47 | char *dp; 48 | char *cp = str; 49 | 50 | if (num == 0) { 51 | *cp++ = '0'; 52 | } 53 | else { 54 | dp = digits; 55 | while (num) { 56 | *dp++ = '0' + num % 10; 57 | num /= 10; 58 | } 59 | while (dp != digits) { 60 | *cp++ = *--dp; 61 | } 62 | } 63 | *cp++ = '\0'; 64 | 65 | return str; 66 | } 67 | 68 | //Print to console 69 | void log_uint64(const char *name, uint64_t num) 70 | { 71 | char str[1024]; 72 | 73 | IOLog(name); 74 | my_itoa((uint64_t)num, &str[0]); 75 | IOLog(&str[0]); 76 | IOLog("\n"); 77 | } 78 | -------------------------------------------------------------------------------- /function-hooks/ipc_kmsg_send/Makefile: -------------------------------------------------------------------------------- 1 | src := $(wildcard src/*.c) $(wildcard src/**/*.c) $(wildcard ../../common_hooks/src/*.c) $(wildcard ../../common_hooks/src/**/*.c) 2 | 3 | ifndef XNU_SOURCES 4 | $(error XNU_SOURCES not set!) 5 | endif 6 | 7 | ifndef KERNEL_SYMBOLS_FILE 8 | $(error KERNEL_SYMBOLS_FILE not set!) 9 | endif 10 | 11 | ifndef QEMU_DIR 12 | $(error QEMU_DIR is not set) 13 | endif 14 | 15 | SELF_DIR := $(dir $(lastword $(MAKEFILE_LIST))) 16 | 17 | MKDIR_P = mkdir -p 18 | TARGET_DIR=bin 19 | TARGET = $(TARGET_DIR)/ipc_kmsg_send 20 | CROSS = aarch64-none-elf- 21 | CC = $(CROSS)gcc 22 | OBJCOPY = $(CROSS)objcopy 23 | LDFLAGS = -Wl,-T,flat.ld,-N 24 | DEFINES = -DOUT_OF_TREE_BUILD -DBCM2837 -DKERNEL -DXNU_KERNEL_PRIVATE -D__arm64__ -D__LITTLE_ENDIAN__ 25 | INCLUDES = -I$(XNU_SOURCES)/bsd \ 26 | -I$(XNU_SOURCES)/osfmk \ 27 | -I$(XNU_SOURCES)/osfmk/libsa \ 28 | -I$(XNU_SOURCES)/libkern \ 29 | -I$(XNU_SOURCES)/pexpert \ 30 | -I$(XNU_SOURCES)/EXTERNAL_HEADERS \ 31 | -I$(QEMU_DIR)/include \ 32 | -I$(SELF_DIR)/../../common_hooks/include 33 | CFLAGS = -fpie -flto -fwhole-program -fno-plt -nostdlib -nostartfiles $(DEFINES) $(LDFLAGS) $(INCLUDES) 34 | 35 | default: $(TARGET_DIR) $(TARGET).bin 36 | 37 | $(TARGET_DIR): 38 | @${MKDIR_P} $@ 39 | 40 | $(TARGET).bin: $(TARGET).elf 41 | @echo "Creating a flat binary..." 42 | @$(OBJCOPY) -O binary $^ $@ 43 | 44 | $(TARGET).elf: $(src) kernel.ld 45 | @echo "Building elf from source..." 46 | @$(CC) -o $@ $(CFLAGS) $(src) 47 | 48 | kernel.ld: 49 | @echo "Generating symbols for linker..." 50 | @python3 getsymbols.py $(KERNEL_SYMBOLS_FILE) $@ 51 | 52 | .PHONY: clean 53 | clean: 54 | rm kernel.ld 55 | rm -rf $(TARGET_DIR)* 56 | -------------------------------------------------------------------------------- /function-hooks/ipc_kmsg_send/flat.ld: -------------------------------------------------------------------------------- 1 | PHDRS 2 | { 3 | text PT_LOAD; 4 | } 5 | 6 | ENTRY(_start) 7 | 8 | SECTIONS 9 | { 10 | /* Kernel functions */ 11 | INCLUDE kernel.ld 12 | 13 | .start : { *(.start) } :text 14 | .text : { *(.text) } 15 | } -------------------------------------------------------------------------------- /function-hooks/ipc_kmsg_send/getsymbols.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import csv 4 | import sys 5 | 6 | def nm2ld(in_file, out_file): 7 | symbols = open(in_file).read() 8 | writer = open(out_file, 'wt') 9 | 10 | for symbol in symbols.splitlines(): 11 | name = symbol.split(" ")[2] 12 | location = symbol.split(" ")[0] 13 | 14 | if name.startswith('_'): 15 | name = name[1:] 16 | 17 | print(f"PROVIDE ({name} = 0x{location});", file=writer) 18 | 19 | def main(): 20 | if len(sys.argv) not in (2, 3): 21 | print("Usage: python3 getsymbols.py [kernel-symbols-ld-provider]") 22 | sys.exit(1) 23 | 24 | in_file = sys.argv[1] 25 | out_file = sys.argv[2] if len(sys.argv) == 3 else "kernel.ld" 26 | 27 | nm2ld(in_file, out_file) 28 | 29 | if __name__ == "__main__": 30 | main() 31 | -------------------------------------------------------------------------------- /function-hooks/ipc_kmsg_send/src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jonathan Afek 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | #include "kern_funcs.h" 27 | #include "utils.h" 28 | #include "qemu-guest-services.h" 29 | #include "ipc-obj.h" 30 | 31 | void _start() __attribute__((section(".start"))); 32 | 33 | void _start(ipc_kmsg *kmsg) { 34 | //hope that first time is non ovrelapping because it is not really protected 35 | //TODO: initialize from outside the hook to remove this assumption 36 | //ugly solution to use preallocated global data in the hooks/drivers at 37 | //a fixed address allocated in the "boot loader" 38 | //TODO: find a less ugly solution for this global storage 39 | void *mtx_grp; 40 | void **global_mtx = (void *)0xFFFFFFF009BF4C00; 41 | if (NULL == *global_mtx) { 42 | mtx_grp = lck_grp_alloc_init("log_file_mutex", NULL); 43 | *global_mtx = lck_mtx_alloc_init(mtx_grp, NULL); 44 | } 45 | lck_mtx_lock(*global_mtx); 46 | //sanity 47 | uint64_t remote_bits = (uint64_t)MACH_MSGH_BITS_REMOTE(kmsg->hdr->msgh_bits); 48 | if (0 != remote_bits) { 49 | ipc_port_t *port = kmsg->hdr->msgh_remote_port; 50 | //TODO: move this extraction to another place 51 | uint32_t is_active = (port->ip_object.io_bits >> 31) & 1; 52 | if (is_active && (NULL != port->receiver)) { 53 | ipc_space_t *space = port->receiver; 54 | size_t size = 16384; 55 | char *message = kern_os_malloc(size); 56 | message[0] = '\0'; 57 | strncat(message, "^^^^^^^^^^^^^^^^^^^^^^^^ ipc_kmsg_send()\n", size); 58 | //if it is directed to the kernel (the mach message that is) 59 | //messages not to the kernel are printed in another hook 60 | if (NULL == space->is_task) { 61 | print_ipc_kmsg(kmsg, message, size); 62 | } 63 | qc_write_file(message, 64 | strlen(message), (uint64_t)qc_size_file(2), 2); 65 | kern_os_free(message); 66 | } 67 | } 68 | lck_mtx_unlock(*global_mtx); 69 | } 70 | -------------------------------------------------------------------------------- /function-hooks/ipc_mqueue_send/Makefile: -------------------------------------------------------------------------------- 1 | src := $(wildcard src/*.c) $(wildcard src/**/*.c) $(wildcard ../../common_hooks/src/*.c) $(wildcard ../../common_hooks/src/**/*.c) 2 | 3 | ifndef XNU_SOURCES 4 | $(error XNU_SOURCES not set!) 5 | endif 6 | 7 | ifndef KERNEL_SYMBOLS_FILE 8 | $(error KERNEL_SYMBOLS_FILE not set!) 9 | endif 10 | 11 | ifndef QEMU_DIR 12 | $(error QEMU_DIR is not set) 13 | endif 14 | 15 | SELF_DIR := $(dir $(lastword $(MAKEFILE_LIST))) 16 | 17 | MKDIR_P = mkdir -p 18 | TARGET_DIR=bin 19 | TARGET = $(TARGET_DIR)/ipc_mqueue_send 20 | CROSS = aarch64-none-elf- 21 | CC = $(CROSS)gcc 22 | OBJCOPY = $(CROSS)objcopy 23 | LDFLAGS = -Wl,-T,flat.ld,-N 24 | DEFINES = -DOUT_OF_TREE_BUILD -DBCM2837 -DKERNEL -DXNU_KERNEL_PRIVATE -D__arm64__ -D__LITTLE_ENDIAN__ 25 | INCLUDES = -I$(XNU_SOURCES)/bsd \ 26 | -I$(XNU_SOURCES)/osfmk \ 27 | -I$(XNU_SOURCES)/osfmk/libsa \ 28 | -I$(XNU_SOURCES)/libkern \ 29 | -I$(XNU_SOURCES)/pexpert \ 30 | -I$(XNU_SOURCES)/EXTERNAL_HEADERS \ 31 | -I$(QEMU_DIR)/include \ 32 | -I$(SELF_DIR)/../../common_hooks/include 33 | CFLAGS = -fpie -flto -fwhole-program -fno-plt -nostdlib -nostartfiles $(DEFINES) $(LDFLAGS) $(INCLUDES) 34 | 35 | default: $(TARGET_DIR) $(TARGET).bin 36 | 37 | $(TARGET_DIR): 38 | @${MKDIR_P} $@ 39 | 40 | $(TARGET).bin: $(TARGET).elf 41 | @echo "Creating a flat binary..." 42 | @$(OBJCOPY) -O binary $^ $@ 43 | 44 | $(TARGET).elf: $(src) kernel.ld 45 | @echo "Building elf from source..." 46 | @$(CC) -o $@ $(CFLAGS) $(src) 47 | 48 | kernel.ld: 49 | @echo "Generating symbols for linker..." 50 | @python3 getsymbols.py $(KERNEL_SYMBOLS_FILE) $@ 51 | 52 | .PHONY: clean 53 | clean: 54 | rm kernel.ld 55 | rm -rf $(TARGET_DIR)* 56 | -------------------------------------------------------------------------------- /function-hooks/ipc_mqueue_send/flat.ld: -------------------------------------------------------------------------------- 1 | PHDRS 2 | { 3 | text PT_LOAD; 4 | } 5 | 6 | ENTRY(_start) 7 | 8 | SECTIONS 9 | { 10 | /* Kernel functions */ 11 | INCLUDE kernel.ld 12 | 13 | .start : { *(.start) } :text 14 | .text : { *(.text) } 15 | } -------------------------------------------------------------------------------- /function-hooks/ipc_mqueue_send/getsymbols.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import csv 4 | import sys 5 | 6 | def nm2ld(in_file, out_file): 7 | symbols = open(in_file).read() 8 | writer = open(out_file, 'wt') 9 | 10 | for symbol in symbols.splitlines(): 11 | name = symbol.split(" ")[2] 12 | location = symbol.split(" ")[0] 13 | 14 | if name.startswith('_'): 15 | name = name[1:] 16 | 17 | print(f"PROVIDE ({name} = 0x{location});", file=writer) 18 | 19 | def main(): 20 | if len(sys.argv) not in (2, 3): 21 | print("Usage: python3 getsymbols.py [kernel-symbols-ld-provider]") 22 | sys.exit(1) 23 | 24 | in_file = sys.argv[1] 25 | out_file = sys.argv[2] if len(sys.argv) == 3 else "kernel.ld" 26 | 27 | nm2ld(in_file, out_file) 28 | 29 | if __name__ == "__main__": 30 | main() 31 | -------------------------------------------------------------------------------- /function-hooks/ipc_mqueue_send/src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jonathan Afek 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | #include "kern_funcs.h" 27 | #include "utils.h" 28 | #include "qemu-guest-services.h" 29 | #include "ipc-obj.h" 30 | 31 | void _start() __attribute__((section(".start"))); 32 | 33 | void _start() { 34 | //hope that first time is non ovrelapping because it is not really protected 35 | //TODO: initialize from outside the hook to remove this assumption 36 | //ugly solution to use preallocated global data in the hooks/drivers at 37 | //a fixed address allocated in the "boot loader" 38 | //TODO: find a less ugly solution for this global storage 39 | void *mtx_grp; 40 | void **global_mtx = (void *)0xFFFFFFF009BF4C00; 41 | if (NULL == *global_mtx) { 42 | mtx_grp = lck_grp_alloc_init("log_file_mutex", NULL); 43 | *global_mtx = lck_mtx_alloc_init(mtx_grp, NULL); 44 | } 45 | uint64_t kmsg_uint; 46 | asm volatile ("mov %0, x19" : "=r"(kmsg_uint) ::); 47 | ipc_kmsg *kmsg = (ipc_kmsg *)kmsg_uint; 48 | lck_mtx_lock(*global_mtx); 49 | size_t size = 16384; 50 | char *message = kern_os_malloc(size); 51 | message[0] = '\0'; 52 | strncat(message, "^^^^^^^^^^^^^^^^^^^^^^^^ ipc_mqueue_send()\n", size); 53 | print_ipc_kmsg(kmsg, message, size); 54 | qc_write_file(message, strlen(message), (uint64_t)qc_size_file(2), 2); 55 | kern_os_free(message); 56 | lck_mtx_unlock(*global_mtx); 57 | } 58 | -------------------------------------------------------------------------------- /gdb/README.md: -------------------------------------------------------------------------------- 1 | # XNU Kernel Debug - GDB Helper Functions 2 | 3 | To ease kernel debugging for our project we'd developed some gdb scripts that will help us along the way. 4 | Here listed what had been implemented already, just use find to search for information that you looking for, if it is not here - PR it :) 5 | 6 | > This is an open source project! Feel more than welcome to contribute! Lets bring the iOS on QEMU up and running :) 7 | 8 | ### Important Note 9 | Those scripts works on the kernel version presented in our work. Some of the functionality was availeble only after reversing the relevant code of specific kernelcashe. Scripts do not support debugging of kernelcache that runs with KSLR! 10 | 11 | ### Install 12 | After completing all steps described [here](https://alephsecurity.com/2019/06/17/xnu-qemu-arm64-1/), copy this project to your project directory (or any other place), run gdb, connect to the QEMU server (target remote :1234) and run: 13 | ```shell 14 | $ source load.py 15 | ``` 16 | Also, run it after any edit of the scripts for the change to take effect 17 | 18 | ### Use 19 | 20 | 21 | Show list of all threads 22 | ```shell 23 | $ xnu-threads 24 | ``` 25 | Show list of all tasks 26 | ```shell 27 | $ xnu-tasks 28 | ``` 29 | Show list of all user threads 30 | ```shell 31 | $ xnu-threads user 32 | ``` 33 | Show list of current's task threads 34 | ```shell 35 | $ xnu-threads current 36 | ``` 37 | Show threads of specific *task* 38 | ```shell 39 | $ xnu-threads ${TASK_PTR} 40 | ``` 41 | Show all parsed info of specific *thread* 42 | ```shell 43 | $ xnu-thread-info ${THREAD_PTR} 44 | ``` 45 | Show all parsed info of specific *task* 46 | ```shell 47 | $ xnu-task-info ${TASK_PTR} 48 | ``` 49 | Break on next Context Switch 50 | ```shell 51 | $ xnu-switch 52 | ``` 53 | Break on specific thread within specified number of context switches 54 | ```shell 55 | $ xnu-switch ${THREAD_PTR} ${NUM_OF_RETRIES} 56 | ``` 57 | Print the metadata of all the kernel allocation zones 58 | ```shell 59 | $ xnu-zones 60 | ``` 61 | Show *is_table* of *itk_space* of specific *task*/*space* 62 | ```shell 63 | $ xnu-ipc_entry-list -task ${TASK_PTR} 64 | $ xnu-ipc_entry-list -space ${SPACE_PTR} 65 | ``` 66 | Show parsed info of *ipc_port* 67 | ```shell 68 | $ xnu-ipc-port-info ${IPC_PORT_PTR} 69 | ``` 70 | Show *ipc_voucher* info of specific *thread* 71 | ```shell 72 | $ xnu-voucher-info ${THREAD_PTR} 73 | ``` 74 | -------------------------------------------------------------------------------- /gdb/load.py: -------------------------------------------------------------------------------- 1 | """ 2 | We want to change the code while still in gdb session. Pyhton wont import already loaded 3 | module. Taht is why we use reload module function. Please note that the ipmorts are not circular 4 | and their order in MODULES_TO_IPMORT matters. 5 | """ 6 | import os 7 | import sys 8 | import traceback 9 | import importlib 10 | import logging 11 | 12 | sys.path.insert(0, os.path.dirname(os.path.expanduser(__file__))) 13 | logging.getLogger("xnu").setLevel(logging.WARNING) 14 | MODULES_TO_IPMORT = [ 15 | "xnu.constants", 16 | "xnu.utils", 17 | "xnu.sys_info", 18 | "xnu.zone", 19 | "xnu.xnu_types", 20 | "xnu.tasks" 21 | ] 22 | 23 | try: 24 | #this will make python to look for new versions 25 | importlib.invalidate_caches() 26 | for module in MODULES_TO_IPMORT: 27 | if module not in sys.modules: 28 | importlib.import_module(module) 29 | else: 30 | importlib.reload(importlib.import_module(module)) 31 | 32 | except Exception as error: 33 | gdb.write( 34 | f"NOTE: Could not init the gdb module: {error} {traceback.format_exc()}\n") 35 | -------------------------------------------------------------------------------- /gdb/xnu/KnownLables: -------------------------------------------------------------------------------- 1 | { 2 | "0xfffffff0070db3fc" : "_lck_mtx_sleep", 3 | "0xfffffff0070db634" : "_lck_mtx_sleep_deadline", 4 | "0xfffffff007178940" : "FUN_fffffff007179a0c", 5 | "0xfffffff0071ac920" : "FUN_fffffff0071ac89c" 6 | } -------------------------------------------------------------------------------- /gdb/xnu/__init__.py: -------------------------------------------------------------------------------- 1 | # nothing to do for the initialization of this package 2 | -------------------------------------------------------------------------------- /gdb/xnu/constants.py: -------------------------------------------------------------------------------- 1 | """ 2 | Here defined all constants, serving all mudules. 3 | """ 4 | 5 | from enum import Enum 6 | 7 | GLOBAL_THREADS_PTR = 0xfffffff00760f9e0 8 | GLOBAL_TASKS_PTR = 0xfffffff00760f9c0 9 | NULL_PTR = 0x0000000000000000 10 | NULL_PTR_STR = "0x0000000000000000" 11 | CURRENT_THREAD = "$TPIDR_EL1" 12 | 13 | IE_BITS_TYPE_MASK = 0x001f0000 14 | 15 | IO_BITS_KOTYPE = 0x00000fff 16 | 17 | 18 | class NextPcHelpOffsets(Enum): 19 | """ Info taken by reversing the 16B92 kernel version """ 20 | NEXT_IN_THREAD_RUN = 0xfffffff0070e7d0c 21 | NEXT_IN_THREAD_BLOCK = 0xfffffff0070e3554 22 | EXEPTION_RETURN_PTR = 0xfffffff0070a1800 23 | SP_OFFSET_FROM_KRN_STACK = 0x100 24 | THREAD_INVOKE_FRAME_SIZE = 0x90 25 | X21_IN_THREAD_INVOKE_FRAME = 0x28 26 | STORED_LR_IN_THREAD_INVOKE_FRAME = 0x88 27 | 28 | 29 | class ThrdItrType(Enum): 30 | """ Info taken by reversing the 16B92 kernel version """ 31 | GLOBAL = 0 32 | TASK = 1 33 | 34 | 35 | class ThreadOffsets(Enum): 36 | """ 37 | What had been parsed of thread struct 38 | xnu kernel ref: darwin-xnu/osfmk/kern/thread.h (thread) 39 | """ 40 | CONTINUATION = 0x80 41 | CURRENT_STATE = 0xa0 42 | THREAD_ID = 0x3e0 43 | GLOBAL_THREADS = 0x348 44 | TASK_THREADS = 0x358 45 | TASK = 0x368 46 | CONTEXT_USER_DATA_PTR = 0x430 47 | KSTACK_PTR = 0x448 48 | VOUCHER_PTR = 0x510 49 | VOUCHER_NAME = 0x50C 50 | 51 | 52 | class TaskOffsets(Enum): 53 | """ 54 | What had been parsed of task struct 55 | xnu kernel ref: darwin-xnu/osfmk/kern/task.h (task) 56 | """ 57 | TASK_NEXT = 0x28 58 | THREAD_LST_FROM_TASK = 0x40 59 | ITK_SELF = 0xD8 60 | ITK_NSELF = 0xE0 61 | ITK_SSELF = 0xE8 62 | BSD_INFO = 0x358 63 | IPC_SPACE = 0x300 64 | 65 | 66 | class BSDInfoOffsets(Enum): 67 | """ xnu kernel ref: darwin-xnu/bsd/sys/proc_internal.h (proc) """ 68 | PID_IN_BSD_INFO = 0x60 69 | NAME_INBSD_INFO = 0x261 70 | 71 | 72 | class IPCSpaceOffsets(Enum): 73 | """ xnu kernel ref: darwin-xnu/osfmk/ipc/ipc_space.h (ipc_space) """ 74 | IS_TABLE_SIZE = 0x14 75 | IS_TABLE_FREE = 0x18 76 | IS_TABLE = 0x20 77 | IS_LOW_MOD = 0x38 78 | IS_HIGH_MOD = 0x3C 79 | 80 | 81 | class IPCEntryOffsets(Enum): 82 | """ xnu kernel ref: darwin-xnu/osfmk/ipc/ipc_entry.h (ipc_entry) """ 83 | IE_BITS = 0x08 84 | IE_INDEX = 0x0C 85 | INDEX = 0x10 86 | 87 | 88 | class IPCObjectOffsets(Enum): 89 | """ xnu kernel ref: darwin-xnu/osfmk/ipc/ipc_object.h (ipc_object) """ 90 | IO_REFS = 0x04 91 | IO_LOCK_DATA = 0x08 92 | IP_MSG = 0x24 93 | 94 | 95 | class IPCPortOffsets(Enum): 96 | """ xnu kernel ref: darwin-xnu/osfmk/ipc/ipc_port.h (ipc_port) """ 97 | IP_MSG = 0x18 98 | DATA = 0x60 99 | KDATA = 0x68 100 | IP_NSREQ = 0x70 101 | IP_PDREQ = 0x78 102 | IP_REQ = 0x80 103 | KDATA2 = 0x88 104 | IP_CTXT = 0x90 105 | IP_SPREQ = 0x98 # bitmap 106 | IP_MSCNT = 0x9C 107 | IP_SRIGHTS = 0xA0 108 | IP_SORIGHTS = 0xA4 109 | 110 | 111 | # osfmk/kern/ipc_kobject.h 112 | IO_BITS_TYPES = [ 113 | "IKOT_NONE", 114 | "IKOT_THREAD", 115 | "IKOT_TASK", 116 | "IKOT_HOST", 117 | "IKOT_HOST_PRIV", 118 | "IKOT_PROCESSOR", 119 | "IKOT_PSET", 120 | "IKOT_PSET_NAME", 121 | "IKOT_TIMER", 122 | "IKOT_PAGING_REQUEST", 123 | "IKOT_MIG", 124 | "IKOT_MEMORY_OBJECT", 125 | "IKOT_XMM_PAGER", 126 | "IKOT_XMM_KERNEL", 127 | "IKOT_XMM_REPLY", 128 | "IKOT_UND_REPLY", 129 | "IKOT_HOST_NOTIFY", 130 | "IKOT_HOST_SECURITY", 131 | "IKOT_LEDGER", 132 | "IKOT_MASTER_DEVICE", 133 | "IKOT_TASK_NAME", 134 | "IKOT_SUBSYSTEM", 135 | "IKOT_IO_DONE_QUEUE", 136 | "IKOT_SEMAPHORE", 137 | "IKOT_LOCK_SET", 138 | "IKOT_CLOCK", 139 | "IKOT_CLOCK_CTRL", 140 | "IKOT_IOKIT_IDENT", 141 | "IKOT_NAMED_ENTRY", 142 | "IKOT_IOKIT_CONNECT", 143 | "IKOT_IOKIT_OBJECT", 144 | "IKOT_UPL", 145 | "IKOT_MEM_OBJ_CONTROL", 146 | "IKOT_AU_SESSIONPORT", 147 | "IKOT_FILEPORT", 148 | "IKOT_LABELH", 149 | "IKOT_TASK_RESUME", 150 | "IKOT_VOUCHER", 151 | "IKOT_VOUCHER_ATTR_CONTROL", 152 | "IKOT_WORK_INTERVAL", 153 | "IKOT_UX_HANDLER" 154 | ] 155 | -------------------------------------------------------------------------------- /gdb/xnu/sys_info.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | import xnu.constants as const 4 | import xnu.utils as utils 5 | import gdb 6 | 7 | 8 | def get_current_task_ptr(): 9 | try: 10 | address = utils.print_val(const.CURRENT_THREAD) 11 | return utils.get_8_byte_at(address + const.ThreadOffsets.TASK.value) 12 | except Exception: 13 | raise gdb.GdbError(f"Error occured, maybe in user land?") 14 | 15 | 16 | def get_current_thread_ptr(): 17 | try: 18 | return utils.print_val(const.CURRENT_THREAD) 19 | except Exception: 20 | raise gdb.GdbError(f"Error occured, maybe in user land?") 21 | 22 | 23 | def is_user_thread(thread): 24 | return thread.ucontext_data != const.NULL_PTR 25 | 26 | 27 | def is_valid_ptr(ptr): 28 | try: 29 | utils.get_8_byte_at(ptr) 30 | return True 31 | except Exception: 32 | raise gdb.GdbError(f"Wrong pointer! {hex(ptr)}") 33 | 34 | 35 | def is_in_kernel_space(): 36 | try: 37 | utils.get_8_byte_at(const.GLOBAL_TASKS_PTR) 38 | return True 39 | except Exception: 40 | return False 41 | 42 | 43 | class Symbols: 44 | """ until implemented in the gdb itself 45 | symbols are taken from files manually exported from ghidra and jtool2 46 | """ 47 | 48 | def __init__(self): 49 | self.sym_dict = {} 50 | self.found_fuct_name_dict = {} 51 | self.sym_dir_path = os.path.dirname(__file__) 52 | self.load_symbols() 53 | 54 | def load_symbols(self): 55 | with open(os.path.join(self.sym_dir_path, "SymbolsNew"), "r") as sym_file: 56 | self.sym_dict = json.load(sym_file) 57 | with open(os.path.join(self.sym_dir_path, "KnownLables"), "r") as known_func_name_file: 58 | self.found_fuct_name_dict = json.load(known_func_name_file) 59 | 60 | def get_symbol_internal(self, addrr): 61 | if addrr in self.sym_dict: 62 | if 'FUN_' not in self.sym_dict[addrr]: 63 | return self.sym_dict[addrr] 64 | if addrr in self.found_fuct_name_dict: 65 | return self.found_fuct_name_dict[addrr] 66 | return addrr 67 | 68 | 69 | SYMBOLS = Symbols() 70 | 71 | 72 | def get_symbol(addrr): 73 | return SYMBOLS.get_symbol_internal(addrr) 74 | -------------------------------------------------------------------------------- /gdb/xnu/tasks.py: -------------------------------------------------------------------------------- 1 | """ This module exposes functions available to user from th gdb """ 2 | import traceback 3 | import xnu.xnu_types as types 4 | import xnu.sys_info as sys_info 5 | import xnu.utils as utils 6 | 7 | import gdb 8 | 9 | 10 | class PrintThreadList(gdb.Command): 11 | """ Gdb command to print all threads """ 12 | def __init__(self): 13 | super(PrintThreadList, self).__init__("xnu-threads", gdb.COMMAND_DATA) 14 | 15 | def invoke(self, arg, from_tty): 16 | """ Parsing arguments, invoking printing. 17 | You can print all theeads of current task (no argument to command), 18 | All threads of current task xnu-threads current 19 | All user threads - xnu-threads user 20 | All threads whithin the system - xnu-threads 21 | All threads of specific task - xnu-threads ${task_ptr} 22 | """ 23 | if sys_info.is_in_kernel_space() is False: 24 | gdb.write("\nYou are currently in user space, " 25 | "this functionality is not available here.\n\n") 26 | return 27 | try: 28 | argv = gdb.string_to_argv(arg) 29 | if len(argv) == 0: 30 | self.print_all_threads(is_global=True) 31 | elif len(argv) == 1: 32 | if argv[0] == "user": 33 | self.print_all_threads(user_only=True, is_global=True) 34 | elif argv[0] == "current": 35 | task = sys_info.get_current_task_ptr() 36 | self.print_all_threads(task=task) 37 | else: 38 | try: 39 | requested_task = int(argv[0], 0) 40 | if sys_info.is_valid_ptr(requested_task): 41 | if not types.is_task_exist(requested_task): 42 | gdb.write(f"\nRequested task {argv[0]} do not exist" 43 | f" in the tasks list of the system!\n\n\n") 44 | self.print_all_threads(task=requested_task) 45 | except Exception: 46 | gdb.write("\nUsage: xnu-threads ${TASK_PTR}\n") 47 | else: 48 | gdb.write("\nUsage: xnu-threads ${TASK_PTR}\n") 49 | except Exception: 50 | raise gdb.GdbError(traceback.format_exc()) 51 | 52 | def print_all_threads(self, user_only=False, is_global=False, task=None): 53 | """ Iterate over threads iterator and print data for each """ 54 | counter = 0 55 | max_length_proc = types.get_max_length_proc_name() 56 | max_length_cont = types.get_max_length_cont_name() 57 | max_length_pc = types.get_max_length_pc_name() 58 | gdb.write( 59 | types.get_thead_info_title(max_length_proc, max_length_cont, max_length_pc)+'\n') 60 | for thread in iter(types.ThreadsIterator(is_global, task)): 61 | if user_only is False or sys_info.is_user_thread(thread): 62 | counter += 1 63 | gdb.write(thread.print_thead_info_short( 64 | max_length_proc, max_length_cont, max_length_pc)+'\n') 65 | gdb.write(f"TOTAL {counter}\n") 66 | 67 | 68 | PrintThreadList() 69 | 70 | 71 | class PrintTaskList(gdb.Command): 72 | """ Gdb command to print all tasks """ 73 | def __init__(self): 74 | super(PrintTaskList, self).__init__("xnu-tasks", gdb.COMMAND_DATA) 75 | 76 | def invoke(self, arg, from_tty): 77 | """ Go over task iterator and print all task data """ 78 | if sys_info.is_in_kernel_space() is False: 79 | gdb.write("\nYou are currently in user space, " 80 | "this functionality is not available here.\n\n") 81 | return 82 | try: 83 | max_length_proc = types.get_max_length_proc_name() 84 | for task in iter(types.TasksIterator()): 85 | gdb.write(task.print_task_info_short(max_length_proc)+'\n') 86 | except Exception: 87 | raise gdb.GdbError(traceback.format_exc()) 88 | 89 | 90 | PrintTaskList() 91 | 92 | 93 | class switchThread(gdb.Command): 94 | """Dummy way to jump to specific thread.""" 95 | 96 | def __init__(self): 97 | super(switchThread, self).__init__("xnu-switch", gdb.COMMAND_DATA) 98 | 99 | def invoke(self, arg, from_tty): 100 | if sys_info.is_in_kernel_space() is False: 101 | gdb.write("\nYou are currently in user space, " 102 | "this functionality is not available here.\n\n") 103 | return 104 | try: 105 | argv = gdb.string_to_argv(arg) 106 | if len(argv) == 0: 107 | self.switch_to_thread(None, 0) 108 | elif len(argv) == 2 and types.is_thread_exist(int(argv[0], 0)): 109 | gdb.write(f"Waiting for {argv[0]} to be scheduled for " 110 | f"{int(argv[1], 0)} retries, this may take a while...\n") 111 | self.switch_to_thread(argv[0], int(argv[1], 0)) 112 | else: 113 | gdb.write("USAGE: xnu-switch ${THREAD_PTR} ${NUM_OF_RETRIES}\n") 114 | except Exception: 115 | raise gdb.GdbError(traceback.format_exc()) 116 | 117 | def switch_to_thread(self, thread, tries): 118 | old_thread = sys_info.get_current_thread_ptr() 119 | utils.disable_all_bp() 120 | bp = utils.conf_curr_thread_watchpoint() 121 | tmp_tries = tries 122 | if thread is None: 123 | utils.gdb_continue() 124 | else: 125 | while sys_info.get_current_thread_ptr() != thread and tmp_tries > 0: 126 | utils.gdb_continue() 127 | tmp_tries -= 1 128 | if tmp_tries == 0 and thread is not None: 129 | gdb.write(f"The thread was not scheduled in last {tries} context" 130 | f" switches, we are still on {hex(old_thread)}\n") 131 | else: 132 | gdb.write(f"Current thread is: " 133 | f"{hex(sys_info.get_current_thread_ptr())} " 134 | f"old: {hex(old_thread)}\n") 135 | utils.delete_bp(bp) 136 | utils.enable_all_bp() 137 | 138 | 139 | switchThread() 140 | 141 | 142 | class PrintThreadInfo(gdb.Command): 143 | """ gdb command to print all known info of specific thread """ 144 | def __init__(self): 145 | super(PrintThreadInfo, self).__init__( 146 | "xnu-thread-info", gdb.COMMAND_DATA) 147 | 148 | def invoke(self, arg, from_tty): 149 | """ print info of given thread, checking if exist""" 150 | if sys_info.is_in_kernel_space() is False: 151 | gdb.write("\nYou are currently in user space, " 152 | "this functionality is not available here.\n\n") 153 | return 154 | try: 155 | argv = gdb.string_to_argv(arg) 156 | if len(argv) == 1: 157 | thread = int(argv[0], 0) 158 | if types.is_thread_exist(thread): 159 | gdb.write(types.Thread(thread).print_thread_info_long()+'\n') 160 | else: 161 | gdb.write("Given thread do not exist\n") 162 | else: 163 | gdb.write("\nUsage: xnu-thread-info ${THREAD_PTR}\n") 164 | except Exception: 165 | raise gdb.GdbError(traceback.format_exc()) 166 | 167 | 168 | PrintThreadInfo() 169 | 170 | 171 | class PrintTaskInfo(gdb.Command): 172 | """ gdb command to print all known info of specific task """ 173 | def __init__(self): 174 | super(PrintTaskInfo, self).__init__("xnu-task-info", gdb.COMMAND_DATA) 175 | 176 | def invoke(self, arg, from_tty): 177 | """ print info of given task, checking if exist""" 178 | if sys_info.is_in_kernel_space() is False: 179 | gdb.write("\nYou are currently in user space, " 180 | "this functionality is not available here.\n\n") 181 | return 182 | try: 183 | argv = gdb.string_to_argv(arg) 184 | if len(argv) == 1: 185 | """convert to integer""" 186 | task = int(argv[0], 0) 187 | if sys_info.is_valid_ptr(task): 188 | if not types.is_task_exist(task): 189 | gdb.write(f"\nRequested task {argv[0]} do not exist in the task " 190 | f"list of the system!\n\n\n") 191 | gdb.write(types.Task(task).print_task_info_long()+'\n') 192 | else: 193 | gdb.write("Given task do not exist\n") 194 | else: 195 | gdb.write("\nUsage: xnu-task-info ${TASK_PTR}\n") 196 | except Exception: 197 | raise gdb.GdbError(traceback.format_exc()) 198 | 199 | 200 | PrintTaskInfo() 201 | 202 | 203 | class PrintVoucherInfo(gdb.Command): 204 | """ 205 | gdb command to print all known info of specific mach voucher 206 | xnu kernel ref: darwin-xnu/osfmk/ipc/ipc_voucher.h (ipc_voucher) 207 | """ 208 | 209 | def __init__(self): 210 | super(PrintVoucherInfo, self).__init__( 211 | "xnu-voucher-info", gdb.COMMAND_DATA) 212 | 213 | def invoke(self, arg, from_tty): 214 | if sys_info.is_in_kernel_space() is False: 215 | gdb.write("\nYou are currently in user space, " 216 | "this functionality is not available here.\n\n") 217 | return 218 | try: 219 | argv = gdb.string_to_argv(arg) 220 | if len(argv) == 1 and sys_info.is_valid_ptr(int(argv[0], 0)): 221 | voucher = int(argv[0], 0) 222 | gdb.write(types.ThreadVoucher(voucher).print_voucher_info()+'\n') 223 | else: 224 | gdb.write("\nUsage: xnu-voucher-info ${THREAD_PTR} " 225 | "(maybe wrong pointer?)\n") 226 | except Exception: 227 | raise gdb.GdbError(traceback.format_exc()) 228 | 229 | 230 | PrintVoucherInfo() 231 | 232 | 233 | class PrintIpcPortInfo(gdb.Command): 234 | """ 235 | gdb command to print all known info of specific xnu ipc_port 236 | xnu kernel ref: darwin-xnu/osfmk/ipc/ipc_port.h (ipc_port) 237 | """ 238 | def __init__(self): 239 | super(PrintIpcPortInfo, self).__init__( 240 | "xnu-ipc-port-info", gdb.COMMAND_DATA) 241 | 242 | def invoke(self, arg, from_tty): 243 | """ print info """ 244 | if sys_info.is_in_kernel_space() is False: 245 | gdb.write("\nYou are currently in user space, " 246 | "this functionality is not available here.\n\n") 247 | return 248 | try: 249 | argv = gdb.string_to_argv(arg) 250 | if len(argv) == 1 and sys_info.is_valid_ptr(int(argv[0], 0)): 251 | ipc_port = int(argv[0], 0) 252 | gdb.write(types.IPCPort(ipc_port).print_ipc_port_info()+'\n') 253 | else: 254 | gdb.write("\nUsage: xnu-ipc-port-info ${IPC_PORT_PTR}\n") 255 | except Exception: 256 | raise gdb.GdbError(traceback.format_exc()) 257 | 258 | 259 | PrintIpcPortInfo() 260 | 261 | 262 | class PrintIPCEntryList(gdb.Command): 263 | """ 264 | gdb command to print a tabl of ipc_entry(ies) of ipc space 265 | xnu kernel ref: 266 | darwin-xnu/osfmk/ipc/ipc_space.h (ipc_space) 267 | darwin-xnu/osfmk/ipc/ipc_entry.h (ipc_entry) 268 | """ 269 | def __init__(self): 270 | super(PrintIPCEntryList, self).__init__( 271 | "xnu-ipc_entry-list", gdb.COMMAND_DATA) 272 | 273 | def invoke(self, arg, from_tty): 274 | """ Can get as argument pointer to task or pointer to space""" 275 | if sys_info.is_in_kernel_space() is False: 276 | gdb.write("\nYou are currently in user space, " 277 | "this functionality is not available here.\n\n") 278 | return 279 | try: 280 | argv = gdb.string_to_argv(arg) 281 | if len(argv) == 2 and sys_info.is_valid_ptr(int(argv[1], 0)): 282 | if argv[0] == "-task": 283 | task = int(argv[1], 0) 284 | if not types.is_task_exist(task): 285 | gdb.write(f"\nRequested task {argv[1]} do not exist in the tasks" 286 | f"list of the system!\n\n\n") 287 | self.print_ipc_space_table(types.Task(task).ipc_space) 288 | elif argv[0] == "-space": 289 | space = int(argv[1], 0) 290 | self.print_ipc_space_table(space) 291 | else: 292 | gdb.write( 293 | "\nUsage: xnu-ipc_entry-list -task/space" 294 | " ${TASK_PTR}/${SPACE_PTR}\n") 295 | else: 296 | gdb.write("\nUsage: xnu-ipc_entry-list -task/space" 297 | " ${TASK_PTR}/${SPACE_PTR}\n") 298 | except Exception: 299 | raise gdb.GdbError(traceback.format_exc()) 300 | 301 | def print_ipc_space_table(self, address): 302 | """ print info """ 303 | gdb.write("=================================================\n") 304 | gdb.write(types.IPCSpace(address).print_ipc_space_info()) 305 | gdb.write("=================================================\n\n") 306 | for entry in iter(types.IPCEntryIterator(address)): 307 | gdb.write(f"{entry.print_ipc_entry_info():<47}") 308 | gdb.write("-----------------------------------------------\n") 309 | 310 | 311 | PrintIPCEntryList() 312 | -------------------------------------------------------------------------------- /gdb/xnu/utils.py: -------------------------------------------------------------------------------- 1 | import traceback 2 | import logging 3 | import gdb 4 | from xnu.constants import NULL_PTR_STR 5 | 6 | LOGGER = logging.getLogger("xnu") 7 | 8 | 9 | def get_8_byte_at(addr): 10 | return execute_get_val(addr, 'g') 11 | 12 | 13 | def get_4_byte_at(addr): 14 | return execute_get_val(addr, 'w') 15 | 16 | 17 | def get_string_at(value): 18 | return execute_get_string(value) 19 | 20 | 21 | def execute_get_string(value): 22 | try: 23 | command = f"x /1s {str(value)}" 24 | LOGGER.debug("Going to excute %s ", command) 25 | res = gdb.execute(command, to_string=True) 26 | res = " ".join(res.split()[1:]) 27 | LOGGER.debug("Got a result %s ", str(res)) 28 | return res 29 | except Exception: 30 | raise gdb.GdbError(traceback.format_exc()) 31 | 32 | 33 | def execute_get_val(val, size): 34 | try: 35 | check_arguments(size) 36 | command = f"x /1x{size} {hex(val)}" 37 | LOGGER.debug("Going to excute %s ", command) 38 | res = gdb.execute(command, to_string=True) 39 | res = int(res.split()[1], 0) 40 | LOGGER.debug("Got a result %s ", str(res)) 41 | return res 42 | except Exception: 43 | raise gdb.GdbError(f"{traceback.format_exc()}") 44 | 45 | 46 | def print_val(var): 47 | try: 48 | command = f"print /1x {str(var)}" 49 | LOGGER.debug("Going to excute %s ", command) 50 | res = gdb.execute(command, to_string=True) 51 | LOGGER.debug("Got a result %s ", str(res)) 52 | res = int(res.split()[2], 0) 53 | return res 54 | except Exception: 55 | raise gdb.GdbError(traceback.format_exc()) 56 | 57 | 58 | def check_arguments(size): 59 | return size in ['b', 'h', 'w', 'g'] 60 | 61 | 62 | def print_ptr_as_string(addr): 63 | return NULL_PTR_STR if not addr else f"0x{addr:016x}" 64 | 65 | 66 | def gdb_continue(): 67 | gdb.execute("continue") 68 | 69 | 70 | def conf_curr_thread_watchpoint(): 71 | bp = gdb.Breakpoint('$TPIDR_EL1', gdb.BP_WATCHPOINT, internal=True) 72 | bp.enabled = True 73 | bp.silent = True 74 | return bp 75 | 76 | 77 | def delete_bp(bp): 78 | bp.delete() 79 | 80 | 81 | def enable_all_bp(): 82 | gdb.execute("enable br") 83 | 84 | 85 | def disable_all_bp(): 86 | gdb.execute("disable br") 87 | -------------------------------------------------------------------------------- /gdb/xnu/zone.py: -------------------------------------------------------------------------------- 1 | import xnu.utils as utils 2 | import xnu.sys_info as sys_info 3 | import gdb 4 | 5 | 6 | class StructZone(object): 7 | zone_globals_16B92 = { 8 | "max_zones": 0xfffffff00763df48, 9 | "zone_array": 0xfffffff007624ef0, 10 | "zone_struct_size": 0x140 11 | } 12 | # TODO: support more versions 13 | globs = zone_globals_16B92 14 | 15 | struct_offsets_16B92 = { 16 | "zone_name": 0x118, 17 | "index": 0x114, 18 | "flags": 0x110, 19 | "flags_valid_shift": 26, 20 | "flags_valid_mask": 1, 21 | "sum_count": 0x108, 22 | "page_count": 0x100, 23 | "alloc_size": 0xf8, 24 | "elem_size": 0xf0, 25 | "max_size": 0xe8, 26 | "cur_size": 0xe0 27 | } 28 | 29 | def __init__(self, addr): 30 | # TODO: support more versions 31 | self.offsets = StructZone.struct_offsets_16B92 32 | self.globals = StructZone.zone_globals_16B92 33 | self.addr = addr 34 | self.cur_size = utils.get_8_byte_at(addr + self.offsets["cur_size"]) 35 | self.max_size = utils.get_8_byte_at(addr + self.offsets["max_size"]) 36 | self.elem_size = utils.get_8_byte_at(addr + self.offsets["elem_size"]) 37 | self.alloc_size = utils.get_8_byte_at(addr + self.offsets["alloc_size"]) 38 | self.page_count = utils.get_8_byte_at(addr + self.offsets["page_count"]) 39 | self.sum_count = utils.get_8_byte_at(addr + self.offsets["sum_count"]) 40 | self.flags = utils.get_4_byte_at(addr + self.offsets["flags"]) 41 | self.index = utils.get_4_byte_at(addr + self.offsets["index"]) 42 | name_ptr = utils.get_8_byte_at(addr + self.offsets["zone_name"]) 43 | self.zone_name = utils.get_string_at(name_ptr) 44 | 45 | def is_valid(self): 46 | shift = self.offsets["flags_valid_shift"] 47 | mask = self.offsets["flags_valid_mask"] 48 | valid = (self.flags >> shift) & mask 49 | return (0 != valid) 50 | 51 | @classmethod 52 | def get_max_zones(cls): 53 | return cls.globs["max_zones"] 54 | 55 | @classmethod 56 | def get_zone_array(cls): 57 | return cls.globs["zone_array"] 58 | 59 | @classmethod 60 | def get_struct_size(cls): 61 | return cls.globs["zone_struct_size"] 62 | 63 | 64 | class PrintZoneInformationCommand(gdb.Command): 65 | def __init__(self): 66 | super(PrintZoneInformationCommand, 67 | self).__init__("xnu-zones", gdb.COMMAND_DATA) 68 | 69 | def invoke(self, arg, from_tty): 70 | if sys_info.is_in_kernel_space() is False: 71 | gdb.write("\nYou are currently in user space, "\ 72 | "this functionality is not available here.\n\n") 73 | return 74 | self.print_zones() 75 | 76 | def print_zones(self): 77 | zone_arr_addr = StructZone.get_zone_array() 78 | max_zones_addr = StructZone.get_max_zones() 79 | max_zones = utils.get_4_byte_at(max_zones_addr) 80 | struct_size = StructZone.get_struct_size() 81 | out = "Printing zones info:\n" 82 | out += f"zone_arr_addr: 0x{zone_arr_addr:016x}\n" 83 | out += f"max_zones: {max_zones}\n" 84 | gdb.write(out) 85 | for i in range(max_zones): 86 | zone_addr = zone_arr_addr + (struct_size * i) 87 | zone = StructZone(zone_addr) 88 | if (not zone.is_valid()): 89 | continue 90 | out = f"Valid zone at 0x{zone_addr:016x} at index {i}\n" 91 | out += f" zone_name: {zone.zone_name}\n" 92 | out += f" elem_size: {zone.elem_size}\n" 93 | out += f" index: {zone.index}\n" 94 | out += f" flags: 0x{zone.flags:08x}\n" 95 | out += f" sum_count: {zone.sum_count}\n" 96 | out += f" page_count: {zone.page_count}\n" 97 | out += f" alloc_size: 0x{zone.alloc_size:016x}\n" 98 | out += f" max_size: 0x{zone.max_size:016x}\n" 99 | out += f" cur_size: 0x{zone.cur_size:016x}\n" 100 | gdb.write(out) 101 | 102 | 103 | PrintZoneInformationCommand() 104 | -------------------------------------------------------------------------------- /ghidra/ColorAddress.java: -------------------------------------------------------------------------------- 1 | import java.awt.Color; 2 | import java.io.BufferedReader; 3 | import java.io.File; 4 | import java.io.FileReader; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.logging.Level; 9 | import java.util.logging.Logger; 10 | import java.util.regex.Matcher; 11 | import java.util.regex.Pattern; 12 | 13 | import ghidra.app.script.GhidraScript; 14 | import ghidra.program.model.address.Address; 15 | import ghidra.program.model.address.AddressSet; 16 | 17 | public class ColorAddress extends GhidraScript { 18 | private static final Logger LOGGER = Logger.getLogger(ColorAddress.class.getName()); 19 | @Override 20 | protected void run() throws Exception { 21 | LOGGER.setLevel(Level.WARNING); 22 | 23 | List
listOfInstPtrToCollor = getAddresses(); 24 | AddressSet addresses = new AddressSet(); 25 | Address minAddress = currentProgram.getMinAddress(); 26 | Address maxAddress = currentProgram.getMaxAddress(); 27 | int counter = 0; 28 | if(listOfInstPtrToCollor == null) { 29 | LOGGER.warning("List is null!"); 30 | return; 31 | } 32 | for (Address addr : listOfInstPtrToCollor) { 33 | //Check whether we are in the correct adress space 34 | if (addr.compareTo(minAddress)>=0 && addr.compareTo(maxAddress) <=0){ 35 | addresses.add(addr); 36 | counter++; 37 | } 38 | } 39 | 40 | //pink fuchsia <3 41 | setBackgroundColor(addresses, new Color(255, 119, 255)); 42 | LOGGER.info(String.format("%d pointers were colored!",counter)); 43 | } 44 | 45 | private List
getAddresses(){ 46 | 47 | Pattern pattern = Pattern.compile("((Trace \\d: 0x.+? \\[.+?/)(.+)(/.+\\] ))"); 48 | List
lst = new ArrayList
(); 49 | BufferedReader reader; 50 | File file; 51 | String line ; 52 | try { 53 | file = askFile("TRACES of QEMU execution", "Choose file:"); 54 | LOGGER.info("File chosen " + file); 55 | 56 | reader = new BufferedReader(new FileReader(file)); 57 | line = reader.readLine(); 58 | while (line != null) { 59 | Matcher m = pattern.matcher(line); 60 | if(m.matches() && m.groupCount() == 4) { 61 | lst.add(currentAddress.getAddress("0x" + m.group(3))); 62 | LOGGER.info("Adding address to be colored: 0x" + m.group(3)); 63 | } 64 | line = reader.readLine(); 65 | } 66 | reader.close(); 67 | 68 | } catch (Exception e) { 69 | e.printStackTrace(); 70 | } 71 | return lst; 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /ghidra/README.md: -------------------------------------------------------------------------------- 1 | # GHIDRA- Color Executed Instructions 2 | 3 | Given a file with the QEMU CPU trace, color the instructions that were executed in the trace 4 | 5 | TL;DR: 6 | To get a CPU trace: 7 | ``` 8 | $qemu-system-aarch64 -d exec -D /tmp/qemu-trace.log ... 9 | ``` 10 | - Ghidra-> CodeBrowser-> Window -> Script Manager 11 | - Find the script (filter by name) and run 12 | - Choose the log file (/tmp/qemu-trace.log) 13 | - To see better the actual flow of the program, it is better to use the *Graph* window 14 | intead of *Listing* 15 | --- 16 | This small script will color all executed instructions according to the provided trace log. That is, the previously executed program's flow will be available at any time it is needed during the reverse engineering task. 17 | 18 | ![](https://user-images.githubusercontent.com/9990629/74430108-e9893180-4e64-11ea-8c72-3b1bad4980ce.png) 19 | -------------------------------------------------------------------------------- /pic-binary/.gitignore: -------------------------------------------------------------------------------- 1 | bin/* 2 | .vscode 3 | kernel.ld -------------------------------------------------------------------------------- /pic-binary/Makefile: -------------------------------------------------------------------------------- 1 | src := $(wildcard src/*.c) $(wildcard src/**/*.c) 2 | 3 | ifndef XNU_SOURCES 4 | $(error XNU_SOURCES not set!) 5 | endif 6 | 7 | ifndef KERNEL_SYMBOLS_FILE 8 | $(error KERNEL_SYMBOLS_FILE not set!) 9 | endif 10 | 11 | TARGET = bin/pic 12 | CROSS = aarch64-none-elf- 13 | CC = $(CROSS)gcc 14 | OBJCOPY = $(CROSS)objcopy 15 | LDFLAGS = -Wl,-T,flat.ld,-N 16 | DEFINES = -DBCM2837 -DKERNEL -DXNU_KERNEL_PRIVATE -D__arm64__ -D__LITTLE_ENDIAN__ 17 | INCLUDES = -I$(XNU_SOURCES)/bsd \ 18 | -I$(XNU_SOURCES)/osfmk \ 19 | -I$(XNU_SOURCES)/osfmk/libsa \ 20 | -I$(XNU_SOURCES)/libkern \ 21 | -I$(XNU_SOURCES)/pexpert \ 22 | -I$(XNU_SOURCES)/EXTERNAL_HEADERS 23 | CFLAGS = -fpie -flto -fwhole-program -fno-plt -nostdlib -nostartfiles $(DEFINES) $(LDFLAGS) $(INCLUDES) 24 | 25 | 26 | $(TARGET).bin: $(TARGET).elf 27 | @echo "Creating a flat binary..." 28 | @$(OBJCOPY) -O binary $^ $@ 29 | 30 | $(TARGET).elf: $(src) kernel.ld 31 | @echo "Building elf from source..." 32 | @$(CC) -o $@ $(CFLAGS) $(src) 33 | 34 | kernel.ld: 35 | @echo "Generating symbols for linker..." 36 | @python3 getsymbols.py $(KERNEL_SYMBOLS_FILE) $@ 37 | 38 | .PHONY: clean 39 | clean: 40 | rm kernel.ld 41 | rm -f $(TARGET)* 42 | -------------------------------------------------------------------------------- /pic-binary/README.md: -------------------------------------------------------------------------------- 1 | # pic-binary 2 | 3 | A sample PIC (position-independent code) binary, that can be loaded into kernel 4 | memory for execution. 5 | 6 | ## Prerequisites 7 | 8 | ### Kernel Sources 9 | 10 | Get the XNU sources from Apple's Github: 11 | 12 | ``` 13 | git clone https://github.com/apple/darwin-xnu.git 14 | ``` 15 | 16 | Set the environment variable `XNU_SOURCES` to point to the darwin-xnu folder, 17 | for example: 18 | 19 | ``` 20 | export XNU_SOURCES=/Users/aronsky/Source/darwin-xnu 21 | ``` 22 | 23 | ### ARM64 GCC cross-compiler 24 | 25 | Use aarch64-none-elf-gcc, availabe from Sergio Benitez through Homebrew: 26 | 27 | ``` 28 | $ brew tap SergioBenitez/osxct 29 | $ brew install aarch64-none-elf 30 | ``` 31 | 32 | ### Kernel Symbols CSV 33 | 34 | From Ghidra, export the symbols to a CSV by opening the symbol table 35 | (Window->Symbol Table), selecting all the symbols, right-clicking the 36 | selection, and choosing Export->Export to CSV: 37 | 38 | ![Export to CSV](https://1.bp.blogspot.com/-MY1TykT2Qic/XRqlzEcdtRI/AAAAAAAABK8/z6M1WuahFS8J3GRpY7UNWIppvLtlN5XOACLcBGAs/s1600/lst2x64dbg%282%29.png) 39 | 40 | Set the environment variable `KERNEL_SYMBOLS_FILE` to point to the exported 41 | file. 42 | 43 | ## Writing New Code 44 | 45 | Writing new code should work out of the box. In theory, any stuff that's 46 | available through the XNU headers should be usable. However, there are two 47 | limitations: 48 | 49 | * Correct include folders: the include folders of XNU are not set up for 50 | driver development (a la SDK), but for building the kernel. Therefore, some 51 | changes might be required for the `INCLUDES` variable in the Makefile. 52 | * The linking step depends on the presence of the relevant symbols in the 53 | kernel. If a symbol is missing, the function needs to be found and created in 54 | Ghidra (make sure to add an `_` in front of the name), and the CSV file has to 55 | be exported again. 56 | 57 | ## Building 58 | 59 | Just run `make` to build the code. The command will produce two files: 60 | 61 | * `bin/pic.elf` - a regular ELF binary (albeit with reduced number of segments) 62 | * `bin/pic.bin` - a flat binary with all the required sections, to be loaded 63 | into the kernel for execution 64 | 65 | ## Running 66 | 67 | This section is not ready - to be continued... -------------------------------------------------------------------------------- /pic-binary/flat.ld: -------------------------------------------------------------------------------- 1 | PHDRS 2 | { 3 | text PT_LOAD; 4 | } 5 | 6 | ENTRY(_start) 7 | 8 | SECTIONS 9 | { 10 | /* Kernel functions */ 11 | INCLUDE kernel.ld 12 | 13 | .start : { *(.start) } :text 14 | .text : { *(.text) } 15 | } -------------------------------------------------------------------------------- /pic-binary/getsymbols.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import csv 4 | import sys 5 | 6 | def csv2ld(in_file, out_file): 7 | reader = csv.reader(open(in_file)) 8 | writer = open(out_file, 'wt') 9 | 10 | fields = next(reader) 11 | 12 | for values in reader: 13 | name = values[fields.index('Name')] 14 | location = values[fields.index('Location')] 15 | symtype = values[fields.index('Symbol Type')] 16 | namespace = values[fields.index('Namespace')] 17 | 18 | if symtype != 'Function' or namespace != 'Global': 19 | continue 20 | 21 | if name.startswith('_'): 22 | name = name[1:] 23 | 24 | print(f"PROVIDE ({name} = 0x{location});", file=writer) 25 | 26 | def main(): 27 | if len(sys.argv) not in (2, 3): 28 | print("Usage: python3 getsymbols.py [kernel-symbols-ld-provider]") 29 | sys.exit(1) 30 | 31 | in_file = sys.argv[1] 32 | out_file = sys.argv[2] if len(sys.argv) == 3 else "kernel.ld" 33 | 34 | csv2ld(in_file, out_file) 35 | 36 | if __name__ == "__main__": 37 | main() -------------------------------------------------------------------------------- /pic-binary/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void _start() __attribute__((section(".start"))); 7 | 8 | void _start() { 9 | char str[] = "Hello, PIC world!"; 10 | char *buf = kern_os_malloc(sizeof(str)); 11 | 12 | memcpy(&str[7], "iOS", 3); 13 | memcpy(buf, str, strlen(str)); 14 | 15 | } -------------------------------------------------------------------------------- /tcp-tunnel/.gitignore: -------------------------------------------------------------------------------- 1 | bin/* 2 | .vscode -------------------------------------------------------------------------------- /tcp-tunnel/Makefile: -------------------------------------------------------------------------------- 1 | ifndef IOS_DIR 2 | $(error IOS_DIR is not set) 3 | endif 4 | 5 | ifndef QEMU_DIR 6 | $(error QEMU_DIR is not set) 7 | endif 8 | 9 | ifndef SDK_DIR 10 | # git clone https://github.com/xybp888/iOS-SDKs.git 11 | # export SDK_DIR=$PWD/iOS-SDKs/iPhoneOS12.4.sdk 12 | SDK_DIR = '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk' 13 | endif 14 | 15 | src := $(wildcard src/*.c) $(wildcard src/**/*.c) 16 | 17 | CC = clang 18 | FLAGS = -DOUT_OF_TREE_BUILD -I$(QEMU_DIR)/include -fno-stack-check -fno-stack-protector -arch arm64 -isysroot $(SDK_DIR) 19 | TARGET = tunnel 20 | 21 | bin/$(TARGET): $(src) 22 | @echo "Compiling from source..." 23 | @mkdir -p bin 24 | @$(CC) -o $@ $(FLAGS) $^ 25 | 26 | .PHONY: clean 27 | clean: 28 | rm -f bin/$(TARGET) 29 | 30 | .PHONY: install 31 | install: bin/$(TARGET) 32 | @echo "Installing into the iOS image..." 33 | @hdiutil attach -imagekey diskimage-class=CRawDiskImage $(IOS_DIR)/hfs.main 34 | @sudo cp $^ /Volumes/PeaceB16B92.arm64UpdateRamDisk/bin/ 35 | @hdiutil detach /Volumes/PeaceB16B92.arm64UpdateRamDisk 36 | @echo "Signing with entitlements..." 37 | @jtool --sign --ent ent.xml --inplace $^ 38 | @jtool --sig --ent $^ | grep CDHash | cut -d' ' -f6 | cut -c 1-40 >> $(IOS_DIR)/tchashes 39 | @echo "Updating static trustcache..." 40 | @python $(IOS_DIR)/xnu-qemu-arm64-tools/bootstrap_scripts/create_trustcache.py $(IOS_DIR)/tchashes $(IOS_DIR)/static_tc 41 | -------------------------------------------------------------------------------- /tcp-tunnel/README.md: -------------------------------------------------------------------------------- 1 | # tcp-tunnel 2 | 3 | Used for tunneling TCP connections into and out of an iOS system emulated on 4 | QEMU. 5 | 6 | ## Prerequisites 7 | 8 | The following environment variables are required: 9 | 10 | * `IOS_DIR` - this should point to the location of the kernelcache, the 11 | disk images, etc. 12 | * `QEMU_DIR` - this should point to the root of the [QEMU with iOS] source tree 13 | (make sure it is up to date). 14 | 15 | To use the project for SSH connections, the disk image should contain the 16 | dropbear binary. The easiest way to obtain it is through [rootlessJB]. The 17 | Dropbear needs an SSH key to run correctly (it can generate those on the fly, but since the filesystem is 18 | mounted read-only, the workaround is to generate the key offline, and copy it 19 | to the RAM disk image before boot). To generate it offline, install `dropbear` 20 | (for example, via `brew install dropbear`), and then use the `dropbearkey` 21 | command. 22 | 23 | ## Building 24 | Build the binary (will be placed in the `bin` folder): 25 | ``` 26 | $ make 27 | ``` 28 | 29 | Sign, update the trust cache and copy the binary to the disk image: 30 | 31 | :bangbang:**NOTE**:bangbang: the following command is using a *hardcoded* path for `mount`/`unmount`. If the disk is already mounted, avoid this command (or edit the path to the mounted disk in the Makefile). 32 | ``` 33 | $ make install 34 | ``` 35 | 36 | ## Running 37 | 38 | A basic execution of the tunnel looks like this: 39 | 40 | ```tunnel 2222:127.0.0.1:22``` 41 | 42 | This will spawn an inward tunnel (from the outside world into the iOS system), 43 | that will forward connections to port 2222 on the host to port 22 on the iOS 44 | system. This is obviously only useful when Dropbear is executed - this is 45 | achieved with the following command: 46 | 47 | ```/jb/usr/local/dropbear -r /var/dropbear/dropbear_ecdsa_host_key``` 48 | 49 | This, of course, assumes that iosbinpack has been extracted into the `/jb` 50 | directory, and that an SSH key has been generated and put into `/var/dropbear`. 51 | 52 | Alternatively, outward connections can be tunnelled, as well: 53 | 54 | ```tunnel out:80:93.184.216.34:80``` 55 | 56 | The above command will allow connections from the iOS system on port 80 to 57 | `example.com`. 58 | 59 | The tunnel runs in the foreground. It can be shut down by pressing 60 | Ctrl+C. All open sockets and connections are properly 61 | closed upon shut down. 62 | 63 | If background operation is required, the tunnel can be executed with the `-d` 64 | (or `--daemonize`) command line argument (it must appear first, as the 65 | address spec is expected to be the last argument). This argument will cause the 66 | tunnel to fork into the background. 67 | 68 | [QEMU with iOS]: https://github.com/alephsecurity/xnu-qemu-arm64.git 69 | [rootlessJB]: https://github.com/jakeajames/rootlessJB 70 | 71 | -------------------------------------------------------------------------------- /tcp-tunnel/ent.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | platform-application 5 | 6 | com.apple.private.security.container-required 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /tcp-tunnel/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "hw/arm/guest-services/general.h" 13 | 14 | #define DIR_IN 1 15 | #define DIR_OUT 2 16 | 17 | typedef struct { 18 | int fd; 19 | int *error; 20 | 21 | int (*close)(int fd); 22 | int (*fcntl)(int fd, int cmd, ...); 23 | 24 | int (*socket)(int domain, int type, int protocol); 25 | int (*accept)(int sckt, struct sockaddr *addr, socklen_t *addrlen); 26 | int (*bind)(int sckt, const struct sockaddr *addr, socklen_t addrlen); 27 | int (*connect)(int sckt, const struct sockaddr *addr, socklen_t addrlen); 28 | int (*listen)(int sckt, int backlog); 29 | ssize_t (*recv)(int sckt, void *buffer, size_t length, int flags); 30 | ssize_t (*send)(int sckt, const void *buffer, size_t length, int flags); 31 | } socket_t; 32 | 33 | static void init_qemu_socket(socket_t *sock_struct); 34 | static void init_native_socket(socket_t *sock_struct); 35 | static void terminate(int signum); 36 | static int usage(const char *prog_name); 37 | static int parse_address_spec(char* address_spec, uint32_t *listen_port, 38 | char *target_ip, size_t target_ip_size, 39 | uint32_t *target_port); 40 | static int send_receive(socket_t *in, socket_t *out); 41 | static int handle_incoming_connection(socket_t *in, socket_t *out, 42 | const char *target_ip, 43 | uint32_t target_port); 44 | static int tunnel(socket_t *s_listen, socket_t *in, socket_t *out, 45 | uint32_t listen_port, char *target_ip, uint32_t target_port); 46 | 47 | static socket_t s_listen = {.fd = -1}, s_in = {.fd = -1}, s_out = {.fd = -1}; 48 | static int daemonize = 0; 49 | 50 | int main(int argc, char *argv[]) 51 | { 52 | uint32_t listen_port = 0, target_port = 0; 53 | char target_ip[30]; 54 | struct sigaction action; 55 | int direction; 56 | 57 | switch (argc) { 58 | case 2: 59 | break; 60 | case 3: 61 | if (!strncmp(argv[1], "-d", strlen("-d")) || 62 | !strncmp(argv[1], "--daemonize", strlen("--daemonize"))) { 63 | daemonize = 1; 64 | break; 65 | } 66 | default: 67 | return usage(argv[0]); 68 | } 69 | 70 | direction = parse_address_spec(argv[argc - 1], &listen_port, target_ip, 71 | sizeof(target_ip), &target_port); 72 | if (direction < 0) 73 | { 74 | return usage(argv[0]); 75 | } 76 | 77 | memset(&action, 0, sizeof(struct sigaction)); 78 | action.sa_handler = terminate; 79 | sigaction(SIGTERM, &action, NULL); 80 | sigaction(SIGINT, &action, NULL); 81 | 82 | 83 | if (DIR_IN == direction) { 84 | init_qemu_socket(&s_listen); 85 | init_qemu_socket(&s_in); 86 | init_native_socket(&s_out); 87 | 88 | return tunnel(&s_listen, &s_in, &s_out, listen_port, target_ip, 89 | target_port); 90 | } else if (DIR_OUT == direction) { 91 | init_native_socket(&s_listen); 92 | init_native_socket(&s_in); 93 | init_qemu_socket(&s_out); 94 | 95 | return tunnel(&s_listen, &s_in, &s_out, listen_port, target_ip, 96 | target_port); 97 | } else { 98 | return usage(argv[0]); 99 | } 100 | } 101 | 102 | static void init_qemu_socket(socket_t *sock_struct) 103 | { 104 | if (sock_struct) { 105 | sock_struct->error = &guest_svcs_errno; 106 | 107 | sock_struct->close = &qc_close; 108 | sock_struct->fcntl = &qc_fcntl; 109 | 110 | sock_struct->socket = &qc_socket; 111 | sock_struct->accept = &qc_accept; 112 | sock_struct->bind = &qc_bind; 113 | sock_struct->connect = &qc_connect; 114 | sock_struct->listen = &qc_listen; 115 | sock_struct->recv = &qc_recv; 116 | sock_struct->send = &qc_send; 117 | } 118 | } 119 | 120 | static void init_native_socket(socket_t *sock_struct) 121 | { 122 | if (sock_struct) { 123 | sock_struct->error = &errno; 124 | 125 | sock_struct->close = &close; 126 | sock_struct->fcntl = &fcntl; 127 | 128 | sock_struct->socket = &socket; 129 | sock_struct->accept = &accept; 130 | sock_struct->bind = &bind; 131 | sock_struct->connect = &connect; 132 | sock_struct->listen = &listen; 133 | sock_struct->recv = &recv; 134 | sock_struct->send = &send; 135 | } 136 | } 137 | 138 | static void terminate(int signum) 139 | { 140 | if (s_out.fd != -1) { 141 | fprintf(stderr, "Closing outward socket...\n"); 142 | s_out.close(s_out.fd); 143 | } 144 | 145 | if (s_in.fd != -1) { 146 | fprintf(stderr, "Closing inward socket...\n"); 147 | s_in.close(s_in.fd); 148 | } 149 | 150 | if (s_listen.fd != -1) { 151 | fprintf(stderr, "Closing listening socket...\n"); 152 | s_listen.close(s_listen.fd); 153 | } 154 | 155 | exit(0); 156 | } 157 | 158 | static int usage(const char *prog_name) 159 | { 160 | fprintf(stderr, "Usage: %s [-d|--daemonize] [:]listen-port:target-ip:target-port\n", 161 | prog_name); 162 | 163 | return -1; 164 | } 165 | 166 | static int parse_address_spec(char* address_spec, uint32_t *listen_port, 167 | char *target_ip, size_t target_ip_size, 168 | uint32_t *target_port) 169 | { 170 | char *token = strtok(address_spec, ":"); 171 | int direction = DIR_IN; 172 | 173 | if (NULL != token) { 174 | if (!strncmp(token, "out", strlen("out"))) { 175 | direction = DIR_OUT; 176 | token = strtok(NULL, ":"); 177 | } else if (!strncmp(token, "in", strlen("in"))) { 178 | direction = DIR_IN; 179 | token = strtok(NULL, ":"); 180 | } 181 | } 182 | 183 | if (NULL != token) { 184 | errno = 0; 185 | *listen_port = (uint32_t) strtoul(token, NULL, 0); 186 | 187 | if (errno) { 188 | fprintf(stderr, "Couldn't parse the listen port argument (%s)!\n", 189 | token); 190 | return -1; 191 | } 192 | 193 | token = strtok(NULL, ":"); 194 | } 195 | 196 | if (NULL != token) { 197 | strncpy(target_ip, token, target_ip_size); 198 | token = strtok(NULL, ":"); 199 | } 200 | 201 | if (NULL != token) { 202 | errno = 0; 203 | *target_port = (uint32_t) strtoul(token, NULL, 0); 204 | 205 | if (errno) { 206 | fprintf(stderr, "Couldn't parse the target port argument (%s)!\n", 207 | token); 208 | return -1; 209 | } 210 | 211 | token = strtok(NULL, ":"); 212 | } 213 | 214 | if (NULL != token) { 215 | fprintf(stderr, "Garbage after address spec (%s)!\n", token); 216 | return -1; 217 | } 218 | 219 | return direction; 220 | } 221 | 222 | static int send_receive(socket_t *in, socket_t *out) 223 | { 224 | int retval; 225 | uint8_t buffer[MAX_BUF_SIZE]; 226 | 227 | for (;;) { 228 | if ((retval = in->recv(in->fd, buffer, sizeof(buffer), 0)) > 0) { 229 | // Data received! 230 | if (out->send(out->fd, buffer, retval, 0) < 0) { 231 | // Couldn't send! 232 | out->close(out->fd); 233 | return 0; 234 | } 235 | } else if (0 == retval) { 236 | // Remote socket closed! 237 | out->close(out->fd); 238 | return 0; 239 | } else { 240 | if ((*(in->error) != EAGAIN) && \ 241 | (*(in->error) != EWOULDBLOCK)) 242 | { 243 | // Remote socket error! 244 | out->close(out->fd); 245 | return 0; 246 | } 247 | // No data yet 248 | } 249 | 250 | if ((retval = out->recv(out->fd, buffer, sizeof(buffer), 0)) > 0) { 251 | // Data received! 252 | if (in->send(in->fd, buffer, retval, 0) < 0) { 253 | // Couldn't send! 254 | out->close(out->fd); 255 | return 0; 256 | } 257 | } else if (0 == retval) { 258 | // Target socket closed! 259 | out->close(out->fd); 260 | return 0; 261 | } else { 262 | if ((*(out->error) != EAGAIN) && \ 263 | (*(out->error) != EWOULDBLOCK)) 264 | { 265 | // Target socket error! 266 | out->close(out->fd); 267 | return 0; 268 | } 269 | // No data yet 270 | } 271 | } 272 | } 273 | 274 | static int handle_incoming_connection(socket_t *in, socket_t *out, 275 | const char *target_ip, 276 | uint32_t target_port) 277 | { 278 | int flags; 279 | struct sockaddr_in target; 280 | 281 | if ((out->fd = out->socket(AF_INET, SOCK_STREAM, 0)) < 0) { 282 | fprintf(stderr, "socket failed: %d\n", *(out->error)); 283 | return -1; 284 | } 285 | 286 | target.sin_family = AF_INET; 287 | target.sin_port = htons(target_port); 288 | 289 | if (inet_pton(AF_INET, target_ip, &target.sin_addr) <= 0) { 290 | fprintf(stderr, "inet_pton failed: %d\n", errno); 291 | out->close(out->fd); 292 | return -1; 293 | } 294 | 295 | if (out->connect(out->fd, (struct sockaddr *) &target, sizeof(target)) < 0) { 296 | fprintf(stderr, "connect failed: %d\n", *(out->error)); 297 | out->close(out->fd); 298 | return -1; 299 | } 300 | 301 | if ((flags = out->fcntl(out->fd, F_GETFL)) < 0) { 302 | fprintf(stderr, "fcntl[F_GETFL] failed: %d\n", *(out->error)); 303 | out->close(out->fd); 304 | return -1; 305 | } 306 | 307 | if (out->fcntl(out->fd, F_SETFL, flags | O_NONBLOCK) < 0) { 308 | fprintf(stderr, "fcntl[F_SETFL] failed: %d\n", *(out->error)); 309 | out->close(out->fd); 310 | return -1; 311 | } 312 | 313 | return send_receive(in, out); 314 | } 315 | 316 | static int tunnel(socket_t *s_listen, socket_t *in, socket_t *out, 317 | uint32_t listen_port, char *target_ip, uint32_t target_port) 318 | { 319 | int flags, process_id; 320 | struct sockaddr_in local, remote; 321 | socklen_t remotelen = sizeof(remote); 322 | 323 | if ((s_listen->fd = s_listen->socket(AF_INET, SOCK_STREAM, 0)) < 0) { 324 | fprintf(stderr, "socket failed: %d\n", *(s_listen->error)); 325 | return -1; 326 | } 327 | 328 | if ((flags = s_listen->fcntl(s_listen->fd, F_GETFL)) < 0) { 329 | fprintf(stderr, "fcntl[F_GETFL] failed: %d\n", *(s_listen->error)); 330 | s_listen->close(s_listen->fd); 331 | return -1; 332 | } 333 | 334 | if (s_listen->fcntl(s_listen->fd, F_SETFL, flags | O_NONBLOCK) < 0) { 335 | fprintf(stderr, "fcntl[F_SETFL] failed: %d\n", *(s_listen->error)); 336 | s_listen->close(s_listen->fd); 337 | return -1; 338 | } 339 | 340 | local.sin_family = AF_INET; 341 | local.sin_port = htons(listen_port); 342 | local.sin_addr.s_addr = INADDR_ANY; 343 | if (s_listen->bind(s_listen->fd, (struct sockaddr*) &local, 344 | sizeof(local)) < 0) 345 | { 346 | fprintf(stderr, "bind failed: %d\n", *(s_listen->error)); 347 | s_listen->close(s_listen->fd); 348 | return -1; 349 | } 350 | 351 | if (s_listen->listen(s_listen->fd, 5) < 0) { 352 | fprintf(stderr, "listen failed: %d\n", *(s_listen->error)); 353 | s_listen->close(s_listen->fd); 354 | return -1; 355 | } 356 | 357 | if (daemonize) { 358 | printf("Waiting for connections in the background...\n"); 359 | if ((process_id = fork()) < 0) { 360 | fprintf(stderr, "Couldn't daemonize - continuing in foreground...\n"); 361 | } else if (process_id > 0) { 362 | exit(0); 363 | } else { 364 | close(STDIN_FILENO); 365 | } 366 | } 367 | 368 | for (;;) { 369 | // Wait for an incoming connection... 370 | in->fd = s_listen->accept(s_listen->fd, (struct sockaddr*) &remote, 371 | &remotelen); 372 | 373 | if (in->fd < 0) { 374 | if ((*(in->error) != EAGAIN ) && \ 375 | (*(in->error) != EWOULDBLOCK)) 376 | { 377 | fprintf(stderr, "accept failed: %d\n", *(in->error)); 378 | s_listen->close(s_listen->fd); 379 | return -1; 380 | } else { 381 | usleep(10000); // TODO: define! 382 | } 383 | } else { 384 | if (handle_incoming_connection(in, out, target_ip, 385 | target_port) < 0) { 386 | break; 387 | } 388 | 389 | in->close(in->fd); 390 | } 391 | } 392 | 393 | in->close(in->fd); 394 | s_listen->close(s_listen->fd); 395 | 396 | return 0; 397 | } 398 | -------------------------------------------------------------------------------- /tcp-tunnel/src/qemu-guest-services/fds.c: -------------------------------------------------------------------------------- 1 | /* 2 | * QEMU Guest Services - File Descriptors API 3 | * 4 | * Copyright (c) 2019 Lev Aronsky 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without retvaltriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPretvalS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #include 26 | #include 27 | #include "hw/arm/guest-services/general.h" 28 | 29 | static int qemu_fd_call(qemu_call_t *qcall) 30 | { 31 | qemu_call(qcall); 32 | 33 | guest_svcs_errno = qcall->error; 34 | return (int) qcall->retval; 35 | } 36 | 37 | int qc_close(int fd) 38 | { 39 | qemu_call_t qcall = { 40 | .call_number = QC_CLOSE, 41 | .args.close.fd = fd, 42 | }; 43 | 44 | return qemu_fd_call(&qcall); 45 | } 46 | 47 | int qc_fcntl(int fd, int cmd, ...) 48 | { 49 | va_list args; 50 | 51 | qemu_call_t qcall = { 52 | .call_number = QC_FCNTL, 53 | .args.fcntl.fd = fd, 54 | .args.fcntl.cmd = cmd, 55 | }; 56 | 57 | switch (cmd) { 58 | case F_SETFL: 59 | va_start(args, cmd); 60 | qcall.args.fcntl.flags = va_arg(args, int); 61 | va_end(args); 62 | break; 63 | default: 64 | // Intentionally left blank 65 | break; 66 | } 67 | 68 | return qemu_fd_call(&qcall); 69 | } 70 | -------------------------------------------------------------------------------- /tcp-tunnel/src/qemu-guest-services/general.c: -------------------------------------------------------------------------------- 1 | /* 2 | * QEMU Guest Services - General 3 | * 4 | * Copyright (c) 2019 Lev Aronsky 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without retvaltriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPretvalS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #include "hw/arm/guest-services/general.h" 26 | 27 | int32_t guest_svcs_errno = 0; 28 | 29 | void qemu_call(qemu_call_t *qcall) 30 | { 31 | asm volatile ("mov x0, %[addr]"::[addr] "r" (qcall)); 32 | asm volatile (".byte 0x00"); 33 | asm volatile (".byte 0xff"); 34 | asm volatile (".byte 0x1b"); 35 | asm volatile (".byte 0xd5"); 36 | } 37 | -------------------------------------------------------------------------------- /tcp-tunnel/src/qemu-guest-services/socket.c: -------------------------------------------------------------------------------- 1 | /* 2 | * QEMU Guest Services - Socket API 3 | * 4 | * Copyright (c) 2019 Lev Aronsky 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without retvaltriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPretvalS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #include "hw/arm/guest-services/general.h" 26 | 27 | static int qemu_sckt_call(qemu_call_t *qcall) 28 | { 29 | qemu_call(qcall); 30 | 31 | guest_svcs_errno = qcall->error; 32 | return (int) qcall->retval; 33 | } 34 | 35 | int qc_socket(int domain, int type, int protocol) 36 | { 37 | qemu_call_t qcall = { 38 | .call_number = QC_SOCKET, 39 | .args.socket.domain = domain, 40 | .args.socket.type = type, 41 | .args.socket.protocol = protocol, 42 | }; 43 | 44 | return qemu_sckt_call(&qcall); 45 | } 46 | 47 | int qc_accept(int sckt, struct sockaddr *addr, socklen_t *addrlen) 48 | { 49 | qemu_call_t qcall = { 50 | .call_number = QC_ACCEPT, 51 | .args.accept.socket = sckt, 52 | .args.accept.addr = addr, 53 | .args.accept.addrlen = addrlen, 54 | }; 55 | 56 | return qemu_sckt_call(&qcall); 57 | } 58 | 59 | int qc_bind(int sckt, const struct sockaddr *addr, socklen_t addrlen) 60 | { 61 | qemu_call_t qcall = { 62 | .call_number = QC_BIND, 63 | .args.bind.socket = sckt, 64 | .args.bind.addr = (struct sockaddr *) addr, 65 | .args.bind.addrlen = addrlen, 66 | }; 67 | 68 | return qemu_sckt_call(&qcall); 69 | } 70 | 71 | int qc_connect(int sckt, const struct sockaddr *addr, socklen_t addrlen) 72 | { 73 | qemu_call_t qcall = { 74 | .call_number = QC_CONNECT, 75 | .args.connect.socket = sckt, 76 | .args.connect.addr = (struct sockaddr *) addr, 77 | .args.connect.addrlen = addrlen, 78 | }; 79 | 80 | return qemu_sckt_call(&qcall); 81 | } 82 | 83 | int qc_listen(int sckt, int backlog) 84 | { 85 | qemu_call_t qcall = { 86 | .call_number = QC_LISTEN, 87 | .args.listen.socket = sckt, 88 | .args.listen.backlog = backlog, 89 | }; 90 | 91 | return qemu_sckt_call(&qcall); 92 | } 93 | 94 | ssize_t qc_recv(int sckt, void *buffer, size_t length, int flags) 95 | { 96 | qemu_call_t qcall = { 97 | .call_number = QC_RECV, 98 | .args.recv.socket = sckt, 99 | .args.recv.buffer = buffer, 100 | .args.recv.length = length, 101 | .args.recv.flags = flags, 102 | }; 103 | 104 | return qemu_sckt_call(&qcall); 105 | } 106 | 107 | ssize_t qc_send(int sckt, const void *buffer, size_t length, int flags) 108 | { 109 | qemu_call_t qcall = { 110 | .call_number = QC_SEND, 111 | .args.send.socket = sckt, 112 | .args.send.buffer = (void *) buffer, 113 | .args.send.length = length, 114 | .args.send.flags = flags, 115 | }; 116 | 117 | return qemu_sckt_call(&qcall); 118 | } 119 | -------------------------------------------------------------------------------- /xnu-kvm-lkm/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 3 | clean: 4 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 5 | 6 | -------------------------------------------------------------------------------- /xnu-kvm-lkm/xnu-kvm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "xnu-kvm.h" 6 | 7 | MODULE_LICENSE("GPL"); 8 | MODULE_AUTHOR("Lev Aronsky"); 9 | MODULE_DESCRIPTION("A Linux module that changes KVM behaviour."); 10 | MODULE_VERSION("0.03"); 11 | 12 | void **arm_exit_handlers; 13 | kvm_arm_handler_fn kvm_handle_sys_reg_orig, kvm_handle_hvc_orig; 14 | 15 | static uint64_t custom_cpregs[12] = {0}; 16 | 17 | /* 18 | * Return 0 (and set exit reason) for proper exit to user-space. 19 | */ 20 | int kvm_handle_hvc_hook(struct kvm_vcpu *vcpu, struct kvm_run *run) { 21 | u32 hvc_imm = kvm_vcpu_hvc_get_imm(vcpu); 22 | u64 hvc_x0 = vcpu_get_reg(vcpu, 0); 23 | 24 | printk(KERN_INFO "KVM Enhancements: hvc #%x [x0 = %llx] called!\n", hvc_imm, hvc_x0); 25 | 26 | if (hvc_imm) { 27 | run->exit_reason = KVM_EXIT_HYPERCALL; 28 | run->hypercall.nr = hvc_imm; 29 | run->hypercall.args[0] = vcpu_get_reg(vcpu, 0); 30 | run->hypercall.args[1] = vcpu_get_reg(vcpu, 1); 31 | run->hypercall.args[2] = vcpu_get_reg(vcpu, 2); 32 | run->hypercall.args[3] = vcpu_get_reg(vcpu, 3); 33 | run->hypercall.args[4] = vcpu_get_reg(vcpu, 4); 34 | run->hypercall.args[0] = vcpu_get_reg(vcpu, 5); 35 | 36 | return 0; 37 | } 38 | 39 | return kvm_handle_hvc_orig(vcpu, run); 40 | } 41 | 42 | /* 43 | * Return 0 (and set exit reason) for proper exit to user-space. 44 | */ 45 | int kvm_handle_sys_reg_hook(struct kvm_vcpu *vcpu, struct kvm_run *run) { 46 | struct sys_reg_params params; 47 | unsigned long esr = kvm_vcpu_get_hsr(vcpu); 48 | int Rt = kvm_vcpu_sys_get_rt(vcpu); 49 | uint64_t *storage; 50 | 51 | params.is_aarch32 = false; 52 | params.is_32bit = false; 53 | params.Op0 = (esr >> 20) & 3; 54 | params.Op1 = (esr >> 14) & 0x7; 55 | params.CRn = (esr >> 10) & 0xf; 56 | params.CRm = (esr >> 1) & 0xf; 57 | params.Op2 = (esr >> 17) & 0x7; 58 | params.regval = vcpu_get_reg(vcpu, Rt); 59 | params.is_write = !(esr & 1); 60 | 61 | if ((params.Op0 == 3) && (params.CRn == 15)) { 62 | switch (params.Op1) { 63 | case 0: 64 | if (params.CRm == 3) { 65 | storage = &custom_cpregs[0]; 66 | } 67 | else if (params.CRm == 4) { 68 | storage = &custom_cpregs[1]; 69 | } 70 | else if (params.CRm == 5) { 71 | storage = &custom_cpregs[2]; 72 | } 73 | else if (params.CRm == 7) { 74 | storage = &custom_cpregs[3]; 75 | } 76 | else if (params.CRm == 8) { 77 | storage = &custom_cpregs[4]; 78 | } 79 | else if (params.CRm == 13) { 80 | storage = &custom_cpregs[5]; 81 | } 82 | else goto kvm_impl; 83 | break; 84 | case 1: 85 | if (params.CRm == 0) { 86 | storage = &custom_cpregs[6]; 87 | } 88 | else if (params.CRm == 1) { 89 | storage = &custom_cpregs[7]; 90 | } 91 | else if (params.CRm == 13) { 92 | storage = &custom_cpregs[8]; 93 | } 94 | else goto kvm_impl; 95 | break; 96 | case 2: 97 | if (params.CRm == 0) { 98 | storage = &custom_cpregs[9]; 99 | } 100 | else if (params.CRm == 1) { 101 | storage = &custom_cpregs[10]; 102 | } 103 | else goto kvm_impl; 104 | break; 105 | case 3: 106 | if (params.CRm == 0) { 107 | storage = &custom_cpregs[11]; 108 | } 109 | else goto kvm_impl; 110 | break; 111 | default: 112 | goto kvm_impl; 113 | } 114 | } else goto kvm_impl; 115 | 116 | if (!params.is_write) { 117 | vcpu_set_reg(vcpu, Rt, *storage); 118 | } else { 119 | *storage = params.regval; 120 | } 121 | 122 | *vcpu_pc(vcpu) += 4; 123 | *vcpu_cpsr(vcpu) &= ~DBG_SPSR_SS; 124 | 125 | return 1; 126 | 127 | kvm_impl: 128 | return kvm_handle_sys_reg_orig(vcpu, run); 129 | } 130 | 131 | int disable_protection(uint64_t addr) { 132 | /* Manually disable write-protection of the relevant page. 133 | Taken from: 134 | https://stackoverflow.com/questions/45216054/arm64-linux-memory-write-protection-wont-disable 135 | */ 136 | pgd_t *pgd; 137 | pte_t *ptep, pte; 138 | pud_t *pud; 139 | pmd_t *pmd; 140 | 141 | pgd = pgd_offset((struct mm_struct*)kallsyms_lookup_name("init_mm"), (addr)); 142 | 143 | if (pgd_none(*pgd) || pgd_bad(*pgd)) 144 | goto out; 145 | printk(KERN_NOTICE "Valid pgd 0x%px\n",pgd); 146 | 147 | pud = pud_offset(pgd, addr); 148 | if (pud_none(*pud) || pud_bad(*pud)) 149 | goto out; 150 | printk(KERN_NOTICE "Valid pud 0x%px\n",pud); 151 | 152 | pmd = pmd_offset(pud, addr); 153 | if (pmd_none(*pmd) || pmd_bad(*pmd)) 154 | goto out; 155 | printk(KERN_NOTICE "Valid pmd 0x%px\n",pmd); 156 | 157 | ptep = pte_offset_map(pmd, addr); 158 | if (!ptep) 159 | goto out; 160 | pte = *ptep; 161 | 162 | printk(KERN_INFO "PTE before 0x%lx\n", *(unsigned long*) &pte); 163 | printk(KERN_INFO "Setting PTE write\n"); 164 | 165 | pte = pte_mkwrite(pte); 166 | *ptep = clear_pte_bit(pte, __pgprot((_AT(pteval_t, 1) << 7))); 167 | 168 | printk(KERN_INFO "PTE after 0x%lx\n", *(unsigned long*) &pte); 169 | flush_tlb_all(); 170 | printk(KERN_INFO "PTE nach flush 0x%lx\n", *(unsigned long*) &pte); 171 | 172 | return 0; 173 | 174 | out: 175 | return 1; 176 | } 177 | 178 | static int __init kvm_enhancer_init(void) { 179 | arm_exit_handlers = (void**) kallsyms_lookup_name("arm_exit_handlers"); 180 | if (NULL == arm_exit_handlers) { 181 | printk(KERN_ERR "KVM Enhancements: arm_exit_handlers not found, make sure you're using a supported kernel!\n"); 182 | return 1; 183 | } 184 | 185 | kvm_handle_sys_reg_orig = arm_exit_handlers[ESR_ELx_EC_SYS64]; 186 | kvm_handle_hvc_orig = arm_exit_handlers[ESR_ELx_EC_HVC64]; 187 | 188 | printk(KERN_INFO "KVM Enhancements: kvm_handle_sys_reg @ 0x%px\n", kvm_handle_sys_reg_orig); 189 | printk(KERN_INFO "KVM Enhancements: kvm_handle_hvc @ 0x%px\n", kvm_handle_hvc_orig); 190 | printk(KERN_INFO "KVM Enhancements: setting hooks...\n"); 191 | 192 | if (disable_protection((uint64_t) arm_exit_handlers)) { 193 | printk(KERN_ERR "KVM Enhancements: Couldn't disable write protection on arm_exit_handlers!\n"); 194 | return 2; 195 | } 196 | 197 | arm_exit_handlers[ESR_ELx_EC_SYS64] = kvm_handle_sys_reg_hook; 198 | arm_exit_handlers[ESR_ELx_EC_HVC64] = kvm_handle_hvc_hook; 199 | 200 | printk(KERN_INFO "KVM Enhancements: hooks set!\n"); 201 | printk(KERN_INFO "KVM Enhancements: loaded!\n"); 202 | return 0; 203 | } 204 | 205 | static void __exit kvm_enhancer_exit(void) { 206 | printk(KERN_INFO "KVM Enhancements: removing hooks...\n"); 207 | 208 | arm_exit_handlers[ESR_ELx_EC_SYS64] = kvm_handle_sys_reg_orig; 209 | arm_exit_handlers[ESR_ELx_EC_HVC64] = kvm_handle_hvc_orig; 210 | 211 | printk(KERN_INFO "KVM Enhancements: hook removed!\n"); 212 | printk(KERN_INFO "KVM Enhancements: unloaded!\n"); 213 | } 214 | 215 | module_init(kvm_enhancer_init); 216 | module_exit(kvm_enhancer_exit); 217 | -------------------------------------------------------------------------------- /xnu-kvm-lkm/xnu-kvm.h: -------------------------------------------------------------------------------- 1 | #ifndef _VCPU_ACCESSORS_H_ 2 | #define _VCPU_ACCESSORS_H_ 3 | 4 | #include 5 | 6 | struct sys_reg_params { 7 | u8 Op0; 8 | u8 Op1; 9 | u8 CRn; 10 | u8 CRm; 11 | u8 Op2; 12 | u64 regval; 13 | bool is_write; 14 | bool is_aarch32; 15 | bool is_32bit; /* Only valid if is_aarch32 is true */ 16 | }; 17 | 18 | typedef int (*kvm_arm_handler_fn)(struct kvm_vcpu*, struct kvm_run*); 19 | 20 | static inline unsigned long vcpu_get_reg(const struct kvm_vcpu *vcpu, 21 | u8 reg_num) 22 | { 23 | return (reg_num == 31) ? 0 : vcpu_gp_regs(vcpu)->regs.regs[reg_num]; 24 | } 25 | 26 | static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num, 27 | unsigned long val) 28 | { 29 | if (reg_num != 31) 30 | vcpu_gp_regs(vcpu)->regs.regs[reg_num] = val; 31 | } 32 | 33 | static inline unsigned long *vcpu_pc(const struct kvm_vcpu *vcpu) 34 | { 35 | return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.pc; 36 | } 37 | 38 | static inline unsigned long *vcpu_cpsr(const struct kvm_vcpu *vcpu) 39 | { 40 | return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.pstate; 41 | } 42 | 43 | static inline u32 kvm_vcpu_get_hsr(const struct kvm_vcpu *vcpu) 44 | { 45 | return vcpu->arch.fault.esr_el2; 46 | } 47 | 48 | static inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu) 49 | { 50 | u32 esr = kvm_vcpu_get_hsr(vcpu); 51 | return ESR_ELx_SYS64_ISS_RT(esr); 52 | } 53 | 54 | static inline u32 kvm_vcpu_hvc_get_imm(const struct kvm_vcpu *vcpu) 55 | { 56 | return kvm_vcpu_get_hsr(vcpu) & ESR_ELx_xVC_IMM_MASK; 57 | } 58 | 59 | #endif /* _VCPU_ACCESSORS_H_ */ 60 | --------------------------------------------------------------------------------