NetScream 1.3.27.2006

这个程序比较怪异,一个是用+号来格开注册码使之成为若干组注册码。
另一个就是:浮点运算值与第一组注册码的差值不要超过某个定值都可以,随便挑注册码。
还有一个你点击程序的菜单都要看看注册码是否正确。

1.脱壳:
PEID:PECompact 2.x -> Jeremy Collake

RORDBG跟踪:
00DA79C2 ***API: KERNEL32.DLL!VirtualFree
可能到OEP了,如果不完全正确,请再单步走几下!
00525BB2 FFE0                JMP EAX
可能到OEP了,如果不完全正确,请再单步走几下!
00493744 55                  PUSH EBP
00DA79C1 ***API: KERNEL32.DLL!GetModuleHandleA

好FLYODBG载入,忽略所有异常,HE 00525BB2,F9运行停住,然后来到OEP:
00493744     55              push ebp
00493745     8BEC            mov ebp,esp
00493747     B9 36000000     mov ecx,36

LORDPE+ImportREC:dump并修复,运行ok。
Borland Delphi 6.0 - 7.0

2.断点:
Spy capure+eXescope+winhex定位注册按钮:
TForm3: OnClick = Button1Click:0047B96C;0047BD68;0047BFAC;0047C364;0047C980,0047CBFC;0048EF24;00492F40;004931DC;
断下:
0047C364     55              push ebp
这里也可以用DeDe来定位,不过加载实在慢。

3.定位核心:
断下后往下走,看到用户名注册码入栈计算:
0047C3ED     8B45 EC         mov eax,dword ptr ss:[ebp-14]    ; 用户名
0047C3F0     5A              pop edx                          ; 注册码
0047C3F1     E8 621D0100     call dumped_.0048E158
0047C3F6     3C 01           cmp al,1
0047C3F8     0F85 DB000000   jnz dumped_.0047C4D9
如果不跳的话就提示谢谢注册。

4.关键call:0047C3F1     E8 621D0100     call dumped_.0048E158
4.1检查注册码是否有2B即+号,分别取出2组注册码:
0048E2DD     8B55 F8         mov edx,dword ptr ss:[ebp-8]       ; zcm
0048E2E0     B8 70E84800     mov eax,dumped_.0048E870           ; 2b
0048E2E5     E8 DA63F7FF     call dumped_.004046C4              ; 检查2B的位置
0048E2EA     40              inc eax                            ; 2B的位置+1
0048E2EB     50              push eax                           ; PUSH
0048E2EC     8B45 F8         mov eax,dword ptr ss:[ebp-8]
0048E2EF     E8 8C60F7FF     call dumped_.00404380
0048E2F4     8BC8            mov ecx,eax
0048E2F6     8B45 F8         mov eax,dword ptr ss:[ebp-8]       ; zcm
0048E2F9     5A              pop edx                            ; POP
0048E2FA     E8 E162F7FF     call dumped_.004045E0              ; 从第edx位开始取zcm
0048E2FF     8B55 D8         mov edx,dword ptr ss:[ebp-28]      ; 剩下的注册码
0048E302     B8 70E84800     mov eax,dumped_.0048E870           ; 2B
0048E307     E8 B863F7FF     call dumped_.004046C4              ; 检查2B的位置
0048E30C     48              dec eax                            ; 2B的位置-1
0048E30D     50              push eax
0048E30E     8D45 D4         lea eax,dword ptr ss:[ebp-2C]
0048E311     50              push eax
0048E312     8B55 F8         mov edx,dword ptr ss:[ebp-8]
0048E315     B8 70E84800     mov eax,dumped_.0048E870
0048E31A     E8 A563F7FF     call dumped_.004046C4
0048E31F     40              inc eax
0048E320     50              push eax
0048E321     8B45 F8         mov eax,dword ptr ss:[ebp-8]
0048E324     E8 5760F7FF     call dumped_.00404380
0048E329     8BC8            mov ecx,eax
0048E32B     8B45 F8         mov eax,dword ptr ss:[ebp-8]       ; zcm
0048E32E     5A              pop edx                            ; 第一次位置+1
0048E32F     E8 AC62F7FF     call dumped_.004045E0              ; 取得第一批注册码
0048E334     8B45 D4         mov eax,dword ptr ss:[ebp-2C]      ; 剩下的注册码
0048E337     BA 01000000     mov edx,1
0048E33C     59              pop ecx                            ; 第二次位置-1
0048E33D     E8 9E62F7FF     call dumped_.004045E0              ; 取得第二批注册码

比如练码为87654+3210+12345+678,得到2批注册码:87654&3210。

