很郁闷。。。
这是我处女KEYGEN,原本想的挺简单,谁知道弄了我一个晚上,伤心吖。。。 评委组有同情分没?
代码如下:
哈希算法,注册算法,都没什么问题,就是逆回去的时候发现 根本对应不到用户名与注册码。这个程序是把ABCDEFGHJKMNPQRSTVWXYZ1234567890 32个字符的位置对应到一章表(256个字节)上 然后取注册码的字符然后用这个字符做索引在这个表里查询,由于有效就有34个,(算上了0xFF + '='号), 后面有个计算的路径,不过最多的组合就是34 * 34 种算子的组合。 里面各有两个运算, 单个字节是256 ,这样有很大的几率对应不上。
也不多说了。。我把代码贴这里,希望KEYGEN高手可以帮我解答一下。。。 向你们学习。

代码:
#include <stdio.h>
#include <windows.h>

#define __MAX_USERNAME_SIZE__                    35
#define __MAX_SERIAL_NUMBER__                    35

#define __USERNAME_SERIAL_NUMBER_SIZE__            0x5C//92        
BYTE g_UserNameKeyTable[__USERNAME_SERIAL_NUMBER_SIZE__] = {0};
DWORD g_UserNameSerialNumber[5] = {0};
BYTE g_SerialNumber[32] = {0};
BYTE g_KeyTable[256] = {0};
CONST PCHAR g_ValidCharTable = "ABCDEFGHJKMNPQRSTVWXYZ1234567890";
CONST PCHAR g_AnsiTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";

DWORD Bswap(DWORD dwDword) {
    DWORD r = 0;
    __asm {
        mov eax, dwDword
        bswap eax
        mov r, eax
    }
    return r;
}

BYTE Shl(BYTE b, BYTE n) {
    BYTE r = 0;
    __asm {
        mov al, b
        mov cl, n
        shl al, cl
        mov r, al
    }
    return r;
}

BYTE Shr(BYTE b, BYTE n) {
    BYTE r = 0;
    __asm {
        mov al, b
        mov cl, n
        shr al, cl
        mov r, al
    }
    return r;
}

