逆向Keygen for Matlab R14


很想知道Matlab的注册算法,不过自己去跟Matlab难度太大,还是分析现成的keygen来得快。
TEAM ROR在很久以前曾经出过几个Matlab的keygen,分别对应Matlab v7.0,v7.01,v7.1。
我选择了Keygen for Matlab R14(for v7.1)动手。废话少说,开始工作。

1、查壳
UPX 0.71 - 0.72 -> Markus & Laszlo
手动脱壳,轻松搞定。

2、脱壳后检查
Microsoft Visual C++ 6.0
没有使用任何密码学算法。

3、找注册码生成函数
IDA加载,分析完成后搜索字符串“14”,找到一处。该处的函数正是生成注册码的关键函数:

--------------------------------------------------------------------------------

UPX0:00407890 GenerateKey     proc near               ; CODE XREF: sub_407470+1E8p
UPX0:00407890                                         ; UPX0:00407880j
UPX0:00407890
UPX0:00407890 szTemp          = byte ptr -1020h
UPX0:00407890 szSerial        = dword ptr -1000h
UPX0:00407890
UPX0:00407890                 mov     eax, 1020h
UPX0:00407895                 call    __alloca_probe
UPX0:0040789A                 push    ebx
UPX0:0040789B                 push    ebp
UPX0:0040789C                 push    esi
UPX0:0040789D                 push    edi
UPX0:0040789E                 mov     ebp, ecx
UPX0:004078A0                 mov     szBuf, 62h
UPX0:004078A7                 mov     byte_412215, 9
UPX0:004078AE                 call    GetTickCount
UPX0:004078B4                 mov     esi, eax
UPX0:004078B6                 call    rand
UPX0:004078BC                 imul    esi, eax
UPX0:004078BF                 mov     word_412216, si
UPX0:004078C6                 mov     byte ptr dword_412218, 33h
UPX0:004078CD                 mov     byte ptr dword_412218+1, 0
UPX0:004078D4                 call    func1           ; 这是一个关键call,比较简单
UPX0:004078D9                 call    func4           ; 这也是一个关键call,稍微复杂一些
UPX0:004078DE                 lea     eax, [esp+1030h+szSerial]
UPX0:004078E2                 push    offset a14      ; "14"
UPX0:004078E7                 push    eax
UPX0:004078E8                 call    lstrcpy
UPX0:004078EE                 mov     ebx, wsprintfA
UPX0:004078F4                 mov     edi, lstrcat
UPX0:004078FA                 mov     esi, offset szBuf
UPX0:004078FF
UPX0:004078FF loc_4078FF:                             ; CODE XREF: GenerateKey+AEj
UPX0:004078FF                 push    esi
UPX0:00407900                 call    func5           ; 这个函数比较简单
UPX0:00407905                 add     esp, 4
UPX0:00407908                 and     eax, 0FFFFh
UPX0:0040790D                 lea     ecx, [esp+1030h+szTemp]
UPX0:00407911                 push    eax
UPX0:00407912                 push    offset a05lu    ; "%05lu"
UPX0:00407917                 push    ecx             ; LPSTR
UPX0:00407918                 call    ebx ; wsprintfA
UPX0:0040791A                 add     esp, 0Ch
UPX0:0040791D                 lea     edx, [esp+1030h+szSerial]
UPX0:00407921                 push    offset asc_412060 ; "-"
UPX0:00407926                 push    edx
UPX0:00407927                 call    edi ; lstrcat
UPX0:00407929                 lea     eax, [esp+1030h+szTemp]
UPX0:0040792D                 lea     ecx, [esp+1030h+szSerial]
UPX0:00407931                 push    eax
UPX0:00407932                 push    ecx
UPX0:00407933                 call    edi ; lstrcat
UPX0:00407935                 add     esi, 2
UPX0:00407938                 cmp     esi, offset word_41226A
UPX0:0040793E                 jb      short loc_4078FF
UPX0:00407940                 lea     edx, [esp+1030h+szSerial]
UPX0:00407944                 lea     ecx, [ebp+9D8h]
UPX0:0040794A                 push    edx
UPX0:0040794B                 call    CWnd::SetWindowTextA(char const *)
UPX0:00407950                 pop     edi
UPX0:00407951                 pop     esi
UPX0:00407952                 pop     ebp
UPX0:00407953                 pop     ebx
UPX0:00407954                 add     esp, 1020h
UPX0:0040795A                 retn
UPX0:0040795A GenerateKey     endp

