├── 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 |
--------------------------------------------------------------------------------