Log in

View Full Version : Project # 3 TASKS 1 & 2


Kayaker
November 20th, 2000, 14:48
TASK 1 - Set your system clock ahead to trigger an expiration nag.
a) Figure out how to change the install date info so the program still functions normally (at least for the next 30 days or so) WITHOUT patching the program.
b) Now patch the program so it will continue to operate (unregistered) indefinitely.

There are many API breakpoints that might, or might not, be successful with time checks. You could just try them all, or maybe use an API monitor to tell you which one(s) are being used. If not, you'll need another way to get to the relevant code. Filemon/Regmon should tell you where the install date info is kept, so you may need to use the corresponding breakpoints (i.e. CreateFileA / ReadFile for files and RegOpenKeyExA / RegQueryValueExA for the registry)

CompareFileTime
DosDateTimeToFileTime
FileTimeToDosDateTime
FileTimeToLocalFileTime
FileTimeToSystemTime
GetFileTime
GetLocalTime
GetSystemTime
GetSystemTimeAsFileTime
GetTimeZoneInformation
LocalFileTimeToFileTime
SystemTimeToFileTime


TASK 2 -
a) Determine where/how the program keeps its registration info.

Trace through the registration routine and register the program by
b) patching a jump or
c) determining a valid serial.
The 1st two projects have given the general techniques sufficient to do this.

d) After you've done b) or c) above, what happens? Trace through the code (F10) and determine what API calls are used and what they are doing.

mersenne
November 23rd, 2000, 21:14
Hi all,

I though I may as well get the ball rolling. here is some preliminary stuff and task 1.

Preliminary stuff
I installed the program with INCTRL 4 which monitors the installation and generates a report showing all files, registry keys and values added or changed during the installation. Useful for making sure you get rid of all of the program when you delete it and damn useful for this sort of work The following created in the registry is probably fishy considering we are looking at a time check:

HKEY_CURRENT_USER\Software\HappyIcon\startdate=01C0546F (29381503)

Note: the startdate value is created from your system clock when you install the program and will be different for each person. The value 29381503 is just the decimal conversion of 01C0546F.

SIDENOTE: If someone could show me how to convert this into a time and date eg 3rd Nov 2000 I would be grateful.

OK, I ran the program to find out what it did. Selecting "about" from the "Help" menu gives the following information:

Licence: Unregistered
Granted to: Unregistered

Selecting "register" from the same menu provides you with a dialog to enter:

Name:
Firstname:
Key:

If you set the system clock forward so that the expiration nag is displayed and then set the clock back to the correct time, you can use the program normally once again. This suggests that there is just a direct comparison with the date it was installed and the current date and nothing else is set.

Task 1
As was mentioned in the task list, set the system time so that the expiration nag appears. Time to look at the program.

Kayaker discussed a couple of the ways you could determine the right breakpoint to use. There is another simple method he did not mention. Get yourself a PE header browser (I use PEBrowse), open the program with it and check out the program's imports. There is only one API function that the program uses that will retrieve the system time; GetSytemTimeAsFileTime. If you set a breakpoint on that API function you will land here:


* Reference To: KERNEL32.GetSystemTimeAsFileTime, Ord:0176h
|
:00414C5A FF15E8004200 Call dword ptr [004200E8]
:00414C60 8B4C241C mov ecx, dword ptr [esp+1C] ;current filetime
:00414C64 8B542404 mov edx, dword ptr [esp+04] ;installed filetime
:00414C68 2BCA sub ecx, edx
:00414C6A 81F993170000 cmp ecx, 00001793
:00414C70 720A jb 00414C7C

If you note the values in ecx and edx after the MOV instructions you will see that one of them corresponds to the the startdate value we saw in the registry earlier, the other is the current system time/date. If you take the value in ecx and use this to replace the startdate value in the registry (Use regedit in the windoze directory, get to the key shown above, rightclick on the value and select modify, type in your new value) you can now use the program for the next 30 days or so.

To make the patch permanent so it will continue to run unregistered, it is a simple matter of changing

:00414C70 720A jb 00414C7C

to

:00414C70 EB0A jmp 00414C7C

which will cause the program to make the right jump regardless of what the result from the comparison is.

mersenne

Kayaker
November 24th, 2000, 16:02
Nice work Mersenne and thanks for a detailed response.

I don't think you can convert GetSystemTimeAsFileTime results as a regular date and time. According to its definition it returns information as Coordinated Universal Time (UTC) format in a FILETIME structure. The FILETIME structure is a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601. Don't know where the hell they come up with that one

If you trace into the Kernel32 call you can see system date info being PUSHed in certain registers (i.e. 7D0=2000, 0B=11=Nov), but they're only being used internally to calculate the UTC.