这个函数不太复杂,其中只有3个未知函数需要继续分析。逆向出来的cpp代码如下:

--------------------------------------------------------------------------------

unsigned char szBuf[87] = {0};

void CKeyGenDlg::OnGenerate() 
{
  char szSerial[1024] = {0};
  char szTemp[32] = {0};
  unsigned long  dw = 0;

  szBuf[0] = 0x62;
  szBuf[1] = 0x09;
  dw = GetTickCount() * rand();
  szBuf[2] = (char)(dw & 0xFF);
  szBuf[3] = (char)((dw >> 8) & 0xFF);
  szBuf[4] = 0x33;
  szBuf[5] = 0x0;

  func1();
  func4();
  
  lstrcpy( szSerial, "14" );
  
  int  i = 0;
  while( i < 85 )
  {
    wsprintf( szTemp, "%05lu", func5(szBuf+i)&0xFFFF );
    lstrcat( szSerial, "-" );
    lstrcat( szSerial, szTemp );
    i += 2;
  }
  
  SetDlgItemText( IDC_SERIAL, szSerial );
}

--------------------------------------------------------------------------------

下面是func1()的汇编代码,由3个独立的循环组成,也不是很复杂。

UPX0:00407170 func1           proc near               ; CODE XREF: GenerateKey+44p
UPX0:00407170
UPX0:00407170 var_A80         = dword ptr -0A80h
UPX0:00407170 var_A00         = dword ptr -0A00h
UPX0:00407170
UPX0:00407170                 sub     esp, 0A80h
UPX0:00407176                 mov     ecx, 4
UPX0:0040717B                 mov     [esp+0A80h+var_A80], 1F1F1F1Fh
UPX0:00407183                 mov     edx, ecx
UPX0:00407185
UPX0:00407185 loc_407185:                             ; CODE XREF: func1+26j
UPX0:00407185                 mov     eax, 1
UPX0:0040718A
UPX0:0040718A loc_40718A:                             ; CODE XREF: func1+23j
UPX0:0040718A                 mov     byte ptr [esp+ecx+0A80h+var_A80], al
UPX0:0040718E                 inc     ecx
UPX0:0040718F                 inc     eax
UPX0:00407190                 cmp     eax, 31
UPX0:00407193                 jle     short loc_40718A
UPX0:00407195                 dec     edx
UPX0:00407196                 jnz     short loc_407185
UPX0:00407198                 push    ebx
UPX0:00407199                 push    ebp
UPX0:0040719A                 push    esi
UPX0:0040719B                 push    edi
UPX0:0040719C                 xor     ebp, ebp
UPX0:0040719E                 lea     edi, [esp+0A90h+var_A00]
UPX0:004071A5
UPX0:004071A5 loc_4071A5:                             ; CODE XREF: func1+60j
UPX0:004071A5                 xor     eax, eax
UPX0:004071A7                 mov     edx, 4
UPX0:004071AC                 mov     al, byte ptr [esp+ebp+0A90h+var_A80]
UPX0:004071B0                 mov     esi, eax
UPX0:004071B2                 mov     eax, edi
UPX0:004071B4                 add     edi, 20
UPX0:004071B7
UPX0:004071B7 loc_4071B7:                             ; CODE XREF: func1+57j
UPX0:004071B7                 mov     ebx, esi
UPX0:004071B9                 mov     cl, dl
UPX0:004071BB                 shr     ebx, cl
UPX0:004071BD                 add     eax, 4
UPX0:004071C0                 and     ebx, 1
UPX0:004071C3                 dec     edx
UPX0:004071C4                 mov     [eax-4], ebx
UPX0:004071C7                 jns     short loc_4071B7
UPX0:004071C9                 inc     ebp
UPX0:004071CA                 cmp     ebp, 128
UPX0:004071D0                 jl      short loc_4071A5
UPX0:004071D2                 xor     edx, edx
UPX0:004071D4                 xor     eax, eax
UPX0:004071D6                 lea     ebp, [esp+0A90h+var_A00]
UPX0:004071DD
UPX0:004071DD loc_4071DD:                             ; CODE XREF: func1+9Bj
UPX0:004071DD                 mov     esi, ebp
UPX0:004071DF                 mov     [eax+41221Ah], dl
UPX0:004071E5                 mov     edi, 7
UPX0:004071EA                 add     ebp, 32
UPX0:004071ED
UPX0:004071ED loc_4071ED:                             ; CODE XREF: func1+95j
UPX0:004071ED                 mov     bl, [esi]
UPX0:004071EF                 mov     ecx, edi
UPX0:004071F1                 shl     bl, cl
UPX0:004071F3                 mov     cl, [eax+41221Ah]
UPX0:004071F9                 add     esi, 4
UPX0:004071FC                 or      cl, bl
UPX0:004071FE                 dec     edi
UPX0:004071FF                 mov     [eax+41221Ah], cl
UPX0:00407205                 jns     short loc_4071ED
UPX0:00407207                 inc     eax
UPX0:00407208                 cmp     eax, 80
UPX0:0040720B                 jl      short loc_4071DD
UPX0:0040720D                 pop     edi
UPX0:0040720E                 pop     esi
UPX0:0040720F                 pop     ebp
UPX0:00407210                 pop     ebx
UPX0:00407211                 add     esp, 0A80h
UPX0:00407217                 retn
UPX0:00407217 func1           endp

