├── control ├── Makefile ├── ent.xml ├── README.md ├── bitmap.h ├── kern_utils.h ├── kern_utils.m └── main.m /control: -------------------------------------------------------------------------------- 1 | Package: net.jakeashacks.sneakyshot 2 | Name: SneakyShot 3 | Version: 0.0.1 4 | Architecture: iphoneos-arm 5 | Description: An awesome tool of some sort!! 6 | Maintainer: Jake James 7 | Author: Jake James 8 | Section: System 9 | Tag: role::hacker 10 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | include $(THEOS)/makefiles/common.mk 2 | 3 | export ARCHS = arm64 arm64e 4 | 5 | TOOL_NAME = SneakyShot 6 | 7 | SneakyShot_FILES = $(wildcard *.m) $(wildcard *.c) 8 | SneakyShot_CFLAGS = -fobjc-arc 9 | SneakyShot_CODESIGN_FLAGS = -Sent.xml 10 | 11 | include $(THEOS_MAKE_PATH)/tool.mk 12 | -------------------------------------------------------------------------------- /ent.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | platform-application 6 | 7 | task_for_pid-allow 8 | 9 | com.apple.private.memorystatus 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SneakyShot 2 | 3 | Kernel-based method to take screenshots on iOS. Works with encrypted videos. 4 | 5 | This code is one year old. I open-sourced it now since I probably won't look into it for the time being. 6 | The issue with it is that it only reads from one framebuffer and most of the time the results will be a few seconds old. 7 | Image is saved as an uncompressed bitmap file. The vinfo address is hardcoded for iPad5,3 iOS 12.4. 8 | -------------------------------------------------------------------------------- /bitmap.h: -------------------------------------------------------------------------------- 1 | #pragma pack(push,1) 2 | typedef struct{ 3 | uint8_t signature[2]; 4 | uint32_t filesize; 5 | uint32_t reserved; 6 | uint32_t fileoffset_to_pixelarray; 7 | } fileheader; 8 | 9 | typedef struct{ 10 | uint32_t dibheadersize; 11 | uint32_t width; 12 | uint32_t height; 13 | uint16_t planes; 14 | uint16_t bitsperpixel; 15 | uint32_t compression; 16 | uint32_t imagesize; 17 | uint32_t ypixelpermeter; 18 | uint32_t xpixelpermeter; 19 | uint32_t numcolorspallette; 20 | uint32_t mostimpcolor; 21 | } bitmapinfoheader; 22 | 23 | typedef struct { 24 | fileheader fileheader; 25 | bitmapinfoheader bitmapinfoheader; 26 | } bitmap; 27 | 28 | #pragma pack(pop) 29 | -------------------------------------------------------------------------------- /kern_utils.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | kern_return_t mach_vm_allocate(vm_map_t target, mach_vm_address_t *address, mach_vm_size_t size, int flags); 7 | kern_return_t mach_vm_deallocate(vm_map_t target, mach_vm_address_t address, mach_vm_size_t size); 8 | kern_return_t mach_vm_read_overwrite(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, mach_vm_address_t data, mach_vm_size_t *outsize); 9 | kern_return_t mach_vm_write(vm_map_t target_task, mach_vm_address_t address, vm_offset_t data, mach_msg_type_number_t dataCnt); 10 | 11 | void init_kernel_utils(mach_port_t tfp0); 12 | 13 | uint64_t kalloc(vm_size_t size); 14 | void kfree(mach_vm_address_t address, vm_size_t size); 15 | 16 | size_t kread(uint64_t where, void *p, size_t size); 17 | uint32_t kread32(uint64_t where); 18 | uint64_t kread64(uint64_t where); 19 | 20 | size_t kwrite(uint64_t where, const void *p, size_t size); 21 | void kwrite32(uint64_t where, uint32_t what); 22 | void kwrite64(uint64_t where, uint64_t what); -------------------------------------------------------------------------------- /kern_utils.m: -------------------------------------------------------------------------------- 1 | #include "kern_utils.h" 2 | 3 | mach_port_t tfpzero; 4 | mach_port_t uc; 5 | 6 | void init_kernel_utils(mach_port_t tfp0) { 7 | tfpzero = tfp0; 8 | } 9 | 10 | uint64_t kalloc(vm_size_t size) { 11 | mach_vm_address_t address = 0; 12 | mach_vm_allocate(tfpzero, (mach_vm_address_t *)&address, size, VM_FLAGS_ANYWHERE); 13 | return address; 14 | } 15 | 16 | size_t kread(uint64_t where, void *p, size_t size) { 17 | int rv; 18 | size_t offset = 0; 19 | while (offset < size) { 20 | mach_vm_size_t sz, chunk = 2048; 21 | if (chunk > size - offset) { 22 | chunk = size - offset; 23 | } 24 | rv = mach_vm_read_overwrite(tfpzero, where + offset, chunk, (mach_vm_address_t)p + offset, &sz); 25 | if (rv || sz == 0) { 26 | printf("[*] error on kread(0x%016llx)\n", (offset + where)); 27 | break; 28 | } 29 | offset += sz; 30 | } 31 | return offset; 32 | } 33 | 34 | uint32_t kread32(uint64_t where) { 35 | uint32_t out; 36 | kread(where, &out, sizeof(uint32_t)); 37 | return out; 38 | } 39 | 40 | uint64_t kread64(uint64_t where) { 41 | uint64_t out; 42 | kread(where, &out, sizeof(uint64_t)); 43 | return out; 44 | } 45 | 46 | size_t kwrite(uint64_t where, const void *p, size_t size) { 47 | int rv; 48 | size_t offset = 0; 49 | while (offset < size) { 50 | size_t chunk = 2048; 51 | if (chunk > size - offset) { 52 | chunk = size - offset; 53 | } 54 | rv = mach_vm_write(tfpzero, where + offset, (mach_vm_offset_t)p + offset, chunk); 55 | if (rv) { 56 | printf("[*] error on kwrite(0x%016llx)\n", (offset + where)); 57 | break; 58 | } 59 | offset += chunk; 60 | } 61 | return offset; 62 | } 63 | 64 | void kwrite32(uint64_t where, uint32_t what) { 65 | uint32_t _what = what; 66 | kwrite(where, &_what, sizeof(uint32_t)); 67 | } 68 | 69 | 70 | void kwrite64(uint64_t where, uint64_t what) { 71 | uint64_t _what = what; 72 | kwrite(where, &_what, sizeof(uint64_t)); 73 | } 74 | 75 | void kfree(mach_vm_address_t address, vm_size_t size){ 76 | mach_vm_deallocate(tfpzero, address, size); 77 | } -------------------------------------------------------------------------------- /main.m: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "kern_utils.h" 7 | #include "bitmap.h" 8 | 9 | #define MEMORYSTATUS_CMD_SET_JETSAM_TASK_LIMIT 6 10 | int memorystatus_control(uint32_t command, int32_t pid, uint32_t flags, void *buffer, size_t buffersize); 11 | 12 | int main(int argc, char *argv[], char *envp[]) { 13 | if (getuid()) { 14 | printf("[-] please run as root\n"); 15 | return 1; 16 | } 17 | 18 | if (argc != 2) { 19 | printf("[-] usage: %s /image/save/path.bmp\n", argv[0]); 20 | return 2; 21 | } 22 | 23 | memorystatus_control(MEMORYSTATUS_CMD_SET_JETSAM_TASK_LIMIT, getpid(), 0, NULL, 0); 24 | 25 | char *save_path = argv[1]; 26 | if (!access(save_path, F_OK)) { 27 | printf("[-] file exists\n"); 28 | return 3; 29 | } 30 | 31 | mach_port_t tfp0 = MACH_PORT_NULL; 32 | kern_return_t ret = task_for_pid(mach_task_self(), 0, &tfp0); 33 | if (ret) { 34 | ret = host_get_special_port(mach_host_self(), HOST_LOCAL_NODE, 4, &tfp0); 35 | if (ret) { 36 | printf("[-] both tfp0 and hsp4 failed. what jailbreak is this?\n"); 37 | return 4; 38 | } 39 | } 40 | printf("[i] tfp0: 0x%x\n", tfp0); 41 | 42 | init_kernel_utils(tfp0); 43 | struct task_dyld_info info; 44 | mach_msg_type_number_t count = 5; 45 | task_info(tfp0, 17, (task_info_t)&info, &count); 46 | uint32_t slide = info.all_image_info_size; 47 | printf("[i] kaslr: 0x%x\n", slide); 48 | 49 | uint64_t vinfo = 0xFFFFFFF00764A0F0 + slide; 50 | uint32_t height = kread32(vinfo); 51 | uint32_t width = kread32(vinfo + 4); 52 | uint32_t depth = kread32(vinfo + 8); 53 | uint64_t baseaddr = kread64(vinfo + 16); 54 | printf("[i] framebuffer: 0x%llx\n", baseaddr); 55 | 56 | size_t buffer_size = width * height * depth/8; 57 | 58 | char *pixelbuffer = malloc(buffer_size); 59 | kread(baseaddr, pixelbuffer, buffer_size); 60 | 61 | FILE *f = fopen(save_path, "wb"); 62 | if (!f) { 63 | printf("[-] fopen failed: %d (%s)\n", errno, strerror(errno)); 64 | return 5; 65 | } 66 | 67 | bitmap *pbitmap = calloc(1, sizeof(bitmap)); 68 | pbitmap->fileheader.signature[0] = 'B'; 69 | pbitmap->fileheader.signature[1] = 'M'; 70 | pbitmap->fileheader.filesize = sizeof(bitmap) + buffer_size; 71 | pbitmap->fileheader.fileoffset_to_pixelarray = sizeof(bitmap); 72 | pbitmap->bitmapinfoheader.dibheadersize = sizeof(bitmapinfoheader); 73 | pbitmap->bitmapinfoheader.width = width; 74 | pbitmap->bitmapinfoheader.height = -height; 75 | pbitmap->bitmapinfoheader.planes = 1; 76 | pbitmap->bitmapinfoheader.bitsperpixel = depth; 77 | pbitmap->bitmapinfoheader.imagesize = buffer_size; 78 | 79 | fwrite(pbitmap, 1, sizeof(bitmap), f); 80 | fwrite(pixelbuffer, 1, buffer_size, f); 81 | fclose(f); 82 | free(pbitmap); 83 | free(pixelbuffer); 84 | 85 | return 0; 86 | } 87 | --------------------------------------------------------------------------------