{{
import datetime
import malcat

DD_NAMES = [
"Export Table",
"Import Table",
"Resource Directory",
"Exception Table",
"Certificate Table",
"Relocation Table",
"Debug Data",
"Architecture",
"Global Pointer",
"TLS Table",
"Load Config Table",
"Bound Import Table",
"Import Address Table",
"Delay Import Descriptor",
"CLR Runtime",
"Unused"
]


def pval(key, val=None, fmt="{}", va=False, fa=False, rva=False, kalign=30, valign=0, formated=False):
    r = ""
    if key:
        r = "[normal]{}[/normal]:".format(key)
        lr = len(r) - 17
        if lr < kalign:
            r += (" "*(kalign-lr))
    if isinstance(val, malcat.StructAccess):
        if val.has_enum and val.enum:
            d = "[color6]{}[/color6]([dim]{}[/dim])".format(val.enum, fmt.format(val.value))
            formated = True
            ld = len(d) - len("[color3][/color3][dim][/dim]")
        else:
            d = fmt.format(val.value)
            ld = len(d)
        val = val.value
    else:
        d = fmt.format(val)
        ld = len(d)
    if not formated:
        if type(val) == int: 
            if val == 0:
                grp = "dim"
            elif fa:
                grp = "fa"
            elif rva:
                grp = "rva"
            elif va:
                grp = "va"
            else:
                grp = "normal"
        else:
            grp = "normal"
        d = "[{}]{}[/{}]".format(grp,d,grp)
    if ld < valign:
        d += (" "*(valign-ld))
    write(r+d)  

def bitfieldpp(fa):
    s = []
    for i in range(fa.count - 1, -1, -1):
        bit = fa.at(i)
        if bit.value:
            s.append("[color5]{}[/color5]([dim]{:X}[/dim])".format(bit.name, 1 << i))
    if s:
        return  " + ".join(s)
    else:
        return "[dim]0[/dim]"

def pbitfield(key, fa, kalign=30):    
    r = "[normal]{}[/normal]:".format(key)
    lr = len(r) - 17
    if lr < kalign:
        r += (" "*(kalign-lr))
    write(r + bitfieldpp(fa))

def sections_rights(rights):
    s = ""
    for e in [
        ("Alloc", "A"),
        ("Write", "W"),
        ("Execute", "X"),
        ("Merged", "M"),
        ("Strings", "S"),
        ("InfoLink", "I"),
        ("PreserveLinkOrder", "L"),
        ("OsSpecific", "O"),
        ("GroupMember", "G"),
        ("Tls", "T"),
        ("Compressed", "Z"),
        ]:
        if rights[e[0]]:
            s += "[color5]{}[/color5]".format(e[1])
        else:
            s += "[dim]∙[/dim]"
    return s

def segments_rights(rights):
    s = ""
    for e in [
        ("Read", "R"),
        ("Write", "W"),
        ("Execute", "X"),
        ]:
        if rights[e[0]]:
            s += "[color5]{}[/color5]".format(e[1])
        else:
            s += "[dim]∙[/dim]"
    return s

def display_entropy(start, size):
    if start is None or size <= 0:
        return " "
    entropy = analysis.entropy[start:start+size]
    return "[ent-{val}:{ent}] [/ent-{val}]".format(val=entropy//4, ent=entropy)
}}
[color1]ELF Header[/color1]
  {{ pval("ELF Type", analysis.struct.ELF.Type, valign=24) }} {{ pval("Encoding",  analysis.struct.ELF.DataEncoding) }}
  {{ pval("Machine", analysis.struct.ELF.Machine, valign=24) }} {{ pval("Class",  analysis.struct.ELF.Class) }}
  {{ pval("Flags", analysis.struct.ELF.Flags, "{:08x}", valign=24) }} {{ pval("Entry point", analysis.struct.ELF.Entry, "{:08x}", rva=True) }}

[color1]Segments[/color1]
{{ if not "Segments" in analysis.struct:}}
  No segment !
{{:else: }}
{{for i, s in enumerate(analysis.struct.Segments):}}
  \[{{"{:2d}".format(i)}}] [color6]{{ "{:14.14s}".format(s.Type.enum or "0x{:x}?".format(s.Type.value)) }}[/color6] \[{{ write(segments_rights(s["Flags"]))}}]  --→  Memory: {{if s["VirtualSize"]:}}[va]{{ "{:08X}".format( s["Vaddress"])}}[/va]-[va]{{ "{:08X}".format(s["Vaddress"] + s["VirtualSize"] - 1)}}[/va]{{:else:}}[dim]00000000[/dim]-[dim]00000000[/dim]{{:end}} ([dim]{{"{:8x}".format(s["VirtualSize"])}}[/dim] bytes)    Disk: {{if s["FileSize"]:}}[fa]{{ "{:08X}".format(s["Offset"])}}[/fa]-[fa]{{ "{:08X}".format(s["Offset"] + s["FileSize"] - 1)}}[/fa] {{ write(display_entropy(analysis.map.from_phys(s["Offset"]), s["FileSize"]))}}{{:else:}}[dim]00000000[/dim]-[dim]00000000[/dim]  {{:end}} ([dim]{{"{:8x}".format(s["FileSize"])}}[/dim] bytes)
{{ :end }}
{{ :endif }}

[color1]Sections[/color1]
{{ if not "Sections" in analysis.struct:}}
  No section !
{{:else: }}
{{for i, s in enumerate(analysis.struct.Sections):}}
{{ if i == 0: continue}}
  \[{{"{:2d}".format(i)}}] [color6]{{ "{:20.20s}".format(analysis.parser.read_string(s["Name"])) }}[/color6] \[{{ write(sections_rights(s["Flags"]))}}]  --→  Memory: {{if s["Address"]:}}[va]{{ "{:08X}".format( s["Address"])}}[/va]-[va]{{ "{:08X}".format(s["Address"] + s["Size"] - 1)}}[/va]{{:else:}}[dim]00000000[/dim]-[dim]00000000[/dim]{{:end}} ([dim]{{"{:8x}".format(s["Size"])}}[/dim] bytes)    Disk: [fa]{{ "{:08X}".format(s["Offset"])}}[/fa]-[fa]{{ "{:08X}".format(s["Offset"] + s["Size"] - 1)}}[/fa] {{ write(display_entropy(analysis.map.from_phys(s["Offset"]), s["Size"]))}} ([dim]{{"{:8x}".format(s["Size"])}}[/dim] bytes)
{{ :end }}
{{ :endif }}

