Angr

Support HackTricks

рдЗрд╕ рдЪреАрдЯрд╢реАрдЯ рдХрд╛ рдПрдХ рднрд╛рдЧ angr рджрд╕реНрддрд╛рд╡реЗрдЬрд╝реАрдХрд░рдг рдкрд░ рдЖрдзрд╛рд░рд┐рдд рд╣реИред

рд╕реНрдерд╛рдкрдирд╛

sudo apt-get install python3-dev libffi-dev build-essential
python3 -m pip install --user virtualenv
python3 -m venv ang
source ang/bin/activate
pip install angr

рдмреБрдирд┐рдпрд╛рджреА рдХреНрд░рд┐рдпрд╛рдПрдБ

import angr
import monkeyhex # this will format numerical results in hexadecimal
#Load binary
proj = angr.Project('/bin/true')

#BASIC BINARY DATA
proj.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 could
angr.Project('examples/fauxware/fauxware', main_opts={'backend': 'blob', 'arch': 'i386'}, lib_opts={'libc.so.6': {'backend': 'elf'}})

Loaded and Main object information

Loaded Data

#LOADED DATA
proj.loader #<Loaded true, maps [0x400000:0x5004000]>
proj.loader.min_addr #0x400000
proj.loader.max_addr #0x5004000
proj.loader.all_objects #All loaded
proj.loader.shared_objects #Loaded binaries
"""
OrderedDict([('true', <ELF Object true, maps [0x400000:0x40a377]>),
('libc.so.6',
<ELF Object libc-2.31.so, maps [0x500000:0x6c4507]>),
('ld-linux-x86-64.so.2',
<ELF Object ld-2.31.so, maps [0x700000:0x72c177]>),
('extern-address space',
<ExternObject Object cle##externs, maps [0x800000:0x87ffff]>),
('cle##tls',
<ELFTLSObjectV2 Object cle##tls, maps [0x900000:0x91500f]>)])
"""
proj.loader.all_elf_objects #Get all ELF objects loaded (Linux)
proj.loader.all_pe_objects #Get all binaries loaded (Windows)
proj.loader.find_object_containing(0x400000)#Get object loaded in an address "<ELF Object fauxware, maps [0x400000:0x60105f]>"

рдореБрдЦреНрдп рдЙрджреНрджреЗрд╢реНрдп

#Main Object (main binary loaded)
obj = proj.loader.main_object #<ELF Object true, maps [0x400000:0x60721f]>
obj.execstack #"False" Check for executable stack
obj.pic #"True" Check PIC
obj.imports #Get imports
obj.segments #<Regions: [<ELFSegment flags=0x5, relro=0x0, vaddr=0x400000, memsize=0xa74, filesize=0xa74, offset=0x0>, <ELFSegment flags=0x4, relro=0x1, vaddr=0x600e28, memsize=0x1d8, filesize=0x1d8, offset=0xe28>, <ELFSegment flags=0x6, relro=0x0, vaddr=0x601000, memsize=0x60, filesize=0x50, offset=0x1000>]>
obj.find_segment_containing(obj.entry) #Get segment by address
obj.sections #<Regions: [<Unnamed | offset 0x0, vaddr 0x0, size 0x0>, <.interp | offset 0x238, vaddr 0x400238, size 0x1c>, <.note.ABI-tag | offset 0x254, vaddr 0x400254, size 0x20>, <.note.gnu.build-id ...
obj.find_section_containing(obj.entry) #Get section by address
obj.plt['strcmp'] #Get plt address of a funcion (0x400550)
obj.reverse_plt[0x400550] #Get function from plt address ('strcmp')

рдкреНрд░рддреАрдХ рдФрд░ рдкреБрдирд░реНрд╕реНрдерд╛рдкрдирд╛рдПрдБ

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 #0x1089cd0
strcmp.linked_addr #0x89cd0
strcmp.relative_addr #0x89cd0
strcmp.is_export #True, as 'strcmp' is a function exported by libc

#Get strcmp from the main object
main_strcmp = proj.loader.main_object.get_symbol('strcmp')
main_strcmp.is_export #False
main_strcmp.is_import #True
main_strcmp.resolvedby #<Symbol "strcmp" in libc.so.6 at 0x1089cd0>

рдмреНрд▓реЙрдХреНрд╕

