个人学习备用档案,高手勿看。
  这是一款国外视频转换软件,可以在AVI/MPEG/VCD/DVD/DAT/VOB之间转换视频文件、分割文件、提取音频或图像。
  如果未注册只能转换文件的一半,开始我被那个大大的注册码框吓倒了,以为注册码很长算法很复杂,就去网上找码子,找了半天也没找着,只好自己干,谁知算法十分的简单,注册机让我轻易地写出来了,这是不是老外和我们开的一个玩笑。
  用字符串参考很快就来到关键点:
00421810  />push    -1
00421812  |>push    0042C5B0                                  ;  SE 处理程序安装
00421817  |>mov     eaxdword ptr fs:[0]
0042181D  |>push    eax
0042181E  |>mov     dword ptr fs:[0], esp
00421825  |>sub     esp, 14
00421828  |>mov     eaxdword ptr [esp+24]                   ;  eax=注册名
0042182C  |>push    ebx
0042182D  |>push    ebp                                       ;  kernel32.GetPrivateProfileStringA
0042182E  |>push    esi
0042182F  |>push    edi
00421830  |>push    eax
00421831  |>lea     ecxdword ptr [esp+18]
00421835  |>call    <jmp.&MFC42.#537_CString::CString>        ;  CString strName=CString(注册名);
0042183A  |>lea     ecxdword ptr [esp+14]
0042183E  |>mov     dword ptr [esp+2C], 0
00421846  |>call    <jmp.&MFC42.#6282_CString::TrimLeft>      ;  去左空格
0042184B  |>lea     ecxdword ptr [esp+14]
0042184F  |>call    <jmp.&MFC42.#6283_CString::TrimRight>     ;  去右空格
00421854  |>push    20
00421856  |>lea     ecxdword ptr [esp+18]
0042185A  |>call    <jmp.&MFC42.#2915_CString::GetBuffer>
0042185F  |>mov     ecxdword ptr [esp+38]                   ;  ecx=注册码
00421863  |>mov     ebxeax                                  ;  ebx=strName.GetBuffer(0x20);
00421865  |>push    ecx
00421866  |>lea     ecxdword ptr [esp+14]
0042186A  |>call    <jmp.&MFC42.#537_CString::CString>        ;  CString strCode=CString(注册码);
0042186F  |>lea     ecxdword ptr [esp+10]
00421873  |>mov     byte ptr [esp+2C], 1
00421878  |>call    <jmp.&MFC42.#6282_CString::TrimLeft>      ;  去左空格
0042187D  |>lea     ecxdword ptr [esp+10]
00421881  |>call    <jmp.&MFC42.#6283_CString::TrimRight>     ;  去右空格
00421886  |>push    20
00421888  |>lea     ecxdword ptr [esp+14]
0042188C  |>call    <jmp.&MFC42.#2915_CString::GetBuffer>
00421891  |>mov     edxeax                                  ;  edx=strCode.GetBuffer(0x20);
00421893  |>or      esi, FFFFFFFF
00421896  |>mov     ediedx
00421898  |>mov     ecxesi
0042189A  |>xor     eaxeax
0042189C  |>mov     dword ptr [esp+20], edx
004218A0  |>repne   scas byte ptr es:[edi]
004218A2  |>not     ecx
004218A4  |>dec     ecx                                       ;  串长
004218A5  |>mov     ediebx
004218A7  |>mov     ebpecx                                  ;  ebp=注册码长度
004218A9  |>mov     ecxesi
004218AB  |>repne   scas byte ptr es:[edi]
004218AD  |>not     ecx                                       ;  串长
004218AF  |>dec     ecx                                       ;  ecx为注册名长度
004218B0  |>cmp     ecxebp                                  ;  比较两串长度
004218B2  |>ja      00421A0C                                  ;  名度不能超过码长
004218B8  |>mov     ediebx
004218BA  |>mov     ecxesi
004218BC  |>repne   scas byte ptr es:[edi]
004218BE  |>not     ecx
004218C0  |>dec     ecx                                       ;  串长
004218C1  |>je      00421A0C                                  ;  名长不能为0
004218C7  |>mov     ediedx
004218C9  |>mov     ecxesi
004218CB  |>repne   scas byte ptr es:[edi]
004218CD  |>not     ecx
004218CF  |>dec     ecx                                       ;  串长
004218D0  |>je      00421A0C                                  ;  码长不能为0
004218D6  |>mov     dword ptr [esp+38], eax                   ;  初始化为NULL
004218DA  |>/mov     edxdword ptr [esp+38]                  ;  计算次数
004218DE  |>|lea     ecxdword ptr [esp+34]
004218E2  |>|mov     albyte ptr [edx+4388A8]                ;  未查到字符时用它
004218E8  |>|mov     byte ptr [esp+18], al
004218EC  |>|call    <jmp.&MFC42.#540_CString::CString>
004218F1  |>|mov     ediebx
004218F3  |>|or      ecx, FFFFFFFF
004218F6  |>|xor     eaxeax
004218F8  |>|xor     ebpebp                                 ;  ebp=0
004218FA  |>|repne   scas byte ptr es:[edi]
004218FC  |>|not     ecx
004218FE  |>|dec     ecx                                      ;  串长
004218FF  |>|mov     byte ptr [esp+2C], 2
00421904  |>|je      short 00421951                           ;  名长是否为0?
00421906  |>|/mov     albyte ptr [ebx+ebp]                  ;  取名的第 EBP 个字符
00421909  |>||xor     esiesi                                ;  esi=0
0042190B  |>||/cmp     albyte ptr [esi*2+438840]
00421912  |>|||je      short 0042191C                         ;  在特定串中找与名的第 EBP 个字符相同的位置
00421914  |>|||inc     esi
00421915  |>|||cmp     esi, 34
00421918  |>||\jl      short 0042190B
0042191A  |>||jmp     short 0042192D
0042191C  |>||mov     clbyte ptr [esi*2+438841]             ;  取注册码字符
00421923  |>||push    ecx
00421924  |>||lea     ecxdword ptr [esp+38]
00421928  |>||call    <jmp.&MFC42.#940_CString::operator+=>   ;  Code+=cl;//连接生成注册码串
0042192D  |>||cmp     esi, 34
00421930  |>||jnz     short 00421940
00421932  |>||mov     edxdword ptr [esp+18]
00421936  |>||lea     ecxdword ptr [esp+34]
0042193A  |>||push    edx
0042193B  |>||call    <jmp.&MFC42.#940_CString::operator+=>   ;  未查到字符的算法
00421940  |>||mov     ediebx
00421942  |>||or      ecx, FFFFFFFF
00421945  |>||xor     eaxeax
00421947  |>||inc     ebp
00421948  |>||repne   scas byte ptr es:[edi]
0042194A  |>||not     ecx
0042194C  |>||dec     ecx                                     ;  串长
0042194D  |>||cmp     ebpecx                                ;  处理到串尾了吗?
0042194F  |>|\jb      short 00421906                          ;  未完继续
00421951  |>|mov     eaxdword ptr [esp+34]                  ;  生成了一个与名长等长的串,为注册码的一部分,记为str1
00421955  |>|mov     ecxdword ptr [eax-8]
00421958  |>|cmp     ecx, 10
0042195B  |>|jge     short 00421997                           ;  串长大于等于16就去比较
0042195D  |>|mov     eaxecx
0042195F  |>|mov     ecx, 10
00421964  |>|sub     ecxeax
00421966  |>|lea     edxdword ptr [esp+1C]
0042196A  |>|push    ecx
0042196B  |>|push    edx
0042196C  |>|mov     ecx, 00438EC4
00421971  |>|call    <jmp.&MFC42.#4129_CString::Left>         ;  取特定字串左边的 16-名长 个字符,记为str2
00421976  |>|push    eax
00421977  |>|lea     ecxdword ptr [esp+38]
0042197B  |>|mov     byte ptr [esp+30], 3
00421980  |>|call    <jmp.&MFC42.#939_CString::operator+=>    ;  注册码=str1+str2
00421985  |>|lea     ecxdword ptr [esp+1C]
00421989  |>|mov     byte ptr [esp+2C], 2
0042198E  |>|call    <jmp.&MFC42.#800_CString::~CString>
00421993  |>|mov     eaxdword ptr [esp+34]
00421997  |>|mov     ecxdword ptr [esp+20]
0042199B  |>|push    ecx                                      ; /你输入的码串
0042199C  |>|push    eax                                      ; |真正的注册码,可做内存注册机
0042199D  |>|call    dword ptr [<&MSVCRT._mbscmp>]            ; \比较注册码是否正确
004219A3  |>|add     esp, 8
004219A6  |>|lea     ecxdword ptr [esp+34]
004219AA  |>|test    eaxeax
004219AC  |>|mov     byte ptr [esp+2C], 1
004219B1  |>|je      short 004219CE                           ;  两串相等就好了,爆破点,jmp就OK了
004219B3  |>|xor     esiesi
004219B5  |>|call    <jmp.&MFC42.#800_CString::~CString>
004219BA  |>|mov     eaxdword ptr [esp+38]
004219BE  |>|inc     eax
004219BF  |>|cmp     eax, 3                                   ;  是否计算了3次
004219C2  |>|mov     dword ptr [esp+38], eax                  ;  计算次数
004219C6  |>\jl      004218DA                                 ;  失败次数小于3,再算一遍,编程者很有耐心啊:)
004219CC  |>jmp     short 004219D8
004219CE  |>mov     esi, 1                                    ;  成功的标志
004219D3  |>call    <jmp.&MFC42.#800_CString::~CString>
004219D8  |>lea     ecxdword ptr [esp+10]
004219DC  |>mov     byte ptr [esp+2C], 0
004219E1  |>call    <jmp.&MFC42.#800_CString::~CString>
004219E6  |>lea     ecxdword ptr [esp+14]
004219EA  |>mov     dword ptr [esp+2C], -1
004219F2  |>call    <jmp.&MFC42.#800_CString::~CString>
004219F7  |>mov     eaxesi                                  ;  成功返回1
004219F9  |>pop     edi
004219FA  |>pop     esi
004219FB  |>pop     ebp
004219FC  |>pop     ebx
004219FD  |>mov     ecxdword ptr [esp+14]
00421A01  |>mov     dword ptr fs:[0], ecx
00421A08  |>add     esp, 20
00421A0B  |>retn
00421A0C  |>lea     ecxdword ptr [esp+10]
00421A10  |>mov     byte ptr [esp+2C], 0
00421A15  |>call    <jmp.&MFC42.#800_CString::~CString>
00421A1A  |>lea     ecxdword ptr [esp+14]
00421A1E  |>mov     dword ptr [esp+2C], esi
00421A22  |>call    <jmp.&MFC42.#800_CString::~CString>
00421A27  |>mov     ecxdword ptr [esp+24]
00421A2B  |>pop     edi
00421A2C  |>pop     esi
00421A2D  |>pop     ebp
00421A2E  |>xor     eaxeax                                  ;  失败返回0
00421A30  |>pop     ebx
00421A31  |>mov     dword ptr fs:[0], ecx
00421A38  |>add     esp, 20
00421A3B  \>retn

  算法:
   1.依次从名字字串中取出一个字符C
   2.在特定字串sss[104]中查找字符C
   3.找到后取该字符紧接着的下一个字符X
   4.把每次找到的字符X连接成与名子长度相等的字串str1
   5.把16-名子长度记为len
   6.取特定字串ss[16]左边len个字符记为串str2
   7.注册码为str1+str2

   如果名子不是英文字母,比如是数字、汉字或标点符号时,可以算出三个注册码,不知为什么要这样?
   如注册名:王仁军
   注册码1:vvvvvvESqNCdaYoD
   注册码2:MMMMMMESqNCdaYoD
   注册码3:wwwwwwESqNCdaYoD
  上边的注册名对应的三个注册码在 power video converter v1.6.2 和 v1.6.6 上注册通过。本软件是用VC++/MFC写的,我也用VC6++写它的注册机:

