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>
Bloklar
#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]"
Dinamik Analiz
Simülasyon Yöneticisi, Durumlar
#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 pointproject.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
Fonksiyonları Çağırma
entry_state ve full_init_state içine args aracılığıyla bir argüman listesi ve env aracılığıyla bir ortam değişkenleri sözlüğü geçirebilirsiniz. Bu yapılardaki değerler string veya bitvector olabilir ve simüle edilmiş yürütme için argümanlar ve ortam olarak duruma serileştirilecektir. Varsayılan args boş bir listedir, bu nedenle analiz ettiğiniz program en az bir argv[0] bulmayı bekliyorsa, bunu her zaman sağlamalısınız!
argc'nin sembolik olmasını istiyorsanız, entry_state ve full_init_state yapıcılarına sembolik bir bitvector olarak argc geçirebilirsiniz. Ancak dikkatli olun: bunu yaparsanız, argc için değerinizin args içine geçirdiğiniz argüman sayısından büyük olamayacağına dair bir kısıtlama da eklemelisiniz.
Çağrı durumunu kullanmak için, .call_state(addr, arg1, arg2, ...) ile çağırmalısınız; burada addr, çağırmak istediğiniz fonksiyonun adresidir ve argN, o fonksiyona geçilecek N'inci argümandır; bu argüman bir python tamsayı, string, dizi veya bitvector olabilir. Bellek tahsis edilmesini ve gerçekten bir nesneye işaretçi geçmek istiyorsanız, bunu bir PointerWrapper içinde sarmalısınız, yani angr.PointerWrapper("point to me!"). Bu API'nin sonuçları biraz öngörülemez olabilir, ama bunun üzerinde çalışıyoruz.
BitVectors
#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
Sembolik BitVektörler & Kısıtlamalar
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.
Hooking
>>> 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
Ayrıca, sembolün bulunduğu adresi bağlamak için ilk argüman olarak sembolün adını vererek proj.hook_symbol(name, hook) kullanabilirsiniz.