typedef struct _FILETIME { // ft
DWORD dwLowDateTime;
DWORD dwHighDateTime;
} FILETIME;

dwLowDateTime- Specifies the low-order 32 bits of the file time.
dwHighDateTime-Specifies the high-order 32 bits of the file time.


If you display the FILETIME structure address pointed to in the GetSystemTimeAsFileTime parameter you see the 2 DWORDS listed. It appears that the HighDateTime is the date and the LowDateTime is the time. The HighDateTime is the [esp+1C] value used in the CMP.



* Reference To: KERNEL32.GetSystemTimeAsFileTime, Ord:0176h
|
:00414C5A FF15E8004200 Call dword ptr [004200E8]
:00414C60 8B4C241C mov ecx, dword ptr [esp+1C]
:00414C64 8B542404 mov edx, dword ptr [esp+04]
:00414C68 2BCA sub ecx, edx
:00414C6A 81F993170000 cmp ecx, 00001793
:00414C70 720A jb 00414C7C

Just for fun here's a few other ways you could patch to force the cmp to be valid:

change
:00414C64 8B542404 mov edx, dword ptr [esp+04]
to
:00414C64 8B4C241C mov edx, dword ptr [esp+1C]

:00414C68 2BCA sub ecx, edx
to
:00414C68 2BC9 sub ecx, ecx

or
:00414C68 2BCA sub ecx, edx
to
:00414C68 33C9 xor ecx, ecx

Regards

ThRaX
November 26th, 2000, 00:08
mhmm...Alright, just finished task 1, same general idea as what mersenne posted. As far as task 2 goes, however I did both B and C....Using a very simple breakpoint (GetDlgItemTextA), I was able to locate and patch *the* conditional jump, and i was registered (actually crazy as it is, I didnt even ahve to patch lol I Just did 'r fl z' in sice and i was registered for good, lol), as well as *fish* out a correct serial within just a few lines of this critical jump.

mersenne
November 27th, 2000, 00:42
Please ignore all the ' marks, I had to try and stop those emoticons from being posted everywhere. Also if someone knows how to format the code stuff better, PLEASE let me know. The pre and fixed tags don't work so well.

Here we go with task 2

Considering that everytime you try to register the program you have to re-enter all the details, suggests that the program is not keeping any information entered (at this stage). There is nothing written to the registry or file.

To patch a jump or determine a valid serial, we first need to break into the code to figure out what the program is doing. The program needs to get the information we enter into the registration dialog so lets begin there. There are a number of API functions which the program can use to do this. Looking at the list of imports again you will see that it is most likely GetDlgItemTextA. Set this breakpoint and then enter the information requested in the registration dialog. For the purposes of this project I entered the following:

Name: copy
First name: pirate
Key: 12344321

Hit the OK button and you will break at this function. The program actually calls this function three times in a row to get the name, followed by the first name and then the key so if you are using Softice you can press ctrl D after the first and second calls to get you to the third one. Press F11 and you will be in the program code. Alternatively you can trace through the code after you break the first time. After the final call you will end up here:
Code:

* Reference To: USER32.wsprintfA, Ord:02B3h
|
:00414079 8B1DF4024200 mov ebx, dword ptr [004202F4]
:0041407F 8D542414 lea edx, dword ptr [esp+14] ;address of name in edx
:00414083 52 push edx ;'push "copy"
:00414084 8D44246C lea eax, dword ptr [esp+6C] ;address of first name in eax

* Possible StringData Ref from Data Obj ->"HappyIcon"
|
:00414088 6878214200 push 00422178 ;'push "HappyIcon"
:0041408D 50 push eax ;'push "pirate"
:0041408E 8D8C24A0050000 lea ecx, dword ptr [esp+000005A0];'destination address

* Possible StringData Ref from Data Obj ->"%s%s%s"
|
:00414095 68B4484200 push 004248B4 ;format string
:0041409A 51 push ecx ;'push destination address
:0041409B FFD3 call ebx ;call wsprintfA


This bit of code takes our name, first name and the string "HappyIcon" and concatenates (links) them. The result is that at the destination address you will see "pirateHappyIconcopy" for this example. For imformation about the format string used check out the API reference.

Code:

:0041409D 8DBC24A8050000 lea edi, dword ptr [esp+000005A8];address of our new string
:004140A4 83C9FF or ecx, FFFFFFFF
:004140A7 33C0 xor eax, eax
:004140A9 83C414 add esp, 00000014
:004140AC F2 repnz
:004140AD AE scasb
:004140AE F7D1 not ecx ;length of string including 00
;termination byte now in ecx

The program now calculates the length of this string. During this time edi is incremented so that after the scasb instruction edi will point to the end of the string. The following corrects edi so that it points to the beginning of the string once more.

