Repository: mandiant/capa
File: capa/features/extractors/dnfile/helpers.py (Python)

Code before:
    
def get_dotnet_types(pe: dnfile.dnPE) -> Iterator[DnType]:
    """get .NET types from TypeDef and TypeRef tables"""
    nested_class_table = get_nested_class_table(pe)
    typedef_class_table = get_typedef_class_table(pe)
    
    for rid, typedef in iter_dotnet_table(pe, dnfile.mdtable.TypeDef.number):
        assert isinstance(typedef, dnfile.mdtable.TypeDefRow)

        typedef_name = []
        if rid in nested_class_table:
            typedef.TypeName = typedef_helper(rid, nested_class_table, typedef_class_table, typedef_name, typedef.TypeName)

        typedef_token: int = calculate_dotnet_token_value(dnfile.mdtable.TypeDef.number, rid)
        yield DnType(typedef_token, typedef.TypeName, namespace=typedef.TypeNamespace)


    typeref_table = get_typeref_table(pe)
    
    for rid, typeref in iter_dotnet_table(pe, dnfile.mdtable.TypeRef.number):
        assert isinstance(typeref, dnfile.mdtable.TypeRefRow)
        
        # If the ResolutionScope decodes to a typeRef type, then it is nested
        n = []
        if type(typeref.ResolutionScope.table) == dnfile.mdtable.TypeRef:
            typeref.TypeName = typeref_helper(typeref.ResolutionScope.row_index, typeref_table, n, typeref.TypeName)
              
        typeref_token: int = calculate_dotnet_token_value(dnfile.mdtable.TypeRef.number, rid)
        yield DnType(typeref_token, typeref.TypeName, namespace=typeref.TypeNamespace)
        
def calculate_dotnet_token_value(table: int, rid: int) -> int:
    return ((table & 0xFF) << Token.TABLE_SHIFT) | (rid & Token.RID_MASK)


def is_dotnet_mixed_mode(pe: dnfile.dnPE) -> bool:
    assert pe.net is not None
    assert pe.net.Flags is not None

    return not bool(pe.net.Flags.CLR_ILONLY)


def iter_dotnet_table(pe: dnfile.dnPE, table_index: int) -> Iterator[Tuple[int, dnfile.base.MDTableRow]]:
    assert pe.net is not None
    assert pe.net.mdtables is not None

    for rid, row in enumerate(pe.net.mdtables.tables.get(table_index, [])):
        # .NET tables are 1-indexed
        yield rid + 1, row


Review comment (suggestion):
Let's create a separate variable here to avoid modifying the object's `TypeName`  instance variable.

Code after:
        # Validate index
        table_row = get_dotnet_table_row(pe, dnfile.mdtable.TypeRef.number, index)
        if table_row is None:
            return typeref.TypeNamespace, (typeref.TypeName,)

        while isinstance(table_row.ResolutionScope.table, dnfile.mdtable.TypeRef):
            # Iterate through the typeref table to resolve the nested name
            typeref_name.append(name)
            name = table_row.TypeName
            table_row = get_dotnet_table_row(pe, dnfile.mdtable.TypeRef.number, table_row.ResolutionScope.row_index)
            if table_row is None:
                return typeref.TypeNamespace, tuple(typeref_name[::-1])

        # Document the root enclosing details
        typeref_name.append(table_row.TypeName)

        return table_row.TypeNamespace, tuple(typeref_name[::-1])

    else:
        return typeref.TypeNamespace, (typeref.TypeName,)


def get_dotnet_nested_class_table_index(pe: dnfile.dnPE) -> Dict[int, int]:
    """Build index for EnclosingClass based off the NestedClass row index in the nestedclass table"""
    nested_class_table = {}

    # Used to find nested classes in typedef
    for _, nestedclass in iter_dotnet_table(pe, dnfile.mdtable.NestedClass.number):
        assert isinstance(nestedclass, dnfile.mdtable.NestedClassRow)
        nested_class_table[nestedclass.NestedClass.row_index] = nestedclass.EnclosingClass.row_index

    return nested_class_table


def get_dotnet_types(pe: dnfile.dnPE) -> Iterator[DnType]:
    """get .NET types from TypeDef and TypeRef tables"""
    nested_class_table = get_dotnet_nested_class_table_index(pe)

    for rid, typedef in iter_dotnet_table(pe, dnfile.mdtable.TypeDef.number):
        assert isinstance(typedef, dnfile.mdtable.TypeDefRow)

        typedefnamespace, typedefname = resolve_nested_typedef_name(nested_class_table, rid, typedef, pe)

        typedef_token: int = calculate_dotnet_token_value(dnfile.mdtable.TypeDef.number, rid)
        yield DnType(typedef_token, typedefname, namespace=typedefnamespace)

    for rid, typeref in iter_dotnet_table(pe, dnfile.mdtable.TypeRef.number):
        assert isinstance(typeref, dnfile.mdtable.TypeRefRow)

        typerefnamespace, typerefname = resolve_nested_typeref_name(typeref.ResolutionScope.row_index, typeref, pe)