Lena's Reversing for Newbie 17 Write-Up
파일 링크: https://tuts4you.com/e107_plugins/download/download.php?list.17
Downloads / Lenas Reversing for Newbies - Tuts 4 You
tuts4you.com
Tutorials Index: 17. Insights and practice in basic (self)keygenning
사용도구: 올리디버거 2.01
Lena's Reversing for Newbie 17(이하 원본파일) 분석해보자.
17단계는 분석할 파일이 2개이다.
1. KeygenMe
2. KeygenMe.Keygen
분석해본 결과 두 파일 모두 시리얼을 만드는 알고리즘은 같다. 위 파일들을 패치할 수 있는 방법은 다음과 같다.
1. 분기 명령어나 인라인 패치를 통해 올바르지 않은 시리얼을 입력하더라도 성공 메시지 박스를 띄우는 방법
2. 시리얼을 만드는 알고리즘을 보고 시리얼을 직접 계산하여 맞추는 방법
두 번째 방법으로 풀면 두 파일 모두 풀리기 때문에 첫 번째 파일에 대한 분석 내용만 쓰겠다.

프로그램을 실행하면 메인 화면은 위와 같다.

About 버튼을 클릭하면 운을 빌어준다.

아무것도 입력하지 않고 Check 버튼을 클릭하면 위와 같다.

실패했을 때의 메시지는 위와 같은데 디버거를 하드에서 지우라고 한다. 안티디버깅 기법을 쓰는지 확인해야 한다.

올리디버거로 프로그램을 실행한 뒤, code 섹션에서 우클릭 - Search for - All referenced strings 기능을 클릭하면 위와 같이 사용되는 문자열들을 확인할 수 있다. 위와 같이 실패했을 때 디버거를 하드에서 지우라는 메시지를 확인할 수 있다. 해당 주소를 살펴보자.

일단 안티디버깅 기법을 사용하는 것은 아니다. 단지 메시지로 디버거를 하드에서 지우라고 하는 것이다. 그리고 0x004012FB 주소에서 lstrlen 함수를 호출하여 첫 번째 입력 값의 길이를 리턴해준다. EAX 레지스터의 값을 보면 0x4 값임을 알 수 있다.
RETN 명령어 밑으로 빈 공간이 있기 때문에 인라인 패치를 하거나 분기 명령어를 패치하면 "That's righet ~~" 문자열이 출력되도록 할 수 있지만 여기선 시리얼 알고리즘을 분석하여 올바른 시리얼을 찾아보자.

