|
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);
}