angr使用[3]--使用技巧

12 篇文章 0 订阅
7 篇文章 6 订阅

0x08对探索结果添加限制

#跳过一些函数来求解

import angr
import claripy
import sys
import binascii

def main(argv):
  path_to_binary = "08_angr_constraints"
  project = angr.Project(path_to_binary)

  start_address = 0x8048625
  initial_state = project.factory.blank_state(addr=start_address)

  password = claripy.BVS('password', 0x10*8)

  password_address = 0x0804A050
  initial_state.memory.store(password_address, password)

  simulation = project.factory.simgr(initial_state)

  # Angr will not be able to reach the point at which the binary prints out
  # 'Good Job.'. We cannot use that as the target anymore.
  # (!)
  address_to_check_constraint = 0x0804866C
  simulation.explore(find=address_to_check_constraint)  #先让程序运行到比较之前

  if simulation.found:
    solution_state = simulation.found[0]

    # Recall that we need to constrain the to_check parameter (see top) of the 
    # check_equals_ function. Determine the address that is being passed as the
    # parameter and load it into a bitvector so that we can constrain it.
    # (!)
    constrained_parameter_address = 0x0804A050        #获取对应内存区域在运行到这里的时候的值
    constrained_parameter_size_bytes = 0x10
    constrained_parameter_bitvector = solution_state.memory.load(
      constrained_parameter_address,
      constrained_parameter_size_bytes
    )

    # We want to constrain the system to find an input that will make
    # constrained_parameter_bitvector equal the desired value.
    # (!)
    constrained_parameter_desired_value = "MRXJKZYRKMKENFZB" # :string   约束这些数据得到符合要求的

    # Specify a claripy expression (using Pythonic syntax) that tests whether
    # constrained_parameter_bitvector == constrained_parameter_desired_value.
    # We will let z3 attempt to find an input that will make this expression
    # true.
    constraint_expression = constrained_parameter_bitvector == constrained_parameter_desired_value
    
    # Add the constraint to the state to instruct z3 to include it when solving
    # for input.
    solution_state.add_constraints(constraint_expression)#添加约束条件

    # Solve for the constrained_parameter_bitvector.
    solution = solution_state.se.eval(password)                                 #求解得到满足上述条件的输入
    solution="".join(map("{:x}".format,[solution]))

    print(binascii.a2b_hex(solution))
  else:
    raise Exception('Could not find the solution')

if __name__ == '__main__':
  main(sys.argv)

# solution_state.add_constraints(constrained_parameter_bitvector == constrained_parameter_desired_value)获取到走到这里的好多数据中满足条件的输入

'''
    constrained_parameter_bitvector = solution_state.memory.load(
      constrained_parameter_address,
      constrained_parameter_size_bytes
    )
    获取一个地址处运行到这个时候的值
'''

核心代码添加求解约束条件,运行到这里已经得到了所有的结果,加上这个条件进一步过滤结果

  constraint_expression = constrained_parameter_bitvector == constrained_parameter_desired_value
    
    # Add the constraint to the state to instruct z3 to include it when solving
    # for input.
    solution_state.add_constraints(constraint_expression)#添加约束条件

0x09对一个地址hook

# This level performs the following computations:
#
# 1. Get 16 bytes of user input and encrypt it.
# 2. Save the result of check_equals_AABBCCDDEEFFGGHH (or similar)
# 3. Get another 16 bytes from the user and encrypt it.
# 4. Check that it's equal to a predefined password.
#
# The ONLY part of this program that we have to worry about is #2. We will be
# replacing the call to check_equals_ with our own version, using a hook, since
# check_equals_ will run too slowly otherwise.

'''
    claripy.If(条件,条件为True时的返回值,条件为False时的返回值) => 创建条件判断

    claripy.BVV(值,值大小) => 创建一个数值


'''


import angr
import claripy
import sys

