맨위로

이 글은 코드엔진(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)

BOOL WINAPI GetVolumeInformation(
  _In_opt_   LPCTSTR lpRootPathName,
  _Out_opt_  LPTSTR lpVolumeNameBuffer,          
 /* 이름을 저장하는 버퍼 */
  _In_       DWORD nVolumeNameSize,
  _Out_opt_  LPDWORD lpVolumeSerialNumber,
  _Out_opt_  LPDWORD lpMaximumComponentLength,
  _Out_opt_  LPDWORD lpFileSystemFlags,
  _Out_opt_  LPTSTR lpFileSystemNameBuffer,    
  _In_       DWORD nFileSystemNameSize
);

지정된 루트 디렉터리에 관한 시스템 볼륨 정보를 얻는 함수인 GetVolumeInformation 를 이용해서 볼륨 정보를 얻고 있는부분입니다. 

다양한 정보가 입력되지만 우리가 주목할부분은 드라이브의 이름에 대한 부분이다. 여기서는 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)


LPTSTR WINAPI lstrcat(
  _Inout_  LPTSTR lpString1,                /* ConcatString */
  _In_     LPTSTR lpString2                  /* StringToAdd  */                        
);

lpString1(ConcatString) + lpString2(StringToAdd) 값을 반환하는 함수입니다. 어셈블리 코드를 통해서 보면 아래와 같습니다.

 0040109E

 PUSH 07.004023F3

 StringToAdd = "4562-ABEX"

 IpString2

 004010A3

 PUSH 07.0040225C (디스크 이름)

 ConcatString = ""

 IpString1

 004010A8

 CALL <JMP.&KERNEL32.IstrcatA>

 IstrcatA

 Istrcat

위의 같은 경우는 "" + "4562-ABEX" 값인 "4562-ABEX"를 반환하여 0040225C 에 저장한다.


  • 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)



"L2C - 5781" 과 위에서 2씩 증가연산을 실행한 "6784-ABEX" 값을 더해서 00402000 주소에 반환하고있다.

위에서 한번 살펴본 내용이므로 자세한 설명은 생략하겠습니다.



  • 004010ED ~ 004010F7 (IstrcmpiA)


00402324 (입력값) 과 00402000 위의 과정을 거쳐서 얻은 시리얼 값(L2C-57816784-ABEX)을 Istrcmpi 함수를 이용해서 비교하고있다.

Istrcmpi 함수는 비교값이 같으면 0을 반환하므로 JE 문을 이용해서 메시지를 띄우게 됩니다.


시리얼값을 얻었으니 확인을 위해서 입력을 해보도록 하겠습니다. 입력을 해보니 아래와 같이 인증에 성공하는것을 볼수있습니다.


Posted by STIH

댓글을 달아 주세요