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。