먼저 0x0040133C 주소의 JNE 명령어에 의해서 실패 메시지를 보여주는 메시지 박스 함수로 점프한다. JNE 명령어 직전에 CMP 명령어를 통해 ESI 레지스터의 값과 0x00403138 주소의 메모리 값을 비교하여 같은지 검사한다. 같지 않으면 0x00401353 주소로 점프하여 실패하는 것이다. 0x00403138 주소의 메모리 값을 보면 두 번째 입력한 값임을 알 수 있다.
시리얼을 만드는 과정은 다음과 같다. 0x004012FB 주소의 lstrlen 함수를 통해 첫 번째 입력 값의 길이를 반환받고 ESI 레지스터를 0x0으로 만든다. 그리고 ECX 레지스터에 반환 받은 값을 저장한다. 그리고 EAX 레지스터의 값을 0x1로 저장한다. 이제 반복 루틴이 실행되는데 상세 내용은 다음과 같다.
1. 0x00401309 / MOV EDX,DWORD PTR DS:[403038]
0x00403038 주소의 메모리 값을 EDX 레지스터에 저장한다. 0x00403038 주소에는 첫 번째 입력 값이 저장되어 있다.
2. 0x0040130F / MOV DL,BYTE PTR DS:[EAX+403037]
0x00403037 주소로부터 EAX 레지스터의 값만큼 더한 값을 DL 레지스터에 저장하는데, 초기 EAX 레지스터의 값은 0x1 값이고 0x00403037 주소는 첫 번째 입력 값보다 1byte 작은 곳이다. 따라서 첫 번째 입력 값의 첫 번째 값이 DL 레지스터에 저장될 것이다.
3. 0x00401315 / AND EDX,000000FF
EDX 레지스터와 0x000000FF 값을 AND 연산하면 DL 레지스터의 값만 유지되고 나머지는 0x0 값으로 바뀐다.
4. 0x0040131B / MOV EBX,EDX
EDX 레지스터의 값을 EBX 레지스터에 복사한다.
5. 0x0040131D / IMUL EBX,EDX
EBX 레지스터의 값과 EDX 레지스터의 값을 곱하여 EBX 레지스터의 저장한다.
6. 0x00401320 / ADD ESI,EBX
ESI 레지스터에 EBX 레지스터의 값을 더한다.
7. 0x00401322 / MOV EBX,EDX
EDX 레지스터의 값을 EBX 레지스터에 복사한다.
8. 0x00401324 / SAR EBX,1
EBX 레지스터의 값을 오른쪽으로 1bit 시프트한다.
9. 0x00401326 / ADD EBX,3
EBX 레지스터의 값에 0x3 값을 더한다.
10. 0x00401329 / IMUL EBX,EDX
EBX 레지스터의 값과 EDX 레지스터의 값을 곱하여 EBX 레지스터의 저장한다.
11. 0x0040132C / SUB EBX,EDX
EBX 레지스터의 값과 EDX 레지스터의 값의 차를 EBX 레지스터에 저장한다.
12. 0x0040132E / ADD ESI,ESI
ESI 레지스터 값을 ESI 레지스터에 더한다. 즉, 두배가 된다.
13. 0x00401332 / INC EAX
EAX 레지스터의 값을 1 증가시킨다.
14. 0x00401333 / DEC ECX
ECX 레지스터의 값을 1 감소시킨다.
15. 0x00401334 / JNZ SHORT 00401309
ECX 레지스터의 값이 0x0 값이 아니면 0x00401309 주소로 점프한다.
위 루틴을 정리해보면 첫 번째 입력 값의 길이 만큼 루틴이 동작한다. 그리고 1byte씩 계산을 하는데, EBX, EDX 레지스터를 계산하는데 사용하고 ESI 레지스터에 최종 값을 누적하여 저장한다.
따라서 "seok" 문자열을 첫 번째 입력 값으로 입력했기 때문에 루틴은 4번 반복하고 각 문자들의 값이 ESI 레지스터에 누적되어 저장된다.
그리고 이 누적된 값과 두 번째 값을 비교하여 같으면 성공하는 것이다.

"seok" 문자열이 루틴을 마치고나면 ESI 레지스터에는 0x00087054 값이 저장된다. 그리고 0x34333231 값과 비교하는데 이 값은 두 번째 입력 값을 16진수로 변환하고 빅앤디언으로 나타낸 것이다.
따라서 ESI 레지스터의 값을 빅앤디언으로 바꾸고 ASCII 값을 두 번째 입력 값으로 넣어주면 된다.
0x00087054 => 54 70 08 => Tp

위와 같이 첫 번째 입력 값에 의해 만들어진 시리얼을 올바르게 입력하면 성공할 수 있다.
'Wargame > Lena’s Reversing for Newbies' 카테고리의 다른 글
| Lena's Reversing for Newbie 19 Write-Up (0) | 2019.08.09 |
|---|---|
| Lena's Reversing for Newbie 18 Write-Up (0) | 2019.08.09 |
| Lena's Reversing for Newbie 16 Write-Up (0) | 2019.08.08 |
| Lena's Reversing for Newbie 15 Write-Up (0) | 2019.08.07 |
| Lena's Reversing for Newbie 14 Write-Up (0) | 2019.08.07 |