void CPowervideoconverterDlg::OnChangeName() 
{    CString str;
    GetDlgItemText(IDC_NAME,str);
    str.TrimLeft();
    str.TrimRight();
    SetDlgItemText(IDC_CODE1,GetRegCode(str,0));
    SetDlgItemText(IDC_CODE2,GetRegCode(str,1));
    SetDlgItemText(IDC_CODE3,GetRegCode(str,2));
}

CString CPowervideoconverterDlg::GetRegCode(LPCTSTR lpName,int i)
{
    CString strCode;//注册码
    char str1[]="aGbmcldSemfkgEhcixjsktlYmbnkoDptqarfswtlujvDwIxPyZzXAPBoCKDgEyFmGtHaIrJqKNLQMUNuOGPJQLRnSbTCUFVHWoXwYEZpvMw";
    CString str2("ESqNCdaYoDciekuS");
    char C,N;
    int len=strlen(lpName);
    if(len>16)len=16;
    C=str1[104+i];
    for(int j=0,k;j<len;j++)
    {
        N=lpName[j];
        k=0;
        while(k<0x34)
        {
            if(str1[k<<1]==N)break;
            k++;
        }
        strCode+=(k<0x34)?str1[1+(k<<1)]:C;
    }
    if(len)strCode+=str2.Left(16-len);

    return strCode;
}

  就这么简单,它的注册验证算法效率也很底,是个小孩编的???还是其中有诈???