본문 바로가기

Reversing

08. angr

1. angr?


먼저 angr 라는게 뭔지부터 말해보자.

뭐 어떤 팀에서 만들어 모듈로 사용한다. 이런식의 말도 할 수 있지만 그런 내용은 블로그 혹은 기사 등에서 잘 찾아볼 수 있으므로 간단하게 얘기하고자한다.(작성자의 실력이 부족한 것도 한 몫한다.)

지금까지 사용한 angr에 대한 결론은 복잡한 reversing 문제들 즉, 중첩 if 문이 너무 많거나 switch 문이 너무 많거나 혹은 어떤 조건을 만족시켜야만 풀 수 있는 문제들을 몇 줄의 코드로 손 쉽게 풀 수 있게 도와주는 도구이다.



2. install?


그럼 설치는 어떻게 하는가. 이 또한 다른 블로그 들에 많이 게재되어 있지만 설치 방법을 소개하고자한다. 필자는 리눅스 시스템을 기본으로 설명한다.


먼저,

sudo apt-get update

apt-get install python-dev libffi-dev build-essential virtualenvwrapper

이 명령어를 입력해서 다운로드를 받자.


그리고 환경변수를 만들어줘야 하므로

mkdir ~/.environments

이렇게 입력해준 뒤


관리자 권한을 받아서

sudo find / -name "virtualenvwrapper.sh"

이렇게 입력하고


echo source path >> ~/.bashrc

echo export WORKON_HOME="~/.environments" >> ~/.bashrc

이렇게 입력하고


source ~/.bashrc

mkvirtualenv angr && pip install angr

이렇게 입력을 모두 하고나면 angr 모듈이 설치되어 있을 것이다.




3. sooooo basic, easy angr


쉬운 앵거 문제로 DEFCON 의 baby-re 문제를 풀곤하지만 필자는 제대로 된 baby-re 파일을 구하지 못해 간단한 비교 후 출력하는 프로그램을 직접 만들어서 angr로 돌려보았다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdio.h>
 
int main(void){
int a = 10;
int b,c,d = 0;
 
printf("Input b: ");
scanf("%d",&b);
 
printf("Input c: ");
scanf("%d",&c);
 
printf("Input d: ");
scanf("%d"&d);
 
if(b == 25){
    if(c == 271){
        if(d == 111){
            printf("Success! a is %d\n", a);
            }
        }
    }
else{
    printf("not b,c,d equal! \n");
}
 
return 0;
}
cs

위 코드는 필자가 작성한 코드이다. 간단하게 b,c,d 를 입력받고 3중첩 if로 b,c,d가 모두 맞으면 a를 출력해준다. 이걸 angr로 풀어보도록 하자.

먼저 이 프로그램에서 if 문이 모두 통과했을 때 주소, else로 가는 주소를 알아야한다. 앵거에서 그 부분으로 가고, 뛰어넘고 이것을 설정해주기 때문이다.

따라서 프로그램을 IDA 혹은 리눅스의 gdb로 분석한다. 필자는 IDA로 분석했다.


어쨌든 열어보게 되면 b,c,d 를 입력받고 하나라도 다르면 0x4006a2 주소로 점프, 아니면 0x40067a 로 점프해서 성공문을 출력해준다.

그렇다면 우리는 0x4006a2 주소로 점프하는 것을 피하고 0x40067a 주소로 점프해 저 성공문을 출력하는 곳까지 진행하는 것을 목표로 해야한다.


그 코드를 파이썬을 이용해 간단하게 짜보면 다음과 같다.


1
2
3
4
5
6
7
8
9
import angr
 
proj = angr.Project("/home/p3ngdump/Desktop/anger", load_options={'auto_load_libs': False})
 
path_group = proj.factory.path_group(threads=4)
path_group.explore(find=0x4006a0, avoid=0x4006a2);
 
print(repr(path_group.found[0].state.posix.dumps(1)))
 
cs

여기서 path_group = proj.factory.path_group(threads=4) 부분은 프로그램이 돌아갈 때 쓰레드의 수를 설정해주는 것인데, 사실상 그렇게 중요하지도 않고 이 정도의 프로그램에서는 굳이 지정해주지 않아도 기본 지정으로도 충분히 잘 돌아간다.


그리고 path_group.explore(find=0x4006a0, avoid=0x4006a2) 가 find 부분이 찾아갈 주소, avoid가 피해갈 주소인데 어째서 찾아갈 주소가 0x4006a0인지 궁금할 수도 있을 것이다. 앵거에서는 프로그램의 실행을 쭉 따라가서 실행해 주는것이 아니라 코딩된 주소를 찾아가는 것을 목적으로 한다. 따라서 printf 함수가 출력되는 0x40069b 전을 찾는 주소로 지정할 시 아마 아무것도 뜨지 않고 프로그램이 종료될 것이다.


이렇게 코딩하고 파이썬을 실행하게되면



이런 화면을 볼 수 있고 실행자는 아무 입력도 주지 않았지만 Success 문이 뜬다. 그리고 주황색으로 표시된 문자열이 신경쓰일 수 있는데 저건 그냥 scanf 에서 실행자가 하는 입력이 없어서 나오는 문자열이므로 크게 신경쓰지 않아도 된다.



반응형

'Reversing' 카테고리의 다른 글

10. FUD(Fully UnDetectable)  (0) 2023.10.05
09. Anti-Debugging  (0) 2018.06.15
07. arm 어셈블리어 정리  (0) 2017.10.27
06. gdb 명령어 정리  (0) 2017.09.29
05. 스택, 스택프레임  (0) 2017.08.04