#Blocks
block = proj.factory.block(proj.entry) #Get the block of the entrypoint fo the binary
block.pp() #Print disassembly of the block
block.instructions #"0xb" Get number of instructions
block.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 analysis
state = proj.factory.entry_state()
state.regs.rip #Get the RIP
state.mem[proj.entry].int.resolved #Resolve as a C int (BV)
state.mem[proj.entry].int.concreteved #Resolve as python int
state.regs.rsi = state.solver.BVV(3, 64) #Modify RIP
state.mem[0x1000].long = 4 #Modify mem

#Other States
project.factory.entry_state()
project.factory.blank_state() #Most of its data left uninitialized
project.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 binary
simgr = proj.factory.simulation_manager(state) #Start
simgr.step() #Execute one step
simgr.active[0].regs.rip #Get RIP from the last state

Calling functions

  • рдЖрдк entry_state рдФрд░ full_init_state рдореЗрдВ args рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рддрд░реНрдХреЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рдФрд░ env рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдкрд░реНрдпрд╛рд╡рд░рдг рдЪрд░ рдХрд╛ рдПрдХ рд╢рдмреНрджрдХреЛрд╢ рдкрд╛рд╕ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЗрди рд╕рдВрд░рдЪрдирд╛рдУрдВ рдореЗрдВ рдорд╛рди рд╕реНрдЯреНрд░рд┐рдВрдЧ рдпрд╛ рдмрд┐рдЯрд╡реЗрдХреНрдЯрд░ рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ, рдФрд░ рдЗрдиреНрд╣реЗрдВ рдЕрдиреБрдХрд░рдгрд┐рдд рдирд┐рд╖реНрдкрд╛рджрди рдХреЗ рд▓рд┐рдП рддрд░реНрдХреЛрдВ рдФрд░ рдкрд░реНрдпрд╛рд╡рд░рдг рдХреЗ рд░реВрдк рдореЗрдВ рд╕реНрдерд┐рддрд┐ рдореЗрдВ рдЕрдиреБрдХреНрд░рдорд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдбрд┐рдлрд╝реЙрд▓реНрдЯ args рдПрдХ рдЦрд╛рд▓реА рд╕реВрдЪреА рд╣реИ, рдЗрд╕рд▓рд┐рдП рдпрджрд┐ рдЖрдк рдЬрд┐рд╕ рдХрд╛рд░реНрдпрдХреНрд░рдо рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░ рд░рд╣реЗ рд╣реИрдВ рд╡рд╣ рдХрдо рд╕реЗ рдХрдо рдПрдХ argv[0] рдЦреЛрдЬрдиреЗ рдХреА рдЕрдкреЗрдХреНрд╖рд╛ рдХрд░рддрд╛ рд╣реИ, рддреЛ рдЖрдкрдХреЛ рд╣рдореЗрд╢рд╛ рд╡рд╣ рдкреНрд░рджрд╛рди рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП!

  • рдпрджрд┐ рдЖрдк argc рдХреЛ рдкреНрд░рддреАрдХрд╛рддреНрдордХ рдмрдирд╛рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рддреЛ рдЖрдк entry_state рдФрд░ full_init_state рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░реНрд╕ рдХреЛ argc рдХреЗ рд░реВрдк рдореЗрдВ рдПрдХ рдкреНрд░рддреАрдХрд╛рддреНрдордХ рдмрд┐рдЯрд╡реЗрдХреНрдЯрд░ рдкрд╛рд╕ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд╣рд╛рд▓рд╛рдВрдХрд┐, рд╕рд╛рд╡рдзрд╛рди рд░рд╣реЗрдВ: рдпрджрд┐ рдЖрдк рдРрд╕рд╛ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдЖрдкрдХреЛ рдкрд░рд┐рдгрд╛рдореА рд╕реНрдерд┐рддрд┐ рдореЗрдВ рдПрдХ рдмрд╛рдзрд╛ рднреА рдЬреЛрдбрд╝рдиреА рдЪрд╛рд╣рд┐рдП рдХрд┐ рдЖрдкрдХреЗ рд▓рд┐рдП argc рдХрд╛ рдорд╛рди рдЖрдк рджреНрд╡рд╛рд░рд╛ args рдореЗрдВ рдкрд╛рд╕ рдХрд┐рдП рдЧрдП рддрд░реНрдХреЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рд╕реЗ рдмрдбрд╝рд╛ рдирд╣реАрдВ рд╣реЛ рд╕рдХрддрд╛ред

  • рдХреЙрд▓ рд╕реНрдерд┐рддрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдЗрд╕реЗ .call_state(addr, arg1, arg2, ...) рдХреЗ рд╕рд╛рде рдХреЙрд▓ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП, рдЬрд╣рд╛рдБ addr рдЙрд╕ рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдкрддрд╛ рд╣реИ рдЬрд┐рд╕реЗ рдЖрдк рдХреЙрд▓ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ рдФрд░ argN рдЙрд╕ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд▓рд┐рдП Nрд╡рд╛рдВ рддрд░реНрдХ рд╣реИ, рдпрд╛ рддреЛ рдПрдХ рдкрд╛рдпрдерди рдкреВрд░реНрдгрд╛рдВрдХ, рд╕реНрдЯреНрд░рд┐рдВрдЧ, рдпрд╛ рдРрд░реЗ, рдпрд╛ рдПрдХ рдмрд┐рдЯрд╡реЗрдХреНрдЯрд░ рдХреЗ рд░реВрдк рдореЗрдВред рдпрджрд┐ рдЖрдк рдореЗрдореЛрд░реА рдЖрд╡рдВрдЯрд┐рдд рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ рдФрд░ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдПрдХ рд╡рд╕реНрддреБ рдХреЗ рд▓рд┐рдП рдПрдХ рдкреЙрдЗрдВрдЯрд░ рдкрд╛рд╕ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рддреЛ рдЖрдкрдХреЛ рдЗрд╕реЗ рдПрдХ PointerWrapper рдореЗрдВ рд▓рдкреЗрдЯрдирд╛ рдЪрд╛рд╣рд┐рдП, рдпрд╛рдиреА angr.PointerWrapper("point to me!")ред рдЗрд╕ API рдХреЗ рдкрд░рд┐рдгрд╛рдо рдереЛрдбрд╝реЗ рдЕрдкреНрд░рддреНрдпрд╛рд╢рд┐рдд рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рд╣рдо рдЗрд╕ рдкрд░ рдХрд╛рдо рдХрд░ рд░рд╣реЗ рд╣реИрдВред