def main(argv):
  path_to_binary = "09_angr_hooks"
  project = angr.Project(path_to_binary)

  # Since Angr can handle the initial call to scanf, we can start from the
  # beginning.
  initial_state = project.factory.entry_state()

  # Hook the address of where check_equals_ is called.
  # (!)
  check_equals_called_address = 0x80486B3        #这个地址是call的地址参数没有改变,只改变call

  # The length parameter in angr.Hook specifies how many bytes the execution
  # engine should skip after completing the hook. This will allow hooks to
  # replace certain instructions (or groups of instructions). Determine the
  # instructions involved in calling check_equals_, and then determine how many
  # bytes are used to represent them in memory. This will be the skip length.
  # (!)
  instruction_to_skip_length = 0x05     #不同系统下call指令的大小不同
  @project.hook(check_equals_called_address, length=instruction_to_skip_length)
  def skip_check_equals_(state):      #hook成这个函数
    # Determine the address where user input is stored. It is passed as a
    # parameter ot the check_equals_ function. Then, load the string. Reminder:
    # int check_equals_(char* to_check, int length) { ...
    user_input_buffer_address = 0x0804A054 # :integer, probably hexadecimal
    user_input_buffer_length = 0x10

    # Reminder: state.memory.load will read the stored value at the address
    # user_input_buffer_address of byte length user_input_buffer_length.
    # It will return a bitvector holding the value. This value can either be
    # symbolic or concrete, depending on what was stored there in the program.
    user_input_string = state.memory.load(       #加载这个地址处的值
      user_input_buffer_address, 
      user_input_buffer_length
    )
    
    # Determine the string this function is checking the user input against.
    # It's encoded in the name of this function; decompile the program to find
    # it.
    check_against_string = 'MRXJKZYRKMKENFZB'# :string

  #因为check_equals_MRXJKZYRKMKENFZB函数的返回值放在eax寄存器里面
    state.regs.eax = claripy.If(
      user_input_string == check_against_string, 
      claripy.BVV(1, 32), 
      claripy.BVV(0, 32)
    )

  simulation = project.factory.simgr(initial_state)

  def is_successful(state):
    stdout_output = state.posix.dumps(sys.stdout.fileno())
    return 'Good Job' in str(stdout_output)

  def should_abort(state):
    stdout_output = state.posix.dumps(sys.stdout.fileno())
    return 'Try again' in str(stdout_output)

  simulation.explore(find=is_successful, avoid=should_abort)

  if simulation.found:
    solution_state = simulation.found[0]

    # Since we are allowing Angr to handle the input, retrieve it by printing
    # the contents of stdin. Use one of the early levels as a reference.
    solution = solution_state.posix.dumps(sys.stdin.fileno())
    print (solution)
  else:
    raise Exception('Could not find the solution')

if __name__ == '__main__':
  main(sys.argv)
#用python 自定义函数来hook程序的函数跳过一些已知函数
#solution = solution_state.posix.dumps(sys.stdin.fileno()) 获取满足条件的格式化输入的数据

核心代码

 check_equals_called_address = 0x80486B3        #这个地址是call的地址参数没有改变,只改变call

  instruction_to_skip_length = 0x05     #不同系统下call指令的大小不同
  @project.hook(check_equals_called_address, length=instruction_to_skip_length)
  def skip_check_equals_(state):      #hook成这个函数
  
  check_equals_called_address为要hook的地址
  def skip_check_equals_(state): 这个函数会代替这个地址处原来的函数
  claripy.If(条件,条件为True时的返回值,条件为False时的返回值) => 创建条件判断

    claripy.BVV(值,值大小) => 创建一个数值


state.regs.eax = claripy.If(
      user_input_string == check_against_string, 
      claripy.BVV(1, 32), 
      claripy.BVV(0, 32)
    )

0x10通过函数名字hook

# This challenge is similar to the previous one. It operates under the same
# premise that you will have to replace the check_equals_ function. In this 
# case, however, check_equals_ is called so many times that it wouldn't make 
# sense to hook where each one was called. Instead, use a SimProcedure to write
# your own check_equals_ implementation and then hook the check_equals_ symbol 
# to replace all calls to scanf with a call to your SimProcedure.
#
# You may be thinking: 
#   Why can't I just use hooks? The function is called many times, but if I hook
#   the address of the function itself (rather than the addresses where it is 
#   called), I can replace its behavior everywhere. Furthermore, I can get the
#   parameters by reading them off the stack (with memory.load(regs.esp + xx)),
#   and return a value by simply setting eax! Since I know the length of the 
#   function in bytes, I can return from the hook just before the 'ret'
#   instruction is called, which will allow the program to jump back to where it
#   was before it called my hook.
# If you thought that, then congratulations! You have just invented the idea of
# SimProcedures! Instead of doing all of that by hand, you can let the already-
# implemented SimProcedures do the boring work for you so that you can focus on
# writing a replacement function in a Pythonic way.
# As a bonus, SimProcedures allow you to specify custom calling conventions, but
# unfortunately it is not covered in this CTF.

import angr
import claripy
import sys

