{"id":28436870,"url":"https://github.com/yoavst/ida-ios-helper","last_synced_at":"2025-06-27T20:32:03.305Z","repository":{"id":288479299,"uuid":"964696239","full_name":"yoavst/ida-ios-helper","owner":"yoavst","description":"Plugin to ease reversing iOS projects","archived":false,"fork":false,"pushed_at":"2025-06-12T15:36:19.000Z","size":233,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-12T16:46:31.268Z","etag":null,"topics":["ida-plugin","idapython","ios","kernelcache","objective-c"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yoavst.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-04-11T16:26:15.000Z","updated_at":"2025-06-12T15:36:23.000Z","dependencies_parsed_at":"2025-04-18T09:21:23.882Z","dependency_job_id":"b80f3376-6170-446a-b253-30429b6cebe1","html_url":"https://github.com/yoavst/ida-ios-helper","commit_stats":null,"previous_names":["yoavst/ida-objc-helper","yoavst/ida-ios-helper"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/yoavst/ida-ios-helper","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yoavst%2Fida-ios-helper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yoavst%2Fida-ios-helper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yoavst%2Fida-ios-helper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yoavst%2Fida-ios-helper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yoavst","download_url":"https://codeload.github.com/yoavst/ida-ios-helper/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yoavst%2Fida-ios-helper/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262327280,"owners_count":23294243,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ida-plugin","idapython","ios","kernelcache","objective-c"],"created_at":"2025-06-05T23:07:48.311Z","updated_at":"2025-06-27T20:32:02.508Z","avatar_url":"https://github.com/yoavst.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# IDA iOS Helper\n\nA plugin for IDA Pro 9.0+ to help with iOS code analysis.\n\n## Supported features\n\n- KernelCache\n    - Calls to `OSBaseClass::safeMetaCast` apply type info on the result.\n    - Calls to `OSObject_typed_operator_new` apply type info on the result.\n    - When the keyboard is on a virtual call (`cls-\u003evcall()`), Shift+X will show a dialog with all the possible\n      implementations of the virtual method. It requires vtable symbols to be present.\n    - When in a C++ method named Class::func, Ctrl+T will change the first argument to `Class* this`. Also works for\n      Obj-C instance methods.\n    - Name globals from `OSSymbol::fromConst*` calls, locals from `get/setProperty` calls, ...\n    - Rename and type all global kalloc_type_view. Use their signature to mark fields as pointers for the actual types.\n- Objective-C\n    - Hide memory management\n      functions - `objc_retain`, `objc_release`, `objc_autorelease`, `objc_retainAutoreleasedReturnValue`.\n        - Optimize `_objc_storeStrong` to an assignment.\n    - collapse `__os_log_impl` calls.\n    - Hide selectors and static classes from Objective-c calls.\n    - When in Obj-C method, Ctrl+4 will show xrefs to the selector.\n- Common\n    - Remove `__break` calls.\n    - collapse blocks initializers and detect `__block` variables (use Alt+Shift+S to trigger detection).\n    - Use `Ctrl+S` to jump to function by a string constant found in the code\n    - Helpful comments near ranged conditions\n    - Try to detect outline functions and mark them as such.\n\n## Installation\n\n1. clone the repo.\n2. symlink `src` folder into your IDA Pro plugins folder:\n    - on unix: `~/.idapro/plugins/`\n    - on windows: `%APPDATA%\\Hex-Rays\\IDA Pro\\plugins`. `mklink /d` command can be used to create a symlink.\n3. Restart IDA.\n\n## Examples\n\n### Solve condition constraints\n\nBefore:\n\n```c\nif ( valueLength - 21 \u003c= 0xFFFFFFFFFFFFFFEFLL ) \n{ \n  ... \n}\n```\n\nAfter:\n\n```c\nif ( valueLength - 21 \u003c= 0xFFFFFFFFFFFFFFEFLL )// 4 \u003c valueLength \u003c 21\n{\n  ...\n}\n```\n\n### Remove `__break`\n\nBefore:\n\n```c\n    if ( ((v6 ^ (2 * v6)) \u0026 0x4000000000000000LL) != 0 )\n      __break(0xC471u);\n```\n\nAfter: removed.\n\n### Hide selectors of Obj-C calls\n\nBefore:\n\n```c\n   -[NSFileManager removeItemAtPath:error:](\n      +[NSFileManager defaultManager](\u0026OBJC_CLASS___NSFileManager, \"defaultManager\"),\n      \"removeItemAtPath:error:\",\n      +[NSString stringWithUTF8String:](\u0026OBJC_CLASS___NSString, \"stringWithUTF8String:\", *(_QWORD *)\u0026buf[v5]),\n      0LL);\n```\n\nAfter:\n\n```c\n   -[NSFileManager removeItemAtPath:error:](\n      +[NSFileManager defaultManager](),\n      +[NSString stringWithUTF8String:](*(_QWORD *)\u0026buf[v5]),\n      0LL);\n```\n\n### Block initializers\n\nBefore:\n\n```c\nv10 = 0LL;\nv15 = \u0026v10;\nv16 = 0x2000000000LL;\nv17 = 0;\nif ( a1 )\n{\n  x0_8 = *(NSObject **)(a1 + 16);\n  v13.isa = _NSConcreteStackBlock;\n  *(_QWORD *)\u0026v13.flags = 0x40000000LL;\n  v13.invoke = func_name_block_invoke;\n  v13.descriptor = \u0026stru_100211F48;\n  v13.lvar3 = a1;\n  v13.lvar4 = a2;\n  v13.lvar1 = a3;\n  v13.lvar2 = \u0026v10;\n  dispatch_sync(queue: x0_8, block: \u0026v13);\n  v11 = *((_BYTE *)v15 + 24);\n}\nelse\n{\n  v11 = 0;\n}\n_Block_object_dispose(\u0026v10, 8);\nreturn v11 \u0026 1;\n```\n\nAfter:\n\n```c\nv10 = _byref_block_arg_init(0);\nv10.value = 0;\nif ( a1 )\n{\n  v6 = *(NSObject **)(a1 + 16);\n  v9 = _stack_block_init(0x40000000, \u0026stru_100211F48, func_name_block_invoke);\n  v9.lvar3 = a1;\n  v9.lvar4 = a2;\n  v9.lvar1 = a3;\n  v9.lvar2 = \u0026v10;\n  dispatch_sync(queue: v6, block: \u0026v9);\n  value = v10.forwarding-\u003evalue;\n}\nelse\n{\n  value = 0;\n}\nreturn value \u0026 1;\n```\n\n### Collapse `os_log`\n\nBefore:\n\n```c\n  v9 = gLogObjects;\n  v10 = gNumLogObjects;\n  if ( gLogObjects \u0026\u0026 gNumLogObjects \u003e= 46 )\n  {\n    v11 = *(NSObject **)(gLogObjects + 360);\n  }\n  else\n  {\n    v11 = (NSObject *)\u0026_os_log_default;\n    if ( ((v6 ^ (2 * v6)) \u0026 0x4000000000000000LL) != 0 )\n      __break(0xC471u);\n    if ( os_log_type_enabled(oslog: (os_log_t)\u0026_os_log_default, type: OS_LOG_TYPE_ERROR) )\n    {\n      *(_DWORD *)buf = 134218240;\n      *(_QWORD *)v54 = v9;\n      *(_WORD *)\u0026v54[8] = 1024;\n      *(_DWORD *)\u0026v54[10] = v10;\n      if ( ((v6 ^ (2 * v6)) \u0026 0x4000000000000000LL) != 0 )\n        __break(0xC471u);\n      _os_log_error_impl(\n        dso: (void *)\u0026_mh_execute_header,\n        log: (os_log_t)\u0026_os_log_default,\n        type: OS_LOG_TYPE_ERROR,\n        format: \"Make sure you have called init_logging()!\\ngLogObjects: %p, gNumLogObjects: %d\",\n        buf: buf,\n        size: 0x12u);\n    }\n  }\n  if ( ((v6 ^ (2 * v6)) \u0026 0x4000000000000000LL) != 0 )\n    __break(0xC471u);\n  if ( os_log_type_enabled(oslog: v11, type: OS_LOG_TYPE_INFO) )\n  {\n    if ( a1 )\n      v12 = *(_QWORD *)(a1 + 8);\n    else\n      v12 = 0LL;\n    *(_DWORD *)buf = 138412290;\n    *(_QWORD *)v54 = v12;\n    if ( ((v6 ^ (2 * v6)) \u0026 0x4000000000000000LL) != 0 )\n      __break(0xC471u);\n    _os_log_impl(\n      dso: (void *)\u0026_mh_execute_header,\n      log: v11,\n      type: OS_LOG_TYPE_INFO,\n      format: \"Random log %@\",\n      buf: buf,\n      size: 0xCu);\n  }\n```\n\nafter:\n\n```c\n  if ( oslog_info_enabled() )\n  {\n    if ( a1 )\n      v4 = *(_QWORD *)(a1 + 8);\n    else\n      v4 = 0LL;\n    oslog_info(\"Random log %@\", v4);\n  }\n```\n\n## Automatic casts with `OSBaseClass::safeMetaCast`\n\nBefore:\n\n```c++\n OSObject *v5;\n v5 = OSBaseClass::safeMetaCast(a2, \u0026IOThunderboltController::metaClass);\n```\n\nAfter:\n\n```c++\n IOThunderboltController *v5;\n v5 = OSDynamicCast\u003cIOThunderboltController\u003e(a2);\n```\n\n## Automatic typing for `OSObject_typed_operator_new`\nRun `Edit-\u003ePlugins-\u003eiOSHelper-\u003eLocate all kalloc_type_view` before.\n\nBefore:\n```c++\nIOAccessoryPowerSourceItemUSB_TypeC_Current *sub_FFFFFFF009B2AA14()\n{\n  OSObject *v0; // x19\n\n  v0 = (OSObject *)OSObject_typed_operator_new(\u0026UNK_FFFFFFF007DBC480, size: 0x38uLL);\n  OSObject::OSObject(this: v0, \u0026IOAccessoryPowerSourceItemUSB_TypeC_Current::gMetaclass)-\u003e__vftable = (OSObject_vtbl *)off_FFFFFFF007D941B0;\n  OSMetaClass::instanceConstructed(this: \u0026IOAccessoryPowerSourceItemUSB_TypeC_Current::gMetaclass);\n  return (IOAccessoryPowerSourceItemUSB_TypeC_Current *)v0;\n}\n```\n\nAfter:\n```c++\nIOAccessoryPowerSourceItemUSB_TypeC_Current *sub_FFFFFFF009B2AA14()\n{\n  IOAccessoryPowerSourceItemUSB_TypeC_Current *v0; // x19\n\n  v0 = OSObjectTypeAlloc\u003cIOAccessoryPowerSourceItemUSB_TypeC_Current\u003e(0x38uLL);\n  OSObject::OSObject(this: v0, \u0026IOAccessoryPowerSourceItemUSB_TypeC_Current::gMetaclass)-\u003e__vftable = (OSObject_vtbl *)off_FFFFFFF007D941B0;\n  OSMetaClass::instanceConstructed(this: \u0026IOAccessoryPowerSourceItemUSB_TypeC_Current::gMetaclass);\n  return v0;\n}\n```\n\n## Jump to virtual call\n\nUse `Shift+X` on a virtual call to jump.\n\n![Jump to virtual call](res/jump_to_virtual_call.png)\n\n## Xrefs to selector\n\nUse `Ctrl+4` inside an Objective-C method to list xrefs to its selector.\n\n![Jump to selector](res/jump_to_selector_xrefs.png)\n\n## Development\n\nIn order to have autocomplete while developing, you need to add IDA's include folder ( `$IDA_INSTALLATION/python/3` ) to\nyour IDE.\n\n- on Visual Studio code you can add the folder to the analyzer's extra paths in the `settings.json` file:\n\n```json\n{\n  \"python.analysis.extraPaths\": [\n    \"$IDA_INSTALLATION\\\\python\\\\3\"\n  ]\n}\n```\n\n- on PyCharm you can add the folder to the interpreter's paths in the project settings.\n  Alternatively, you can create `idapython.pth` in `$VENV_FOLDER/Lib/site-packages` and add the path to it.\n\nInside IDA, you can use `ioshelper.reload()` to reload the plugin during development.\nIf you create file name `DEBUG` inside `src/`, then you can use `F2` to reload the\nplugin.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyoavst%2Fida-ios-helper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyoavst%2Fida-ios-helper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyoavst%2Fida-ios-helper/lists"}