리버싱kr easy_crackme풀이 3
이전에 두 번째 루틴까지 풀었다.
풀은 루틴까지 적용시켜 빠르게 디버깅 해 보기 위해
이전 루틴들을 맞춘 상태로 실행시켰다.
이전 루틴 다음줄까지 다른 수정 없이 바로 진행되는 것을 볼 수 있다. 다시 시작해보자.
따로 함수 호출을 하진 않지만 많은 연산을 거치며 마지막에 test연산을 통해 루틴 검사를 하는 것을 볼 수 있다.
esi와 ebx의 레지스터를 온전히 사용하기 위해 스택에 push해 백업하고, esi에 "R3versing"이라는 문자열을 복사한다.
push를 2번 하여 스택 포인터, 즉 esp가 가리키는 위치는 두 번 증가하였고, esp + 10의 위치는 입력한 문자열의 5번째 위치, 숫자 '1'의 위치이다.
문자열이 있는 주소를 eax에 복사하여 넣어준다.
그 후 dl과 bl에 각각 eax와 esi가 가진 데이터를 바이트 크기로 복사하여 값을 넣은 것을 볼 수 있다.
두 실행문을 실행하고 난 결과이다.
ebx에는 "R3versing" 문자열의 바이트 크기 첫 번째 문자 'R'이 들어갔고,
edx에는 "12345667" 문자열의 바이트 크기 첫 번째 문자 '1'이 들어갔다.
그 후에 cl에 dl의 값을 복사한 뒤, cmp로 dl과 bl을 비교하여 같지 않으면 점프하는게 보인다.
내용이 비슷한게 있어보이니 하나하나 보기보단 조금 큰 흐름으로 봐보자.
세 번째 루틴이다. 마지막에 test eax, eax를 통해 틀렸는지 검사해 Incorrect로 점프하는 곳이 있다.
그 위를 보면
xor eax, eax를 톻해 eax레지스터의 값을 0으로 만들고 test실행문에 점프하는 곳이 있다.
앞전에도 알아낸 결과로 생각하면 xor을 통해 레지스터의 값을 0으로 만들고 test실행문을 거치면 equal이 나온다.
그럼 004010FE 식을 실행하면 된다. sbb연산을 통해 eax의 값을 0이 아닌 값으로 바꾸게 하면 안된다는 것이다.
sbb에 점프되는 위치들이
두 군데 있는 것을 볼 수 있다.
그리고 xor식 바로 위를 보면
jne문을 통해 다시 위로 점프하는 곳이 있는데, 점프된 위치가 다른 함수가 있는 곳이나 전혀 모르는 위치가 아닌 이 루틴의 시작 지점으로 간다.
그럼 dl과 bl을 반복적으로 검사하며 틀렸을 경우 eax에 연산을 가해 test에서 걸리게 만든 형식같다.

다시, 처음 이곳으로 와서
cl은 jne로 반복문의 조건을 담당하게 되는데, dl의 값을 복사해 카운터로 사용하고,
cl도 마찬가지로 test연산을 통해 0일 경우 점프하게 되어있다.
그럼 dl은 무슨 값을 가지고 있을까 하면
내가 입력한 값의 문자를 가지고 있다.

