www.pudn.com > 通用注册机.zip > main.h


//--------------------------------------------------------------------------- 
#ifndef mainH 
#define mainH 
//--------------------------------------------------------------------------- 
#include  
#include  
#include  
#include  
//--------------------------------------------------------------------------- 
class TForm1 : public TForm 
{ 
__published:	// IDE-managed Components 
        TLabel *Label1; 
        TEdit *Edit1; 
        TLabel *Label2; 
        TEdit *Edit2; 
        TButton *Button1; 
        TButton *Button2; 
        void __fastcall Button1Click(TObject *Sender); 
        void __fastcall Button2Click(TObject *Sender); 
private:	// User declarations 
public:		// User declarations 
        __fastcall TForm1(TComponent* Owner); 
}; 
//--------------------------------------------------------------------------- 
extern PACKAGE TForm1 *Form1; 
//--------------------------------------------------------------------------- 
//////////转换成数字 
char ConvertTable[]="0123456789-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+"; 
int GetIndex(char n) 
{ 
 int i = -1; 
 ConvertTable[64] = n; 
 while(ConvertTable[++i]!=n); 
 return i>63 ? 63 : i; 
} 
//--------------------------------------------------------------------------- 
#define f_rnd(i,a,b,c,d)                \ 
        u = _lrotl(d*(d+d+1), 5);       \ 
        t = _lrotl(b*(b+b+1), 5);       \ 
        a = _lrotl(a^t, u)+l_key[i];    \ 
        c = _lrotl(c^u, t)+l_key[i+1] 
 
unsigned long l_key[44]; 
//--------------------------------------------------------------------------- 
//////////设置注册序列 
void set_key(const unsigned char *key) 
{ 
 unsigned long i, j, k, a, b, l[8]; 
 
 unsigned long in_key[256]; 
 j = 0; 
 k = 32; 
 for(i=0; i<256; i++) 
    in_key[i] = 0; 
 for(i=strlen(key); i>0; i--) { 
    if(k >= 32) { 
       k = 0; 
       in_key[j] = 0; 
       j++; 
       } 
    in_key[j-1] |= (key[i-1]< 
#include  
 
#pragma inline 
//--------------------------------------------------------------------------- 
// IDE NT/2000/XP专用变量 
#define GETVERSIONOUTPARAMS     GETVERSIONINPARAMS 
#define DFP_GET_VERSION         SMART_GET_VERSION 
#define DFP_SEND_DRIVE_COMMAND  SMART_SEND_DRIVE_COMMAND 
#define DFP_RCV_DRIVE_DATA      SMART_RCV_DRIVE_DATA 
 
const WORD IDE_ATAPI_IDENTIFY = 0xA1;   // 读取ATAPI设备的命令 
const WORD IDE_ATA_IDENTIFY   = 0xEC;   // 读取ATA设备的命令 
 
const int MAX_IDE_DRIVES = 4; 
 
// SCSI专用变量 
const DWORD FILE_DEVICE_SCSI             = 0x0000001B; 
const DWORD IOCTL_SCSI_MINIPORT_IDENTIFY = ((FILE_DEVICE_SCSI << 16) + 0x0501); 
const DWORD IOCTL_SCSI_MINIPORT          = 0x0004D008; // see NTDDSCSI.H for definition 
const DWORD SENDIDLENGTH  = sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE; 
 
typedef struct _SRB_IO_CONTROL 
{ 
    ULONG HeaderLength; 
    UCHAR Signature[8]; 
    ULONG Timeout; 
    ULONG ControlCode; 
    ULONG ReturnCode; 
    ULONG Length; 
}SRB_IO_CONTROL, *PSRB_IO_CONTROL; 
//--------------------------------------------------------------------------- 
// 读取的主函数 
void __fastcall ReadPhysicalDrive(TStrings *pSerList, TStrings *pModeList); 
// 辅助函数 
char *__fastcall ConvertToString(DWORD dwDiskData[256], int nFirstIndex, int nLastIndex); 
// NT/2000/XP函数 
void __fastcall ReadPhysicalDriveOnNT(TStrings *pSerList, TStrings *pModeList); 
bool __fastcall DoIdentify(HANDLE hPhysicalDriveIOCTL, PSENDCMDINPARAMS pSCIP, PSENDCMDOUTPARAMS pSCOP, BYTE btIDCmd, BYTE btDriveNum, PDWORD lpcbBYTEsReturned); 
// Windows 9X函数 
void __fastcall ReadPhysicalDriveOnW9X(TStrings *pSerList, TStrings *pModeList); 
void __fastcall ReadPhysicalDriveOnW9X_Ring0(bool IsFirst, WORD BaseAddress, BYTE MoS, bool &IsIDEExist, bool &IsDiskExist, WORD *OutData); 
// SCSI读取函数(for NT/2000/XP) 
String __fastcall ReadIDEDriveAsScsiDriveOnNT(); 
//--------------------------------------------------------------------------- 
// ReadPhysicalDrive 
void __fastcall ReadPhysicalDrive(TStrings *pSerList, TStrings *pModeList) 
{ 
    switch(Win32Platform) 
    { 
        case VER_PLATFORM_WIN32_WINDOWS: 
            ReadPhysicalDriveOnW9X(pSerList, pModeList); 
            break; 
        case VER_PLATFORM_WIN32_NT: 
            ReadPhysicalDriveOnNT(pSerList, pModeList); 
            break; 
        default: 
            break; 
    } 
} 
//--------------------------------------------------------------------------- 
// ConvertToString 
char *__fastcall ConvertToString(DWORD dwDiskData[256], int nFirstIndex, int nLastIndex) 
{ 
    static char szResBuf[1024]; 
    int nIndex; 
    int nPosition = 0; 
 
    // Each integer has two characters stored in it backwards 
    for(nIndex = nFirstIndex; nIndex <= nLastIndex; nIndex++) 
    { 
        // Get high BYTE for 1st character 
        szResBuf[nPosition] = (char)(dwDiskData[nIndex] / 256); 
        nPosition++; 
 
        // Get low BYTE for 2nd character 
        szResBuf[nPosition] = (char)(dwDiskData[nIndex] % 256); 
        nPosition++; 
    } 
 
    // End the string 
    szResBuf[nPosition] = '\0'; 
 
    // Cut off the trailing blanks 
    for(nIndex = nPosition - 1; nIndex > 0 && ' ' == szResBuf[nIndex]; nIndex--) 
        szResBuf[nIndex] = '\0'; 
 
    return szResBuf; 
} 
//--------------------------------------------------------------------------- 
// Winndows NT4/2000/XP 代码 
void __fastcall ReadPhysicalDriveOnNT(TStrings *pSerList, TStrings *pModeList) 
{ 
    // 输出参数 
    BYTE btIDOutCmd[sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1]; 
 
    for(int nDrive=0; nDrive < MAX_IDE_DRIVES; nDrive++) 
    { 
        HANDLE hPhysicalDriveIOCTL; 
        char szDriveName[32]; 
 
        sprintf(szDriveName, "\\\\.\\PhysicalDrive%d", nDrive); 
        hPhysicalDriveIOCTL = CreateFile(szDriveName, 
                        GENERIC_READ | GENERIC_WRITE, 
                        FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 
                        OPEN_EXISTING, 0, NULL); 
 
        if(hPhysicalDriveIOCTL != INVALID_HANDLE_VALUE) 
        { 
            DWORD dwBytesReturned = 0; 
            GETVERSIONOUTPARAMS gvopVersionParams; 
 
            // Get the version, etc of PhysicalDrive IOCTL 
            ZeroMemory(&gvopVersionParams, sizeof(GETVERSIONOUTPARAMS)); 
 
            if(!DeviceIoControl(hPhysicalDriveIOCTL, DFP_GET_VERSION, 
                    NULL, 0, &gvopVersionParams, sizeof(gvopVersionParams), 
                    &dwBytesReturned, NULL)) 
            { 
                continue; 
            } 
 
            if(gvopVersionParams.bIDEDeviceMap > 0) 
            { 
                // IDE or ATAPI IDENTIFY cmd 
                BYTE btIDCmd; 
                SENDCMDINPARAMS InParams; 
                // Now, get the ID sector for all IDE devices in the system. 
                // If the device is ATAPI use the IDE_ATAPI_IDENTIFY command, 
                // otherwise use the IDE_ATA_IDENTIFY command 
                // 具体所得结果请参考头文件中的说明 
                btIDCmd = (gvopVersionParams.bIDEDeviceMap >> nDrive & 0x10) ? 
                        IDE_ATAPI_IDENTIFY : IDE_ATA_IDENTIFY; 
                ZeroMemory(&InParams, sizeof(SENDCMDINPARAMS)); 
                ZeroMemory(btIDOutCmd, sizeof(btIDOutCmd)); 
 
                if(DoIdentify(hPhysicalDriveIOCTL, 
                     &InParams, (PSENDCMDOUTPARAMS)btIDOutCmd, 
                     (BYTE)btIDCmd, (BYTE)nDrive, &dwBytesReturned)) 
                { 
                    DWORD dwDiskData[256]; 
                    USHORT *pIDSector; // 对应结构IDSECTOR,见头文件 
                    char szSerialNumber[21]; 
                    char szModelNumber[41]; 
 
                    pIDSector = (USHORT*)((SENDCMDOUTPARAMS*)btIDOutCmd)->bBuffer; 
                    for(int i=0; i < 256; i++) 
                        dwDiskData[i] = pIDSector[i]; 
                    // 取系列号 
                    ZeroMemory(szSerialNumber, sizeof(szSerialNumber)); 
                    strcpy(szSerialNumber, ConvertToString(dwDiskData, 10, 19)); 
 
                    // 取模型号 
                    ZeroMemory(szModelNumber, sizeof(szModelNumber)); 
                    strcpy(szModelNumber, ConvertToString(dwDiskData, 27, 46)); 
 
                    pSerList->Add(szSerialNumber); 
                    pModeList->Add(szModelNumber); 
                } 
            } 
            CloseHandle (hPhysicalDriveIOCTL); 
        } 
    } 
} 
//--------------------------------------------------------------------------- 
// DoIdentify 
bool __fastcall DoIdentify(HANDLE hPhysicalDriveIOCTL, PSENDCMDINPARAMS pSCIP, 
              PSENDCMDOUTPARAMS pSCOP, BYTE btIDCmd, BYTE btDriveNum, 
              PDWORD pdwBytesReturned) 
{ 
    // Set up data structures for IDENTIFY command. 
    pSCIP->cBufferSize = IDENTIFY_BUFFER_SIZE; 
    pSCIP->irDriveRegs.bFeaturesReg = 0; 
    pSCIP->irDriveRegs.bSectorCountReg  = 1; 
    pSCIP->irDriveRegs.bSectorNumberReg = 1; 
    pSCIP->irDriveRegs.bCylLowReg  = 0; 
    pSCIP->irDriveRegs.bCylHighReg = 0; 
 
    // Compute the drive number.(主盘和从盘所对应的值是不一样的) 
    pSCIP->irDriveRegs.bDriveHeadReg = (btDriveNum & 1) ? 0xB0 : 0xA0; 
 
    // The command can either be IDE identify or ATAPI identify. 
    pSCIP->irDriveRegs.bCommandReg = btIDCmd; 
    pSCIP->bDriveNumber = btDriveNum; 
    pSCIP->cBufferSize = IDENTIFY_BUFFER_SIZE; 
 
    return DeviceIoControl(hPhysicalDriveIOCTL, DFP_RCV_DRIVE_DATA, 
           (LPVOID)pSCIP, 
           sizeof(SENDCMDINPARAMS) - 1, 
           (LPVOID)pSCOP, 
           sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1, 
           pdwBytesReturned, NULL); 
} 
//--------------------------------------------------------------------------- 
// Windows 95/98/ME 代码 
//--------------------------------------------------------------------------- 
// ReadPhysicalDriveOnW9X 
void __fastcall ReadPhysicalDriveOnW9X(TStrings *pSerList, TStrings *pModeList) 
{ 
    WORD wOutData[256]; 
    SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS); 
 
    // 经过测试,发现第一次调用而且Drive >= 2时会在Ring0代码中出现错误,导致蓝屏。 
    // 经过N(N > 15)次的蓝屏后仍找不到原因:(不得不在这里增加一段无用代码以 
    // 避免蓝屏的出现。(期待高人能指出原因) 
    for(int nDrive = 0; nDrive < 8; nDrive++) 
    { 
        WORD dwBaseAddress; 
        BYTE btMasterSlave;         // Master Or Slave 
        bool bIsIDEExist; 
        bool IsDiskExist; 
 
        switch(nDrive / 2) 
        { 
            case 0: dwBaseAddress = 0x01F0; break; 
            case 1: dwBaseAddress = 0x0170; break; 
            case 2: dwBaseAddress = 0x01E8; break; 
            case 3: dwBaseAddress = 0x0168; break; 
        } 
 
        btMasterSlave = (BYTE)(((nDrive % 2) == 0) ? 0xA0 : 0xB0); 
 
        // 进入Ring0 
        ReadPhysicalDriveOnW9X_Ring0(true, dwBaseAddress, btMasterSlave, 
                bIsIDEExist, IsDiskExist, wOutData); 
    } 
 
    // 开始读取 
    for(int nDrive = 0; nDrive < 8; nDrive++) 
    { 
        WORD dwBaseAddress; 
        BYTE btMasterSlave;         // Master Or Slave 
        bool bIsIDEExist; 
        bool bIsDiskExist; 
        switch(nDrive / 2) 
        { 
            case 0: dwBaseAddress = 0x01F0; break; 
            case 1: dwBaseAddress = 0x0170; break; 
            case 2: dwBaseAddress = 0x01E8; break; 
            case 3: dwBaseAddress = 0x0168; break; 
        } 
 
        btMasterSlave = (BYTE)(((nDrive % 2) == 0) ? 0xA0 : 0xB0); 
 
        // 进入Ring0 
        bIsIDEExist  = false; 
        bIsDiskExist = false; 
        ZeroMemory(wOutData, sizeof(wOutData)); 
 
        ReadPhysicalDriveOnW9X_Ring0(false, dwBaseAddress, btMasterSlave, 
                bIsIDEExist, bIsDiskExist, wOutData); 
 
        if(bIsIDEExist && bIsDiskExist) 
        { 
            DWORD dwDiskData[256]; 
            char  szSerialNumber[21]; 
            char  szModelNumber[41]; 
 
            for(int k=0; k < 256; k++) 
                dwDiskData[k] = wOutData[k]; 
 
            // 取系列号 
            ZeroMemory(szSerialNumber, sizeof(szSerialNumber)); 
            strcpy(szSerialNumber, ConvertToString(dwDiskData, 10, 19)); 
 
            // 取模型号 
            ZeroMemory(szModelNumber, sizeof(szModelNumber)); 
            strcpy(szModelNumber, ConvertToString(dwDiskData, 27, 46)); 
 
            pSerList->Add(szSerialNumber); 
            pModeList->Add(szModelNumber); 
        } 
    } 
    SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); 
} 
//--------------------------------------------------------------------------- 
// ReadPhysicalDriveOnW9X_Ring0() 
// 
// dwBaseAddress = IDE(0,1,2,3) : 1F0h, 170h, 1E8h, 168h 
// btMasterSlave = Master(0xA0) Or Slave(0xB0) 
//--------------------------------------------------------------------------- 
void __fastcall ReadPhysicalDriveOnW9X_Ring0(bool bIsFirst, WORD dwBaseAddress, 
        BYTE btMasterSlave, bool &bIsIDEExist, bool &bIsDiskExist, WORD *pOutData) 
{ 
    BYTE  btIDTR1[6]; 
    DWORD dwOldExceptionHook; 
    const int nHookExceptionNo = 5; 
 
    BYTE  btIsIDEExist = 0; 
    BYTE  btIsDiskExist = 0; 
    WORD  wOutDataBuf[256]; 
 
    BYTE  btIsFirst = (BYTE)bIsFirst; 
 
    const BYTE btBit00 = 0x01; 
    // const BYTE btBit02 = 0x04; 
    const BYTE btBit06 = 0x40; 
    const BYTE btBit07 = 0x80; 
    // const BYTE btERR  = btBit00; 
    const BYTE btBusy = btBit07; 
    const BYTE btAtaCmd   = 0xEC; 
    const BYTE btAtapiCmd = 0xA1; 
 
    __asm 
    { 
        // 必须先执行这条语句 
        JMP EnterRing0 
 
        // 定义过程 
        // 等待IDE设备直到其不为忙为止 
        WaitWhileBusy proc 
 
        MOV  EBX, 100000 
        MOV  DX, dwBaseAddress 
        ADD  DX, 7 
 
        LoopWhileBusy: 
 
        DEC  EBX 
        CMP  EBX, 0 
        JZ   Timeout 
        in   AL, DX 
        TEST AL, btBusy 
        JNZ  LoopWhileBusy 
        JMP  DriveReady 
 
        // 超时,直接退出 
        Timeout: 
        JMP  LeaveRing0 
        DriveReady: 
        RET 
        ENDP   // End of WaitWhileBusy Procedure 
 
        // 设置主盘和从盘标志 
        SelectDevice proc 
 
        MOV  DX, dwBaseAddress 
        ADD  DX, 6 
        MOV  AL, btMasterSlave 
 
        out  DX, AL 
        RET 
 
        ENDP  // End of SelectDevice Procedure 
 
        // 向IDE设备发送存取指令 
        SendCmd proc 
 
        MOV DX, dwBaseAddress 
        ADD DX, 7 
        MOV AL, BL // BL是主从盘标识,在过程外设置 
        out DX, AL 
        RET 
        ENDP  // End of SendCmd Procedure 
 
        // Ring0代码 
        Ring0Proc: 
        PUSHAD 
        // 查询IDE设备是否存在 
        MOV DX, dwBaseAddress 
        ADD DX, 7 
        in  AL,DX 
 
        // 当AL的值是0xFF或者0x7F时,IDE设备不存在,这时候直接返回 
        CMP AL,0xFF 
        JZ  LeaveRing0 
        CMP AL, 0x7F 
        JZ  LeaveRing0 
 
        // 设置IDE设备存在标志 
        MOV btIsIDEExist, 1 
 
        // 查询IDE设备上的驱动器是否存在(有IDE插槽在主板上,但是却不一定有硬盘插在上面) 
        CALL WaitWhileBusy 
        CALL SelectDevice 
 
        // 如果是第一次调用,则直接返回,否则执行下行语句时会出现蓝屏 
        CMP  btIsFirst, 1 
        JZ   LeaveRing0 
 
        // 第一次调用时,如果执行这行语句会导致蓝屏,Why??? 
        CALL WaitWhileBusy 
 
        // AL的值等于cBit06时,不存在驱动器,直接返回 
        TEST AL, btBit06 
        JZ   LeaveRing0 
 
        // 设置驱动器存在标志 
        MOV  btIsDiskExist, 1 
 
        // 发送存取端口命令 
        // 无法像NT/2000/XP那样可以通过查询VERSION的值得到驱动器的类型, 
        // 所以只能一步一步地测试,如果不是ATA设备,再尝试使用ATAPI设备命令 
        CALL WaitWhileBusy 
        CALL SelectDevice    // 设置主从盘标识 
        MOV  BL, btAtaCmd      // 发送读取命令 
        CALL SendCmd 
        CALL WaitWhileBusy 
 
        // 检查是否出错 
        MOV  DX, dwBaseAddress 
        ADD  DX, 7 
 
        in   AL, DX 
 
        TEST AL, btBit00 
        JZ   RetrieveInfo   // 没有错误时则读数据 
 
        // 如果出错,则进一步尝试使用ATAPI设备命令 
        CALL WaitWhileBusy 
        CALL SelectDevice 
        MOV  BL, btAtapiCmd 
        CALL SendCmd 
        CALL WaitWhileBusy 
 
        // 检查是否还出错 
        MOV  DX, dwBaseAddress 
        ADD  DX, 7 
        in   AL, DX 
        TEST AL, btBit00 
        JZ   RetrieveInfo   // 没有错误时则读数据 
        JMP  LeaveRing0     // 如果还是出错,直接返回 
 
        // 读取数据 
        RetrieveInfo: 
 
        LEA  EDI, wOutDataBuf 
        MOV  ECX, 256 
        MOV  DX, dwBaseAddress 
        CLD 
 
        REP  INSW 
 
        // 退出Ring0代码 
        LeaveRing0: 
 
        POPAD 
        IRETD 
 
        // 激活Ring0代码 
        EnterRing0: 
 
        // 修改中断门 
        SIDT FWORD PTR btIDTR1 
        MOV EAX, DWORD PTR btIDTR1 + 02h 
        ADD EAX, nHookExceptionNo * 08h + 04h 
        CLI 
 
        // 保存原异常处理例程入口 
        MOV ECX, DWORD PTR [EAX] 
        MOV CX, WORD PTR [EAX-04h] 
        MOV dwOldExceptionHook, ECX 
 
        // 指定新入口 
        LEA EBX, Ring0Proc 
        MOV WORD PTR [EAX-04h],BX 
        SHR EBX, 10h 
        MOV WORD PTR[EAX+02h], BX 
 
        // 激活Ring0代码 
        INT nHookExceptionNo 
 
        // 复原入口 
        MOV ECX,dwOldExceptionHook 
        MOV WORD PTR[EAX-04h], CX 
        SHR ECX,10h 
        MOV WORD PTR[EAX+02h], CX 
        STI 
    } 
    if(!bIsFirst) 
    { 
        bIsIDEExist  = (bool)btIsIDEExist; 
        bIsDiskExist = (bool)btIsDiskExist; 
        CopyMemory(pOutData, wOutDataBuf, sizeof(wOutDataBuf)); 
    } 
} 
//--------------------------------------------------------------------------- 
bool GetFirstHDDSerial(char *buf) 
{ 
 TStringList *SerialList = new TStringList(); 
 TStringList *ModelList = new TStringList(); 
 ReadPhysicalDrive(SerialList, ModelList); 
 if(SerialList->Count) 
    strcpy(buf, SerialList->Strings[0].c_str()); 
 else 
    strcpy(buf, ""); 
 delete SerialList; 
 delete ModelList; 
 if(*buf) { 
    int i, k=0; 
    unsigned char temp[256]; 
    unsigned char mask[12]={0x4e,0x24,0x69,0xf7,0xe1,0xa6,0x53,0x46,0x2d,0x74,0x3e,0xb1}; 
    for(i=0; buf[i]; i++) { 
       buf[i] = GetIndex(buf[i]); 
       k += buf[i]; 
       } 
    k /= i; 
    while(i<16) 
       buf[i++] = k; 
    i = k = 0; 
    while(i<12) { 
       temp[i++] = buf[k]|buf[k+1]<<6; 
       temp[i++] = buf[k+1]>>2|buf[k+2]<<4; 
       temp[i++] = buf[k+2]>>4|buf[k+3]<<2; 
       k += 4; 
       } 
    for(i=0; i<12; i++) 
       temp[i] = ~temp[i]^mask[i]; 
    i = k = 0; 
    while(i<16) { 
       buf[i++] = ConvertTable[temp[k]&0x3f]; 
       buf[i++] = ConvertTable[(temp[k]>>6|temp[k+1]<<2)&0x3f]; 
       buf[i++] = ConvertTable[(temp[k+1]>>4|temp[k+2]<<4)&0x3f]; 
       buf[i++] = ConvertTable[temp[k+2]>>2]; 
       k += 3; 
       } 
    buf[16] = 0; 
    return true; 
    } 
 return false; 
} 
//--------------------------------------------------------------------------- 
//////////判断是否为正确的序列号 
bool CheckSerial(const unsigned char *serial, const unsigned char *key) 
{ 
 unsigned long a, b, c, d, t, u; 
 
 unsigned char _tin[16], _tout[16]; 
 unsigned long in_blk[4], out_blk[4]; 
 
 int i, k; 
 char tin[32]; 
 i = k = 0; 
 GetFirstHDDSerial(tin); 
 while(i<12) { 
    _tin[i++] = GetIndex(tin[k])|GetIndex(tin[k+1])<<6; 
    _tin[i++] = GetIndex(tin[k+1])>>2|GetIndex(tin[k+2])<<4; 
    _tin[i++] = GetIndex(tin[k+2])>>4|GetIndex(tin[k+3])<<2; 
    k += 4; 
    } 
 _tin[12] = _tin[13] = _tin[14] = _tin[15] = 0; 
 
 in_blk[0] = _tin[0]|(_tin[1]<<8)|(_tin[2]<<16)|(_tin[3]<<24); 
 in_blk[1] = _tin[4]|(_tin[5]<<8)|(_tin[6]<<16)|(_tin[7]<<24); 
 in_blk[2] = _tin[8]|(_tin[9]<<8)|(_tin[10]<<16)|(_tin[11]<<24); 
 in_blk[3] = _tin[12]|(_tin[13]<<8)|(_tin[14]<<16)|(_tin[15]<<24); 
 
 set_key(key); 
 
 a = in_blk[0]; b = in_blk[1]+l_key[0]; 
 c = in_blk[2]; d = in_blk[3]+l_key[1]; 
 
 f_rnd( 2,a,b,c,d); f_rnd( 4,b,c,d,a); 
 f_rnd( 6,c,d,a,b); f_rnd( 8,d,a,b,c); 
 f_rnd(10,a,b,c,d); f_rnd(12,b,c,d,a); 
 f_rnd(14,c,d,a,b); f_rnd(16,d,a,b,c); 
 f_rnd(18,a,b,c,d); f_rnd(20,b,c,d,a); 
 f_rnd(22,c,d,a,b); f_rnd(24,d,a,b,c); 
 f_rnd(26,a,b,c,d); f_rnd(28,b,c,d,a); 
 f_rnd(30,c,d,a,b); f_rnd(32,d,a,b,c); 
 f_rnd(34,a,b,c,d); f_rnd(36,b,c,d,a); 
 f_rnd(38,c,d,a,b); f_rnd(40,d,a,b,c); 
 
 out_blk[0] = a+l_key[42]; out_blk[1] = b; 
 out_blk[2] = c+l_key[43]; out_blk[3] = d; 
 
 _tout[0] = out_blk[0]&0x000000ff;  _tout[1] = (out_blk[0]>>8)&0x000000ff;  _tout[2] = (out_blk[0]>>16)&0x000000ff;  _tout[3] = (out_blk[0]>>24)&0x000000ff; 
 _tout[4] = out_blk[1]&0x000000ff;  _tout[5] = (out_blk[1]>>8)&0x000000ff;  _tout[6] = (out_blk[1]>>16)&0x000000ff;  _tout[7] = (out_blk[1]>>24)&0x000000ff; 
 _tout[8] = out_blk[2]&0x000000ff;  _tout[9] = (out_blk[2]>>8)&0x000000ff;  _tout[10] = (out_blk[2]>>16)&0x000000ff; _tout[11] = (out_blk[2]>>24)&0x000000ff; 
 _tout[12] = out_blk[3]&0x000000ff; _tout[13] = (out_blk[3]>>8)&0x000000ff; _tout[14] = (out_blk[3]>>16)&0x000000ff; _tout[15] = (out_blk[3]>>24)&0x000000ff; 
 
 k = 0; 
 for(i=0; i<16; i++) 
    k += (GetIndex(serial[i])-(_tout[i]&0x3f)); 
 return !k; 
} 
//--------------------------------------------------------------------------- 
#endif