#define __TABLE_1__                    0
#define __TABLE_2__                    64
DWORD dwSwitch = 0;
VOID HashIt(PUCHAR pKeyArray, PUCHAR pUserNameKeyString) {
    DWORD dwKeyX = 0;
    DWORD dwKeyY = 0;
    DWORD dwEbp = 0;//模仿的EBP
    BYTE Table[64 + 256] = {0};//第一张表64字节,第二张表256字节

    // 生成第一章表
    // 第一次循环将pUserNameKeyString指向的内存中的64个字节每
    // 4个字节做反转存入表1
    __asm {
        cld
        xor ecx, ecx
        mov esi, pUserNameKeyString
        lea edi, Table
_make_table_1:
        lodsd
        bswap eax
        stosd
        add ecx, 1
        cmp ecx, 0x10
        jl _make_table_1
    }

    // 生成第二章表
    __asm {
        mov edx, 0x40
        lea eax, [Table + 0x08]
_make_table_2:
        mov ecx, dword ptr [eax + 0x2C]
        xor ecx, dword ptr [eax + 0x18]
        add eax, 4
        xor ecx, dword ptr [eax - 0x0C]
        xor ecx, dword ptr [eax - 0x04]
        rol ecx, 1
        sub edx, 1
        mov dword ptr [eax + 0x34], ecx
        jnz _make_table_2
    }

    // 这里开始计算两个重要的KEY
    __asm {
        mov eax, pKeyArray
        mov edx, dword ptr [eax + 0x04]
        //push ebx
        mov ebx, dword ptr [eax + 0x0C]
        //push ebp
        //push esi
        mov esi, dword ptr [eax + 0x08]
        //push edi
        mov edi, dword ptr [eax]
        mov eax, dword ptr [eax + 0x10]
        mov dwKeyX, eax
        mov dwKeyY, edi
        xor eax, eax
        mov edi, edi
_fuck_loop:
        rol edi, 5
        mov dwEbp, esi
        and dwEbp, edx
        mov ecx, edx
        not ecx
        and ecx, ebx
        xor ecx, dwEbp
        add edi, ecx
        add edi, dword ptr [Table + eax * 4]
        mov ecx, dwKeyX
        lea ecx, dword ptr [edi + ecx + 0x5A827999]
        mov edi, dwKeyY
        mov dwKeyX, ebx
        ror edx, 2
        mov dwKeyY, ecx
        rol ecx, 5
        mov ebx, edi
        not ebx
        and ebx, esi
        mov dwEbp, edx
        and dwEbp, edi
        xor ebx, dwEbp
        add ecx, ebx
        {
            // add ecx, dword ptr [esp + eax * 4 + 0x1C]
            mov dwSwitch, edi
            lea edi, [Table + eax * 4]
            add edi, 0x04
            add ecx, dword ptr [edi]
            mov edi, dwSwitch
        }
        mov ebx, dwKeyX
        lea ecx, dword ptr [ecx + ebx + 0x5A827999]
        ror edi, 2
        mov dwKeyX, esi
        mov ebx, edx
        mov edx, dwKeyY
        mov dwKeyY, ecx
        rol ecx, 5
        mov dwEbp, edi
        and dwEbp, edx
        mov esi, edx
        not esi
        and esi, ebx
        xor esi, dwEbp
        add ecx, esi
        {
            // add ecx, dword ptr [esp + eax * 4 + 0x20]
            mov dwSwitch, edi
            lea edi, [Table + eax * 4]
            add edi, 0x08
            add ecx, dword ptr [edi]
            mov edi, dwSwitch
        }
        mov esi, dwKeyX
        lea ecx, dword ptr [ecx + esi + 0x5A827999]
        mov esi, dwKeyY
        ror edx, 2
        mov dwKeyX, ebx
        mov dwKeyY, ecx
        rol ecx, 5
        mov ebx, esi
        not ebx
        and ebx, edi
        mov dwEbp, edx
        and dwEbp, esi
        xor ebx, dwEbp
        add ecx, ebx
        {
            // add ecx, dword ptr [esp + eax * 4 + 0x24]
            mov dwSwitch, edi
            lea edi, [Table + eax * 4]
            add edi, 0x0C
            add ecx, dword ptr [edi]
            mov edi, dwSwitch
        }
        mov ebx, dwKeyX
        lea ecx, dword ptr [ecx + ebx + 0x5A827999]
        ror esi, 2
        mov dwKeyX, edi
        mov ebx, esi
        mov esi, dwKeyY
        mov edi, esi
        not edi
        and edi, edx
        mov dwKeyY, ecx
        rol ecx, 5
        mov dwEbp, ebx
        and dwEbp, esi
        xor edi, dwEbp
        add ecx, edi
        {
            // add ecx, dword ptr [esp + eax * 4 + 0x28]
            mov dwSwitch, edi
            lea edi, [Table + eax * 4]
            add edi, 0x10
            add ecx, dword ptr [edi]
            mov edi, dwSwitch
        }
        mov edi, dwKeyX
        lea ecx, dword ptr [ecx + edi + 0x5A827999]
        mov dwEbp, edx
        mov edx, dwKeyY
        mov edi, ecx
        add eax, 5 //指针计数增加
        ror esi, 2
        {
            // mov dword ptr [esp + 0x10], ebp
            mov dwSwitch, eax
            mov eax, dwEbp
            mov dwKeyX, eax
            mov eax, dwSwitch
        }
        mov dwKeyY, edi
        cmp eax, 0x14
        jl _fuck_loop
    }

    // 继续计算KEY
    __asm {
_fuck_loop2:
        mov dwEbp, ebx
        xor dwEbp, esi
        xor dwEbp, edx
        rol ecx, 5
        add ecx, dwEbp
        add ecx, dword ptr [Table + eax * 4]
        {
            // mov ebp, dwKeyX
            mov dwSwitch, eax
            mov eax, dwKeyX
            mov dwEbp, eax
            mov eax, dwSwitch
        }
        {
            // lea ecx, dword ptr [ecx + ebp + 0x6ED9EBA1]
            mov dwSwitch, eax
            mov eax, dwEbp
            lea ecx, dword ptr [ecx + eax + 0x6ED9EBA1]
            mov eax, dwSwitch
        }
        ror edx, 2
        mov dwEbp, ebx
        mov ebx, esi
        add eax, 1    // 移动指针
        cmp eax, 0x28
        mov esi, edx
        mov edx, edi
        {
            // mov dwKeyX, ebp
            mov dwSwitch, eax
            mov eax, dwEbp
            mov dwKeyX, eax
            mov eax, dwSwitch
        }
        mov edi, ecx
        jl _fuck_loop2
    }

    // 单独设置一下KeyY
    __asm {
        mov dwKeyY, ecx
    }

    // 继续
    __asm {
_fuck_loop3:
        mov edi, esi
        xor edi, edx
        and edi, ebx
        mov dwEbp, esi
        and dwEbp, edx
        rol ecx, 5
        add ecx, dwKeyX
        xor edi, dwEbp
        add edi, dword ptr [Table + eax * 4]
        ror edx, 2
        mov dwEbp, ebx
        mov ebx, esi
        add eax, 1
        cmp eax, 0x3C
        lea ecx, dword ptr [edi + ecx + 0x8F1BBCDC]
        mov esi, edx
        mov edx, dwKeyY
        {
            // mov dwKeyX, ebp
            mov dwSwitch, eax
            mov eax, dwEbp
            mov dwKeyX, eax
            mov eax, dwSwitch
        }
        mov dwKeyY, ecx
        jl _fuck_loop3
    }

    // 还有
    __asm {
_fuck_loop4:
        mov edi, ebx
        xor edi, esi
        rol ecx, 5
        xor edi, edx
        add edi, dword ptr [Table + eax * 4]
        add ecx, dwEbp
        ror edx, 2
        mov dwEbp, ebx
        mov ebx, esi
        add eax, 1
        cmp eax, 0x50
        lea ecx, [edi + ecx + 0xCA62C1D6]
        mov esi, edx
        mov edx, dwKeyY
        mov dwKeyY, ecx
        jl _fuck_loop4
    }

    // 输出结果
    __asm {
        mov eax, pKeyArray
        mov edi, dword ptr [eax]
        add edi, ecx
        mov ecx, dword ptr [eax + 0x04]
        add ecx, edx
        mov dword ptr [eax + 0x04], ecx
        mov ecx, dword ptr [eax + 0x08]
        add ecx, esi
        mov dword ptr [eax + 0x08], ecx
        mov ecx, dword ptr [eax + 0x0C]
        add ecx, ebx
        mov dword ptr [eax], edi
        mov dword ptr [eax + 0x0C], ecx
        mov ecx, dword ptr [eax + 0x10]
        add ecx, dwEbp
        mov dword ptr [eax + 0x10], ecx
    }
    return;
}

