{"id":23419459,"url":"https://github.com/bannsec/pysym","last_synced_at":"2026-03-08T16:05:04.023Z","repository":{"id":43576087,"uuid":"53240762","full_name":"bannsec/pySym","owner":"bannsec","description":"Python Symbolic Execution","archived":false,"fork":false,"pushed_at":"2019-08-03T00:23:57.000Z","size":56102,"stargazers_count":67,"open_issues_count":1,"forks_count":12,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-03-26T07:22:58.114Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bannsec.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-03-06T06:15:09.000Z","updated_at":"2025-03-21T01:53:38.000Z","dependencies_parsed_at":"2022-08-29T21:11:11.087Z","dependency_job_id":null,"html_url":"https://github.com/bannsec/pySym","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bannsec%2FpySym","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bannsec%2FpySym/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bannsec%2FpySym/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bannsec%2FpySym/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bannsec","download_url":"https://codeload.github.com/bannsec/pySym/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248570271,"owners_count":21126393,"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-12-23T01:18:02.161Z","updated_at":"2026-03-08T16:05:03.978Z","avatar_url":"https://github.com/bannsec.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# pySym\nPython Symbolic Execution\n\n[![Build Status](https://travis-ci.org/bannsec/pySym.svg?branch=master)](https://travis-ci.org/bannsec/pySym)\n[![Coverage Status](https://coveralls.io/repos/github/Owlz/pySym/badge.svg?branch=HEAD)](https://coveralls.io/github/Owlz/pySym?branch=HEAD)\n[![Documentation Status](https://readthedocs.org/projects/pysym/badge/?version=latest)](http://pysym.readthedocs.org/en/latest/?badge=latest)\n\n# Disclaimer\nWhile I'm still using this as a test ground to learn, the script itself has at least gotten somewhat useful. Feel free to let me know if you find things that aren't right. For now, it will do very basic things. For loops, while loops, List Comprehensions, arithmetic, booleans, etc. If you start wondering into a lot of built-in commands or methods, you probably will not have success.\n\nFor more information on what is and isn't implemented, check out WhatIsImplemented.md\n\nFor examples of what is possible, probably the best resource right now is the unit tests. I'll post more detailed examples later.\n\n# Docs\nPlease see my ReadTheDocs for the most updated documentation: http://pysym.readthedocs.org/en/latest\n\n# Install\n## Pypi\npySym is now structured as a python package. You can use pip to install it:\n\n```bash\n$ git clone https://github.com/bannsec/pySym.git \u0026\u0026 cd pySym\n$ (optional) virtualenv --python=$(which python3) pySym \u0026\u0026 . pySym/bin/activate\n(pySym)$ pip install .\n```\n\n## Docker\npySym has a docker build for easy install and use. Just do the following:\n\n```bash\n$ sudo docker pull bannsec/pysym\n$ sudo docker run -it --rm bannsec/pysym\n```\n\n# Tests\nJust open up your environment and run ``pytest`` from the root directory.\n\n```bash\n$ workon pySym\n(pySym)$ pytest\n```\n\n# Basic/Medium Example\nSince the first example, I've implemented more things. It's still very much in development, but you can do better things with it now. Here's an example program:\n\n```python\ndef test(x,y):\n    out = 2\n    while x \u003c y:\n        out *= x\n        x += 1\n\n    return out\n\nx = 0\nz = 0\nwhile x \u003c 5:\n    y = 0\n    while y \u003c 3:\n        z += test(x,y)\n        y += 1\n    x += 1\n```\n\nYou can use a path group to automagically walk through the program as follows. First, save that example as 'test.py'. Now, do the following:\n\n```python\nimport pySym\nproj = pySym.Project(\"./test.py\")\npg = proj.factory.path_group()\npg.explore()\n```\n\nThat will tell pySym to attempt to find all the paths through the program to completion. Once it completes, you can ask what the value of z was at completion.\n\n```python\nIn [4]: pg\nOut[4]: \u003cPathGroup with 45 deadended, 1 completed\u003e\n\nIn [5]: pg.completed[0].state.any_int('z')\nOut[5]: 26\n```\n\n# Basic Example\nA lot of the layout for pySym is shamelessly stolen from the `angr` project. If you're familiar with their calls, this will make sense to you.\n\nAs an example of what is currently working, take the following script:\n\n```python\nx = 1.5\ny = 1\nif x == 1:\n    y = 2\nelse:\n    y += x\n```\n\nWhile basic, it can show how stepping through a program works. The following python script excersizes this functionality:\n\n```python\nfrom pySym.pyPath import Path\nimport ast\nimport logging\nfrom pySym import Colorer\nlogging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')\n\nsource = \"\"\"\nx = 1.5\ny = 1\nif x == 1:\n    y = 2\nelse:\n    y += x\n\"\"\"\nb = ast.parse(source).body\np = Path(b,source=source)\np = p.step()[0]\np = p.step()[0]\nifSide,elseSide = p.step()\nelseSide = elseSide.step()[0]\n```\n\nNote that I put the source inline. It doens't have to be. You could read it from a file or really anywhere else that gives you a string. What happens in this script is the following:\n\nb = ast.parse(source).body -- This call parses out the mini script into functional blocks that we use.\n\np = Path(b,source=source) -- This sets up our initial path variable. For now, this starts at the top of the script and works its way down.\n\np = p.step()[0] -- These are stepping through the program. The path itself does not get modified. However, a copy of the path returns. Note on the third step we encounter an if statement that causes the path to branch into two (taking both).\n\nelseSide = elseSide.step()[0] -- Perform our final step, executing \"y += x\"\n\nWe can see if our given path is viable by checking path.state.isSat()\n\n```python\nIn [2]: ifSide.state.isSat()\nOut[2]: False\n\nIn [3]: elseSide.state.isSat()\nOut[3]: True\n```\n\nAs expected, the else is the only viable path through here. We can also ask what the variable should be at this point:\n\n```python\nIn [4]: elseSide.state.any_real('y')\nOut[4]: 2.5\n```\n\nAgain, nothing fancy but it does give us the value we would expect from this path. If we wanted to discover what this elsePath looked like from start to finish, we can ask that as well:\n\n```python\nIn [5]: elseSide.printBacktrace()\n Line 2  x = 1.5     \u003c_ast.Assign object at 0x7f9263f8a438\u003e    \n Line 3  y = 1       \u003c_ast.Assign object at 0x7f9263f8d080\u003e    \n Line 4  if x == 1:  \u003c_ast.If object at 0x7f926985b550\u003e        \n Line 7      y += x  \u003c_ast.AugAssign object at 0x7f9263f8d400\u003e \n```\n\nMuch work left to do as I have only implimented a limited set of operations. However, this is pretty neat!\n\n# To-Do\nHere's a list of things I have left to implement. This is really just a subset of things, but these are high on my list.\n\n* Due to needing loose matching, some expressions will likely fail to work as expected\n * Need to determine when this will happen\n* Fix explore find=. It's not working correctly\n* Create pyObjectManager.Dict\n* Create pyObjectManager.Set\n* Add automatic BitVector scaling\n * http://stackoverflow.com/questions/22568867/z3-bitvector-overflow-checking-from-python\n * http://stackoverflow.com/questions/14579377/z3py-how-to-extend-and-trunc-variables\n* ifelse inline (x = 1 if 1 \u003e 2 else 2)\n* function calls (mostly completed)\n * starargs\n* imports\n* \"global\" keyword\n* symbolic arrays\n* function annotations\n* built-in calls\n * print\n * Some done... need to update this...\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbannsec%2Fpysym","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbannsec%2Fpysym","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbannsec%2Fpysym/lists"}