binaryninja-api icon indicating copy to clipboard operation
binaryninja-api copied to clipboard

python binding can't add label in mlil

Open SGSGsama opened this issue 2 months ago • 1 comments

What is the feature you'd like to have? add python workflow api to add label in mlil like llil.add_label_for_address

Is your feature request related to a problem? when solve indirect branch jump, its suppose to use mlil data flow analyze to calculate possible dest and replace 'jump' MLIL to 'if' MLIL , so a easy way to create label in mlil is necessary

Are any alternative solutions acceptable? i have not found yet

Additional Information: my code here ,can't work and i can't find a solution

import json
from binaryninja import(
    Workflow,
    AnalysisContext,
    Variable,
    Activity,
    MediumLevelILFunction,
    MediumLevelILConstPtr,
    MediumLevelILConstData,
    MediumLevelILConst,
    MediumLevelILLoad,
    MediumLevelILVar,
    MediumLevelILAdd,
    MediumLevelILSub,
    MediumLevelILXor,
    MediumLevelILMul,
    MediumLevelILJump,
    PossibleValueSet,
    RegisterValueType,
    MediumLevelILLabel,
    LowLevelILLabel,
)
mlil_const=MediumLevelILConstPtr | MediumLevelILConstData | MediumLevelILConst
def search_var_def(var:Variable,mlil:MediumLevelILFunction,cond):
    var_def=mlil.get_var_definitions(var)
    # print(hex(var_def[0].address))
    if len(var_def)==1 and isinstance(var_def[0].src,mlil_const):
        print("def==1",var_def)
        return
    if (len(var_def)==2):
        # print(var_def)
        if isinstance(var_def[0].src,mlil_const) and isinstance(var_def[1].src,mlil_const):
            if cond["value"]==None:
                for key in var_def[0].branch_dependence.keys():
                    cond["value"]=mlil[key].condition.expr_index
                    break
            return {var:{"t":var_def[0].src.value.value,"f":var_def[1].src.value.value}}
        return
    if len(var_def)>2:
        print("def>2",var_def)
        return None
    var_def=var_def[0]
    var_def_src=var_def.src
    # print(var_def_src)
    if isinstance(var_def_src,mlil_const):
        print("const:",var_def_src)
        return
    if isinstance(var_def_src,MediumLevelILLoad):
        # print("load:",var_def_src.operands)
        table=var_def.get_possible_reg_values_after(var_def.dest.storage)
        # print(table.mapping)
        
        var_def_token=list(var_def_src.traverse(lambda x:  x))
        for token in var_def_token:
            if isinstance(token,MediumLevelILVar):
                mp=search_var_def(token.var,mlil,cond)
                if mp==None:
                    return
                # print(table,var_def,var_def.dest.storage)
                if (table.type==RegisterValueType.UndeterminedValue):
                    print("undetermined table,check data section")
                    return
                # print(mp,table.mapping)
                try:
                    return {var:{"t":table.mapping[mp[token.var]["t"]],"f":table.mapping[mp[token.var]["f"]]}}
                except KeyError:
                    return {var:{"t":table.mapping[mp[token.var]["t"]//8],"f":table.mapping[mp[token.var]["f"]//8]}}
        return

    Lvalue=search_var_def(var_def_src.left.var,mlil,cond)
    Rvalue=search_var_def(var_def_src.right.var,mlil,cond)
    tmp=Lvalue|Rvalue
    if isinstance(var_def_src,MediumLevelILAdd):
        Tvalue=tmp[var_def_src.left.var]["t"]+tmp[var_def_src.right.var]["t"]
        Fvalue=tmp[var_def_src.left.var]["f"]+tmp[var_def_src.right.var]["f"]
        return {var:{"t":Tvalue,"f":Fvalue}}
    elif isinstance(var_def_src,MediumLevelILSub):
        Tvalue=tmp[var_def_src.left.var]["t"]-tmp[var_def_src.right.var]["t"]
        Fvalue=tmp[var_def_src.left.var]["f"]-tmp[var_def_src.right.var]["f"]
        return {var:{"t":Tvalue,"f":Fvalue}}
    elif isinstance(var_def_src,MediumLevelILXor):
        Tvalue=tmp[var_def_src.left.var]["t"]^tmp[var_def_src.right.var]["t"]
        Fvalue=tmp[var_def_src.left.var]["f"]^tmp[var_def_src.right.var]["f"]
        return {var:{"t":Tvalue,"f":Fvalue}}
    elif isinstance(var_def_src,MediumLevelILMul):
        Tvalue=tmp[var_def_src.left.var]["t"]*tmp[var_def_src.right.var]["t"]
        Fvalue=tmp[var_def_src.left.var]["f"]*tmp[var_def_src.right.var]["f"]
        return {var:{"t":Tvalue,"f":Fvalue}}
    else:
        print("Unsupported operation:",var_def_src)
        return None
def handle_two_direct_indirect_jump(ctx:AnalysisContext):
    bv=ctx.function.view
    mlil=ctx.function.mlil
    llil=ctx.function.llil
    update=False
    for instr in mlil.instructions:
        if isinstance(instr,MediumLevelILJump) and isinstance(instr.dest,MediumLevelILVar):
            # print(instr.get_possible_reg_values(instr.dest.var.storage))
            if instr.get_possible_reg_values(instr.dest.var.storage).type==RegisterValueType.UndeterminedValue:
                # print(instr.dest.var)
                cond={"value":None}
                res=search_var_def(instr.dest.var, mlil,cond)
                # print(cond)
                
                if res==None or cond["value"]==None:
                    raise RuntimeError("calc fail,check {}".format(hex(instr.address)))
                ctx.function.set_user_indirect_branches(instr.address, [(ctx.function.arch,res[instr.dest.var]["t"]),(ctx.function.arch,res[instr.dest.var]["f"])],ctx.function.arch)
                print(hex(res[instr.dest.var]["t"]),llil.get_instruction_start(res[instr.dest.var]["t"]))
                print(hex(res[instr.dest.var]["f"]),llil.get_instruction_start(res[instr.dest.var]["f"]))
                t_instr=llil[llil.get_instruction_start(res[instr.dest.var]["t"])].mapped_medium_level_il
                f_instr=llil[llil.get_instruction_start(res[instr.dest.var]["f"])].mapped_medium_level_il
                print(hex(res[instr.dest.var]["t"]),t_instr)
                print(hex(res[instr.dest.var]["f"]),f_instr)
                t_label=mlil.get_label_for_source_instruction(t_instr.instr_index)
                f_label=mlil.get_label_for_source_instruction(f_instr.instr_index)
                print("set indirect jump at {} to {}:{},{}:{}".format(hex(instr.address),hex(res[instr.dest.var]["t"]),t_label,hex(res[instr.dest.var]["f"]),f_label))

                if_instr=mlil.if_expr(cond["value"],t_label,f_label,instr.source_location)
                mlil.replace_expr(instr.expr_index,if_instr)
                mlil.append(if_instr)
                update=True
    if update:
        mlil.finalize()
        mlil.generate_ssa_form()

                




wf=Workflow("").clone("satori.function.deobf")
wf.register_activity(Activity(configuration=json.dumps({
    "name":"satori.function.handle_two_direct_indirect_jump.activity",
    "title":"handle_two_direct_indirect_jump",
    "description":"handle_two_direct_indirect_jump",
    "eligibility":{
        "auto":{
            "default":True
        }
    }

}),action=lambda context: handle_two_direct_indirect_jump(context)))
wf.insert("core.function.generateHighLevelIL",["satori.function.handle_two_direct_indirect_jump.activity"])

wf.register()

SGSGsama avatar Dec 01 '25 13:12 SGSGsama

get_label_for_source_instruction can only be used when doing rewriting via a "copy transformation". See Adding Instructions and Replacing Multiple Instructions (Copy Transformation) and Using GOTO/IF Instructions and IL Labels for more information on how to work with labels when rewriting IL.

bdash avatar Dec 01 '25 16:12 bdash