VOID ShowSign() {
    DWORD dwSign = 0;
    int i = 0;

    do {
        dwSign += 0xFFFFFFFD;
        dwSign &= 7;
        printf("%d ", dwSign);
        if ((i != 0) && (i % 0x10 == 0))
            printf("\r\n");
        i++;
    } while (i < 0x20);
}

// 注册算法
VOID SerialNumberGen(PCHAR pSerialNumberString) {
    DWORD dwSign = 0;
    int i = 0, j = 0;
    DWORD n = 0;
    BYTE ch = 0, ch2 = 0;
    
    do {
        // 读取一个字符
        ch = pSerialNumberString[i];
        ch = g_KeyTable[ch];

        if (dwSign <= 3) {
            dwSign += 0xFFFFFFFD;
            dwSign &= 7;
            if (dwSign == 0) {
                g_SerialNumber[j] |= ch;
                j++;
            } else {
                n = 8 - dwSign;
                ch = Shl(ch, (BYTE)n);
                g_SerialNumber[j] |= ch;
            }
        } else {
            dwSign += 0xFFFFFFFD;
            dwSign &= 7;
            ch2 = ch;
            n = (BYTE)dwSign;
            ch2 = Shr(ch2, (BYTE)n);
            g_SerialNumber[j] |= ch2;
            j++;
            // 设置下一个字节
            n = 8 - dwSign;
            ch = Shl(ch, (BYTE)n);
            g_SerialNumber[j] |= ch;
        }
        i++;
    } while (i < 0x20);
}


/*
 * 最多 34 * 34 种组合的值,不能满足所有用户名的需求
 */
