import angrimport monkeyhex # this will format numerical results in hexadecimal#Load binaryproj = angr.Project('/bin/true')#BASIC BINARY DATAproj.arch #Get arch "<Arch AMD64 (LE)>"proj.arch.name #'AMD64'proj.arch.memory_endness #'Iend_LE'proj.entry #Get entrypoint "0x4023c0"proj.filename #Get filename "/bin/true"#There are specific options to load binaries#Usually you won't need to use them but you couldangr.Project('examples/fauxware/fauxware', main_opts={'backend': 'blob', 'arch': 'i386'}, lib_opts={'libc.so.6': {'backend': 'elf'}})
strcmp = proj.loader.find_symbol('strcmp')#<Symbol "strcmp" in libc.so.6 at 0x1089cd0>strcmp.name #'strcmp'strcmp.owne #<ELF Object libc-2.23.so, maps [0x1000000:0x13c999f]>strcmp.rebased_addr #0x1089cd0strcmp.linked_addr #0x89cd0strcmp.relative_addr #0x89cd0strcmp.is_export #True, as 'strcmp' is a function exported by libc#Get strcmp from the main objectmain_strcmp = proj.loader.main_object.get_symbol('strcmp')main_strcmp.is_export #Falsemain_strcmp.is_import #Truemain_strcmp.resolvedby #<Symbol "strcmp" in libc.so.6 at 0x1089cd0>
ブロック
#Blocksblock = proj.factory.block(proj.entry)#Get the block of the entrypoint fo the binaryblock.pp()#Print disassembly of the blockblock.instructions #"0xb" Get number of instructionsblock.instruction_addrs #Get instructions addresses "[0x401670, 0x401672, 0x401675, 0x401676, 0x401679, 0x40167d, 0x40167e, 0x40167f, 0x401686, 0x40168d, 0x401694]"
ダイナミック分析
シミュレーションマネージャー、ステート
#Live States#This is useful to modify content in a live analysisstate = proj.factory.entry_state()state.regs.rip #Get the RIPstate.mem[proj.entry].int.resolved #Resolve as a C int (BV)state.mem[proj.entry].int.concreteved #Resolve as python intstate.regs.rsi = state.solver.BVV(3, 64)#Modify RIPstate.mem[0x1000].long =4#Modify mem#Other Statesproject.factory.entry_state()project.factory.blank_state()#Most of its data left uninitializedproject.factory.full_init_statetate() #Execute through any initializers that need to be run before the main binary's entry point
project.factory.call_state()#Ready to execute a given function.#Simulation manager#The simulation manager stores all the states across the execution of the binarysimgr = proj.factory.simulation_manager(state)#Startsimgr.step()#Execute one stepsimgr.active[0].regs.rip #Get RIP from the last state
コールステートを使用するには、.call_state(addr, arg1, arg2, ...) で呼び出す必要があります。ここで addr は呼び出したい関数のアドレスで、argN はその関数への N 番目の引数であり、Python の整数、文字列、配列、またはビットベクタとして指定できます。メモリを割り当ててオブジェクトへのポインタを実際に渡したい場合は、angr.PointerWrapper("point to me!") のように PointerWrapper でラップする必要があります。この API の結果は少し予測不可能な場合がありますが、改善に取り組んでいます。
ビットベクタ
#BitVectorsstate = proj.factory.entry_state()bv = state.solver.BVV(0x1234, 32)#Create BV of 32bits with the value "0x1234"state.solver.eval(bv)#Convert BV to python intbv.zero_extend(30)#Will add 30 zeros on the left of the bitvectorbv.sign_extend(30)#Will add 30 zeros or ones on the left of the BV extending the sign
シンボリックビットベクターと制約
x = state.solver.BVS("x", 64)#Symbolic variable BV of length 64y = state.solver.BVS("y", 64)#Symbolic oprationstree = (x +1) / (y +2)tree #<BV64 (x_9_64 + 0x1) / (y_10_64 + 0x2)>tree.op #'__floordiv__' Access last operationtree.args #(<BV64 x_9_64 + 0x1>, <BV64 y_10_64 + 0x2>)tree.args[0].op #'__add__' Access of dirst argtree.args[0].args #(<BV64 x_9_64>, <BV64 0x1>)tree.args[0].args[1].op #'BVV'tree.args[0].args[1].args #(1, 64)#Symbolic constraints solverstate = proj.factory.entry_state()#Get a fresh state without constraintsinput= state.solver.BVS('input', 64)operation = (((input+4) *3) >>1) +inputoutput =200state.solver.add(operation == output)state.solver.eval(input)#0x3333333333333381state.solver.add(input<2**32)state.satisfiable()#False#Solver solutionssolver.eval(expression)#one possible solutionsolver.eval_one(expression)#solution to the given expression, or throw an error if more than one solution is possible.solver.eval_upto(expression, n) #n solutions to the given expression, returning fewer than n if fewer than n are possible.
solver.eval_atleast(expression, n) #n solutions to the given expression, throwing an error if fewer than n are possible.
solver.eval_exact(expression, n) #n solutions to the given expression, throwing an error if fewer or more than are possible.
solver.min(expression)#minimum possible solution to the given expression.solver.max(expression)#maximum possible solution to the given expression.
フッキング
>>> stub_func = angr.SIM_PROCEDURES['stubs']['ReturnUnconstrained'] # this is a CLASS>>> proj.hook(0x10000, stub_func())# hook with an instance of the class>>> proj.is_hooked(0x10000)# these functions should be pretty self-explanitoryTrue>>> proj.hooked_by(0x10000)<ReturnUnconstrained>>>> proj.unhook(0x10000)>>>@proj.hook(0x20000, length=5)... defmy_hook(state):... state.regs.rax =1>>> proj.is_hooked(0x20000)True