--------------------------------------------------------------------------------

void func1()
{
  int  i, j;
  char szA00[2560] = {0};
  char szA80[128] = {0};
  char *p, *p1, c, d;
  unsigned long  dw;

  szA80[0] = 0x1F;
  szA80[1] = 0x1F;
  szA80[2] = 0x1F;
  szA80[3] = 0x1F;

  for( i=0; i<4; i++ )
  {
    for( j=1; j<32; j++ )
    {
      szA80[i*31+j+3] = j;
    }
  }

  p = szA00;
  for( i=0; i<128; i++ )
  {
    c = szA80[i];
    p1 = p;
    p += 20;
    for( j=4; j>=0; j-- )
    {
      dw = c;
      dw = dw>>j;
      dw = dw & 1;
      memcpy( p1, (char*)&dw, 4 );
      p1 += 4;
    }
  }
  
  p = szA00;
  for( i=0; i<80; i++ )
  {
    p1 = p;
    p += 32;
    szBuf[6+i] = 0;
    for( j=7; j>=0; j-- )
    {
      c = *p1;
      p1 += 4;
      c = c<<j;
      d = szBuf[6+i];
      szBuf[6+i] = d|c;
    }
  }
}

--------------------------------------------------------------------------------

这是func2()的反汇编代码,作用是将连续4个字节转化为一个32位的无符号整数。

UPX0:00407040 func2           proc near               ; CODE XREF: func4+1Bp
UPX0:00407040                                         ; func4+23p
UPX0:00407040
UPX0:00407040 arg_0           = dword ptr  4
UPX0:00407040
UPX0:00407040                 mov     ecx, [esp+arg_0]
UPX0:00407044                 xor     edx, edx
UPX0:00407046                 movsx   eax, byte ptr [ecx]
UPX0:00407049                 mov     dl, [ecx+1]
UPX0:0040704C                 shl     eax, 8
UPX0:0040704F                 or      eax, edx
UPX0:00407051                 xor     edx, edx
UPX0:00407053                 mov     dl, [ecx+2]
UPX0:00407056                 shl     eax, 8
UPX0:00407059                 or      eax, edx
UPX0:0040705B                 xor     edx, edx
UPX0:0040705D                 mov     dl, [ecx+3]
UPX0:00407060                 shl     eax, 8
UPX0:00407063                 or      eax, edx
UPX0:00407065                 retn
UPX0:00407065 func2           endp

--------------------------------------------------------------------------------

unsigned long func2( unsigned char *p )
{
  unsigned long  dw = 0;
  dw = *p;
  dw = (dw<<8) + *(p+1);
  dw = (dw<<8) + *(p+2);
  dw = (dw<<8) + *(p+3);
  return dw;
}

--------------------------------------------------------------------------------
这是func3()的反汇编代码,作用是将一个32位的无符号整数转化为连续4个字节。

UPX0:00407070 func3           proc near               ; CODE XREF: func4+8Dp
UPX0:00407070                                         ; func4+9Ep
UPX0:00407070
UPX0:00407070 arg_0           = dword ptr  4
UPX0:00407070 arg_4           = dword ptr  8
UPX0:00407070
UPX0:00407070                 mov     eax, [esp+arg_0]
UPX0:00407074                 mov     ecx, [esp+arg_4]
UPX0:00407078                 mov     edx, eax
UPX0:0040707A                 shr     edx, 24
UPX0:0040707D                 mov     [ecx], dl
UPX0:0040707F                 mov     edx, eax
UPX0:00407081                 shr     edx, 16
UPX0:00407084                 mov     [ecx+1], dl
UPX0:00407087                 mov     edx, eax
UPX0:00407089                 shr     edx, 8
UPX0:0040708C                 mov     [ecx+2], dl
UPX0:0040708F                 mov     [ecx+3], al
UPX0:00407092                 retn
UPX0:00407092 func3           endp

--------------------------------------------------------------------------------

void func3( unsigned char *p, unsigned long dw )
{
  *p     = (unsigned char)((dw>>24) & 0xFF);
  *(p+1) = (unsigned char)((dw>>16) & 0xFF);
  *(p+2) = (unsigned char)((dw>>8 ) & 0xFF);
  *(p+3) = (unsigned char)( dw      & 0xFF);
}

--------------------------------------------------------------------------------

这个函数稍微有点麻烦,它还要用到一个常数表。

UPX0:004070B0 func4           proc near               ; CODE XREF: GenerateKey+49p
UPX0:004070B0
UPX0:004070B0 var_8           = dword ptr -8
UPX0:004070B0 var_4           = dword ptr -4
UPX0:004070B0
UPX0:004070B0                 sub     esp, 8
UPX0:004070B3                 push    ebx
UPX0:004070B4                 push    ebp
UPX0:004070B5                 push    esi
UPX0:004070B6                 xor     esi, esi
UPX0:004070B8                 push    edi
UPX0:004070B9                 mov     [esp+18h+var_8], esi
UPX0:004070BD
UPX0:004070BD loc_4070BD:                             ; CODE XREF: func4+AEj
UPX0:004070BD                 lea     edi, dword_412218[esi]
UPX0:004070C3                 lea     eax, [edi-4]
UPX0:004070C6                 push    eax
UPX0:004070C7                 mov     [esp+1Ch+var_4], eax
UPX0:004070CB                 call    func2
UPX0:004070D0                 push    edi
UPX0:004070D1                 mov     esi, eax
UPX0:004070D3                 call    func2
UPX0:004070D8                 mov     ecx, dword_40EF5C
UPX0:004070DE                 mov     edi, eax
UPX0:004070E0                 mov     eax, dword_40EF58
UPX0:004070E5                 add     esp, 8
UPX0:004070E8                 add     edi, ecx
UPX0:004070EA                 mov     edx, offset dword_40EF60
UPX0:004070EF                 add     esi, eax
UPX0:004070F1                 mov     ebx, 10
UPX0:004070F6
UPX0:004070F6 loc_4070F6:                             ; CODE XREF: func4+85j
UPX0:004070F6                 mov     eax, edi
UPX0:004070F8                 xor     esi, edi
UPX0:004070FA                 and     eax, 31
UPX0:004070FD                 mov     ecx, 32
UPX0:00407102                 sub     ecx, eax
UPX0:00407104                 mov     ebp, esi
UPX0:00407106                 shr     ebp, cl
UPX0:00407108                 mov     ecx, eax
UPX0:0040710A                 mov     eax, [edx]
UPX0:0040710C                 shl     esi, cl
UPX0:0040710E                 mov     ecx, 32
UPX0:00407113                 add     edx, 8
UPX0:00407116                 or      ebp, esi
UPX0:00407118                 add     ebp, eax
UPX0:0040711A                 mov     esi, ebp
UPX0:0040711C                 mov     eax, esi
UPX0:0040711E                 xor     edi, esi
UPX0:00407120                 and     eax, 31
UPX0:00407123                 mov     ebp, edi
UPX0:00407125                 sub     ecx, eax
UPX0:00407127                 shr     ebp, cl
UPX0:00407129                 mov     ecx, eax
UPX0:0040712B                 shl     edi, cl
UPX0:0040712D                 or      ebp, edi
UPX0:0040712F                 mov     edi, [edx-4]
UPX0:00407132                 add     edi, ebp
UPX0:00407134                 dec     ebx
UPX0:00407135                 jnz     short loc_4070F6
UPX0:00407137                 mov     eax, [esp+18h+var_4]
UPX0:0040713B                 push    eax
UPX0:0040713C                 push    esi
UPX0:0040713D                 call    func3
UPX0:00407142                 mov     esi, [esp+20h+var_8]
UPX0:00407146                 lea     eax, dword_412218[esi]
UPX0:0040714C                 push    eax
UPX0:0040714D                 push    edi
UPX0:0040714E                 call    func3
UPX0:00407153                 add     esp, 10h
UPX0:00407156                 inc     esi
UPX0:00407157                 cmp     esi, 78
UPX0:0040715A                 mov     [esp+18h+var_8], esi
UPX0:0040715E                 jbe     loc_4070BD
UPX0:00407164                 pop     edi
UPX0:00407165                 pop     esi
UPX0:00407166                 pop     ebp
UPX0:00407167                 pop     ebx
UPX0:00407168                 add     esp, 8
UPX0:0040716B                 retn
UPX0:0040716B func4           endp