// 逆向注册算法
// 流程处理到5, 2 ,7, 4, 1, 6, 3, 0其余做同样的循环
CONST BYTE g_ReverseSign[33] = {//由ShowSign得出
    "\x05\x02\x07\x04\x01\x06\x03\x00\x05\x02\x07\x04\x01\x06\x03\x00"
    "\x05\x02\x07\x04\x01\x06\x03\x00\x05\x02\x07\x04\x01\x06\x03\x00"
};
VOID ReverseSerialNumberGen(PUCHAR pSerialNumber, PCHAR pSerialNumberString) {
    CHAR ch = 0, ch2 = 0, x = 0, y = 0, z = 0, result = 0;
    BYTE _ch = 0, _ch2 = 0, _c = 0;
    int i = 0, j = 0;
    int n = 0, m = 0;

    for (n = 0; n < 20; n+=5) {
        // 0, 5, 2-
        result = pSerialNumber[n];
        for (i = 0; i < 36; i++) {
            ch = g_AnsiTable[i];
            _ch = g_KeyTable[ch];
            _ch = Shl(_ch, 8 - 5);
            x |= _ch;
            y = x;
            for (j = 0; j < 36; j++) {
                ch2 = g_AnsiTable[j];
                _ch2 = g_KeyTable[ch2];
                _c = _ch2;
                _ch2 = Shr(_ch2, 2);
                x |= _ch2;
                if (x == result) {
                    pSerialNumberString[m++] = ch;
                    pSerialNumberString[m++] = ch2;
                    goto _byte_2;
                }
                x = y;
            }/* end for */
            x = 0;
        }

_byte_2:
        // -2, 7, 4-
        x = 0;
        result = pSerialNumber[n+1];
        _c = Shl(_c, 8 - 2);
        x |= _c;
        z = x;

        for (i = 0; i < 36; i++) {
            ch = g_AnsiTable[i];
            _ch = g_KeyTable[ch];
            _ch = Shl(_ch, 8 - 7);
            x |= _ch;
            y = x;
            for (j = 0; j < 36; j++) {
                ch2 = g_AnsiTable[j];
                _ch2 = g_KeyTable[ch2];
                _c = _ch2;
                _ch2 = Shr(_ch2, 4);
                x |= _ch2;
                if (x == result) {
                    pSerialNumberString[m++] = ch;
                    pSerialNumberString[m++] = ch2;
                    goto _byte_3;
                }
                x = y;
            }/* end for */
            x = z;
        }

_byte_3:
        // -4, 1-
        x = 0;
        result = pSerialNumber[n+2];
        _c = Shl(_c, 8 - 4);
        x |= _c;
        z = x;

        for (i = 0; i < 36; i++) {
            ch = g_AnsiTable[i];
            _ch = g_KeyTable[ch];
            _c = _ch;
            _ch = Shr(_ch, 1);
            x |= _ch;
            if (x == result) {
                pSerialNumberString[m++] = ch;
                goto _byte_4;
            }
            x = z;
        }

_byte_4:
        // -1, 6, 3-
        x = 0;
        result = pSerialNumber[n+3];
        _c = Shl(_c, 8 - 1);
        x |= _c;
        z = x;

        for (i = 0; i < 36; i++) {
            ch = g_AnsiTable[i];
            _ch = g_KeyTable[ch];
            _ch = Shl(_ch, 8 - 6);
            x |= _ch;
            y = x;
            for (j = 0; j < 36; j++) {
                ch2 = g_AnsiTable[j];
                _ch2 = g_KeyTable[ch2];
                _c = _ch2;
                _ch2 = Shr(_ch2, 3);
                x |= _ch2;
                if (x == result) {
                    pSerialNumberString[m++] = ch;
                    pSerialNumberString[m++] = ch2;
                    goto _byte_5;
                }
                x = y;
            }
            x = z;
        }

_byte_5:
        // -3, 0
        x = 0;
        result = pSerialNumber[n+4];
        _c = Shl(_c, 8 - 3);
        x |= _c;
        z = x;

        for (i = 0; i < 36; i++) {
            ch = g_AnsiTable[ch];
            _ch = g_KeyTable[i];
            x |= _ch;
            if (x == result) {
                pSerialNumberString[m++] = ch;
                goto _next_turn;
            }
            x = z;
        }
_next_turn:
        ;
    }/* end for */
}

// 生成注册字符表
VOID MakeValidCharTable() {
    int i = 0;
    CHAR ch = '=';
    memset(g_KeyTable, 0xFF, 256);
    do {
        ch = g_ValidCharTable[i];
        g_KeyTable[ch] = i;
        i++;
    } while (i < 0x20);
    g_KeyTable[0x3D] = 0x20;//i
}

/*
 * 感觉最后逆注册算法上算子组合的有很大可能碰不到用户名生成的HASH值
 * 最后只有34种可能32个有效字符 + 0xFF + 0x20,但是可能有些路径上
 * 只有34种单一的选择,至少我的KEYGEN能力到这里了。
 * 哈希算法正确,注册算法正确,生表算法正确,最后的逆运算应该也没错,
 * 不知道神人们是怎么弄出来的,多多向你们学习。
 */