dl에 '1'이 들어가 있는 것을 볼 수 있다.
dl과 bl을 비교해 같지 않으면 틀린 연산 점프
test cl, cl의 값이 equal일 경우 맞는 연산 점프(dl과 bl이 같은데 NULL일 경우)
그리고 eax + 1의 값을 다시 dl에
esi + 1의 값을 다시 bl에 넣고
dl과 bl을 비교해 같지 않으면 틀린 연산 점프
test cl, cl의 값이 같지 않을 경우동안 반복
이런 순서로 진행되는 것을 볼 수 있다.
한 번 한 번 실행해 보는 것보단 크게 보며 분석을 통해 진행하는 편이 수월할 것 같다.
좀 더 깔끔히 정리해서
어셈블리어를 c언어로 간단히 번역하자면 이렇게 생각하면 될 것 같다.
그럼 이 루틴의 풀이법은 뭐냐, 하면 간단히 생각해서 그냥 두 문자열이 정확히 같으면 된다..는 것이다.
그리고 문자열이 뒤에 더 없어야 한다. 입력한 문자열이 NULL이 나올 때까지 반복하는데 입력한 문자열이 "R3versing"보다 길면 NULL과 내가 입력한 문자열을 비교할 때 틀리게 될 것이다.
다시 실행해 문자열을 정확히 똑같이 맞추고 실행시켜 보았다.
바이너리 수정 없이 빠르게 루틴을 클리어 한 것을 볼 수 있다.
마지막으로, 그 다음 실행문은
esp + 4와 'E'를 비교해 같지 않으면 틀렸다고 판단하는 조건문인데, esp + 4의 위치는 내가 입력한 문자열의 첫 번째 문자가 시작되는 위치이다.
다시말해, 첫 번째 문자가 'E'가 아니면 틀렸다고 본다.
이곳까지 지나고 나면 모든 루틴은 지나갔다. 맞았다는 MessageBox를 띄우고 프로그램을 종료한다.
세-네번째 루틴을 통하며 모든 루틴을 해석하면
루틴의 순서대로
1. 입력한 문자열의 두 번째 문자가 'a'여야 한다.
2. 입력한 문자열의 세 번째 문자부터 정확히 두 문자가 "5y"여야 한다,
3. 입력한 문자열의 다섯 번째 문자부터 정확히 문자열이 "R3versing"이어야 한다.
4. 입력한 문자열의 첫 번째 문자가 'E'여야 한다.
이를 통하여 플래그 값은 "Ea5yR3versing"인 것을 볼 수 있다.
풀은 루틴까지 적용시켜 빠르게 디버깅 해 보기 위해
이전 루틴들을 맞춘 상태로 실행시켰다.
이전 루틴 다음줄까지 다른 수정 없이 바로 진행되는 것을 볼 수 있다. 다시 시작해보자.
따로 함수 호출을 하진 않지만 많은 연산을 거치며 마지막에 test연산을 통해 루틴 검사를 하는 것을 볼 수 있다.
esi와 ebx의 레지스터를 온전히 사용하기 위해 스택에 push해 백업하고, esi에 "R3versing"이라는 문자열을 복사한다.
push를 2번 하여 스택 포인터, 즉 esp가 가리키는 위치는 두 번 증가하였고, esp + 10의 위치는 입력한 문자열의 5번째 위치, 숫자 '1'의 위치이다.
문자열이 있는 주소를 eax에 복사하여 넣어준다.
그 후 dl과 bl에 각각 eax와 esi가 가진 데이터를 바이트 크기로 복사하여 값을 넣은 것을 볼 수 있다.
두 실행문을 실행하고 난 결과이다.
ebx에는 "R3versing" 문자열의 바이트 크기 첫 번째 문자 'R'이 들어갔고,
edx에는 "12345667" 문자열의 바이트 크기 첫 번째 문자 '1'이 들어갔다.
그 후에 cl에 dl의 값을 복사한 뒤, cmp로 dl과 bl을 비교하여 같지 않으면 점프하는게 보인다.
내용이 비슷한게 있어보이니 하나하나 보기보단 조금 큰 흐름으로 봐보자.
세 번째 루틴이다. 마지막에 test eax, eax를 통해 틀렸는지 검사해 Incorrect로 점프하는 곳이 있다.
그 위를 보면
xor eax, eax를 톻해 eax레지스터의 값을 0으로 만들고 test실행문에 점프하는 곳이 있다.
앞전에도 알아낸 결과로 생각하면 xor을 통해 레지스터의 값을 0으로 만들고 test실행문을 거치면 equal이 나온다.
그럼 004010FE 식을 실행하면 된다. sbb연산을 통해 eax의 값을 0이 아닌 값으로 바꾸게 하면 안된다는 것이다.
sbb에 점프되는 위치들이
두 군데 있는 것을 볼 수 있다.
그리고 xor식 바로 위를 보면
jne문을 통해 다시 위로 점프하는 곳이 있는데, 점프된 위치가 다른 함수가 있는 곳이나 전혀 모르는 위치가 아닌 이 루틴의 시작 지점으로 간다.
그럼 dl과 bl을 반복적으로 검사하며 틀렸을 경우 eax에 연산을 가해 test에서 걸리게 만든 형식같다.
다시, 처음 이곳으로 와서
cl은 jne로 반복문의 조건을 담당하게 되는데, dl의 값을 복사해 카운터로 사용하고,
cl도 마찬가지로 test연산을 통해 0일 경우 점프하게 되어있다.
그럼 dl은 무슨 값을 가지고 있을까 하면
내가 입력한 값의 문자를 가지고 있다.
dl에 '1'이 들어가 있는 것을 볼 수 있다.
dl과 bl을 비교해 같지 않으면 틀린 연산 점프
test cl, cl의 값이 equal일 경우 맞는 연산 점프(dl과 bl이 같은데 NULL일 경우)
그리고 eax + 1의 값을 다시 dl에
esi + 1의 값을 다시 bl에 넣고
dl과 bl을 비교해 같지 않으면 틀린 연산 점프
test cl, cl의 값이 같지 않을 경우동안 반복
이런 순서로 진행되는 것을 볼 수 있다.
한 번 한 번 실행해 보는 것보단 크게 보며 분석을 통해 진행하는 편이 수월할 것 같다.
좀 더 깔끔히 정리해서
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 24 |
esi = "R3versing"
eax = "12345678"
dl = *eax;
bl = *esi;
do {
dl = *eax;
bl = *esi;
cl = dl;
if (dl != bl) goto L1;
dl = *(eax + 1);
bl = *(esi + 1);
cl = bl;
if (dl != bl) goto L1;
eax += 2;
esi += 2;
} while (cl != 0);
eax = 0;
goto Ret;
L1: //sbb 연산
Ret : return;
| cs |
그럼 이 루틴의 풀이법은 뭐냐, 하면 간단히 생각해서 그냥 두 문자열이 정확히 같으면 된다..는 것이다.
그리고 문자열이 뒤에 더 없어야 한다. 입력한 문자열이 NULL이 나올 때까지 반복하는데 입력한 문자열이 "R3versing"보다 길면 NULL과 내가 입력한 문자열을 비교할 때 틀리게 될 것이다.
다시 실행해 문자열을 정확히 똑같이 맞추고 실행시켜 보았다.
바이너리 수정 없이 빠르게 루틴을 클리어 한 것을 볼 수 있다.
마지막으로, 그 다음 실행문은
esp + 4와 'E'를 비교해 같지 않으면 틀렸다고 판단하는 조건문인데, esp + 4의 위치는 내가 입력한 문자열의 첫 번째 문자가 시작되는 위치이다.
다시말해, 첫 번째 문자가 'E'가 아니면 틀렸다고 본다.
이곳까지 지나고 나면 모든 루틴은 지나갔다. 맞았다는 MessageBox를 띄우고 프로그램을 종료한다.
세-네번째 루틴을 통하며 모든 루틴을 해석하면
루틴의 순서대로
1. 입력한 문자열의 두 번째 문자가 'a'여야 한다.
2. 입력한 문자열의 세 번째 문자부터 정확히 두 문자가 "5y"여야 한다,
3. 입력한 문자열의 다섯 번째 문자부터 정확히 문자열이 "R3versing"이어야 한다.
4. 입력한 문자열의 첫 번째 문자가 'E'여야 한다.
이를 통하여 플래그 값은 "Ea5yR3versing"인 것을 볼 수 있다.
댓글
댓글 쓰기