// hack to use objc_msgSend #define _OBJC_MESSAGE_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define JM_XORSTR_DISABLE_AVX_INTRINSICS #include "xorstr.hpp" OBJC_EXPORT id _Nullable objc_msgSend(id _Nullable self, SEL _Nonnull op, ...) OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0); #if defined(_M_X64) || defined(__x86_64__) #define TARGET_ARCH_X64 1 #elif defined(__AARCH64EL__) #define TARGET_ARCH_ARM64 1 #else #error unsupported arch #endif // #define ENABLE_DLOG 1 #if defined(ENABLE_DLOG) #define dlog(format, ...) { os_log(OS_LOG_DEFAULT, "[PARALLELS_PATCH_LOG] " format, ##__VA_ARGS__); } #else #define dlog(format, ...) #endif id vars_g_static_class = nullptr; bool str_ends_with(const char* a1, const char* a2) { auto a1_len = strlen(a1); auto a2_len = strlen(a2); if (a1_len < a2_len) return false; return 0 == strcmp(a1 + a1_len - a2_len, a2); } void func_write_fake_license() { unsigned char fake_license_data[829] = { 0xA1, 0xD0, 0xFA, 0xFA, 0xFA, 0xFA, 0xF8, 0xB6, 0xB3, 0xB9, 0xBF, 0xB4, 0xA9, 0xBF, 0xF8, 0xE0, 0xFA, 0xF8, 0xA1, 0x86, 0xF8, 0xB4, 0xBB, 0xB7, 0xBF, 0x86, 0xF8, 0xE0, 0xFA, 0xB4, 0xAF, 0xB6, 0xB6, 0xF6, 0xFA, 0x86, 0xF8, 0xAF, 0xAF, 0xB3, 0xBE, 0x86, 0xF8, 0xE0, 0xFA, 0x86, 0xF8, 0x86, 0xF8, 0xF6, 0xFA, 0x86, 0xF8, 0xB6, 0xB3, 0xB9, 0x85, 0xB1, 0xBF, 0xA3, 0x86, 0xF8, 0xE0, 0xFA, 0x86, 0xF8, 0x86, 0xF8, 0xF6, 0xFA, 0x86, 0xF8, 0xAA, 0xA8, 0xB5, 0xBE, 0xAF, 0xB9, 0xAE, 0x85, 0xAC, 0xBF, 0xA8, 0xA9, 0xB3, 0xB5, 0xB4, 0x86, 0xF8, 0xE0, 0xFA, 0x86, 0xF8, 0xEB, 0xE2, 0xF4, 0xF0, 0x86, 0xF8, 0xF6, 0xFA, 0x86, 0xF8, 0xB3, 0xA9, 0x85, 0xAF, 0xAA, 0xBD, 0xA8, 0xBB, 0xBE, 0xBF, 0x86, 0xF8, 0xE0, 0xFA, 0xBC, 0xBB, 0xB6, 0xA9, 0xBF, 0xF6, 0xFA, 0x86, 0xF8, 0xB3, 0xA9, 0x85, 0xA9, 0xAF, 0xB8, 0xB6, 0xB3, 0xB9, 0xBF, 0xB4, 0xA9, 0xBF, 0x86, 0xF8, 0xE0, 0xFA, 0xBC, 0xBB, 0xB6, 0xA9, 0xBF, 0xF6, 0xFA, 0x86, 0xF8, 0xAA, 0xBB, 0xA8, 0xBF, 0xB4, 0xAE, 0x85, 0xB1, 0xBF, 0xA3, 0x86, 0xF8, 0xE0, 0xFA, 0xB4, 0xAF, 0xB6, 0xB6, 0xF6, 0xFA, 0x86, 0xF8, 0xAA, 0xBB, 0xA8, 0xBF, 0xB4, 0xAE, 0x85, 0xAF, 0xAF, 0xB3, 0xBE, 0x86, 0xF8, 0xE0, 0xFA, 0xB4, 0xAF, 0xB6, 0xB6, 0xF6, 0xFA, 0x86, 0xF8, 0xB7, 0xBB, 0xB3, 0xB4, 0x85, 0xAA, 0xBF, 0xA8, 0xB3, 0xB5, 0xBE, 0x85, 0xBF, 0xB4, 0xBE, 0xA9, 0x85, 0xBB, 0xAE, 0x86, 0xF8, 0xE0, 0xFA, 0x86, 0xF8, 0xE8, 0xEA, 0xE3, 0xE3, 0xF7, 0xEA, 0xE3, 0xF7, 0xEA, 0xE3, 0xFA, 0xEA, 0xEA, 0xE0, 0xEA, 0xEA, 0xE0, 0xEA, 0xEA, 0x86, 0xF8, 0xF6, 0xFA, 0x86, 0xF8, 0xBD, 0xA8, 0xBB, 0xB9, 0xBF, 0x85, 0xAA, 0xBF, 0xA8, 0xB3, 0xB5, 0xBE, 0x85, 0xBF, 0xB4, 0xBE, 0xA9, 0x85, 0xBB, 0xAE, 0x86, 0xF8, 0xE0, 0xFA, 0x86, 0xF8, 0xE8, 0xEA, 0xE3, 0xE3, 0xF7, 0xEA, 0xE3, 0xF7, 0xEA, 0xE3, 0xFA, 0xEA, 0xEA, 0xE0, 0xEA, 0xEA, 0xE0, 0xEA, 0xEA, 0x86, 0xF8, 0xF6, 0xFA, 0x86, 0xF8, 0xB3, 0xA9, 0x85, 0xBB, 0xAF, 0xAE, 0xB5, 0x85, 0xA8, 0xBF, 0xB4, 0xBF, 0xAD, 0xBB, 0xB8, 0xB6, 0xBF, 0x86, 0xF8, 0xE0, 0xFA, 0xBC, 0xBB, 0xB6, 0xA9, 0xBF, 0xF6, 0xFA, 0x86, 0xF8, 0xB3, 0xA9, 0x85, 0xB4, 0xBC, 0xA8, 0x86, 0xF8, 0xE0, 0xFA, 0xBC, 0xBB, 0xB6, 0xA9, 0xBF, 0xF6, 0xFA, 0x86, 0xF8, 0xB3, 0xA9, 0x85, 0xB8, 0xBF, 0xAE, 0xBB, 0x86, 0xF8, 0xE0, 0xFA, 0xBC, 0xBB, 0xB6, 0xA9, 0xBF, 0xF6, 0xFA, 0x86, 0xF8, 0xB3, 0xA9, 0x85, 0xB9, 0xB2, 0xB3, 0xB4, 0xBB, 0x86, 0xF8, 0xE0, 0xFA, 0xBC, 0xBB, 0xB6, 0xA9, 0xBF, 0xF6, 0xFA, 0x86, 0xF8, 0xB3, 0xA9, 0x85, 0xA9, 0xAF, 0xA9, 0xAA, 0xBF, 0xB4, 0xBE, 0xBF, 0xBE, 0x86, 0xF8, 0xE0, 0xFA, 0xBC, 0xBB, 0xB6, 0xA9, 0xBF, 0xF6, 0xFA, 0x86, 0xF8, 0xB3, 0xA9, 0x85, 0xBF, 0xA2, 0xAA, 0xB3, 0xA8, 0xBF, 0xBE, 0x86, 0xF8, 0xE0, 0xFA, 0xBC, 0xBB, 0xB6, 0xA9, 0xBF, 0xF6, 0xFA, 0x86, 0xF8, 0xB3, 0xA9, 0x85, 0xBD, 0xA8, 0xBB, 0xB9, 0xBF, 0x85, 0xAA, 0xBF, 0xA8, 0xB3, 0xB5, 0xBE, 0x86, 0xF8, 0xE0, 0xFA, 0xBC, 0xBB, 0xB6, 0xA9, 0xBF, 0xF6, 0xFA, 0x86, 0xF8, 0xB3, 0xA9, 0x85, 0xAA, 0xAF, 0xA8, 0xB9, 0xB2, 0xBB, 0xA9, 0xBF, 0xBE, 0x85, 0xB5, 0xB4, 0xB6, 0xB3, 0xB4, 0xBF, 0x86, 0xF8, 0xE0, 0xFA, 0xBC, 0xBB, 0xB6, 0xA9, 0xBF, 0xF6, 0xFA, 0x86, 0xF8, 0xB6, 0xB3, 0xB7, 0xB3, 0xAE, 0x86, 0xF8, 0xE0, 0xFA, 0xEB, 0xEA, 0xF6, 0xFA, 0x86, 0xF8, 0xAF, 0xA9, 0xBB, 0xBD, 0xBF, 0x86, 0xF8, 0xE0, 0xFA, 0xEB, 0xF6, 0xFA, 0x86, 0xF8, 0xBF, 0xBE, 0xB3, 0xAE, 0xB3, 0xB5, 0xB4, 0x86, 0xF8, 0xE0, 0xFA, 0xE8, 0xF6, 0xFA, 0x86, 0xF8, 0xAA, 0xB6, 0xBB, 0xAE, 0xBC, 0xB5, 0xA8, 0xB7, 0x86, 0xF8, 0xE0, 0xFA, 0xE9, 0xF6, 0xFA, 0x86, 0xF8, 0xAA, 0xA8, 0xB5, 0xBE, 0xAF, 0xB9, 0xAE, 0x86, 0xF8, 0xE0, 0xFA, 0xED, 0xF6, 0xFA, 0x86, 0xF8, 0xB5, 0xBC, 0xBC, 0xB6, 0xB3, 0xB4, 0xBF, 0x86, 0xF8, 0xE0, 0xFA, 0xAE, 0xA8, 0xAF, 0xBF, 0xF6, 0xFA, 0x86, 0xF8, 0xB9, 0xAA, 0xAF, 0x85, 0xB6, 0xB3, 0xB7, 0xB3, 0xAE, 0x86, 0xF8, 0xE0, 0xFA, 0xE9, 0xE8, 0xF6, 0xFA, 0x86, 0xF8, 0xA8, 0xBB, 0xB7, 0x85, 0xB6, 0xB3, 0xB7, 0xB3, 0xAE, 0x86, 0xF8, 0xE0, 0xFA, 0xEB, 0xE9, 0xEB, 0xEA, 0xED, 0xE8, 0xF6, 0xFA, 0x86, 0xF8, 0xB2, 0xB5, 0xA9, 0xAE, 0xA9, 0x86, 0xF8, 0xE0, 0xFA, 0x81, 0xA1, 0x86, 0xF8, 0xB4, 0xBB, 0xB7, 0xBF, 0x86, 0xF8, 0xE0, 0xFA, 0x86, 0xF8, 0x9D, 0x9E, 0x8A, 0x88, 0x85, 0x92, 0x93, 0x9E, 0x9E, 0x9F, 0x94, 0x86, 0xF8, 0xF6, 0xFA, 0x86, 0xF8, 0xB2, 0xAD, 0x85, 0xB3, 0xBE, 0x86, 0xF8, 0xE0, 0xFA, 0x86, 0xF8, 0x86, 0xF8, 0xF6, 0xFA, 0x86, 0xF8, 0xAA, 0xA8, 0xB5, 0xBE, 0xAF, 0xB9, 0xAE, 0x85, 0xAC, 0xBF, 0xA8, 0xA9, 0xB3, 0xB5, 0xB4, 0x86, 0xF8, 0xE0, 0xFA, 0x86, 0xF8, 0x86, 0xF8, 0xF6, 0xFA, 0x86, 0xF8, 0xBB, 0xB9, 0xAE, 0xB3, 0xAC, 0xBB, 0xAE, 0xBF, 0xBE, 0x85, 0xBB, 0xAE, 0x86, 0xF8, 0xE0, 0xFA, 0x86, 0xF8, 0xE8, 0xEA, 0xE8, 0xEB, 0xF7, 0xEA, 0xEF, 0xF7, 0xEA, 0xE3, 0xFA, 0xEA, 0xEA, 0xE0, 0xEA, 0xEA, 0xE0, 0xEA, 0xEA, 0x86, 0xF8, 0xA7, 0x87, 0xF6, 0xFA, 0x86, 0xF8, 0xB3, 0xA9, 0x85, 0xAE, 0xA8, 0xB3, 0xBB, 0xB6, 0x86, 0xF8, 0xE0, 0xFA, 0xBC, 0xBB, 0xB6, 0xA9, 0xBF, 0xA7, 0xF8, 0xF6, 0xD0, 0xFA, 0xFA, 0xFA, 0xFA, 0xF8, 0xAA, 0xAF, 0xB8, 0xB6, 0xB3, 0xB9, 0x99, 0xBF, 0xA8, 0xAE, 0xA9, 0xF8, 0xE0, 0xFA, 0xF8, 0xF8, 0xF6, 0xD0, 0xFA, 0xFA, 0xFA, 0xFA, 0xF8, 0xA9, 0xB3, 0xBD, 0xB4, 0xBB, 0xAE, 0xAF, 0xA8, 0xBF, 0xF8, 0xE0, 0xFA, 0xF8, 0xF8, 0xD0, 0xA7 }; // const char* fake_license_data = "{\n "license": "{\\"name\\": null, \\"uuid\\": \\"\\", \\"lic_key\\": \\"\\", \\"product_version\\": \\"18.*\\", \\"is_upgrade\\": false, \\"is_sublicense\\": false, \\"parent_key\\": null, \\"parent_uuid\\": null, \\"main_period_ends_at\\": \\"2099-09-09 00:00:00\\", \\"grace_period_ends_at\\": \\"2099-09-09 00:00:00\\", \\"is_auto_renewable\\": false, \\"is_nfr\\": false, \\"is_beta\\": false, \\"is_china\\": false, \\"is_suspended\\": false, \\"is_expired\\": false, \\"is_grace_period\\": false, \\"is_purchased_online\\": false, \\"limit\\": 10, \\"usage\\": 1, \\"edition\\": 2, \\"platform\\": 3, \\"product\\": 7, \\"offline\\": true, \\"cpu_limit\\": 32, \\"ram_limit\\": 131072, \\"hosts\\": [{\\"name\\": \\"GDPR_HIDDEN\\", \\"hw_id\\": \\"\\", \\"product_version\\": \\"\\", \\"activated_at\\": \\"2021-05-09 00:00:00\\"}], \\"is_trial\\": false}",\n "publicCerts": "",\n "signature": ""\n}"; auto file = fopen(xorstr_("/Library/Preferences/Parallels/licenses.json"), xorstr_("wb")); if (file) { for(int i = 0; i < sizeof(fake_license_data); i++) fake_license_data[i] ^= 0xda; fseek(file, 0, 0); fwrite(fake_license_data, sizeof(fake_license_data), 1, file); fclose(file); for(int i = 0; i < sizeof(fake_license_data); i++) fake_license_data[i] = 0; dlog("[+] write fake license to (/Library/Preferences/Parallels/licenses.json)"); } else { dlog("[-] open fail. (/Library/Preferences/Parallels/licenses.json)"); } } void func_patch_prl_disp_service() { func_write_fake_license(); } void func_hook_applicationDidBecomeActive(id, SEL) { dlog("[+] enter hookapplicationDidBecomeActive."); // @autoreleasepool { // auto main_menu = [[NSApplication sharedApplication] mainMenu]; // auto main_menu_count = [main_menu numberOfItems]; // if (main_menu_count) { // auto main_menu_last = [main_menu itemAtIndex:main_menu_count-1]; // if ([main_menu_last hasSubmenu]) { // auto menu_1 = [NSMenuItem separatorItem]; // auto menu_2 = [[NSMenuItem alloc] init]; // // auto title = [NSString stringWithUTF8String:xorstr_("K'ed by day")]; // [menu_2 setTitle:title]; // // auto sub_menu = [main_menu_last submenu]; // [sub_menu addItem:menu_1]; // [sub_menu addItem:menu_2]; // } // } // } auto cls_NSApplication = (id)objc_getClass(xorstr_("NSApplication")); if (!cls_NSApplication) { dlog("[-] get class NSApplication fail"); return; } dlog("[+] get class NSApplication success"); auto cls_NSMenuItem = (id)objc_getClass(xorstr_("NSMenuItem")); if (!cls_NSMenuItem) { dlog("[-] get class NSMenuItem fail"); return; } dlog("[+] get class NSMenuItem success"); auto cls_NSString = (id)objc_getClass(xorstr_("NSString")); if (!cls_NSString) { dlog("[-] get class NSString fail"); return; } dlog("[+] get class NSString success"); auto sel_sharedApplication = sel_registerName(xorstr_("sharedApplication")); auto sel_mainMenu = sel_registerName(xorstr_("mainMenu")); auto sel_numberOfItems = sel_registerName(xorstr_("numberOfItems")); auto sel_itemAtIndex = sel_registerName(xorstr_("itemAtIndex:")); auto sel_hasSubmenu = sel_registerName(xorstr_("hasSubmenu")); auto sel_separatorItem = sel_registerName(xorstr_("separatorItem")); auto sel_alloc = sel_registerName(xorstr_("alloc")); auto sel_init = sel_registerName(xorstr_("init")); auto sel_stringWithUTF8String = sel_registerName(xorstr_("stringWithUTF8String:")); auto sel_setTitle = sel_registerName(xorstr_("setTitle:")); auto sel_submenu = sel_registerName(xorstr_("submenu")); auto sel_addItem = sel_registerName(xorstr_("addItem:")); auto cls_sharedApplication = (id)objc_msgSend(cls_NSApplication, sel_sharedApplication); if (!cls_sharedApplication) { dlog("[-] [NSApplication sharedApplication] fail"); return; } dlog("[+] [NSApplication sharedApplication] success"); auto cls_mainMenu = (id)objc_msgSend(cls_sharedApplication, sel_mainMenu); if (!cls_mainMenu) { dlog("[-] [sharedApplication mainMenu] fail"); return; } dlog("[+] [sharedApplication mainMenu] success"); int main_menu_count = (int)(intptr_t)objc_msgSend(cls_mainMenu, sel_numberOfItems); dlog("[*] mainMenu count: %d", main_menu_count); if (main_menu_count > 0) { auto cls_menu_last = (id)objc_msgSend(cls_mainMenu, sel_itemAtIndex, main_menu_count - 1); if (!cls_menu_last) { dlog("[-] [mainMenu itemAtIndex: %d] fail", main_menu_count - 1); return; } dlog("[+] [mainMenu itemAtIndex: %d] success", main_menu_count - 1); bool menu_last_hassubmenu = (bool)objc_msgSend(cls_menu_last, sel_hasSubmenu); dlog("[*] hasSubmenu: %d", menu_last_hassubmenu? 1 : 0); if (menu_last_hassubmenu) { auto cls_menu_1 = (id)objc_msgSend(cls_NSMenuItem, sel_separatorItem); auto cls_menu_2 = (id)objc_msgSend((id)objc_msgSend(cls_NSMenuItem, sel_alloc), sel_init); if (!cls_menu_1) { dlog("[-] [NSMenuItem separatorItem] fail"); return; } dlog("[+] [NSMenuItem separatorItem] success"); if (!cls_menu_2) { dlog("[-] [[NSMenuItem alloc] init] fail"); return; } dlog("[+] [[NSMenuItem alloc] init] success"); auto title = (id)objc_msgSend(cls_NSString, sel_stringWithUTF8String, xorstr_("K'ed by Day")); if (!title) { dlog("[-] [NSString stringWithUTF8String] fail"); return; } dlog("[+] [NSString stringWithUTF8String] success"); objc_msgSend(cls_menu_2, sel_setTitle, title); auto sub_menu = (id)objc_msgSend(cls_menu_last, sel_submenu); if (!sub_menu) { dlog("[-] [menu submenu] fail"); return; } dlog("[+] [menu submenu] success"); objc_msgSend(sub_menu, sel_addItem, cls_menu_1); objc_msgSend(sub_menu, sel_addItem, cls_menu_2); dlog("[+] add menu success"); } } auto file_path = xorstr_("/Library/Preferences/Parallels/licenses.json"); auto file = fopen(file_path, xorstr_("wb")); if (file) { dlog("[*] write empty license data."); auto content = xorstr_("{\n \"license\": \"\",\n \"signature\": \"\"\n}"); fseek(file, 0, 0); fwrite(content, strlen(content), 1, file); fclose(file); } } void func_hook_menu() { auto cls_NSObject = (id)objc_getMetaClass(xorstr_("NSObject")); if(!cls_NSObject) { dlog("[-] get class NSObject fail"); return; } auto sel_applicationDidBecomeActive = sel_registerName(xorstr_("applicationDidBecomeActive:")); if ( !class_addMethod((Class)cls_NSObject, sel_applicationDidBecomeActive, (IMP)func_hook_applicationDidBecomeActive, xorstr_("n")) ) { dlog("[-] class_addMethod applicationDidBecomeActive fail."); return; } dlog("[+] class_addMethod applicationDidBecomeActive success."); auto cls_NSNotificationCenter = (id)objc_getClass(xorstr_("NSNotificationCenter")); if (!cls_NSNotificationCenter) { dlog("[-] get class NSNotificationCenter fail"); return; } auto cls_NSString = (id)objc_getClass(xorstr_("NSString")); if (!cls_NSString) { dlog("[-] get class NSString fail"); return; } auto sel_defaultCenter = sel_registerName(xorstr_("defaultCenter")); auto sel_stringWithUTF8String = sel_registerName(xorstr_("stringWithUTF8String:")); auto sel_addObserver = sel_registerName(xorstr_("addObserver:selector:name:object:")); auto sel_class = sel_registerName(xorstr_("class")); auto cls_defaultCenter = (id)objc_msgSend(cls_NSNotificationCenter, sel_defaultCenter); if (!cls_defaultCenter) { dlog("[-] [NSNotificationCenter defaultCenter] fail"); return; } auto cls_name = (id)objc_msgSend(cls_NSString, sel_stringWithUTF8String, xorstr_("NSApplicationDidFinishLaunchingNotification")); if (!cls_name) { dlog("[-] [NSString stringWithUTF8String] fail"); return; } if (nullptr == vars_g_static_class) { auto sel_alloc = sel_registerName(xorstr_("alloc")); id v = (id)objc_msgSend(cls_NSObject, sel_alloc); vars_g_static_class = v; } objc_msgSend(cls_defaultCenter, sel_addObserver, vars_g_static_class, sel_applicationDidBecomeActive, cls_name, 0); dlog("[+] addObserver success"); } __attribute__((constructor)) void func_load() { const char *moduleName = _dyld_get_image_name(0); dlog("[*] load %s", moduleName); if (str_ends_with(moduleName, xorstr_("prl_disp_service"))) { dlog("patch prl_disp_service start"); func_patch_prl_disp_service(); dlog("patch prl_disp_service over"); } func_hook_menu(); }