├── README.md ├── ent.xml ├── fb_write.c └── hacked.jpeg /README.md: -------------------------------------------------------------------------------- 1 | # framebuffer_write 2 | A tool to write text to the iOS screen by directly modifying the pixel information in the framebuffer 3 | 4 | Usage: `fb_write ` 5 | 6 | Example result: 7 | ![](hacked.jpeg) 8 | 9 | Blog post - https://medium.com/@bellis1000/exploring-the-ios-screen-frame-buffer-a-kernel-reversing-experiment-6cbf9847365 10 | -------------------------------------------------------------------------------- /ent.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | platform-application 5 | 6 | com.apple.private.security.no-container 7 | 8 | com.apple.system-task-ports 9 | 10 | task_for_pid-allow 11 | 12 | get-task-allow 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /fb_write.c: -------------------------------------------------------------------------------- 1 | // 2 | // fb_write.c 3 | // written by Billy Ellis (@bellis1000) on 18/01/2020 4 | // 5 | // 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | // requires iso_font.c from https://github.com/apple/darwin-xnu/blob/master/osfmk/console/iso_font.c 13 | #include "iso_font.c" 14 | 15 | #define WHITE 0xffffffff 16 | #define BLACK 0x00000000 17 | #define VINFO_ADDR 0x8037F260 18 | #define LC_SIZE 0x0000000f 19 | #define FRAMEBUFFER_OFFSET 0x10 20 | 21 | mach_port_t get_kernel_task_port(){ 22 | mach_port_t kernel_task; 23 | kern_return_t kr; 24 | if ((kr = task_for_pid(mach_task_self(), 0, &kernel_task)) != KERN_SUCCESS){ 25 | return -1; 26 | } 27 | return kernel_task; 28 | } 29 | 30 | uint32_t do_kernel_read(uint32_t addr){ 31 | size_t size = 4; 32 | uint32_t data = 0; 33 | 34 | kern_return_t kr = vm_read_overwrite(get_kernel_task_port(),(vm_address_t)addr,size,(vm_address_t)&data,&size); 35 | if (kr != KERN_SUCCESS){ 36 | printf("[!] Read failed. %s\n",mach_error_string(kr)); 37 | return -1; 38 | } 39 | return data; 40 | } 41 | 42 | void do_kernel_write(uint32_t addr, uint32_t data){ 43 | kern_return_t kr = vm_write(get_kernel_task_port(),(vm_address_t)addr,(vm_address_t)&data,sizeof(data)); 44 | 45 | if (kr != KERN_SUCCESS){ 46 | printf("Error writing!\n"); 47 | return; 48 | } 49 | } 50 | 51 | uint32_t get_kernel_slide(){ 52 | uint32_t slide; 53 | uint32_t base = 0x80001000; 54 | uint32_t slid_base; 55 | 56 | for (int slide_byte = 256; slide_byte >= 1; slide_byte--){ 57 | slide = 0x01000000 + 0x00200000 * slide_byte; 58 | slid_base = base + slide; 59 | 60 | if (do_kernel_read(slid_base) == 0xfeedface){ 61 | if (do_kernel_read(slid_base + 0x10) == LC_SIZE){ 62 | return slide; 63 | } 64 | } 65 | } 66 | return -1; 67 | } 68 | 69 | uint32_t get_frame_buffer_address(){ 70 | return do_kernel_read(VINFO_ADDR + FRAMEBUFFER_OFFSET + get_kernel_slide()); 71 | } 72 | 73 | void write_char(char c, int col){ 74 | uint32_t addr = get_frame_buffer_address(); 75 | 76 | for (int y = 0; y < 15; y += 1){ 77 | int value = iso_font[c * 16 + y]; 78 | 79 | for (int x = col; x < col + 8; x++){ 80 | 81 | if ((value & (1 << (x - col)))){ 82 | do_kernel_write(addr + (x * 4) + (y * 256), WHITE); 83 | }else{ 84 | do_kernel_write(addr + (x * 4) + (y * 256), BLACK); 85 | } 86 | 87 | } 88 | } 89 | } 90 | 91 | void print(char *str, int len){ 92 | for (int i = 0; i < len; i++){ 93 | write_char(str[i], i * 8); 94 | } 95 | } 96 | 97 | int main(int argc, char *argv[]){ 98 | if (argc < 2){ 99 | printf("Usage: %s \n", argv[0]); 100 | exit(0); 101 | } 102 | print(argv[1], strlen(argv[1])); 103 | return 0; 104 | } 105 | -------------------------------------------------------------------------------- /hacked.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Billy-Ellis/framebuffer_write/f678656bc966044a454375a9a43123650dfb9380/hacked.jpeg --------------------------------------------------------------------------------