首页
社区
课程
招聘
[原创]Internet Download Manager 算法分析
发表于: 2015-8-4 13:43 4456

[原创]Internet Download Manager 算法分析

2015-8-4 13:43
4456
【文章标题】Internet Download Manager 算法分析
【文章作者】BinGzL
【软件版本】Internet Download Manager v6.23 Build17
【保护方式】序列号
【分析过程】
本文不阐述定位算法的过程,通过调试定位如下函数(看官可略过,看下面的分析):
刚进入函数就看到了获取注册信息的部分与初始化一张Key表
获取名字
.text:004FFB31                 lea     eax, [ebp+szName]
.text:004FFB3A                 push    32h             ; cchMax
.text:004FFB3E                 push    eax             ; lpString
.text:004FFB3F                 push    4B0h            ; nIDDlgItem
.text:004FFC4A                 call    GetRegUserInfo

获取姓氏
.text:004FFC78                 lea     edx, [ebp+szSurName]
.text:004FFC7E                 push    32h             ; cchMax
.text:004FFC80                 push    edx             ; lpString
.text:004FFC81                 push    413h            ; nIDDlgItem
.text:004FFC88                 call    GetRegUserInfo

获取EMail
.text:004FFC9F                 lea     ecx, [ebp+szEmail]
.text:004FFCA5                 push    32h             ; cchMax
.text:004FFCA7                 push    ecx             ; lpString
.text:004FFCA8                 push    4A5h            ; nIDDlgItem
.text:004FFCAF                 call    GetRegUserInfo 

获取序列号
.text:004FFCC7                 lea     eax, [ebp+szSerialNum]
.text:004FFCCD                 push    32h             ; cchMax
.text:004FFCCF                 push    eax             ; lpString
.text:004FFCD0                 push    4AAh            ; nIDDlgItem
.text:004FFCD7                 call    GetRegUserInfo


.text:005E30A4 ; int __stdcall GetRegUserInfo(int nIDDlgItem, LPSTR lpString, int cchMax)
.text:005E30A4 GetRegUserInfo  proc near               ; CODE XREF: IsRegister+13Ap
.text:005E30A4                                         ; IsRegister+178p ...
.text:005E30A4
.text:005E30A4 nIDDlgItem      = dword ptr  8
.text:005E30A4 lpString        = dword ptr  0Ch
.text:005E30A4 cchMax          = dword ptr  10h
.text:005E30A4
.text:005E30A4                 push    ebp
.text:005E30A5                 mov     ebp, esp
.text:005E30A7                 mov     eax, [ecx+34h]
.text:005E30AA                 test    eax, eax
.text:005E30AC                 jnz     short loc_5E30C2
.text:005E30AE                 push    [ebp+cchMax]    ; cchMax
.text:005E30B1                 push    [ebp+lpString]  ; lpString
.text:005E30B4                 push    [ebp+nIDDlgItem] ; nIDDlgItem
.text:005E30B7                 push    dword ptr [ecx+1Ch] ; hDlg
.text:005E30BA                 call    ds:GetDlgItemTextA
.text:005E30C0                 jmp     short loc_5E30D2
.text:005E30C2 ; ---------------------------------------------------------------------------
.text:005E30C2
.text:005E30C2 loc_5E30C2:                             ; CODE XREF: GetRegUserInfo+8j
.text:005E30C2                 push    [ebp+cchMax]
.text:005E30C5                 mov     edx, [eax]
.text:005E30C7                 mov     ecx, eax
.text:005E30C9                 push    [ebp+lpString]
.text:005E30CC                 push    [ebp+nIDDlgItem]
.text:005E30CF                 call    dword ptr [edx+78h]
.text:005E30D2
.text:005E30D2 loc_5E30D2:                             ; CODE XREF: GetRegUserInfo+1Cj
.text:005E30D2                 pop     ebp
.text:005E30D3                 retn    0Ch
.text:005E30D3 GetRegUserInfo  endp


Key表内容为:
char g_KeyTable[] = 
{
	0x32, 0x59, 0x4f, 0x50, 0x42, 0x33, 
	0x41, 0x51, 0x43, 0x56, 0x55, 0x58, 
	0x4d, 0x4e, 0x52, 0x53,	0x39, 0x37, 
	0x57, 0x45, 0x30, 0x49, 0x5a, 0x44, 
	0x34, 0x4b, 0x4c, 0x46, 0x47, 0x48, 
	0x4a, 0x38, 0x31, 0x36, 0x35, 0x54 
};


