{"id":20149036,"url":"https://github.com/emergetools/simpledebugger","last_synced_at":"2025-04-09T20:02:53.105Z","repository":{"id":257825886,"uuid":"870764398","full_name":"EmergeTools/SimpleDebugger","owner":"EmergeTools","description":"A basic in-process debugger for iOS apps, set breakpoints and respond when they are hit.","archived":false,"fork":false,"pushed_at":"2025-03-05T21:27:00.000Z","size":25,"stargazers_count":11,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-09T20:02:33.526Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://www.emergetools.com","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/EmergeTools.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}},"created_at":"2024-10-10T16:13:55.000Z","updated_at":"2025-03-29T15:52:13.000Z","dependencies_parsed_at":"2025-03-05T22:25:31.051Z","dependency_job_id":"35115b58-bb16-49c1-8dce-41bcaea3b932","html_url":"https://github.com/EmergeTools/SimpleDebugger","commit_stats":null,"previous_names":["emergetools/simpledebugger"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EmergeTools%2FSimpleDebugger","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EmergeTools%2FSimpleDebugger/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EmergeTools%2FSimpleDebugger/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EmergeTools%2FSimpleDebugger/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/EmergeTools","download_url":"https://codeload.github.com/EmergeTools/SimpleDebugger/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248103865,"owners_count":21048245,"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":[],"created_at":"2024-11-13T22:40:56.336Z","updated_at":"2025-04-09T20:02:53.079Z","avatar_url":"https://github.com/EmergeTools.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🩺 SimpleDebugger\n\n[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FEmergeTools%2FSimpleDebugger%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/EmergeTools/SimpleDebugger)\n[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FEmergeTools%2FSimpleDebugger%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/EmergeTools/SimpleDebugger)\n\nA minimal demonstration of breakpoints in an iOS app debugger. It can be used for function hooking, like a very lightweight Frida. It’s mainly for demonstration/learning purposes, the entire implementation is less than 200 lines of code. Works on arm64 simulator and device.\n\n# Getting started\n\nCreate an instance of SimpleDebugger like so:\n\n```c++\nSimpleDebugger *debugger = new SimpleDebugger();\n```\n\n## Hook functions\n\nHook functions using the `hookFunction(void *originalFunc, void *newFunc)` method. The originalFunction must be at\nleast 5 instructions long, if not you will get undefined behavior.\n\nAfter the hook is added all calls to originalFunc will go to newFunc. Make sure the signature for newFunc exactly\nmatches originalFunc. Once a hook is added it is active for the lifetime of the process. There is not a way to\ncall the original function from the hooked function.\n\n## Set breakpoints\n\nSet breakpoints using the `setBreakpoint(vm_address_t address)` method. The provided address must be in the __TEXT/__text section (the memory region containing executable code).\n\nIf you set breakpoints without calling `startDebugging` lldb can handle these breakpoints instead, although continuing past a breakpoint will not automatically work in lldb for breakpoints set by SimpleDebugger. You can manually increment the program counter in lldb to continue.\n\n## Respond to breakpoints\n\nHandle a breakpoint being hit using the `setExceptionCallback` method. The provided callback takes two parameters, one is the CPU state and the other is a function that can be called to continue execution on the thread that hit the breakpoint. Call `startDebugging` to begin receiving events.\n\n## Example:\n\nThis example creates a debugger and adds one breakpoint.\n\n```c++\n#include \u003cSimpleDebugger.h\u003e\n\nvoid myFunction() { printf(\"Hello world\\n\"); }\n\nvoid breakpointCallback(arm_thread_state64_t state, std::function\u003cvoid()\u003e sendReply) {\n    printf(\"Got breakpoint with PC: 0x%llx\\n\", state.__pc);\n    sendReply();\n}\n\n__attribute__((constructor)) void example(void);\n__attribute__((constructor)) void setup() {\n  SimpleDebugger *debugger = new SimpleDebugger();\n  debugger-\u003esetExceptionCallback(breakpointCallback);\n  debugger-\u003esetBreakpoint((vm_address_t) \u0026myFunction);\n  // You must call start debugging to set up the exception server.\n  debugger-\u003estartDebugging();\n\n  // The breakpoint handler will run before myFunction\n  myFunction();\n}\n```\n\nThis example hooks the `gettimeofday` function:\n\n```c++\n#include \u003cSimpleDebugger.h\u003e\n\nSimpleDebugger *handler;\n\nint gettimeofday_new(struct timeval *t, void *a) {\n  t-\u003etv_sec = 1723532400;\n  t-\u003etv_usec = 0;\n  return 0;\n}\n\nvoid hookTime() {\n  handler = new SimpleDebugger();\n  handler-\u003ehookFunction((void *) \u0026gettimeofday, (void *) \u0026gettimeofday_new);\n}\n```\n\n# How it works\n\nSimpleDebugger overwrites instructions with a break instruction by modifying the vm protection of the memory address to be writeable. The original instruction is stored in a table and written back after the breakpoint is hit. Break instructions are handled with a mach exception server.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Femergetools%2Fsimpledebugger","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Femergetools%2Fsimpledebugger","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Femergetools%2Fsimpledebugger/lists"}