diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d5917742..03888c8e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -17,7 +17,7 @@ jobs: with: python-version: 3.8 - name: Install dependencies - run: pip install 'isort==5.*' black + run: pip install -e .[dev] - name: Lint with isort run: isort --profile black --length-sort --line-width 120 -c . - name: Lint with black @@ -34,7 +34,6 @@ jobs: uses: actions/setup-python@v2 with: python-version: 3.8 - # We don't need vivisect, so we can install capa using Python3 - name: Install capa run: pip install -e . - name: Run rule linter diff --git a/capa/features/__init__.py b/capa/features/__init__.py index 1eee81b4..c88cd153 100644 --- a/capa/features/__init__.py +++ b/capa/features/__init__.py @@ -31,7 +31,7 @@ def bytes_to_str(b): def hex_string(h): - """ render hex string e.g. "0a40b1" as "0A 40 B1" """ + """render hex string e.g. "0a40b1" as "0A 40 B1" """ return " ".join(h[i : i + 2] for i in range(0, len(h), 2)).upper() diff --git a/capa/features/extractors/ida/file.py b/capa/features/extractors/ida/file.py index 5ca2370d..6f55ed45 100644 --- a/capa/features/extractors/ida/file.py +++ b/capa/features/extractors/ida/file.py @@ -78,7 +78,7 @@ def extract_file_embedded_pe(): def extract_file_export_names(): - """ extract function exports """ + """extract function exports""" for (_, _, ea, name) in idautils.Entries(): yield Export(name), ea @@ -144,7 +144,7 @@ def extract_file_strings(): def extract_features(): - """ extract file features """ + """extract file features""" for file_handler in FILE_HANDLERS: for feature, va in file_handler(): yield feature, va diff --git a/capa/features/extractors/ida/helpers.py b/capa/features/extractors/ida/helpers.py index 8c62af58..4b7dcdeb 100644 --- a/capa/features/extractors/ida/helpers.py +++ b/capa/features/extractors/ida/helpers.py @@ -79,7 +79,7 @@ def get_segment_buffer(seg): def get_file_imports(): - """ get file imports """ + """get file imports""" imports = {} for idx in range(idaapi.get_import_module_qty()): @@ -116,7 +116,7 @@ def get_instructions_in_range(start, end): def is_operand_equal(op1, op2): - """ compare two IDA op_t """ + """compare two IDA op_t""" if op1.flags != op2.flags: return False @@ -142,7 +142,7 @@ def is_operand_equal(op1, op2): def is_basic_block_equal(bb1, bb2): - """ compare two IDA BasicBlock """ + """compare two IDA BasicBlock""" if bb1.start_ea != bb2.start_ea: return False @@ -156,7 +156,7 @@ def is_basic_block_equal(bb1, bb2): def basic_block_size(bb): - """ calculate size of basic block """ + """calculate size of basic block""" return bb.end_ea - bb.start_ea @@ -174,7 +174,7 @@ def read_bytes_at(ea, count): def find_string_at(ea, min=4): - """ check if ASCII string exists at a given virtual address """ + """check if ASCII string exists at a given virtual address""" found = idaapi.get_strlit_contents(ea, -1, idaapi.STRTYPE_C) if found and len(found) > min: try: @@ -228,23 +228,23 @@ def get_op_phrase_info(op): def is_op_write(insn, op): - """ Check if an operand is written to (destination operand) """ + """Check if an operand is written to (destination operand)""" return idaapi.has_cf_chg(insn.get_canon_feature(), op.n) def is_op_read(insn, op): - """ Check if an operand is read from (source operand) """ + """Check if an operand is read from (source operand)""" return idaapi.has_cf_use(insn.get_canon_feature(), op.n) def is_op_offset(insn, op): - """ Check is an operand has been marked as an offset (by auto-analysis or manually) """ + """Check is an operand has been marked as an offset (by auto-analysis or manually)""" flags = idaapi.get_flags(insn.ea) return ida_bytes.is_off(flags, op.n) def is_sp_modified(insn): - """ determine if instruction modifies SP, ESP, RSP """ + """determine if instruction modifies SP, ESP, RSP""" for op in get_insn_ops(insn, target_ops=(idaapi.o_reg,)): if op.reg == idautils.procregs.sp.reg and is_op_write(insn, op): # register is stack and written @@ -253,7 +253,7 @@ def is_sp_modified(insn): def is_bp_modified(insn): - """ check if instruction modifies BP, EBP, RBP """ + """check if instruction modifies BP, EBP, RBP""" for op in get_insn_ops(insn, target_ops=(idaapi.o_reg,)): if op.reg == idautils.procregs.bp.reg and is_op_write(insn, op): # register is base and written @@ -262,12 +262,12 @@ def is_bp_modified(insn): def is_frame_register(reg): - """ check if register is sp or bp """ + """check if register is sp or bp""" return reg in (idautils.procregs.sp.reg, idautils.procregs.bp.reg) def get_insn_ops(insn, target_ops=()): - """ yield op_t for instruction, filter on type if specified """ + """yield op_t for instruction, filter on type if specified""" for op in insn.ops: if op.type == idaapi.o_void: # avoid looping all 6 ops if only subset exists @@ -278,7 +278,7 @@ def get_insn_ops(insn, target_ops=()): def is_op_stack_var(ea, index): - """ check if operand is a stack variable """ + """check if operand is a stack variable""" return idaapi.is_stkvar(idaapi.get_flags(ea), index) @@ -332,7 +332,7 @@ def is_basic_block_tight_loop(bb): def find_data_reference_from_insn(insn, max_depth=10): - """ search for data reference from instruction, return address of instruction if no reference exists """ + """search for data reference from instruction, return address of instruction if no reference exists""" depth = 0 ea = insn.ea @@ -375,5 +375,5 @@ def get_function_blocks(f): def is_basic_block_return(bb): - """ check if basic block is return block """ + """check if basic block is return block""" return bb.type == idaapi.fcb_ret diff --git a/capa/features/extractors/ida/insn.py b/capa/features/extractors/ida/insn.py index 3f5aef52..ec2f8070 100644 --- a/capa/features/extractors/ida/insn.py +++ b/capa/features/extractors/ida/insn.py @@ -53,7 +53,7 @@ def get_imports(ctx): def check_for_api_call(ctx, insn): - """ check instruction for API call """ + """check instruction for API call""" if not insn.get_canon_mnem() in ("call", "jmp"): return @@ -256,7 +256,7 @@ def bb_stack_cookie_registers(bb): def is_nzxor_stack_cookie_delta(f, bb, insn): - """ check if nzxor exists within stack cookie delta """ + """check if nzxor exists within stack cookie delta""" # security cookie check should use SP or BP if not capa.features.extractors.ida.helpers.is_frame_register(insn.Op2.reg): return False @@ -279,7 +279,7 @@ def is_nzxor_stack_cookie_delta(f, bb, insn): def is_nzxor_stack_cookie(f, bb, insn): - """ check if nzxor is related to stack cookie """ + """check if nzxor is related to stack cookie""" if contains_stack_cookie_keywords(idaapi.get_cmt(insn.ea, False)): # Example: # xor ecx, ebp ; StackCookie diff --git a/capa/features/extractors/smda/basicblock.py b/capa/features/extractors/smda/basicblock.py index 07477139..98b91ec3 100644 --- a/capa/features/extractors/smda/basicblock.py +++ b/capa/features/extractors/smda/basicblock.py @@ -15,7 +15,7 @@ def _bb_has_tight_loop(f, bb): def extract_bb_tight_loop(f, bb): - """ check basic block for tight loop indicators """ + """check basic block for tight loop indicators""" if _bb_has_tight_loop(f, bb): yield Characteristic("tight loop"), bb.offset @@ -39,7 +39,7 @@ def get_operands(smda_ins): def extract_stackstring(f, bb): - """ check basic block for stackstring indicators """ + """check basic block for stackstring indicators""" if _bb_has_stackstring(f, bb): yield Characteristic("stack string"), bb.offset diff --git a/capa/features/extractors/smda/insn.py b/capa/features/extractors/smda/insn.py index bf23f607..48ef4c1c 100644 --- a/capa/features/extractors/smda/insn.py +++ b/capa/features/extractors/smda/insn.py @@ -293,7 +293,7 @@ def extract_insn_peb_access_characteristic_features(f, bb, insn): def extract_insn_segment_access_features(f, bb, insn): - """ parse the instruction for access to fs or gs """ + """parse the instruction for access to fs or gs""" operands = [o.strip() for o in insn.operands.split(",")] for operand in operands: if "fs:" in operand: diff --git a/capa/features/extractors/viv/basicblock.py b/capa/features/extractors/viv/basicblock.py index 76ffefe6..a76aa179 100644 --- a/capa/features/extractors/viv/basicblock.py +++ b/capa/features/extractors/viv/basicblock.py @@ -45,7 +45,7 @@ def _bb_has_tight_loop(f, bb): def extract_bb_tight_loop(f, bb): - """ check basic block for tight loop indicators """ + """check basic block for tight loop indicators""" if _bb_has_tight_loop(f, bb): yield Characteristic("tight loop"), bb.va @@ -68,7 +68,7 @@ def _bb_has_stackstring(f, bb): def extract_stackstring(f, bb): - """ check basic block for stackstring indicators """ + """check basic block for stackstring indicators""" if _bb_has_stackstring(f, bb): yield Characteristic("stack string"), bb.va diff --git a/capa/features/extractors/viv/insn.py b/capa/features/extractors/viv/insn.py index 6321fcab..42deee51 100644 --- a/capa/features/extractors/viv/insn.py +++ b/capa/features/extractors/viv/insn.py @@ -476,7 +476,7 @@ def extract_insn_peb_access_characteristic_features(f, bb, insn): def extract_insn_segment_access_features(f, bb, insn): - """ parse the instruction for access to fs or gs """ + """parse the instruction for access to fs or gs""" prefix = insn.getPrefixName() if prefix == "fs": diff --git a/capa/ida/helpers/__init__.py b/capa/ida/helpers/__init__.py index 17744ebb..41e4b463 100644 --- a/capa/ida/helpers/__init__.py +++ b/capa/ida/helpers/__init__.py @@ -71,7 +71,7 @@ def get_disasm_line(va): def is_func_start(ea): - """ check if function stat exists at virtual address """ + """check if function stat exists at virtual address""" f = idaapi.get_func(ea) return f and f.start_ea == ea diff --git a/capa/ida/plugin/item.py b/capa/ida/plugin/item.py index e6f4d436..77db0c32 100644 --- a/capa/ida/plugin/item.py +++ b/capa/ida/plugin/item.py @@ -202,7 +202,7 @@ class CapaExplorerRuleMatchItem(CapaExplorerDataItem): @property def source(self): - """ return rule contents for display """ + """return rule contents for display""" return self._source diff --git a/setup.py b/setup.py index a6e47bac..580a3be1 100644 --- a/setup.py +++ b/setup.py @@ -70,7 +70,7 @@ setuptools.setup( "pytest-instafail==0.4.2", "pytest-cov==2.11.1", "pycodestyle==2.7.0", - "black==20.8b1", + "black==21.4b0", "isort==5.8.0", ] },