4.2用户名+取得的注册码的运算:
0048E35D     0FB600          movzx eax,byte ptr ds:[eax]        ; 顺取用户名
0048E360     F7EB            imul ebx                           ; ebx初始值=1,累增
...
0048E385     E8 3ABAF7FF     call dumped_.00409DC4              ; 用户名乘积转换成十进制
0048E38A     FF75 D0         push dword ptr ss:[ebp-30]         ; 入栈
0048E38D     8D55 BC         lea edx,dword ptr ss:[ebp-44]
0048E390     8BC3            mov eax,ebx
0048E392     E8 B5A1F7FF     call dumped_.0040854C
0048E397     FF75 BC         push dword ptr ss:[ebp-44]         ; 序号入栈1,2,3...
0048E39A     FF35 6C7F4900   push dword ptr ds:[497F6C]         ; 第2批注册码入栈
0048E3A0     8D45 E4         lea eax,dword ptr ss:[ebp-1C]      ; 
0048E3A3     BA 03000000     mov edx,3                          ; 待连接个数
0048E3A8     E8 9360F7FF     call dumped_.00404440              ; 连接
0048E3AD     8B45 E4         mov eax,dword ptr ss:[ebp-1C]      ; 连接值
0048E3B0     E8 D3A2F7FF     call dumped_.00408688              ; 转换成十六进制
0048E3B5     8BF0            mov esi,eax
0048E3B7     8B45 E4         mov eax,dword ptr ss:[ebp-1C]
0048E3BA     E8 C9A2F7FF     call dumped_.00408688
0048E3BF     03F0            add esi,eax                        ; 转换后的十六进制×2
0048E3C1     8BC6            mov eax,esi
0048E3C3     8D55 B8         lea edx,dword ptr ss:[ebp-48]
0048E3C6     E8 81A1F7FF     call dumped_.0040854C              ; 转换成十进制
0048E3CB     8B55 B8         mov edx,dword ptr ss:[ebp-48]      ; 转换值

这里就要小心了,如果取得的注册码值太大的话,转换成十六进制就会异常,最好取<5位。
连接的参数有3个:用户名+序号+第2组注册码
用户名:cyto,ASCII码十进制=99,121,116,111,乘积=99,242,348,444
序号:1,2,3,...
取得的第2组注册码=3210
得到的值分别为:99 1 3210,242 2 3210,348 3 3210,444 4 3210
×2后的值:19826420,...,88886420

4.3对最后一组值88886420的浮点计算:
0048E3E8     6A 16           push 16
0048E3EA     68 95B5AE55     push 55AEB595
0048E3EF     8B45 E4         mov eax,dword ptr ss:[ebp-1C]      ; 最后一组计算值
0048E3F2     E8 91A2F7FF     call dumped_.00408688              ; 转换成十六进制
0048E3F7     99              cdq
0048E3F8     E8 BF6BF7FF     call dumped_.00404FBC              ; 计算
0048E3FD     8945 C0         mov dword ptr ss:[ebp-40],eax      ; 低位值
0048E400     8955 C4         mov dword ptr ss:[ebp-3C],edx      ; 高位值

0012F580  24 36 25 38 C3 87 54 76  $6%8脟Tv

最后一组计算值=88886420=54C4C94(H)
值×16=54C4C94×16=748E94B8
值×55AEB595=54C4C94×55AEB595=1C5F30B 38253624
高位值=值×16+值×55AEB595的高位=748E94B8+1C5F30B=765487C3
低位值=值×55AEB595的低位=38253624

转换成浮点:8.5265892670495268200E+18

4.4取扣除前2组剩下的注册码,再次检查有无2B:
0048E482     8B55 EC         mov edx,dword ptr ss:[ebp-14]      ; 所剩下的注册码
0048E485     B8 70E84800     mov eax,dumped_.0048E870           ; 2B
0048E48A     E8 3562F7FF     call dumped_.004046C4              ; 检查2B的位置
0048E48F     85C0            test eax,eax                       ; 返回的位置值
0048E491     0F8E 6B010000   jle dumped_.0048E602
比如练码为87654+3210+12345+678,剩下的就是12345+678。

4.5检查通过后取第4组:
0048E49B     8B55 EC         mov edx,dword ptr ss:[ebp-14]
0048E49E     B8 70E84800     mov eax,dumped_.0048E870
0048E4A3     E8 1C62F7FF     call dumped_.004046C4
0048E4A8     40              inc eax
0048E4A9     50              push eax
0048E4AA     8B45 EC         mov eax,dword ptr ss:[ebp-14]
0048E4AD     E8 CE5EF7FF     call dumped_.00404380
0048E4B2     8BC8            mov ecx,eax
0048E4B4     8B45 EC         mov eax,dword ptr ss:[ebp-14]
0048E4B7     5A              pop edx
0048E4B8     E8 2361F7FF     call dumped_.004045E0
0048E4BD     8B45 AC         mov eax,dword ptr ss:[ebp-54]       ; 第4组
比如练码为87654+3210+12345+678,第4组就是678。

