Abex’ Crackme #2
이번 crackme는 Visual Basic으로 작성되었다고 한다. VB는 MSVBVM60.dll이라는 VB 전용 엔진을 사용하며, 사용 예를 들어보면 메시지 박스를 출력할 때 MsgBox라는 함수를 호출해 그 함수 안에서 Win32 API인 user32.dll의 MessageBoxW 함수를 호출하는 형식이다. 물론 소스코드 내에서 user32.dll의 MessageBoxW 함수를 직접 호출하는 것도 가능하다.
VB는 주로 GUI 프로그래밍을 할 때 사용되며, IDE 인터페이스 자체도 GUI 프로그래밍에 최적화 되어있다. 이는 즉 VB 프로그램이 Windows 운영체제의 Event Driven 방식(사용자의 명령·마우스 클릭·다른 프로그램의 메시지·키보드 글쇠 입력 등의 ‘사건’에 따라, 제어 흐름이 결정되어 일을 하도록 하게끔 만들어진 방식)으로 동작하기 때문에, main 혹은 WinMain에 사용자 코드가 존재하는 것이 아니라 각 event handler에 사용자의 코드가 존재한다.
먼저 실행해서 어떤 프로그램인지 살펴본다.
그냥 뭐라도 입력해보면 다음과 같은 창이 뜬다.
틀렸다고 한다. 이름과 시리얼에 어떤 관계가 있는건지, 혹은 그냥 시리얼만 맞으면 되는건진 모르겠지만 어쨌든 맞으면 뭔가 다른 것을 뱉어주는 것 같다.
OllyDbg에 올려서 한 번 살펴보자. 먼저 우리한테 틀렸다고 알려주는 저 메시지 박스에 나오는 내용을 Search for All Strings에서 찾아 더블클릭해서 찾아가보자.
저기서 찾아 들어가보면 다음과 같은 코드를 볼 수 있다.
맞췄다고 보여주는 메시지 박스의 내용을 띄우는 코드인 것 같이 보이는 부분이 있다. vbaVarTstEq라는 함수의 결과값이 저장된 AX가 0인지 아닌지 판단하여, JE문을 통해 AX가 0일 경우 틀렸다는 메시지 박스의 내용을 띄우는 것 같다. 그렇다면 AX를 리턴으로 돌려주는 vbaVarTstEq라는 이름의 함수가 입력한 시리얼이 맞는지 틀린지 판단하는 것 같다는 것을 유추할 수 있다.
저 빨간색 박스 안을 잘 살펴보면 함수의 파라미터처럼 전달해주는 형태가 보인다. LEA 명령은 좌변(무조건 레지스터)에 우변의 주솟값을 대입하는 것이다. MOV와 비슷하지만 좌변에 우변(상수도 가능)의 값을 대입하는 MOV와는 주솟값을 대입한다는 점에서 약간 다르다. EDX와 EAX에 EBP-44 주소에 있는 값, EBP-34 주소에 있는 값을 각각 대입하고 있는데, 저것이 인자로 넘겨준 string이 아닐까 해서 스택에서 EBP 주변을 살펴보았다.
아니나 다를까, 입력했던 ‘BinZIP’ 문자열과 시리얼로 입력했던 ‘supernice’, 그 근처에 뭔가 알 수 없는 문자열이 있다. 위치상으로 저 문자열이 아마 시리얼인 것 같다. 옮겨 적고 입력해보았다.
그런데, 그냥 시리얼을 알아냈으니 다른 이름으로 해도 인증이 될까?
그냥 인증이 된다. 진짜 시리얼만 알아내도 되는건가 싶어서 그냥 한 글자를 덧붙이는 것이 아니라 문자열을 좀 많이(?) 바꾸어 넣어보았다.
아니나 다를까, Serial은 항상 똑같은 것이 아니었다. 그렇다는 것은 Name에 따라서 시리얼을 생성하는 함수가 있다는 얘기다. VB는 위에서 언급한 것처럼 프로그램 자체에 사용자의 코드가 있는 것이 아니라 이벤트가 일어남에 따라서 실행되는 Event Handler 안에 사용자의 코드가 존재한다. 그렇다는 것은 시리얼을 생성하는 함수는 Check 버튼을 누르는 Event에 실행되는 Event Handler 안에 사용자의 코드가 존재한다는 것이다. 또한 시리얼을 생성한 후 사용자가 입력한 시리얼과 비교해서 맞는지 틀렸는지 확인해 메시지 박스로 띄우는 함수 또한 이 Event Handler 안에 들어있을 것이다. 이는 우리가 찾았던 문자열을 비교하는 함수 위쪽에 시리얼을 생성하는 함수가 존재한다는 것으로 자연스럽게 유추된다.
아까 찾았던 코드에서 더 위로 올라가보자. 뭔가 익숙한 코드를 찾을 수 있다.
PUSH EBP와 MOV EBP ESP는 이전 Stack Frame을 공부할 때 함수의 시작에서 일반적으로 보이는 형태라고 공부 했었다. 이는 즉 여기가 함수의 시작이라는 것을 알 수 있게 해준다.
그러면 Serial Key를 생성하는 함수는 도대체 어떤 형태로 동작할까? Name에 따라서 Serial이 달라진다는 것을 확인했으니 아마도, 문자열을 받아와서 루프를 돌며 암호화를 한다던지 하는 행동을 할 것이다. 그럼 Name으로 입력해준 문자열을 읽는 부분을 찾아보기 위해, CALL 명령어와 ESI에 유의하며 코드를 살펴본다.
저 부분을 잘 보면 함수의 로컬 객체 SS:[EBP-88]의 주소를 파라미터로 전달하고 있다.
이렇게 도착한 곳에 무엇이 있는지 이렇게 봐서는 확인하기 어려우니, Long – Address with ASCII Dump 메뉴를 활용해 확인해본다.
위와 같이 BeenZIP이라는 Name에 입력했던 문자열이 정확히 EBP-88의 위치에 들어가 있는 것을 확인할 수 있다.
이제 반복문을 찾을 차례이다. EBX에 유의하며 내려가다 보면 아래와 같은 코드를 볼 수 있다.
위의 코드는 아래쪽 문자열을 보니 4글자 이상 입력하는지 체크하는 반복문인 것 같다. 더 내려가본다.
오른쪽에 디버거가 달아놓은 Comment를 참고해서 유추해보면 vbaVarForInit과 vbaVarForNext 사이에서 반복횟수만큼 한 글자씩 확인해가는 것 같다. EBX의 크기가 4이므로 4번째 글자까지 가져와서 확인하는 것 같은데, 그렇다면 아까 Name에 BinZIP과 BinZIPP을 넣었을 때 Serial이 같았던 것이 이해가 된다. 아마 이곳에서 Serial이 생성되는 것 같다.
그럼 이제 디버깅을 하면서 스택을 확인해보자.
레지스터에서도 EAX, ECX, EDX에 있는 주소를 확인할 수 있고 스택에 차례로 쌓여있는 것을 아래와 같이 확인할 수 있다. 각각의 주소로 찾아가보자.
EAX가 가리키는 주소의 값은 2, ECX가 가리키는 주소의 값은 0, EDX가 가리키는 주소의 값은 2이다. 무슨 의미인지 잘 모르겠지만, Step Over를 하면서 스택 창을 유심히 보자.
코멘트를 보면 UNICODE로 A6이 생성된 것을 볼 수 있다. 아까 우리는 한 글자씩 떼어와서 어떤 암호화 과정을 거칠 것이라고 유추했었다. 그렇다면, 우리가 Name에 입력했던 ‘Beenzip’의 맨 처음 글자 ‘B’와, A6은 무슨 관계가 있는걸까? 일단 다음 글자도 보기 위해 한번 더 루프문을 돌려보자.
두 번째로 생긴 문자는 C9이다. 그리고 우리가 입력한 문자열에서 두 번째 글자는 ‘e’이다. 한번 더 돌려보겠다.
세 번째로 생긴 문자 역시 C9이다. 우리가 입력한 문자열의 세 번째 문자 역시 ‘e’였다. 그리고 이 과정을 하는 중에, 18F424주소에서 아까 생성했던 유니코드 문자열을 이어 붙이고 있는 것을 확인했다. 같은 문자를 암호화시키면 같은 결과가 나오는 것을 확인 했으니, B와 e에서 각각 A6, C9가 튀어나왔다는 것에서 규칙을 찾아봐야 한다.
일단 B의 ASCII 코드 문자 번호는 십진법으로 66, 십육진법으로 42이다. 그리고 e의 번호는 각각 101, 65이다. 일반적으로 한 글자씩 가져와서 암호화하는 방법에는 이 번호에 더하거나 빼거나 곱하거나 나누는 연산을 주로 할 것이라고 예상해서 먼저 결과값에서 각각 이 번호를 빼봤다.
A6-42=64, C9-65=64. 이는 즉 암호화 하는 방법이 한 글자를 가져와 그 아스키 코드 값에 64를 더한 값을 UNICODE로 4번 이어 붙이는 것임을 알 수 있다.
이렇게 유추한 바로 BeenZIP이라는 문자열의 Serial 값은 A6C9C9D2일 것이라고 예상할 수 있다. 루프문을 모두 돌리고 메모리 상 18F424주소를 확인해보자.
유추한 내용이 맞았음을 알 수 있다. 그럼 마지막으로 얻어낸 문자열을 Serial에 넣고 확인해보자.
암호화 알고리즘은 Name에 입력받은 String에서 앞의 4글자를 가져와 그 ASCII 코드 값에 64를 더한 값을 UNICODE로 이어붙인 것이었음을 확인할 수 있었다.
'Reversing > Reversing' 카테고리의 다른 글
Lena's Reversing for Newbies #1 (0) | 2017.07.03 |
---|---|
Calling Convention (함수 호출 규약) (0) | 2017.07.02 |
Stack Frame (0) | 2017.06.27 |
Abex' Crackme #1 (0) | 2017.06.27 |
OllyDbg Commands & Assembly Basic & etc (0) | 2017.06.27 |