def main(argv):
  path_to_binary = "10_angr_simprocedures"
  project = angr.Project(path_to_binary)

  initial_state = project.factory.entry_state()

  # Define a class that inherits angr.SimProcedure in order to take advantage
  # of Angr's SimProcedures.
  class ReplacementCheckEquals(angr.SimProcedure):

    def run(self, to_check,check_data_length):       #to_check,check_data_length代表着被hook的函数的两个参数
      # We can almost copy and paste the solution from the previous challenge.
      # Hint: Don't look up the address! It's passed as a parameter.
      # (!)
      user_input_buffer_address = to_check
      user_input_buffer_length = check_data_length

      # Note the use of self.state to find the state of the system in a 
      # SimProcedure.
      user_input_string = self.state.memory.load(
        user_input_buffer_address,
        user_input_buffer_length
      )

      check_against_string = 'MRXJKZYRKMKENFZB'
      
      # Finally, instead of setting eax, we can use a Pythonic return statement
      # to return the output of this function. 
      # Hint: Look at the previous solution.
      return claripy.If(
        check_against_string==user_input_string,
        claripy.BVV(1,32),
        claripy.BVV(0,32)
      )


  # Hook the check_equals symbol. Angr automatically looks up the address 
  # associated with the symbol. Alternatively, you can use 'hook' instead
  # of 'hook_symbol' and specify the address of the function. To find the 
  # correct symbol, disassemble the binary.
  # (!)
  check_equals_symbol = 'check_equals_MRXJKZYRKMKENFZB' # :string   要hook的函数名字
  project.hook_symbol(check_equals_symbol, ReplacementCheckEquals())    #仅仅指定函数名字和设置参数获取的变量,能自动获取到参数和函数
#和9不同这个二进制文件有很多call check_equals_MRXJKZYRKMKENFZB指令  不知道要hook哪一个
  simulation = project.factory.simgr(initial_state)

  def is_successful(state):
    stdout_output = state.posix.dumps(sys.stdout.fileno())
    return 'Good Job' in str(stdout_output)

  def should_abort(state):
    stdout_output = state.posix.dumps(sys.stdout.fileno())
    return 'Try again' in str(stdout_output)

  simulation.explore(find=is_successful, avoid=should_abort)

  if simulation.found:
    solution_state = simulation.found[0]

    solution = solution_state.posix.dumps(sys.stdin.fileno())
    print (solution)
  else:
    raise Exception('Could not find the solution')

if __name__ == '__main__':
  main(sys.argv)

核心代码
通过函数名hook一堆函数,并且获取这些函数的参数

class ReplacementCheckEquals(angr.SimProcedure):

    def run(self, to_check,check_data_length):       #to_check,check_data_length代表着被hook的函数的两个参数
 project.hook_symbol(check_equals_symbol, ReplacementCheckEquals())    #仅仅指定函数名字和设置参数获取的变量,能自动获取到参数和函数
#和9不同这个二进制文件有很多call check_equals_MRXJKZYRKMKENFZB指令  不知道要hook哪一个

0x11hook scanf函数,声明最终要解析的变量

# This time, the solution involves simply replacing scanf with our own version,
# since Angr does not support requesting multiple parameters with scanf.

import angr
import claripy
import sys
import binascii

def main(argv):
  path_to_binary = "11_angr_sim_scanf"
  project = angr.Project(path_to_binary)

  initial_state = project.factory.entry_state()

  class ReplacementScanf(angr.SimProcedure):
    # Finish the parameters to the scanf function. Hint: 'scanf("%u %u", ...)'.
    # (!)
    def run(self, format_string, scanf0_address, scanf1_address):
      scanf0 = claripy.BVS('scanf0', 4*8)
      scanf1 = claripy.BVS('scanf1', 4 * 8)

      # The scanf function writes user input to the buffers to which the 
      # parameters point.
      self.state.memory.store(scanf0_address, scanf0, endness=project.arch.memory_endness)
      self.state.memory.store(scanf1_address, scanf1, endness=project.arch.memory_endness)

      # Now, we want to 'set aside' references to our symbolic values in the
      # globals plugin included by default with a state. You will need to
      # store multiple bitvectors. You can either use a list, tuple, or multiple
      # keys to reference the different bitvectors.
      # (!)
      self.state.globals['solution0'] = scanf0
      self.state.globals['solution1'] = scanf1

  scanf_symbol = "__isoc99_scanf"
  project.hook_symbol(scanf_symbol, ReplacementScanf())

  simulation = project.factory.simgr(initial_state)

  def is_successful(state):
    stdout_output = state.posix.dumps(sys.stdout.fileno())
    return 'Good Job' in str(stdout_output)

  def should_abort(state):
    stdout_output = state.posix.dumps(sys.stdout.fileno())
    return 'Try again' in str(stdout_output)

  simulation.explore(find=is_successful, avoid=should_abort)

  if simulation.found:
    solution_state = simulation.found[0]

    # Grab whatever you set aside in the globals dict.
    stored_solutions0 = solution_state.globals['solution0']
    stored_solutions1 = solution_state.globals['solution1']
    solution0 = solution_state.se.eval(stored_solutions0)
    solution1 = solution_state.se.eval(stored_solutions1)

    solution = "".join(map("{:x}".format,[solution0,solution1]))

    print (binascii.a2b_hex(solution))
  else:
    raise Exception('Could not find the solution')