int main() {
    DWORD VolumeSerialNumber = 0;
    DWORD dwMagicLen = 0;
    DWORD dwTmp = 0;
    CHAR UserName[__MAX_USERNAME_SIZE__ + 1] = {0};
    CHAR SerialNumber[__MAX_SERIAL_NUMBER__ + 1] = {0};
    CHAR Command[64] = {0};
    int Len = 0;
    PUCHAR pKeyArray = NULL;
    PUCHAR pUserNameKeyString = NULL;
    int i = 0;

    //ShowSign();

    printf("输入用户名(最长35个字节):");
    fgets(Command, 64, stdin);
    Len = strlen(Command);
    Len--;
    Command[Len] = '\0';
    strcpy(UserName, Command);

    // 获取C盘序列号
    GetVolumeInformationA("C:\\", \
                          0, \
                          0, \
                          &VolumeSerialNumber, \
                          0, \
                          0, \
                          0, \
                          0);

    // 通过长度获取值
    dwMagicLen = (Len + 11) * 8;
    dwMagicLen = Bswap(dwMagicLen);

    // 开始设置表
    memset(g_UserNameKeyTable, 0, __USERNAME_SERIAL_NUMBER_SIZE__);
    memcpy(g_UserNameKeyTable + 0x00, "\x00\x20\x00\x00\x00\x00\x00\x00", 8);
    memcpy(g_UserNameKeyTable + 0x08, "\xCA\xB1\xCA\xB1", 4);
    memcpy(g_UserNameKeyTable + 0x0C, "\xBF\xCC\xBF\xCC", 4);
    memcpy(g_UserNameKeyTable + 0x10, "\xBE\xD6\xB2\xBF", 4);
    memcpy(g_UserNameKeyTable + 0x14, "\xB5\xD8\xC7\xF8", 4);
    memcpy(g_UserNameKeyTable + 0x18, "\xCD\xBC\xC7\xEE", 4);
    memcpy(g_UserNameKeyTable + 0x1C, UserName, Len);
    memcpy(g_UserNameKeyTable + 0x1C + Len, &VolumeSerialNumber, 4);
    memcpy(g_UserNameKeyTable + 0x1C + Len + 4, "Tencent", 7);
    memcpy(g_UserNameKeyTable + 0x1C + Len + 4 + 7, "\x80\x00\x00\x00", 4);
    memcpy(g_UserNameKeyTable + 0x58, &dwMagicLen, 4);

    // 将这个数据传人哈希算法
    pKeyArray = (g_UserNameKeyTable + 0x08);
    pUserNameKeyString = (g_UserNameKeyTable + 0x1C);
    HashIt(pKeyArray, pUserNameKeyString);
    // 将得到的哈希值每个都经过一次翻转, 总共20个字节
    for (i = 0; i < 5; i++) {
        dwTmp = *((PDWORD)pKeyArray + i);
        g_UserNameSerialNumber[i] = Bswap(dwTmp);
    }
    
    // 通过用户名的哈希值算出注册码
    MakeValidCharTable();//生成有效字符表
    ReverseSerialNumberGen((PUCHAR)g_UserNameSerialNumber, SerialNumber);
    printf("Serial Number = %C%C%C%C%C%C%C%C-%C%C%C%C%C%C%C%C-%C%C%C%C%C%C%C%C-%C%C%C%C%C%C%C%C\r\n", \
            SerialNumber[0], SerialNumber[1], SerialNumber[2], SerialNumber[3], \
            SerialNumber[4], SerialNumber[5], SerialNumber[6], SerialNumber[7], \
            SerialNumber[8], SerialNumber[9], SerialNumber[10], SerialNumber[11], \
            SerialNumber[12], SerialNumber[13], SerialNumber[14], SerialNumber[15], \
            SerialNumber[16], SerialNumber[17], SerialNumber[18], SerialNumber[19], \
            SerialNumber[20], SerialNumber[21], SerialNumber[22], SerialNumber[23], \
            SerialNumber[24], SerialNumber[25], SerialNumber[26], SerialNumber[27], \
            SerialNumber[28], SerialNumber[29], SerialNumber[30], SerialNumber[31]);

    //SerialNumberGen("FFFFFFFF-FFFFFFFF-FFFFFFFF-FFFFFFFF");

    fgetc(stdin);
    // 打印最终结果
    return 0;
}

  • 标 题:答复
  • 作 者:accessd
  • 时 间:2010-10-25 16:48:06

其实不需要汇编代码的
SHA1 直接用openssl库就行了

