이 글은 코드엔진(http://codeengn.com/) 에서 제공하는 리버스 엔지니어링 관련 다양한 문제들을 풀어보면서 리버스 엔지니어링을 공부하는 목적으로 작성되었습니다. 이글을 작성하는 필자도 리버스 엔지니어링에 흥미를 가지고 공부하는 입장이므로 잘못된 내용이 있을수도 있습니다. 잘못된 내용이 있다면 댓글이나 방명록에 알려주세요 :)
Challenges : Basic 07
Author : abex
Korean :
컴퓨터 C 드라이브의 이름이 CodeEngn 일경우 시리얼이 생성될때 CodeEngn은 "어떤것"으로 변경되는가
English :
Assuming the drive name of C is CodeEngn, what does CodeEngn transform into in the process of the serial construction
문제를 확인했으니 프로그램을 다운받아 실행시켜보도록 하겠습니다. 실행해보니 보통의 시리얼 인증프로그램과 비슷해보입니다. 혹시나하고 임의의 값을 넣었으나 역시나 에러를 표시합니다.
프로그램을 실행해봤으니 이제 본격적인 분석을 위해 올리디버거를 이용해서 프로그램을 열어보겠습니다. 빠른분석을 위해서 Search For - All Referenced Text Strings 을 이용해서 시리얼과 연관되 있는 곳을찾아가 보도록 하겠습니다.
확인을 해보니 시리얼과 관련있어보이는것들이 눈에 들어옵니다. 그중 "4562-ABEX" 가위치한 곳으로 이동해보겠습니다. 이동을 해보니 아래와 같이 시리얼 관련 루틴을 볼수있습니다.
어떤식으로 작동하는지에 대해 알아보기위해 부분부분 나눠서 분석해보도록 하겠습니다.
- 0040106C ~ 00401078 (GetDlgItemText)
UINT WINAPI GetDlgItemText(
_In_ HWND hDlg,
_In_ int nIDDlgItem,
_Out_ LPTSTR lpString, /* 입력받은 텍스트를 저장하는 부분 */
_In_ int nMaxCount
);
대화상자에서 텍스트에 관한 정보를 얻는 함수인 GetDlgItemText 를 이용해서 사용자가 입력한 시리얼에 대한 정보를 얻고있는 부분입니다. 어셈블리어 코드를 통해서 보면 아래와 같이 입력되어있는것과 같습니다.
0040106C |
PUSH 25 |
Count = 25 (37.) |
nMaxCount |
0040106E |
PUSH 07.00402324 |
Buffer = 07.00402324 |
lpString |
00401073 |
PUSH 68 |
ControlID = 68 (104.) |
nIDDlgItem |
00401075 |
PUSH DWORD PTR SS:[EBP+8] |
hWnd |
hDlg |
00401078 |
CALL <JMP.&USER32.GetDlgItemTextA> |
GetDlgItemTextA |
GetDlgItemText |
즉, 우리가 시리얼입력칸에 입력한 값은 07.00402324 주소에 저장된다는것을 알수있습니다.
- 0040107D ~ 00401099 (GetVolumeInformationA)
다양한 정보가 입력되지만 우리가 주목할부분은 드라이브의 이름에 대한 부분이다. 여기서는 VolumeNameBuffer에 드라이브의 이름이 저장된다.
0040107D |
PUSH 0 |
pFileSystemNameSize = NULL |
nFileSystemNameSize |
0040107F |
PUSH 0 |
pFileSystemNameBuffer = NULL |
lpFileSystemNameBuffer |
00401081 |
PUSH 07.004020C8 |
pFileSystemFlags = 07.004020C8 |
lpFileSystemFlags |
00401086 |
PUSH 07.00402190 |
pMaxFilenameLength = 07.00402190 |
lpMaximumComponentLength |
0040108B |
PUSH 07.00402194 |
pVolumeSerialNumber = 07.00402194 |
lpVolumeSerialNumber |
00401090 |
PUSH 32 |
MaxVolumeNameSize = 32 (50.) |
nVolumeNameSize |
00401092 |
PUSH 07.0040225C |
VolumeNameBuffer = 07.0040225C |
lpVolumeNameBuffer |
00401097 |
PUSH 0 |
RootPathName = NULL |
lpRootPathName |
00401099 |
CALL 00401153 |
GetVolumeInformationA |
GetVolumeInformation |
즉, 우리가 찾는 드라이브의 이름은 0040225C 주소에 저장된다는것을 알수있습니다. 이를 이용해서 드라이브 이름을 변경할수 있게됬다.
0040109E ~ 004010A8 (lstrcat)
0040109E |
PUSH 07.004023F3 |
StringToAdd = "4562-ABEX" |
IpString2 |
004010A3 |
PUSH 07.0040225C (디스크 이름) |
ConcatString = "" |
IpString1 |
004010A8 |
CALL <JMP.&KERNEL32.IstrcatA> |
IstrcatA |
Istrcat |
- 004010AD ~ 004010CD (연산)
0040225C ~ 0040225F 값들을 간단한 어셈블리연산으로 변경시키고있다. 자세한 설명은 아래와 같다.
004010AD |
MOV DL,2 |
DL 의 값을 2로 설정한다. |
004010AF |
ADD DWORD PTR DS:[40225C],1 |
40225C 값에 1을 더한다. |
004010B6 |
ADD DWORD PTR DS:[40225D],1 |
40225D 값에 1을 더한다. |
004010BD |
ADD DWORD PTR DS:[40225E],1 |
40225E 값에 1을 더한다. |
004010C4 |
ADD DWORD PTR DS:[40225F],1 |
40225F 값에 1을 더한다. |
004010CB |
DEC DL |
DL 의 값에서 1을 뺸다. |
004010CD |
JNZ SHORT 07.004010AF |
DL의 값이 0인지검사하고 0이 아니면 004010AF로 점프한다. |
즉 0040225C (디스크 이름 저장 주소) 의 4자리 값들에 대해서 2씩 더해주는 연산을하고 있는것이다. 만약에 디스크이름이 Codeengn 이라면 Code 값이 2번 증가한 값 + "engn" 이 될것이다.
- 004010CF ~ 004010E8 (IstrcatA)
위에서 한번 살펴본 내용이므로 자세한 설명은 생략하겠습니다.
- 004010ED ~ 004010F7 (IstrcmpiA)
시리얼값을 얻었으니 확인을 위해서 입력을 해보도록 하겠습니다. 입력을 해보니 아래와 같이 인증에 성공하는것을 볼수있습니다.
'리버스 엔지니어링 > 코드엔진 문제풀이' 카테고리의 다른 글
코드 엔진 Challenges : Basic 09 (0) | 2014.08.13 |
---|---|
코드 엔진 Challenges : Basic 08 (1) | 2014.08.08 |
코드 엔진 Challenges : Basic 07 (0) | 2014.08.07 |
코드 엔진 Challenges : Basic 06 (1) | 2014.08.06 |
코드 엔진 Challenges : Basic 05 (0) | 2014.08.04 |
코드 엔진 Challenges : Basic 04 (0) | 2014.08.04 |
댓글을 달아 주세요