Posted by hobgoblin on 1/16/2000, 4:21 pm
130.67.48.134
Task 2.1
First task is to remove nag screen at opening. OK. I opened the Softice loader and ran the program in there. After tracing through the code for a short while, I found this code:
:00447027 84DB test bl, bl
:00447029 0F84C1020000 je 004472F0
I basically followed the calls, and every time the nag showed up, I entered the call that brought up the nag to see if there possible was any conditional jumps that could be reversed. And that’s what I did. When I changed the instruction at 00447029 to 0F85C1020000, the nag screen didn’t show any more at start up. This isn’t exactly the most elegant way to find it, but it works.
Task 2.2
After pushing my system clock way ahead, I got the messagebox stating that the evaluation period is over.After loading the program in W32dasm, I searched for the text-string displayed in the messagebox. I found it at the address 00446E8A. A few lines above I saw a call to 00446BBC. I put a bpx in Softice at 00446E70, and when Softice broke after I fired up the program, I forced the program to jump at the conditional jump instruction at 00446E78. It ran as if I was within the evaluation period. That means if the call to 446BBC returns the value 1 in the al (lower) part of the eax register, the program jumps. By checking the call, I found out some interesting things: The call checks the register for values stored in C, General, Cross and Reverb. This call makes another call to the api function GetSystemTimeAsFileTime. And this routine is only called from one place in the program. That means it can probably be patched without any spesific problems. By checking this routine step by step I found that at 00446C72 the value stored in eax is the number of days I have used, and this value is moved into ecx. At 00446C7A this value is compared with the hex value 1E, which is 30 in decimal. If the value in exc is greater or equal to 1E, the value of al is set to 0 in the next instruction. If the value is less than 30, the al value is set to 1.
So, to patch the program to never expire I changed
:00446C7D 0F9EC0 setle al
to
:00446C7D B001 mov al, 01
:00446C7F 90 nop
Task 2.3
The code routine that starts at 00446A74 checks the register for information stored there; informations as name, company and key. During the execution of the first part of this routine, there are three calls made to 00413B98. These three calls eventually leads to a RegQueryValueExA call, which checks the register for name, company and key. The obtained information that’s stored here is brought on, out of the RegQueryValueExA call, and out of the call made to 00446A74. One of the calls to the routine that starts at 00446A74, starts here:
:00446774 E8FB020000 call 00446A74
:00446779 59 pop ecx
:0044677A 84C0 test al, al
:0044677C 0F85E6000000 jne 00446868
:00446782 66C785FCFDFFFF0800 mov word ptr [ebp+FFFFFDFC], 0008* Possible StringData Ref from Data Obj ->"Unregistered"
|
:0044678B 681E9F4900 push 00499F1E
:00446790 83C4FC add esp, FFFFFFFC
If the program is unregistered, it will not jump at 0044677C, and Unregistered is written into the about box. If the program is registered, it will jump here, and continue to write whatever info it finds in the register into the about box. The best way to patch this? See my comments under task 2.5
Task 2.4
OK. Serial – time. I checked the disassembled body for the textstring that occurs when I enter the right and the fake serial. There are two places where this text is displayed, and just a few lines above there is a call to 00446A74. The routine that starts here is called four times. Two of them deals with serial checking, one is dealing with whether the word “Unregistered” is to be displayed and the last one deals with whether the Expired message is to be displayed or not. When I checked out the routine I saw the call to the function lstrcmpA. That function is used to compare entered text/digits. So I put a bpx on 00446B91, just to get Softice to break some lines above the call to lstrcmpA. I wanted to check out to see whether I could see the values that were going to be compared. (BTW, a few lines above I saw that the word AC200- was pushed into the call I bpx’d. Maybe the program checks to see whether this is a part of the entered serial). I was right. When Softice broke, I checked what was pushed into edx at 00446B99, that was my fake serial. When I checked what was pushed into ecx at 00446BA0 I found the serial AC200-52586, which I believe is the correct serial (name=Unregistered, company=Unregistered]
Task 2.5
Now, this is the most interesting part IMHO. How do I patch the program so it’s fully functional, and at the same time use as few bytes as possible when patching it? Look at this code::00446B85 68A39F4900 push 00499FA3
:00446B8A 8D85A0FEFFFF lea eax, dword ptr [ebp+FFFFFEA0]
:00446B90 50 push eax
:00446B91 E8DA880300 call 0047F470
:00446B96 83C40C add esp, 0000000C
:00446B99 8D9510FFFFFF lea edx, dword ptr [ebp+FFFFFF10]
:00446B9F 52 push edx
:00446BA0 8D8DA0FEFFFF lea ecx, dword ptr [ebp+FFFFFEA0]
:00446BA6 51 push ecx* Reference To: KERNEL32.lstrcmpA, Ord:0000h
|
:00446BA7 E8AE460400 Call 0048B25A
:00446BAC 85C0 test eax, eax
:00446BAE 0F94C0 sete al
:00446BB1 83E001 and eax, 00000001
:00446BB4 5F pop edi
:00446BB5 5E pop esi
:00446BB6 5B pop ebx
:00446BB7 8BE5 mov esp, ebp
:00446BB9 5D pop ebp
:00446BBA C3 retAt 00446B99 the fake serial is pushed into edx, and at 00446BA0 the real serial is pushed into ecx. The values now stored in the edx and ecx registers goes into the lstrcmpA function to be compared with each other. Why not make the program compare the real serial, calculated by the program, with itself? If we change
:00446B99 8D9510FFFFFF
to
:00446B99 8D95A0FEFFFF
that’s whats going to happen. By doing this you can enter any serial, and it will be accepted. In fact, after changing it this way you will not even see the opening/register nag at all when you open the program. The program runs through this code at startup and it checks to see whether the register info is correct.
That was two bytes.
Is it possible to achieve this by changing only one byte?
Yes, it is.
Look at the instruction at 00446BAE, sete al. If the serial check is successful, the call made from 00446BA7 returns the eax value 0, and after the two instructions after the test eax, eax are executed, the value stored in eax is 1, and the program continues as registered. If the serial check fails, the call at 00446BA7 returns eax = 1, and the eax value after executing the three next instructions is 0, and the program goes on as unregistered. Then why not reverse the sete al instruction? I changed sete al to setne al ( 0F94C0 to 0F95C0). It worked.
That was only one byte.:-)