检查序列号是否为空
.text:004FFCF1                 mov     dl, ' '         ; 0x20 == ' '
.text:004FFCF3                 cmp     [ebp+szSerialNum], dl
.text:004FFCF9                 jnz     short loc_4FFD57 ;


序列号转换与检查
.text:004FFDAD                 lea     edx, [ebp+szSerialNum]
.text:004FFDB3                 push    edx             ; char *
.text:004FFDB4                 call    __strupr        ; 序列号转换大写
.text:004FFDB9                 lea     edi, [ebp+szSerialNum]
.text:004FFDBF                 or      ecx, 0FFFFFFFFh
.text:004FFDC2                 xor     eax, eax
.text:004FFDC4                 add     esp, 4
.text:004FFDC7                 repne scasb
.text:004FFDC9                 not     ecx
.text:004FFDCB                 dec     ecx
.text:004FFDCC                 cmp     ecx, 23         ; 比较序列号是否为23位
.text:004FFDCF                 jnz     short loc_4FFD69
.text:004FFDD1                 mov     cl, [ebp+szSerialNum+5]
.text:004FFDD4                 mov     byte ptr [ebp+var_14+3], al ; bSerialNumLog == FALSE
.text:004FFDD7                 mov     al, 2Dh
.text:004FFDD9                 cmp     cl, al          ; 比较序列号第6位是否为'-'(0x2d)
.text:004FFDDB                 jnz     short loc_4FFDE7 ; bSerialNumLog == TRUE
.text:004FFDDD                 cmp     [ebp+szSerialNum+0Bh], al ; 比较序列号第12位是否为'-'(0x2d)
.text:004FFDE0                 jnz     short loc_4FFDE7 ; bSerialNumLog == TRUE
.text:004FFDE2                 cmp     [ebp+szSerialNum+11h], al ; 比较序列号第18位是否为'-'(0x2d)
.text:004FFDE5                 jz      short loc_4FFDEB

由此可以确定系列号的格式为XXXXX-XXXXX-XXXXX-XXXXX,接下来又把4段系列号分别拷贝出来
.text:004FFDEB                 lea     eax, [ebp+szSerialNum]
.text:004FFDF1                 push    5               ; size_t
.text:004FFDF3                 lea     ecx, [ebp+szSerialNum_0_4]
.text:004FFDF6                 push    eax             ; char *
.text:004FFDF7                 push    ecx             ; char *
.text:004FFDF8                 call    _strncpy        ; 获取0-4位的序列号
.text:004FFDFD                 lea     edx, [ebp+szSerialNum+6]
.text:004FFE00                 push    5               ; size_t
.text:004FFE02                 lea     eax, [ebp+szSerialNum_6_10]
.text:004FFE05                 push    edx             ; char *
.text:004FFE06                 push    eax             ; char *
.text:004FFE07                 call    _strncpy        ; 获取6-10位序列号
.text:004FFE0C                 lea     ecx, [ebp+szSerialNum+0Ch]
.text:004FFE0F                 push    5               ; size_t
.text:004FFE11                 lea     edx, [ebp+szSerialNum_12_16]
.text:004FFE14                 push    ecx             ; char *
.text:004FFE15                 push    edx             ; char *
.text:004FFE16                 call    _strncpy        ; 获取12-16位序列号
.text:004FFE1B                 lea     eax, [ebp+szSerialNum+12h]
.text:004FFE1E                 push    5               ; size_t
.text:004FFE20                 lea     ecx, [ebp+szSerialNum_18_22]
.text:004FFE23                 push    eax             ; char *
.text:004FFE24                 push    ecx             ; char *
.text:004FFE25                 call    _strncpy        ; 获取18-22位序列号
.text:004FFE2A                 xor     edi, edi
.text:004FFE2C                 add     esp, 30h
.text:004FFE2F                 mov     [ebp+szSerialNum_0_4+5], 0 ; 为拷贝出来的每段加'\0'
.text:004FFE33                 mov     [ebp+szSerialNum_6_10+5], 0
.text:004FFE37                 mov     [ebp+szSerialNum_12_16+5], 0
.text:004FFE3B                 mov     [ebp+szSerialNum_18_22+5], 0 ;