#include <openssl/sha.h>

#pragma comment (lib,"libeay32.lib")

#define SWAPDWORD(x) (((x)<<24) | (((x)<<8)&0x00FF0000) | (((x)>>8) & 0x0000FF00) | ((x)>>24))


void GetHash(const char* pszUserName, BYTE* pHash)
{
  DWORD dwVolumeSerialNumber = 0;
  GetVolumeInformation("c:\\", NULL, 0, &dwVolumeSerialNumber, NULL, NULL, NULL, 0);
  
  int nLen = strlen(pszUserName);
  BYTE* pData = new BYTE[nLen + 16];
  memcpy(pData, pszUserName, nLen);
  memcpy(pData+nLen, &dwVolumeSerialNumber, 4);
  memcpy(pData+nLen+4, "Tencent", 7);
  
  
  SHA_CTX c;
  unsigned long h[] = {
      0xB1CAB1CA, 
      0xCCBFCCBF, 
      0xBFB2D6BE, 
      0xF8C7D8B5, 
      0xEEC7BCCD};
    
  unsigned char byte_40CD50[0x80] = {0};
  byte_40CD50[0] = byte_40CD50[0x48] = 0x80;
  byte_40CD50[0x40] = 0x3d;
  
  
  SHA1_Init(&c);
  c.h0 = h[0];
  c.h1 = h[1];
  c.h2 = h[2];
  c.h3 = h[3];
  c.h4 = h[4];
  
  SHA1_Update(&c, pData, nLen+4+7);
  
  delete[] pData;
  pData = NULL;
  
  DWORD xlen[2];
  xlen[0] = SWAPDWORD(c.Nh);
  xlen[1] = SWAPDWORD(c.Nl);
  
  int n1 = (c.Nl >> 3) & 0x3F;
  int n2 = 56;
  if ( (unsigned int)n1 >= 0x38 )
    n2 = 120;
  
  SHA1_Update(&c, byte_40CD50, n2-n1);
  SHA1_Update(&c, xlen, 8);
  
  DWORD* hash = (DWORD*)pHash;
  hash[0] = SWAPDWORD(c.h0);
  hash[1] = SWAPDWORD(c.h1);
  hash[2] = SWAPDWORD(c.h2);
  hash[3] = SWAPDWORD(c.h3);
  hash[4] = SWAPDWORD(c.h4);
}

void HashToData(BYTE* pHash, BYTE* pData)
{
  int i;
  int j;
  BYTE bits[20*8];
  for(i=0; i<20; i++)
  {
    for(j=0; j<8; j++)
    {
      bits[i*8+7-j] = (pHash[i]>>j)&1;
    }
  }

  for(i=0; i<32; i++)
  {
    for(j=0; j<5; j++)
    {
      pData[i] |= bits[i*5+j] << (4-j);
    }
  }
}

void DataToCode(BYTE* pData, char* pszCode)
{
  char* pstr = "ABCDEFGHJKMNPQRSTVWXYZ1234567890";
  int i;
  for(i=0; i<32; i++)
  {
    pszCode[i] = pstr[pData[i]];
  }
}

void Keygen(const char* pszUserName, char* pszLicenseCode)
{
  BYTE cbHash[20];
  BYTE cbData[32];
  GetHash(pszUserName, cbHash);

  memset(cbData, 0, sizeof(cbData));
  HashToData(cbHash, cbData);

  char szCode[64] = {0};
  DataToCode(cbData, szCode);

  pszLicenseCode[8] = pszLicenseCode[0x11] = pszLicenseCode[0x1a] = '-';
  memcpy(pszLicenseCode, szCode, 8);
  memcpy(pszLicenseCode+9, szCode+8, 8);
  memcpy(pszLicenseCode+0x12, szCode+16, 8);
  memcpy(pszLicenseCode+0x1b, szCode+24, 8);
}

void CKeygenDlg::OnGen() 
{
  CString sUserName;
  GetDlgItemText(IDC_EDIT_USERNAME, sUserName);
  if(sUserName.IsEmpty())
  {
    SetDlgItemText(IDC_EDIT_LIC_CODE, NULL);
    GetDlgItem(IDC_EDIT_USERNAME)->SetFocus();
    return;
  }

  char szLicenseCode[128];
  memset(szLicenseCode, 0, sizeof(szLicenseCode));
  Keygen(sUserName, szLicenseCode);

  SetDlgItemText(IDC_EDIT_LIC_CODE, szLicenseCode);
}