--------------------------------------------------------------------------------

void func4()
{
  unsigned int  i, j, k;
  unsigned long  data[22] = { 0x5F9C979BUL, 0xE5DBF044UL,
    0x11E7ABDAUL, 0x6550DA97UL, 0xBD21EB0DUL, 0x90E30E59UL, 0x90C7D548UL, 
    0x7EEBE540UL, 0xBE8C93F3UL, 0x4A01992FUL, 0xBAB151A7UL, 0x347ABF9BUL, 
    0x66B4E1F0UL, 0x23A7B353UL, 0x03BC780CUL, 0xF89C1689UL, 0xBAC1F8A6UL, 
    0xE16BBD31UL, 0xE862289FUL, 0x6F783C83UL, 0xBE85A948UL, 0x2303D5DDUL
  };
  unsigned char *p;
  unsigned long  esi, edi, eax, ecx, ebp;

  p = szBuf;
  for( i=0; i<=78; i++ )
  {
    esi = func2(p+i) + data[0];
    edi = func2(p+4+i) + data[1];
    for( j=10; j>0; j-- )
    {
      esi ^= edi;
      eax = edi & 31;
      ecx = 32 - eax;
      ebp = esi>>ecx;
      esi = esi<<eax;
      k = (10-j)*2+2;
      esi = (ebp|esi) + data[k];

      edi ^= esi;
      eax = esi & 31;
      ecx = 32 - eax;
      ebp = edi>>ecx;
      edi = edi<<eax;
      k = (10-j)*2+3;
      edi = (ebp|edi) + data[k];
    }
    func3( p+i, esi );
    func3( p+4+i, edi );
  }
}

--------------------------------------------------------------------------------

这是func5()的反汇编代码,作用是将连续2个字节转化为一个32位的无符号整数。

UPX0:004070A0 func5           proc near               ; CODE XREF: GenerateKey+70p
UPX0:004070A0
UPX0:004070A0 arg_0           = dword ptr  4
UPX0:004070A0
UPX0:004070A0                 mov     eax, [esp+arg_0]
UPX0:004070A4                 xor     ecx, ecx
UPX0:004070A6                 mov     ch, [eax]
UPX0:004070A8                 mov     cl, [eax+1]
UPX0:004070AB                 mov     eax, ecx
UPX0:004070AD                 retn
UPX0:004070AD func5           endp

--------------------------------------------------------------------------------

unsigned int func5( unsigned char *p )
{
  unsigned int  t = 0;
  t = *p;
  t = (t<<8) + *(p+1);
  return t;
}

--------------------------------------------------------------------------------

分析完这个keygen以后,我顺便又看了看其它的两个keygen。我发现v7.01和v7.1的keygen
其实是一样的,而v7.0的keygen算法也差不多,相比之下更简单,生成的key也要短一截。

至于更新一些的Matlab,比如R2006b,TEAM ACME曾经出过一个keygen,不过加了壳,暂时还
没有搞定。依key的格式推断,注册算法应该差不多。

最新的R2007a也出来了,不过只有一个现成的key,没见过keygen,期待哪位高手试试,
我等菜鸟只能在旁边看热闹了,呵呵~~


逆向出来的注册机源码见附件,已调试通过。

Just for fun !