---
# System prepended metadata

title: Angr Tutorial

---

# 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.`

![image](https://hackmd.io/_uploads/HymfzILAkl.png)
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
![image](https://hackmd.io/_uploads/HJh1oUICye.png)

![image](https://hackmd.io/_uploads/rJ0ic8IRkg.png)

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.`

![image](https://hackmd.io/_uploads/rJh9i8UA1x.png)

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