{"id":38135584,"url":"https://github.com/bieganski/asstrace","last_synced_at":"2026-01-16T22:41:14.791Z","repository":{"id":216776752,"uuid":"742287439","full_name":"bieganski/asstrace","owner":"bieganski","description":"A stateful strace-like - Linux syscall tampering-first strace-like tool.","archived":false,"fork":false,"pushed_at":"2025-05-08T17:40:53.000Z","size":340,"stargazers_count":16,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-08T17:48:02.714Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","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/bieganski.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":"2024-01-12T06:24:54.000Z","updated_at":"2025-05-08T17:40:56.000Z","dependencies_parsed_at":"2024-01-21T00:25:38.911Z","dependency_job_id":"ad551fc8-cfb6-48c2-b08e-8d2c46fe0b9a","html_url":"https://github.com/bieganski/asstrace","commit_stats":null,"previous_names":["bieganski/asstrace"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/bieganski/asstrace","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bieganski%2Fasstrace","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bieganski%2Fasstrace/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bieganski%2Fasstrace/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bieganski%2Fasstrace/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bieganski","download_url":"https://codeload.github.com/bieganski/asstrace/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bieganski%2Fasstrace/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28485621,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T11:59:17.896Z","status":"ssl_error","status_checked_at":"2026-01-16T11:55:55.838Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":"2026-01-16T22:41:14.554Z","updated_at":"2026-01-16T22:41:14.762Z","avatar_url":"https://github.com/bieganski.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# About\n`asstrace` stands for **a** **s**tateful **strace**-like - Linux syscall tampering-first `strace`-like tool.\n\nAs opposed to `strace`, `asstrace` alters binary behavior by being \"man in the middle\" of binary and operating system. If your goal is to understand why some black-box binary is not working as expected, then `strace` with all it's advanced features is the way to go.\n\n`asstrace` is designed to **provide a convenient way of altering binary behavior and sharing it to other people**.\n\nIt doesn't change the binary itself, but allows for manipulating behavior of system calls that the binary executes.\n`asstrace` is designed to work with `Linux`. Currently `x86` and `RISC-V` are supported.\n\n# Example use cases\n\n* legacy executable which source code is not available no longer works on modern workstations, as it assumes presence of some special files (sockets, device character special etc.). We can intercept all system calls touching that particular device and provide our own implementation that emulate the device (all the emulation is in user mode).\n\n* black-box executable does not work because inside a binary there are IP address and port hardcoded, that are no longer accessible as the service moved to a different server. We can intercept network system calls that try to access non-existing address, and change it so that the new address is used.\n\n* black-box executable does some computation, and as a result it creates a single output file. During computation it creates lots of meaningful temporary files, but unfortunately it deletes them all before output is produced. Using `asstrace` we can intercept all `unlink` system calls and cause them to do nothing. This way no temporary files get removed! [[go to example]](#unlink-example)\n\n# `unlink` example\n\nIn this example we run `gcc`, but prevent it from deleting temporary files.\n\nThe command used: `echo \"int main();\" | ./asstrace.py -q  -ex 'unlink:nop:msg=prevented {path} from deletion' -- gcc  -o a.out -x c -c -`\n\n![unlink example](jpg/unlink.png)\n\n\n# `pathsubst` example\n\nOften in order to get some functionality, we need to hook more than a single syscall. For such purpose `asstrace` defines concept of groups, available by `-g` CLI param.\nHere we use `pathsubst`, that hooks `open`, `openat`, `faccessat2` and `statx`.\n\nThe command used is `./asstrace.py -qq  -g 'pathsubst:old=zeros,new=abc' -- cat zeros`\n\n![pathsubst example](jpg/pathsubst.png)\n\n\n# `count_lines` example\n\nIn this example we manipulate `ls -1` command, so that for each regular file that it prints it will include metadata: number of lines.\n\nThe command used: `./asstrace.py -qq -x examples/count_lines.py ls -1`\n\n![count_lines example](jpg/count_lines.png)\n\nThe code of `write` syscall in `count_lines` example is slightly more complicated, thus not suitable for `--ex` as previously. Instead we have a Python file that can use `API` functionality:\n\n```py\n# examples/count_lines.py\n\nfrom pathlib import Path\nfrom asstrace import API\n\n# defining function called asstrace_X will make a hook for syscall named 'X'.\n# hook will be executed before each entry to 'X'.\ndef asstrace_write(fd, buf, num, *_):\n    if fd != 1:\n        # not interesting to use - we care about stdout only.\n        API.invoke_syscall_anyway() # jump to 'write' with default params\n        return\n    path = Path(API.ptrace_read_mem(buf, num)[:-1].decode(\"ascii\")) # strip '\\n' and decode from bytes\n    if not path.is_file():\n        # probably a directory - follow default execution path\n        API.invoke_syscall_anyway()\n        return\n    try:\n        num_lines = len(path.read_text().splitlines())\n    except UnicodeDecodeError:\n        # raw-bytes file - number of lines doesn't make sense for it.\n        API.invoke_syscall_anyway()\n        return\n    \n    # if we are here, it means that our file is regular, UTF-8, and has 'num_lines' lines.\n    # print it to stdout instead of default 'buf'.\n    res_str = f\"{path}({num_lines})\\n\"\n    print(res_str, end=\"\")\n\n    # 'ls -1' program will think that it has written 'len(res_str)' characters,\n    # as 'write' syscall returns number of characters really written (see 'man write').\n    return len(res_str)\n\n```\n\n# Few more examples\n\n```\n-ex 'open,openat:delay:time=0.5'        - invoke each 'open' and 'openat' syscall as usual, but sleep for 0.5s before each invocation\n-ex 'unlink:nop'                        - 'unlink' syscall will not have any effect. value '0' will be returned to userspace.\n-ex 'mmap:nop:ret=-1'                   - 'mmap' syscall will not have any effect. value '-1' will be returned to userspace (fault injection; see 'man mmap').\n-ex 'open:nop:ret=-1' -ex read:detach   - fail each open, detach on first read\n```\n\n# Verbose mode\n\nWhen invoking without `-q` or `-qq` params `asstrace.py` will print all syscalls executed to stderr, in similar manner as `strace` do (but without fancy beautifying):\n\n```bash\nm.bieganski@test:~/github/asstrace$ ./asstrace.py ls\nopenat(0xffffff9c, 0x7f4883e8d660, 0x80000, 0x0, 0x80000, 0x7f4883e8d660) = 0x3\nread(0x3, 0x7ffd70b6e9b8, 0x340, 0x0, 0x80000, 0x7f4883e8d660) = 0x340\npread64(0x3, 0x7ffd70b6e5c0, 0x310, 0x40, 0x7ffd70b6e5c0, 0x7f4883e8d660) = 0x310\npread64(0x3, 0x7ffd70b6e580, 0x30, 0x350, 0x7ffd70b6e5c0, 0x0) = 0x30\npread64(0x3, 0x7ffd70b6e530, 0x44, 0x380, 0x7ffd70b6e5c0, 0x0) = 0x44\nnewfstatat(0x3, 0x7f4883ebdee9, 0x7ffd70b6e850, 0x1000, 0x7f4883e8d660, 0x7f4883eca2e0) = 0x0\npread64(0x3, 0x7ffd70b6e490, 0x310, 0x40, 0xc0ff, 0x7f4883e8db08) = 0x310\nmmap(0x0, 0x228e50, 0x1, 0x802, 0x3, 0x0) = 0x7f4883c00000\nmprotect(0x7f4883c28000, 0x1ee000, 0x0, 0x802, 0x3, 0x0) = 0x0\n...\n```\n\n\n# User Guide\n\nSee [user guide](./USER_GUIDE.md) for more details.\n\n# Distribution\n\n* MIT license\n* to make `asstrace` run on your Linux only a single file is needed (`asstrace.py`)*\n* no external Python dependencies - no need for `requirements.txt` etc.\n* no native code - only CPython interpreter is required\n* cross platform - adding a new target is as simple as defining CPU ABI:\n\n```py\n    CPU_Arch.riscv64: CPU_ABI(\n        user_regs_struct_type=riscv64_user_regs_struct,\n        syscall_args_registers_ordered=[f\"a{i}\" for i in range(6)],\n        syscall_number=\"a7\",\n        syscall_ret_val=\"a0\",\n        syscall_ret_addr=\"ra\",\n        pc=\"pc\",\n    )\n```\n\n* the `*` gotcha is that it needs additionaly `syscall_names.csv`. It either seeks it locally (will fork if obtained `asstrace` via `git clone`) or downloads directly from GitHub (url is hardcoded in `asstrace.py`).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbieganski%2Fasstrace","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbieganski%2Fasstrace","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbieganski%2Fasstrace/lists"}