算法的准备工作就算完成了,接下来出现了四段一样的算法,如下
.text:004FFE3F                 mov     [ebp+dwResult0_4], edi
.text:004FFE42                 xor     esi, esi
.text:004FFE44
.text:004FFE44 loc_4FFE44:                             ; CODE XREF: IsRegister+362j
.text:004FFE44                 cmp     esi, 5
.text:004FFE47                 jge     short loc_4FFE7B ; nData = 0
.text:004FFE49                 mov     dl, [ebp+esi+szSerialNum_0_4]
.text:004FFE4D                 or      ecx, 0FFFFFFFFh
.text:004FFE50                 xor     eax, eax
.text:004FFE52
.text:004FFE52 loc_4FFE52:                             ; CODE XREF: IsRegister+365j
.text:004FFE52                 cmp     eax, 36         ; KeyTable Len
.text:004FFE55                 jge     short loc_4FFE61 ;
.text:004FFE55                                         ; ;
.text:004FFE57                 cmp     g_szKeyTable[eax], dl
.text:004FFE5D                 jnz     short loc_4FFE74
.text:004FFE5F                 mov     ecx, eax        ; nIndex = j
.text:004FFE61
.text:004FFE61 loc_4FFE61:                             ; CODE XREF: IsRegister+345j
.text:004FFE61                 cmp     ecx, 0FFFFFFFFh
.text:004FFE64                 jz      short loc_4FFE77
.text:004FFE66                 lea     edx, [edi+edi*8]
.text:004FFE69                 add     ecx, edi
.text:004FFE6B                 inc     esi
.text:004FFE6C                 lea     edi, [ecx+edx*4] ; nData = nIndex + dwResult0_4 + (dwResult0_4 * 9) * 4;
.text:004FFE6F                 mov     [ebp+dwResult0_4], edi ; dwResult = nData
.text:004FFE72                 jmp     short loc_4FFE44
.text:004FFE74 ; ---------------------------------------------------------------------------
.text:004FFE74
.text:004FFE74 loc_4FFE74:                             ; CODE XREF: IsRegister+34Dj
.text:004FFE74                 inc     eax
.text:004FFE75                 jmp     short loc_4FFE52 ; KeyTable Len
.text:004FFE77 ; ---------------------------------------------------------------------------
.text:004FFE77
.text:004FFE77 loc_4FFE77:                             ; CODE XREF: IsRegister+354j
.text:004FFE77                 mov     byte ptr [ebp+var_14+3], 1


分析过后得出如下代码:
int CIDMKeyGenDlg::GetCalcResult(char *pData)
{
	int i = 0, j = 0;
	int nIndex = 0;
	int nData = 0;

	while (i < 5)
	{
		for (j = 0; j < 36; j++)
		{
			if (g_KeyTable[j] == pData[i])
			{
				nIndex = j;
				nData = nIndex + nData + (nData * 9) * 4;
				i++;
				break;
			}
		}
	}
	return nData;
}

接下来在得到4段序列号计算出的值后,分别有对四个值做了校验
 第一段
.text:004FFF42                 mov     ecx, [ebp+dwResult0_4]
.text:004FFF45                 mov     esi, 43
.text:004FFF4A                 mov     eax, ecx
.text:004FFF4C                 cdq
.text:004FFF4D                 idiv    esi
.text:004FFF4F                 test    edx, edx
.text:004FFF51                 jnz     short loc_4FFF57
 第二段
.text:004FFF5B                 mov     ecx, dword ptr [ebp+dwResult6_10]
.text:004FFF5E                 mov     esi, 23
.text:004FFF63                 mov     eax, ecx
.text:004FFF65                 cdq
.text:004FFF66                 idiv    esi
.text:004FFF68                 test    edx, edx
.text:004FFF6A                 jnz     short loc_4FFF70
 第三段
.text:004FFF74                 mov     eax, ebx
.text:004FFF76                 mov     ecx, 17
.text:004FFF7B                 cdq
.text:004FFF7C                 idiv    ecx
.text:004FFF7E                 test    edx, edx
.text:004FFF80                 jnz     short loc_4FFF86
 第四段
.text:004FFF8A                 mov     eax, edi
.text:004FFF8C                 mov     ecx, 53
.text:004FFF91                 cdq
.text:004FFF92                 idiv    ecx
.text:004FFF94                 test    edx, edx
.text:004FFF96                 jnz     short loc_4FFFA3

剩下的就是保存注册信息的代码了,由此可以了解软件注册的验证流程为4段计算的值都可以整除一个值才可以注册。本以为到此结束....第二天用的时候打开弹出了让我心碎的提示

再次分析启动验证,发现是有网络验证,看来是不能够愉快的KeyGen了,这KeyGen自然也就是然并卵了。通杀补丁可以去飘云阁找飘哥的那份补丁。

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 0
支持
分享
最新回复 (2)
雪    币: 204
活跃值: (44)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢分享.能分析汇编算法的都是大神.
2015-8-4 15:42
0
雪    币: 6
活跃值: (19)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
谢谢楼主分享。
2015-8-4 17:13
0
游客
登录 | 注册 方可回帖
返回
//