[CodeEngn Basic 7] WHAT ABOUT THE CHANGE BY 'CodeEngn'

2017. 8. 20. 05:240x02 Reverse Engineer/0x01. CodeEngn

728x90

문제 : Assuming the drive name of C is CodeEngn, what does CodeEngn transform into in the process of the serial construction 


바이너리 실행:


 

 [그림 1] 이놈도 시리얼 입력 문제 


틀린 값을 넣었을 때


 

 [그림 2] 틀린 값 넣었을 때



프로그램을 뜯어봅시다. 


0040107D  |.  6A 00         push 0x0                                 ; /pFileSystemNameSize = NULL

0040107F  |.  6A 00         push 0x0                                 ; |pFileSystemNameBuffer = NULL

00401081  |.  68 C8204000   push 07.004020C8                         ; |pFileSystemFlags = 07.004020C8

00401086  |.  68 90214000   push 07.00402190                         ; |pMaxFilenameLength = 07.00402190

0040108B  |.  68 94214000   push 07.00402194                         ; |pVolumeSerialNumber = 07.00402194

00401090  |.  6A 32         push 0x32                                ; |MaxVolumeNameSize = 32 (50.)

00401092  |.  68 5C224000   push 07.0040225C                         ; |VolumeNameBuffer = 07.0040225C

00401097  |.  6A 00         push 0x0                                 ; |RootPathName = NULL

00401099  |.  E8 B5000000   call <jmp.&KERNEL32.GetVolumeInformation>; \GetVolumeInformationA

0040109E  |.  68 F3234000   push 07.004023F3                         ; /StringToAdd = "4562-ABEX"

004010A3  |.  68 5C224000   push 07.0040225C                         ; |ConcatString = ""

004010A8  |.  E8 94000000   call <jmp.&KERNEL32.lstrcatA>            ; \lstrcatA


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

);


Parameters


lpRootPathName [in, optional]

A pointer to a string that contains the root directory of the volume to be described.

If this parameter is NULL, the root of the current directory is used. A trailing backslash is required. For example, you specify \\MyServer\MyShare as "\\MyServer\MyShare\", or the C drive as "C:\".


lpVolumeNameBuffer [out, optional]

A pointer to a buffer that receives the name of a specified volume. The buffer size is specified by the nVolumeNameSize parameter.

nVolumeNameSize [in]

The length of a volume name buffer, in TCHARs. The maximum buffer size is MAX_PATH+1.

This parameter is ignored if the volume name buffer is not supplied.


lpVolumeSerialNumber [out, optional]

A pointer to a variable that receives the volume serial number.

This parameter can be NULL if the serial number is not required.

This function returns the volume serial number that the operating system assigns when a hard disk is formatted. To programmatically obtain the hard disk's serial number that the manufacturer assigns, use the Windows Management Instrumentation (WMI) Win32_PhysicalMedia property SerialNumber.


lpMaximumComponentLength [out, optional]

A pointer to a variable that receives the maximum length, in TCHARs, of a file name component that a specified file system supports.

A file name component is the portion of a file name between backslashes.

The value that is stored in the variable that *lpMaximumComponentLength points to is used to indicate that a specified file system supports long names. For example, for a FAT file system that supports long names, the function stores the value 255, rather than the previous 8.3 indicator. Long names can also be supported on systems that use the NTFS file system.


lpFileSystemFlags [out, optional]

A pointer to a variable that receives flags associated with the specified file system.

This parameter can be one or more of the following flags. However, FILE_FILE_COMPRESSION and FILE_VOL_IS_COMPRESSED are mutually exclusive.


유심히 보아야 하는 파라미터는 lpRootPathName, 이놈인 것 같다.


RootPathName을 CodeEngn으로 바꾸어 보자.


 

 [그림 3] 문제에서 의도한 대로 드라이브 이름을 변경해봄 


0040109E  |.  68 F3234000   push 07.004023F3                         ; /StringToAdd = "4562-ABEX"

004010A3  |.  68 5C224000   push 07.0040225C                         ; |ConcatString = "6784-ABEX"

004010A8  |.  E8 94000000   call <jmp.&KERNEL32.lstrcatA>            ; \lstrcatA


strcat은 문자열을 이어주는 역할을 한다.


4562-ABEX 에서 다음의 루틴을 만나면서 [0]~[3]까지의 배열 값이 +1 된다.

004010AF  |> /8305 5C224000>/add dword ptr [0x40225C],0x1

004010B6  |. |8305 5D224000>|add dword ptr [0x40225D],0x1

004010BD  |. |8305 5E224000>|add dword ptr [0x40225E],0x1

004010C4  |. |8305 5F224000>|add dword ptr [0x40225F],0x1

004010CB  |. |FECA          |dec dl

004010CD  |.^\75 E0         \jnz short 07.004010AF






004010CF  |.  68 FD234000   push 07.004023FD                         ; /StringToAdd = "L2C-5781"

004010D4  |.  68 00204000   push 07.00402000                         ; |ConcatString = ""

004010D9  |.  E8 63000000   call <jmp.&KERNEL32.lstrcatA>            ; \lstrcatA

004010DE  |.  68 5C224000   push 07.0040225C                         ; /StringToAdd = "6784-ABEX"

004010E3  |.  68 00204000   push 07.00402000                         ; |ConcatString = ""

004010E8  |.  E8 54000000   call <jmp.&KERNEL32.lstrcatA>            ; \lstrcatA

004010ED  |.  68 24234000   push 07.00402324                         ; /String2 = "CodeEngn"

