# Angr Tutorial
Link: https://github.com/Hustcw/Angr_Tutorial_For_CTF
Sử dụng `pypy` để có thể chạy angr nhanh hơn
Vì conda chỉ hỗ trợ đến phiên bản pypy3.9 nên ở đây mình sẽ không sử dụng conda
```bash
wget https://downloads.python.org/pypy/pypy3.11-v7.3.19-linux64.tar.bz2
tar -xvjf pypy3.11-v7.3.19-linux64.tar.bz2
cd pypy3.11-v7.3.19-linux64
./bin/pypy3 -m venv angr-env
source angr-env/bin/activate
pypy3 -m pip install angr
```
## Problem 1
```c=
int __cdecl main(int argc, const char **argv, const char **envp)
{
int i; // [esp+1Ch] [ebp-1Ch]
char s1[9]; // [esp+23h] [ebp-15h] BYREF
unsigned int v6; // [esp+2Ch] [ebp-Ch]
v6 = __readgsdword(0x14u);
printf("Enter the password: ");
__isoc99_scanf("%8s", s1);
for ( i = 0; i <= 7; ++i )
s1[i] = complex_function(s1[i], i);
if ( !strcmp(s1, "JACEJGCS") )
puts("Good Job.");
else
puts("Try again.");
return 0;
}
```
Ở đây ta thấy nếu như input đúng thì chương trình sẽ in ra `Good Job.`

Kiểm tra địa chỉ in ra thông báo `0x804867D`
**Script**
```python=
import angr
def main():
# create project
proj = angr.Project('problems/00_angr_find')
# entry point
init_state = proj.factory.entry_state()
# create simulation
simulation = proj.factory.simgr(init_state)
# expected address
print_good = 0x804867d
# start explore
simulation.explore(find=print_good)
if simulation.found:
solution = simulation.found[0]
flag = solution.posix.dumps(0)
print(f"Flag: {flag}")
else:
print("No solution")
if __name__ == "__main__":
main()
# Flag: b'JXWVXRKX'
```
Mã này sẽ thực hiện mô phỏng lại chương trình và tìm đường đến địa chỉ `print_good`
## problem 2


Phần này ta thấy rằng giá trị được khởi tạo ban đầu của `should_succeed` là 1
Và chương trình sẽ in ra `Good Job.` khi giá trị `should_succeed` bằng 1
Nhưng trước đó sẽ có một function là `avoid_me` sẽ thay đổi giá trị của `should_succeed` thành 0 --> chương trình sẽ in ra `Try again.`

Vì vậy ta cần tránh chương trình chạy vào hàm này (`0x80485a8`)
**Script**
```python=
import angr
def main():
# create project
proj = angr.Project("problems/01_angr_avoid")
# entry point
init_state = proj.factory.entry_state()
# create simulation
simulation = proj.factory.simgr(init_state)
# expected address
print_good = 0x080485e5
# avoid address
avoid_addr = 0x80485a8
simulation.explore(find=print_good, avoid=avoid_addr)
if simulation.found:
solution = simulation.found[0]
flag = solution.posix.dumps(0)
print(f"Flag: {flag}")
else:
print("No solution")
if __name__ == "__main__":
main()
# Flag: b'HUJOZMYS'
```
Tương tự như chương trình trên nhưng sẽ khác là sẽ tránh chạy vào `avoid_addr`
## Problem 3
```c=
int __cdecl main(int argc, const char **argv, const char **envp)
{
int i; // [esp+18h] [ebp-40h]
int j; // [esp+1Ch] [ebp-3Ch]
char s1[20]; // [esp+24h] [ebp-34h] BYREF
char s2[20]; // [esp+38h] [ebp-20h] BYREF
unsigned int v8; // [esp+4Ch] [ebp-Ch]
v8 = __readgsdword(0x14u);
for ( i = 0; i <= 19; ++i )
s2[i] = 0;
qmemcpy(s2, "VXRRJEUR", 8);
printf("Enter the password: ");
__isoc99_scanf("%8s", s1);
for ( j = 0; j <= 7; ++j )
s1[j] = complex_function(s1[j], j + 8);
if ( !strcmp(s1, s2) )
puts("Good Job.");
else
puts("Try again.");
return 0;
}
```
Chương trình này cũng chỉ là nhập vào chuỗi s1 và so sánh lại với chuỗi s2
Nhưng khác với các chương trình trên tìm kiếm theo địa chỉ, thì ở đây ta sẽ tìm kiểm theo đầu ra được trả về từ chương trình
**Script**
```python=
import angr, sys
def main():
proj = angr.Project("problems/02_angr_find_condition")
init_state = proj.factory.entry_state()
simulation = proj.factory.simgr(init_state)
simulation.explore(find=is_successful, avoid=should_abort)
if simulation.found:
solution = simulation.found[0]
flag = solution.posix.dumps(sys.stdin.fileno())
print(f"Flag: {flag}")
else:
print("No solution")
# set expected function
# note: sys.stdout.fileno() is the stdout file discription number. you can replace it by 1
# note: state.posix is the api for posix, and dumps(file discription number) will get the
# bytes for the pointed file.
def is_successful(state):
# Có thể thay thế sys.stdin.fileno() bằng 1
return b"Good Job" in state.posix.dumps(1)
# set disexpected function
def should_abort(state):
return b"Try again" in state.posix.dumps(1)
if __name__ == "__main__":
main()
# Flag: b'HETOBRCU'
```
So với tìm kiếm theo địa chỉ thì việc tìm kiếm theo đầu ra sẽ chậm hơn
Theo mình nghĩ thì nó sẽ thích hợp với các dạng mà địa chỉ không cố định