# 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