4.6取第3组注册码:
0048E4CC     8B55 EC         mov edx,dword ptr ss:[ebp-14]
0048E4CF     B8 70E84800     mov eax,dumped_.0048E870
0048E4D4     E8 EB61F7FF     call dumped_.004046C4
0048E4D9     8BC8            mov ecx,eax
0048E4DB     49              dec ecx
0048E4DC     BA 01000000     mov edx,1
0048E4E1     8B45 EC         mov eax,dword ptr ss:[ebp-14]
0048E4E4     E8 F760F7FF     call dumped_.004045E0
0048E4E9     8B45 A0         mov eax,dword ptr ss:[ebp-60]

比如练码为87654+3210+12345+678,第3组就是12345。

第3组累和:得到值=255=FF(H)

4.7浮点计算值与第1组注册码的运算:
0048E61C     8B45 F0         mov eax,dword ptr ss:[ebp-10]       ; 第1组注册码
0048E61F     E8 F8B7F7FF     call dumped_.00409E1C
0048E624     DB7D 84         fstp tbyte ptr ss:[ebp-7C]
0048E627     9B              wait
0048E628     8B45 E4         mov eax,dword ptr ss:[ebp-1C]
0048E62B     E8 ECB7F7FF     call dumped_.00409E1C
0048E630     DB6D 84         fld tbyte ptr ss:[ebp-7C]
0048E633     DEE1            fsubrp st(1),st                     ; 浮点值与第1组注册码差值 
0048E635     D81D 8CE84800   fcomp dword ptr ds:[48E88C]         ; 差值与4000比较
0048E63B     DFE0            fstsw ax
0048E63D     9E              sahf
0048E63E     0F87 53010000   ja dumped_.0048E797
0048E644     8B45 E4         mov eax,dword ptr ss:[ebp-1C]
0048E647     E8 D0B7F7FF     call dumped_.00409E1C
0048E64C     DBBD 78FFFFFF   fstp tbyte ptr ss:[ebp-88]
0048E652     9B              wait
0048E653     8B45 F0         mov eax,dword ptr ss:[ebp-10]
0048E656     E8 C1B7F7FF     call dumped_.00409E1C
0048E65B     DBAD 78FFFFFF   fld tbyte ptr ss:[ebp-88]
0048E661     DEE1            fsubrp st(1),st                     ; 浮点值与第1组注册码差值
0048E663     D81D 8CE84800   fcomp dword ptr ds:[48E88C]         ; 差值与4000比较
0048E669     DFE0            fstsw ax
0048E66B     9E              sahf
0048E66C     0F87 25010000   ja dumped_.0048E797

这两个ja不能跳,跳就完。
试了好几个方法,让fsubrp st(1),st的值=0,都不会跳。
反复调试发现:fsubrp st(1),st的值只要不超过48E88C的值=4000就能通过。

4.8通过上面2个ja后,比较:
0048E672     8B45 E8         mov eax,dword ptr ss:[ebp-18]       ; 第4组注册码
0048E675     8B55 E0         mov edx,dword ptr ss:[ebp-20]       ; 第3组注册码累和ASCII码
0048E678     E8 4F5EF7FF     call dumped_.004044CC               ; 比较
0048E67D     75 0B           jnz short dumped_.0048E68A          ; 核心跳转
0048E67F     C605 647F4900 0>mov byte ptr ds:[497F64],1
0048E686     C645 F7 01      mov byte ptr ss:[ebp-9],1
0048E68A     33C0            xor eax,eax

只要修改0048E67D处的跳转,这样就能爆破成功。

5.算法小结:
注册码需要3个+号格开得到4组注册码。
用户名与第2组注册码运算得到浮点值,浮点值要约等于第1组注册码。
第3组注册码累和=第4组注册码。

好,让第2组注册码小点,设为0,第3组注册码如果为12345的话,第4组就要=255,这样只需要反推第1组注册码,假设练码为:8+0+12345+255
得到浮点值=st(1)=8.5259734170344796160e+15
即8525973417034479.616,
第一组注册码从8525973417030480-8525973417038479任意数都可以注册成功。

用户名:cyto 
注册码:8525973417034479+0+12345+255

写入注册表:
HKLM\Software\SWIFTDOG\NetScream\Name  SUCCESS  "cyto"  
HKLM\Software\SWIFTDOG\NetScream\Serial  SUCCESS  "8525973417034479+0+12345+255"