Crack WinGroov.drv 0.9E 1. enter registration info. you may enter arbitery user name. 2. bpx GetDlgItemText, than click on OK 3. when it triggers, p ret it, and than disable the breakpoint. 4. it should stop at (shown below) call far ptr GetDlgItemText -----> push word ptr [bp+PARAMETER_5] push 66h push ss lea ax, [bp-36h] push ax push 20h call far ptr GetDlgItemText 5. if you have entered all the reg info, step until this code (shown below) since the codes are just checking if you have entered all the fields. if not, it will move the cursor to the field and ask you to enter it. xor di, di push ss ; PARAMETER_2 lea ax, [bp-56h] push ax ; PARAMETER_1 6. the code follows are to check the rough format for reg info. generally, the password should be 8 characters in length and should begin with a 'N'. the registration code should be 8 character long and the first three should be alphabets and the rest of the digits are numbers. 7. if you get into the following code by accident, you know you are dead! push word ptr [bp+PARAMETER_5] push ss lea ax, [bp-56h] push ax push 40h call far ptr GetWindowText push 10h call far ptr MessageBeep push word ptr [bp+PARAMETER_5] because it will than show up the registration info error message and you will have to reenter the info. don't worry, just repeat with the above steps, but type something with the correct format. 8. if there's no problem, step to the following code mov word ptr ds:[data_802e], 1966h ; data_802e = 1248 mov ds:[data_801e], ds mov word ptr ds:[data_800e], 195Eh ; data_800e = 124c call far ptr func_38 and here comes the tricky part. step over the call as shown above until timeSetEvent gets called. if you just pass through that system call, you will miss validation of reg info. 9. timeSetEvent sets an event handler as specified, when the multimedia clock ticks. but in this case, the event handler calls the validation procedure. the address of the procedure is shown in the parameters of timeSetEvent, which is x:1afc. x varies depending on the system stage. push 64h push 64h push 4639h ; x -> wingroov.2 ;* push OFF 1afc db 68h,0FFh,0FFh push 4879h ; y -> wingroov.3 ;* push OFF 01bc db 68h,0FFh,0FFh push 1 call far ptr timeSetEvent 10. by analyzing the handler procedure as shown below: mov ax, 32bfh ; windows prologue code inc bp push bp mov bp, sp push ds mov ds, ax pushad call far ptr [bp+PARAMETER_5] ; (bp+0e) popad pop ds pop bp dec bp retf 0010h we know that it calls a procedure given as the user data. now look back in step 9, the user data is y:01bc (y varies, pointes to wingroov.3 code segment), which is the address of the procedure we are looking for. 11. the entire procedure begins with 'push esi'. the psuedo code is shown below. lpszPasswd = [1248] ; where [1248] points to actual ; password + 1 if lpszPasswd != NULL passcode = 0 repeat 7 times passcode = passcode * 26 (1ah) passcode += (*lpszPasswd - 41h) ; 41h = 'A' lpszPasswd++ end repeat lpszRegCode = [124c] ; [124c] -> reg code regcode = 0 checksum = 0 repeat 8 times ch = *lpszRegCode checksum = checksum + ch ch = ch - 30h ('0') if ch > 9 ch = ch - 11h ; totally - 41h ('A') if is ; alphabet ch = ch & 0fh ; ch should be no greater than ; 15 in any cases. end if regcode = (regcode << 4) | ch ; fill nibbles in ; regcode lpszRegCode++ end repeat passcode = passcode ror (checksum & 1fh (31)) ^ 19670109h [124c] = passcode - regcode ; ideal for this value is 0. end if [1248] = 0 ; executed. no need to execute again. return 12. Okay, we've gone to the core. We will not get the registration code/password from the program, so we have to work on algorithm. 13. since passcode - regcode = 0, that means passcode = regcode. therefore regcode = passcode ror (checksum & 1fh) ^ 19670109h 14. when passcode = 0, the regcode will be 19670109h no matter what the checksum value is. It is known that password of 'NAAAAAAA' will cause the passcode to be zero. (see psuedocode) 15. if we work on the regcode, a registration code of BJG70109 will have the result regcode 19670109h. So that when we try this combination: PASSWORD: NAAAAAAA REG CODE: BJG70109 with any user name (since it is related to calculation of neither password nor registration code), we can than register it successfully. However, I do recommend you to register with the user name Robin Hood (give me credit on cracking the code ;) ). *. No code changes to WinGroove is necessary. 了解了原理,要写出注册机并不难。请注意,你一定要有 MSVCRT.DLL 和 MFC42.DLL 才可执行。下列出算注册码的片段。原理是由 RegCode 算 PassWord(可是在 WinGroove 中两者的顺序颠倒) pWnd = GetDlgItem(IDC_REGCODE); // 此 edit control 储存了已经加以确认过的 userid(regcode) pWnd->SendMessage(EM_SETREADONLY, TRUE, 0); // 纯粹是为了使用者介面的一致性 pWnd->GetWindowText(m_strRegCode); // 取得文字 for (i = 0; i < 8; i++) { ch = m_strRegCode.GetAt(i); nChecksum += ch; ch -= _T('0'); if (ch > 9) ch = (ch - 0x11) & 0xf; // totally - _T('A') ulRegCode = (ulRegCode << 4) | ch; } // 因为 ulRegCode - ulPassCode = 0 // 所以 ulRegCode = ulPassCode // 又 ulPassCode = (ulPassCode ror (nChecksum & 0x1f)) ^ 0x19670109 // 则 ulRegCode = (ulPassCode ror (nChecksum & 0x1f)) ^ 0x19670109 // ulRegCode ^ 0x19670109 = ulPassCode ror (nChecksum & 0x1f) // (ulRegCode ^ 0x19670109) rol (nChecksum & 0x1f) = ulPassCode ulPassCode = _lrotl(ulRegCode ^ 0x19670109, nChecksum & 0x1f); // 反运算码 ul = ulPassCode; for (i = 7; i > 0; i--) // 码转成字串 { ch = (TCHAR)(ul % 26) + _T('A'); ul /= 26; // truncate towards 0 str.SetAt(i, ch); } str.SetAt(0, _T('N')); // 冠上 'N' 就成了密码