[原创]WinNc v6.6.0.0算法分析+KenGenSrc
【文章标题】WinNc v6.6.0.0算法分析
【文章作者】BinGzL
【原版下载】www.winnc.com
【保护方式】序列号
【分析过程】
本文不阐述定位算法的过程,通过调试定位如下函数(看官可略过,看下面的分析):
.text:00954664 WinNc_KeyGenFun proc near ; CODE XREF: sub_954820+2Cp .text:00954664 ; DATA XREF: .text:009536FDo .text:00954664 .text:00954664 var_44 = dword ptr -44h .text:00954664 var_40 = byte ptr -40h .text:00954664 lnv_203h = dword ptr -10h .text:00954664 pszKeyTable = dword ptr -0Ch .text:00954664 var_8 = dword ptr -8 .text:00954664 pRegName_U = dword ptr -4 .text:00954664 arg_0 = dword ptr 8 .text:00954664 .text:00954664 push ebp .text:00954665 mov ebp, esp .text:00954667 add esp, 0FFFFFFBCh .text:0095466A push ebx .text:0095466B push esi .text:0095466C push edi .text:0095466D xor ebx, ebx .text:0095466F mov [ebp+var_44], ebx .text:00954672 mov [ebp+var_8], ebx .text:00954675 mov [ebp+pszKeyTable], ecx .text:00954678 mov [ebp+pRegName_U], edx ; .text:00954678 ; ; .text:0095467B mov eax, [ebp+pRegName_U] .text:0095467E call sub_408E0C .text:00954683 xor eax, eax .text:00954685 push ebp .text:00954686 push offset loc_9547E4 .text:0095468B push dword ptr fs:[eax] .text:0095468E mov fs:[eax], esp .text:00954691 .text:00954691 GetRegNameLen: .text:00954691 mov edx, [ebp+pRegName_U] .text:00954694 mov eax, edx .text:00954696 test eax, eax .text:00954698 jz short RegNameLenCmp .text:0095469A sub eax, 4 .text:0095469D mov eax, [eax] .text:0095469F .text:0095469F RegNameLenCmp: ; CODE XREF: WinNc_KeyGenFun+34j .text:0095469F cmp eax, 3 .text:009546A2 jg short _CalcRegCode .text:009546A4 mov eax, [ebp+arg_0] .text:009546A7 mov edx, offset off_954800 .text:009546AC call sub_409108 .text:009546B1 jmp loc_9547C1 .text:009546B6 ; --------------------------------------------------------------------------- .text:009546B6 .text:009546B6 _CalcRegCode: ; CODE XREF: WinNc_KeyGenFun+3Ej .text:009546B6 mov [ebp+lnv_203h], 203h .text:009546BD mov eax, edx .text:009546BF test eax, eax .text:009546C1 jz short loc_9546C8 .text:009546C3 sub eax, 4 .text:009546C6 mov eax, [eax] .text:009546C8 .text:009546C8 loc_9546C8: ; CODE XREF: WinNc_KeyGenFun+5Dj .text:009546C8 mov esi, eax .text:009546CA test esi, esi .text:009546CC jle short loc_95470D .text:009546CE mov ebx, 1 .text:009546D3 .text:009546D3 _While_Begin: ; CODE XREF: WinNc_KeyGenFun+9Aj .text:009546D3 push ebp .text:009546D4 mov eax, [ebp+pRegName_U] .text:009546D7 dec ebx .text:009546D8 test eax, eax .text:009546DA jz short loc_9546E1 .text:009546DC cmp ebx, [eax-4] .text:009546DF jb short loc_9546E6 .text:009546E1 .text:009546E1 loc_9546E1: ; CODE XREF: WinNc_KeyGenFun+76j .text:009546E1 call sub_406DDC .text:009546E6 ; --------------------------------------------------------------------------- .text:009546E6 .text:009546E6 loc_9546E6: ; CODE XREF: WinNc_KeyGenFun+7Bj .text:009546E6 inc ebx .text:009546E7 movzx eax, word ptr [eax+ebx*2-2] ; pRegName_U[i] .text:009546EC call Get_Calc_Hex ; nData = GetCalcHex(); .text:009546F1 pop ecx .text:009546F2 add [ebp+lnv_203h], eax ; 0x203 += nData .text:009546F5 jno short loc_9546FC .text:009546F7 call sub_406DE4 .text:009546FC ; --------------------------------------------------------------------------- .text:009546FC .text:009546FC loc_9546FC: ; CODE XREF: WinNc_KeyGenFun+91j .text:009546FC inc ebx .text:009546FD dec esi .text:009546FE jnz short _While_Begin ; .text:009546FE ; ; .text:00954700 jmp short loc_95470D .text:00954702 ; --------------------------------------------------------------------------- .text:00954702 .text:00954702 _While_Begin2: ; CODE XREF: WinNc_KeyGenFun+B4j .text:00954702 lea eax, [ebp+pRegName_U] .text:00954705 mov edx, [ebp+pRegName_U] .text:00954708 call SetNewName ; Name = NameName .text:0095470D .text:0095470D loc_95470D: ; CODE XREF: WinNc_KeyGenFun+68j .text:0095470D ; WinNc_KeyGenFun+9Cj .text:0095470D mov eax, [ebp+pRegName_U] .text:00954710 call GetNameLen .text:00954715 cmp eax, 0Ch .text:00954718 jl short _While_Begin2 ; .text:00954718 ; ; .text:0095471A mov ebx, 1 .text:0095471F mov esi, [ebp+pszKeyTable] .text:00954722 lea edi, [ebp+var_40] .text:00954725 .text:00954725 loc_954725: ; CODE XREF: WinNc_KeyGenFun+10Bj .text:00954725 push ebp .text:00954726 mov eax, [ebp+pRegName_U] .text:00954729 dec ebx .text:0095472A test eax, eax .text:0095472C jz short loc_954733 .text:0095472E cmp ebx, [eax-4] .text:00954731 jb short loc_954738 .text:00954733 .text:00954733 loc_954733: ; CODE XREF: WinNc_KeyGenFun+C8j .text:00954733 call sub_406DDC .text:00954738 ; --------------------------------------------------------------------------- .text:00954738 .text:00954738 loc_954738: ; CODE XREF: WinNc_KeyGenFun+CDj .text:00954738 inc ebx .text:00954739 movzx eax, word ptr [eax+ebx*2-2] ; pRegName_U[i] .text:0095473E add eax, [esi] ; pRegName_U[i] + (dword)pKeyTable[i] .text:00954740 jno short loc_954747 ; .text:00954740 ; ; .text:00954742 call sub_406DE4 .text:00954747 ; --------------------------------------------------------------------------- .text:00954747 .text:00954747 loc_954747: ; CODE XREF: WinNc_KeyGenFun+DCj .text:00954747 add eax, [ebp+lnv_203h] ; .text:00954747 ; ; .text:0095474A jno short loc_954751 .text:0095474C call sub_406DE4 .text:00954751 ; --------------------------------------------------------------------------- .text:00954751 .text:00954751 loc_954751: ; CODE XREF: WinNc_KeyGenFun+E6j .text:00954751 cdq .text:00954752 xor eax, edx .text:00954754 sub eax, edx .text:00954756 jno short loc_95475D .text:00954758 call sub_406DE4 .text:0095475D ; --------------------------------------------------------------------------- .text:0095475D .text:0095475D loc_95475D: ; CODE XREF: WinNc_KeyGenFun+F2j .text:0095475D call Get_Calc_Hex ; nData = GetCalcHex(); .text:00954762 pop ecx ; .text:00954762 ; ; .text:00954763 mov [edi], eax ; edi is RegCodeTable .text:00954765 inc ebx .text:00954766 add edi, 4 .text:00954769 add esi, 4 .text:0095476C cmp ebx, 0Dh .text:0095476F jnz short loc_954725 .text:00954771 lea eax, [ebp+var_8] .text:00954774 call sub_408D28 .text:00954779 mov ebx, 1 .text:0095477E lea esi, [ebp+var_40] .text:00954781 .text:00954781 loc_954781: ; CODE XREF: WinNc_KeyGenFun+150j .text:00954781 lea edx, [ebp+var_44] .text:00954784 mov eax, [esi] .text:00954786 call sub_425820 .text:0095478B mov edx, [ebp+var_44] .text:0095478E lea eax, [ebp+var_8] .text:00954791 call SetNewName ; Name = NameName .text:00954796 cmp ebx, 4 .text:00954799 jz short loc_9547A0 .text:0095479B cmp ebx, 8 .text:0095479E jnz short loc_9547AD .text:009547A0 .text:009547A0 loc_9547A0: ; CODE XREF: WinNc_KeyGenFun+135j .text:009547A0 lea eax, [ebp+var_8] .text:009547A3 mov edx, offset dword_95481C .text:009547A8 call SetNewName ; Name = NameName .text:009547AD .text:009547AD loc_9547AD: ; CODE XREF: WinNc_KeyGenFun+13Aj .text:009547AD inc ebx .text:009547AE add esi, 4 .text:009547B1 cmp ebx, 0Dh .text:009547B4 jnz short loc_954781 .text:009547B6 mov eax, [ebp+arg_0] .text:009547B9 mov edx, [ebp+var_8] .text:009547BC call sub_409108 .text:009547C1 .text:009547C1 loc_9547C1: ; CODE XREF: WinNc_KeyGenFun+4Dj .text:009547C1 xor eax, eax .text:009547C3 pop edx .text:009547C4 pop ecx .text:009547C5 pop ecx .text:009547C6 mov fs:[eax], edx .text:009547C9 push offset loc_9547EB .text:009547CE .text:009547CE loc_9547CE: ; CODE XREF: WinNc_KeyGenFun+185j .text:009547CE lea eax, [ebp+var_44] .text:009547D1 call sub_408D28 .text:009547D6 lea eax, [ebp+var_8] .text:009547D9 mov edx, 2 .text:009547DE call sub_408D88 .text:009547E3 retn .text:009547E4 ; --------------------------------------------------------------------------- .text:009547E4 .text:009547E4 loc_9547E4: ; DATA XREF: WinNc_KeyGenFun+22o .text:009547E4 jmp loc_408260 .text:009547E9 ; --------------------------------------------------------------------------- .text:009547E9 jmp short loc_9547CE .text:009547EB ; --------------------------------------------------------------------------- .text:009547EB .text:009547EB loc_9547EB: ; CODE XREF: WinNc_KeyGenFun+17Fj .text:009547EB ; DATA XREF: WinNc_KeyGenFun+165o .text:009547EB pop edi .text:009547EC pop esi .text:009547ED pop ebx .text:009547EE mov esp, ebp .text:009547F0 pop ebp .text:009547F1 retn 4 .text:009547F1 WinNc_KeyGenFun endp
我们抛出无用代码,看运算过程,下面是一段通过用户名进行的运算:
.text:009546D3 _While_Begin: ; CODE XREF: WinNc_KeyGenFun+9Aj .text:009546D3 push ebp .text:009546D4 mov eax, [ebp+pRegName_U] .text:009546D7 dec ebx .text:009546D8 test eax, eax .text:009546DA jz short loc_9546E1 .text:009546DC cmp ebx, [eax-4] .text:009546DF jb short loc_9546E6 .text:009546E1 .text:009546E1 loc_9546E1: ; CODE XREF: WinNc_KeyGenFun+76j .text:009546E1 call sub_406DDC .text:009546E6 ; --------------------------------------------------------------------------- .text:009546E6 .text:009546E6 loc_9546E6: ; CODE XREF: WinNc_KeyGenFun+7Bj .text:009546E6 inc ebx .text:009546E7 movzx eax, word ptr [eax+ebx*2-2] ; pRegName_U[i] .text:009546EC call Get_Calc_Hex ; nData = GetCalcHex(); .text:009546F1 pop ecx .text:009546F2 add [ebp+lnv_203h], eax ; 0x203 += nData .text:009546F5 jno short loc_9546FC .text:009546F7 call sub_406DE4 .text:009546FC ; --------------------------------------------------------------------------- .text:009546FC .text:009546FC loc_9546FC: ; CODE XREF: WinNc_KeyGenFun+91j .text:009546FC inc ebx .text:009546FD dec esi .text:009546FE jnz short _While_Begin ;
这是一段循环计算,主要函数内部实现为:
.text:0095461C Get_Calc_Hex proc near ; CODE XREF: Get_Calc_Hex+37p .text:0095461C ; WinNc_KeyGenFun+88p ... .text:0095461C .text:0095461C arg_0 = dword ptr 8 .text:0095461C .text:0095461C push ebp .text:0095461D mov ebp, esp .text:0095461F push ebx .text:00954620 push esi ; .text:00954620 ; ; .text:00954621 mov ebx, eax ; nTmp = pRegName_U[i] .text:00954623 xor esi, esi .text:00954625 .text:00954625 _While_Calc_Hex: ; CODE XREF: Get_Calc_Hex+2Aj .text:00954625 mov eax, ebx .text:00954627 mov ecx, 0Ah .text:0095462C cdq .text:0095462D idiv ecx .text:0095462F add esi, edx ; nData += nTmp % 0xA .text:00954631 jno short _While_Step .text:00954633 call sub_406DE4 .text:00954638 ; --------------------------------------------------------------------------- .text:00954638 .text:00954638 _While_Step: ; CODE XREF: Get_Calc_Hex+15j .text:00954638 mov ecx, 0Ah .text:0095463D mov eax, ebx .text:0095463F cdq .text:00954640 idiv ecx .text:00954642 mov ebx, eax ; nTmp = nTmp / 0xA .text:00954644 test ebx, ebx ; nTmp != 0 .text:00954646 jnz short _While_Calc_Hex ; .text:00954646 ; ; .text:00954648 cmp esi, 9 .text:0095464B jle short FunExit .text:0095464D mov eax, [ebp+arg_0] .text:00954650 push eax .text:00954651 mov eax, esi .text:00954653 call Get_Calc_Hex ; nData = GetCalcHex(); .text:00954658 pop ecx .text:00954659 mov esi, eax .text:0095465B .text:0095465B FunExit: ; CODE XREF: Get_Calc_Hex+2Fj .text:0095465B mov eax, esi .text:0095465D pop esi .text:0095465E pop ebx .text:0095465F pop ebp .text:00954660 retn .text:00954660 Get_Calc_Hex endp
这一段实际上就是在累加计算一个值,还原代码如下:
int CWinNcKeyGenDlg::GetCalcHex(DWORD dwKey)
{
int nTmp = dwKey;
int nData = 0;
while (nTmp != 0)
{
nData += nTmp % 0xA;
nTmp = nTmp / 0xA;
}
if (nData > 9)
{
nData = GetCalcHex(nData);
}
return nData;
}
nRegNameLen = wcslen(szRegName);
for (int i = 0; i < nRegNameLen; i++)
{
nKey += GetCalcHex(szRegName[i]);
}
接下来是一段对于用户名长度的检验:
.text:00954702 _While_Begin2: ; CODE XREF: WinNc_KeyGenFun+B4j .text:00954702 lea eax, [ebp+pRegName_U] .text:00954705 mov edx, [ebp+pRegName_U] .text:00954708 call SetNewName ; Name = NameName .text:0095470D .text:0095470D loc_95470D: ; CODE XREF: WinNc_KeyGenFun+68j .text:0095470D ; WinNc_KeyGenFun+9Cj .text:0095470D mov eax, [ebp+pRegName_U] .text:00954710 call GetNameLen .text:00954715 cmp eax, 0Ch .text:00954718 jl short _While_Begin2 ; .text:0040A018 SetNewName proc near ; CODE XREF: sub_4061D0+AAp .text:0040A018 ; sub_40A070+1Dj ... .text:0040A018 test edx, edx .text:0040A01A jz short locret_40A06C .text:0040A01C mov ecx, [eax] .text:0040A01E test ecx, ecx .text:0040A020 jz sub_409108 .text:0040A026 push ebx .text:0040A027 push esi .text:0040A028 push edi .text:0040A029 mov ebx, eax .text:0040A02B mov esi, edx .text:0040A02D mov edi, [ecx-4] .text:0040A030 mov edx, [esi-4] .text:0040A033 add edx, edi .text:0040A035 test edx, 0C0000000h .text:0040A03B jnz short loc_40A067 .text:0040A03D cmp esi, ecx .text:0040A03F jz short loc_40A05C .text:0040A041 call sub_409F98 .text:0040A046 mov eax, esi .text:0040A048 mov ecx, [esi-4] .text:0040A04B .text:0040A04B loc_40A04B: ; CODE XREF: SetNewName+4Dj .text:0040A04B mov edx, [ebx] .text:0040A04D shl edi, 1 .text:0040A04F add edx, edi .text:0040A051 shl ecx, 1 .text:0040A053 call sub_404C78 .text:0040A058 pop edi .text:0040A059 pop esi .text:0040A05A pop ebx .text:0040A05B retn .text:0040A05C ; --------------------------------------------------------------------------- .text:0040A05C .text:0040A05C loc_40A05C: ; CODE XREF: SetNewName+27j .text:0040A05C call sub_409F98 .text:0040A061 mov eax, [ebx] .text:0040A063 mov ecx, edi .text:0040A065 jmp short loc_40A04B .text:0040A067 ; --------------------------------------------------------------------------- .text:0040A067 .text:0040A067 loc_40A067: ; CODE XREF: SetNewName+23j .text:0040A067 jmp sub_406DE4 .text:0040A06C ; --------------------------------------------------------------------------- .text:0040A06C .text:0040A06C locret_40A06C: ; CODE XREF: SetNewName+2j .text:0040A06C retn .text:0040A06C SetNewName endp
实际上代码很简单,还原算法如下:
int nCount = nRegNameLen;
while (nCount < 0xc)
{
WCHAR szTmpBuf[0x100] = { 0 };
wcscpy_s(szTmpBuf, szRegName);
wcscat_s(szRegName, szTmpBuf);
nCount = wcslen(szRegName);
}
接下来有了再次用前面得到的结果与一个表一起进行运算:
.text:0095471A mov ebx, 1 .text:0095471F mov esi, [ebp+pszKeyTable] .text:00954722 lea edi, [ebp+var_40] .text:00954725 .text:00954725 loc_954725: ; CODE XREF: WinNc_KeyGenFun+10Bj .text:00954725 push ebp .text:00954726 mov eax, [ebp+pRegName_U] .text:00954729 dec ebx .text:0095472A test eax, eax .text:0095472C jz short loc_954733 .text:0095472E cmp ebx, [eax-4] .text:00954731 jb short loc_954738 .text:00954733 .text:00954733 loc_954733: ; CODE XREF: WinNc_KeyGenFun+C8j .text:00954733 call sub_406DDC .text:00954738 ; --------------------------------------------------------------------------- .text:00954738 .text:00954738 loc_954738: ; CODE XREF: WinNc_KeyGenFun+CDj .text:00954738 inc ebx .text:00954739 movzx eax, word ptr [eax+ebx*2-2] ; pRegName_U[i] .text:0095473E add eax, [esi] ; pRegName_U[i] + (dword)pKeyTable[i] .text:00954740 jno short loc_954747 ; .text:00954740 ; ; .text:00954742 call sub_406DE4 .text:00954747 ; --------------------------------------------------------------------------- .text:00954747 .text:00954747 loc_954747: ; CODE XREF: WinNc_KeyGenFun+DCj .text:00954747 add eax, [ebp+lnv_203h] ; .text:00954747 ; ; .text:0095474A jno short loc_954751 .text:0095474C call sub_406DE4 .text:00954751 ; --------------------------------------------------------------------------- .text:00954751 .text:00954751 loc_954751: ; CODE XREF: WinNc_KeyGenFun+E6j .text:00954751 cdq .text:00954752 xor eax, edx .text:00954754 sub eax, edx .text:00954756 jno short loc_95475D .text:00954758 call sub_406DE4 .text:0095475D ; --------------------------------------------------------------------------- .text:0095475D .text:0095475D loc_95475D: ; CODE XREF: WinNc_KeyGenFun+F2j .text:0095475D call Get_Calc_Hex ; nData = GetCalcHex(); .text:00954762 pop ecx ;
表内容:
DWORD g_szKeyTable[] =
{
0x37, 0x54, 0x7c, 0xf1,
0x19, 0x91, 0x3855f, 0xf4,
0xc6, 0x58, 0xd2, 0x93
};
代码还原如下:
char szShowRegCode[15] = { 0 };
char szRegCode[12] = { 0 };
for (int i = 0; i < 12; i++)
{
szRegCode[i] = GetCalcHex(szRegName[i] + g_szKeyTable[i] + nKey);
}
至此算法还原完毕,很简单的算法,完整计算过程如下:
DWORD g_szKeyTable[] =
{
0x37, 0x54, 0x7c, 0xf1,
0x19, 0x91, 0x3855f, 0xf4,
0xc6, 0x58, 0xd2, 0x93
};
int CWinNcKeyGenDlg::GetCalcHex(DWORD dwKey)
{
int nTmp = dwKey;
int nData = 0;
while (nTmp != 0)
{
nData += nTmp % 0xA;
nTmp = nTmp / 0xA;
}
if (nData > 9)
{
nData = GetCalcHex(nData);
}
return nData;
}
void CWinNcKeyGenDlg::OnBnClickedBtnKeygen()
{
WCHAR szRegName[0x100] = { 0 };
int nRegNameLen = 0;
int nKey = 0x203;
//获取注册名
::GetDlgItemText(m_hWnd, IDC_EDIT_REGNAME, szRegName, 0xc);
if (szRegName[0] == 0)
{
return;
}
//算法
nRegNameLen = wcslen(szRegName);
for (int i = 0; i < nRegNameLen; i++)
{
nKey += GetCalcHex(szRegName[i]);
}
//长度不足0xC 处理用户名
int nCount = nRegNameLen;
while (nCount < 0xc)
{
WCHAR szTmpBuf[0x100] = { 0 };
wcscpy_s(szTmpBuf, szRegName);
wcscat_s(szRegName, szTmpBuf);
nCount = wcslen(szRegName);
}
char szShowRegCode[15] = { 0 };
char szRegCode[12] = { 0 };
for (int i = 0; i < 12; i++)
{
szRegCode[i] = GetCalcHex(szRegName[i] + g_szKeyTable[i] + nKey);
}
wsprintfA(szShowRegCode, "%d%d%d%d-%d%d%d%d-%d%d%d%d",
szRegCode[0], szRegCode[1], szRegCode[2], szRegCode[3],
szRegCode[4], szRegCode[5], szRegCode[6], szRegCode[7],
szRegCode[8], szRegCode[9], szRegCode[0xa], szRegCode[0xb]);
::SetDlgItemTextA(m_hWnd, IDC_EDIT_REGCODE, szShowRegCode);
}
源码文件:
