1. 파일 탐지
1-1. Objective-C 메소드
- – (BOOL)isReadableFileAtPath:(NSString *)path;
- – (BOOL)fileExistsAtPath: (NSString *)path isDirectory: (BOOL *)isDirectory
- – (BOOL)fileExistsAtPath: (NSString *)path
- – (NSArray *)contentsOfDirectoryAtPath:(NSString *)path error:(NSError * _Nullable *)error;
Example
if ([[NSFileManager defaultManager] fileExistsAtPath:@”/Applications/Sileo.app”]]) { return YES; //Detected Jailbroken }
1-2. C System Library
- FILE *fopen(const char *pathname, const char *mode);
- int access(const char *path, int amode);
- int open(const char *path, int oflag, …);
- int lstat(const char *path, struct stat * buf);
Example
#include <unistd.h> if (access("/Applications/Sileo.app", F_OK) == 0) { return YES; //Detected Jailbroken }
1-3. Supervisor Call (Low-level, SVC #0x80)
Example
static inline int SVC_statfs64(const char* path, struct statfs *buf) { int64_t flag = 0; __asm __volatile("mov x0, %0" :: "r" ((int64_t)SYS_statfs64)); //SYS_statfs64 __asm __volatile("mov x1, %0" :: "r" (path)); //path __asm __volatile("mov x2, %0" :: "r" (buf)); //struct statfs __asm __volatile("mov x16, %0" :: "r" ((int64_t)SYS_syscall)); //SYS_syscall __asm __volatile("svc #0x80"); //supervisor call __asm __volatile("mov %0, x0" : "=r" (flag)); return (int)flag; } static inline int SVC_Access(const char* detectionPath, int64_t mode) { int64_t flag = 0; __asm __volatile("mov x0, %0" :: "r" ((int64_t)SYS_access)); //SYS_access __asm __volatile("mov x1, %0" :: "r" (detectionPath)); //path __asm __volatile("mov x2, %0" :: "r" (mode)); //mode __asm __volatile("mov x16, %0" :: "r" ((int64_t)SYS_syscall)); //SYS_syscall __asm __volatile("svc #0x80"); //supervisor call __asm __volatile("mov %0, x0" : "=r" (flag)); return (int)flag; } if(SVC_Access("Applications/Sileo/app", F_OK) != ENOENT) { return YES; //Detected Jailbroken }
-(NSArray *)jailbreakFiles { NSArray *file = [NSArray arrayWithObjects: @"/Applications/Cydia.app", @"/Applications/Sileo.app", @"/var/binpack", @"/Library/MobileSubstrate/DynamicLibraries", @"/Library/PreferenceBundles/LibertyPref.bundle", @"/Library/PreferenceBundles/ShadowPreferences.bundle", @"/Library/PreferenceBundles/ABypassPrefs.bundle", @"/Library/PreferenceBundles/FlyJBPrefs.bundle", @"/usr/lib/libhooker.dylib", @"/usr/lib/libsubstitute.dylib", @"/usr/lib/substrate", @"/usr/lib/TweakInject", nil]; return file; } ... +(BOOL)isJailbreakFileExist { BOOL check = NO; NSArray *jbPatternFile = [[[XFJailbreakPattern alloc] init] jailbreakFiles]; NSFileManager *fileManager = [NSFileManager defaultManager]; for (NSString *jbFile in jbPatternFile) { const char *jbFile2 = [jbFile cStringUsingEncoding:NSUTF8StringEncoding]; //NSFileManager fileExistsAtPath if ([fileManager fileExistsAtPath:jbFile]) { NSLog(@"NSFilemanager: %@", jbFile); check = YES; } //System Library - opendir: Sustitute doesn't like hooking opendir :) DIR *dirPoint = opendir(jbFile2); if (dirPoint != NULL) { NSLog(@"opendir: %@ - %p", jbFile, dirPoint); check = YES; } //syscall - SYS_access if(syscall(SYS_access, jbFile2, F_OK) == 0) { NSLog(@"Syscall SYS_access: %@", jbFile); check = YES; } //SVC #0x80 - SYS_syscall - SYS_access, SYS_access, SYS_lstat64, SYS_stat64, SYS_statfs64, SYS_open #if defined __arm64__ || defined __arm64e__ int64_t flag = ENOENT; __asm __volatile("mov x0, #0x21"); //access __asm __volatile("mov x1, %0" :: "r" (jbFile2)); //path __asm __volatile("mov x2, #0"); //mode __asm __volatile("mov x16, #0"); //syscall __asm __volatile("svc #0x80"); //supervisor call __asm __volatile("mov %0, x0" : "=r" (flag)); #else int flag = ENOENT; __asm __volatile("mov r0, #0x21"); //access __asm __volatile("mov r1, %0" :: "r" (jbFile2)); //path __asm __volatile("mov r2, #0"); //mode __asm __volatile("mov r12, #0"); //syscall __asm __volatile("svc #0x80"); //supervisor call __asm __volatile("mov %0, r0" : "=r" (flag)); #endif if (flag != ENOENT ) { NSLog(@"SVC #0x80 SYS_syscall - SYS_access: %s", jbFile2); check = YES; } #if defined __arm64__ || defined __arm64e__ flag = ENOENT; __asm __volatile("mov x0, %0" :: "r" (jbFile2)); //path __asm __volatile("mov x1, #0"); //mode __asm __volatile("mov x16, #0x21"); //access __asm __volatile("svc #0x80"); //supervisor call __asm __volatile("mov %0, x0" : "=r" (flag)); #else flag = ENOENT; __asm __volatile("mov r0, %0" :: "r" (jbFile2)); //path __asm __volatile("mov r1, #0"); //mode __asm __volatile("mov r12, #0x21"); //access __asm __volatile("svc #0x80"); //supervisor call __asm __volatile("mov %0, r0" : "=r" (flag)); #endif if (flag != ENOENT ) { NSLog(@"SVC #0x80 SYS_access: %s", jbFile2); check = YES; } struct stat statPoint; #if defined __arm64__ || defined __arm64e__ flag = ENOENT; __asm __volatile("mov x0, %0" :: "r" (jbFile2)); //path __asm __volatile("mov x1, %0" :: "r" (&statPoint)); //struct stat __asm __volatile("mov x16, #0x154"); //lstat64 __asm __volatile("svc #0x80"); //supervisor call __asm __volatile("mov %0, x0" : "=r" (flag)); #else flag = ENOENT; __asm __volatile("mov r0, %0" :: "r" (jbFile2)); //path __asm __volatile("mov x1, %0" :: "r" (&statPoint)); //struct stat __asm __volatile("mov r12, #0x154"); //lstat64 __asm __volatile("svc #0x80"); //supervisor call __asm __volatile("mov %0, r0" : "=r" (flag)); #endif if (flag != ENOENT ) { NSLog(@"SVC #0x80 SYS_lstat64: %s", jbFile2); check = YES; } #if defined __arm64__ || defined __arm64e__ flag = ENOENT; __asm __volatile("mov x0, %0" :: "r" (jbFile2)); //path __asm __volatile("mov x1, %0" :: "r" (&statPoint)); //struct stat __asm __volatile("mov x16, #0x152"); //stat64 __asm __volatile("svc #0x80"); //supervisor call __asm __volatile("mov %0, x0" : "=r" (flag)); #else flag = ENOENT; __asm __volatile("mov r0, %0" :: "r" (jbFile2)); //path __asm __volatile("mov x1, %0" :: "r" (&statPoint)); //struct stat __asm __volatile("mov r12, #0x152"); //stat64 __asm __volatile("svc #0x80"); //supervisor call __asm __volatile("mov %0, r0" : "=r" (flag)); #endif if (flag != ENOENT ) { NSLog(@"SVC #0x80 SYS_stat64: %s", jbFile2); check = YES; } struct statfs statfsPoint; #if defined __arm64__ || defined __arm64e__ flag = ENOENT; __asm __volatile("mov x0, %0" :: "r" (jbFile2)); //path __asm __volatile("mov x1, %0" :: "r" (&statfsPoint)); //struct statfs __asm __volatile("mov x16, #0x159"); //statfs64 __asm __volatile("svc #0x80"); //supervisor call __asm __volatile("mov %0, x0" : "=r" (flag)); #else flag = ENOENT; __asm __volatile("mov r0, %0" :: "r" (jbFile2)); //path __asm __volatile("mov x1, %0" :: "r" (&statfsPoint)); //struct statfs __asm __volatile("mov r12, #0x159"); //statfs64 __asm __volatile("svc #0x80"); //supervisor call __asm __volatile("mov %0, r0" : "=r" (flag)); #endif if (flag != ENOENT ) { NSLog(@"SVC #0x80 SYS_statfs64: %s", jbFile2); check = YES; } #if defined __arm64__ || defined __arm64e__ flag = 0; __asm __volatile("mov x0, %0" :: "r" (jbFile2)); //path __asm __volatile("mov x1, #0"); __asm __volatile("mov x2, #0"); __asm __volatile("mov x16, #0x5"); //open __asm __volatile("svc #0x80"); //supervisor call __asm __volatile("bcc #0xC"); __asm __volatile("mov x0, #0x0"); __asm __volatile("b #0x8"); __asm __volatile("mov x0, #0x1"); __asm __volatile("mov %0, x0" : "=r" (flag)); #else flag = 0; __asm __volatile("mov r0, %0" :: "r" (jbFile2)); // path __asm __volatile("mov r1, #0"); __asm __volatile("mov r2, #0"); __asm __volatile("mov r12, #0x5"); // open __asm __volatile("svc #0x80"); //supervisor call __asm __volatile("bcc #0x6"); __asm __volatile("mov r0, 0x0"); __asm __volatile("b #0x4"); __asm __volatile("mov r0, #0x1"); __asm __volatile("mov %0, r0" : "=r" (flag)); #endif if(flag == 1) { NSLog(@"SVC #0x80 SYS_open: %s", jbFile2); check = YES; } } return check; }
2. 샌드박스 우회 탐지
2-1. Objective-C / C System Library
Example
NSError *error; [@"Jailbreak Test" writeToFile:@”/private/var/sandbox.txt” atomically:YES encoding:NSUTF8StringEncoding error:&error]; if(error == nil) { return YES; //Detected Jailbroken }
2-2. Private API
- int sandbox_check(pid_t, const char *operation, int sandbox_filter_type, …);
(operation: file-read*)
Example
void *sandbox = dlopen("/usr/lib/system/libsystem_sandbox.dylib", RTLD_NOW); if(sandbox != NULL) { _sandbox_check = dlsym(sandbox, "sandbox_check"); if(_sandbox_check != NULL) { int filter = SANDBOX_FILTER_PATH | SANDBOX_CHECK_NO_REPORT; if(_sandbox_check(getpid(), "file-read*", filter, "/Library") != 1) { return YES; //Detected Jailbroken } } }
3. URL Scheme 탐지
- -(BOOL)canOpenURL:(NSURL *)arg1;
Example
NSURL *url = [NSURL URLWithString:@"sileo://"]; if([[UIApplication sharedApplication] canOpenURL:url]) { return YES; //Detected Jailbroken }
4. 후킹 라이브러리 탐지
4-1. Private API
- kern_return_t task_info(task_name_t target_task, task_flavor_t flavor, task_info_t task_info_out, mach_msg_type_number_t *task_info_outCnt);
- uint32_t _dyld_image_count(void);
- const struct mach_header* _dyld_get_image_header(uint32_t image_index);
- const char* _dyld_get_image_name(uint32_t image_index);
- kern_return_t vm_region_recurse_64(vm_map_read_t target_task, vm_address_t *address, vm_size_t *size, natural_t *nesting_depth, vm_region_recurse_info_t info, mach_msg_type_number_t *infoCnt)
- kern_return_t vm_region_64(vm_map_read_t target_task, vm_address_t *address, vm_size_t *size, vm_region_flavor_t flavor, vm_region_info_t info, mach_msg_type_number_t *infoCnt, mach_port_t *object_name);
- int proc_regionfilename(int pid, uint64_t address, void * buffer, uint32_t buffersize);
Example
+(BOOL)isJailbreakInjectExist { BOOL check = NO; integer_t task_info_out[TASK_DYLD_INFO_COUNT]; mach_msg_type_number_t task_info_outCnt = TASK_DYLD_INFO_COUNT; if(task_info(mach_task_self_, TASK_DYLD_INFO, task_info_out, &task_info_outCnt) == KERN_SUCCESS) { struct task_dyld_info dyld_info = *(struct task_dyld_info*)(void*)(task_info_out); struct dyld_all_image_infos* infos = (struct dyld_all_image_infos *) dyld_info.all_image_info_addr; struct dyld_uuid_info* pUuid_info = (struct dyld_uuid_info*) infos->uuidArray; for( int i = 0; i < infos->uuidArrayCount; i++, pUuid_info += 1) { const struct mach_header_64* mheader = (const struct mach_header_64*)pUuid_info->imageLoadAddress; if (mheader->filetype == MH_DYLIB) { if(mheader->magic == MH_MAGIC_64 && mheader->ncmds > 0) { void *loadCmd = (void*)(mheader + 1); struct segment_command_64 *sc = (struct segment_command_64 *)loadCmd; for (int index = 0; index < mheader->ncmds; ++index, sc = (struct segment_command_64*)((BYTE*)sc + sc->cmdsize)) { if (sc->cmd == LC_ID_DYLIB) { struct dylib_command *dc = (struct dylib_command *)sc; struct dylib dy = dc->dylib; const char *detectedDyld = (char*)dc + dy.name.offset; for (NSString *jbDyld in jbPatternDyld) { if([[NSString stringWithUTF8String:detectedDyld] containsString:jbDyld]) { NSLog(@"dyld2: %s", detectedDyld); check = YES; break; } } } } } } } } return check; }
Reference
https://knight.sc/reverse%20engineering/2019/04/15/detecting-task-modifications.html
https://www.romainthomas.fr/post/22-08-singpass-rasp-analysis/
https://gist.github.com/ddrccw/8412847#file-hello-h-L122
4-2. C System Library
- int dladdr(void *addr, Dl_info *info);
- void *dlopen(const char *filename, int flag);
- void *dlsym(void *handle, const char *symbol);
Example
-(NSArray *)jailbreakSymbols { NSArray *symbol = [NSArray arrayWithObjects: @"MSHookFunction", @"MSHookMessageEx", @"MSFindSymbol", @"MSGetImageByName", @"ZzBuildHook", @"DobbyHook", @"LHHookFunctions", nil]; return symbol; } ... NSArray *jbPatternSymbol = [[[XFJailbreakPattern alloc] init] jailbreakSymbols]; for (NSString *jbSymbol in jbPatternSymbol) { const char *jbSymbol2 = [jbSymbol cStringUsingEncoding:NSUTF8StringEncoding]; void* dlpoint = dlsym((void *)RTLD_DEFAULT, jbSymbol2); if(dlpoint != NULL) { return YES; //Detected Jailbroken } }
static void _check_image(const struct mach_header *header, intptr_t slide) { NSSet *dylibSet = [NSSet setWithObjects: @"/usr/lib/CepheiUI.framework/CepheiUI", @"/usr/lib/libsubstitute.dylib" @"/usr/lib/substitute-inserter.dylib", @"/usr/lib/substitute-loader.dylib", nil]; Dl_info info; if (dladdr(header, &info) == 0) { char *dlerro = dlerror(); if(dlerro == NULL && info.dli_fname != NULL) { NSString *libName = [NSString stringWithUTF8String:info.dli_fname]; if ([dylibSet containsObject:libName]) { return YES; //Detected Jailbroken } } return; } } bool hasHookedMethods(void) { bool ret = false; MethodsList = [[NSMutableArray alloc] init]; int classCount = 5; const char* classes[5] = { "NSFileManager", "UIApplication", "NSString", "NSData", "NSBundle", }; for(int i = 0; i < classCount; i++) { Class ourClass = objc_getClass(classes[i]); unsigned int methodCount = 0; Method *methods = class_copyMethodList(ourClass, &methodCount); for (unsigned int i = 0; i < methodCount; i++) { Method method = methods[i]; Dl_info image_info; if(dladdr(class_getMethodImplementation(ourClass, method_getName(method)), &image_info) != 0) { struct mach_header_64 *header = image_info.dli_fbase; if(header && header->magic == MH_MAGIC_64) { struct load_command *loadCmd = (struct load_command *) (header + 1); struct segment_command_64 *sc = (struct segment_command_64 *)loadCmd; for (int index = 0; index < header->ncmds; ++index, sc = (struct segment_command_64*)((char*)sc + sc->cmdsize)) { if(sc->cmd == LC_LOAD_DYLIB) { struct dylib_command *dc = (struct dylib_command *)sc; struct dylib dy = dc->dylib; const char *detectedDyld = (char*)dc + dy.name.offset; if(strcmp(detectedDyld, "/Library/Frameworks/CydiaSubstrate.framework/CydiaSubstrate") == 0) { NSString *func = [NSString stringWithFormat:@"%s %s", class_getName(ourClass), sel_getName(method_getName(method))]; [MethodsList addObject:func]; ret = true; } } } } } } } return ret; }
5. 커널 접근 탐지
- kern_return_t task_for_pid(mach_port_t parent, int pid, mach_port_t *task_out );
- kern_return_t host_get_special_port(host_priv_t host_priv, int node, int which, mach_port_t *port);
Example
bool hasKernelTaskPort(void) { mach_port_t kernel_task = MACH_PORT_NULL; kern_return_t ret = task_for_pid(mach_task_self(), 0, &kernel_task); if(ret == KERN_SUCCESS && MACH_PORT_VALID(kernel_task)) { kernelTaskPort = kernel_task; mach_port_deallocate(mach_task_self(), kernel_task); return true; } else { host_t host = mach_host_self(); ret = host_get_special_port(host, HOST_LOCAL_NODE, 4, &kernel_task); if(ret == KERN_SUCCESS && MACH_PORT_VALID(kernel_task)) { kernelTaskPort = kernel_task; mach_port_deallocate(mach_task_self(), kernel_task); return true; } mach_port_deallocate(mach_task_self(), host); } return false; } if(hasKernelTaskPort()) { return YES; //Detected Jailbroken }
6. 환경 탐지
- char ***_NSGetEnviron(void);
- char *getenv(const char *varname);
- extern char **environ;
- [[NSProcessInfo processInfo] environment];
Example
-(NSArray *)jailbreakEnvs { NSArray *env = [NSArray arrayWithObjects: @"JB_ROOT_PATH", @"_MSSafeMode", @"DYLD_INSERT_LIBRARIES", @"substitute", nil]; return env; } +(BOOL)isJailbreakInjectExist { BOOL check = NO; NSArray *jbPatternEnv = [[[XFJailbreakPattern alloc] init] jailbreakEnvs]; char ***envp = _NSGetEnviron(); if (envp) { char **env = *envp; while (*env) { for (NSString *jbEnv in jbPatternEnv) { if([[NSString stringWithUTF8String:*env] containsString:jbEnv]) { check = YES; } } env++; } } //Env Check2 extern char **environ; for(int i=0; environ[i]; i++) { for (NSString *jbEnv in jbPatternEnv) { if([[NSString stringWithUTF8String:environ[i]] containsString:jbEnv]) { check = YES; } } } return check; }
7. 루트 파일 시스템 쓰기 여부 / 리마운트 (iOS ~14.x)
rootless 탈옥 환경에서는 /usr/standalone/firmware 마운트된 Device 경로를 참고하여
/private/preboot/(UUID)에 접근해서 stat으로 파일 갯수 확인
- int statfs(const char *path, struct statfs *buf);
- int getmntinfo(struct statfs **mntbufp, int flags);
Example
bool hasRenamedRootFS(void) { struct statfs *st; int num_fs = getmntinfo(&st, MNT_NOWAIT); if(num_fs != 0) { for (int i = 0; i < num_fs; i++) { if(strstr(st[i].f_mntfromname, "com.apple.os.update-") != NULL) { return false; } if(strstr(st[i].f_mntfromname, "orig-fs") != NULL) { return true; } if(strcmp(st[i].f_mntfromname, "/dev/disk0s1s1") == 0) { if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"11.3")) return true; } } } return false; } static inline int SVC_statfs64(const char* path, struct statfs *buf) { int64_t flag = 0; __asm __volatile("mov x0, %0" :: "r" ((int64_t)SYS_statfs64)); //SYS_statfs64 __asm __volatile("mov x1, %0" :: "r" (path)); //path __asm __volatile("mov x2, %0" :: "r" (buf)); //struct statfs __asm __volatile("mov x16, %0" :: "r" ((int64_t)SYS_syscall)); //SYS_syscall __asm __volatile("svc #0x80"); //supervisor call __asm __volatile("mov %0, x0" : "=r" (flag)); return (int)flag; } bool hasRootFSmountedRW(void) { struct statfs rootfs; if(SVC_statfs64("/", &rootfs) == 0) { if(rootfs.f_flags & MNT_RDONLY) { return false; } } return true; }
8. 포트
- int bind(int sockfd, struct sockaddr *myaddr, socklen_t addrlen);
- int socket(int domain, int type, int protocol);
- SSH 포트: 22, 2222 | Frida 포트: 27042
Example
bool hasSSHAvailable(void) { int server_socket = socket(AF_INET, SOCK_STREAM, 0); if(server_socket == -1) { return false; } struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(22); server_addr.sin_addr.s_addr = htonl(INADDR_ANY); int status = bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)); if(status == 0) { close(server_socket); return false; } return true; }
9. 디버깅
- pid_t getppid(void);
- int sysctl(const int *name, u_int namelen, void *oldp, size_t *oldlenp, const void *newp, size_t newlen);
- long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
- int isatty(int fd);
- int ioctl(int fd, unsigned long request, …);
- kern_return_t task_get_exception_ports(task_t task, exception_mask_t exception_mask, exception_mask_array_t masks, mach_msg_type_number_t *masksCnt, exception_handler_array_t old_handlers, exception_behavior_array_t old_behaviors, exception_flavor_array_t old_flavors);
Example
bool hasDebuggerAttached(void) { bool ret = false; int mib[4]; struct kinfo_proc info; size_t info_size = sizeof(info); info.kp_proc.p_flag = 0; mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PID; mib[3] = getpid(); if (sysctl(mib, 4, &info, &info_size, NULL, 0) == 0) { int traceStatus = info.kp_proc.p_flag & P_TRACED; if(traceStatus != 0) ret = true; } int launchdPid = 1; if (getppid() != launchdPid) ret = true; if(isatty(STDERR_FILENO) != 0) ret = true; struct winsize ws; if (!ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws)) ret = true; mach_msg_type_number_t count = 0; exception_mask_t masks[EXC_TYPES_COUNT]; mach_port_t ports[EXC_TYPES_COUNT]; exception_behavior_t behaviors[EXC_TYPES_COUNT]; thread_state_flavor_t flavors[EXC_TYPES_COUNT]; exception_mask_t mask = EXC_MASK_ALL & ~(EXC_MASK_RESOURCE | EXC_MASK_GUARD); kern_return_t result = task_get_exception_ports(mach_task_self(), mask, masks, &count, ports, behaviors, flavors); if (result == KERN_SUCCESS) { for (mach_msg_type_number_t portIndex = 0; portIndex < count; portIndex++) { if (MACH_PORT_VALID(ports[portIndex])) { ret = true; } } } return ret; }
10. 코드 서명
- int fcntl(int fildes, int cmd, …); (cmd = F_ADDSIGS, F_CHECK_LV)
- int csops(pid_t pid, unsigned int ops, void *useraddr, size_t usersize); (ops = CS_OPS_MARKKILL)
Example
bool hasCodeSigningValidated(void) { bool ret = false; FILE* dyld_file = fopen("/usr/lib/dyld", "rb"); fsignatures_t siginfo; if(dyld_file != NULL) { uint8_t firstPage[4096]; if(fread(firstPage, 1, 4096, dyld_file) == 4096) { struct mach_header *mh = (struct mach_header*)firstPage; uint32_t cmd_count = mh->ncmds; struct load_command *cmds = (struct load_command*)((char*)firstPage+(sizeof(struct mach_header_64))); struct load_command *cmd = cmds; for (uint32_t i = 0; i < cmd_count; ++i) { if (cmd->cmd == LC_CODE_SIGNATURE) { const struct linkedit_data_command *sigcmd = (struct linkedit_data_command*) cmd; siginfo.fs_file_start = O_DIRECTORY; siginfo.fs_blob_start = malloc(sigcmd->datasize); siginfo.fs_blob_size = sigcmd->datasize; } cmd = (struct load_command*)(((char*)cmd)+cmd->cmdsize); } } } fclose(dyld_file); int dyld_fd = open("/usr/lib/dyld", O_RDONLY, 0); if(dyld_fd != -1) { int result = fcntl(dyld_fd, F_ADDSIGS, &siginfo); if(result == -1) { if(errno == EBADEXEC || errno == EPERM) { ret = true; } } } close(dyld_fd); return ret; }
Reference
https://lapcatsoftware.com/articles/hardened-runtime-xpc.html
https://www.synacktiv.com/sites/default/files/2021-10/2021_sthack_jailbreak.pdf
11. Mach 접근
- int sandbox_check(pid_t, const char *operation, int sandbox_filter_type, …);
(operation: mach-lookup) - kern_return_t bootstrap_check_in(mach_port_t bp, const name_t service_name, mach_port_t *sp);
- kern_return_t bootstrap_look_up(mach_port_t bp, const name_t service_name, mach_port_t *sp);
Reference
https://github.com/Lessica/shadow/blob/master/Shadow.dylib/hooks/mach.x#L3
https://github.com/Lessica/shadow/blob/master/Shadow.dylib/hooks/sandbox.x#L104
좋은 글 공유해주셔서 감사합니다.
현재 fcntl(F_ADDSIGS)를 사용해서 Dopamine jailbreak를 감지하려고 하는데요,
혹시 iphoneos 환경에서도 /usr/lib/dyld로 가능한 부분일까요?
공유해주신 예시 코드에서
siginfo.fs_file_start = O_DIRECTORY;
siginfo.fs_blob_start = malloc(sigcmd->datasize);
siginfo.fs_blob_size = sigcmd->datasize;
여기서 fs_file_start가 enum값인 O_DIRECTORY인 것은 어떤 의미이실까요?
그리고 fs_blob_start가 sigcmd->dataoff가 아니라 malloc으로 들어가는 이유를 알 수 있을까요?
안녕하세요!
저 코드는 많이 오래되어서 기억이 가물가물하긴한데 제가 잘못된 코드를 적어넣었을 가능성이 크고 작동될지는 잘 모르겠습니다 ㅠㅠ
대신에 도파민 탈옥을 감지하고 싶으시다면, /usr/lib 경로에 bindfs 형태로 마운트되었는지 아닌지 판단해서 탈옥감지해보는건 어떨까요?
답변 감사합니다!!