if __name__ == '__main__':
  main(sys.argv)


'''
stored_solutions1 = solution_state.globals['solution1']
solution0 = solution_state.se.eval(stored_solutions0)

获取全局变量
self.state.globals['solution1'] = scanf1
这样声明全局变量
'''
  

核心代码
生成二位向量,把变量放入内存,声明这个变量最终求解时用到

     scanf0 = claripy.BVS('scanf0', 4*8)
      scanf1 = claripy.BVS('scanf1', 4 * 8)

      # The scanf function writes user input to the buffers to which the 
      # parameters point.
      self.state.memory.store(scanf0_address, scanf0, endness=project.arch.memory_endness)
      self.state.memory.store(scanf1_address, scanf1, endness=project.arch.memory_endness)

      # Now, we want to 'set aside' references to our symbolic values in the
      # globals plugin included by default with a state. You will need to
      # store multiple bitvectors. You can either use a list, tuple, or multiple
      # keys to reference the different bitvectors.
      # (!)
      self.state.globals['solution0'] = scanf0
      self.state.globals['solution1'] = scanf1

求解声明的变量
stored_solutions0 = solution_state.globals['solution0']
solution0 = solution_state.se.eval(stored_solutions0)

0x12对比较长的变量求解

import angr
import sys
def main(argv):
    path_to_binary="12_angr_veritesting"
    project=angr.Project(path_to_binary)
    initial_state=project.factory.entry_state()
    simulation=project.factory.simgr(initial_state,veritesting=True)
    def is_successful(state):
        stdout_output=state.posix.dumps(sys.stdout.fileno())
        return 'Good Job'.encode() in stdout_output
    def should_abord(state):
        should_output=state.posix.dumps(sys.stdout.fileno())
        return 'Try again'.encode() in should_output

    simulation.explore(find=is_successful,avoid=should_abord)

    if simulation.found:
        solution_state = simulation.found[0]
        print(solution_state.posix.dumps(sys.stdin.fileno()))
    else:
        raise Exception('Could not find the solution')


if __name__ == '__main__':
    main(sys.argv)

核心代码
用veritesting=True选项来解决比较长的变量求解

simulation=project.factory.simgr(initial_state,veritesting=True)

0x04针对自定义的库函数求解
把函数hook掉(如果不hook会很难求解)

# This challenge is the exact same as the first challenge, except that it was
# compiled as a static binary. Normally, Angr automatically replaces standard
# library functions with SimProcedures that work much more quickly.
#
# Here are a few SimProcedures Angr has already written for you. They implement
# standard library functions. You will not need all of them:
# angr.SIM_PROCEDURES['libc']['malloc']
# angr.SIM_PROCEDURES['libc']['fopen']
# angr.SIM_PROCEDURES['libc']['fclose']
# angr.SIM_PROCEDURES['libc']['fwrite']
# angr.SIM_PROCEDURES['libc']['getchar']
# angr.SIM_PROCEDURES['libc']['strncmp']
# angr.SIM_PROCEDURES['libc']['strcmp']
# angr.SIM_PROCEDURES['libc']['scanf']
# angr.SIM_PROCEDURES['libc']['printf']
# angr.SIM_PROCEDURES['libc']['puts']
# angr.SIM_PROCEDURES['libc']['exit']
#
# As a reminder, you can hook functions with something similar to:
# project.hook(malloc_address, angr.SIM_PROCEDURES['libc']['malloc'])
#
# There are many more, see:
# https://github.com/angr/angr/tree/master/angr/procedures/libc
#
# Additionally, note that, when the binary is executed, the main function is not
# the first piece of code called. In the _start function, __libc_start_main is 
# called to start your program. The initialization that occurs in this function
# can take a long time with Angr, so you should replace it with a SimProcedure.
# angr.SIM_PROCEDURES['glibc']['__libc_start_main']
# Note 'glibc' instead of 'libc'.
import angr
import sys
def main(argv):
    path_to_binary="13_angr_static_binary"
    project=angr.Project(path_to_binary)
    initial_state=project.factory.entry_state()
    simulation=project.factory.simgr(initial_state,veritesting=True)


    project.hook(0x804ed40,angr.SIM_PROCEDURES['libc']['printf']())
    project.hook(0x804ed80, angr.SIM_PROCEDURES['libc']['scanf']())
    project.hook(0x804f350, angr.SIM_PROCEDURES['libc']['puts']())
    project.hook(0x8048d10, angr.SIM_PROCEDURES['glibc']['__libc_start_main']())

    def is_successful(state):
        stdout_output=state.posix.dumps(sys.stdout.fileno())
        return 'Good Job'.encode() in stdout_output
    def should_abord(state):
        should_output=state.posix.dumps(sys.stdout.fileno())
        return 'Try again'.encode() in should_output

    simulation.explore(find=is_successful,avoid=should_abord)

    if simulation.found:
        solution_state = simulation.found[0]
        print(solution_state.posix.dumps(sys.stdin.fileno()))
    else:
        raise Exception('Could not find the solution')