BitVectors

#BitVectors
state = 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 int
bv.zero_extend(30) #Will add 30 zeros on the left of the bitvector
bv.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 64
y = state.solver.BVS("y", 64)

#Symbolic oprations
tree = (x + 1) / (y + 2)
tree #<BV64 (x_9_64 + 0x1) / (y_10_64 + 0x2)>
tree.op #'__floordiv__' Access last operation
tree.args #(<BV64 x_9_64 + 0x1>, <BV64 y_10_64 + 0x2>)
tree.args[0].op #'__add__' Access of dirst arg
tree.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 solver
state = proj.factory.entry_state() #Get a fresh state without constraints
input = state.solver.BVS('input', 64)
operation = (((input + 4) * 3) >> 1) + input
output = 200
state.solver.add(operation == output)
state.solver.eval(input) #0x3333333333333381
state.solver.add(input < 2**32)
state.satisfiable() #False

#Solver solutions
solver.eval(expression) #one possible solution
solver.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-explanitory
True
>>> proj.hooked_by(0x10000)
<ReturnUnconstrained>
>>> proj.unhook(0x10000)

>>> @proj.hook(0x20000, length=5)
... def my_hook(state):
...     state.regs.rax = 1

>>> proj.is_hooked(0x20000)
True

рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдЖрдк proj.hook_symbol(name, hook) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдкрд╣рд▓реЗ рддрд░реНрдХ рдХреЗ рд░реВрдк рдореЗрдВ рдПрдХ рдкреНрд░рддреАрдХ рдХрд╛ рдирд╛рдо рдкреНрд░рджрд╛рди рдХрд░рддреЗ рд╣реБрдП, рдЙрд╕ рдкрддреЗ рдХреЛ рд╣реБрдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд╣рд╛рдВ рдкреНрд░рддреАрдХ рд╕реНрдерд┐рдд рд╣реИред

рдЙрджрд╛рд╣рд░рдг

HackTricks рдХрд╛ рд╕рдорд░реНрдерди рдХрд░реЗрдВ

Last updated