angr的学习与记录(一:输入find地址、avoid地址和不确定查找)

angr是干嘛的

总结来说,angr用于逆向工程中进行二进制分析的一个python框架
具体介绍见其github主页angr

符号执行 (Symbolic Execution)是一种程序分析技术。其可以通过分析程序来得到让特定代码区域执行的输入。使用符号执行分析一个程序时,该程序会使用符号值作为输入,而非一般执行程序时使用的具体值。在达到目标代码时,分析器可以得到相应的路径约束,然后通过约束求解器来得到可以触发目标代码的具体值。 – 摘自维基百科

我的理解就是一个可以自己寻路的爆破工具

然后说一下学习:

学习的题目来自Github的ctf_angr。
使用环境目前出了问题,先只针对题目描述填空,环境配好之后再做添加修改。

需要题目直接在Github搜索ctf_angr

下载下来是这样的:

在这里插入图片描述

这是程序源码,题目在dist里面,答案在aolutions里面。

类型差不多的会放在一个文章

00_angr_find

光看题目,爆破完全,没问题,这里使用angr解决吧
在这里插入图片描述

打开题目提供的对应py文件(附带翻译):

# Before you begin, here are a few notes about these capture-the-flag
# challenges.
#
# Each binary, when run, will ask for a password, which can be entered via stdin
# (typing it into the console.) Many of the levels will accept many different
# passwords. Your goal is to find a single password that works for each binary.
#
# If you enter an incorrect password, the program will print "Try again." If you
# enter a correct password, the program will print "Good Job."
#
# Each challenge will be accompanied by a file like this one, named
# "scaffoldXX.py". It will offer guidance as well as the skeleton of a possible
# solution. You will have to edit each file. In some cases, you will have to
# edit it significantly. While use of these files is recommended, you can write
# a solution without them, if you find that they are too restrictive.
#
# Places in the scaffoldXX.py that require a simple substitution will be marked
# with three question marks (???). Places that require more code will be marked
# with an ellipsis (...). Comments will document any new concepts, but will be
# omitted for concepts that have already been covered (you will need to use
# previous scaffoldXX.py files as a reference to solve the challenges.) If a
# comment documents a part of the code that needs to be changed, it will be
# marked with an exclamation point at the end, on a separate line (!).

import angr
import sys

def main(argv):
  # Create an Angr project.
  # If you want to be able to point to the binary from the command line, you can
  # use argv[1] as the parameter. Then, you can run the script from the command
  # line as follows:
  # python ./scaffold00.py [binary]
  # (!)
  path_to_binary =  ???# :string输入的是题目文件地址,argv[1]来自控制台参数,也可以直接输入地址
  project = angr.Project(path_to_binary)

  # Tell Angr where to start executing (should it start from the main()
  # function or somewhere else?) For now, use the entry_state function
  # to instruct Angr to start from the main() function.
  # 告诉Angr从哪里开始执行(应该从main()开始) 现在,使用entry_state函数指示Angr从main()函数开始。
  initial_state = project.factory.entry_state()
  

  # Create a simulation manager initialized with the starting state. It provides
  # a number of useful tools to search and execute the binary.
  #创建使用启动状态初始化的模拟管理器。它提供了许多有用的工具来搜索和执行二进制文件。
  simulation = project.factory.simgr(initial_state)

  # Explore the binary to attempt to find the address that prints "Good Job."
  # You will have to find the address you want to find and insert it here. 
  # This function will keep executing until it either finds a solution or it 
  # has explored every possible path through the executable.
  # (!)
  #探索二进制文件以尝试找到打印“干得好”的地址。您必须找到要查找的地址并将其插入此处。此函数将一直执行,直到找到解决方案或探索通过可执行文件的所有可能路径为止。(!)
  print_good_address = ??? # :integer (probably in hexadecimal)
  simulation.explore(find=print_good_address)

  # Check that we have found a solution. The simulation.explore() method will
  # set simulation.found to a list of the states that it could find that reach
  # the instruction we asked it to search for. Remember, in Python, if a list
  # is empty, it will be evaluated as false, otherwise true.
  # 检查我们是否找到了解决方案。explore()方法将simulation.found设置为它可以找到到达的状态列表 我们要求它搜索的指令。记住,在Python中,如果列表为空,则将其计算为false,否则为true。
  if simulation.found:
    # The explore method stops after it finds a single state that arrives at the
    # target address.
    #explore方法在找到到达目标地址的单个状态后停止。
    solution_state = simulation.found[0]

    # Print the string that Angr wrote to stdin to follow solution_state. This 
    # is our solution.
    # 打印Angr写入stdin的字符串以遵循解决方案状态。这是我们的解决方案。
    print solution_state.posix.dumps(sys.stdin.fileno())
  else:
    # If Angr could not find a path that reaches print_good_address, throw an
    # error. Perhaps you mistyped the print_good_address?
    # 如果Angr找不到到达print\u good\u地址的路径,则抛出一个错误。也许你把打印地址打错了?

    raise Exception('Could not find the solution')#这是一个错误处理机制,也不是很懂,可以百度看看

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

