reversing

Layer7 리버싱 5차시 과제(3) - prob4 분석

leesu0605 2022. 8. 1. 18:01

목차

1. prob4 분석 및 코드 복원


1. prob4 분석 및 코드 복원


main함수를 뜯어봤다.
처음에 시작하자마자 fopen으로 파일을 여는 걸 볼 수 있는데, 한 번 어떤 파일인지 확인해보자.
fopen은 첫 번째 인자가 파일 이름, 두 번째 인자가 파일 열기 모드이므로 첫번째 인자에 파일 이름이 들어있을 것이다.

그랬더니 이런 문자열이 나왔다.
/dev 경로에 있다는 건 문제 제작자가 직접 urandom 파일을 만들었을 확률은 적으니 인터넷에 무슨 파일인지 검색해봤다.

검색해보니, urandom에선 절대 예측 불가능한 문자열을 준다는 사실을 알게 됐고, 다음 함수를 분석하기 시작했다.

rbp-0x10에 fopen으로 얻은 파일 디스크립터를 저장하고, 4바이트 1블록를 읽어와 rbp-0x1c에 저장한다는 사실을 알 수 있었다.

그 다음엔 fclose로 파일을 닫아주고, 아까 urandom에서 얻어온 4바이트 1블록을 srand의 인자로 줘 rand()의 시드를 무작위로 설정했다.

그 다음 rbp-0x14에 반복횟수를 저장한 for문의 전개가 나오면서 반복문이 시작됐다.

총 0x2710번 반복하는 반복문이다.

그럼 for문의 내용을 살펴보자.

반복문의 초반부에서는 printf 함수로 [반복횟수+1] 값을 출력하고 있다.
아마 0x400a63에는 "%d" 형식지정자가 들어있는 문자열이 있을 것이다.

존재한다.
printf로 반복횟수를 출력한 다음엔, scanf로 rbp-0x18에 입력을 받는데, 0x400a6d를 첫 번째 인자로 전해주고 있는 것으로 보아, 형식지정자가 포함된 문자열일 것이다.

맞았다.

이렇게 입력을 받은 후, rand()함수로 입력을 받고, 몇가지 연산을 진행하는데, 0x66666667, sar, imul이 한꺼번에 나오는 것으로 보아, 10으로 나눈 모듈러 연산을 수행한다는 사실을 알 수 있다.
자세한 설명은 prob3 블로그를 보면 좋을 것 같다.

어쨌든, rand()로 얻은 값을 10으로 나눈 나머지와 비교한 후, 값이 다르면 0x400a70에 있는 문자열("Wrong!!")을 출력한 후 프로세스를 종료하고, 같으면 계속 반복문을 수행한다.

그렇게 반복문을 0x2710번 수행하게 되면, for문을 빠져나와 flag_generator에서 만든 문자열을 puts로 출력한다.
이제 한 번 플래그를 알아내보자.

urandom에서 만든 문자열은 완전 무작위라 했으므로, prob3에서 했던 것처럼 jump명령어를 통해 flag_generator를 호출하는 부분으로 edi를 이동시키면 문제가 풀릴 것 같다.
한 번 해보자.

반복문에 들어가기 전에 점프할 것이므로 반복 횟수 저장 변수를 0으로 초기화하는 코드에 브레이크 포인트를 걸었다.
그 후, r명령어로 실행시켜 원하는 포인트에 멈추는지 확인했다.

브레이크 포인트에 잘 걸렸다.

그럼 flag_generator를 호출하는 main+223으로 점프를 시도해보자.

플래그가 제대로 나왔다.
flag : Layer7{TH3_3ND_0F_3V4NG3L1ON}

그럼 이 코드를 C코드로 복원시켜보자.

#include <stdio.h>
#include <time.h>
#include <stdlib.h>

char* flag_generator(){
        return "Layer7{TH3_3ND_0F_3V4NG3L1ON}";
}

int main(){
        FILE* fd = fopen("/dev/urandom", "r");
        int seed;
        fread(&seed, 4, 1, fd);
        fclose(fd);
        srand(seed);
        for(int i=0;i<=0x270f;i++){
                int t;
                printf("step %d : ", i+1);
                scanf("%d", &t);
                if(t!=rand()%10){
                        puts("Wrong!!");
                        return 0;
                }
        }
        puts(flag_generator());
}