continuing drlan's work |
Not Assigned | |
by fravia+ |
||
fra_00xx 980715 bb 0100 NA PC | ||
Well, not quite. We also need to fool the caller a bit. Let's take a look at that EnumWindows call that Drlan mentions. For our purposes, it's important. (I'm using the VIW.EXE as our little test proggie.)
Inside the callback function of the EnumWindows, we have:
00017747: 8B7508 mov esi,[ebp][00008] 0001774A: 6AEB push 0EB 0001774C: 56 push esi 0001774D: FF15F8B64300 call GetWindowLongA ;USER32.dll 00017753: 3DEBED0900 cmp eax,00009EDEB 00017758: 7533 jne .00001778D ---------- (1) 0001775A: 8D459C lea eax,[ebp][-0064] 0001775D: 6A64 push 064 0001775F: 50 push eax 00017760: 56 push esi 00017761: FF1538B84300 call GetWindowTextA ;USER32.dll 00017767: 8D4D9C lea ecx,[ebp][-0064] 0001776A: 68BCEB4200 push 00042EBBC ; "MKS Toolkit Demo" 0001776F: 51 push ecx 00017770: E8BB540000 call .00001CC30 ---------- (2) 00017775: 83C408 add esp,008 00017778: 85C0 test eax,eax 0001777A: 7511 jne .00001778D ---------- (3)
Ok, we start with a GetWindowLong(arg_8, 0xeb). The 0eb is most probably for the USERDATA. (check your header files if you're unsure..) That would mean the CMP right before jmp#1 is a magic number that our window needs to have in it's userdata. Once it passes that, we have a GetWindowText, which will pull our the window title into the buffer at ebp-64. That buffer, along with an argument @ 42eBBc which just so happens to be the text "MKS Toolkit Demo", gets passed to call#2, so we can guess that's the strcmp.
So we've got to fool this guy with two things: our userdata section has to have the magic number 0x09edeb in it, and our window needs to be called "MKS Toolkit Demo". Right on, let's write some code.
I'm using LCC, so some particulars apply differently to the compiler that you may choose. I've got code that looks like:
#include <win.h> main() { HWND hwnd; hwnd=CreateWindow( "STATIC" /* lpClassName */, "MKS Toolkit Demo" /* lpWindowName */, WS_DISABLED|WS_POPUP /* dwStyle */, 0 /* x */, 0 /* y */, 0 /* nWidth */, 0 /* nHeight */, NULL /* hWndParent */, NULL /* hMenu */, NULL /* hInstance */, 0 /* lParam */ ); if (hwnd==NULL) { printf("no hwnd\n"); exit(-1); } SetWindowLong(hwnd,GWL_USERDATA,0x0009edeb); SetWindowText(hwnd,"MKS Toolkit Demo"); Sleep(1000); exit(0); }We create a window of no size, set the appropriate magic number and window text, then sleep for a short time, allowing our MKS executable to find us and bypass the evil message about being unable to start MKSDEMO.EXE... Compile this and link it with "-subsystem windows", replace the old MKSDEMO.EXE, and you've got no more nag. Now let's move on to the time limit.
What do we have here? Well, we've got a registry value in HKEY_LOCAL_MACHINE called SOFTWARE\Mortice Kern Systems\Toolkit\DemoVersion\DemoNumber which contains some number that represents the software install date, and then we've got another routine that comes along with a GetSystemTime and produces a similar number. A comparison between these two numbers is done, and if it just so happens to differ beyond 0x278d00, or thirty days, the executable refuses to work.
My first thought was to hook the RegQueryValueEx API function to check if we're looking for that registry key, and if we are, do a GetSystemTime and return the appropriate juju. That would probably work, though it would mean we'd need some sort of setup program for MKS to initialize the hook, and that just seems sloppy.
But then it occurred to me, since every executable is calling MKSDEMO, why can't we just have MKSDEMO update the key to the current time everytime a MKS tool is run? After I stopped giggling (for some reason, I found this intensely funny), I realized that this was justice preserved. MKS went through all this trouble to make it hard on us, and here we are using the mechanism of their own obstructionist tactics against them.
So our object now is to figure out how the number in the registry key is developed from GetSystemTime, and then to put that code into our own MKSDEMO.C. Our install time in DemoNumber will get updated to the current time and our 30-day trial will consistently renew itself whenever we run an MKS tool.
At 4175e0 we have our call to RegQueryValueEx, and there's a call to 423420 shortly thereafter, which has our GetSystemTime in it. The function at 423420 returns the number we want in eax, so we've got to reverse this routine. We need to remember the SYSTEMTIME structure, so follow along. (In this code, the WORDs of the structure get shoved into the DWORDs of the registers. Many times the WORD in the high part of the DWORD gets masked out, sometimes it doesn't; the high WORD never matters, though, so I'm ignoring it in the comments.)
typedef struct _SYSTEMTIME { WORD wYear; // 0x10 WORD wMonth; // 0x0e WORD wDayOfWeek; // 0x0c WORD wDay; // 0x0a WORD wHour; // 0x08 WORD wMinute; // 0x06 WORD wSecond; // 0x04 WORD wMilliseconds; // 0x02 } SYSTEMTIME;
The fairly long code snippet looks like:
00023420: 55 push ebp 00023421: 8BEC mov ebp,esp 00023423: 83EC10 sub esp,010 00023426: 53 push ebx 00023427: 56 push esi ; save regs 00023428: 8D45F0 lea eax,[ebp][-0010] 0002342B: 57 push edi ; save edi 0002342C: 50 push eax 0002342D: FF1590B64300 call GetSystemTime ; ebp-10=Systemtime 00023433: 8B5DF2 mov ebx,[ebp][-000E] ; ebx=wMonth 00023436: 8B45F0 mov eax,[ebp][-0010] ; eax=wYear 00023439: 8BCB mov ecx,ebx 0002343B: 8B55F6 mov edx,[ebp][-000A] ; edx=wDay 0002343E: 81E1FFFF0000 and ecx,00000FFFF 00023444: 4A dec edx ; wDay-- ; the table in 42f73e is ; int mon2day[14]={ 0x0, 0x0, 0x1f, 0x3b, 0x5a, 0x78, 0x97, 0xb5, ; 0xd4, 0xf3, 0x111, 0x130, 0x14e, 0x16d }; ; which, given a month, gives us the number of days for each month since Jan 01 00023445: 668B344D3EF74200 mov si,[00042F73E][ecx]*2 ; si=mon2day[ecx] 0002344D: 8D8844F8FFFF lea ecx,[eax][0FFFFF844] ;ecx=edi-1980 00023453: 8BF9 mov edi,ecx ; edi=wYear-1980 00023455: 6603F2 add si,dx ; si += wDay ; si now = the number of days into the year from Jan 01, discounting the leap year ; so we should expect a leap calculation now 00023458: 81E7FFFF0000 and edi,00000FFFF 0002345E: 8BC7 mov eax,edi ; eax=wYear-1980 00023460: 99 cdq ; edx=0, (usually a precursor to a modulo?) 00023461: 33C2 xor eax,edx 00023463: 2BC2 sub eax,edx 00023465: 83E003 and eax,003 ; eax = wYear % 3 00023468: 33C2 xor eax,edx 0002346A: 2BC2 sub eax,edx 0002346C: 7507 jne .000023475 ; if we're not in a leap year, jump 0002346E: 6683FB02 cmp bx,002 ; if we're not past February yet, 00023472: 7601 jbe .000023475 ; jump 00023474: 46 inc esi ; add a day ; our leap year calculation is done 00023475: 8D14C9 lea edx,[ecx][ecx]*8 ; edx=9*(wYear-1980) 00023478: 8D4703 lea eax,[edi][00003] ; eax=(wYear-1980)+3 (+3?) 0002347B: 8D0CD1 lea ecx,[ecx][edx]*8 ; ecx=73*(wYear-1980) ; 73 is an important number, 73 * 5 = 365, we should see that nearby 0002347E: 99 cdq ; edx =0 0002347F: 8BD9 mov ebx,ecx 00023481: 83E203 and edx,003 00023484: 03DE add ebx,esi ; ebx=(73(wYear-1980)+#days) 00023486: 03C2 add eax,edx 00023488: C1F802 sar eax,002 ; eax=(wYear+3)/4 ; this eax will be used to calculate how many leap days have past 0002348B: 8D0C8B lea ecx,[ebx][ecx]*4 ; ecx=73*5*wYear+si=365wYear+si ; Here's our 365 days a year we're calculating since 1980 0002348E: 8D8408440E0000 lea eax,[eax][ecx][000000E44] ; and here we have an adjustment for 3652 days, about 10 years-ish, 1970-ish instead of ; 1980, plus an adjustment for leap days past ; our #days calculation is now complete. ; we need #days * 24 hrs a day * 60 mins an hour * 60 seconds a min ; to compute it in seconds.. We'll see it here. 00023495: 25FFFF0000 and eax,00000FFFF 0002349A: 8D1440 lea edx,[eax][eax]*2 ; edx=3*#days 0002349D: 8B45F8 mov eax,[ebp][-0008] ; eax=whour 000234A0: 25FFFF0000 and eax,00000FFFF 000234A5: 8D04D0 lea eax,[eax][edx]*8 ; edx=8*3*#days+wHour ; 24 hrs in a day + wHour here, gives us eax = total # of hours so far since begin date. 000234A8: 8B55FA mov edx,[ebp][-0006] ; edx=wMinute 000234AB: 8BC8 mov ecx,eax 000234AD: 81E2FFFF0000 and edx,00000FFFF 000234B3: C1E104 shl ecx,004 ; ecx=totalhrs*16 000234B6: 2BC8 sub ecx,eax ; make that totalhrs*15 000234B8: 8D048A lea eax,[edx][ecx]*4 ; eax=15*totalhrs*4+wMinute ; 60 mins per hour + minutes, one last * 60 and we should be done. 000234BB: 8B55FC mov edx,[ebp][-0004] ; edx=wSecond 000234BE: 8BC8 mov ecx,eax 000234C0: 81E2FFFF0000 and edx,00000FFFF 000234C6: C1E104 shl ecx,004 ; * 16 000234C9: 2BC8 sub ecx,eax ; * 15 000234CB: 8D048A lea eax,[edx][ecx]*4 ; 15*4*totalsecs+wSecond ; eax = the # of seconds past since some target date. 000234CE: 8B4D08 mov ecx,[ebp][00008] ; and finally, if we've got arg to put this in, put it there, otherwise we'll drop it in eax 000234D1: 85C9 test ecx,ecx 000234D3: 7402 je .0000234D7 000234D5: 8901 mov [ecx],eax 000234D7: 5F pop edi 000234D8: 5E pop esi 000234D9: 5B pop ebx 000234DA: 8BE5 mov esp,ebp 000234DC: 5D pop ebp 000234DD: C3 retn
Not bad, certainly easier than some serial # routines. We can simplify this a bit in C:
GetSystemTime(&st); adddays=mon2day[st.wMonth]+st.wDay-1; if ( ! (st.wYear-1980)%4 ) if (st.wMonth>2) adddays++; yeardays=st.wYear-1980; yeardays*=73; yeardays=(yeardays*4)+(yeardays+adddays); leapdays=(st.wYear-1980+3)/4; yeardays+=leapdays; yeardays+=3652; mytime = st.wSecond + (st.wMinute*60) + (st.wHour*60*60) + (yeardays*60*60*24);
What's curious here is the adjustments of 3,652 days. This calculation starts with Jan 01, 1980, but then instead gives us 10 years extra. The routine actually calculates the number of UTC seconds since Jan 01, 1970, but the programmer chose to calculate the date from 1980 and then add in the 10 extra years. Doubtless we'll never figure out why, but who cares? It's beat, and that's all that matters.
Add this into our MKSDEMO.C program, along with an appropriate registry change, and we're using MKS toolkit, nagless and forever.
#include <win.h> main() { HWND hwnd; SYSTEMTIME st; PHKEY keyhand; unsigned long mytime; int mon2day[14]={ 0x0, 0x0, 0x1f, 0x3b, 0x5a, 0x78, 0x97, 0xb5, 0xd4, 0xf3, 0x111, 0x130, 0x14e, 0x16d }; hwnd=CreateWindow("STATIC", "MKS Toolkit Demo", WS_DISABLED|WS_POPUP, 0, 0, 0, 0, NULL, NULL, NULL, NULL, 0); SetWindowLong(hwnd,GWL_USERDATA,0x0009edeb); SetWindowText(hwnd,"MKS Toolkit Demo"); GetSystemTime(&st); adddays=mon2day[st.wMonth]+st.wDay-1; if ( ! (st.wYear-1980)%4 ) if (st.wMonth>2) adddays++; yeardays=st.wYear-1980; yeardays*=73; yeardays=(yeardays*4)+(yeardays+adddays); leapdays=(st.wYear-1980+3)/4; yeardays+=leapdays; yeardays+=3652; mytime = st.wSecond + (st.wMinute*60) + (st.wHour*60*60) + (yeardays*60*60*24); RegOpenKeyEx(HKEY_LOCAL_MACHINE,"SOFTWARE\\Mortice Kern Systems\\Toolkit\\DemoVersion", 0, KEY_WRITE, &keyhand); RegSetValueEx(keyhand,"DemoNumber",0,REG_DWORD,&mytime,sizeof(DWORD)); Sleep(1000); exit(0); }