if __name__ == '__main__':
    main(sys.argv)

# project.hook(0x804ed40,angr.SIM_PROCEDURES['libc']['printf']())
#获取angr内部实现的函数

angr已经实现了系统函数,想hook很简单
不过这里好像只需要hook输入输出函数就行了还有这个函数__libc_start_main

用来hook系统函数,注意库函数不同,这个地址为函数被call过之后的开始

    project.hook(0x804f350, angr.SIM_PROCEDURES['libc']['puts']())
    project.hook(0x8048d10, angr.SIM_PROCEDURES['glibc']['__libc_start_main']())

0x14分析动态链接库

import angr
import claripy
import sys
import binascii

def main(argv):
  path_to_binary ="lib14_angr_shared_library.so"

  base = 0x400000
  project = angr.Project(path_to_binary, load_options={ 
    'main_opts' : { 
      'custom_base_addr' : base 
    } 
  })    #加载动态链接库



  buffer_pointer=claripy.BVV(0x3000000,32)#创造一个32位的指针,值是任意的但这个值指向输入数据
  validate_function_address = base+0x000006D7
  initial_state = project.factory.call_state(validate_function_address, buffer_pointer,claripy.BVV(8,32))#要调用的库函数和他的参数

  # You will need to add code to inject a symbolic value into the program at the
  # end of the function that constrains eax to equal true (value of 1) just
  # before the function returns. There are multiple ways to do this:
  # 1. Use a hook.
  # 2. Search for the address just before the function returns and then
  #    constrain eax (this may require putting code elsewhere)
  password=claripy.BVS('password',8*8)
  initial_state.memory.store(buffer_pointer,password)   #向0x30000000地址处存入数据


  simulation = project.factory.simgr(initial_state)

  success_address = base+0x0000783        #函数结束的地址
  simulation.explore(find=success_address)

  if simulation.found:
    solution_state = simulation.found[0]
    solution_state.add_constraints(solution_state.regs.eax != 0)       #添加限制条件

    # Determine where the program places the return value, and constrain it so
    # that it is true. Then, solve for the solution and print it.
    # (!)
    solution = solution_state.se.eval(password)
    solution="".join(map("{:x}".format,[solution]))

    print (binascii.a2b_hex(solution))
  else:
    raise Exception('Could not find the solution')

if __name__ == '__main__':
  main(sys.argv)


'''
 base = 0x400000
  project = angr.Project(path_to_binary, load_options={ 
    'main_opts' : { 
      'custom_base_addr' : base 
    } 
  })    #加载动态链接库
  加载动态链接库
  
  
  buffer_pointer=claripy.BVV(0x3000000,32)#创造一个32位的指针,值是任意的但这个值指向输入数据
  validate_function_address = base+0x000006D7
  initial_state = project.factory.call_state(validate_function_address, buffer_pointer,claripy.BVV(8,32))#要调用的库函数和他的参数
  设置要调用的库函数

获取运行到这里时寄存器的值

solution = solution_state.se.eval(password)
获取运行到这里时满足的输入
'''

对动态库的操作

 base = 0x400000
  project = angr.Project(path_to_binary, load_options={ 
    'main_opts' : { 
      'custom_base_addr' : base 
    } 
  })    #加载动态链接库
  加载动态链接库
  
  
  buffer_pointer=claripy.BVV(0x3000000,32)#创造一个32位的指针,值是任意的但这个值指向输入数据
  validate_function_address = base+0x000006D7
  initial_state = project.factory.call_state(validate_function_address, buffer_pointer,claripy.BVV(8,32))#要调用的库函数和他的参数
  设置要调用的库函数
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值