004010F2  |.  68 00204000   push 07.00402000                         ; |String1 = ""

004010F7  |.  E8 51000000   call <jmp.&KERNEL32.lstrcmpiA>           ; \lstrcmpiA

004010FC  |.  83F8 00       cmp eax,0x0


004010ED  |.  68 24234000   push 07.00402324                         ; /String2 = "CodeEngn"

004010F2  |.  68 00204000   push 07.00402000                         ; |String1 = "L2C-57816784-ABEX"

004010F7  |.  E8 51000000   call <jmp.&KERNEL32.lstrcmpiA>           ; \lstrcmpiA

내가 시리얼에 입력한 CodeEngn과 L2C-57816784-ABEX를 비교한다. 


004010FC  |.  83F8 00       cmp eax,0x0

004010FF  |.  74 16         je short 07.00401117

지금은 당연히 다르니까 에러가 뜬다.


우선, 시리얼을 L2C-57816784-ABEX 이걸로 다시 해보자.



004010ED  |.  68 24234000   push 07.00402324                         ; /String2 = "L2C-57816784-ABEX"

004010F2  |.  68 00204000   push 07.00402000                         ; |String1 = "L2C-57816784-ABEX"

004010F7  |.  E8 51000000   call <jmp.&KERNEL32.lstrcmpiA>           ; \lstrcmpiA

004010FC  |.  83F8 00       cmp eax,0x0


시리얼은 올바르게 나왔다. 


근데, 문제는 시리얼만 찾는 것이 아니다..


00401117  |> \6A 00         push 0x0                                 ; /Style = MB_OK|MB_APPLMODAL

00401119  |.  68 06244000   push 07.00402406                         ; |Title = "Well Done!"

0040111E  |.  68 11244000   push 07.00402411                         ; |Text = "Yep, you entered a correct serial!"

00401123  |.  FF75 08       push [arg.1]                             ; |hOwner

00401126  |.  E8 40000000   call <jmp.&USER32.MessageBoxA>           ; \MessageBoxA


 

 [그림 4] 크랙은 성공했다. 


문제를 한번 더 곱씹어 보면, 드라이버 명이 CodeEngn일 때 CodeEngn은 어떤 것으로 변경되는지를 찾아야 한다. 


정확하게 패치가 안됬을 수도 있으니, 패치 파일을 저장하고 패치파일을 실행해보았다.


파라미터 값을 바꾸어도 적용이 되지 않았다. 그렇다면 , 직접 C드라이버의 이름을 변경해보자. 


 

 [그림 5] 직접 드라이버 명을 바꿈


이번엔 루틴에서 값의 변함이 있을까?


0040109E  |.  68 F3234000   push 07.004023F3                         ; /StringToAdd = "4562-ABEX"

004010A3  |.  68 5C224000   push 07.0040225C                         ; |ConcatString = "CodeEngn"

004010A8  |.  E8 94000000   call <jmp.&KERNEL32.lstrcatA>            ; \lstrcatA


ConatString에 CodeEngn이 들어갔다. 


0040109E  |.  68 F3234000   push 07.004023F3                         ; /StringToAdd = "4562-ABEX"

004010A3  |.  68 5C224000   push 07.0040225C                         ; |ConcatString = "CodeEngn4562-ABEX"

004010A8  |.  E8 94000000   call <jmp.&KERNEL32.lstrcatA>            ; \lstrcatA


아까 처럼 [0]~[3] 루틴을 보자.


0040109E  |.  68 F3234000   push 07.004023F3                         ; /StringToAdd = "4562-ABEX"

004010A3  |.  68 5C224000   push 07.0040225C                         ; |ConcatString = "EqfgEngn4562-ABEX"

004010A8  |.  E8 94000000   call <jmp.&KERNEL32.lstrcatA>            ; \lstrcatA

004010AD  |.  B2 02         mov dl,0x2

004010AF  |>  8305 5C224000>/add dword ptr [0x40225C],0x1

004010B6  |.  8305 5D224000>|add dword ptr [0x40225D],0x1

004010BD  |.  8305 5E224000>|add dword ptr [0x40225E],0x1

004010C4  |.  8305 5F224000>|add dword ptr [0x40225F],0x1

004010CB  |.  FECA          |dec dl

004010CD  |.^ 75 E0         \jnz short 07.004010AF


 

 CodeEngn -> EqfgEngn 로 바꼈다 



004010ED  |.  68 24234000   push 07.00402324                         ; /String2 = "L2C-57816784-ABEX"

004010F2  |.  68 00204000   push 07.00402000                         ; |String1 = "L2C-5781EqfgEngn4562-ABEX"

004010F7  |.  E8 51000000   call <jmp.&KERNEL32.lstrcmpiA>           ; \lstrcmpiA


드라이버 명이 바뀌면서 시리얼 값도 바뀌게 되었다. 


다시, 바뀐 시리얼 값으로 재 실행 하자 .


004010ED  |.  68 24234000   push 07.00402324                         ; /String2 = "L2C-5781EqfgEngn4562-ABEX"

004010F2  |.  68 00204000   push 07.00402000                         ; |String1 = "L2C-5781EqfgEngn4562-ABEX"

004010F7  |.  E8 51000000   call <jmp.&KERNEL32.lstrcmpiA>           ; \lstrcmpiA

004010FC  |.  83F8 00       cmp eax,0x0

004010FF  |.  74 16         je short 07.00401117


 

 [그림 6] 성공 !! NICE ! 


플래그는 미 공개합니다.