第一次看觉得混不打紧,总结一下主要流程:
先告诉angr文件地址在哪里:

project = angr.Project(path_to_binary)

再告诉angr文件的main函数在哪里:

initial_state = project.factory.entry_state()

创建模拟管理器:

simulation = angr.factory.simgr(initial_state)

告诉angr输入正确的地址:

angr.explore(find = print_good_address)

使用答案很简单:

agrv[1]
0x0804867D

01_angr_avoid

打开题目文件,main函数反汇编失败:
在这里插入图片描述这angr的优势就出来了。

打开对应py文件:

import angr
import sys

def main(argv):
  path_to_binary = argv[1]
  project = angr.Project(path_to_binary)
  initial_state = project.factory.entry_state()
  simulation = project.factory.simgr(initial_state)

  # Explore the binary, but this time, instead of only looking for a state that
  # reaches the print_good_address, also find a state that does not reach
  # will_not_succeed_address. The binary is pretty large, to save you some time,
  # everything you will need to look at is near the beginning of the address
  # space.
  # (!)
  print_good_address = ???
  will_not_succeed_address = ???
  simulation.explore(find=print_good_address, avoid=will_not_succeed_address)

  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)

和第一题差不多,多了一个avoid。
顾名思义就是避免这条路径,可以使爆破更准确。

在这里插入图片描述
这个avoid_me不一定要是最后输出错误的地址,但填那个地址也没多大问题。
可以看到每次比较以后跳转后都有个函数。
这个函数点进去:
在这里插入图片描述
有一个将should_succeed置零的操作:

所以这个函数一个是不正确执行的,这么多分支jump,要是告诉了angr会不会跳转,是不是效率就更高了。
所以填:

0x0x080485e5
0x080485A8

提示:
在这里插入图片描述
should_succeed是个define 为 1,置零就是错误。

02_angr_find_condition

这个我们先看描述:在这里插入图片描述
意思就是,当程序中不至一个输出正确的函数地址时,我们可以通过他输出的字符串来让angr自动确定多个地址。

打开
可以看到有很多的puts干扰我们。虽然看main也可以找到到底是哪一个puts,但这不重要,我们要了解angr有这样一个机制。

提供的py文件:

# It is very useful to be able to search for a state that reaches a certain
# instruction. However, in some cases, you may not know the address of the
# specific instruction you want to reach (or perhaps there is no single
# instruction goal.) In this challenge, you don't know which instruction
# grants you success. Instead, you just know that you want to find a state where
# the binary prints "Good Job."
#
# Angr is powerful in that it allows you to search for a states that meets an
# arbitrary condition that you specify in Python, using a predicate you define
# as a function that takes a state and returns True if you have found what you
# are looking for, and False otherwise.

import angr
import sys

def main(argv):
  path_to_binary = argv[1]
  project = angr.Project(path_to_binary)
  initial_state = project.factory.entry_state()
  simulation = project.factory.simgr(initial_state)

  # Define a function that checks if you have found the state you are looking
  # for.
  def is_successful(state):
    # Dump whatever has been printed out by the binary so far into a string.
    stdout_output = state.posix.dumps(sys.stdout.fileno())

    # Return whether 'Good Job.' has been printed yet.
    # (!)
    return ???  # :boolean

  # Same as above, but this time check if the state should abort. If you return
  # False, Angr will continue to step the state. In this specific challenge, the
  # only time at which you will know you should abort is when the program prints
  # "Try again."
  def should_abort(state):
    stdout_output = state.posix.dumps(sys.stdout.fileno())
    return ???  # :boolean

  # Tell Angr to explore the binary and find any state that is_successful identfies
  # as a successful state by returning True.
  #将函数名变成变量传递
  simulation.explore(find=is_successful, avoid=should_abort)

  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)

这里可能有一点不好理解,在simulation.explore(find=is_successful, avoid=should_abort),我们可能有个疑惑,为什么传入的是一个函数的名字,难道我们要寻找这个函数的名字吗。

函数名字代表什么,有哪些操作
在这里插入图片描述
python中的函数可以看做是一个单独的类型,type方法输出函数名时,输出的是function
在这里插入图片描述
simulation.explore(find=is_successful, avoid=should_abort) 中就应该是一个重载,重载的函数可以将查找的数据作为函数的参数,并通过返回值判断是否位Ture

state.posix.dumps(sys.stdout.fileno()) 将查找的二进制代码转为字符串(不是太懂,是这么个格式)

所以答案就是:

“Good Job.” in stdout_output
“Try again.” in stdout_output"
或者
“Good Job.” == stdout_output
“Try again.” == stdout_output"

文章部分为自己的理解,如有错误希望指出,thinku。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

I Am Rex

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值