├── .coveragerc ├── .gitignore ├── .gitmodules ├── .travis.yml ├── Dockerfile ├── README.md ├── bkpctf ├── bkpctf_crc_mod.py ├── bkpctf_crc_mod_run.py ├── bkpctf_crc_orig.py ├── cipher.py ├── cipher_mod.py ├── encrypted.txt ├── notes ├── test.py ├── test2.py ├── test_7.py ├── test_7_run.py ├── test_augassign_list.py ├── test_list_index.py ├── tmp.py ├── writeup_notes └── z3_test.py ├── chals ├── docs ├── Makefile ├── about.rst ├── api │ ├── Project.rst │ ├── index.rst │ ├── modules.old │ ├── pyObjectManager.rst │ ├── pyPath.rst │ ├── pyPathGroup.rst │ ├── pyState.rst │ └── pyState │ │ └── pyState.functions.rst ├── conf.py ├── examples.rst ├── hooking.rst ├── index.rst ├── installation.rst ├── make.bat ├── quickstart.rst ├── requirements ├── what_is_implemented.rst └── z3-4.6.0-x64-ubuntu-16.04 │ ├── LICENSE.txt │ ├── bin │ ├── Microsoft.Z3.dll │ ├── Microsoft.Z3.xml │ ├── com.microsoft.z3.jar │ ├── libz3.a │ ├── libz3.so │ ├── libz3java.so │ ├── python │ │ ├── example.py │ │ └── z3 │ │ │ ├── __init__.py │ │ │ ├── z3.py │ │ │ ├── z3consts.py │ │ │ ├── z3core.py │ │ │ ├── z3num.py │ │ │ ├── z3poly.py │ │ │ ├── z3printer.py │ │ │ ├── z3rcf.py │ │ │ ├── z3types.py │ │ │ └── z3util.py │ └── z3 │ └── include │ ├── z3++.h │ ├── z3.h │ ├── z3_algebraic.h │ ├── z3_api.h │ ├── z3_ast_containers.h │ ├── z3_fixedpoint.h │ ├── z3_fpa.h │ ├── z3_interp.h │ ├── z3_macros.h │ ├── z3_optimization.h │ ├── z3_polynomial.h │ ├── z3_rcf.h │ ├── z3_spacer.h │ └── z3_v1.h ├── fix_git.sh ├── pySym ├── Colorer.py ├── Config.py ├── Factory.py ├── Project.py ├── __init__.py ├── ast_parse.py ├── pyObjectManager │ ├── BitVec.py │ ├── Char.py │ ├── Ctx.py │ ├── Int.py │ ├── List.py │ ├── Real.py │ ├── String.py │ ├── __init__.py │ └── decorators.py ├── pyPath.py ├── pyPathGroup.py └── pyState │ ├── Assert.py │ ├── Assign.py │ ├── AugAssign.py │ ├── BinOp.py │ ├── BoolOp.py │ ├── Break.py │ ├── Call.py │ ├── Compare.py │ ├── Expr.py │ ├── For.py │ ├── FunctionDef.py │ ├── GeneratorExp.py │ ├── If.py │ ├── ListComp.py │ ├── Pass.py │ ├── Return.py │ ├── Subscript.py │ ├── UnaryOp.py │ ├── While.py │ ├── __init__.py │ ├── functions │ ├── List │ │ ├── __init__.py │ │ ├── append.py │ │ ├── clear.py │ │ └── insert.py │ ├── String │ │ ├── index.py │ │ ├── join.py │ │ ├── rstrip.py │ │ └── zfill.py │ ├── __init__.py │ ├── abs.py │ ├── bin.py │ ├── chr.py │ ├── hex.py │ ├── int.py │ ├── len.py │ ├── ord.py │ ├── print.py │ ├── pyState │ │ ├── BVS.py │ │ ├── BVV.py │ │ ├── Int.py │ │ ├── Real.py │ │ └── String.py │ ├── random │ │ └── randint.py │ ├── range.py │ ├── str.py │ └── zip.py │ └── z3Helpers.py ├── run_tests.sh ├── setup.cfg ├── setup.py ├── setup_detectOS.sh └── tests ├── __init__.py ├── functions ├── List │ └── test_function_List_insert.py └── random │ └── test_randint.py ├── longer_tests └── test_one.py ├── scripts ├── assert_script_1.py ├── basic_function.py └── ord_symbolic_chr.py ├── test_function_List.py ├── test_function_List_clear.py ├── test_function_String_index.py ├── test_function_String_join.py ├── test_function_String_rstrip.py ├── test_function_String_zfill.py ├── test_function_abs.py ├── test_function_bin.py ├── test_function_chr.py ├── test_function_hex.py ├── test_function_int.py ├── test_function_len.py ├── test_function_ord.py ├── test_function_pyState_BVS.py ├── test_function_pyState_BVV.py ├── test_function_pyState_Real.py ├── test_function_pyState_String.py ├── test_function_range.py ├── test_function_str.py ├── test_function_zip.py ├── test_path.py ├── test_project.py ├── test_pyObjectManager.py ├── test_pyObjectManager_BitVec.py ├── test_pyObjectManager_Char.py ├── test_pyObjectManager_Int.py ├── test_pyObjectManager_List.py ├── test_pyObjectManager_Real.py ├── test_pyObjectManager_String.py ├── test_pyPathGroup.py ├── test_pyState_Assert.py ├── test_pyState_AugAssign.py ├── test_pyState_BinOp.py ├── test_pyState_Break.py ├── test_pyState_Call.py ├── test_pyState_Compare.py ├── test_pyState_For.py ├── test_pyState_FuncionDef.py ├── test_pyState_GeneratorExp.py ├── test_pyState_If.py ├── test_pyState_ListComp.py ├── test_pyState_Pass.py ├── test_pyState_Subscript.py ├── test_pyState_UnaryOp.py ├── test_pyState_While.py └── test_state.py /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | omit = pySym/Colorer.py 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .cache/ 2 | .coverage 3 | *.swp 4 | htmlcov 5 | *.pyc 6 | test 7 | docs/_build 8 | *.egg-info/ 9 | .eggs/ 10 | .coverage.pysym* 11 | .pytest_cache 12 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/z3"] 2 | path = lib/z3 3 | url = https://github.com/Z3Prover/z3.git 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | sudo: required 3 | services: 4 | - docker 5 | python: 6 | - 3.6 7 | before_install: 8 | - curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - 9 | - sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" 10 | - sudo apt-get update 11 | - sudo apt-get -y install docker-ce 12 | install: 13 | - docker build -t bannsec/pysym . 14 | script: 15 | - docker run -it --rm -e COVERALLS_REPO_TOKEN=$COVERALLS_REPO_TOKEN -e TRAVIS_BRANCH=$TRAVIS_BRANCH bannsec/pysym bash -c '. ~/.virtualenvs/pySym/bin/activate && cd /home/pySym/pySym/ && pytest && if [ ! -z "$COVERALLS_REPO_TOKEN" ]; then coveralls; fi' 16 | env: 17 | global: 18 | secure: GkgOfJq14ozjJ0dUtOAduBTyIBIGgI17EGSeJ6ypxYVZhEk5O10lJoY/cPHltJ11RcTAcGZmUYkAgGa+GgmY1csotqBpNOfuojYOCZst27v20khjPxkbRSwpokwoyi4jhv/HtlOVTUW808uZpa+vLs0B8w+atRO87wt7UucB98W1jqiveRrzJaiQsqCvImuZp93d1gocE7/TPLAC5KObNcmkdkFsVhZZGijWO66OvRcXUaiL7oDqY6KhxVP4lk73q4LRnok7/XBmIVhRrHhPzxigxGf+KB9nFv5iV76xRJ4gDlvPrPk5y7mkPnuUKp4FsoLWJHF/PtXOpwkqpAUVBWl3swDiIfMOMalqbHTyOW+hWlN7h8Bz9CCBXxZlDjT8O4NJKoldsVNb93vhkjWPBtR31GPnZ5uIS0MHVz/V/bp+gZghpFXOPkOF6xnL6pmuv0fY5MkNPtyTLy41hiJQlLmsNomzRMfnkGqNDlkefStr32f9ttxx9AOjk0arMX7ryAdZgPSSony+lgjb6wXhRYyxNCZL8RdKD+y4JE/e+uyMJPnlBicwSXN6/38qRGV8rvSu0UeJ7OaIbe7Ogq0Liy5gKlUY2LRX2N8nqnCeepqjidyHqTianpPN+nJJkqIrfZKtbC/IpaOontan6+403OhrkOFJN3CNenjT3IVpycY= 19 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:bionic 2 | 3 | # Root commands 4 | RUN apt-get update && apt-get install -y python3 python3-virtualenv sudo git binutils g++ gcc make libdpkg-perl python-dev libpython3.6-dev coreutils wget && \ 5 | rm -rf /var/lib/apt/lists/* && \ 6 | useradd -m pySym && \ 7 | echo 'pySym ALL=(ALL) NOPASSWD:ALL' | sudo EDITOR='tee -a' visudo 8 | 9 | WORKDIR /home/pySym 10 | 11 | USER pySym 12 | 13 | COPY . /home/pySym/pySym/ 14 | 15 | RUN mkdir /home/pySym/.virtualenvs && \ 16 | sudo chown -R pySym:pySym /home/pySym/. && \ 17 | python3 -m virtualenv --python=$(which python3) ~/.virtualenvs/pySym && \ 18 | echo ". ~/.virtualenvs/pySym/bin/activate" >> ~/.bashrc && \ 19 | . ~/.virtualenvs/pySym/bin/activate && cd pySym && PYSYM_NO_Z3=True pip install -e .[dev] && \ 20 | cd lib/z3 && python scripts/mk_make.py --python && \ 21 | cd build && make -j$(nproc) && make install 22 | 23 | CMD ["/bin/bash","-i"] 24 | -------------------------------------------------------------------------------- /bkpctf/bkpctf_crc_mod.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | def to_bits(length, N): 3 | #return [int(i) for i in bin(N)[2:].zfill(length)] 4 | out = [] 5 | for i in range(length): 6 | out.insert(0, pyState.BVV((N >> i) & 1,1)) 7 | return out 8 | 9 | def from_bits(N): 10 | return int("".join(str(i) for i in N), 2) 11 | 12 | CRC_POLY = to_bits(65, (2**64) + 0xeff67c77d13835f7) 13 | CONST = to_bits(64, 0xabaddeadbeef1dea) 14 | 15 | pass 16 | 17 | def crc(mesg): 18 | mesg += CONST 19 | shift = 151 # 0 20 | while shift < len(mesg) - 64: 21 | #pass 22 | if mesg[shift]: 23 | for i in range(65): 24 | mesg[shift + i] ^= CRC_POLY[i] 25 | shift += 1 26 | return mesg[-64:] 27 | 28 | """ 29 | from copy import copy 30 | import z3 31 | import pySym 32 | 33 | proj = pySym.Project("./bkpctf_crc_mod.py") 34 | 35 | 36 | shift = int(state.getVar('shift')) 37 | CRC_POLY = state.getVar('CRC_POLY', ctx=0) 38 | Then = [] 39 | Else = [] 40 | If = copy(mesg[shift]).getZ3Object() != 0 41 | 42 | for i in range(65): 43 | old_c = copy(mesg[shift+i]) 44 | new_c = mesg[shift+i] 45 | new_c.increment() 46 | Then.append(new_c.getZ3Object() == old_c.getZ3Object() ^ CRC_POLY[i].getZ3Object()) 47 | Else.append(new_c.getZ3Object() == old_c.getZ3Object()) 48 | 49 | state.addConstraint(z3.If(If, z3.And(Then), z3.And(Else))) 50 | """ 51 | 52 | INNER = to_bits(8, 0x36) * 8 53 | OUTER = to_bits(8, 0x5c) * 8 54 | 55 | """ 56 | def xor(x, y): 57 | return [g ^ h for (g, h) in zip(x, y)] 58 | """ 59 | 60 | def xor(x, y): 61 | l = [] 62 | for i in range(len(x)): 63 | l.append(x[i] ^ y[i]) 64 | pass 65 | return l 66 | 67 | """ 68 | def hmac(h, key, mesg): 69 | return h(xor(key, OUTER) + h(xor(key, INNER) + mesg)) 70 | """ 71 | 72 | def hmac(key, mesg): 73 | return crc(xor(key, OUTER) + crc(xor(key, INNER) + mesg)) 74 | 75 | PLAIN_1 = "zupe zecret" 76 | PLAIN_2 = "BKPCTF" 77 | 78 | def str_to_bits(s): 79 | return [b for i in s for b in to_bits(8, ord(i))] 80 | 81 | def bits_to_hex(b): 82 | return hex(from_bits(b)).rstrip("L") 83 | # 84 | # Create key 85 | # 86 | 87 | KEY = [] 88 | for i in range(64): 89 | KEY.append(pyState.BVS(1)) 90 | 91 | #p1 = hmac(crc, KEY, str_to_bits(PLAIN_1)) 92 | p1 = hmac(KEY, str_to_bits(PLAIN_1)) 93 | 94 | # to_bits(64, 0xa57d43a032feb286) == [1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0] 95 | 96 | """ 97 | if __name__ == "__main__": 98 | with open("key.txt") as f: 99 | KEY = to_bits(64, int(f.read().strip("\n"), 16)) 100 | print PLAIN_1, "=>", bits_to_hex(hmac(crc, KEY, str_to_bits(PLAIN_1))) # Should equal 0xa57d43a032feb286 101 | print "BKPCTF{" + bits_to_hex(hmac(crc, KEY, str_to_bits(PLAIN_2))) + "}" 102 | """ 103 | -------------------------------------------------------------------------------- /bkpctf/bkpctf_crc_mod_run.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from copy import copy 3 | import z3 4 | import pySym 5 | import IPython 6 | 7 | proj = pySym.Project("./bkpctf_crc_mod.py") 8 | 9 | def hook_crc(state): 10 | shift = int(state.getVar('shift')) 11 | mesg = state.getVar('mesg') 12 | CRC_POLY = state.getVar('CRC_POLY', ctx=0) 13 | Then = [] 14 | Else = [] 15 | If = copy(mesg[shift]).getZ3Object() != 0 16 | 17 | print("Hit hook. Shift == " + str(shift)) 18 | print("Len msg == " + str(len(mesg))) 19 | 20 | for i in range(65): 21 | old_c = copy(mesg[shift+i]) 22 | new_c = mesg[shift+i] 23 | new_c.increment() 24 | Then.append(new_c.getZ3Object() == old_c.getZ3Object() ^ CRC_POLY[i].getZ3Object()) 25 | Else.append(new_c.getZ3Object() == old_c.getZ3Object()) 26 | 27 | state.addConstraint(z3.If(If, z3.And(Then), z3.And(Else))) 28 | mesg = state.getVar('mesg')[-64:] 29 | #print([c.state for c in mesg]) 30 | #print(state) 31 | 32 | def hook_interactive(state): 33 | IPython.embed() 34 | 35 | proj.hook(21, hook_crc) 36 | #proj.hook(64, hook_interactive) 37 | pg = proj.factory.path_group(ignore_groups='deadended') 38 | 39 | pg.explore() 40 | -------------------------------------------------------------------------------- /bkpctf/bkpctf_crc_orig.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | def to_bits(length, N): 3 | return [int(i) for i in bin(N)[2:].zfill(length)] 4 | 5 | def from_bits(N): 6 | return int("".join(str(i) for i in N), 2) 7 | 8 | CRC_POLY = to_bits(65, (2**64) + 0xeff67c77d13835f7) 9 | CONST = to_bits(64, 0xabaddeadbeef1dea) 10 | 11 | def crc(mesg): 12 | print(len(mesg)) 13 | mesg += CONST 14 | shift = 0 15 | while shift < len(mesg) - 64: 16 | if mesg[shift]: 17 | for i in range(65): 18 | mesg[shift + i] ^= CRC_POLY[i] 19 | shift += 1 20 | return mesg[-64:] 21 | 22 | INNER = to_bits(8, 0x36) * 8 23 | OUTER = to_bits(8, 0x5c) * 8 24 | 25 | def xor(x, y): 26 | return [g ^ h for (g, h) in zip(x, y)] 27 | 28 | def hmac(h, key, mesg): 29 | return h(xor(key, OUTER) + h(xor(key, INNER) + mesg)) 30 | 31 | PLAIN_1 = "zupe zecret" 32 | PLAIN_2 = "BKPCTF" 33 | 34 | def str_to_bits(s): 35 | return [b for i in s for b in to_bits(8, ord(i))] 36 | 37 | def bits_to_hex(b): 38 | return hex(from_bits(b)).rstrip("L") 39 | 40 | if __name__ == "__main__": 41 | with open("key.txt") as f: 42 | KEY = to_bits(64, int(f.read().strip("\n"), 16)) 43 | print PLAIN_1, "=>", bits_to_hex(hmac(crc, KEY, str_to_bits(PLAIN_1))) 44 | print "BKPCTF{" + bits_to_hex(hmac(crc, KEY, str_to_bits(PLAIN_2))) + "}" 45 | -------------------------------------------------------------------------------- /bkpctf/cipher.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2 2 | 3 | import sys 4 | import random 5 | 6 | key = sys.argv[1] 7 | flag = '**CENSORED**' 8 | 9 | assert len(key) == 13 10 | assert max([ord(char) for char in key]) < 128 11 | assert max([ord(char) for char in flag]) < 128 12 | 13 | message = flag + "|" + key 14 | 15 | encrypted = chr(random.randint(0, 128)) 16 | 17 | for i in range(0, len(message)): 18 | encrypted += chr((ord(message[i]) + ord(key[i % len(key)]) + ord(encrypted[i])) % 128) 19 | 20 | print(encrypted.encode('hex')) 21 | -------------------------------------------------------------------------------- /bkpctf/cipher_mod.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2 2 | 3 | key = pyState.String(13) 4 | flag = pyState.String(21) # Calculated length 5 | 6 | assert len(key) == 13 7 | 8 | #assert max([ord(char) for char in key]) < 128 9 | 10 | for char in key: 11 | assert ord(char) < 128 12 | 13 | #assert max([ord(char) for char in flag]) < 128 14 | for char in flag: 15 | assert ord(char) < 128 16 | 17 | message = flag + "|" + key 18 | 19 | encrypted = chr(random.randint(0, 128)) 20 | 21 | for i in range(0, len(message)): 22 | encrypted += chr((ord(message[i]) + ord(key[i % len(key)]) + ord(encrypted[i])) % 128) 23 | 24 | #print(encrypted.encode('hex')) 25 | -------------------------------------------------------------------------------- /bkpctf/encrypted.txt: -------------------------------------------------------------------------------- 1 | 7c153a474b6a2d3f7d3f7328703e6c2d243a083e2e773c45547748667c1511333f4f745e 2 | -------------------------------------------------------------------------------- /bkpctf/test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | def to_bits(length, N): 3 | #return [int(i) for i in bin(N)[2:].zfill(length)] 4 | out = [] 5 | for i in range(length): 6 | out.insert(0, pyState.BVV((N >> i) & 1,1)) 7 | return out 8 | 9 | def from_bits(N): 10 | return int("".join(str(i) for i in N), 2) 11 | 12 | CRC_POLY = to_bits(65, (2**64) + 0xeff67c77d13835f7) 13 | CONST = to_bits(64, 0xabaddeadbeef1dea) 14 | 15 | def crc(mesg): 16 | mesg += CONST 17 | shift = 0 18 | while shift < len(mesg) - 64: 19 | if mesg[shift]: 20 | for i in range(65): 21 | mesg[shift + i] ^= CRC_POLY[i] 22 | shift += 1 23 | return mesg[-64:] 24 | 25 | INNER = to_bits(8, 0x36) * 8 26 | OUTER = to_bits(8, 0x5c) * 8 27 | 28 | """ 29 | def xor(x, y): 30 | return [g ^ h for (g, h) in zip(x, y)] 31 | """ 32 | 33 | def xor(x, y): 34 | l = [] 35 | for i in range(len(x)): 36 | l.append(x[i] ^ y[i]) 37 | return l 38 | 39 | """ 40 | def hmac(h, key, mesg): 41 | return h(xor(key, OUTER) + h(xor(key, INNER) + mesg)) 42 | """ 43 | 44 | def hmac(key, mesg): 45 | return crc(xor(key, OUTER) + crc(xor(key, INNER) + mesg)) 46 | 47 | PLAIN_1 = "zupe zecret" 48 | PLAIN_2 = "BKPCTF" 49 | 50 | def str_to_bits(s): 51 | return [b for i in s for b in to_bits(8, ord(i))] 52 | 53 | def bits_to_hex(b): 54 | return hex(from_bits(b)).rstrip("L") 55 | # 56 | # Create key 57 | # 58 | 59 | KEY = [] 60 | for i in range(64): 61 | KEY.append(pyState.BVS(1)) 62 | 63 | #plain = str_to_bits(PLAIN_1) 64 | p1 = hmac(KEY, str_to_bits(PLAIN_1)) 65 | 66 | # to_bits(64, 0xa57d43a032feb286) == [1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0] 67 | 68 | """ 69 | if __name__ == "__main__": 70 | with open("key.txt") as f: 71 | KEY = to_bits(64, int(f.read().strip("\n"), 16)) 72 | print PLAIN_1, "=>", bits_to_hex(hmac(crc, KEY, str_to_bits(PLAIN_1))) # Should equal 0xa57d43a032feb286 73 | print "BKPCTF{" + bits_to_hex(hmac(crc, KEY, str_to_bits(PLAIN_2))) + "}" 74 | """ 75 | -------------------------------------------------------------------------------- /bkpctf/test2.py: -------------------------------------------------------------------------------- 1 | x = 0 2 | y = 0 3 | 4 | y += 12 5 | 6 | if y > 0: 7 | x = 1 8 | else: 9 | x = 0 10 | 11 | -------------------------------------------------------------------------------- /bkpctf/test_7.py: -------------------------------------------------------------------------------- 1 | 2 | x = 1 3 | #s = pyState.String(2) 4 | #x = "_" 5 | #x += "testt".rstrip(s) 6 | -------------------------------------------------------------------------------- /bkpctf/test_7_run.py: -------------------------------------------------------------------------------- 1 | import pySym 2 | 3 | proj = pySym.Project("./test_7.py") 4 | pg = proj.factory.path_group() 5 | pg.explore() 6 | -------------------------------------------------------------------------------- /bkpctf/test_augassign_list.py: -------------------------------------------------------------------------------- 1 | 2 | l1 = [1,2,3] 3 | l1 *= 3 4 | -------------------------------------------------------------------------------- /bkpctf/test_list_index.py: -------------------------------------------------------------------------------- 1 | 2 | l = [1,2,3,4] 3 | x = l[-2:] 4 | y = l[-3:-1] 5 | -------------------------------------------------------------------------------- /bkpctf/tmp.py: -------------------------------------------------------------------------------- 1 | def egcd(a, b): 2 | if a == 0: 3 | return (b, 0, 1) 4 | else: 5 | g, y, x = egcd(b % a, a) 6 | return (g, x - (b // a) * y, y) 7 | 8 | def modinv(a, m): 9 | g, x, y = egcd(a, m) 10 | if g != 1: 11 | raise Exception('modular inverse does not exist') 12 | else: 13 | return x % m 14 | -------------------------------------------------------------------------------- /bkpctf/z3_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import pySym 4 | 5 | proj = pySym.Project("./cipher_mod.py",debug=True) 6 | pg = proj.factory.path_group() 7 | pg.explore() 8 | 9 | print("When z3 doesn't freeze, i should make it here in about 30 seconds. Otherwise, it will take infinite amount of time.") 10 | -------------------------------------------------------------------------------- /chals: -------------------------------------------------------------------------------- 1 | Challenges that should be doable to attempt to get pySym to work with 2 | ----------------------------------- 3 | 4 | Boston Key Party 2016 -- HMAC CRC 5 | https://github.com/ctfs/write-ups-2016/blob/master/boston-key-party-2016/crypto/hamc_crc-5/0c7433675c3c555afb77271d6a549bf5d941d2ab 6 | 7 | SECCON Quals 2017 -- Crypto Vigenere 8 | https://github.com/p4-team/ctf/tree/master/2017-12-09-seccon-quals/crypto_vigenere 9 | -------------------------------------------------------------------------------- /docs/about.rst: -------------------------------------------------------------------------------- 1 | ======================== 2 | About pySym 3 | ======================== 4 | 5 | Introduction to ``pySym`` 6 | ========================== 7 | 8 | ``pySym`` is a python application that utilizes the Microsoft Z3 Theorem 9 | Prover to solve it's constraints. The goal for this application is to 10 | faithfully execute *basic* python scripts and provide a means to analyze them 11 | symbolically. Note that this application will not allow you to test your python 12 | apps for python interpreter version dependent bugs. It will attempt to follow 13 | what Python *should* be doing and thus would be more appropriate for the 14 | following two cases: 15 | 16 | 1) Finding logic bugs in your application. 17 | 2) Discovering possibly unused code segments 18 | 3) Generating test cases 19 | 4) Rapidly prototyping concepts for symbolic analysis 20 | 21 | Python Versions 22 | ======================== 23 | pySym is written in Python 3 and will parse Python 3 code. It will likely not 24 | parse Python 2 code, however small code can simple be auto-upgraded if need be 25 | by the 2to3 script. 26 | 27 | pySym Weaknesses 28 | ======================== 29 | ``pySym`` is not, nor will it ever be, a complete Python Symbolic Execution 30 | Engine. Scripted languages are rapidly evolving, and Python is no exception. 31 | Rapid evolution aside, even between minor versions of Python there are many 32 | small changes that will cause unintended code paths. Likely it is not feasible 33 | for any script based Symbolic Execution of Python to be that thorough. 34 | 35 | If your goal is faithful Python symbolic exeuction to any given Python 36 | major/minor versions, I'd recommend looking at a project called `CHEF 37 | `_. This project is a novel approach whereby 38 | the authors instrument the source interpreter with the `S2E 39 | `_ framework thereby causing very thorough code path 40 | generation. 41 | 42 | pySym Strengths 43 | ======================== 44 | ``pySym`` is an attempt at generalizing Python Symbolic Execution utilizing 45 | Python itself. One major downfall that approaches such as CHEF have is that it 46 | is unable to make symbolic input aside from int and string types. With 47 | ``pySym``, already it has the ability to produce fully symbolic ints, floats, 48 | lists, and strings. When more datatypes are added, they will have the ability 49 | to be fully symbolic as well. This is important when you want to stress test 50 | symbolic Dictionaries or other more complex objects. 51 | 52 | It is also easy to use. Simply run the installer, load up the script you want 53 | to execute (with or without changes), and tell ``pySym`` to explore. It's not 54 | dependent on compiling special versions of applications or using strange 55 | commands that you're not quite sure what you're doing. You can be up and 56 | running in as little as 10 minutes. 57 | 58 | As a follow-on, because everything can be symbolic and you can prototype Python 59 | code in general quickly, ``pySym`` gives you a way to explore concepts without 60 | needing to be a symbolic exeuction expert. Simply write your code as you would 61 | normally for Python, then run it through ``pySym``. 62 | -------------------------------------------------------------------------------- /docs/api/Project.rst: -------------------------------------------------------------------------------- 1 | Project 2 | ======= 3 | 4 | .. automodule:: pySym.Project 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/api/index.rst: -------------------------------------------------------------------------------- 1 | #################################### 2 | API 3 | #################################### 4 | 5 | What follows is ``pySym`` core API documentation. 6 | 7 | .. note:: 8 | This documentation is a work in progress. Not everything is 9 | documented yet. 10 | 11 | .. toctree:: 12 | :maxdepth: 20 13 | :glob: 14 | 15 | * 16 | -------------------------------------------------------------------------------- /docs/api/modules.old: -------------------------------------------------------------------------------- 1 | pySym 2 | ===== 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | pyObjectManager 8 | pyPath 9 | pyPathGroup 10 | pyState 11 | -------------------------------------------------------------------------------- /docs/api/pyObjectManager.rst: -------------------------------------------------------------------------------- 1 | pyObjectManager 2 | ======================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | pyObjectManager.BitVec module 8 | ----------------------------- 9 | 10 | .. automodule:: pySym.pyObjectManager.BitVec 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | pyObjectManager.Char module 16 | --------------------------- 17 | 18 | .. automodule:: pySym.pyObjectManager.Char 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | pyObjectManager.Ctx module 24 | -------------------------- 25 | 26 | .. automodule:: pySym.pyObjectManager.Ctx 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | pyObjectManager.Int module 32 | -------------------------- 33 | 34 | .. automodule:: pySym.pyObjectManager.Int 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | pyObjectManager.List module 40 | --------------------------- 41 | 42 | .. automodule:: pySym.pyObjectManager.List 43 | :members: 44 | :undoc-members: 45 | :show-inheritance: 46 | 47 | pyObjectManager.Real module 48 | --------------------------- 49 | 50 | .. automodule:: pySym.pyObjectManager.Real 51 | :members: 52 | :undoc-members: 53 | :show-inheritance: 54 | 55 | pyObjectManager.String module 56 | ----------------------------- 57 | 58 | .. automodule:: pySym.pyObjectManager.String 59 | :members: 60 | :undoc-members: 61 | :show-inheritance: 62 | 63 | 64 | Module contents 65 | --------------- 66 | 67 | .. automodule:: pySym.pyObjectManager 68 | :members: 69 | :undoc-members: 70 | :show-inheritance: 71 | -------------------------------------------------------------------------------- /docs/api/pyPath.rst: -------------------------------------------------------------------------------- 1 | pyPath 2 | ============= 3 | 4 | .. automodule:: pySym.pyPath 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/api/pyPathGroup.rst: -------------------------------------------------------------------------------- 1 | pyPathGroup 2 | ================== 3 | 4 | .. automodule:: pySym.pyPathGroup 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/api/pyState.rst: -------------------------------------------------------------------------------- 1 | pyState 2 | =============== 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :glob: 9 | 10 | pyState/pyState.functions 11 | 12 | pyState.Assign 13 | --------------------- 14 | 15 | .. automodule:: pySym.pyState.Assign 16 | :members: 17 | :undoc-members: 18 | :show-inheritance: 19 | 20 | 21 | pyState.AugAssign 22 | ------------------------ 23 | 24 | .. automodule:: pySym.pyState.AugAssign 25 | :members: 26 | :undoc-members: 27 | :show-inheritance: 28 | 29 | pyState.BinOp 30 | -------------------- 31 | 32 | .. automodule:: pySym.pyState.BinOp 33 | :members: 34 | :undoc-members: 35 | :show-inheritance: 36 | 37 | pyState.BoolOp 38 | --------------------- 39 | 40 | .. automodule:: pySym.pyState.BoolOp 41 | :members: 42 | :undoc-members: 43 | :show-inheritance: 44 | 45 | pyState.Break 46 | -------------------- 47 | 48 | .. automodule:: pySym.pyState.Break 49 | :members: 50 | :undoc-members: 51 | :show-inheritance: 52 | 53 | pyState.Call 54 | ------------------- 55 | 56 | .. automodule:: pySym.pyState.Call 57 | :members: 58 | :undoc-members: 59 | :show-inheritance: 60 | 61 | pyState.Compare 62 | ---------------------- 63 | 64 | .. automodule:: pySym.pyState.Compare 65 | :members: 66 | :undoc-members: 67 | :show-inheritance: 68 | 69 | pyState.Expr 70 | ------------------- 71 | 72 | .. automodule:: pySym.pyState.Expr 73 | :members: 74 | :undoc-members: 75 | :show-inheritance: 76 | 77 | pyState.For 78 | ------------------ 79 | 80 | .. automodule:: pySym.pyState.For 81 | :members: 82 | :undoc-members: 83 | :show-inheritance: 84 | 85 | pyState.FunctionDef 86 | -------------------------- 87 | 88 | .. automodule:: pySym.pyState.FunctionDef 89 | :members: 90 | :undoc-members: 91 | :show-inheritance: 92 | 93 | pyState.GeneratorExp 94 | --------------------------- 95 | 96 | .. automodule:: pySym.pyState.GeneratorExp 97 | :members: 98 | :undoc-members: 99 | :show-inheritance: 100 | 101 | pyState.If 102 | ----------------- 103 | 104 | .. automodule:: pySym.pyState.If 105 | :members: 106 | :undoc-members: 107 | :show-inheritance: 108 | 109 | pyState.ListComp 110 | ----------------------- 111 | 112 | .. automodule:: pySym.pyState.ListComp 113 | :members: 114 | :undoc-members: 115 | :show-inheritance: 116 | 117 | pyState.Pass 118 | ------------------- 119 | 120 | .. automodule:: pySym.pyState.Pass 121 | :members: 122 | :undoc-members: 123 | :show-inheritance: 124 | 125 | pyState.Return 126 | --------------------- 127 | 128 | .. automodule:: pySym.pyState.Return 129 | :members: 130 | :undoc-members: 131 | :show-inheritance: 132 | 133 | pyState.Subscript 134 | ------------------------ 135 | 136 | .. automodule:: pySym.pyState.Subscript 137 | :members: 138 | :undoc-members: 139 | :show-inheritance: 140 | 141 | pyState.UnaryOp 142 | ---------------------- 143 | 144 | .. automodule:: pySym.pyState.UnaryOp 145 | :members: 146 | :undoc-members: 147 | :show-inheritance: 148 | 149 | pyState.While 150 | -------------------- 151 | 152 | .. automodule:: pySym.pyState.While 153 | :members: 154 | :undoc-members: 155 | :show-inheritance: 156 | 157 | pyState.z3Helpers 158 | ------------------------ 159 | 160 | .. automodule:: pySym.pyState.z3Helpers 161 | :members: 162 | :undoc-members: 163 | :show-inheritance: 164 | 165 | 166 | Module contents 167 | --------------- 168 | 169 | .. automodule:: pySym.pyState 170 | :members: 171 | :undoc-members: 172 | :show-inheritance: 173 | -------------------------------------------------------------------------------- /docs/api/pyState/pyState.functions.rst: -------------------------------------------------------------------------------- 1 | pyState.functions package 2 | ========================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | pyState.functions.abs module 8 | ---------------------------- 9 | 10 | .. automodule:: pySym.pyState.functions.abs 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | pyState.functions.bin module 16 | ---------------------------- 17 | 18 | .. automodule:: pySym.pyState.functions.bin 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | pyState.functions.hex module 24 | ---------------------------- 25 | 26 | .. automodule:: pySym.pyState.functions.hex 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | pyState.functions.int module 32 | ---------------------------- 33 | 34 | .. automodule:: pySym.pyState.functions.int 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | pyState.functions.len module 40 | ---------------------------- 41 | 42 | .. automodule:: pySym.pyState.functions.len 43 | :members: 44 | :undoc-members: 45 | :show-inheritance: 46 | 47 | pyState.functions.ord module 48 | ---------------------------- 49 | 50 | .. automodule:: pySym.pyState.functions.ord 51 | :members: 52 | :undoc-members: 53 | :show-inheritance: 54 | 55 | pyState.functions.print module 56 | ------------------------------ 57 | 58 | .. automodule:: pySym.pyState.functions.print 59 | :members: 60 | :undoc-members: 61 | :show-inheritance: 62 | 63 | pyState.functions.range module 64 | ------------------------------ 65 | 66 | .. automodule:: pySym.pyState.functions.range 67 | :members: 68 | :undoc-members: 69 | :show-inheritance: 70 | 71 | pyState.functions.str module 72 | ---------------------------- 73 | 74 | .. automodule:: pySym.pyState.functions.str 75 | :members: 76 | :undoc-members: 77 | :show-inheritance: 78 | 79 | pyState.functions.zip module 80 | ---------------------------- 81 | 82 | .. automodule:: pySym.pyState.functions.zip 83 | :members: 84 | :undoc-members: 85 | :show-inheritance: 86 | 87 | 88 | Module contents 89 | --------------- 90 | 91 | .. automodule:: pySym.pyState.functions 92 | :members: 93 | :undoc-members: 94 | :show-inheritance: 95 | -------------------------------------------------------------------------------- /docs/examples.rst: -------------------------------------------------------------------------------- 1 | ======================== 2 | Examples 3 | ======================== 4 | 5 | Tokyo Westerns CTF 2017: My Simple Cipher 6 | ========================================= 7 | External Writeup: `BannSecurity.com `_ 8 | 9 | Prime Finder 10 | ======================== 11 | 12 | Let's recreate a simple problem of finding all the primes under 50. Stealing 13 | and modifying some code from the internet, we can use the following python code 14 | to do just that. 15 | 16 | .. code-block:: python 17 | 18 | # Enable logging if you want. It's faster without. 19 | #import logging 20 | #logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 21 | from pySym.pyPath import Path 22 | from pySym import ast_parse 23 | from pySym import Colorer 24 | from pySym.pyPathGroup import PathGroup 25 | 26 | source = """ 27 | def isprime(n): 28 | 29 | # 0 and 1 are not primes 30 | if n < 2: 31 | return 0 32 | 33 | # 2 is the only even prime number 34 | if n == 2: 35 | return 1 36 | 37 | # all other even numbers are not primes 38 | if n % 2 == 0: 39 | return 0 40 | 41 | # range starts with 3 and only needs to go up 42 | # the square root of n for all odd numbers 43 | for x in range(3, int(n**0.5) + 1, 2): 44 | if n % x == 0: 45 | return 0 46 | 47 | return 1 48 | 49 | x = [x for x in range(50) if isprime(x) == 1] 50 | """ 51 | 52 | b = ast_parse.parse(source).body 53 | p = Path(b,source=source) 54 | pg = PathGroup(p,discardFailures=True) 55 | 56 | The first two lines are just to add more logging. If you're not interested in 57 | watching scrolling text, just leave those two out. Aside from that, the rest is 58 | self explanatory. As of writing, I have not implemented Bools yet, so this is 59 | why I'm returning integer 1 or 0. The end effect is the same, however. 60 | 61 | As written, this code will symbolically execute without special changes. To do 62 | so, just execute: 63 | 64 | .. code-block:: python 65 | 66 | pg.explore() 67 | 68 | This will cause `pySym` to start exploring this state and finding valid paths. 69 | Since we're only dealing with concrete variables, there will be one valid path 70 | through. However, there will be many deadended paths since `pySym` will take 71 | every branch along the way. 72 | 73 | Also note, I used "discardFailures=True" in PathGroup. This is because with 74 | this option enabled, you won't be wasting memory of your computer with 75 | deadended paths. When there are many such paths, or if the paths are 76 | complicated, the total memory used by paths you're not interested in can become 77 | high. This option allows you to immediately forget those paths and thus reduce 78 | your memory profile. 79 | 80 | Once done, we can confirm that the expected results were attained: 81 | 82 | .. code-block:: python 83 | 84 | In [7]: pg 85 | Out[7]: 86 | 87 | In [8]: x = pg.completed[0].state.getVar('x') 88 | 89 | In [9]: print(x) 90 | [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47] 91 | 92 | The first command simply shows us that our path group has 1 completed path. As 93 | mentioned above, there would be many more deadended paths if we hadn't set 94 | discardFailures to True. The second command reaches into our only completed 95 | path (index 0) and asks the state to give us the pyObjectManager object for 96 | variable named 'x'. We can do many things with this variable at this point, 97 | however for the purposes of this example, we simply print out the variable. It 98 | will pause for a few moments as z3 solves constraints for us and `pySym` puts 99 | it into the proper representation (a list). 100 | 101 | 102 | -------------------------------------------------------------------------------- /docs/hooking.rst: -------------------------------------------------------------------------------- 1 | ================ 2 | Symbolic Hooking 3 | ================ 4 | 5 | What is Hooking 6 | =============== 7 | 8 | Hooking is a means to interject your own commands into the symbolic execution 9 | of the application. For instance, a common reason to hook a function or part of 10 | a function is to provide your own symbolic summary for it. In this way, you can 11 | jump out of the symbolically executed script, back into the engine and tell 12 | `pySym` how to keep that section symbolic. 13 | 14 | One quick example is, if you consider an if statement nested inside a while 15 | loop, as follows: 16 | 17 | .. code-block:: python 18 | 19 | def my_function(my_list): 20 | output = [] 21 | for element in my_list: 22 | if element == 0: 23 | output.append("zero") 24 | else: 25 | output.append("one") 26 | return output 27 | 28 | In the above example, that ``if`` statement inside the ``for`` loop would actually 29 | cause pySym to state split for each element. Depending on the size of the input 30 | list and how symbolic the input actually is, this could cause a path explosion 31 | issue. One way around that is to hook ``my_function`` and create a summary for 32 | it. 33 | 34 | How to Hook 35 | =========== 36 | At present, hooking in `pySym` is accomplished via the `pySym.Project.hook` 37 | method. 38 | 39 | See the method documentation for more details: 40 | 41 | :meth:`pySym.Project.Project.hook` 42 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | #################################### 2 | Welcome to pySym's documentation! 3 | #################################### 4 | 5 | ``pySym`` is a Symbolic Execution Engine for Python Scripts. It is 6 | written in Python and designed for easy adoption for a subset of 7 | symbolic execution problems. 8 | 9 | **************** 10 | Getting Started 11 | **************** 12 | 13 | .. toctree:: 14 | :maxdepth: 2 15 | :glob: 16 | 17 | about 18 | installation 19 | quickstart 20 | examples 21 | what_is_implemented 22 | hooking 23 | api/index 24 | -------------------------------------------------------------------------------- /docs/quickstart.rst: -------------------------------------------------------------------------------- 1 | ======================== 2 | pySym Quick-Start 3 | ======================== 4 | 5 | Running Your First Program 6 | ========================== 7 | 8 | Assuming that you have already `installed `_ pySym, actiate 9 | your virtual environment and load up a source:: 10 | 11 | $ workon pySym 12 | (pySym)$ ipython 13 | 14 | +++++++++++++++++ 15 | Automated Loading 16 | +++++++++++++++++ 17 | 18 | Assuming you have a program you want to symbolically execute called 19 | `my_test_program.py`, you can do so with the following lines: 20 | 21 | .. code-block:: python 22 | 23 | In [1]: import pySym 24 | 25 | In [2]: proj = pySym.Project("my_test_program.py") 26 | 27 | In [3]: pg = proj.factory.path_group() 28 | 29 | You can now run it by simply executing: 30 | 31 | .. code-block:: python 32 | 33 | In [4]: pg.explore() 34 | 35 | +++++++++++++++++++++ 36 | Manually From Strings 37 | +++++++++++++++++++++ 38 | 39 | You can also load your script directly via python string. The following example 40 | loads it from a file: 41 | 42 | .. code-block:: python 43 | 44 | In [1]: from pySym.pyPath import Path 45 | 46 | In [2]: import ast 47 | 48 | In [3]: from pySym import Colorer 49 | 50 | In [4]: from pySym.pyPathGroup import PathGroup 51 | 52 | In [5]: with open("test","r") as f: 53 | ...: b = ast.parse(source).body 54 | ...: p = Path(b,source=source) 55 | ...: pg = PathGroup(p) 56 | 57 | You can now run it by simply executing: 58 | 59 | .. code-block:: python 60 | 61 | In [6]: pg.explore() 62 | 63 | See the `examples `_ page for example programs. 64 | -------------------------------------------------------------------------------- /docs/requirements: -------------------------------------------------------------------------------- 1 | enforce 2 | prettytable 3 | -------------------------------------------------------------------------------- /docs/z3-4.6.0-x64-ubuntu-16.04/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Z3 2 | Copyright (c) Microsoft Corporation 3 | All rights reserved. 4 | MIT License 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 9 | 10 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /docs/z3-4.6.0-x64-ubuntu-16.04/bin/Microsoft.Z3.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bannsec/pySym/497b5d84e5e360ea57ceaf26d477d3fad1d4e6c8/docs/z3-4.6.0-x64-ubuntu-16.04/bin/Microsoft.Z3.dll -------------------------------------------------------------------------------- /docs/z3-4.6.0-x64-ubuntu-16.04/bin/com.microsoft.z3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bannsec/pySym/497b5d84e5e360ea57ceaf26d477d3fad1d4e6c8/docs/z3-4.6.0-x64-ubuntu-16.04/bin/com.microsoft.z3.jar -------------------------------------------------------------------------------- /docs/z3-4.6.0-x64-ubuntu-16.04/bin/libz3.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bannsec/pySym/497b5d84e5e360ea57ceaf26d477d3fad1d4e6c8/docs/z3-4.6.0-x64-ubuntu-16.04/bin/libz3.a -------------------------------------------------------------------------------- /docs/z3-4.6.0-x64-ubuntu-16.04/bin/libz3.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bannsec/pySym/497b5d84e5e360ea57ceaf26d477d3fad1d4e6c8/docs/z3-4.6.0-x64-ubuntu-16.04/bin/libz3.so -------------------------------------------------------------------------------- /docs/z3-4.6.0-x64-ubuntu-16.04/bin/libz3java.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bannsec/pySym/497b5d84e5e360ea57ceaf26d477d3fad1d4e6c8/docs/z3-4.6.0-x64-ubuntu-16.04/bin/libz3java.so -------------------------------------------------------------------------------- /docs/z3-4.6.0-x64-ubuntu-16.04/bin/python/example.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation 2015, 2016 2 | 3 | # The Z3 Python API requires libz3.dll/.so/.dylib in the 4 | # PATH/LD_LIBRARY_PATH/DYLD_LIBRARY_PATH 5 | # environment variable and the PYTHON_PATH environment variable 6 | # needs to point to the `python' directory that contains `z3/z3.py' 7 | # (which is at bin/python in our binary releases). 8 | 9 | # If you obtained example.py as part of our binary release zip files, 10 | # which you unzipped into a directory called `MYZ3', then follow these 11 | # instructions to run the example: 12 | 13 | # Running this example on Windows: 14 | # set PATH=%PATH%;MYZ3\bin 15 | # set PYTHONPATH=MYZ3\bin\python 16 | # python example.py 17 | 18 | # Running this example on Linux: 19 | # export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:MYZ3/bin 20 | # export PYTHONPATH=MYZ3/bin/python 21 | # python example.py 22 | 23 | # Running this example on OSX: 24 | # export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:MYZ3/bin 25 | # export PYTHONPATH=MYZ3/bin/python 26 | # python example.py 27 | 28 | 29 | from z3 import * 30 | 31 | x = Real('x') 32 | y = Real('y') 33 | s = Solver() 34 | s.add(x + y > 5, x > 1, y > 1) 35 | print(s.check()) 36 | print(s.model()) 37 | -------------------------------------------------------------------------------- /docs/z3-4.6.0-x64-ubuntu-16.04/bin/python/z3/__init__.py: -------------------------------------------------------------------------------- 1 | from .z3 import * 2 | 3 | from . import z3num 4 | from . import z3poly 5 | from . import z3printer 6 | from . import z3rcf 7 | from . import z3types 8 | from . import z3util 9 | 10 | # generated files 11 | from . import z3core 12 | from . import z3consts 13 | -------------------------------------------------------------------------------- /docs/z3-4.6.0-x64-ubuntu-16.04/bin/python/z3/z3poly.py: -------------------------------------------------------------------------------- 1 | ############################################ 2 | # Copyright (c) 2012 Microsoft Corporation 3 | # 4 | # Z3 Python interface for Z3 polynomials 5 | # 6 | # Author: Leonardo de Moura (leonardo) 7 | ############################################ 8 | 9 | from .z3 import * 10 | 11 | def subresultants(p, q, x): 12 | """ 13 | Return the non-constant subresultants of 'p' and 'q' with respect to the "variable" 'x'. 14 | 15 | 'p', 'q' and 'x' are Z3 expressions where 'p' and 'q' are arithmetic terms. 16 | Note that, any subterm that cannot be viewed as a polynomial is assumed to be a variable. 17 | Example: f(a) is a considered to be a variable b in the polynomial 18 | 19 | f(a)*f(a) + 2*f(a) + 1 20 | 21 | >>> x, y = Reals('x y') 22 | >>> subresultants(2*x + y, 3*x - 2*y + 2, x) 23 | [-7*y + 4] 24 | >>> r = subresultants(3*y*x**2 + y**3 + 1, 2*x**3 + y + 3, x) 25 | >>> r[0] 26 | 4*y**9 + 12*y**6 + 27*y**5 + 162*y**4 + 255*y**3 + 4 27 | >>> r[1] 28 | -6*y**4 + -6*y 29 | """ 30 | return AstVector(Z3_polynomial_subresultants(p.ctx_ref(), p.as_ast(), q.as_ast(), x.as_ast()), p.ctx) 31 | 32 | if __name__ == "__main__": 33 | import doctest 34 | if doctest.testmod().failed: 35 | exit(1) 36 | -------------------------------------------------------------------------------- /docs/z3-4.6.0-x64-ubuntu-16.04/bin/z3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bannsec/pySym/497b5d84e5e360ea57ceaf26d477d3fad1d4e6c8/docs/z3-4.6.0-x64-ubuntu-16.04/bin/z3 -------------------------------------------------------------------------------- /docs/z3-4.6.0-x64-ubuntu-16.04/include/z3.h: -------------------------------------------------------------------------------- 1 | /*++ 2 | Copyright (c) 2007 Microsoft Corporation 3 | 4 | Module Name: 5 | 6 | z3.h 7 | 8 | Abstract: 9 | 10 | Z3 API. 11 | 12 | Author: 13 | 14 | Nikolaj Bjorner (nbjorner) 15 | Leonardo de Moura (leonardo) 2007-06-8 16 | 17 | Notes: 18 | 19 | --*/ 20 | 21 | #ifndef Z3_H_ 22 | #define Z3_H_ 23 | 24 | #include 25 | #include "z3_macros.h" 26 | #include "z3_api.h" 27 | #include "z3_ast_containers.h" 28 | #include "z3_algebraic.h" 29 | #include "z3_polynomial.h" 30 | #include "z3_rcf.h" 31 | #include "z3_fixedpoint.h" 32 | #include "z3_optimization.h" 33 | #include "z3_interp.h" 34 | #include "z3_fpa.h" 35 | #include "z3_spacer.h" 36 | #endif 37 | 38 | -------------------------------------------------------------------------------- /docs/z3-4.6.0-x64-ubuntu-16.04/include/z3_macros.h: -------------------------------------------------------------------------------- 1 | 2 | /*++ 3 | Copyright (c) 2015 Microsoft Corporation 4 | 5 | --*/ 6 | 7 | #ifndef Z3_bool_opt 8 | #define Z3_bool_opt Z3_bool 9 | #endif 10 | 11 | #ifndef Z3_API 12 | # ifdef __GNUC__ 13 | # define Z3_API __attribute__ ((visibility ("default"))) 14 | # else 15 | # define Z3_API 16 | # endif 17 | #endif 18 | 19 | #ifndef DEFINE_TYPE 20 | #define DEFINE_TYPE(T) typedef struct _ ## T *T 21 | #endif 22 | 23 | #ifndef DEFINE_VOID 24 | #define DEFINE_VOID(T) typedef void* T 25 | #endif 26 | -------------------------------------------------------------------------------- /docs/z3-4.6.0-x64-ubuntu-16.04/include/z3_polynomial.h: -------------------------------------------------------------------------------- 1 | /*++ 2 | Copyright (c) 2012 Microsoft Corporation 3 | 4 | Module Name: 5 | 6 | z3_polynomial.h 7 | 8 | Abstract: 9 | 10 | Additional APIs for polynomials. 11 | 12 | Author: 13 | 14 | Leonardo de Moura (leonardo) 2012-12-09 15 | 16 | Notes: 17 | 18 | --*/ 19 | 20 | #ifndef Z3_POLYNOMIAL_H_ 21 | #define Z3_POLYNOMIAL_H_ 22 | 23 | #ifdef __cplusplus 24 | extern "C" { 25 | #endif // __cplusplus 26 | 27 | /** \defgroup capi C API */ 28 | /*@{*/ 29 | 30 | 31 | /** @name Polynomials */ 32 | /*@{*/ 33 | 34 | /** 35 | \brief Return the nonzero subresultants of \c p and \c q with respect to the "variable" \c x. 36 | 37 | \pre \c p, \c q and \c x are Z3 expressions where \c p and \c q are arithmetic terms. 38 | Note that, any subterm that cannot be viewed as a polynomial is assumed to be a variable. 39 | Example: f(a) is a considered to be a variable in the polynomial 40 | 41 | f(a)*f(a) + 2*f(a) + 1 42 | 43 | def_API('Z3_polynomial_subresultants', AST_VECTOR, (_in(CONTEXT), _in(AST), _in(AST), _in(AST))) 44 | */ 45 | Z3_ast_vector Z3_API Z3_polynomial_subresultants(Z3_context c, Z3_ast p, Z3_ast q, Z3_ast x); 46 | 47 | 48 | /*@}*/ 49 | /*@}*/ 50 | 51 | #ifdef __cplusplus 52 | } 53 | #endif // __cplusplus 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /docs/z3-4.6.0-x64-ubuntu-16.04/include/z3_v1.h: -------------------------------------------------------------------------------- 1 | /*++ 2 | Copyright (c) 2011 Microsoft Corporation 3 | 4 | Module Name: 5 | 6 | z3_v1.h 7 | 8 | Abstract: 9 | 10 | Z3 1.x backwards compatibility macros. 11 | These macros are used to simulate the Z3 API using in the 1.x versions. 12 | This file should only be used by users still using the Z3 1.x API. 13 | 14 | Author: 15 | 16 | Leonardo de Moura (leonardo) 2011-09-22 17 | 18 | Notes: 19 | 20 | --*/ 21 | #ifndef Z3_V1_H_ 22 | #define Z3_V1_H_ 23 | 24 | #include "api/z3.h" 25 | 26 | // Backwards compatibility 27 | #define Z3_type_ast Z3_sort 28 | #define Z3_const_decl_ast Z3_func_decl 29 | #define Z3_const Z3_app 30 | #define Z3_pattern_ast Z3_pattern 31 | #define Z3_UNINTERPRETED_TYPE Z3_UNINTERPRETED_SORT 32 | #define Z3_BOOL_TYPE Z3_BOOL_SORT 33 | #define Z3_INT_TYPE Z3_INT_SORT 34 | #define Z3_REAL_TYPE Z3_REAL_SORT 35 | #define Z3_BV_TYPE Z3_BV_SORT 36 | #define Z3_ARRAY_TYPE Z3_ARRAY_SORT 37 | #define Z3_TUPLE_TYPE Z3_DATATYPE_SORT 38 | #define Z3_UNKNOWN_TYPE Z3_UNKNOWN_SORT 39 | #define Z3_CONST_DECL_AST Z3_FUNC_DECL_AST 40 | #define Z3_TYPE_AST Z3_SORT_AST 41 | #define Z3_SORT_ERROR Z3_TYPE_ERROR 42 | #define Z3_mk_uninterpreted_type Z3_mk_uninterpreted_sort 43 | #define Z3_mk_bool_type Z3_mk_bool_sort 44 | #define Z3_mk_int_type Z3_mk_int_sort 45 | #define Z3_mk_real_type Z3_mk_real_sort 46 | #define Z3_mk_bv_type Z3_mk_bv_sort 47 | #define Z3_mk_array_type Z3_mk_array_sort 48 | #define Z3_mk_tuple_type Z3_mk_tuple_sort 49 | #define Z3_get_type Z3_get_sort 50 | #define Z3_get_pattern_ast Z3_get_pattern 51 | #define Z3_get_type_kind Z3_get_sort_kind 52 | #define Z3_get_type_name Z3_get_sort_name 53 | #define Z3_get_bv_type_size Z3_get_bv_sort_size 54 | #define Z3_get_array_type_domain Z3_get_array_sort_domain 55 | #define Z3_get_array_type_range Z3_get_array_sort_range 56 | #define Z3_get_tuple_type_num_fields Z3_get_tuple_sort_num_fields 57 | #define Z3_get_tuple_type_field_decl Z3_get_tuple_sort_field_decl 58 | #define Z3_get_tuple_type_mk_decl Z3_get_tuple_sort_mk_decl 59 | #define Z3_to_const_ast Z3_to_app 60 | #define Z3_get_numeral_value_string Z3_get_numeral_string 61 | #define Z3_get_const_ast_decl Z3_get_app_decl 62 | #define Z3_get_value Z3_eval_func_decl 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /fix_git.sh: -------------------------------------------------------------------------------- 1 | # Sooo... If you want to git checkout different branches, you need to update the git repo to fetch ALL sources 2 | git config --local --add remote.origin.fetch +refs/heads/*:refs/remotes/origin/* 3 | -------------------------------------------------------------------------------- /pySym/Colorer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | import logging 4 | # now we patch Python code to add color support to logging.StreamHandler 5 | def add_coloring_to_emit_windows(fn): 6 | # add methods we need to the class 7 | def _out_handle(self): 8 | import ctypes 9 | return ctypes.windll.kernel32.GetStdHandle(self.STD_OUTPUT_HANDLE) 10 | out_handle = property(_out_handle) 11 | 12 | def _set_color(self, code): 13 | import ctypes 14 | # Constants from the Windows API 15 | self.STD_OUTPUT_HANDLE = -11 16 | hdl = ctypes.windll.kernel32.GetStdHandle(self.STD_OUTPUT_HANDLE) 17 | ctypes.windll.kernel32.SetConsoleTextAttribute(hdl, code) 18 | 19 | setattr(logging.StreamHandler, '_set_color', _set_color) 20 | 21 | def new(*args): 22 | FOREGROUND_BLUE = 0x0001 # text color contains blue. 23 | FOREGROUND_GREEN = 0x0002 # text color contains green. 24 | FOREGROUND_RED = 0x0004 # text color contains red. 25 | FOREGROUND_INTENSITY = 0x0008 # text color is intensified. 26 | FOREGROUND_WHITE = FOREGROUND_BLUE|FOREGROUND_GREEN |FOREGROUND_RED 27 | # winbase.h 28 | STD_INPUT_HANDLE = -10 29 | STD_OUTPUT_HANDLE = -11 30 | STD_ERROR_HANDLE = -12 31 | 32 | # wincon.h 33 | FOREGROUND_BLACK = 0x0000 34 | FOREGROUND_BLUE = 0x0001 35 | FOREGROUND_GREEN = 0x0002 36 | FOREGROUND_CYAN = 0x0003 37 | FOREGROUND_RED = 0x0004 38 | FOREGROUND_MAGENTA = 0x0005 39 | FOREGROUND_YELLOW = 0x0006 40 | FOREGROUND_GREY = 0x0007 41 | FOREGROUND_INTENSITY = 0x0008 # foreground color is intensified. 42 | 43 | BACKGROUND_BLACK = 0x0000 44 | BACKGROUND_BLUE = 0x0010 45 | BACKGROUND_GREEN = 0x0020 46 | BACKGROUND_CYAN = 0x0030 47 | BACKGROUND_RED = 0x0040 48 | BACKGROUND_MAGENTA = 0x0050 49 | BACKGROUND_YELLOW = 0x0060 50 | BACKGROUND_GREY = 0x0070 51 | BACKGROUND_INTENSITY = 0x0080 # background color is intensified. 52 | 53 | levelno = args[1].levelno 54 | if(levelno>=50): 55 | color = BACKGROUND_YELLOW | FOREGROUND_RED | FOREGROUND_INTENSITY | BACKGROUND_INTENSITY 56 | elif(levelno>=40): 57 | color = FOREGROUND_RED | FOREGROUND_INTENSITY 58 | elif(levelno>=30): 59 | color = FOREGROUND_YELLOW | FOREGROUND_INTENSITY 60 | elif(levelno>=20): 61 | color = FOREGROUND_GREEN 62 | elif(levelno>=10): 63 | color = FOREGROUND_MAGENTA 64 | else: 65 | color = FOREGROUND_WHITE 66 | args[0]._set_color(color) 67 | 68 | ret = fn(*args) 69 | args[0]._set_color( FOREGROUND_WHITE ) 70 | #print "after" 71 | return ret 72 | return new 73 | 74 | def add_coloring_to_emit_ansi(fn): 75 | # add methods we need to the class 76 | def new(*args): 77 | levelno = args[1].levelno 78 | if(levelno>=50): 79 | color = '\x1b[31m' # red 80 | elif(levelno>=40): 81 | color = '\x1b[31m' # red 82 | elif(levelno>=30): 83 | color = '\x1b[33m' # yellow 84 | elif(levelno>=20): 85 | color = '\x1b[32m' # green 86 | elif(levelno>=10): 87 | color = '\x1b[35m' # pink 88 | else: 89 | color = '\x1b[0m' # normal 90 | args[1].msg = color + args[1].msg + '\x1b[0m' # normal 91 | #print "after" 92 | return fn(*args) 93 | return new 94 | 95 | import platform 96 | if platform.system()=='Windows': 97 | # Windows does not support ANSI escapes and we are using API calls to set the console color 98 | logging.StreamHandler.emit = add_coloring_to_emit_windows(logging.StreamHandler.emit) 99 | else: 100 | # all non-Windows platforms are supporting ANSI escapes so we use them 101 | logging.StreamHandler.emit = add_coloring_to_emit_ansi(logging.StreamHandler.emit) 102 | #log = logging.getLogger() 103 | #log.addFilter(log_filter()) 104 | #//hdlr = logging.StreamHandler() 105 | #//hdlr.setFormatter(formatter()) 106 | -------------------------------------------------------------------------------- /pySym/Config.py: -------------------------------------------------------------------------------- 1 | # This file will house generic PySym config settings 2 | 3 | PYSYM_MAX_SYM_LIST_SPLIT=256 4 | -------------------------------------------------------------------------------- /pySym/Factory.py: -------------------------------------------------------------------------------- 1 | import logging 2 | logger = logging.getLogger("Factory") 3 | 4 | import ast 5 | import enforce 6 | 7 | from .pyPath import Path 8 | from .pyPathGroup import PathGroup 9 | 10 | #@enforce.runtime_validation 11 | class Factory: 12 | 13 | __slots__ = ['__project','__weakref__'] 14 | 15 | def __init__(self, project): 16 | self._project = project 17 | 18 | def path(self) -> Path: 19 | """pySym.pyPath.Path: Path object for this project.""" 20 | 21 | # Read in the file 22 | with open(self._project.file_name, "r") as f: 23 | source = f.read() 24 | 25 | # Parse it 26 | body = ast.parse(source).body 27 | 28 | # Return the new path 29 | return Path(body,source=source,project=self._project) 30 | 31 | def path_group(self, *args, **kwargs) -> PathGroup: 32 | """pySym.pyPathGroup.PathGroup: Basic PathGroup object for this project.""" 33 | kwargs['project'] = self._project 34 | return PathGroup(self.path(), *args, **kwargs) 35 | 36 | ############## 37 | # Properties # 38 | ############## 39 | 40 | @property 41 | def _project(self): 42 | """pySym.Project.Project: Associated Project object.""" 43 | return self.__project 44 | 45 | @_project.setter 46 | def _project(self, project) -> None: 47 | if type(project) is not Project: 48 | raise Exception("Invalid type for project ({0}) should be type Project".format(type(project))) 49 | 50 | self.__project = project 51 | 52 | from .Project import Project 53 | -------------------------------------------------------------------------------- /pySym/Project.py: -------------------------------------------------------------------------------- 1 | import logging 2 | logger = logging.getLogger("Project") 3 | from . import Colorer 4 | 5 | import enforce 6 | import os 7 | import types 8 | 9 | #@enforce.runtime_validation 10 | class Project: 11 | 12 | __slots__ = ['__file_name', '__factory', '__weakref__', '__hooks'] 13 | 14 | def __init__(self, file, debug=False): 15 | 16 | if debug: 17 | logging.basicConfig(level=logging.DEBUG) 18 | 19 | self.file_name = file 20 | self.factory = Factory(self) 21 | self._hooks = {} 22 | 23 | def hook(self, address, callback): 24 | """Registers pySym to hook address and call the callback when hit. 25 | 26 | Callback function will be called with the current state as the first parameter. 27 | 28 | Args: 29 | address (int): Line number of the source code to hook this callback to. 30 | callback (types.FunctionType): Function to call when line number is hit. 31 | 32 | Example: 33 | >>> def my_callback(state): 34 | print(state) 35 | >>> project.hook(12, my_callback) 36 | """ 37 | assert type(address) is int, "Unexpected address type of {}".format(type(address)) 38 | assert type(callback) is types.FunctionType, "Unexpected callback type of {}".format(type(callback)) 39 | 40 | # TODO: Sanity check that the number is within source range and that there's an instruction at that location 41 | self._hooks[address] = callback 42 | 43 | ############## 44 | # Properties # 45 | ############## 46 | 47 | @property 48 | def _hooks(self): 49 | """dict: Dictionary of registered hooks.""" 50 | return self.__hooks 51 | 52 | @_hooks.setter 53 | def _hooks(self, hooks): 54 | assert isinstance(hooks, dict), "Unexpected type for hooks of {}".format(type(hooks)) 55 | self.__hooks = hooks 56 | 57 | @property 58 | def factory(self): 59 | return self.__factory 60 | 61 | @factory.setter 62 | def factory(self, factory) -> None: 63 | self.__factory = factory 64 | 65 | @property 66 | def file_name(self) -> str: 67 | """str: Name of the file that's being symbolically executed.""" 68 | return self.__file_name 69 | 70 | @file_name.setter 71 | def file_name(self, file_name: str) -> None: 72 | file_name = os.path.abspath(file_name) 73 | 74 | # Make sure this is a real file. 75 | if not os.path.isfile(file_name): 76 | raise Exception("Not a valid file: {file_name:s}".format(file_name=file_name)) 77 | 78 | self.__file_name = file_name 79 | 80 | from .Factory import Factory 81 | -------------------------------------------------------------------------------- /pySym/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from .Project import Project 4 | 5 | """ 6 | import ast 7 | import argparse 8 | import logging 9 | import symbolicExecutor 10 | from pySym import Colorer 11 | 12 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 13 | logger = logging.getLogger('main') 14 | 15 | 16 | parser = argparse.ArgumentParser(description='Symbolically Execute A Python Script.') 17 | parser.add_argument('script', type=str, nargs=1, 18 | help='Script file name') 19 | args = parser.parse_args() 20 | 21 | #print(args) 22 | script = args.script[0] 23 | 24 | # Load it 25 | logger.debug("Loading script {0}".format(script)) 26 | with open(script,"r") as f: 27 | body = ast.parse(f.read()).body 28 | 29 | # Run it 30 | symbolicExecutor.runBody(body) 31 | """ 32 | -------------------------------------------------------------------------------- /pySym/ast_parse.py: -------------------------------------------------------------------------------- 1 | import ast 2 | from copy import copy 3 | 4 | def astCopy(self): 5 | new = self.__class__() 6 | 7 | #pypy has trouble writing to dict in this way :-( 8 | #new.__dict__ = {x: copy(getattr(self,x)) for x in self.__dict__} 9 | 10 | for attr in self.__dict__: 11 | setattr(new, attr, copy(getattr(self,attr))) 12 | 13 | return new 14 | 15 | 16 | for t in ['If','While','Compare','Return','For', "Assign", "AugAssign","BinOp"]: 17 | getattr(ast,t).__copy__ = astCopy 18 | 19 | def parse(s): 20 | """ 21 | Parse string into python AST. Note that this needs to be separate due to hooking that I am performing on the objects. 22 | Returns: ast 23 | """ 24 | return ast.parse(s) 25 | -------------------------------------------------------------------------------- /pySym/pyObjectManager/decorators.py: -------------------------------------------------------------------------------- 1 | def as_clone(orig_func): 2 | def run_from_clone(self, *args, **kwargs): 3 | # Transparently run from clone object if we have one 4 | if self._clone is not None: 5 | return getattr(self._clone,orig_func.__name__)(*args, **kwargs) 6 | 7 | # We're not a clone, run the original 8 | else: 9 | return orig_func(self, *args, **kwargs) 10 | 11 | return run_from_clone 12 | 13 | # TODO: Probably should just make this all one decorator with an arg or something. 14 | def as_clone_property(orig_func): 15 | def run_from_clone(self, *args, **kwargs): 16 | # Transparently run from clone object if we have one 17 | if self._clone is not None: 18 | return getattr(self._clone,orig_func.__name__) 19 | 20 | # We're not a clone, run the original 21 | else: 22 | return orig_func(self, *args, **kwargs) 23 | 24 | return run_from_clone 25 | -------------------------------------------------------------------------------- /pySym/pyPath.py: -------------------------------------------------------------------------------- 1 | import z3 2 | import ast 3 | import logging 4 | from .pyState import State 5 | from .Project import Project 6 | from prettytable import PrettyTable 7 | import sys 8 | from copy import copy 9 | from random import random 10 | 11 | logger = logging.getLogger("Path") 12 | 13 | class Path(): 14 | """ 15 | Defines a path of execution. 16 | """ 17 | 18 | __slots__ = ['backtrace','state','source','error','__weakref__','__project'] 19 | 20 | def __init__(self,path=None,backtrace=None,state=None,source=None,project=None): 21 | """ 22 | (optional) path = list of sequential actions. Derived by ast.parse. Passed to state. 23 | (optional) backtrace = list of asts that happened before the current one 24 | (optional) state = State object for current path 25 | (optional) source = source code that we're looking at. This can make things prettier 26 | (optional) project = pySym project file associated with this group. This will be auto-filled. 27 | """ 28 | 29 | self._project = project 30 | path = [] if path is None else path 31 | self.backtrace = [] if backtrace is None else backtrace 32 | self.state = State(path=path,project=self._project) if state is None else state 33 | self.source = source 34 | 35 | def step(self): 36 | """ 37 | Move the current path forward by one step 38 | Note, this actually makes a copy/s and returns them. The initial path isn't modified. 39 | Returns: A list of paths or empty list if the path is done 40 | """ 41 | 42 | # Step-it 43 | stateList = self.state.step() 44 | 45 | pathList = [] 46 | 47 | for state in stateList: 48 | # New path. State should already be copied via state.step above. 49 | path = self.copy(state=state) 50 | 51 | # New state 52 | #path.state = state 53 | 54 | pathList.append(path) 55 | 56 | return pathList 57 | 58 | def printBacktrace(self): 59 | """ 60 | Convinence function to print out what we've executed so far 61 | """ 62 | source = self.source 63 | source = source.split("\n") if source != None else None 64 | 65 | table = PrettyTable(header=False,border=False,field_names=["lineno","line","element"]) 66 | table.align = 'l' 67 | 68 | for inst in self.state.backtrace[::-1]: 69 | table.add_row([ 70 | "Line {0}".format(inst.lineno), 71 | source[inst.lineno-1] if source != None else " ", 72 | inst]) 73 | 74 | print(table) 75 | 76 | def copy(self, state=None): 77 | """ 78 | Input: 79 | (optional) state == pyState object to use instead of copying the current state. 80 | Action: 81 | Create a copy of the current Path object 82 | Returns: 83 | Copy of the path 84 | """ 85 | # TODO: Don't think i need to copy state in this... 86 | return Path( 87 | backtrace=copy(self.backtrace), 88 | state=self.state.copy() if state is None else state, 89 | source=copy(self.source), 90 | project=self._project 91 | ) 92 | 93 | def __copy__(self): 94 | return self.copy() 95 | 96 | @property 97 | def _project(self): 98 | """pySym Project that this is associated with.""" 99 | return self.__project 100 | 101 | @_project.setter 102 | def _project(self, project): 103 | assert isinstance(project, (Project, type(None))), "Invalid type for Project of {}".format(type(project)) 104 | self.__project = project 105 | -------------------------------------------------------------------------------- /pySym/pyState/Assert.py: -------------------------------------------------------------------------------- 1 | import logging 2 | logger = logging.getLogger("pyState:Assert") 3 | 4 | import z3 5 | import ast 6 | from . import Compare, BoolOp, ReturnObject 7 | from copy import copy 8 | 9 | 10 | def handle(state,element,ctx=None): 11 | """Attempt to handle the Python Assert element 12 | 13 | Parameters 14 | ---------- 15 | state : pyState.State 16 | pyState.State object to handle this element under 17 | element : ast.Assert 18 | element from source to be handled 19 | ctx : int, optional 20 | `ctx` is an optional input to specify a context to be used 21 | when resolving this ast object 22 | 23 | 24 | Returns 25 | ------- 26 | list 27 | list contains state objects either generated or discovered through 28 | handling this ast. 29 | 30 | 31 | This function handles calls to ast.Assert. It is not meant to be 32 | called manually via a user. Under the hood, it resolves the conitional 33 | arguments, then asserts the truth of that statement on the state. 34 | 35 | 36 | Example 37 | ------- 38 | Example of ast.Assert is: assert x > 5 39 | """ 40 | 41 | # element.msg -- what to evaluate if assertion is wrong. It doesn't have to be a string, just some expression. 42 | 43 | # Check what type of test this is 44 | 45 | # Example: assert 4 > 2 46 | if type(element.test) == ast.Compare: 47 | constraints = Compare.handle(state, element.test, ctx=ctx) 48 | 49 | else: 50 | raise Exception("Assert: Unknown test type of '{0}'".format(type(element.test))) 51 | 52 | """ 53 | # Example: assert False 54 | # TODO: Need to add ast.NameConstant resolution to resolveObject before implementing this. 55 | elif type(element.test) == ast.NameConstant: 56 | import IPython 57 | IPython.embed() 58 | exit(0) 59 | """ 60 | 61 | #elif type(element.test) == ast.UnaryOp: 62 | # trueConstraint = pyState.UnaryOp.handle(state, element.test) 63 | # # This returns pyObjectManager objects, need to resolve the 64 | # trueConstraint = [[x for x in constraint.state.assertions()][-1] for constraint in trueConstraint] 65 | 66 | # Resolve calls if we need to 67 | retObjs = [x.state for x in constraints if type(x) is ReturnObject] 68 | if len(retObjs) > 0: 69 | return retObjs 70 | 71 | state.addConstraint(*constraints) 72 | 73 | # Not waiting on anything, move forward 74 | state.path.pop(0) 75 | 76 | return [state] 77 | -------------------------------------------------------------------------------- /pySym/pyState/BoolOp.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import z3 3 | import ast 4 | from .. import pyState 5 | from . import Compare 6 | 7 | logger = logging.getLogger("pyState:BoolOp") 8 | 9 | def _handle(state,op,values,ifSideConstraints=None): 10 | ifSideConstraints = [] if ifSideConstraints is None else ifSideConstraints 11 | 12 | # Loop through our requested checks 13 | for value in values: 14 | if type(value) is ast.Compare: 15 | ifSide = Compare.handle(state,value) 16 | 17 | # Normalize 18 | ifSide = [ifSide] if type(ifSide) is not list else ifSide 19 | 20 | # Resolve calls if we need to 21 | retObjs = [x for x in ifSide if type(x) is pyState.ReturnObject] 22 | if len(retObjs) > 0: 23 | return retObjs 24 | 25 | 26 | # Recursively build this 27 | v = values[:] 28 | v.pop(0) 29 | ret = [] 30 | for i in ifSide: 31 | ret += _handle(state,op,v,ifSideConstraints + [i]) 32 | return ret 33 | 34 | else: 35 | err = "handle: Don't know how to handle type '{0}' at line {1} column {2}".format(type(value),value.lineno,value.col_offset) 36 | logger.error(err) 37 | raise Exception(err) 38 | 39 | # Change the checks into a Z3 Expression 40 | if type(op) is ast.And: 41 | ifSide = z3.And(ifSideConstraints) 42 | return [ifSide] 43 | 44 | elif type(op) is ast.Or: 45 | ifSide = z3.Or(ifSideConstraints) 46 | return [ifSide] 47 | 48 | else: 49 | err = "handle: Don't know how to handle op type '{0}' at line {1} column {2}".format(type(op),element.lineno,element.col_offset) 50 | logger.error(err) 51 | raise Exception(err) 52 | 53 | 54 | def handle(state, element): 55 | """Attempt to handle the Python BoolOp element 56 | 57 | Parameters 58 | ---------- 59 | state : pyState.State 60 | pyState.State object to handle this element under 61 | element : ast.BoolOp 62 | element from source to be handled 63 | 64 | Returns 65 | ------- 66 | list 67 | list contains state objects either generated or discovered through 68 | handling this ast. 69 | 70 | 71 | This function handles calls to BoolOp. It is not meant to be called 72 | manually via a user. 73 | 74 | 75 | Example 76 | ------- 77 | Example of ast.BoolOp is: x == 1 and y == 2 78 | """ 79 | 80 | assert type(element) == ast.BoolOp 81 | 82 | op = element.op 83 | 84 | values = element.values 85 | 86 | return _handle(state,op,values) 87 | -------------------------------------------------------------------------------- /pySym/pyState/Break.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import z3 3 | import ast 4 | from .. import pyState 5 | 6 | logger = logging.getLogger("pyState:Break") 7 | 8 | def handle(state,element): 9 | """Attempt to handle the Python Break element 10 | 11 | Parameters 12 | ---------- 13 | state : pyState.State 14 | pyState.State object to handle this element under 15 | element : ast.Break 16 | element from source to be handled 17 | 18 | Returns 19 | ------- 20 | list 21 | list contains state objects either generated or discovered through handling this ast. 22 | 23 | 24 | This function handles calls to Break. It is not meant to be called 25 | manually via a user. Under the hood, it simply pops off the call stack 26 | until a loop change is seen (i.e.: we've left the for loop) 27 | 28 | 29 | Example 30 | ------- 31 | Example of ast.Break is: break 32 | """ 33 | 34 | assert type(state) == pyState.State 35 | assert type(element) == ast.Break 36 | 37 | # We could be in a few levels of if/else statements. Pop back up to the loop 38 | while state.loop == None: 39 | state.popCallStack() 40 | 41 | # Good to go, pop out of our loop 42 | state.popCallStack() 43 | 44 | return [state] 45 | 46 | -------------------------------------------------------------------------------- /pySym/pyState/Expr.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import z3 3 | import ast 4 | from .. import pyState 5 | from . import Call, ReturnObject 6 | 7 | logger = logging.getLogger("pyState:Expr") 8 | 9 | def handle(state,element): 10 | """Attempt to handle the Python Expr element 11 | 12 | Parameters 13 | ---------- 14 | state : pyState.State 15 | pyState.State object to handle this element under 16 | element : ast.Expr 17 | element from source to be handled 18 | 19 | 20 | Returns 21 | ------- 22 | list 23 | list contains state objects either generated or discovered through 24 | handling this ast. 25 | 26 | 27 | This function handles calls to ast.Expr. It is not meant to be called 28 | manually via a user. 29 | 30 | 31 | Example 32 | ------- 33 | Example of ast.Expr is: test() (Note no assignment for call. This makes it 34 | an expression) 35 | """ 36 | 37 | assert type(state) == pyState.State 38 | assert type(element) == ast.Expr 39 | 40 | # What is this expression? 41 | value = element.value 42 | 43 | if type(value) == ast.Call: 44 | ret = state.resolveObject(value) 45 | 46 | # Normalize 47 | ret = [ret] if type(ret) is not list else ret 48 | 49 | # Check for return object. Return all applicable 50 | retObjs = [x.state for x in ret if type(x) is pyState.ReturnObject] 51 | if len(retObjs) > 0: 52 | return retObjs 53 | 54 | states = [x for x in ret if type(x) is pyState.State] 55 | 56 | if len(states) > 0: 57 | return states 58 | 59 | # Don't really care about the return object for now... Maybe later? 60 | # A str expression is just a multi-line comment. Ignore 61 | elif type(value) in [ReturnObject, ast.Str]: 62 | pass 63 | 64 | else: 65 | err = "Expr: Don't know how to handle expr type {0} at line {1} col {2}".format(type(value),value.lineno,value.col_offset) 66 | logger.error(err) 67 | raise Exception(err) 68 | 69 | 70 | state.path.pop(0) 71 | return [state] 72 | 73 | -------------------------------------------------------------------------------- /pySym/pyState/FunctionDef.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import z3 3 | import ast 4 | from .. import pyState 5 | 6 | logger = logging.getLogger("pyState:FunctionDef") 7 | 8 | def handle(state,element): 9 | """Attempt to handle the Python FunctionDef element 10 | 11 | Parameters 12 | ---------- 13 | state : pyState.State 14 | pyState.State object to handle this element under 15 | element : ast.FunctionDef 16 | element from source to be handled 17 | 18 | 19 | Returns 20 | ------- 21 | list 22 | list contains state objects either generated or discovered through 23 | handling this ast. 24 | 25 | 26 | This function handles calls to ast.FunctionDef. It is not meant to be called 27 | manually via a user. Under the hood, it registers this function with the 28 | `state` object so that when it's referenced later it can be found. 29 | 30 | 31 | Example 32 | ------- 33 | Example of ast.FunctionDef is: def test(): 34 | """ 35 | 36 | assert type(state) == pyState.State 37 | assert type(element) == ast.FunctionDef 38 | 39 | state.registerFunction(element) 40 | 41 | # Pop instruction 42 | state.path.pop(0) 43 | 44 | # Return state 45 | return [state] 46 | -------------------------------------------------------------------------------- /pySym/pyState/GeneratorExp.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import z3 3 | import ast 4 | from ..pyObjectManager.Int import Int 5 | from ..pyObjectManager.Real import Real 6 | from ..pyObjectManager.BitVec import BitVec 7 | from ..pyObjectManager.List import List 8 | from .. import pyState 9 | from . import ListComp 10 | 11 | logger = logging.getLogger("pyState:GeneratorExp") 12 | 13 | #import astunparse 14 | 15 | 16 | def handle(state,element,ctx=None): 17 | """Attempt to handle the Python GeneratorExp element 18 | 19 | Parameters 20 | ---------- 21 | state : pyState.State 22 | pyState.State object to handle this element under 23 | element : ast.GeneratorExp 24 | element from source to be handled 25 | 26 | 27 | Returns 28 | ------- 29 | list 30 | list contains state objects either generated or discovered through 31 | handling this ast. 32 | 33 | 34 | This function handles calls to ast.GeneratorExp. It is not meant to be 35 | called manually via a user. Under the hood, it converts the generator 36 | expression into a list comprehension and calls the handler for list 37 | comprehension. 38 | 39 | 40 | Example 41 | ------- 42 | Example of ast.GeneratorExp is: x for x in [1,2,3] (note it's not inside 43 | List Comprehension brackets) 44 | """ 45 | 46 | assert type(element) is ast.GeneratorExp 47 | 48 | ctx = state.ctx if ctx is None else ctx 49 | 50 | # NOTE: Maybe there are cases where we don't want the GeneratorExp to be turned into ListComp? 51 | 52 | # Create a skelleton ListComp 53 | listComp = ast.parse("[x for x in []]").body[0].value 54 | 55 | # Pop in our generator 56 | listComp.generators = element.generators 57 | 58 | # Pop in our element 59 | listComp.elt = element.elt 60 | 61 | # Make the switch 62 | pyState.replaceObjectWithObject(state.path[0],element,listComp) 63 | 64 | #print(astunparse.unparse(element)) 65 | #print(astunparse.unparse(listComp)) 66 | 67 | # Call ListComp to handle this 68 | return ListComp.handle(state,listComp,ctx=ctx) 69 | 70 | 71 | -------------------------------------------------------------------------------- /pySym/pyState/Pass.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import z3 3 | import ast 4 | from .. import pyState 5 | 6 | logger = logging.getLogger("pyState:Pass") 7 | 8 | def handle(state,element): 9 | """Attempt to handle the Python Pass element 10 | 11 | Parameters 12 | ---------- 13 | state : pyState.State 14 | pyState.State object to handle this element under 15 | element : ast.Pass 16 | element from source to be handled 17 | 18 | 19 | Returns 20 | ------- 21 | list 22 | list contains state objects either generated or discovered through 23 | handling this ast. 24 | 25 | 26 | This function handles calls to ast.Pass. It is not meant to be 27 | called manually via a user. Under the hood, it very simply pops off the 28 | current instruction and returns the updated state object as a list. 29 | 30 | 31 | Example 32 | ------- 33 | Example of ast.Pass is: pass 34 | """ 35 | 36 | 37 | state.path.pop(0) 38 | 39 | return [state] 40 | -------------------------------------------------------------------------------- /pySym/pyState/Return.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import z3 3 | import ast 4 | from .. import pyState 5 | 6 | logger = logging.getLogger("pyState:Return") 7 | 8 | def handle(state,element): 9 | """Attempt to handle the Python Return element 10 | 11 | Parameters 12 | ---------- 13 | state : pyState.State 14 | pyState.State object to handle this element under 15 | element : ast.Return 16 | element from source to be handled 17 | 18 | 19 | Returns 20 | ------- 21 | list 22 | list contains state objects either generated or discovered through 23 | handling this ast. 24 | 25 | 26 | This function handles calls to ast.Return. It is not meant to be 27 | called manually via a user. Under the hood, it resolves the return element, 28 | sets the ReturnObject, and updates the state. 29 | 30 | 31 | Example 32 | ------- 33 | Example of ast.Return is: return x 34 | """ 35 | 36 | 37 | assert type(state) == pyState.State 38 | assert type(element) == ast.Return 39 | 40 | ret = state.Return(element) 41 | 42 | logger.debug("handle: ret value = {0}".format(ret)) 43 | 44 | # Normalize 45 | ret = [ret] if type(ret) is not list else ret 46 | 47 | # Check for return object. Return all applicable 48 | retObjs = [x.state for x in ret if type(x) is pyState.ReturnObject] 49 | if len(retObjs) > 0: 50 | return retObjs 51 | 52 | # Asserting 1 thing to return for now 53 | assert len(ret) == 1 54 | obj = ret[0] 55 | 56 | state = obj.state if obj is not None else state 57 | 58 | # Pop callstacks until we change context 59 | leavingCtx = state.ctx 60 | 61 | # Pop until we've left 62 | while leavingCtx == state.ctx: 63 | 64 | state.popCallStack() 65 | 66 | return [state] 67 | 68 | -------------------------------------------------------------------------------- /pySym/pyState/UnaryOp.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import z3 3 | import ast 4 | from .. import pyState 5 | from ..pyObjectManager.Int import Int 6 | from ..pyObjectManager.Real import Real 7 | from ..pyObjectManager.BitVec import BitVec 8 | 9 | logger = logging.getLogger("pyState:UnaryOp") 10 | 11 | def handle(state,element,ctx=None): 12 | """Attempt to handle the Python UnaryOp element 13 | 14 | Parameters 15 | ---------- 16 | state : pyState.State 17 | pyState.State object to handle this element under 18 | element : ast.UnaryOp 19 | element from source to be handled 20 | ctx : int , optional 21 | Context to resolve this UnaryOp in (default is current context) 22 | 23 | 24 | Returns 25 | ------- 26 | list 27 | list contains state objects either generated or discovered through 28 | handling this ast. 29 | 30 | 31 | This function handles calls to ast.UnaryOp. It is not meant to be 32 | called manually via a user. 33 | 34 | 35 | Example 36 | ------- 37 | Example of ast.UnaryOp is: not True 38 | """ 39 | 40 | ctx = state.ctx if ctx is None else ctx 41 | 42 | assert type(state) == pyState.State 43 | assert type(element) == ast.UnaryOp 44 | 45 | op = element.op 46 | targets = state.resolveObject(element.operand) 47 | 48 | ret = [] 49 | 50 | for target in targets: 51 | 52 | # Use the target's state 53 | state = target.state 54 | 55 | if type(target) not in [Int, Real, BitVec]: 56 | err = "handle: unable to resolve UnaryOp target type '{0}'".format(type(target)) 57 | logger.error(err) 58 | raise Exception(err) 59 | 60 | # Get a new variable 61 | t,args = pyState.duplicateSort(target) 62 | newVar = state.getVar("tempUnaryOp",varType=t,kwargs=args) 63 | newVar.increment() 64 | 65 | if type(op) == ast.USub: 66 | # Optimize if we can 67 | if target.isStatic(): 68 | newVar.setTo(target.getValue() * -1) 69 | else: 70 | state.addConstraint(newVar.getZ3Object() == -target.getZ3Object()) 71 | 72 | elif type(op) == ast.UAdd: 73 | #state.addConstraint(newVar.getZ3Object() == target.getZ3Object()) 74 | newVar.setTo(target) 75 | 76 | elif type(op) == ast.Not: 77 | # TODO: Verify functionality here... Should be able to optimize like I did with the other two, but need to check how "Not" is being dealt with 78 | state.addConstraint(newVar.getZ3Object() == z3.Not(target.getZ3Object())) 79 | 80 | elif type(op) == ast.Invert: 81 | err = "handle: Invert not implemented yet" 82 | logger.error(err) 83 | raise Exception(err) 84 | 85 | else: 86 | # We really shouldn't get here... 87 | err = "handle: {0} not implemented yet".format(type(op)) 88 | logger.error(err) 89 | raise Exception(err) 90 | 91 | ret.append(newVar.copy()) 92 | 93 | return ret 94 | -------------------------------------------------------------------------------- /pySym/pyState/While.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import z3 3 | import ast 4 | from . import Compare, ReturnObject 5 | from copy import copy 6 | import pickle 7 | 8 | logger = logging.getLogger("pyState:While") 9 | 10 | def _handle(stateIf,stateElse,element,ifConstraint): 11 | # Add the constraints 12 | if type(ifConstraint) is not bool or ifConstraint != True: 13 | stateIf.addConstraint(ifConstraint) 14 | if type(ifConstraint) is not bool or ifConstraint == True: 15 | stateElse.addConstraint(z3.Not(ifConstraint)) 16 | 17 | # Check if statement. We'll have at least one instruction here, so treat this as a call 18 | # Saving off the current path so we can return to it and pick up at the next instruction 19 | cs = copy(stateIf.path) 20 | # Only push our stack if it's not empty 21 | if len(cs) > 0: 22 | stateIf.pushCallStack(path=cs) 23 | 24 | # Our new path becomes the inside of the if statement 25 | stateIf.path = element.body 26 | 27 | # If state should get a copy of the loop we're now in 28 | stateIf.loop = copy(element) 29 | 30 | # Update the else's path 31 | # Check if there is an else path we need to take 32 | #if len(element.orelse) > 0: 33 | cs = copy(stateElse.path) 34 | if len(cs) > 0: 35 | stateElse.pushCallStack(path=cs) 36 | 37 | # else side should be done with the loop 38 | stateElse.loop = None 39 | 40 | stateElse.path = element.orelse 41 | 42 | return [stateIf, stateElse] 43 | 44 | 45 | def handle(state,element): 46 | """Attempt to handle the Python While element 47 | 48 | Parameters 49 | ---------- 50 | state : pyState.State 51 | pyState.State object to handle this element under 52 | element : ast.While 53 | element from source to be handled 54 | 55 | 56 | Returns 57 | ------- 58 | list 59 | list contains state objects either generated or discovered through 60 | handling this ast. 61 | 62 | 63 | This function handles calls to ast.While. It is not meant to be 64 | called manually via a user. 65 | 66 | 67 | Example 68 | ------- 69 | Example of ast.While is: while x < 10: 70 | """ 71 | 72 | 73 | # While is basically a repeated If statement, we want to take both sides 74 | 75 | stateIf = state 76 | ret = [] 77 | 78 | # Check what type of test this is 79 | if type(element.test) == ast.Compare: 80 | # Try to handle the compare 81 | ifConstraint = Compare.handle(stateIf,element.test) 82 | 83 | else: 84 | err = "handle: I don't know how to handle type {0}".format(type(element.test)) 85 | logger.error(err) 86 | raise Exception(err) 87 | 88 | # Normalize 89 | ifConstraint = ifConstraint if type(ifConstraint) is list else [ifConstraint] 90 | 91 | # See if we need to pass back a call 92 | retObjs = [x.state for x in ifConstraint if type(x) is ReturnObject] 93 | if len(retObjs) > 0: 94 | return retObjs 95 | 96 | # If we're good to go, pop the instruction 97 | stateIf.path.pop(0) 98 | 99 | # Loop through possible constraints 100 | for constraint in ifConstraint: 101 | 102 | ret += _handle(stateIf.copy(),stateIf.copy(),element,constraint) 103 | 104 | return ret 105 | -------------------------------------------------------------------------------- /pySym/pyState/functions/List/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bannsec/pySym/497b5d84e5e360ea57ceaf26d477d3fad1d4e6c8/pySym/pyState/functions/List/__init__.py -------------------------------------------------------------------------------- /pySym/pyState/functions/List/append.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from ....pyObjectManager.List import List 3 | from ....pyObjectManager.Int import Int 4 | from ....pyObjectManager.Real import Real 5 | from ....pyObjectManager.BitVec import BitVec 6 | from ....pyObjectManager.String import String 7 | from .... import pyState 8 | from copy import copy 9 | 10 | logger = logging.getLogger("pyState:SimFunction:List:append") 11 | 12 | 13 | def handle(state,call,var,ctx=None): 14 | """ 15 | Append var to list 16 | """ 17 | ctx = ctx if ctx is not None else state.ctx 18 | 19 | #print("Attempting to append {0} of type {1} from CTX {2}".format(var,type(var),ctx)) 20 | 21 | # Resolve what we're going to be appending 22 | varList = state.resolveObject(var,ctx=ctx) 23 | 24 | # If we're waiting on a symbolic call, return 25 | retObjs = [x for x in varList if type(x) is pyState.ReturnObject] 26 | if len(retObjs) > 0: 27 | return retObjs 28 | 29 | ret = [] 30 | 31 | for var in varList: 32 | s = var.state.copy() 33 | 34 | s.path.pop(0) 35 | 36 | # If we are given a List object, use that as root 37 | if type(call) is List: 38 | root = call 39 | 40 | # Resolve Root 41 | else: 42 | root = s.resolveObject(call.func.value,ctx=ctx) 43 | 44 | assert len(root) == 1 45 | root = root.pop() 46 | 47 | assert type(root) is List 48 | 49 | # Append it 50 | root.append(copy(var)) 51 | 52 | # Add this to our returns 53 | retObj = pyState.ReturnObject(1) 54 | retObj.state = s 55 | 56 | ret.append(retObj) 57 | 58 | return ret 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /pySym/pyState/functions/List/clear.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from ....pyObjectManager.List import List 3 | from ....pyObjectManager.Int import Int 4 | from ....pyObjectManager.Real import Real 5 | from ....pyObjectManager.BitVec import BitVec 6 | from ....pyObjectManager.String import String 7 | from .... import pyState 8 | 9 | logger = logging.getLogger("pyState:SimFunction:List:clear") 10 | 11 | 12 | def handle(state,call,ctx=None): 13 | """ 14 | Clear list 15 | """ 16 | ctx = ctx if ctx is not None else state.ctx 17 | 18 | # The "l" in "l.clear()" 19 | roots = state.resolveObject(call.func.value,ctx=ctx) 20 | 21 | # If we're waiting on a symbolic call (that'd be weird..), return 22 | retObjs = [x for x in roots if type(x) is pyState.ReturnObject] 23 | if len(retObjs) > 0: 24 | return retObjs 25 | 26 | # Not sure when we'd ever have multiple... 27 | assert len(roots) == 1 28 | 29 | root = roots[0] 30 | 31 | root.state.path.pop(0) 32 | 33 | root.increment() 34 | root.variables = [] 35 | 36 | return [root.state] 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /pySym/pyState/functions/List/insert.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from ....pyObjectManager.List import List 3 | from ....pyObjectManager.Int import Int 4 | from ....pyObjectManager.Real import Real 5 | from ....pyObjectManager.BitVec import BitVec 6 | from ....pyObjectManager.String import String 7 | from .... import pyState 8 | from copy import copy 9 | 10 | logger = logging.getLogger("pyState:SimFunction:List:insert") 11 | 12 | 13 | def handle(state,call,index,object,ctx=None): 14 | """ 15 | Insert object in a list at index 16 | """ 17 | ctx = ctx if ctx is not None else state.ctx 18 | 19 | # Resolve index 20 | indexList = state.resolveObject(index,ctx=ctx) 21 | 22 | # If we're waiting on a symbolic call, return 23 | retObjs = [x for x in indexList if type(x) is pyState.ReturnObject] 24 | if len(retObjs) > 0: 25 | return retObjs 26 | 27 | # Resolve what we're going to be inserting 28 | objList = state.resolveObject(object,ctx=ctx) 29 | 30 | # If we're waiting on a symbolic call, return 31 | retObjs = [x for x in objList if type(x) is pyState.ReturnObject] 32 | if len(retObjs) > 0: 33 | return retObjs 34 | 35 | ret = [] 36 | 37 | for obj in objList: 38 | 39 | for index in indexList: 40 | 41 | # Only static index for now 42 | if not index.isStatic(): 43 | err = "List.insert called with symbolic index. This is not supported right now." 44 | logger.error(err) 45 | raise Exception(err) 46 | 47 | s = obj.state.copy() 48 | 49 | s.path.pop(0) 50 | 51 | # Resolve Root 52 | root = s.resolveObject(call.func.value,ctx=ctx) 53 | 54 | assert len(root) == 1, "Unhandled root of length {}".format(len(root)) 55 | root = root.pop() 56 | 57 | assert type(root) is List, "Unexpected root type of {}".format(type(root)) 58 | 59 | # Append it 60 | root.insert(index, copy(obj)) 61 | 62 | # Add this to our returns 63 | retObj = pyState.ReturnObject(1) 64 | retObj.state = s 65 | 66 | ret.append(retObj) 67 | 68 | return ret 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /pySym/pyState/functions/String/index.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from ....pyObjectManager.List import List 3 | from ....pyObjectManager.Int import Int 4 | from ....pyObjectManager.Real import Real 5 | from ....pyObjectManager.BitVec import BitVec 6 | from ....pyObjectManager.Char import Char 7 | from ....pyObjectManager.String import String 8 | import ast 9 | 10 | logger = logging.getLogger("pyState:SimFunction:String.index") 11 | 12 | 13 | def handle(state,call,sub,start=None,end=None,ctx=None): 14 | """ 15 | Determine location of char in string. 16 | """ 17 | ctx = ctx if ctx is not None else state.ctx 18 | 19 | # The root (i.e.: "s" in s.index()) 20 | root = state.resolveObject(call.func.value,ctx=ctx) 21 | 22 | assert len(root) == 1 23 | 24 | root = root.pop() 25 | 26 | assert type(root) is String 27 | 28 | # Resolve the vars 29 | subs = state.resolveObject(sub,ctx=ctx) 30 | 31 | for sub in subs: 32 | # If we're indexing a Char, just change it into a String 33 | if type(sub) is Char: 34 | c = sub 35 | sub = String("tempIndex",1,state=sub.state) 36 | sub.variables.append(c) 37 | subs[subs.index(c)] = sub 38 | 39 | 40 | assert min([type(sub) is String for sub in subs]) == True 41 | 42 | start = state.resolveObject(start,ctx=ctx) if start is not None else None 43 | end = state.resolveObject(end,ctx=ctx) if end is not None else None 44 | 45 | if type(start) not in [int,type(None)]: 46 | if not start.isStatic(): 47 | err = "handle: Don't know how to handle appending type {0}".format(type(var)) 48 | logger.error(err) 49 | raise Exception(err) 50 | start = start.getValue() 51 | 52 | if type(end) not in [int,type(None)]: 53 | if not end.isStatic(): 54 | err = "handle: Don't know how to handle appending type {0}".format(type(var)) 55 | logger.error(err) 56 | raise Exception(err) 57 | end = end.getValue() 58 | 59 | # Get the substring 60 | if start is None: 61 | start = 0 62 | 63 | if end is None: 64 | end = len(root) 65 | 66 | subStr = root[start:end] 67 | ret = [] 68 | 69 | # Move the size window through the input 70 | for i in range(0,len(subStr) - len(sub) + 1): 71 | # If it is possible to have this index here, add it 72 | if subStr[i:i+len(sub)].canBe(sub): 73 | ret.append(Int('tempStrIndex',1,value=i,state=state)) 74 | 75 | # If this is the only possible place, we must stop 76 | if subStr[i:i+len(sub)].mustBe(sub): 77 | break 78 | 79 | return ret 80 | 81 | 82 | -------------------------------------------------------------------------------- /pySym/pyState/functions/String/join.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from ....pyObjectManager.List import List 3 | from ....pyObjectManager.Int import Int 4 | from ....pyObjectManager.Real import Real 5 | from ....pyObjectManager.BitVec import BitVec 6 | from ....pyObjectManager.Char import Char 7 | from ....pyObjectManager.String import String 8 | import ast 9 | from .... import pyState 10 | 11 | logger = logging.getLogger("pyState:SimFunction:String.join") 12 | 13 | 14 | def handle(state,call,elem,ctx=None): 15 | """ 16 | Simulate Python's join string method 17 | """ 18 | ctx = ctx if ctx is not None else state.ctx 19 | 20 | # The root (i.e.: "s" in s.join()) 21 | root = state.resolveObject(call.func.value,ctx=ctx) 22 | 23 | assert len(root) == 1 24 | root = root.pop() 25 | 26 | assert type(root) is String 27 | 28 | # Resolve the elem 29 | elems = state.resolveObject(elem,ctx=ctx) 30 | 31 | elems = elems if type(elems) is list else [elems] 32 | 33 | # If we're waiting on a symbolic call, return 34 | retObjs = [x for x in elems if type(x) is pyState.ReturnObject] 35 | if len(retObjs) > 0: 36 | return retObjs 37 | 38 | ret = [] 39 | 40 | for elem in elems: 41 | 42 | if type(elem) is not List: 43 | err = "handle: Don't know how to handle non-List join iterators" 44 | logger.error(err) 45 | raise Exception(err) 46 | 47 | 48 | # Get new string 49 | newString = state.getVar('tempStrJoin',ctx=1,varType=String) 50 | newString.increment() 51 | 52 | # Loop through elem values 53 | for item in elem: 54 | if type(item) is String: 55 | newString.variables += item.variables + root.variables 56 | elif type(item) is Char: 57 | newString.variables += [item.variable] + root.variables 58 | else: 59 | err = "handle: Don't know how to handle type {0}".format(type(item)) 60 | logger.error(err) 61 | raise Exception(err) 62 | 63 | if len(root) > 0: 64 | # Remove the excess chars that may have built up 65 | newString = newString[:-len(root)] 66 | 67 | ret.append(newString.copy()) 68 | 69 | return ret 70 | 71 | -------------------------------------------------------------------------------- /pySym/pyState/functions/String/zfill.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from ....pyObjectManager.List import List 3 | from ....pyObjectManager.Int import Int 4 | from ....pyObjectManager.Real import Real 5 | from ....pyObjectManager.BitVec import BitVec 6 | from ....pyObjectManager.Char import Char 7 | from ....pyObjectManager.String import String 8 | import ast 9 | from .... import pyState 10 | 11 | logger = logging.getLogger("pyState:SimFunction:String.zfill") 12 | 13 | 14 | def handle(state,call,width,ctx=None): 15 | """ 16 | Simulate Python's zfill string method 17 | """ 18 | ctx = ctx if ctx is not None else state.ctx 19 | 20 | # The root (i.e.: "s" in s.zfill()) 21 | root = state.resolveObject(call.func.value,ctx=ctx) 22 | 23 | assert len(root) == 1 24 | root = root.pop() 25 | 26 | assert type(root) is String 27 | 28 | # Resolve the width 29 | widths = state.resolveObject(width,ctx=ctx) 30 | 31 | # Resolve calls if we need to 32 | retObjs = [x for x in widths if type(x) is pyState.ReturnObject] 33 | if len(retObjs) > 0: 34 | return retObjs 35 | 36 | ret = [] 37 | 38 | for width in widths: 39 | 40 | # TODO: Add symbolic width capability 41 | if not width.isStatic(): 42 | err = "handle: Don't know how to handle non static width" 43 | logger.error(err) 44 | raise Exception(err) 45 | 46 | # TODO: Add symbolic string capability 47 | if not root.isStatic(): 48 | err = "handle: Don't know how to handle symbolic string" 49 | logger.error(err) 50 | raise Exception(err) 51 | 52 | # Get new str 53 | newString = state.getVar('tempZfillStr',ctx=1,varType=String) 54 | newString.increment() 55 | 56 | # Resolve the width 57 | width = width.getValue() 58 | 59 | # zfill will not truncate 60 | newString.setTo(root,clear=True) 61 | 62 | # If we're already at our length, just return 63 | if len(newString) >= width: 64 | ret.append(newString.copy()) 65 | continue 66 | 67 | # Add as many "0"s as needed 68 | while len(newString) < width: 69 | # Create the new Char 70 | c = state.getVar('tempCharZfill',ctx=1,varType=Char) 71 | c.increment() 72 | # Set it 73 | c.setTo('0') 74 | # Insert it 75 | newString.variables.insert(0,c.copy()) 76 | 77 | ret.append(newString.copy()) 78 | 79 | return ret 80 | 81 | -------------------------------------------------------------------------------- /pySym/pyState/functions/__init__.py: -------------------------------------------------------------------------------- 1 | # blerg 2 | -------------------------------------------------------------------------------- /pySym/pyState/functions/abs.py: -------------------------------------------------------------------------------- 1 | from ...pyObjectManager.Int import Int 2 | from ...pyObjectManager.Real import Real 3 | from ...pyObjectManager.BitVec import BitVec 4 | from ...pyObjectManager.String import String 5 | from ... import pyState 6 | import logging 7 | import z3 8 | 9 | logger = logging.getLogger("pyState:functions:abs") 10 | 11 | 12 | def handle(state,call,obj,ctx=None): 13 | """ 14 | Simulate abs funcion 15 | """ 16 | ctx = ctx if ctx is not None else state.ctx 17 | 18 | # Resolve the object 19 | objs = state.resolveObject(obj,ctx=ctx) 20 | 21 | # Resolve calls if we need to 22 | retObjs = [x for x in objs if type(x) is pyState.ReturnObject] 23 | if len(retObjs) > 0: 24 | return retObjs 25 | 26 | retList = [] 27 | 28 | # Loop through all possible inputs 29 | for obj in objs: 30 | 31 | s = obj.state.copy() 32 | 33 | obj.state = s 34 | 35 | if type(obj) not in [Int, Real, BitVec]: 36 | err = "handle: This shouldn't happen. Possibly a target program bug? Got obj type {0}".format(type(obj)) 37 | logger.error(err) 38 | raise Exception(err) 39 | 40 | oldObj = obj.copy() 41 | 42 | obj.increment() 43 | newObj = obj 44 | 45 | # Take shortcut if we know these values are static-ish 46 | if oldObj.isStatic(): 47 | newObj.setTo(abs(oldObj.getValue())) 48 | 49 | else: 50 | 51 | # Add a little z3 If statement to mimic abs() call 52 | s.addConstraint( 53 | newObj.getZ3Object() == 54 | z3.If( 55 | oldObj.getZ3Object() > 0, 56 | oldObj.getZ3Object(), 57 | -oldObj.getZ3Object() 58 | ) 59 | ) 60 | 61 | retList.append(obj.copy()) 62 | 63 | # Return all options 64 | return retList 65 | -------------------------------------------------------------------------------- /pySym/pyState/functions/bin.py: -------------------------------------------------------------------------------- 1 | from ...pyObjectManager.Int import Int 2 | from ...pyObjectManager.Real import Real 3 | from ...pyObjectManager.BitVec import BitVec 4 | from ...pyObjectManager.String import String 5 | from ... import pyState 6 | import logging 7 | 8 | logger = logging.getLogger("pyState:functions:bin") 9 | 10 | 11 | def handle(state,call,obj,ctx=None): 12 | """ 13 | Simulate bin funcion 14 | """ 15 | ctx = ctx if ctx is not None else state.ctx 16 | 17 | # Resolve the object 18 | objs = state.resolveObject(obj,ctx=ctx) 19 | 20 | # Normalize 21 | objs = [objs] if type(objs) is not list else objs 22 | 23 | # Resolve calls if we need to 24 | retObjs = [x for x in objs if type(x) is pyState.ReturnObject] 25 | if len(retObjs) > 0: 26 | return retObjs 27 | 28 | retList = [] 29 | 30 | # Loop through all possible inputs 31 | for obj in objs: 32 | 33 | if type(obj) not in [Int, Real, BitVec]: 34 | err = "handle: This shouldn't happen. Possibly a target program bug? Got obj type {0}".format(type(obj)) 35 | logger.error(err) 36 | raise Exception(err) 37 | 38 | # Only dealing with concrete values for now. 39 | if obj.isStatic(): 40 | val = obj.getValue() 41 | ret = state.getVar("tmpStrVal",ctx=1,varType=String) 42 | ret.increment() 43 | ret.setTo(bin(val),clear=True) 44 | 45 | # TODO: Deal with symbolic values (returning list of possibilities) 46 | else: 47 | err = "handle: Don't know how to handle symbolic ints for now" 48 | logger.error(err) 49 | raise Exception(err) 50 | 51 | 52 | retList.append(ret.copy()) 53 | 54 | # Return all options 55 | return retList 56 | -------------------------------------------------------------------------------- /pySym/pyState/functions/chr.py: -------------------------------------------------------------------------------- 1 | from ...pyObjectManager.Int import Int 2 | from ...pyObjectManager.Real import Real 3 | from ...pyObjectManager.BitVec import BitVec 4 | from ...pyObjectManager.String import String 5 | from ...pyObjectManager.List import List 6 | import logging 7 | from ... import pyState 8 | 9 | logger = logging.getLogger("pyState:functions:chr") 10 | 11 | import z3 12 | 13 | def handle(state,call,obj,ctx=None): 14 | """ 15 | Simulate chr funcion 16 | """ 17 | ctx = ctx if ctx is not None else state.ctx 18 | 19 | # Resolve the object 20 | objs = state.resolveObject(obj,ctx=ctx) 21 | 22 | # Normalize 23 | objs = [objs] if type(objs) is not list else objs 24 | 25 | # Resolve calls if we need to 26 | retObjs = [x for x in objs if type(x) is pyState.ReturnObject] 27 | if len(retObjs) > 0: 28 | return retObjs 29 | 30 | # Loop through our input 31 | retList = [] 32 | for obj in objs: 33 | 34 | # This is probably a script problem, not us 35 | # TODO: Handle sending Exceptions back to the program, not us. 36 | if type(obj) is not Int: 37 | err = "handle: Invalid param for chr type {0}".format(type(obj)) 38 | raise Exception(err) 39 | 40 | # Single value 41 | if obj.isStatic(): 42 | 43 | # Is this integer too large or too small? 44 | obj_value = int(obj) 45 | if obj_value < 0 or obj_value >= 0x110000: 46 | err = "handle: Invalid integer value for chr of {0}. Needs to be in range(0x110000)".format(obj_value) 47 | raise Exception(err) 48 | 49 | # TODO: Figure out how to handle this case... 50 | elif obj_value > 0xff: 51 | err = "handle: Not sure how to handle chr(>0xff) right now..." 52 | raise Exception(err) 53 | 54 | 55 | # Grab a new var to work with 56 | ret = obj.state.getVar("tmpChrVal",ctx=1,varType=String,kwargs={'increment':True}) 57 | ret.setTo(chr(int(obj)),clear=True) 58 | 59 | # If it's symbolic, we need help from z3 60 | else: 61 | # Grab a new var to work with 62 | ret = obj.state.getVar("tmpChrVal",ctx=1,varType=String,kwargs={'increment':True}) 63 | ret.setTo(obj, clear=True) 64 | 65 | retList.append(ret.copy()) 66 | 67 | return retList 68 | -------------------------------------------------------------------------------- /pySym/pyState/functions/hex.py: -------------------------------------------------------------------------------- 1 | from ...pyObjectManager.Int import Int 2 | from ...pyObjectManager.Real import Real 3 | from ...pyObjectManager.BitVec import BitVec 4 | from ...pyObjectManager.String import String 5 | from ...pyObjectManager.List import List 6 | import logging 7 | from ... import pyState 8 | 9 | logger = logging.getLogger("pyState:functions:hex") 10 | 11 | 12 | def handle(state,call,obj,ctx=None): 13 | """ 14 | Simulate hex funcion 15 | """ 16 | ctx = ctx if ctx is not None else state.ctx 17 | 18 | # Resolve the object 19 | objs = state.resolveObject(obj,ctx=ctx) 20 | 21 | # Normalize 22 | objs = [objs] if type(objs) is not list else objs 23 | 24 | # Resolve calls if we need to 25 | retObjs = [x for x in objs if type(x) is pyState.ReturnObject] 26 | if len(retObjs) > 0: 27 | return retObjs 28 | 29 | # Loop through our input 30 | retList = [] 31 | 32 | for obj in objs: 33 | 34 | # This is probably a script problem, not us 35 | if type(obj) not in [Int, BitVec]: 36 | err = "handle: Invalid param for hex type {0}".format(type(obj)) 37 | logger.error(err) 38 | raise Exception(err) 39 | 40 | # Only dealing with concrete values for now. 41 | if obj.isStatic(): 42 | ret = state.getVar("tmpHexVal",ctx=1,varType=String) 43 | ret.increment() 44 | ret.setTo(hex(obj.getValue()),clear=True) 45 | 46 | # TODO: Deal with symbolic values (returning list of possibilities) 47 | else: 48 | err = "handle: Don't know how to handle symbolic for now" 49 | logger.error(err) 50 | raise Exception(err) 51 | 52 | 53 | retList.append(ret.copy()) 54 | 55 | return retList 56 | -------------------------------------------------------------------------------- /pySym/pyState/functions/int.py: -------------------------------------------------------------------------------- 1 | from ...pyObjectManager.Int import Int 2 | from ...pyObjectManager.Real import Real 3 | from ...pyObjectManager.BitVec import BitVec 4 | from ...pyObjectManager.String import String 5 | from ...pyObjectManager.Char import Char 6 | import logging 7 | from ... import pyState 8 | 9 | logger = logging.getLogger("pyState:functions:int") 10 | 11 | 12 | def handle(state,call,obj,base=10,ctx=None): 13 | """ 14 | Simulate int funcion 15 | """ 16 | ctx = ctx if ctx is not None else state.ctx 17 | 18 | # Resolve the object 19 | objs = state.resolveObject(obj,ctx=ctx) 20 | 21 | # Resolve calls if we need to 22 | retObjs = [x for x in objs if type(x) is pyState.ReturnObject] 23 | if len(retObjs) > 0: 24 | return retObjs 25 | 26 | # Loop through inputs 27 | retList = [] 28 | 29 | for obj in objs: 30 | 31 | if type(obj) not in [Int, Real, BitVec, String, Char]: 32 | err = "handle: Don't know how to handle type {0}".format(type(obj)) 33 | logger.error(err) 34 | raise Exception(err) 35 | 36 | # Check up-front types for int. Catch these issues 37 | if type(obj) in [Int, Real, BitVec] and type(base) is not int: 38 | err = "handle: Cannot use base variable when using non-string object".format(type(obj)) 39 | logger.error(err) 40 | raise Exception(err) 41 | 42 | # Resolve base 43 | base = [base] if type(base) is int else obj.state.resolveObject(base,ctx=ctx) 44 | 45 | # TODO: Deal with extra states later... 46 | assert len(base) == 1 47 | base = base.pop() 48 | 49 | # Only dealing with concrete values for now. 50 | if obj.isStatic() and (type(base) is int or base.isStatic()): 51 | val = obj.getValue() 52 | ret = state.getVar("tmpIntVal",ctx=1,varType=Int) 53 | ret.increment() 54 | base = base if type(base) is int else base.getValue() 55 | 56 | # int() doesn't like base set for non-strings 57 | if type(val) is str: 58 | ret.setTo(int(val,base)) 59 | else: 60 | ret.setTo(int(val)) 61 | 62 | 63 | # TODO: Deal with symbolic values (returning list of possibilities) 64 | else: 65 | print("any",state.any_n_real(obj,10)) 66 | print(state.solver) 67 | print(obj.getZ3Object()) 68 | print(state.solver.check()) 69 | err = "handle: Don't know how to handle symbolic ints for now" 70 | logger.error(err) 71 | raise Exception(err) 72 | 73 | 74 | retList.append(ret.copy()) 75 | 76 | return retList 77 | -------------------------------------------------------------------------------- /pySym/pyState/functions/len.py: -------------------------------------------------------------------------------- 1 | from ...pyObjectManager.Int import Int 2 | from ... import pyState 3 | 4 | def handle(state,call,obj,ctx=None): 5 | """ 6 | Simulate len funcion 7 | """ 8 | ctx = ctx if ctx is not None else state.ctx 9 | 10 | # Resolve the object 11 | objs = state.resolveObject(obj,ctx=ctx) 12 | 13 | # Normalize 14 | objs = [objs] if type(objs) is not list else objs 15 | 16 | # Resolve calls if we need to 17 | retObjs = [x for x in objs if type(x) is pyState.ReturnObject] 18 | if len(retObjs) > 0: 19 | return retObjs 20 | 21 | # Loop through input 22 | 23 | ret = [] 24 | 25 | for obj in objs: 26 | 27 | # Just calling the length function on the object.. 28 | l = len(obj) 29 | 30 | i = state.getVar("tmpLenValue",ctx=1, varType=Int) 31 | i.increment() 32 | 33 | i.setTo(l) 34 | 35 | #ret.append(i.copy()) 36 | ret.append(i) 37 | 38 | return ret 39 | -------------------------------------------------------------------------------- /pySym/pyState/functions/ord.py: -------------------------------------------------------------------------------- 1 | from ...pyObjectManager.Int import Int 2 | from ...pyObjectManager.Real import Real 3 | from ...pyObjectManager.BitVec import BitVec 4 | from ...pyObjectManager.String import String 5 | from ...pyObjectManager.List import List 6 | from ...pyObjectManager.Char import Char 7 | import logging 8 | from ... import pyState 9 | 10 | logger = logging.getLogger("pyState:functions:ord") 11 | 12 | import z3 13 | 14 | def handle(state,call,obj,ctx=None): 15 | """ 16 | Simulate ord funcion 17 | """ 18 | ctx = ctx if ctx is not None else state.ctx 19 | 20 | # Resolve the object 21 | objs = state.resolveObject(obj,ctx=ctx) 22 | 23 | # Normalize 24 | objs = [objs] if type(objs) is not list else objs 25 | 26 | # Resolve calls if we need to 27 | retObjs = [x for x in objs if type(x) is pyState.ReturnObject] 28 | if len(retObjs) > 0: 29 | return retObjs 30 | 31 | # Loop through our input 32 | retList = [] 33 | for obj in objs: 34 | 35 | # This is probably a script problem, not us 36 | if (type(obj) not in [String, Char]) or (type(obj) is String and len(obj) != 1): 37 | err = "handle: Invalid param for ord type {0}".format(type(obj)) 38 | logger.error(err) 39 | raise Exception(err) 40 | 41 | # Grab a new var to work with 42 | ret = state.getVar("tmpOrdVal",ctx=1,varType=Int) 43 | ret.increment() 44 | 45 | # Sanitize String to Char 46 | if type(obj) is String: 47 | obj = obj[0] 48 | 49 | # Simple case, it's static 50 | if obj.isStatic(): 51 | ret.setTo(ord(obj.getValue())) 52 | 53 | # If it's symbolic, we need help from z3 54 | else: 55 | # Tell z3 to convert the BitVec to an int, then set equal 56 | #ret.state.addConstraint(z3.BV2Int(obj.getZ3Object()) == ret.getZ3Object()) 57 | ret.setTo(obj) 58 | 59 | retList.append(ret.copy()) 60 | 61 | return retList 62 | -------------------------------------------------------------------------------- /pySym/pyState/functions/print.py: -------------------------------------------------------------------------------- 1 | from ... import pyState 2 | 3 | def handle(state,call,s,ctx=None): 4 | """ 5 | Pretend to print stuff 6 | """ 7 | ctx = ctx if ctx is not None else state.ctx 8 | 9 | s = state.resolveObject(s,ctx=ctx) 10 | 11 | # Resolve calls if we need to 12 | retObjs = [x for x in s if type(x) is pyState.ReturnObject] 13 | if len(retObjs) > 0: 14 | return retObjs 15 | 16 | for obj in s: 17 | print(obj) 18 | -------------------------------------------------------------------------------- /pySym/pyState/functions/pyState/BVS.py: -------------------------------------------------------------------------------- 1 | import z3 2 | import ast 3 | from ...z3Helpers import Z3_DEFAULT_BITVEC_SIZE 4 | from ....pyObjectManager.BitVec import BitVec 5 | 6 | def handle(state,call,size=ast.Num(Z3_DEFAULT_BITVEC_SIZE),ctx=None): 7 | """ 8 | Returns a BitVec object. Use this to inform pySym that something should be BitVec symbolic 9 | """ 10 | ctx = ctx if ctx is not None else state.ctx 11 | 12 | assert type(size) is ast.Num, "Unknown size for BVS of type {}".format(type(size)) 13 | 14 | bvs = state.resolveObject(ast.Name('temp',0),ctx=1,varType=BitVec,kwargs={'size': size.n}) 15 | assert len(bvs) == 1 16 | 17 | bvs = bvs[0] 18 | bvs.increment() 19 | 20 | return [bvs.copy()] 21 | -------------------------------------------------------------------------------- /pySym/pyState/functions/pyState/BVV.py: -------------------------------------------------------------------------------- 1 | import logging 2 | logger = logging.getLogger("pyState:functions:pyState:BVV") 3 | 4 | import z3 5 | import ast 6 | from ...z3Helpers import Z3_DEFAULT_BITVEC_SIZE 7 | from ....pyObjectManager.BitVec import BitVec 8 | from ....pyObjectManager.Int import Int 9 | from .... import pyState 10 | 11 | def _handle_num(i, size, ctx): 12 | """i is already resolved as Int or BitVec. size is not.""" 13 | 14 | state = i.state.copy() 15 | 16 | # Resolve the size object 17 | size_vals = state.resolveObject(size,ctx=ctx) 18 | 19 | # Resolve calls if we need to 20 | retObjs = [x for x in size_vals if type(x) is pyState.ReturnObject] 21 | if len(retObjs) > 0: 22 | return retObjs 23 | 24 | ret = [] 25 | 26 | # Loop through sizes 27 | for size in size_vals: 28 | 29 | state = size.state.copy() 30 | 31 | if type(size) not in [Int, BitVec]: 32 | error = "Unhandled size type of {}".format(type(size)) 33 | logger.error(error) 34 | raise Exception(error) 35 | 36 | assert size.isStatic(), "Not handling symbolic size value for pyState.BVV right now." 37 | 38 | # Resolve it to be an int 39 | size = size.getValue() 40 | 41 | # Generate a BitVec object for this. 42 | bvv = state.resolveObject(ast.Name('tempBVV',0),ctx=1,varType=BitVec,kwargs={'size': size}) 43 | 44 | assert len(bvv) == 1, "pyState.BVV somehow resolved two values for ast.Num??" 45 | bvv = bvv.pop() 46 | 47 | bvv.increment() 48 | bvv.setTo(i) 49 | ret.append(bvv.copy()) 50 | 51 | return ret 52 | 53 | def handle(state,call,i,size=ast.Num(Z3_DEFAULT_BITVEC_SIZE),ctx=None): 54 | """ 55 | Returns a BitVecVal object. This is helpful if we want to manually state what type a variable should be. 56 | """ 57 | ctx = ctx if ctx is not None else state.ctx 58 | 59 | ret_bvv = [] 60 | 61 | # Resolve the i object 62 | i_vals = state.resolveObject(i,ctx=ctx) 63 | 64 | # Resolve calls if we need to 65 | retObjs = [x for x in i_vals if type(x) is pyState.ReturnObject] 66 | if len(retObjs) > 0: 67 | return retObjs 68 | 69 | # Loop through our possible i values 70 | for i in i_vals: 71 | 72 | if type(i) in [Int, BitVec]: 73 | ret_bvv += _handle_num(i, size, ctx) 74 | 75 | else: 76 | error = "Unhandled i type of {}".format(type(i)) 77 | logger.error(i) 78 | raise Exception(i) 79 | 80 | # Resolve calls if we need to 81 | retObjs = [x for x in ret_bvv if type(x) is pyState.ReturnObject] 82 | if len(retObjs) > 0: 83 | return retObjs 84 | 85 | return ret_bvv 86 | 87 | -------------------------------------------------------------------------------- /pySym/pyState/functions/pyState/Int.py: -------------------------------------------------------------------------------- 1 | 2 | import z3 3 | import ast 4 | from ....pyObjectManager.Int import Int 5 | 6 | def handle(state,call,ctx=None): 7 | """ 8 | Returns an Int object. Use this to inform pySym that something should be Int symbolic 9 | """ 10 | ctx = ctx if ctx is not None else state.ctx 11 | 12 | myInt = state.resolveObject(ast.Name('temp',0),ctx=1,varType=Int) 13 | 14 | # Everything is moved around as lists... 15 | for i in myInt: 16 | i.increment() 17 | 18 | return myInt.copy() 19 | -------------------------------------------------------------------------------- /pySym/pyState/functions/pyState/Real.py: -------------------------------------------------------------------------------- 1 | import z3 2 | import ast 3 | from ....pyObjectManager.Real import Real 4 | from ... import z3Helpers 5 | 6 | def handle(state,call,value=None,ctx=None): 7 | """ 8 | Returns a z3 Real object. Use this to inform pySym that something should be Real symbolic 9 | (optional) value == the value to set this variable to 10 | """ 11 | ctx = ctx if ctx is not None else state.ctx 12 | 13 | myReal = state.resolveObject(ast.Name('tempReal',0),ctx=ctx,varType=Real) 14 | 15 | ret = [] 16 | 17 | for r in myReal: 18 | 19 | if value is not None: 20 | state = r.state 21 | value = state.resolveObject(value,ctx=ctx) 22 | 23 | for v in value: 24 | realObj,valueObj = z3Helpers.z3_matchLeftAndRight(r,v,ast.Add) 25 | #r.setTo(v) 26 | r.increment() 27 | state.addConstraint(r.getZ3Object() == valueObj) 28 | ret.append(r.copy()) 29 | 30 | else: 31 | r.increment() 32 | ret.append(r.copy()) 33 | 34 | return ret 35 | -------------------------------------------------------------------------------- /pySym/pyState/functions/pyState/String.py: -------------------------------------------------------------------------------- 1 | 2 | import z3 3 | import ast 4 | from ...z3Helpers import Z3_MAX_STRING_LENGTH 5 | from ....pyObjectManager.String import String 6 | 7 | def handle(state,call,length=ast.Num(Z3_MAX_STRING_LENGTH),ctx=None): 8 | """ 9 | Returns a String object. This is helpful if we want to manually state what type a variable should be. 10 | Create a completely symbolic array of default max length: 11 | x = pyState.String() 12 | """ 13 | ctx = ctx if ctx is not None else state.ctx 14 | 15 | assert type(length) in [ast.Num,int] 16 | length = length.n if type(length) is ast.Num else length 17 | 18 | string = state.getVar('pyStateStringTemp',ctx=1,varType=String,kwargs={'length': length}) 19 | string.increment() 20 | 21 | return [string.copy()] 22 | -------------------------------------------------------------------------------- /pySym/pyState/functions/random/randint.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from ....pyObjectManager.Int import Int 3 | from ....pyObjectManager import CTX_RETURNS 4 | from .... import pyState 5 | import z3 6 | 7 | logger = logging.getLogger("pyState:functions:random.randint") 8 | 9 | 10 | def handle(state,call,a,b,ctx=None): 11 | """ 12 | Implements python random.randint 13 | """ 14 | ctx = ctx if ctx is not None else state.ctx 15 | 16 | # Resolve arguments 17 | a_list = state.resolveObject(a,ctx=ctx) 18 | 19 | # If we're waiting on a symbolic call, return 20 | retObjs = [x for x in a_list if type(x) is pyState.ReturnObject] 21 | if len(retObjs) > 0: 22 | return retObjs 23 | 24 | b_list = state.resolveObject(b,ctx=ctx) 25 | 26 | # If we're waiting on a symbolic call, return 27 | retObjs = [x for x in b_list if type(x) is pyState.ReturnObject] 28 | if len(retObjs) > 0: 29 | return retObjs 30 | 31 | ret = [] 32 | 33 | # Generally this will only be a single a and b value, but you never know. 34 | for a in a_list: 35 | 36 | # Not handling symbolic a rn 37 | if not a.isStatic(): 38 | exc = "Not handling symbolic 'a' value in random.randint right now." 39 | logger.error(exc) 40 | raise Exception(exc) 41 | 42 | for b in b_list: 43 | 44 | # Not handling symbolic b rn 45 | if not b.isStatic(): 46 | exc = "Not handling symbolic 'b' value in random.randint right now." 47 | logger.error(exc) 48 | raise Exception(exc) 49 | 50 | s = state.copy() 51 | 52 | # Create a new Int 53 | obj = s.getVar('tmpRandomRandint',ctx=CTX_RETURNS,varType=Int) 54 | 55 | # Add constraints 56 | s.addConstraint(z3.And(obj.getZ3Object() >= int(a), obj.getZ3Object() <= int(b))) 57 | 58 | # Done with this command 59 | #print(s.path.pop(0)) 60 | 61 | ret.append(obj) 62 | 63 | return ret 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /pySym/pyState/functions/range.py: -------------------------------------------------------------------------------- 1 | from ...pyObjectManager.List import List 2 | from ...pyObjectManager.Int import Int 3 | from ...pyObjectManager.BitVec import BitVec 4 | import itertools 5 | from ... import pyState 6 | import logging 7 | 8 | logger = logging.getLogger("pyState:functions:range") 9 | 10 | def handle(state,call,a,b=None,c=None,ctx=None): 11 | """ 12 | Simulate range funcion 13 | """ 14 | ctx = ctx if ctx is not None else state.ctx 15 | 16 | # Resolve the vars 17 | aa = state.resolveObject(a,ctx=ctx) 18 | 19 | # Normalize 20 | aa = [aa] if type(aa) is not list else aa 21 | 22 | # Resolve calls if we need to 23 | retObjs = [x for x in aa if type(x) is pyState.ReturnObject] 24 | if len(retObjs) > 0: 25 | return retObjs 26 | 27 | bb = state.resolveObject(b,ctx=ctx) if b is not None else None 28 | 29 | # Normalize 30 | bb = [bb] if type(bb) is not list else bb 31 | 32 | # Resolve calls if we need to 33 | retObjs = [x for x in bb if type(x) is pyState.ReturnObject] 34 | if len(retObjs) > 0: 35 | return retObjs 36 | 37 | cc = state.resolveObject(c,ctx=ctx) if c is not None else None 38 | 39 | # Normalize 40 | cc = [cc] if type(cc) is not list else cc 41 | 42 | # Resolve calls if we need to 43 | retObjs = [x for x in cc if type(x) is pyState.ReturnObject] 44 | if len(retObjs) > 0: 45 | return retObjs 46 | 47 | ret = [] 48 | 49 | # Loop through all possibilities 50 | for a,b,c in itertools.product(aa,bb,cc): 51 | 52 | ############## 53 | # a Concrete # 54 | ############## 55 | 56 | if type(a) not in [int,type(None)]: 57 | if a.isStatic(): 58 | a = a.getValue() 59 | 60 | # Check if it's a variable that only has one possibility 61 | elif type(a) in [Int, BitVec] and len(state.any_n_int(a,2)) == 1: 62 | a = state.any_int(a) 63 | 64 | else: 65 | err = "handle: Don't know how to handle symbolic integers at the moment" 66 | logger.error(err) 67 | raise Exception(err) 68 | 69 | 70 | ############## 71 | # b Concrete # 72 | ############## 73 | if type(b) not in [int,type(None)]: 74 | if b.isStatic(): 75 | b = b.getValue() 76 | 77 | # Check if it's a variable that only has one possibility 78 | elif type(b) in [Int, BitVec] and len(state.any_n_int(b,2)) == 1: 79 | b = state.any_int(b) 80 | 81 | else: 82 | err = "handle: Don't know how to handle symbolic integers at the moment" 83 | logger.error(err) 84 | raise Exception(err) 85 | 86 | 87 | ############## 88 | # c Concrete # 89 | ############## 90 | 91 | if type(c) not in [int,type(None)]: 92 | if c.isStatic(): 93 | c = c.getValue() 94 | 95 | # Check if it's a variable that only has one possibility 96 | elif type(c) in [Int, BitVec] and len(state.any_n_int(c,2)) == 1: 97 | lower = state.any_int(c) 98 | 99 | else: 100 | err = "handle: Don't know how to handle symbolic integers at the moment" 101 | logger.error(err) 102 | raise Exception(err) 103 | 104 | 105 | # Create the return List object 106 | out = state.getVar("range",ctx=1,varType=List) 107 | out.increment() 108 | 109 | if b == None: 110 | rangeOut = range(a) 111 | 112 | elif c == None: 113 | rangeOut = range(a,b) 114 | 115 | else: 116 | rangeOut = range(a,b,c) 117 | 118 | # Copy the output 119 | for var in rangeOut: 120 | out.append(Int,kwargs={'value':var}) 121 | 122 | # Return a copy 123 | ret.append(out.copy()) 124 | 125 | return ret 126 | 127 | -------------------------------------------------------------------------------- /pySym/pyState/functions/str.py: -------------------------------------------------------------------------------- 1 | from ...pyObjectManager.Int import Int 2 | from ...pyObjectManager.Real import Real 3 | from ...pyObjectManager.BitVec import BitVec 4 | from ...pyObjectManager.String import String 5 | from ...pyObjectManager.List import List 6 | import logging 7 | from ... import pyState 8 | 9 | logger = logging.getLogger("pyState:functions:str") 10 | 11 | 12 | def handle(state,call,obj,ctx=None): 13 | """ 14 | Simulate str funcion 15 | """ 16 | ctx = ctx if ctx is not None else state.ctx 17 | 18 | # Resolve the object 19 | objs = state.resolveObject(obj,ctx=ctx) 20 | 21 | # Normalize 22 | objs = [objs] if type(objs) is not list else objs 23 | 24 | # Resolve calls if we need to 25 | retObjs = [x for x in objs if type(x) is pyState.ReturnObject] 26 | if len(retObjs) > 0: 27 | return retObjs 28 | 29 | # Loop through objects 30 | retList = [] 31 | for obj in objs: 32 | 33 | if type(obj) not in [Int, Real, BitVec, List]: 34 | # Only know how to do str on numbers for now 35 | err = "handle: Don't know how to handle type {0}".format(type(obj)) 36 | logger.error(err) 37 | raise Exception(err) 38 | 39 | # Only dealing with concrete values for now. 40 | if obj.isStatic(): 41 | ret = state.getVar("tmpStrVal",ctx=1,varType=String) 42 | ret.increment() 43 | # Utilize pyObjectManager class methods 44 | ret.setTo(obj.__str__(),clear=True) 45 | 46 | # TODO: Deal with symbolic values (returning list of possibilities) 47 | else: 48 | err = "handle: Don't know how to handle symbolic ints for now" 49 | logger.error(err) 50 | raise Exception(err) 51 | 52 | 53 | retList.append(ret.copy()) 54 | 55 | return retList 56 | -------------------------------------------------------------------------------- /pySym/pyState/functions/zip.py: -------------------------------------------------------------------------------- 1 | from ...pyObjectManager.Int import Int 2 | from ...pyObjectManager.Real import Real 3 | from ...pyObjectManager.BitVec import BitVec 4 | from ...pyObjectManager.String import String 5 | from ...pyObjectManager.List import List 6 | import logging 7 | from ... import pyState 8 | import itertools 9 | 10 | logger = logging.getLogger("pyState:functions:zip") 11 | 12 | 13 | def handle(state,call,left,right,ctx=None): 14 | """ 15 | Simulate zip funcion 16 | """ 17 | ctx = ctx if ctx is not None else state.ctx 18 | 19 | # Resolve the object 20 | lefts = state.resolveObject(left,ctx=ctx) 21 | 22 | # Normalize 23 | lefts = [lefts] if type(lefts) is not list else lefts 24 | 25 | # Resolve calls if we need to 26 | retObjs = [x for x in lefts if type(x) is pyState.ReturnObject] 27 | if len(retObjs) > 0: 28 | return retObjs 29 | 30 | # Don't want to lose track of our vars 31 | lefts = [left.copy() for left in lefts] 32 | 33 | rights = state.resolveObject(right,ctx=ctx) 34 | 35 | # Normalize 36 | rights = [rights] if type(rights) is not list else rights 37 | 38 | # Resolve calls if we need to 39 | retObjs = [x for x in rights if type(x) is pyState.ReturnObject] 40 | if len(retObjs) > 0: 41 | return retObjs 42 | 43 | rights = [right.copy() for right in rights] 44 | 45 | ret = [] 46 | 47 | # Loop through possibilities 48 | for left,right in itertools.product(lefts,rights): 49 | 50 | # Only handling List and String objects for now 51 | if type(left) not in [List, String]: 52 | err = "handle: Don't know how to handle type {0}".format(type(left)) 53 | logger.error(err) 54 | raise Exception(err) 55 | 56 | if type(right) not in [List, String]: 57 | err = "handle: Don't know how to handle type {0}".format(type(right)) 58 | logger.error(err) 59 | raise Exception(err) 60 | 61 | # Create our output List 62 | newList = state.getVar('tmpZipList',ctx=1,varType=List) 63 | newList.increment() 64 | 65 | # Might as well use Python's own zip function to help us 66 | for (l,r) in zip(left,right): 67 | # TODO: This should really be a Tuple, but I haven't implemented that yet. 68 | tempList = state.getVar('tmpZipInner',ctx=1,varType=List) 69 | tempList.increment() 70 | tempList.variables = [l,r] 71 | newList.variables.append(tempList.copy()) 72 | 73 | ret.append(newList.copy()) 74 | 75 | return ret 76 | -------------------------------------------------------------------------------- /run_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | py.test --forked -d -n auto --cov=. --cov-config=.coveragerc tests/ 3 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [aliases] 2 | test=pytest 3 | 4 | [tool:pytest] 5 | addopts = --forked -d -n auto --cov=pySym --cov-branch --cov-config=.coveragerc --cov-report=term --cov-report html tests/ 6 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | """A setuptools based setup module. 2 | 3 | See: 4 | https://packaging.python.org/en/latest/distributing.html 5 | https://github.com/pypa/sampleproject 6 | """ 7 | 8 | # Always prefer setuptools over distutils 9 | from setuptools import setup, find_packages 10 | # To use a consistent encoding 11 | from codecs import open 12 | from os import path 13 | import os 14 | 15 | here = path.abspath(path.dirname(__file__)) 16 | 17 | #with open(path.join(here, 'README.md'), encoding='utf-8') as f: 18 | # long_description = f.read() 19 | long_description = "See website for more info." 20 | 21 | dev_tools = ['pytest','python-coveralls','coverage','pytest-cov','pytest-xdist','ipython', 'gprof2dot', 'sphinx', 'sphinx_rtd_theme'] 22 | 23 | # 24 | # Install z3 or no? 25 | # 26 | 27 | install_requires=['prettytable','enforce'] 28 | 29 | # Defaulting RTD builds to use pip z3 solver 30 | if "PYSYM_NO_Z3" not in os.environ or os.environ.get('READTHEDOCS', None) == 'True': 31 | install_requires.append('z3-solver') 32 | 33 | setup( 34 | name='pySym', 35 | version='0.0.2', 36 | description='Symbolic execution of python source.', 37 | long_description=long_description, 38 | # The project's main homepage. 39 | url='https://github.com/bannsec/pySym', 40 | author='Michael Bann', 41 | author_email='self@bannsecurity.com', 42 | license='MIT', 43 | classifiers=[ 44 | # Pick your license as you wish (should match "license" above) 45 | 'License :: OSI Approved :: MIT License', 46 | 'Programming Language :: Python :: 3', 47 | 'Operating System :: POSIX :: Linux', 48 | 'Environment :: Console' 49 | ], 50 | keywords='symbolic execution python', 51 | packages=find_packages(exclude=['contrib', 'docs', 'tests', 'longer_tests']), 52 | install_requires=install_requires, 53 | setup_requires=['pytest-runner'], 54 | tests_require=dev_tools, 55 | extras_require={ 56 | 'dev': dev_tools, 57 | }, 58 | 59 | #entry_points={ 60 | # 'console_scripts': [ 61 | # 'pySym = pySym.pySym:main', 62 | # ], 63 | #}, 64 | 65 | ) 66 | 67 | -------------------------------------------------------------------------------- /setup_detectOS.sh: -------------------------------------------------------------------------------- 1 | lowercase(){ 2 | echo "$1" | sed "y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/" 3 | } 4 | 5 | OS=`lowercase \`uname\`` 6 | KERNEL=`uname -r` 7 | MACH=`uname -m` 8 | 9 | if [ "{$OS}" == "windowsnt" ]; then 10 | OS=windows 11 | elif [ "{$OS}" == "darwin" ]; then 12 | OS=mac 13 | else 14 | OS=`uname` 15 | if [ "${OS}" = "SunOS" ] ; then 16 | OS=Solaris 17 | ARCH=`uname -p` 18 | OSSTR="${OS} ${REV}(${ARCH} `uname -v`)" 19 | elif [ "${OS}" = "AIX" ] ; then 20 | OSSTR="${OS} `oslevel` (`oslevel -r`)" 21 | elif [ "${OS}" = "Linux" ] ; then 22 | if [ -f /etc/redhat-release ] ; then 23 | DistroBasedOn='RedHat' 24 | DIST=`cat /etc/redhat-release |sed s/\ release.*//` 25 | PSUEDONAME=`cat /etc/redhat-release | sed s/.*\(// | sed s/\)//` 26 | REV=`cat /etc/redhat-release | sed s/.*release\ // | sed s/\ .*//` 27 | elif [ -f /etc/SuSE-release ] ; then 28 | DistroBasedOn='SuSe' 29 | PSUEDONAME=`cat /etc/SuSE-release | tr "\n" ' '| sed s/VERSION.*//` 30 | REV=`cat /etc/SuSE-release | tr "\n" ' ' | sed s/.*=\ //` 31 | elif [ -f /etc/mandrake-release ] ; then 32 | DistroBasedOn='Mandrake' 33 | PSUEDONAME=`cat /etc/mandrake-release | sed s/.*\(// | sed s/\)//` 34 | REV=`cat /etc/mandrake-release | sed s/.*release\ // | sed s/\ .*//` 35 | elif [ -f /etc/debian_version ] ; then 36 | DistroBasedOn='Debian' 37 | DIST=`cat /etc/lsb-release | grep '^DISTRIB_ID' | awk -F= '{ print $2 }'` 38 | PSUEDONAME=`cat /etc/lsb-release | grep '^DISTRIB_CODENAME' | awk -F= '{ print $2 }'` 39 | REV=`cat /etc/lsb-release | grep '^DISTRIB_RELEASE' | awk -F= '{ print $2 }'` 40 | fi 41 | if [ -f /etc/UnitedLinux-release ] ; then 42 | DIST="${DIST}[`cat /etc/UnitedLinux-release | tr "\n" ' ' | sed s/VERSION.*//`]" 43 | fi 44 | OS=`lowercase $OS` 45 | DistroBasedOn=`lowercase $DistroBasedOn` 46 | readonly OS 47 | readonly DIST 48 | readonly DistroBasedOn 49 | readonly PSUEDONAME 50 | readonly REV 51 | readonly KERNEL 52 | readonly MACH 53 | fi 54 | 55 | fi 56 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | # because 2 | -------------------------------------------------------------------------------- /tests/functions/List/test_function_List_insert.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | import logging 6 | from pySym import Colorer 7 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 8 | 9 | 10 | from pySym import ast_parse 11 | import z3 12 | from pySym.pyPath import Path 13 | from pySym.pyPathGroup import PathGroup 14 | from pySym.pyObjectManager.Real import Real 15 | from pySym.pyObjectManager.List import List 16 | from pySym.pyObjectManager.String import String 17 | from pySym.pyObjectManager.Int import Int 18 | from pySym.pyObjectManager.Char import Char 19 | from pySym.pyObjectManager.BitVec import BitVec 20 | 21 | import pytest 22 | 23 | test1 = """ 24 | s = pyState.String(6) 25 | c = pyState.String(1)[0] 26 | r = pyState.Real() 27 | bv = pyState.BVS(32) 28 | l = [1,2,3] 29 | l.insert(0, 0) 30 | l.insert(0, 1.234) 31 | l.insert(0,[1,2,4,5]) 32 | l.insert(0,"test") 33 | l.insert(0,bv) 34 | l.insert(0,s) 35 | l.insert(0,c) 36 | l.insert(0,r) 37 | 38 | assert bv == 14 39 | assert r == 5.15 40 | assert c == "c" 41 | assert ord(s[0]) == ord('s') 42 | """ 43 | 44 | 45 | def test_function_List_insert(): 46 | b = ast_parse.parse(test1).body 47 | p = Path(b,source=test1) 48 | pg = PathGroup(p) 49 | 50 | pg.explore() 51 | 52 | # [5.15, 'c', 's\x00\x00\x00\x00\x00', 14, 'test', [1, 2, 4, 5], 1.234, 0, 1, 2, 3] 53 | assert len(pg.completed) == 1 54 | 55 | s = pg.completed[0].state.copy() 56 | 57 | l = s.getVar('l') 58 | 59 | assert type(l[0]) == Real 60 | assert type(l[1]) == String and len(l[1]) == 1 61 | assert type(l[2]) == String 62 | assert type(l[3]) == BitVec 63 | my_list = s.any_list(l) 64 | assert my_list[0] == 5.15 65 | assert my_list[1] == "c" 66 | assert my_list[2].startswith("s") 67 | assert my_list[3] == 14 68 | assert my_list[4] == "test" 69 | assert my_list[5] == [1,2,4,5] 70 | assert my_list[6] == 1.234 71 | assert my_list[7:] == [0,1,2,3] 72 | 73 | -------------------------------------------------------------------------------- /tests/functions/random/test_randint.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | 4 | import logging 5 | from pySym import Colorer 6 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 7 | 8 | from pySym import ast_parse 9 | import z3 10 | from pySym.pyPath import Path 11 | from pySym.pyPathGroup import PathGroup 12 | import pytest 13 | 14 | test1 = """ 15 | r = random.randint(1337,31337) 16 | """ 17 | 18 | test2 = """ 19 | s = pyState.String(8) 20 | r = random.randint(0, s.index('a')) 21 | """ 22 | 23 | def test_function_random_randint_statesplit(): 24 | b = ast_parse.parse(test2).body 25 | p = Path(b,source=test2) 26 | pg = PathGroup(p) 27 | 28 | pg.explore() 29 | assert len(pg.completed) == 8 30 | 31 | # Check where each state maxes out to ensure we're splitting right 32 | max_values = set() 33 | 34 | for path in pg.completed: 35 | 36 | r = path.state.getVar('r') 37 | 38 | for i in range(16): 39 | if not r.canBe(i): 40 | max_values.add(i-1) 41 | break 42 | else: 43 | assert False, "Random went way out of range..." 44 | 45 | assert max_values == set([0,1,2,3,4,5,6,7]) 46 | 47 | 48 | def test_function_random_randint_basic(): 49 | b = ast_parse.parse(test1).body 50 | p = Path(b,source=test1) 51 | pg = PathGroup(p) 52 | 53 | pg.explore() 54 | assert len(pg.completed) == 1 55 | 56 | s = pg.completed[0].state.copy() 57 | r = s.getVar('r') 58 | 59 | assert r.canBe(1337) 60 | assert r.canBe(31337) 61 | assert not r.canBe(31338) 62 | assert not r.canBe(1336) 63 | 64 | -------------------------------------------------------------------------------- /tests/longer_tests/test_one.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | import logging 6 | from pySym import Colorer 7 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 8 | 9 | from pySym import ast_parse 10 | import z3 11 | from pySym.pyPath import Path 12 | from pySym.pyPathGroup import PathGroup 13 | import pytest 14 | from pySym.pyObjectManager.Int import Int 15 | from pySym.pyObjectManager.Real import Real 16 | from pySym.pyObjectManager.BitVec import BitVec 17 | from pySym.pyObjectManager.List import List 18 | 19 | test = """ 20 | def to_bits(length, N): 21 | return [int(i) for i in bin(N)[2:].zfill(length)] 22 | 23 | def from_bits(N): 24 | return int("".join(str(i) for i in N), 2) 25 | 26 | CRC_POLY = to_bits(65, (2**64) + 0xeff67c77d13835f7) # 0b11110111111110110011111000111011111010001001110000011010111110111 27 | 28 | def crc(mesg): 29 | mesg += CONST 30 | shift = 0 31 | while shift < len(mesg) - 64: 32 | if mesg[shift]: 33 | for i in range(65): 34 | mesg[shift + i] ^= CRC_POLY[i] 35 | shift += 1 36 | return mesg[-64:] 37 | 38 | INNER = to_bits(8, 0x36) * 8 # 0b0011011000110110001101100011011000110110001101100011011000110110 39 | 40 | def xor(x, y): 41 | return [g ^ h for (g, h) in zip(x, y)] 42 | 43 | def hmac(h, key, mesg): 44 | return h(xor(key, OUTER) + h(xor(key, INNER) + mesg)) 45 | 46 | PLAIN_1 = "zupe zecret" 47 | PLAIN_2 = "BKPCTF" 48 | 49 | def str_to_bits(s): 50 | return [b for i in s for b in to_bits(8, ord(i))] 51 | 52 | def bits_to_hex(b): 53 | return hex(from_bits(b)).rstrip("L") 54 | 55 | PLAIN_1_BITS = str_to_bits(PLAIN_1) 56 | """ 57 | 58 | def test_longer_one(): 59 | b = ast_parse.parse(test).body 60 | p = Path(b,source=test) 61 | pg = PathGroup(p) 62 | 63 | pg.explore() 64 | 65 | assert len(pg.completed) == 1 66 | 67 | assert pg.completed[0].state.any_list('CRC_POLY') == [1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1] 68 | 69 | assert pg.completed[0].state.any_list('INNER') == [0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0] 70 | 71 | assert pg.completed[0].state.any_list('PLAIN_1_BITS') == [0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0] 72 | 73 | -------------------------------------------------------------------------------- /tests/scripts/assert_script_1.py: -------------------------------------------------------------------------------- 1 | def test(): 2 | return 12 3 | 4 | i = pyState.Int() 5 | assert i % test() == 4 6 | -------------------------------------------------------------------------------- /tests/scripts/basic_function.py: -------------------------------------------------------------------------------- 1 | x = 0 2 | y = 0 3 | 4 | y += 12 5 | 6 | pass # Hook point 7 | 8 | if y > 0: 9 | x = 1 10 | else: 11 | x = 0 12 | -------------------------------------------------------------------------------- /tests/scripts/ord_symbolic_chr.py: -------------------------------------------------------------------------------- 1 | s = pyState.String(5) 2 | c = ord(s[1]) 3 | -------------------------------------------------------------------------------- /tests/test_function_List.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | import logging 6 | from pySym import Colorer 7 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 8 | 9 | 10 | from pySym import ast_parse 11 | import z3 12 | from pySym.pyPath import Path 13 | from pySym.pyPathGroup import PathGroup 14 | import pytest 15 | 16 | test1 = """ 17 | l = [] 18 | l.append(1) 19 | l.append(2.3) 20 | l.append([1,2.2,3]) 21 | """ 22 | 23 | test2 = """ 24 | s = pyState.String(8) 25 | l = [] 26 | l.append(s.index('a')) 27 | """ 28 | 29 | def test_function_List_append_statesplit(): 30 | b = ast_parse.parse(test2).body 31 | p = Path(b,source=test2) 32 | pg = PathGroup(p) 33 | 34 | pg.explore() 35 | assert len(pg.completed) == 8 36 | assert set([p.state.any_list('l').pop() for p in pg.completed]) == set(range(8)) 37 | 38 | 39 | def test_function_List_append(): 40 | b = ast_parse.parse(test1).body 41 | p = Path(b,source=test1) 42 | pg = PathGroup(p) 43 | 44 | pg.explore() 45 | assert len(pg.completed) == 1 46 | assert pg.completed[0].state.any_list('l') == [1, 2.3, [1, 2.2, 3]] 47 | 48 | -------------------------------------------------------------------------------- /tests/test_function_List_clear.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | import logging 6 | from pySym import Colorer 7 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 8 | 9 | from pySym import ast_parse 10 | import z3 11 | from pySym.pyPath import Path 12 | from pySym.pyPathGroup import PathGroup 13 | import pytest 14 | from pySym.pyObjectManager.Int import Int 15 | from pySym.pyObjectManager.Real import Real 16 | from pySym.pyObjectManager.BitVec import BitVec 17 | from pySym.pyObjectManager.List import List 18 | 19 | test1 = """ 20 | l = [1,2,3] 21 | l.clear() 22 | """ 23 | 24 | test2 = """ 25 | l = [1,2,3] 26 | l.clear() 27 | l.append(5) 28 | """ 29 | 30 | def test_function_String_clear_append(): 31 | b = ast_parse.parse(test2).body 32 | p = Path(b,source=test2) 33 | pg = PathGroup(p) 34 | 35 | pg.explore() 36 | 37 | assert len(pg.completed) == 1 38 | 39 | assert pg.completed[0].state.any_list('l') == [5] 40 | 41 | 42 | def test_function_String_clear_basic(): 43 | b = ast_parse.parse(test1).body 44 | p = Path(b,source=test1) 45 | pg = PathGroup(p) 46 | 47 | pg.explore() 48 | 49 | assert len(pg.completed) == 1 50 | 51 | assert pg.completed[0].state.any_list('l') == [] 52 | 53 | 54 | -------------------------------------------------------------------------------- /tests/test_function_String_index.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | import logging 6 | from pySym import Colorer 7 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 8 | 9 | from pySym import ast_parse 10 | import z3 11 | from pySym.pyPath import Path 12 | from pySym.pyPathGroup import PathGroup 13 | import pytest 14 | from pySym.pyObjectManager.Int import Int 15 | from pySym.pyObjectManager.Real import Real 16 | from pySym.pyObjectManager.BitVec import BitVec 17 | from pySym.pyObjectManager.List import List 18 | 19 | test1 = """ 20 | s = "Test" 21 | x = s.index("{0}") 22 | """ 23 | 24 | test2 = """ 25 | s = pyState.String(10) 26 | x = s.index('a') 27 | """ 28 | 29 | test3 = """ 30 | s = pyState.String(10) 31 | x = -1 32 | if s[3] == "a": 33 | x = s.index('a') 34 | """ 35 | 36 | 37 | 38 | def test_function_String_Index_PartiallySymbolic(): 39 | b = ast_parse.parse(test3).body 40 | p = Path(b,source=test3) 41 | pg = PathGroup(p) 42 | 43 | pg.explore() 44 | 45 | # Every index should be a possibility 46 | assert len(pg.completed) == 5 47 | 48 | indexes = [] 49 | # Make sure we got all of them 50 | for path in pg.completed: 51 | indexes.append(path.state.any_int('x')) 52 | 53 | assert set(indexes) == set(range(4)).union({-1}) 54 | 55 | 56 | 57 | def test_function_String_Index_Symbolic(): 58 | b = ast_parse.parse(test2).body 59 | p = Path(b,source=test2) 60 | pg = PathGroup(p) 61 | 62 | pg.explore() 63 | 64 | # Every index should be a possibility 65 | assert len(pg.completed) == 10 66 | 67 | indexes = [] 68 | # Make sure we got all of them 69 | for path in pg.completed: 70 | indexes.append(path.state.any_int('x')) 71 | 72 | assert set(indexes) == set(range(10)) 73 | 74 | 75 | def test_function_String_Index(): 76 | b = ast_parse.parse(test1.format("T")).body 77 | p = Path(b,source=test1.format("T")) 78 | pg = PathGroup(p) 79 | 80 | pg.explore() 81 | assert len(pg.completed) == 1 82 | 83 | assert pg.completed[0].state.any_int('x') == 0 84 | 85 | b = ast_parse.parse(test1.format("t")).body 86 | p = Path(b,source=test1.format("t")) 87 | pg = PathGroup(p) 88 | 89 | pg.explore() 90 | assert len(pg.completed) == 1 91 | 92 | assert pg.completed[0].state.any_int('x') == 3 93 | 94 | b = ast_parse.parse(test1.format("es")).body 95 | p = Path(b,source=test1.format("es")) 96 | pg = PathGroup(p) 97 | 98 | pg.explore() 99 | assert len(pg.completed) == 1 100 | 101 | assert pg.completed[0].state.any_int('x') == 1 102 | 103 | b = ast_parse.parse(test1.format("st")).body 104 | p = Path(b,source=test1.format("st")) 105 | pg = PathGroup(p) 106 | 107 | pg.explore() 108 | assert len(pg.completed) == 1 109 | 110 | assert pg.completed[0].state.any_int('x') == 2 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /tests/test_function_String_join.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | import logging 6 | from pySym import Colorer 7 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 8 | 9 | from pySym import ast_parse 10 | import z3 11 | from pySym.pyPath import Path 12 | from pySym.pyPathGroup import PathGroup 13 | import pytest 14 | from pySym.pyObjectManager.Int import Int 15 | from pySym.pyObjectManager.Real import Real 16 | from pySym.pyObjectManager.BitVec import BitVec 17 | from pySym.pyObjectManager.List import List 18 | 19 | test1 = """ 20 | x = ''.join(["1","2","3"]) 21 | y = ','.join(["4","5","6"]) 22 | z = "".join([str(i) for i in [1,2,3]]) 23 | """ 24 | 25 | test2 = """ 26 | s = pyState.String(8) 27 | x = "".join([str(x) for x in range(s.index('a'))]) 28 | """ 29 | 30 | def test_function_strJoin_statesplit(): 31 | b = ast_parse.parse(test2).body 32 | p = Path(b,source=test2) 33 | pg = PathGroup(p) 34 | 35 | pg.explore() 36 | assert len(pg.completed) == 8 37 | out = [p.state.any_str('x') for p in pg.completed] 38 | out.sort() 39 | assert out == ['', '0', '01', '012', '0123', '01234', '012345', '0123456'] 40 | 41 | 42 | def test_function_strJoin(): 43 | b = ast_parse.parse(test1).body 44 | p = Path(b,source=test1) 45 | pg = PathGroup(p) 46 | 47 | pg.explore() 48 | assert len(pg.completed) == 1 49 | 50 | assert pg.completed[0].state.any_str('x') == ''.join(["1","2","3"]) 51 | assert pg.completed[0].state.any_str('y') == ','.join(["4","5","6"]) 52 | assert pg.completed[0].state.any_str('z') == "".join([str(i) for i in [1,2,3]]) 53 | -------------------------------------------------------------------------------- /tests/test_function_String_rstrip.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | import logging 6 | from pySym import Colorer 7 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 8 | 9 | from pySym import ast_parse 10 | import z3 11 | from pySym.pyPath import Path 12 | from pySym.pyPathGroup import PathGroup 13 | import pytest 14 | from pySym.pyObjectManager.Int import Int 15 | from pySym.pyObjectManager.Real import Real 16 | from pySym.pyObjectManager.BitVec import BitVec 17 | from pySym.pyObjectManager.List import List 18 | 19 | test1 = """ 20 | x = "test ".rstrip() 21 | y = "test".rstrip() 22 | z = "test".rstrip("t") 23 | d = "test".rstrip("st") 24 | """ 25 | 26 | test2 = """ 27 | s = pyState.String(8) 28 | x = "test1".rstrip(str(s.index('a'))) 29 | """ 30 | 31 | test3 = """ 32 | s = pyState.String(2) 33 | x = "testt" 34 | x = x.rstrip(s) 35 | """ 36 | 37 | test4 = """ 38 | s = pyState.String(8) 39 | x = s.rstrip("x") 40 | """ 41 | 42 | test5 = """ 43 | s = "mee" 44 | s2 = pyState.String(1) 45 | x = ''.join([x for x in s.rstrip(s2)]) 46 | """ 47 | 48 | test6 = """ 49 | x = "test".rstrip(pyState.String(1) + "t") 50 | """ 51 | 52 | def test_function_String_rstrip_partiallySymbolic(): 53 | b = ast_parse.parse(test6).body 54 | p = Path(b,source=test6) 55 | pg = PathGroup(p) 56 | 57 | pg.explore() 58 | assert len(pg.completed) == 3 59 | o = [p.state.any_str('x') for p in pg.completed] 60 | o.sort() 61 | assert o == ['te', 'tes', 'tes'] 62 | 63 | 64 | def test_function_String_rstrip_Char(): 65 | b = ast_parse.parse(test5).body 66 | p = Path(b,source=test5) 67 | pg = PathGroup(p) 68 | 69 | pg.explore() 70 | assert len(pg.completed) == 2 71 | assert set([p.state.any_str('x') for p in pg.completed]) == {"m","mee"} 72 | 73 | 74 | def test_function_String_rstrip_symbolicStrip(): 75 | b = ast_parse.parse(test3).body 76 | p = Path(b,source=test3) 77 | pg = PathGroup(p) 78 | 79 | pg.explore() 80 | assert len(pg.completed) == 5 81 | o = [p.state.any_str('x') for p in pg.completed] 82 | o.sort() 83 | # 3 cases. 1) both chars miss, 2) one char hit's "t" and the other misses. 3) one hits 84 | # "t" and the other hits "s" 85 | assert o == ['te', 'te', 'tes', 'tes', 'testt'] 86 | 87 | b = ast_parse.parse(test4).body 88 | p = Path(b,source=test4) 89 | pg = PathGroup(p) 90 | 91 | pg.explore() 92 | assert len(pg.completed) == 9 93 | 94 | # TODO: This is a brittle match.. 95 | o = [p.state.any_str('s') for p in pg.completed] 96 | # Sort by number of 'x' that appear in the output 97 | o = sorted(o, key=lambda x: x.count('x')) 98 | assert not o[0].endswith("x") 99 | for x in range(1,8): 100 | assert o[x].endswith("x"*x) 101 | #['\x00\x00\x00\x00\x00\x00\x00\x00', '\x00\x00\x00\x00\x00\x00\x00x', '\x00\x00\x00\x00\x00\x00xx', '\x00\x00\x00\x00\x00xxx', '\x00\x00\x00\x00xxxx', '\x00\x00\x00xxxxx', '\x00\x00xxxxxx', '\x00xxxxxxx', 'xxxxxxxx'] 102 | 103 | 104 | 105 | def test_function_String_rstrip_statesplit(): 106 | b = ast_parse.parse(test2).body 107 | p = Path(b,source=test2) 108 | pg = PathGroup(p) 109 | 110 | pg.explore() 111 | assert len(pg.completed) == 8 112 | o = [p.state.any_str('x') for p in pg.completed] 113 | o.sort() 114 | assert o == ['test', 'test1', 'test1', 'test1', 'test1', 'test1', 'test1', 'test1'] 115 | 116 | 117 | def test_function_String_rstrip(): 118 | b = ast_parse.parse(test1).body 119 | p = Path(b,source=test1) 120 | pg = PathGroup(p) 121 | 122 | pg.explore() 123 | assert len(pg.completed) == 1 124 | 125 | assert pg.completed[0].state.any_str('x') == "test ".rstrip() 126 | assert pg.completed[0].state.any_str('y') == "test".rstrip() 127 | assert pg.completed[0].state.any_str('z') == "test".rstrip("t") 128 | assert pg.completed[0].state.any_str('d') == "test".rstrip("st") 129 | 130 | -------------------------------------------------------------------------------- /tests/test_function_String_zfill.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | import logging 6 | from pySym import Colorer 7 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 8 | 9 | from pySym import ast_parse 10 | import z3 11 | from pySym.pyPath import Path 12 | from pySym.pyPathGroup import PathGroup 13 | import pytest 14 | from pySym.pyObjectManager.Int import Int 15 | from pySym.pyObjectManager.Real import Real 16 | from pySym.pyObjectManager.BitVec import BitVec 17 | from pySym.pyObjectManager.List import List 18 | 19 | test1 = """ 20 | x = "test" 21 | y = x.zfill(5) 22 | z = x.zfill(3) 23 | d = x.zfill(10) 24 | """ 25 | 26 | test2 = """ 27 | s = pyState.String(8) 28 | x = "test" 29 | y = x.zfill(s.index('a')) 30 | """ 31 | 32 | def test_function_String_zfill_statesplit(): 33 | b = ast_parse.parse(test2).body 34 | p = Path(b,source=test2) 35 | pg = PathGroup(p) 36 | 37 | pg.explore() 38 | 39 | # Every index should be a possibility 40 | assert len(pg.completed) == 8 41 | 42 | o = [p.state.any_str('y') for p in pg.completed] 43 | o.sort() 44 | assert o == ['000test', '00test', '0test', 'test', 'test', 'test', 'test', 'test'] 45 | 46 | 47 | def test_function_String_zfill_static(): 48 | b = ast_parse.parse(test1).body 49 | p = Path(b,source=test1) 50 | pg = PathGroup(p) 51 | 52 | pg.explore() 53 | 54 | # Every index should be a possibility 55 | assert len(pg.completed) == 1 56 | 57 | assert pg.completed[0].state.any_str('x') == "test" 58 | assert pg.completed[0].state.any_str('y') == "0test" 59 | assert pg.completed[0].state.any_str('z') == "test" 60 | assert pg.completed[0].state.any_str('d') == "000000test" 61 | 62 | -------------------------------------------------------------------------------- /tests/test_function_abs.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | #myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | import logging 6 | from pySym import Colorer 7 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 8 | 9 | from pySym import ast_parse 10 | import z3 11 | from pySym.pyPath import Path 12 | from pySym.pyPathGroup import PathGroup 13 | import pytest 14 | from pySym.pyObjectManager.Int import Int 15 | from pySym.pyObjectManager.Real import Real 16 | from pySym.pyObjectManager.BitVec import BitVec 17 | from pySym.pyObjectManager.List import List 18 | 19 | test1 = """ 20 | x = 10 21 | y = -10 22 | z = pyState.Int() 23 | a = abs(x) 24 | b = abs(y) 25 | c = abs(10) 26 | d = abs(-10) 27 | e = abs(z) 28 | """ 29 | 30 | def test_funcion_abs(): 31 | b = ast_parse.parse(test1).body 32 | p = Path(b,source=test1) 33 | pg = PathGroup(p) 34 | 35 | pg.explore() 36 | 37 | assert len(pg.completed) == 1 38 | assert pg.completed[0].state.any_int('a') == 10 39 | assert pg.completed[0].state.any_int('b') == 10 40 | assert pg.completed[0].state.any_int('c') == 10 41 | assert pg.completed[0].state.any_int('d') == 10 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /tests/test_function_bin.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | import logging 6 | from pySym import Colorer 7 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 8 | 9 | from pySym import ast_parse 10 | import z3 11 | from pySym.pyPath import Path 12 | from pySym.pyPathGroup import PathGroup 13 | import pytest 14 | from pySym.pyObjectManager.Int import Int 15 | from pySym.pyObjectManager.Real import Real 16 | from pySym.pyObjectManager.BitVec import BitVec 17 | from pySym.pyObjectManager.List import List 18 | 19 | test1 = """ 20 | s = 5 21 | x = bin(12) 22 | y = bin(13)[2:] 23 | z = bin(s) 24 | """ 25 | 26 | test2 = """ 27 | s = pyState.String(8) 28 | x = bin(s.index('a')) 29 | """ 30 | 31 | def test_funcion_bin_StateSplit(): 32 | b = ast_parse.parse(test2).body 33 | p = Path(b,source=test2) 34 | pg = PathGroup(p) 35 | 36 | pg.explore() 37 | 38 | # We should get 8 states back 39 | assert len(pg.completed) == 8 40 | assert set([int(p.state.any_str('x'),2) for p in pg.completed]) == set(range(8)) 41 | 42 | 43 | def test_function_bin(): 44 | b = ast_parse.parse(test1).body 45 | p = Path(b,source=test1) 46 | pg = PathGroup(p) 47 | 48 | pg.explore() 49 | assert len(pg.completed) == 1 50 | 51 | assert pg.completed[0].state.any_str('x') == bin(12) 52 | assert pg.completed[0].state.any_str('y') == bin(13)[2:] 53 | assert pg.completed[0].state.any_str('z') == bin(5) 54 | 55 | -------------------------------------------------------------------------------- /tests/test_function_chr.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | 4 | import logging 5 | from pySym import Colorer 6 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 7 | 8 | from pySym import ast_parse 9 | import z3 10 | from pySym.pyPath import Path 11 | from pySym.pyPathGroup import PathGroup 12 | import pytest 13 | from pySym.pyObjectManager.Int import Int 14 | from pySym.pyObjectManager.Real import Real 15 | from pySym.pyObjectManager.BitVec import BitVec 16 | from pySym.pyObjectManager.List import List 17 | import pySym 18 | 19 | test1 = """ 20 | i = 88 # 'X' 21 | c = chr(i) 22 | """ 23 | 24 | test2 = """ 25 | i = pyState.Int() 26 | c = chr(i) 27 | """ 28 | 29 | def test_function_chr_symbolic_input(): 30 | b = ast_parse.parse(test2).body 31 | p = Path(b,source=test2) 32 | pg = PathGroup(p) 33 | pg.explore() 34 | 35 | assert len(pg.completed) == 1 36 | 37 | i = pg.completed[0].state.getVar('i') 38 | c = pg.completed[0].state.getVar('c') 39 | 40 | # Set i, check that it propagates to c. 41 | i.setTo(ord('X')) 42 | assert str(c) == "X" 43 | 44 | def test_function_chr(): 45 | b = ast_parse.parse(test1).body 46 | p = Path(b,source=test1) 47 | pg = PathGroup(p) 48 | 49 | pg.explore() 50 | assert len(pg.completed) == 1 51 | 52 | assert chr(pg.completed[0].state.any_int('c')) == 'X' 53 | -------------------------------------------------------------------------------- /tests/test_function_hex.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | import logging 6 | from pySym import Colorer 7 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 8 | 9 | from pySym import ast_parse 10 | import z3 11 | from pySym.pyPath import Path 12 | from pySym.pyPathGroup import PathGroup 13 | import pytest 14 | from pySym.pyObjectManager.Int import Int 15 | from pySym.pyObjectManager.Real import Real 16 | from pySym.pyObjectManager.BitVec import BitVec 17 | from pySym.pyObjectManager.List import List 18 | 19 | test1 = """ 20 | x = hex(12) 21 | y = 1337 22 | z = hex(y) 23 | """ 24 | 25 | test2 = """ 26 | s = pyState.String(8) 27 | x = hex(s.index('a')) 28 | """ 29 | 30 | def test_function_hex_StateSplit(): 31 | b = ast_parse.parse(test2).body 32 | p = Path(b,source=test2) 33 | pg = PathGroup(p) 34 | 35 | pg.explore() 36 | assert len(pg.completed) == 8 37 | assert set([int(p.state.any_str('x'),16) for p in pg.completed]) == set(range(8)) 38 | 39 | 40 | def test_function_hex(): 41 | b = ast_parse.parse(test1).body 42 | p = Path(b,source=test1) 43 | pg = PathGroup(p) 44 | 45 | pg.explore() 46 | assert len(pg.completed) == 1 47 | 48 | assert pg.completed[0].state.any_str('x') == hex(12) 49 | assert pg.completed[0].state.any_str('z') == hex(1337) 50 | 51 | -------------------------------------------------------------------------------- /tests/test_function_int.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | import logging 6 | from pySym import Colorer 7 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 8 | 9 | from pySym import ast_parse 10 | import z3 11 | from pySym.pyPath import Path 12 | from pySym.pyPathGroup import PathGroup 13 | import pytest 14 | from pySym.pyObjectManager.Int import Int 15 | from pySym.pyObjectManager.Real import Real 16 | from pySym.pyObjectManager.BitVec import BitVec 17 | from pySym.pyObjectManager.List import List 18 | 19 | test1 = """ 20 | x = int("123") 21 | y = int(12.3) 22 | z = int("0b1101",2) 23 | """ 24 | 25 | test2 = """ 26 | q = int("12","10") 27 | """ 28 | 29 | test3 = """ 30 | s = pyState.String(8) 31 | x = int(s.index('a')) 32 | """ 33 | 34 | def test_function_int_statesplit(): 35 | b = ast_parse.parse(test3).body 36 | p = Path(b,source=test3) 37 | pg = PathGroup(p) 38 | 39 | pg.explore() 40 | assert len(pg.completed) == 8 41 | assert set([p.state.any_int('x') for p in pg.completed]) == set(range(8)) 42 | 43 | 44 | def test_function_int(): 45 | b = ast_parse.parse(test1).body 46 | p = Path(b,source=test1) 47 | pg = PathGroup(p) 48 | 49 | pg.explore() 50 | assert len(pg.completed) == 1 51 | 52 | assert pg.completed[0].state.any_int('x') == int("123") 53 | assert pg.completed[0].state.any_int('y') == int(12.3) 54 | assert pg.completed[0].state.any_int('z') == int("0b1101",2) 55 | 56 | b = ast_parse.parse(test2).body 57 | p = Path(b,source=test2) 58 | pg = PathGroup(p) 59 | 60 | pg.explore() 61 | assert len(pg.errored) == 1 62 | 63 | 64 | -------------------------------------------------------------------------------- /tests/test_function_len.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | import logging 6 | from pySym import Colorer 7 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 8 | 9 | from pySym import ast_parse 10 | import z3 11 | from pySym.pyPath import Path 12 | from pySym.pyPathGroup import PathGroup 13 | import pytest 14 | from pySym.pyObjectManager.Int import Int 15 | from pySym.pyObjectManager.Real import Real 16 | from pySym.pyObjectManager.BitVec import BitVec 17 | from pySym.pyObjectManager.List import List 18 | 19 | test1 = """ 20 | s = "abcd" 21 | l = [x for x in s] + [1,2] 22 | x = len(s) 23 | y = len(l) 24 | """ 25 | 26 | test2 = """ 27 | s = pyState.String(8) 28 | x = len("A" * s.index('a')) 29 | """ 30 | 31 | def test_fnuction_len_statesplit(): 32 | b = ast_parse.parse(test2).body 33 | p = Path(b,source=test2) 34 | pg = PathGroup(p) 35 | 36 | pg.explore() 37 | assert len(pg.completed) == 8 38 | assert set([p.state.any_int('x') for p in pg.completed]) == set(range(8)) 39 | 40 | 41 | def test_function_len(): 42 | b = ast_parse.parse(test1).body 43 | p = Path(b,source=test1) 44 | pg = PathGroup(p) 45 | 46 | pg.explore() 47 | assert len(pg.completed) == 1 48 | 49 | assert pg.completed[0].state.any_int('x') == 4 50 | assert pg.completed[0].state.any_int('y') == 6 51 | 52 | -------------------------------------------------------------------------------- /tests/test_function_ord.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | 4 | import logging 5 | from pySym import Colorer 6 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 7 | 8 | from pySym import ast_parse 9 | import z3 10 | from pySym.pyPath import Path 11 | from pySym.pyPathGroup import PathGroup 12 | import pytest 13 | from pySym.pyObjectManager.Int import Int 14 | from pySym.pyObjectManager.Real import Real 15 | from pySym.pyObjectManager.BitVec import BitVec 16 | from pySym.pyObjectManager.List import List 17 | import pySym 18 | 19 | test1 = """ 20 | x = ord("A") 21 | s = "Test" 22 | y = ord(s[0]) 23 | """ 24 | 25 | test2 = """ 26 | s = pyState.String(8) 27 | x = ord(str(s.index('a'))) 28 | """ 29 | 30 | def test_function_ord_symbolic_input(): 31 | proj = pySym.Project(os.path.join(myPath, "scripts", "ord_symbolic_chr.py")) 32 | pg = proj.factory.path_group() 33 | pg.explore() 34 | 35 | assert len(pg.completed) == 1 36 | 37 | s = pg.completed[0].state.getVar('s') 38 | c = pg.completed[0].state.getVar('c') 39 | 40 | # Set the integer value, back prop to the string 41 | c.setTo(ord('X')) 42 | assert str(s)[1] == "X" 43 | 44 | 45 | def test_function_ord_StateSplitting(): 46 | b = ast_parse.parse(test2).body 47 | p = Path(b,source=test2) 48 | pg = PathGroup(p) 49 | 50 | pg.explore() 51 | assert len(pg.completed) == 8 52 | assert set([p.state.any_int('x') for p in pg.completed]) == set([ord(str(x)) for x in range(8)]) 53 | 54 | 55 | 56 | def test_function_ord(): 57 | b = ast_parse.parse(test1).body 58 | p = Path(b,source=test1) 59 | pg = PathGroup(p) 60 | 61 | pg.explore() 62 | assert len(pg.completed) == 1 63 | 64 | assert chr(pg.completed[0].state.any_int('x')) == "A" 65 | assert chr(pg.completed[0].state.any_int('y')) == "T" 66 | 67 | 68 | -------------------------------------------------------------------------------- /tests/test_function_pyState_BVS.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | 4 | import logging 5 | from pySym import Colorer 6 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 7 | 8 | from pySym import ast_parse 9 | import z3 10 | from pySym.pyPath import Path 11 | from pySym.pyPathGroup import PathGroup 12 | import pytest 13 | from pySym.pyObjectManager.Int import Int 14 | from pySym.pyObjectManager.Real import Real 15 | from pySym.pyObjectManager.BitVec import BitVec 16 | from pySym.pyObjectManager.List import List 17 | from pySym.pyState.z3Helpers import Z3_MAX_STRING_LENGTH 18 | 19 | test1 = """ 20 | s1 = pyState.BVS(1) 21 | s2 = pyState.BVS(1) 22 | """ 23 | 24 | test2 = """ 25 | l = [] 26 | 27 | for i in range(24): 28 | l.append(pyState.BVS(1)) 29 | """ 30 | 31 | def test_function_pyState_BVS_ret_as_list(): 32 | b = ast_parse.parse(test2).body 33 | p = Path(b,source=test2) 34 | pg = PathGroup(p) 35 | 36 | pg.explore() 37 | assert len(pg.completed) == 1 38 | 39 | def test_function_pyState_BVS_basic(): 40 | b = ast_parse.parse(test1).body 41 | p = Path(b,source=test1) 42 | pg = PathGroup(p) 43 | 44 | pg.explore() 45 | assert len(pg.completed) == 1 46 | 47 | s1 = pg.completed[0].state.getVar('s1') 48 | s2 = pg.completed[0].state.getVar('s2') 49 | 50 | # Make sure that we're not duplicating variables on creation 51 | assert str(s1.getZ3Object()) != str(s2.getZ3Object()) 52 | -------------------------------------------------------------------------------- /tests/test_function_pyState_BVV.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | 4 | import logging 5 | from pySym import Colorer 6 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 7 | 8 | from pySym import ast_parse 9 | import z3 10 | from pySym.pyPath import Path 11 | from pySym.pyPathGroup import PathGroup 12 | import pytest 13 | from pySym.pyObjectManager.Int import Int 14 | from pySym.pyObjectManager.Real import Real 15 | from pySym.pyObjectManager.BitVec import BitVec 16 | from pySym.pyObjectManager.List import List 17 | from pySym.pyState.z3Helpers import Z3_MAX_STRING_LENGTH 18 | 19 | test1 = """ 20 | x = pyState.BVV((16 >> 4)&1,1) # Results in BitVec 1 of size 1 21 | y = pyState.BVV((16 >> 4)&1,2**10) # Results in BitVec 1 of size 1024 22 | """ 23 | 24 | def test_function_pyState_BVV_basic(): 25 | b = ast_parse.parse(test1).body 26 | p = Path(b,source=test1) 27 | pg = PathGroup(p) 28 | 29 | pg.explore() 30 | assert len(pg.completed) == 1 31 | 32 | x = pg.completed[0].state.getVar('x') 33 | y = pg.completed[0].state.getVar('y') 34 | 35 | assert x.isStatic() and x.mustBe(1) and x.size == 1 36 | assert y.isStatic() and y.mustBe(1) and y.size == 1024 37 | -------------------------------------------------------------------------------- /tests/test_function_pyState_Real.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | import logging 6 | from pySym import Colorer 7 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 8 | 9 | from pySym import ast_parse 10 | import z3 11 | from pySym.pyPath import Path 12 | from pySym.pyPathGroup import PathGroup 13 | import pytest 14 | from pySym.pyObjectManager.Int import Int 15 | from pySym.pyObjectManager.Real import Real 16 | from pySym.pyObjectManager.BitVec import BitVec 17 | from pySym.pyObjectManager.List import List 18 | from pySym.pyState.z3Helpers import Z3_MAX_STRING_LENGTH 19 | 20 | test1 = """ 21 | s = pyState.Real() 22 | s2 = pyState.Real(123) 23 | s3 = pyState.Real(123.5) 24 | """ 25 | 26 | 27 | def test_function_pyState_Real(): 28 | b = ast_parse.parse(test1).body 29 | p = Path(b,source=test1) 30 | pg = PathGroup(p) 31 | 32 | pg.explore() 33 | assert len(pg.completed) == 1 34 | 35 | s = pg.completed[0].state.getVar('s') 36 | s2 = pg.completed[0].state.getVar('s2') 37 | s3 = pg.completed[0].state.getVar('s3') 38 | 39 | assert type(s) == Real 40 | assert type(s2) == Real 41 | assert type(s3) == Real 42 | 43 | assert s.canBe(123.0) 44 | assert s2.getValue() == 123.0 45 | assert s3.getValue() == 123.5 46 | -------------------------------------------------------------------------------- /tests/test_function_pyState_String.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | import logging 6 | from pySym import Colorer 7 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 8 | 9 | from pySym import ast_parse 10 | import z3 11 | from pySym.pyPath import Path 12 | from pySym.pyPathGroup import PathGroup 13 | import pytest 14 | from pySym.pyObjectManager.Int import Int 15 | from pySym.pyObjectManager.Real import Real 16 | from pySym.pyObjectManager.BitVec import BitVec 17 | from pySym.pyObjectManager.List import List 18 | from pySym.pyState.z3Helpers import Z3_MAX_STRING_LENGTH 19 | 20 | test1 = """ 21 | s = pyState.String(32) 22 | s2 = pyState.String() 23 | """ 24 | 25 | 26 | def test_function_pyState_String(): 27 | b = ast_parse.parse(test1).body 28 | p = Path(b,source=test1) 29 | pg = PathGroup(p) 30 | 31 | pg.explore() 32 | assert len(pg.completed) == 1 33 | 34 | s = pg.completed[0].state.getVar('s') 35 | s2 = pg.completed[0].state.getVar('s2') 36 | 37 | assert len(s) == 32 38 | assert len(s2) == Z3_MAX_STRING_LENGTH 39 | 40 | -------------------------------------------------------------------------------- /tests/test_function_range.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | import logging 6 | from pySym import Colorer 7 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 8 | 9 | 10 | from pySym import ast_parse 11 | import z3 12 | from pySym.pyPath import Path 13 | from pySym.pyPathGroup import PathGroup 14 | import pytest 15 | 16 | test1 = """ 17 | out = 0 18 | for i in range(0,10,2): 19 | for j in range(5): 20 | out += i + j 21 | """ 22 | 23 | test2 = """ 24 | out = 0 25 | l = range(4,10) 26 | """ 27 | 28 | test3 = """ 29 | out = 0 30 | l = range(12) 31 | """ 32 | 33 | test4 = """ 34 | s = pyState.String(8) 35 | x = range(s.index('a')) 36 | """ 37 | 38 | def test_function_range_StateSplit(): 39 | b = ast_parse.parse(test4).body 40 | p = Path(b,source=test4) 41 | pg = PathGroup(p) 42 | 43 | pg.explore() 44 | assert len(pg.completed) == 8 45 | out = [p.state.any_list('x') for p in pg.completed] 46 | out.sort() 47 | assert out == [[], [0], [0, 1], [0, 1, 2], [0, 1, 2, 3], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5, 6]] 48 | 49 | 50 | def test_function_range(): 51 | b = ast_parse.parse(test1).body 52 | p = Path(b,source=test1) 53 | pg = PathGroup(p) 54 | 55 | pg.explore() 56 | 57 | assert len(pg.completed) == 1 58 | assert pg.completed[0].state.any_int('out') == 150 59 | 60 | b = ast_parse.parse(test2).body 61 | p = Path(b,source=test2) 62 | pg = PathGroup(p) 63 | 64 | pg.explore() 65 | assert len(pg.completed) == 1 66 | assert pg.completed[0].state.any_list('l') == [4, 5, 6, 7, 8, 9] 67 | 68 | b = ast_parse.parse(test3).body 69 | p = Path(b,source=test3) 70 | pg = PathGroup(p) 71 | 72 | pg.explore() 73 | assert len(pg.completed) == 1 74 | assert pg.completed[0].state.any_list('l') == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] 75 | 76 | -------------------------------------------------------------------------------- /tests/test_function_str.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | import logging 6 | from pySym import Colorer 7 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 8 | 9 | from pySym import ast_parse 10 | import z3 11 | from pySym.pyPath import Path 12 | from pySym.pyPathGroup import PathGroup 13 | import pytest 14 | from pySym.pyObjectManager.Int import Int 15 | from pySym.pyObjectManager.Real import Real 16 | from pySym.pyObjectManager.BitVec import BitVec 17 | from pySym.pyObjectManager.List import List 18 | 19 | test1 = """ 20 | s = str(12) 21 | s2 = str(1.2) 22 | s3 = str([1,2,3]) 23 | """ 24 | 25 | test2 = """ 26 | s = pyState.String(8) 27 | x = str(s.index('a')) 28 | """ 29 | 30 | def test_function_str_statesplit(): 31 | b = ast_parse.parse(test2).body 32 | p = Path(b,source=test2) 33 | pg = PathGroup(p) 34 | 35 | pg.explore() 36 | assert len(pg.completed) == 8 37 | 38 | set([int(p.state.any_str('x')) for p in pg.completed]) == set(range(8)) 39 | 40 | 41 | def test_function_str(): 42 | b = ast_parse.parse(test1).body 43 | p = Path(b,source=test1) 44 | pg = PathGroup(p) 45 | 46 | pg.explore() 47 | assert len(pg.completed) == 1 48 | 49 | assert pg.completed[0].state.any_str('s') == str(12) 50 | assert pg.completed[0].state.any_str('s2') == str(1.2) 51 | assert pg.completed[0].state.any_str('s3') == str([1,2,3]) 52 | -------------------------------------------------------------------------------- /tests/test_function_zip.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | import logging 6 | from pySym import Colorer 7 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 8 | 9 | from pySym import ast_parse 10 | import z3 11 | from pySym.pyPath import Path 12 | from pySym.pyPathGroup import PathGroup 13 | import pytest 14 | from pySym.pyObjectManager.Int import Int 15 | from pySym.pyObjectManager.Real import Real 16 | from pySym.pyObjectManager.BitVec import BitVec 17 | from pySym.pyObjectManager.List import List 18 | 19 | test1 = """ 20 | l = zip([1,2,3],[4,5,6]) 21 | l1 = [1,2,3] 22 | l2 = [4,5,6] 23 | l3 = zip(l1,l2) 24 | l4 = ["1","2","3"] 25 | l5 = ["4","5","6"] 26 | l6 = zip(l4,l5) 27 | l7 = zip(["1","2","3","4"],["5","6"]) 28 | l8 = zip(["1","2"],["3","4","5","6"]) 29 | l9 = zip([1,2,3],"abc") 30 | """ 31 | 32 | 33 | def test_function_zip(): 34 | b = ast_parse.parse(test1).body 35 | p = Path(b,source=test1) 36 | pg = PathGroup(p) 37 | 38 | pg.explore() 39 | assert len(pg.completed) == 1 40 | 41 | assert pg.completed[0].state.any_list('l') == [[1, 4], [2, 5], [3, 6]] 42 | assert pg.completed[0].state.any_list('l3') == [[1, 4], [2, 5], [3, 6]] 43 | assert pg.completed[0].state.any_list('l6') == [["1", "4"], ["2", "5"], ["3", "6"]] 44 | assert pg.completed[0].state.any_list('l7') == [["1","5"], ["2","6"]] 45 | assert pg.completed[0].state.any_list('l8') == [["1","3"], ["2","4"]] 46 | assert pg.completed[0].state.any_list('l9') == [[1,"a"],[2,"b"],[3,"c"]] 47 | 48 | 49 | -------------------------------------------------------------------------------- /tests/test_path.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | from pySym import ast_parse 6 | import z3 7 | from pySym.pyPath import Path 8 | import pytest 9 | 10 | test1 = "x = 1\ny = 2" 11 | 12 | simpleIf = """ 13 | x = 1 14 | y = 1 15 | if x > y: 16 | print("This shouldn't hit") 17 | else: 18 | print("This should hit") 19 | x = 2 20 | """ 21 | 22 | testIfReturn = """ 23 | x = 1 24 | y = 1.2 25 | if y > x: 26 | x += 1 27 | else: 28 | x -= 1 29 | 30 | y += 1 31 | """ 32 | 33 | def test_ifReturn(): 34 | b = ast_parse.parse(testIfReturn).body 35 | p = Path(b,source=testIfReturn) 36 | p = p.step()[0].step()[0] 37 | ifSide,elseSide = p.step() 38 | ifSide = ifSide.step()[0].step()[0] 39 | elseSide = elseSide.step()[0].step()[0] 40 | 41 | assert ifSide.state.any_int('x') == 2 42 | assert ifSide.state.any_real('y') == 2.2 43 | assert elseSide.state.any_int('x') == None 44 | assert elseSide.state.any_real('y') == None # Else side is wonky because it's not a possible path 45 | 46 | 47 | def test_basicPathStep(): 48 | b = ast_parse.parse(test1).body 49 | p1 = Path(b,source=test1) 50 | p2 = p1.step()[0].step()[0] 51 | p1.printBacktrace() 52 | p2.printBacktrace() 53 | assert p2.state.any_int('x') == 1 54 | assert p2.state.any_int('y') == 2 55 | with pytest.raises(Exception): 56 | p1.state.any_int('x') 57 | with pytest.raises(Exception): 58 | p1.state.any_int('y') 59 | 60 | def test_pathCopy(): 61 | b = ast_parse.parse(test1).body 62 | p = Path(b,source=test1) 63 | p2 = p.copy() 64 | assert p2 != p 65 | p = p.step()[0] 66 | assert p.state.any_int('x') == 1 67 | with pytest.raises(Exception): 68 | p2.state.any_int('x') 69 | 70 | def test_simpleIf(): 71 | b = ast_parse.parse(simpleIf).body 72 | p = Path(b,source=simpleIf) 73 | # Step through the "if" statement 74 | p = p.step()[0] 75 | p = p.step()[0] 76 | p2 = p.step() 77 | ifSide = p2[0] 78 | elseSide = p2[1] 79 | 80 | # ifSide's path should now be inside, meaning only the print statement 81 | assert len(ifSide.state.path) == 1 82 | # Else should be in the else statement 83 | assert len(elseSide.state.path) == 2 84 | 85 | # Neither have anything to do after the if statement 86 | assert len(ifSide.state.callStack) == 1 87 | assert len(elseSide.state.callStack) == 0 88 | 89 | # If side should not be possible 90 | assert not ifSide.state.isSat() 91 | assert elseSide.state.isSat() 92 | 93 | # Track expected number of assertions 94 | #assert len(ifSide.state.solver.assertions()) == 3 95 | #assert len(elseSide.state.solver.assertions()) == 3 96 | 97 | # Make sure the answer makes sense 98 | assert ifSide.state.any_int('x') == None 99 | assert elseSide.state.any_int('x') == 1 100 | -------------------------------------------------------------------------------- /tests/test_project.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | 4 | import z3 5 | import pySym 6 | import pytest 7 | 8 | def test_basic_hooking(): 9 | # Temporarily bastardizing the hook dictionary to pass state back to my test. ONLY for this test. 10 | proj = pySym.Project(os.path.join(myPath, "scripts", "basic_function.py")) 11 | 12 | def my_hook(state): 13 | state._project._hooks[6969] = True 14 | assert isinstance(state, pySym.pyState.State) 15 | 16 | proj.hook(6, my_hook) 17 | proj._hooks[6969] = False 18 | pg = proj.factory.path_group() 19 | pg.explore() 20 | 21 | assert proj._hooks[6969] 22 | 23 | def test_basic_project(): 24 | proj = pySym.Project(os.path.join(myPath, "scripts", "basic_function.py")) 25 | pg = proj.factory.path_group() 26 | pg.explore() 27 | 28 | assert len(pg.deadended) == 1 29 | assert len(pg.completed) == 1 30 | assert pg.completed[0].state.any_int('x') == 1 31 | 32 | # Make sure we're passing the project through fully 33 | assert pg._project is proj 34 | assert pg.deadended[0]._project is proj 35 | assert pg.deadended[0].state._project is proj 36 | assert pg.completed[0]._project is proj 37 | assert pg.completed[0].state._project is proj 38 | 39 | -------------------------------------------------------------------------------- /tests/test_pyObjectManager.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | import logging 6 | from pySym import Colorer 7 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 8 | 9 | from pySym import ast_parse 10 | import z3 11 | from pySym.pyPath import Path 12 | from pySym.pyPathGroup import PathGroup 13 | import pytest 14 | from pySym.pyObjectManager.Int import Int 15 | from pySym.pyObjectManager.Real import Real 16 | from pySym.pyObjectManager.BitVec import BitVec 17 | from pySym.pyObjectManager.List import List 18 | 19 | test1 = """ 20 | l = [1,2.2,3] 21 | q = [1,2,[3,4]] 22 | """ 23 | 24 | test2 = """ 25 | l = [1,2,3] 26 | s = "test" 27 | i = 1337 28 | bvs = pyState.BVS(32) 29 | """ 30 | 31 | def test_pyObjectManager_uuid(): 32 | b = ast_parse.parse(test2).body 33 | p = Path(b,source=test2) 34 | pg = PathGroup(p) 35 | 36 | pg.explore() 37 | assert len(pg.completed) == 1 38 | 39 | s = pg.completed[0].state.copy() 40 | l = s.getVar('l') 41 | for elm in l: 42 | assert type(elm.uuid) is bytes 43 | assert type(l.uuid) is bytes 44 | 45 | st = s.getVar('s') 46 | assert type(st.uuid) is bytes 47 | for elm in st: 48 | assert type(elm.uuid) is bytes 49 | 50 | i = s.getVar('i') 51 | assert type(i.uuid) is bytes 52 | 53 | bvs = s.getVar('bvs') 54 | assert type(bvs.uuid) is bytes 55 | 56 | 57 | def test_pyObjectManager_getParent(): 58 | b = ast_parse.parse(test1).body 59 | p = Path(b,source=test1) 60 | pg = PathGroup(p) 61 | 62 | pg.explore() 63 | assert len(pg.completed) == 1 64 | 65 | l = pg.completed[0].state.getVar('l') 66 | i = l[2] 67 | 68 | # Make sure it returned the right object 69 | assert pg.completed[0].state.objectManager.getParent(i) == l 70 | 71 | q = pg.completed[0].state.getVar('q') 72 | i = q[2][0] 73 | 74 | # Check that it recurses fully 75 | assert pg.completed[0].state.objectManager.getParent(i) == q[2] 76 | 77 | 78 | -------------------------------------------------------------------------------- /tests/test_pyObjectManager_BitVec.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | import logging 6 | from pySym import Colorer 7 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 8 | 9 | from pySym import ast_parse 10 | import z3 11 | from pySym.pyPath import Path 12 | from pySym.pyPathGroup import PathGroup 13 | import pytest 14 | from pySym.pyObjectManager.Int import Int 15 | from pySym.pyObjectManager.Real import Real 16 | from pySym.pyObjectManager.BitVec import BitVec 17 | from pySym.pyObjectManager.List import List 18 | 19 | test1 = """ 20 | x = pyState.BVV(5,16) 21 | """ 22 | 23 | test2 = """ 24 | x = pyState.BVS(32) 25 | y = pyState.BVV(15,32) 26 | """ 27 | 28 | test3 = """ 29 | x = pyState.BVV(1234,32) 30 | """ 31 | 32 | test4 = """ 33 | x = pyState.BVS(32) 34 | assert x == 1234 35 | """ 36 | 37 | def test_pyObjectManager_BitVec_as_int(): 38 | b = ast_parse.parse(test4).body 39 | p = Path(b,source=test4) 40 | pg = PathGroup(p) 41 | 42 | pg.explore() 43 | assert len(pg.completed) == 1 44 | 45 | s = pg.completed[0].state.copy() 46 | x = s.getVar('x') 47 | assert int(x) == 1234 48 | 49 | 50 | def test_pyObjectManager_BitVec_is_unconstrained(): 51 | b = ast_parse.parse(test2).body 52 | p = Path(b,source=test2) 53 | pg = PathGroup(p) 54 | 55 | pg.explore() 56 | assert len(pg.completed) == 1 57 | 58 | s = pg.completed[0].state.copy() 59 | x = s.getVar('x') 60 | 61 | assert x.is_unconstrained 62 | 63 | # add a real constraint 64 | s.addConstraint(x.getZ3Object() > 14) 65 | assert x.is_constrained 66 | 67 | 68 | def test_pyObjectManager_BitVec_strPrint(): 69 | b = ast_parse.parse(test3).body 70 | p = Path(b,source=test3) 71 | pg = PathGroup(p) 72 | 73 | pg.explore() 74 | assert len(pg.completed) == 1 75 | 76 | x = pg.completed[0].state.getVar('x') 77 | assert x.__str__() == "1234" 78 | 79 | 80 | def test_pyObjectManager_BitVec_setTo(): 81 | b = ast_parse.parse(test2).body 82 | p = Path(b,source=test2) 83 | pg = PathGroup(p) 84 | 85 | pg.explore() 86 | assert len(pg.completed) == 1 87 | 88 | x = pg.completed[0].state.getVar('x') 89 | y = pg.completed[0].state.getVar('y') 90 | 91 | x.setTo(1337) 92 | assert pg.completed[0].state.any_int('x') == 1337 93 | 94 | x.increment() 95 | x.setTo(y) 96 | assert pg.completed[0].state.any_int('x') == 15 97 | 98 | 99 | 100 | def test_pyObjectManager_BitVec_isStatic(): 101 | b = ast_parse.parse(test1).body 102 | p = Path(b,source=test1) 103 | pg = PathGroup(p) 104 | 105 | pg.explore() 106 | assert len(pg.completed) == 1 107 | 108 | x = pg.completed[0].state.getVar('x') 109 | 110 | assert x.isStatic() 111 | assert x.getValue() == 5 112 | 113 | 114 | -------------------------------------------------------------------------------- /tests/test_pyObjectManager_Char.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | import logging 6 | from pySym import Colorer 7 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 8 | 9 | from pySym import ast_parse 10 | import z3 11 | from pySym.pyPath import Path 12 | from pySym.pyPathGroup import PathGroup 13 | import pytest 14 | from pySym.pyObjectManager.Int import Int 15 | from pySym.pyObjectManager.Real import Real 16 | from pySym.pyObjectManager.BitVec import BitVec 17 | from pySym.pyObjectManager.List import List 18 | from pySym.pyObjectManager.Char import Char 19 | 20 | test1 = """ 21 | s = "Test" 22 | d = pyState.String(10) 23 | """ 24 | 25 | test2 = """ 26 | s = "Blerg" 27 | c2 = pyState.String(1) 28 | """ 29 | 30 | test3 = """ 31 | c = "b" 32 | """ 33 | 34 | test4 = """ 35 | s = pyState.String(1) 36 | d = "Test" 37 | e = "Feet" 38 | """ 39 | 40 | def test_pyObjectManager_Char_is_unconstrained(): 41 | b = ast_parse.parse(test2).body 42 | p = Path(b,source=test2) 43 | pg = PathGroup(p) 44 | 45 | pg.explore() 46 | assert len(pg.completed) == 1 47 | 48 | s = pg.completed[0].state.copy() 49 | c = s.getVar('s')[0] 50 | 51 | assert c.is_unconstrained 52 | 53 | # For now, this will add bounded int constraints to the solver... 54 | z3_obj = c.getZ3Object() 55 | # Those bounds should not count as constrained 56 | assert c.is_unconstrained 57 | 58 | # This constraint should eval to True, and not be added 59 | s.addConstraint(z3_obj > 5) 60 | assert c.is_unconstrained 61 | 62 | # Try with symbolic 63 | c = s.getVar('c2')[0] 64 | 65 | assert c.is_unconstrained 66 | 67 | # For now, this will add bounded int constraints to the solver... 68 | z3_obj = c.getZ3Object() 69 | # Those bounds should not count as constrained 70 | assert c.is_unconstrained 71 | 72 | # This should add a real constraint 73 | s.addConstraint(z3_obj > 5) 74 | assert c.is_constrained 75 | 76 | def test_pyObjectManager_Char_mustBe(): 77 | b = ast_parse.parse(test4).body 78 | p = Path(b,source=test4) 79 | pg = PathGroup(p) 80 | 81 | pg.explore() 82 | assert len(pg.completed) == 1 83 | 84 | s = pg.completed[0].state.getVar('s') 85 | d = pg.completed[0].state.getVar('d') 86 | e = pg.completed[0].state.getVar('e') 87 | 88 | assert s[0].canBe(d[0]) 89 | assert s[0].canBe("b") 90 | assert not s[0].mustBe("b") 91 | assert not s[0].mustBe(d[0]) 92 | assert not s[0].canBe("test") 93 | 94 | assert d[1].canBe(e[1]) 95 | assert d[1].mustBe(e[2]) 96 | 97 | 98 | def test_pyObjectManager_Char_strPrint(): 99 | b = ast_parse.parse(test3).body 100 | p = Path(b,source=test3) 101 | pg = PathGroup(p) 102 | 103 | pg.explore() 104 | assert len(pg.completed) == 1 105 | 106 | c = pg.completed[0].state.getVar('c') 107 | c = c[0] 108 | 109 | assert c.__str__() == "b" 110 | 111 | 112 | def test_pyObjectManager_Char_setTo(): 113 | b = ast_parse.parse(test2).body 114 | p = Path(b,source=test2) 115 | pg = PathGroup(p) 116 | 117 | pg.explore() 118 | assert len(pg.completed) == 1 119 | 120 | c = pg.completed[0].state.getVar('c',varType=Char) 121 | 122 | c.setTo('x') 123 | assert c.getValue() == "x" 124 | 125 | 126 | def test_pyObjectManager_Char_isStatic(): 127 | b = ast_parse.parse(test1).body 128 | p = Path(b,source=test1) 129 | pg = PathGroup(p) 130 | 131 | pg.explore() 132 | assert len(pg.completed) == 1 133 | 134 | s = pg.completed[0].state.getVar('s') 135 | d = pg.completed[0].state.getVar('d') 136 | 137 | assert s[0].isStatic() 138 | assert s[0].getValue() == "T" 139 | 140 | assert not d.isStatic() 141 | 142 | -------------------------------------------------------------------------------- /tests/test_pyObjectManager_Int.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | import logging 6 | from pySym import Colorer 7 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 8 | 9 | from pySym import ast_parse 10 | import z3 11 | from pySym.pyPath import Path 12 | from pySym.pyPathGroup import PathGroup 13 | import pytest 14 | from pySym.pyObjectManager.Int import Int 15 | from pySym.pyObjectManager.Real import Real 16 | from pySym.pyObjectManager.BitVec import BitVec 17 | from pySym.pyObjectManager.List import List 18 | 19 | test1 = """ 20 | x = 1 21 | """ 22 | 23 | test2 = """ 24 | x = pyState.Int() 25 | y = 5 26 | """ 27 | 28 | test3 = """ 29 | x = 12 30 | """ 31 | 32 | test4 = """ 33 | l = [pyState.Int(), pyState.Int()] 34 | if l[0] != l[1]: 35 | pass 36 | if l[0] == l[1]: 37 | pass 38 | 39 | pass 40 | """ 41 | 42 | test5 = """ 43 | i = pyState.Int() 44 | l = [0,1,2,3,4,5] 45 | x = l[i] 46 | """ 47 | 48 | def test_pyObjectManager_Int_is_unconstrained(): 49 | b = ast_parse.parse(test2).body 50 | p = Path(b,source=test2) 51 | pg = PathGroup(p) 52 | 53 | pg.explore() 54 | assert len(pg.completed) == 1 55 | 56 | s = pg.completed[0].state.copy() 57 | x = s.getVar('x') 58 | 59 | assert x.is_unconstrained 60 | 61 | # add a real constraint 62 | s.addConstraint(x.getZ3Object() > 5) 63 | assert x.is_constrained 64 | 65 | 66 | def test_pyObjectManager_Int_PostSet(): 67 | b = ast_parse.parse(test5).body 68 | p = Path(b,source=test5) 69 | pg = PathGroup(p) 70 | 71 | pg.explore() 72 | assert len(pg.completed) == 1 73 | 74 | for q in range(6): 75 | s = pg.completed[0].state.copy() 76 | x = s.getVar('x') 77 | i = s.getVar('i') 78 | i.setTo(q) 79 | assert x.getValue() == q 80 | 81 | 82 | 83 | def test_pyObjectManager_Int_MultipleObj(): 84 | b = ast_parse.parse(test4).body 85 | p = Path(b,source=test4) 86 | pg = PathGroup(p) 87 | 88 | pg.explore(find=4) 89 | assert len(pg.found) == 1 90 | 91 | pg = PathGroup(p) 92 | pg.explore(find=6) 93 | 94 | assert len(pg.found) == 1 95 | 96 | def test_pyObjectManager_Int_strPrint(): 97 | b = ast_parse.parse(test3).body 98 | p = Path(b,source=test3) 99 | pg = PathGroup(p) 100 | 101 | pg.explore() 102 | assert len(pg.completed) == 1 103 | 104 | x = pg.completed[0].state.getVar('x') 105 | assert x.__str__() == "12" 106 | 107 | def test_pyObjectManager_Int_setTo(): 108 | b = ast_parse.parse(test2).body 109 | p = Path(b,source=test2) 110 | pg = PathGroup(p) 111 | 112 | pg.explore() 113 | assert len(pg.completed) == 1 114 | 115 | x = pg.completed[0].state.getVar('x') 116 | y = pg.completed[0].state.getVar('y') 117 | x.setTo(1337) 118 | 119 | assert pg.completed[0].state.any_int('x') == 1337 120 | x.increment() 121 | x.setTo(y) 122 | 123 | #assert pg.completed[0].state.any_int('x') == 5 124 | assert x.getValue() == 5 125 | 126 | 127 | def test_pyObjectManager_Int_isStatic(): 128 | b = ast_parse.parse(test1).body 129 | p = Path(b,source=test1) 130 | pg = PathGroup(p) 131 | 132 | pg.explore() 133 | assert len(pg.completed) == 1 134 | 135 | x = pg.completed[0].state.getVar('x') 136 | 137 | assert x.isStatic() 138 | assert x.getValue() == 1 139 | 140 | 141 | -------------------------------------------------------------------------------- /tests/test_pyObjectManager_Real.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | import logging 6 | from pySym import Colorer 7 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 8 | 9 | from pySym import ast_parse 10 | import z3 11 | from pySym.pyPath import Path 12 | from pySym.pyPathGroup import PathGroup 13 | import pytest 14 | from pySym.pyObjectManager.Int import Int 15 | from pySym.pyObjectManager.Real import Real 16 | from pySym.pyObjectManager.BitVec import BitVec 17 | from pySym.pyObjectManager.List import List 18 | 19 | test1 = """ 20 | x = 1.5 21 | """ 22 | 23 | test2 = """ 24 | x = pyState.Real() 25 | y = 5.5 26 | z = 2 27 | """ 28 | 29 | test3 = """ 30 | x = 6.2 31 | """ 32 | 33 | 34 | 35 | def test_pyObjectManager_Real_strPrint(): 36 | b = ast_parse.parse(test3).body 37 | p = Path(b,source=test3) 38 | pg = PathGroup(p) 39 | 40 | pg.explore() 41 | assert len(pg.completed) == 1 42 | 43 | x = pg.completed[0].state.getVar('x') 44 | assert x.__str__() == "6.2" 45 | 46 | 47 | def test_pyObjectManager_Real_setTo(): 48 | b = ast_parse.parse(test2).body 49 | p = Path(b,source=test2) 50 | pg = PathGroup(p) 51 | 52 | pg.explore() 53 | assert len(pg.completed) == 1 54 | 55 | x = pg.completed[0].state.getVar('x') 56 | y = pg.completed[0].state.getVar('y') 57 | z = pg.completed[0].state.getVar('z') 58 | 59 | x.setTo(1337.4) 60 | assert pg.completed[0].state.any_real('x') == 1337.4 61 | x.increment() 62 | x.setTo(y) 63 | assert pg.completed[0].state.any_real('x') == 5.5 64 | 65 | x.increment() 66 | x.setTo(z) 67 | assert pg.completed[0].state.any_real('z') == 2 68 | 69 | 70 | 71 | def test_pyObjectManager_Real_isStatic(): 72 | b = ast_parse.parse(test1).body 73 | p = Path(b,source=test1) 74 | pg = PathGroup(p) 75 | 76 | pg.explore() 77 | assert len(pg.completed) == 1 78 | 79 | x = pg.completed[0].state.getVar('x') 80 | 81 | assert x.isStatic() 82 | assert x.getValue() == 1.5 83 | 84 | 85 | -------------------------------------------------------------------------------- /tests/test_pyObjectManager_String.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | import logging 6 | from pySym import Colorer 7 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 8 | 9 | from pySym import ast_parse 10 | import z3 11 | from pySym.pyPath import Path 12 | from pySym.pyPathGroup import PathGroup 13 | import pytest 14 | from pySym.pyObjectManager.Int import Int 15 | from pySym.pyObjectManager.Real import Real 16 | from pySym.pyObjectManager.BitVec import BitVec 17 | from pySym.pyObjectManager.List import List 18 | 19 | test1 = """ 20 | s = "Test" 21 | """ 22 | 23 | test2 = """ 24 | s = "Test" 25 | l = [x for x in s] 26 | """ 27 | 28 | test3 = """ 29 | s = "abcd" 30 | d = "abcd" 31 | f = "Abcd" 32 | g = pyState.String(4) 33 | """ 34 | 35 | test4 = """ 36 | s = "abcd" 37 | d = pyState.String(5) 38 | """ 39 | 40 | def test_pyObjectManager_String_isStatic(): 41 | b = ast_parse.parse(test4).body 42 | p = Path(b,source=test4) 43 | pg = PathGroup(p) 44 | 45 | pg.explore() 46 | assert len(pg.completed) == 1 47 | 48 | s = pg.completed[0].state.getVar('s') 49 | d = pg.completed[0].state.getVar('d') 50 | 51 | assert s.isStatic() 52 | assert s.getValue() == "abcd" 53 | 54 | assert not d.isStatic() 55 | 56 | 57 | def test_pyObjectManager_String_canBe_mustBe_String(): 58 | b = ast_parse.parse(test3).body 59 | p = Path(b,source=test3) 60 | pg = PathGroup(p) 61 | 62 | pg.explore() 63 | assert len(pg.completed) == 1 64 | 65 | s = pg.completed[0].state.getVar('s') 66 | d = pg.completed[0].state.getVar('d') 67 | f = pg.completed[0].state.getVar('f') 68 | g = pg.completed[0].state.getVar('g') 69 | 70 | assert s.canBe(d) 71 | assert not s.canBe(f) 72 | assert g.canBe(s) 73 | assert not g.mustBe(s) 74 | assert g.canBe(f) 75 | 76 | 77 | def test_pyObjectMAnager_String_mustBe(): 78 | b = ast_parse.parse(test1).body 79 | p = Path(b,source=test1) 80 | pg = PathGroup(p) 81 | 82 | pg.explore() 83 | assert len(pg.completed) == 1 84 | 85 | s = pg.completed[0].state.getVar('s') 86 | 87 | assert s.mustBe("Test") 88 | assert not s.mustBe("test") 89 | 90 | 91 | def test_pyObjectManager_String_canBe(): 92 | b = ast_parse.parse(test1).body 93 | p = Path(b,source=test1) 94 | pg = PathGroup(p) 95 | 96 | pg.explore() 97 | assert len(pg.completed) == 1 98 | 99 | s = pg.completed[0].state.getVar('s') 100 | 101 | assert s.canBe("Test") 102 | assert not s.canBe("test") 103 | assert s[0:1].canBe("T") 104 | assert not s[0:2].canBe("T3") 105 | assert s[:3].canBe("Tes") 106 | 107 | 108 | def test_pyObjectManager_String_ListComp(): 109 | b = ast_parse.parse(test2).body 110 | p = Path(b,source=test2) 111 | pg = PathGroup(p) 112 | 113 | pg.explore() 114 | assert len(pg.completed) == 1 115 | 116 | assert pg.completed[0].state.any_list('l') == [x for x in "Test"] 117 | 118 | 119 | def test_pyObjectManager_String_Assign(): 120 | b = ast_parse.parse(test1).body 121 | p = Path(b,source=test1) 122 | pg = PathGroup(p) 123 | 124 | pg.explore() 125 | assert len(pg.completed) == 1 126 | 127 | assert pg.completed[0].state.any_str('s') == "Test" 128 | 129 | 130 | -------------------------------------------------------------------------------- /tests/test_pyPathGroup.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | import logging 6 | from pySym import Colorer 7 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 8 | from pySym import ast_parse 9 | import z3 10 | from pySym.pyPath import Path 11 | from pySym.pyPathGroup import PathGroup 12 | 13 | test1 = """ 14 | def test2(): 15 | return 5 16 | 17 | def test(): 18 | return test2() + test2() 19 | 20 | x = test() 21 | z = 1 22 | """ 23 | 24 | test2 = """ 25 | def test(): 26 | return 5 + 1.5 27 | 28 | x = test() 29 | 30 | if x > 5: 31 | x = 1 32 | else: 33 | x = 0 34 | 35 | if x == 1: 36 | x = 1337 37 | 38 | z = 1 39 | """ 40 | 41 | test3 = """ 42 | def test(): 43 | return 5 44 | 45 | if test() == 5.0: 46 | x = 1 47 | else: 48 | x = 0 49 | 50 | q = 5 51 | """ 52 | 53 | test4 = """ 54 | s = "A"*16 55 | 56 | for c in s: 57 | if c == "A": 58 | q = 1 59 | else: 60 | q = 2 61 | """ 62 | 63 | def test_pyPathGroup_ignore_paths(): 64 | b = ast_parse.parse(test4).body 65 | p = Path(b,source=test4) 66 | pg = PathGroup(p,ignore_groups=['deadended']) 67 | 68 | # Execute to the end 69 | pg.explore() 70 | 71 | assert len(pg.completed) == 1 72 | assert len(pg.deadended) == 0 73 | 74 | 75 | def test_pyPathGroup_exploreFunctionCompare(): 76 | b = ast_parse.parse(test3).body 77 | p = Path(b,source=test3) 78 | pg = PathGroup(p) 79 | 80 | # Execute to the end 81 | assert pg.explore(find=10) 82 | 83 | assert len(pg.active) == 0 84 | assert len(pg.completed) == 0 85 | assert len(pg.errored) == 0 86 | assert len(pg.deadended) == 1 87 | assert len(pg.found) == 1 88 | 89 | assert pg.found[0].state.any_int('x') == 1 90 | 91 | 92 | def test_pyPathGroup_exploreWithIf(): 93 | b = ast_parse.parse(test2).body 94 | p = Path(b,source=test2) 95 | pg = PathGroup(p) 96 | 97 | # Explore to the end 98 | assert pg.explore(find=15) 99 | 100 | assert len(pg.active) == 0 101 | assert len(pg.completed) == 0 102 | assert len(pg.errored) == 0 103 | assert len(pg.deadended) == 2 104 | assert len(pg.found) == 1 105 | 106 | assert pg.found[0].state.any_int('x') == 1337 107 | 108 | 109 | def test_pyPath_exploreFindLine(): 110 | b = ast_parse.parse(test1).body 111 | p = Path(b,source=test1) 112 | pg = PathGroup(p) 113 | 114 | # Explore to line 9 (z = 1) 115 | # Current setup means that z=1 will not actually be executed 116 | assert pg.explore(find=9) 117 | 118 | assert len(pg.active) == 0 119 | assert len(pg.completed) == 0 120 | assert len(pg.errored) == 0 121 | assert len(pg.deadended) == 0 122 | assert len(pg.found) == 1 123 | 124 | assert pg.found[0].state.any_int('x') == 10 125 | 126 | 127 | def test_pyPath_stepThroughProgram(): 128 | b = ast_parse.parse(test1).body 129 | p = Path(b,source=test1) 130 | pg = PathGroup(p) 131 | pg.explore() 132 | 133 | assert len(pg.active) == 0 134 | assert len(pg.completed) == 1 135 | assert len(pg.errored) == 0 136 | assert len(pg.deadended) == 0 137 | assert len(pg.found) == 0 138 | 139 | assert pg.completed[0].state.any_int('x') == 10 140 | assert pg.completed[0].state.any_int('z') == 1 141 | 142 | -------------------------------------------------------------------------------- /tests/test_pyState_Assert.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | 4 | import logging 5 | from pySym import Colorer 6 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 7 | 8 | from pySym import ast_parse 9 | import z3 10 | from pySym.pyPath import Path 11 | from pySym.pyPathGroup import PathGroup 12 | import pySym 13 | import pytest 14 | 15 | def test_assert_compare(): 16 | proj = pySym.Project(os.path.join(myPath, "scripts", "assert_script_1.py")) 17 | pg = proj.factory.path_group() 18 | pg.explore() 19 | 20 | assert len(pg.completed) == 1 21 | s = pg.completed[0].state.copy() 22 | i = s.getVar('i') 23 | 24 | # Try some values 25 | assert all([x%12==4 for x in s.any_n_int(i, 32)]) 26 | -------------------------------------------------------------------------------- /tests/test_pyState_Break.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | from pySym import ast_parse 6 | import z3 7 | from pySym.pyPath import Path 8 | import pytest 9 | from pySym.pyPathGroup import PathGroup 10 | 11 | test1 = """ 12 | x = 0 13 | y = 1 14 | while x < 10: 15 | if x == 5: 16 | if y == 1: 17 | break 18 | x += 1 19 | 20 | y = 1 21 | """ 22 | 23 | test2 = """ 24 | out = 0 25 | q = [1,2,3,4,5] 26 | for x in q: 27 | for y in [10,11,12,13]: 28 | out += x + y 29 | 30 | if x == 3: 31 | break 32 | """ 33 | 34 | def test_pySym_breakFor(): 35 | b = ast_parse.parse(test2).body 36 | p = Path(b,source=test2) 37 | pg = PathGroup(p) 38 | 39 | pg.explore() 40 | 41 | assert len(pg.completed) == 1 42 | assert pg.completed[0].state.any_int('out') == 162 43 | assert pg.completed[0].state.any_int('x') == 3 44 | 45 | 46 | def test_pySym_breakWhile(): 47 | b = ast_parse.parse(test1).body 48 | p = Path(b,source=test1) 49 | pg = PathGroup(p) 50 | 51 | pg.explore() 52 | 53 | assert len(pg.completed) == 1 54 | assert pg.completed[0].state.any_int('x') == 5 55 | 56 | 57 | -------------------------------------------------------------------------------- /tests/test_pyState_For.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | import logging 6 | from pySym import Colorer 7 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 8 | 9 | 10 | from pySym import ast_parse 11 | import z3 12 | from pySym.pyPath import Path 13 | from pySym.pyPathGroup import PathGroup 14 | import pytest 15 | 16 | test1 = """ 17 | out = 0 18 | for x in [1,2,3,4,5]: 19 | out += x 20 | """ 21 | 22 | test2 = """ 23 | out = 0 24 | for x in [1,2,3,4,5]: 25 | for y in [10,11,12,13]: 26 | out += x + y 27 | """ 28 | 29 | test3 = """ 30 | out = 0 31 | q = [1,2,3,4,5] 32 | for x in q: 33 | for y in [10,11,12,13]: 34 | out += x + y 35 | """ 36 | 37 | test4 = """ 38 | out = 0 39 | q = [1,2,3,4,5] 40 | for x in q[:2]: 41 | for y in [10,11,12,13]: 42 | out += x + y 43 | 44 | if x == 3: 45 | break 46 | """ 47 | 48 | test5 = """ 49 | a = 0 50 | b = 0 51 | for x in zip([1,8],[2,3]): 52 | a += x[0] 53 | b += x[1] 54 | """ 55 | 56 | def test_pySym_For_ListReturn(): 57 | b = ast_parse.parse(test5).body 58 | p = Path(b,source=test5) 59 | pg = PathGroup(p) 60 | 61 | pg.explore() 62 | assert len(pg.completed) == 1 63 | 64 | assert pg.completed[0].state.any_int('a') == 9 65 | assert pg.completed[0].state.any_int('b') == 5 66 | 67 | 68 | def test_pySym_variableSlice(): 69 | b = ast_parse.parse(test4).body 70 | p = Path(b,source=test4) 71 | pg = PathGroup(p) 72 | 73 | pg.explore() 74 | assert len(pg.completed) == 1 75 | assert pg.completed[0].state.any_int('out') == 104 76 | 77 | 78 | def test_pySym_variableFor(): 79 | b = ast_parse.parse(test3).body 80 | p = Path(b,source=test3) 81 | pg = PathGroup(p) 82 | 83 | pg.explore() 84 | assert len(pg.completed) == 1 85 | assert pg.completed[0].state.any_int('out') == 290 86 | assert pg.completed[0].state.any_list('q') == [1,2,3,4,5] 87 | 88 | 89 | def test_pySym_nestedFor(): 90 | b = ast_parse.parse(test2).body 91 | p = Path(b,source=test2) 92 | pg = PathGroup(p) 93 | 94 | pg.explore() 95 | assert len(pg.completed) == 1 96 | assert pg.completed[0].state.any_int('out') == 290 97 | 98 | 99 | def test_pySym_stupidFor(): 100 | b = ast_parse.parse(test1).body 101 | p = Path(b,source=test1) 102 | pg = PathGroup(p) 103 | 104 | pg.explore() 105 | assert len(pg.completed) == 1 106 | assert pg.completed[0].state.any_int('out') == 15 107 | assert pg.completed[0].state.any_int('x') == 5 108 | 109 | 110 | -------------------------------------------------------------------------------- /tests/test_pyState_FuncionDef.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | from pySym import ast_parse 6 | import z3 7 | from pySym.pyPath import Path 8 | import pytest 9 | 10 | test1 = """ 11 | def test(): 12 | x = 12 13 | 14 | def test2(a,b,c): 15 | a = 13 16 | """ 17 | 18 | 19 | def test_pySym_FuncionDef(): 20 | b = ast_parse.parse(test1).body 21 | p = Path(b,source=test1) 22 | # Step through program 23 | p = p.step()[0] 24 | p = p.step()[0] 25 | # We should have two defs now 26 | assert "test" in p.state.functions 27 | assert "test2" in p.state.functions 28 | -------------------------------------------------------------------------------- /tests/test_pyState_GeneratorExp.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | import logging 6 | from pySym import Colorer 7 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 8 | 9 | 10 | from pySym import ast_parse 11 | import z3 12 | from pySym.pyPath import Path 13 | from pySym.pyPathGroup import PathGroup 14 | import pytest 15 | 16 | test1 = """ 17 | x = "".join(str(i) for i in range(5)) 18 | """ 19 | 20 | def test_pyState_GeneratorExp_General(): 21 | b = ast_parse.parse(test1).body 22 | p = Path(b,source=test1) 23 | pg = PathGroup(p) 24 | 25 | pg.explore() 26 | assert len(pg.completed) == 1 27 | assert pg.completed[0].state.any_str('x') == "".join(str(i) for i in range(5)) 28 | 29 | 30 | -------------------------------------------------------------------------------- /tests/test_pyState_If.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | import logging 6 | from pySym import Colorer 7 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 8 | 9 | 10 | from pySym import ast_parse 11 | import z3 12 | from pySym.pyPath import Path 13 | from pySym.pyPathGroup import PathGroup 14 | import pytest 15 | 16 | test1 = """ 17 | x = 5 18 | y = 6 19 | if x == y or 2 == 2: 20 | pass 21 | """ 22 | 23 | test2 = """ 24 | x = 5 25 | y = 5 26 | if x == y and y + 2 == x + 2: 27 | pass 28 | """ 29 | 30 | test3 = """ 31 | s = pyState.String(8) 32 | y = 0 33 | if 2 > s.index('a'): 34 | y += 1 35 | """ 36 | 37 | test4 = """ 38 | s = pyState.String(8) 39 | x = 5 40 | y = 6 41 | z = 0 42 | if x == y or s.index('a') == 2: 43 | z += 1 44 | """ 45 | 46 | test5 = """ 47 | i = pyState.Int() 48 | l = [0,i,2] 49 | 50 | x = 0 51 | y = 0 52 | 53 | if l[0]: 54 | y = 1 55 | 56 | if l[2]: 57 | y = 2 58 | 59 | if l[1]: 60 | x = 1 61 | """ 62 | 63 | def test_pySym_If_Subscript_Int(): 64 | b = ast_parse.parse(test5).body 65 | p = Path(b,source=test5) 66 | pg = PathGroup(p) 67 | 68 | pg.explore() 69 | 70 | # Splits into 8 possibilities and then if splits again 71 | assert len(pg.completed) == 2 72 | assert len(pg.deadended) == 2 73 | 74 | s = pg.completed[0].state.copy() 75 | x = s.getVar('x') 76 | y = s.getVar('y') 77 | i = s.getVar('i') 78 | 79 | assert y.mustBe(2) 80 | 81 | if i.mustBe(0): 82 | assert x.mustBe(0) 83 | else: 84 | assert not x.canBe(0) 85 | 86 | s = pg.completed[1].state.copy() 87 | x = s.getVar('x') 88 | y = s.getVar('y') 89 | i = s.getVar('i') 90 | 91 | assert y.mustBe(2) 92 | 93 | if i.mustBe(0): 94 | assert x.mustBe(0) 95 | else: 96 | assert not x.canBe(0) 97 | 98 | 99 | def test_pySym_If_StateSplit(): 100 | b = ast_parse.parse(test3).body 101 | p = Path(b,source=test3) 102 | pg = PathGroup(p) 103 | 104 | pg.explore() 105 | 106 | # Splits into 8 possibilities and then if splits again 107 | assert len(pg.completed) == 8 108 | assert len(pg.deadended) == 8 109 | 110 | # Two of those states should hit the y+=1 111 | assert sum([p.state.any_int('y') for p in pg.completed]) == 2 112 | 113 | b = ast_parse.parse(test4).body 114 | p = Path(b,source=test4) 115 | pg = PathGroup(p) 116 | 117 | pg.explore() 118 | 119 | # Splits into 8 possibilities and then if splits again 120 | assert len(pg.completed) == 8 121 | assert len(pg.deadended) == 8 122 | 123 | # Two of those states should hit the y+=1 124 | assert sum([p.state.any_int('z') for p in pg.completed]) == 1 125 | 126 | def test_pySym_ifBoolOp(): 127 | b = ast_parse.parse(test1).body 128 | p = Path(b,source=test1) 129 | pg = PathGroup(p) 130 | 131 | pg.explore() 132 | 133 | b = ast_parse.parse(test2).body 134 | p = Path(b,source=test2) 135 | pg = PathGroup(p) 136 | 137 | pg.explore() 138 | 139 | -------------------------------------------------------------------------------- /tests/test_pyState_ListComp.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | import logging 6 | from pySym import Colorer 7 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 8 | 9 | 10 | from pySym import ast_parse 11 | import z3 12 | from pySym.pyPath import Path 13 | from pySym.pyPathGroup import PathGroup 14 | import pytest 15 | 16 | test1 = """ 17 | l = [x for x in range(5)] 18 | """ 19 | 20 | test2 = """ 21 | l = [x for x in [1,2,3,4,5] if x%2 == 0] 22 | """ 23 | 24 | test3 = """ 25 | l = [x for x in range(10) if x%2 == 0 or x%3 == 0] 26 | """ 27 | 28 | test4 = """ 29 | l = [x for x in [1,2,3,4,5] for y in [1,2,3]] 30 | """ 31 | 32 | test5 = """ 33 | l = [[x,y] for x in [1,2,3] for y in [1]] 34 | """ 35 | 36 | test6 = """ 37 | l = [x**2 for x in range(5)] 38 | """ 39 | 40 | test7 = """ 41 | s = "abcd" 42 | l = [x for x in s if x == "b"] 43 | """ 44 | 45 | test8 = """ 46 | l = [str(i) for i in range(10)] 47 | """ 48 | 49 | def test_pyState_ListComp_MoreFunctions(): 50 | b = ast_parse.parse(test8).body 51 | p = Path(b,source=test8) 52 | pg = PathGroup(p) 53 | 54 | pg.explore() 55 | assert len(pg.completed) == 1 56 | assert pg.completed[0].state.any_list('l') == [str(i) for i in range(10)] 57 | 58 | 59 | def test_pyState_ListComp_StringCmp(): 60 | b = ast_parse.parse(test7).body 61 | p = Path(b,source=test7) 62 | pg = PathGroup(p) 63 | 64 | pg.explore() 65 | assert len(pg.completed) == 1 66 | assert pg.completed[0].state.any_list('l') == ["b"] 67 | 68 | 69 | def test_pyState_ListComp_outputModifier(): 70 | b = ast_parse.parse(test6).body 71 | p = Path(b,source=test6) 72 | pg = PathGroup(p) 73 | 74 | pg.explore() 75 | assert len(pg.completed) == 1 76 | assert pg.completed[0].state.any_list('l') == [x**2 for x in range(5)] 77 | 78 | 79 | def test_pyState_ListComp_MultipleFor_ReturnList(): 80 | b = ast_parse.parse(test5).body 81 | p = Path(b,source=test5) 82 | pg = PathGroup(p) 83 | 84 | pg.explore() 85 | assert len(pg.completed) == 1 86 | assert pg.completed[0].state.any_list('l') == [[x,y] for x in [1,2,3] for y in [1]] 87 | 88 | 89 | def test_pyState_ListComp_MultipleFor(): 90 | b = ast_parse.parse(test4).body 91 | p = Path(b,source=test4) 92 | pg = PathGroup(p) 93 | 94 | pg.explore() 95 | assert len(pg.completed) == 1 96 | assert pg.completed[0].state.any_list('l') == [x for x in [1,2,3,4,5] for y in [1,2,3]] 97 | 98 | with pytest.raises(Exception): 99 | pg.completed[0].state.any_int('x') 100 | 101 | 102 | def test_pyState_ListComp_BoolComp(): 103 | b = ast_parse.parse(test3).body 104 | p = Path(b,source=test3) 105 | pg = PathGroup(p) 106 | 107 | pg.explore() 108 | assert len(pg.completed) == 1 109 | assert pg.completed[0].state.any_list('l') == [x for x in range(10) if x%2 == 0 or x%3 == 0] 110 | 111 | 112 | def test_pyState_ListComp_If(): 113 | b = ast_parse.parse(test2).body 114 | p = Path(b,source=test2) 115 | pg = PathGroup(p) 116 | 117 | pg.explore() 118 | assert len(pg.completed) == 1 119 | assert pg.completed[0].state.any_list('l') == [x for x in [1,2,3,4,5] if x%2 == 0] 120 | 121 | 122 | def test_pyState_ListComp_Simple(): 123 | b = ast_parse.parse(test1).body 124 | p = Path(b,source=test1) 125 | pg = PathGroup(p) 126 | 127 | pg.explore() 128 | assert len(pg.completed) == 1 129 | assert pg.completed[0].state.any_list('l') == [x for x in range(5)] 130 | 131 | -------------------------------------------------------------------------------- /tests/test_pyState_Pass.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | from pySym import ast_parse 6 | import z3 7 | from pySym.pyPath import Path 8 | import pytest 9 | 10 | test1 = """ 11 | x = 4 12 | pass 13 | def test(): 14 | x = 6 15 | return 5 16 | 17 | x = test() 18 | z = 1 19 | """ 20 | 21 | 22 | def test_pySym_pass(): 23 | # Testing we can pass :-) 24 | b = ast_parse.parse(test1).body 25 | p = Path(b,source=test1) 26 | p = p.step()[0] 27 | p = p.step()[0] 28 | 29 | assert p.state.any_int('x') == 4 30 | assert len(p.state.backtrace) == 2 31 | 32 | 33 | -------------------------------------------------------------------------------- /tests/test_pyState_UnaryOp.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | import logging 6 | from pySym import Colorer 7 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 8 | 9 | 10 | from pySym import ast_parse 11 | import z3 12 | from pySym.pyPath import Path 13 | from pySym.pyPathGroup import PathGroup 14 | import pytest 15 | 16 | test1 = """ 17 | x = -1 18 | y = -x 19 | z = +x 20 | """ 21 | 22 | def test_pySym_UnaryOp_Simple(): 23 | b = ast_parse.parse(test1).body 24 | p = Path(b,source=test1) 25 | pg = PathGroup(p) 26 | 27 | pg.explore() 28 | assert len(pg.completed) == 1 29 | assert pg.completed[0].state.any_int('x') == -1 30 | assert pg.completed[0].state.any_int('y') == 1 31 | assert pg.completed[0].state.any_int('z') == -1 32 | 33 | -------------------------------------------------------------------------------- /tests/test_pyState_While.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | myPath = os.path.dirname(os.path.abspath(__file__)) 3 | #sys.path.insert(0, myPath + '/../') 4 | 5 | import logging 6 | from pySym import Colorer 7 | logging.basicConfig(level=logging.DEBUG,format='%(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 8 | 9 | 10 | from pySym import ast_parse 11 | import z3 12 | from pySym.pyPath import Path 13 | from pySym.pyPathGroup import PathGroup 14 | import pytest 15 | from copy import copy 16 | 17 | 18 | test1 = """ 19 | x = 0 20 | while x < 10: 21 | x += 1 22 | 23 | y = 1 24 | """ 25 | 26 | test2 = """ 27 | def test(): 28 | return 5 29 | 30 | x = 0 31 | while x < test(): 32 | x += 1 33 | 34 | y = 1 35 | """ 36 | 37 | test3 = """ 38 | def test(x,y): 39 | return x + y 40 | 41 | x = 0 42 | z = 0 43 | while x < 5: 44 | y = 0 45 | while y < 3: 46 | z = z + test(x,y) 47 | y += 1 48 | x += 1 49 | 50 | z = z 51 | """ 52 | 53 | test4 = """ 54 | def test(x,y): 55 | return x + y 56 | 57 | x = 0 58 | z = 0 59 | while x < 5: 60 | y = 0 61 | while y < 3: 62 | z += test(x,y) 63 | y += 1 64 | x += 1 65 | 66 | z = z 67 | """ 68 | 69 | test5 = """ 70 | def test(x,y): 71 | out = 2 72 | while x < y: 73 | out *= x 74 | x += 1 75 | 76 | return out 77 | 78 | x = 0 79 | z = 0 80 | while x < 5: 81 | y = 0 82 | while y < 3: 83 | z += test(x,y) 84 | y += 1 85 | x += 1 86 | 87 | z = z 88 | """ 89 | 90 | test6 = """ 91 | x = 0 92 | y = 0 93 | o = 0 94 | while x < 10: 95 | while y < 5: 96 | o += 1 97 | y += 1 98 | x += 1 99 | 100 | print(o) 101 | """ 102 | 103 | test7 = """ 104 | s = pyState.String(3) 105 | x = 0 106 | while x < s.index('a'): 107 | x += 1 108 | """ 109 | 110 | 111 | def test_pySym_While_StateSplit(): 112 | # TODO: I'm not 100% sure this is right.. But can't think of why it's wrong atm... 113 | b = ast_parse.parse(test7).body 114 | p = Path(b,source=test7) 115 | pg = PathGroup(p) 116 | 117 | pg.explore() 118 | assert len(pg.completed) > 0 119 | 120 | assert set([p.state.any_int('x') for p in pg.completed]) == set([0,1,2]) 121 | 122 | 123 | def test_pySym_stupidWhile(): 124 | b = ast_parse.parse(test6).body 125 | p = Path(b,source=test6) 126 | pg = PathGroup(p) 127 | 128 | pg.explore() 129 | assert len(pg.completed) == 1 130 | assert pg.completed[0].state.any_int('x') == 10 131 | assert pg.completed[0].state.any_int('y') == 5 132 | assert pg.completed[0].state.any_int('o') == 5 133 | 134 | 135 | def test_pySym_complicated(): 136 | b = ast_parse.parse(test5).body 137 | p = Path(b,source=test5) 138 | pg = PathGroup(p) 139 | 140 | assert pg.explore(find=19) 141 | assert pg.found[0].state.any_int('z') == 26 142 | 143 | def test_pySym_nestedWhile(): 144 | b = ast_parse.parse(test3).body 145 | p = Path(b,source=test3) 146 | pg = PathGroup(p) 147 | 148 | assert pg.explore(find=14) 149 | assert pg.found[0].state.any_int('z') == 45 150 | 151 | b = ast_parse.parse(test4).body 152 | p = Path(b,source=test4) 153 | pg = PathGroup(p) 154 | assert pg.explore(find=14) 155 | assert pg.found[0].state.any_int('z') == 45 156 | 157 | 158 | 159 | def test_pySym_funcInWhileTest(): 160 | b = ast_parse.parse(test2).body 161 | p = Path(b,source=test2) 162 | pg = PathGroup(p) 163 | pg.explore() 164 | 165 | 166 | assert len(pg.active) == 0 167 | assert len(pg.completed) == 1 168 | assert len(pg.errored) == 0 169 | assert len(pg.deadended) == 6 170 | 171 | assert pg.completed[0].state.any_int('x') == 5 172 | 173 | 174 | def test_pySym_simpleWhile(): 175 | b = ast_parse.parse(test1).body 176 | p = Path(b,source=test1) 177 | pg = PathGroup(p) 178 | assert pg.explore(find=6) 179 | 180 | assert len(pg.active) == 0 181 | assert len(pg.completed) == 0 182 | assert len(pg.errored) == 0 183 | assert len(pg.deadended) == 11 184 | assert len(pg.found) == 1 185 | 186 | assert pg.found[0].state.isSat() 187 | assert pg.found[0].state.any_int('x') == 10 188 | 189 | --------------------------------------------------------------------------------