see part 2................

mersenne
November 27th, 2000, 00:46
Code:

:004140B0 2BF9 sub edi, ecx


:004140B2 8D942490010000 lea edx, dword ptr [esp+00000190];new address for string
:004140B9 8BC1 mov eax, ecx
:004140BB 8BF7 mov esi, edi
:004140BD 8BFA mov edi, edx
:004140BF C1E902 shr ecx, 02 ;converts length to dwords
:004140C2 F3 repz
:004140C3 A5 movsd ;move the string
:004140C4 8BC8 mov ecx, eax ;string length back into ecx
:004140C6 8D842490010000 lea eax, dword ptr [esp+00000190] ;address of string
:004140CD 83E103 and ecx, 00000003
:004140D0 F3 repz
:004140D1 A4 movsb
:004140D2 8A8C2490010000 mov cl, byte ptr [esp+00000190] ;first character of our string
:004140D9 84C9 test cl, cl ;Is it zero?
:004140DB 741F je 004140FC ;if yes, jump

The string gets moved to a different address and now the fun begins
Code:

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004140FA(C)
|
:004140DD 80385F cmp byte ptr [eax], 5F
:004140E0 7503 jne 004140E5
:004140E2 C60020 mov byte ptr [eax], 20

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004140E0(C)
|
:004140E5 0FBE08 movsx ecx, byte ptr [eax] ;move character into ecx
:004140E8 334C2410 xor ecx, dword ptr [esp+10] ;xor with value in [esp+10]
:004140EC 81F1CE9A5713 xor ecx, 13579ACE ;xor with 13579ACE
:004140F2 40 inc eax ;move pointer to next char
:004140F3 894C2410 mov dword ptr [esp+10], ecx ;'put new value in [esp+10]
:004140F7 803800 cmp byte ptr [eax], 00 ;is our next char=0?
:004140FA 75E1 jne 004140DD ;if no, jump up

This is the major loop of our serial calculating routine. It cycles through the string one character at a time, checks to see if the character is 5F ("_" and if yes, replaces it with 20h (space character). The charcter is then XORed with what is at address [ESP+10]. The starting value in [ESP+10] is FFFFFFFF. This value is then XORed by 13579ACE and stored back in [ESP+10]. The pointer to our string is moved to the next character which is checked to see if it is zero (the end of the string). If it is not zero the loop repeats.

Code:

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004140DB(C)
|
:004140FC 8D9424BC000000 lea edx, dword ptr [esp+000000BC] ;the key we entered
:00414103 52 push edx
:00414104 E873220000 call 0041637C ;the key converted to hex
:00414109 8B4C2414 mov ecx, dword ptr [esp+14] ;our calculated value
:0041410D 83C404 add esp, 00000004
:00414110 81F1F0BD6824 xor ecx, 2468BDF0 ;xor with 2468BDF0
:00414116 3BC1 cmp eax, ecx ;compare the values
:00414118 742E je 00414148 ;if the same, please continue

mersenne
November 27th, 2000, 00:47
The key we entered is converted to hex. The value from the loop above is then XORed with 2468BDF0. Note that after this instruction, ecx contains our correct serial IN HEXIDECIMAL for the name we entered. For pirate copy it is C8C0D8A4. To get the correct key to enter in the registration screen all we need do is covert it back to decimal viz -926885724. The jmp directly after the compare is where the program decides who gets registered and who get the "Invalid registration" message. If we wish we could change

:00414118 742E je 00414148

to

:00414118 EB2E jmp 00414148

to permanently patch the program. There are also other ways to patch this, as Kayaker mentioned in a post above.

After the program is successfully registered, the file HappyIcon.lic is created in the same directory that Happy Icon is installed in. The unregistered string disappears from the main window title and the about menu item now has the registration information entered as does the register menu item but now all the edit boxes have been greyed.

mersenne

mersenne
November 27th, 2000, 00:49
Groan.....

Remind me not to use code tags either, they take up too many characters! Found out a little too late.

Sorry about the split posts

mersenne

()whore
November 27th, 2000, 22:29
Well I haven't seen anything here yet about the happyicon.lic file so I will mention it. After the prog decides the user typed in a valid reg number, it creates the .lic file with your registration info. Most programs will check the reg info every time on start up to make sure it is valid but not in this case. If you pass the original check you are reged for life it seams. There is a checksum number in the *.lic file. I haven't traced through the CRC routine but if I have time I will look at it.
Thanks for the interesting project. The target is damn easy to crack but untill now I never bothered to follow all the api calls and see what was going on in a program. Normaly I was just interested in getting it reged. This is a bit more interesting.