Exemple #1
0
def get_mappings(source, deployed_source_map):
    mappings = []
    for item in deployed_source_map:
        mapping = item.split(":")

        if len(mapping) > 0 and len(mapping[0]) > 0:
            offset = int(mapping[0])

        if len(mapping) > 1 and len(mapping[1]) > 0:
            length = int(mapping[1])

        if len(mapping) > 2 and len(mapping[2]) > 0:
            idx = int(mapping[2])

        lineno = source.encode("utf-8")[0:offset].count(
            "\n".encode("utf-8")) + 1

        mappings.append(SourceMapping(idx, offset, length, lineno))

    return mappings
Exemple #2
0
def analyze_truffle_project(args):

    project_root = os.getcwd()

    build_dir = os.path.join(project_root, "build", "contracts")

    files = os.listdir(build_dir)

    for filename in files:

        if re.match(r'.*\.json$', filename) and filename != "Migrations.json":

            with open(os.path.join(build_dir, filename)) as cf:
                contractdata = json.load(cf)

            try:
                name = contractdata['contractName']
                bytecode = contractdata['deployedBytecode']
            except:
                print(
                    "Unable to parse contract data. Please use Truffle 4 to compile your project."
                )
                sys.exit()

            if (len(bytecode) < 4):
                continue

            ethcontract = ETHContract(bytecode, name=name)

            address = util.get_indexed_address(0)
            sym = SymExecWrapper(ethcontract, address, max_depth=10)
            issues = fire_lasers(sym)

            if not len(issues):
                if (args.outform == 'text' or args.outform == 'markdown'):
                    print("# Analysis result for " + name +
                          "\n\nNo issues found.")
                else:
                    result = {
                        'contract': name,
                        'result': {
                            'success': True,
                            'error': None,
                            'issues': []
                        }
                    }
                    print(json.dumps(result))
            else:

                report = Report()
                # augment with source code

                disassembly = ethcontract.disassembly
                source = contractdata['source']

                deployedSourceMap = contractdata['deployedSourceMap'].split(
                    ";")

                mappings = []

                for item in deployedSourceMap:
                    mapping = item.split(":")

                    if len(mapping) > 0 and len(mapping[0]) > 0:
                        offset = int(mapping[0])

                    if len(mapping) > 1 and len(mapping[1]) > 0:
                        length = int(mapping[1])

                    if len(mapping) > 2 and len(mapping[2]) > 0:
                        idx = int(mapping[2])

                    lineno = source[0:offset].count('\n') + 1

                    mappings.append(SourceMapping(idx, offset, length, lineno))

                for issue in issues:

                    index = helper.get_instruction_index(
                        disassembly.instruction_list, issue.address)

                    if index:
                        try:
                            offset = mappings[index].offset
                            length = mappings[index].length

                            issue.filename = filename
                            issue.code = source[offset:offset + length]
                            issue.lineno = mappings[index].lineno
                        except IndexError:
                            logging.debug("No code mapping at index %d", index)

                    report.append_issue(issue)

                if (args.outform == 'json'):

                    result = {
                        'contract': name,
                        'result': {
                            'success': True,
                            'error': None,
                            'issues': list(map(lambda x: x.as_dict(), issues))
                        }
                    }
                    print(json.dumps(result))

                else:
                    if (args.outform == 'text'):
                        print("# Analysis result for " + name + ":\n\n" +
                              report.as_text())
                    elif (args.outform == 'markdown'):
                        print(report.as_markdown())
Exemple #3
0
def analyze_truffle_project(sigs, args):

    project_root = os.getcwd()

    build_dir = os.path.join(project_root, "build", "contracts")

    files = os.listdir(build_dir)

    for filename in files:

        if re.match(r".*\.json$", filename) and filename != "Migrations.json":

            with open(os.path.join(build_dir, filename)) as cf:
                contractdata = json.load(cf)

            try:
                name = contractdata["contractName"]
                bytecode = contractdata["deployedBytecode"]
                filename = PurePath(contractdata["sourcePath"]).name
            except KeyError:
                print(
                    "Unable to parse contract data. Please use Truffle 4 to compile your project."
                )
                sys.exit()
            if len(bytecode) < 4:
                continue

            sigs.import_from_solidity_source(contractdata["sourcePath"],
                                             solc_args=args.solc_args)
            sigs.write()

            ethcontract = ETHContract(bytecode, name=name)

            address = util.get_indexed_address(0)
            sym = SymExecWrapper(
                ethcontract,
                address,
                args.strategy,
                max_depth=args.max_depth,
                create_timeout=args.create_timeout,
                execution_timeout=args.execution_timeout,
            )
            issues = fire_lasers(sym)

            if not len(issues):
                if args.outform == "text" or args.outform == "markdown":
                    print("# Analysis result for " + name +
                          "\n\nNo issues found.")
                else:
                    result = {
                        "contract": name,
                        "result": {
                            "success": True,
                            "error": None,
                            "issues": []
                        },
                    }
                    print(json.dumps(result))
            else:

                report = Report()
                # augment with source code

                disassembly = ethcontract.disassembly
                source = contractdata["source"]

                deployed_source_map = contractdata["deployedSourceMap"].split(
                    ";")

                mappings = []

                for item in deployed_source_map:
                    mapping = item.split(":")

                    if len(mapping) > 0 and len(mapping[0]) > 0:
                        offset = int(mapping[0])

                    if len(mapping) > 1 and len(mapping[1]) > 0:
                        length = int(mapping[1])

                    if len(mapping) > 2 and len(mapping[2]) > 0:
                        idx = int(mapping[2])

                    lineno = (source.encode("utf-8")[0:offset].count(
                        "\n".encode("utf-8")) + 1)

                    mappings.append(SourceMapping(idx, offset, length, lineno))

                for issue in issues:

                    index = get_instruction_index(disassembly.instruction_list,
                                                  issue.address)

                    if index:
                        try:
                            offset = mappings[index].offset
                            length = mappings[index].length

                            issue.filename = filename
                            issue.code = source.encode("utf-8")[offset:offset +
                                                                length].decode(
                                                                    "utf-8")
                            issue.lineno = mappings[index].lineno
                        except IndexError:
                            logging.debug("No code mapping at index %d", index)

                    report.append_issue(issue)

                if args.outform == "json":

                    result = {
                        "contract": name,
                        "result": {
                            "success": True,
                            "error": None,
                            "issues": list(map(lambda x: x.as_dict, issues)),
                        },
                    }
                    print(json.dumps(result))

                else:
                    if args.outform == "text":
                        print("# Analysis result for " + name + ":\n\n" +
                              report.as_text())
                    elif args.outform == "markdown":
                        print(report.as_markdown())