这是国产软件,若斑主看过觉得内容不合适,可以删之。
下载地址:
http://dl.pconline.com.cn/html_2/1/94/id=11223&pn=0.html
说明:有朋友要找个视频会议系统,找了几个试用一下。看看这个好象还不错。但是
只支持一个用户,厂家说可以免费注册,有可能是注册信息随便乱写的,没有
收到注册码,于是就自己看看了。这里主要是给大家看看程序算法的实现。请
支持国产软件。
系统:windows2003
使用工具:OllyDbg 1.1
1,注册码生成。
进入服务器的管理程序,在许可管理里,两个文本框,一个是机器码,一个是注册码。
随便添入一个字符串后会提示成功,重新启动服务器。然后该不好使还是不好使。这
里跟踪一下,看如何处理的。
bp GetVolumeInformationA
然后打开许可界面,程序就断下了:
0040EE27 . 6A 50 push 50 ; /pFileSystemNameSize = 00000050
0040EE29 . 52 push edx ; |pFileSystemNameBuffer
0040EE2A . 50 push eax ; |pFileSystemFlags
0040EE2B . 8D5424 24 lea edx, [esp+24] ; |
0040EE2F . 51 push ecx ; |pMaxFilenameLength
0040EE30 . 52 push edx ; |pVolumeSerialNumber
0040EE31 . 8D8424 880300>lea eax, [esp+388] ; |
0040EE38 . 68 04010000 push 104 ; |MaxVolumeNameSize = 104 (260.)
0040EE3D . 8D8C24 740100>lea ecx, [esp+174] ; |
0040EE44 . 50 push eax ; |VolumeNameBuffer
0040EE45 . 51 push ecx ; |RootPathName
0040EE46 . FF15 80704100 call [<&KERNEL32.GetVolumeInformationA>] ; \GetVolumeInformationA ;取C盘卷标
0040EE4C . 3BC3 cmp eax, ebx
0040EE4E . 74 2F je short 0040EE7F
0040EE50 . 395C24 18 cmp [esp+18], ebx
0040EE54 . 75 15 jnz short 0040EE6B
0040EE56 . 8D5424 18 lea edx, [esp+18]
0040EE5A . 8D8424 5C0100>lea eax, [esp+15C]
0040EE61 . 52 push edx
0040EE62 . 50 push eax
0040EE63 . E8 38FBFFFF call 0040E9A0
0040EE68 . 83C4 08 add esp, 8
0040EE6B > 8B4C24 18 mov ecx, [esp+18]
0040EE6F . 8D9424 940000>lea edx, [esp+94]
0040EE76 . 51 push ecx
0040EE77 . 68 4CD54100 push 0041D54C ; %x
0040EE7C . 52 push edx
0040EE7D . EB 14 jmp short 0040EE93
0040EE7F > FF15 F4704100 call [<&KERNEL32.GetLastError>] ; [GetLastError
0040EE85 . 50 push eax
0040EE86 . 8D8424 980000>lea eax, [esp+98]
0040EE8D . 68 4CD54100 push 0041D54C ; %x
0040EE92 . 50 push eax
0040EE93 > FFD6 call esi ;sprintf 把C盘卷标转换成16进字符串
0040EE95 . 83C4 0C add esp, 0C
0040EE98 . 8D4C24 24 lea ecx, [esp+24]
0040EE9C . 8D9424 5C0100>lea edx, [esp+15C]
0040EEA3 . C74424 24 C70>mov dword ptr [esp+24], 0C7
0040EEAB . 51 push ecx ; /pBufferSize
0040EEAC . 52 push edx ; |Buffer
0040EEAD . FF15 84704100 call [<&KERNEL32.GetComputerNameA>] ; \GetComputerNameA ;取得主机名称
0040EEB3 . 8DBC24 5C0100>lea edi, [esp+15C]
0040EEBA . 83C9 FF or ecx, FFFFFFFF
0040EEBD . 33C0 xor eax, eax
0040EEBF . 8D9424 940000>lea edx, [esp+94]
0040EEC6 . F2:AE repne scas byte ptr es:[edi] ;以下几行代码功能是把C盘卷标
0040EEC8 . F7D1 not ecx
0040EECA . 2BF9 sub edi, ecx ;连接在一起
0040EECC . 8BF7 mov esi, edi
0040EECE . 8BFA mov edi, edx
0040EED0 . 8BD1 mov edx, ecx
0040EED2 . 83C9 FF or ecx, FFFFFFFF
0040EED5 . F2:AE repne scas byte ptr es:[edi]
0040EED7 . 8BCA mov ecx, edx
0040EED9 . 4F dec edi
0040EEDA . C1E9 02 shr ecx, 2
0040EEDD . F3:A5 rep movs dword ptr es:[edi], dword ptr [esi] ;
0040EEDF . 8BCA mov ecx, edx
0040EEE1 . 8D8424 940000>lea eax, [esp+94]
0040EEE8 . 83E1 03 and ecx, 3
0040EEEB . 50 push eax ;这里是保存连接后字符串的地址
0040EEEC . F3:A4 rep movs byte ptr es:[edi], byte ptr [esi]
0040EEEE . 8BCD mov ecx, ebp
0040EEF0 . E8 7B020000 call 0040F170 ;进行运算
0040EEF5 . 8DBC24 940000>lea edi, [esp+94]
0040EEFC . 83C9 FF or ecx, FFFFFFFF
0040EEFF . 33C0 xor eax, eax
0040EF01 . 8D55 68 lea edx, [ebp+68]
0040EF04 . F2:AE repne scas byte ptr es:[edi]
0040EF06 . F7D1 not ecx
0040EF08 . 2BF9 sub edi, ecx
0040EF0A . 8BC1 mov eax, ecx
0040EF0C . 8BF7 mov esi, edi
0040EF0E . 8BFA mov edi, edx
0040EF10 . C1E9 02 shr ecx, 2
0040EF13 . F3:A5 rep movs dword ptr es:[edi], dword ptr [esi]
0040EF15 . 8BC8 mov ecx, eax
0040EF17 . 83E1 03 and ecx, 3
0040EF1A . F3:A4 rep movs byte ptr es:[edi], byte ptr [esi]
0040EF1C . 8D8C24 940000>lea ecx, [esp+94]
0040EF23 . 51 push ecx
0040EF24 . 68 07040000 push 407
0040EF29 . 8BCD mov ecx, ebp
0040EF2B . E8 60540000 call <jmp.&MFC42.#5953_CWnd::SetDlgItemTextA> ;运算完后写到文本框里
0040EF30 . 68 48D54100 push 0041D548 ; 3.0%x
0040EF35 . 68 09040000 push 409
0040EF3A . 8BCD mov ecx, ebp
0040EF3C . E8 4F540000 call <jmp.&MFC42.#5953_CWnd::SetDlgItemTextA>
0040EF41 . 8B15 54D64100 mov edx, [41D654]
0040EF47 . B9 19000000 mov ecx, 19
0040EF4C . 33C0 xor eax, eax
0040EF4E . 8D7C24 30 lea edi, [esp+30]
0040EF52 . F3:AB rep stos dword ptr es:[edi]
0040EF54 . 52 push edx ; /IniFileName => "C:\WINNT\lrmcu.ini"
0040EF55 . 8D4424 34 lea eax, [esp+34] ; |
0040EF59 . 6A 64 push 64 ; |BufSize = 64 (100.)
0040EF5B . 50 push eax ; |ReturnBuffer
0040EF5C . 68 D8D54100 push 0041D5D8 ; |Default = ""
0040EF61 . 68 40D54100 push 0041D540 ; |code
0040EF66 . 68 E4D34100 push 0041D3E4 ; |regcode ;这里是注册码保存的地方。
0040EF6B . FF15 14714100 call [<&KERNEL32.GetPrivateProfileStringA>] ; \GetPrivateProfileStringA
接下来后面有WritetPrivateProfileStringA,可以看出,程序只是把注册码保存起来,并不做验证,验证是由服务程序启动时候检验的。
在看看0040F170处:
0040F170 /$ 56 push esi
0040F171 |. 8B7424 08 mov esi, [esp+8] ;取参数
0040F175 |. 57 push edi
0040F176 |. 8BFE mov edi, esi
0040F178 |. 83C9 FF or ecx, FFFFFFFF
0040F17B |. 33C0 xor eax, eax
0040F17D |. 33D2 xor edx, edx
0040F17F |. F2:AE repne scas byte ptr es:[edi] ;取参数长度
0040F181 |. F7D1 not ecx
0040F183 |. 49 dec ecx
0040F184 |. 74 1F je short 0040F1A5
0040F186 |> 8A0C32 /mov cl, [edx+esi] ;取出一位
0040F189 |. 8AC2 |mov al, dl ;初始时候是0
0040F18B |. 24 01 |and al, 1 ;al只能为0和1
0040F18D |. 8BFE |mov edi, esi ;保存
0040F18F |. FEC0 |inc al ;al加1,可以看出,当循环计数是偶数时这里是,为奇数时候,是2
0040F191 |. 02C8 |add cl, al ;偶数加1,奇数加2
0040F193 |. 33C0 |xor eax, eax
0040F195 |. 880C32 |mov [edx+esi], cl ;保存回去
0040F198 |. 83C9 FF |or ecx, FFFFFFFF
0040F19B |. 42 |inc edx ;计数加1
0040F19C |. F2:AE |repne scas byte ptr es:[edi] ;取长度
0040F19E |. F7D1 |not ecx
0040F1A0 |. 49 |dec ecx
0040F1A1 |. 3BD1 |cmp edx, ecx ;没完继续
0040F1A3 |.^ 72 E1 \jb short 0040F186
0040F1A5 |> 5F pop edi
0040F1A6 |. 5E pop esi
0040F1A7 \. C2 0400 retn 4
这里比较简单,只是把字符串按每一位是偶数加1,奇数加2。逆也简单,分别减1减2就可以了。
void DecodeMathineCode( char *szMachineCode )
{
int i,nFlag,nLength;
nLength = strlen( szMachineCode );
for( i=0;i<nLength;i++ )
{
nFlag = i%2==0?1:2;
szMachineCode[i] -= nFlag;
}
if( nLength < 11 ) //这里我把不足11位的补'0'了,不知道实际上是怎么处理的
{
for( i=nLength;i<11;i++ )
{
szMachineCode[i] = '0';
}
}
szMachineCode[11] = 0;
}
2,服务端验证
有几个服务程序,找了一下,是在LRMCU.exe中进行验证的。可能是开发的程序员为了调试方便,留了个-debug的命令行运行的接口。
这给我们调试也带来了方便。OD 载入,参数里输入-debug。然后重新启动程序。这个程序没有反调试手段。
bp GetPrivateProfileStringA [esp+4]=="regcode"
F9走,中断第二次的时候,取消断点ALT+F9返回:
0040F36C . 68 38494200 push 00424938 ; /lrmcu.ini
0040F371 . 8D8424 500300>lea eax, [esp+350] ; |
0040F378 . 68 C8000000 push 0C8 ; |BufSize = C8 (200.)
0040F37D . 50 push eax ; |ReturnBuffer
0040F37E . 68 B0754200 push 004275B0 ; |Default = ""
0040F383 . 68 B4604200 push 004260B4 ; |code
0040F388 . 68 A8604200 push 004260A8 ; |regcode
0040F38D . FF15 FC854200 call [<&KERNEL32.GetPrivateProfileStr>; \GetPrivateProfileStringA
0040F393 . 8D8C24 480100>lea ecx, [esp+148] ; 这是返回值,就是我们在注册界面里随便写入的东西
0040F39A . 8D9424 4C0300>lea edx, [esp+34C]
0040F3A1 . 51 push ecx ; 注册码地址
0040F3A2 . 52 push edx
0040F3A3 . E8 981DFFFF call 00401140 ; 这个CALL的功能是把注册码去掉'-'后格式变16进格式
0040F3A8 . 83C4 08 add esp, 8
0040F3AB . 8D8424 800000>lea eax, [esp+80]
0040F3B2 . 6A 3B push 3B
0040F3B4 . 6A 3F push 3F
0040F3B6 . 6A 24 push 24
0040F3B8 . 6A 47 push 47
0040F3BA . 6A 5E push 5E
0040F3BC . 6A 42 push 42
0040F3BE . 6A 31 push 31
0040F3C0 . 6A 62 push 62
0040F3C2 . 68 94604200 push 00426094 ; %c%c%c%c%c%c%c%c
0040F3C7 . 50 push eax
0040F3C8 . FFD5 call ebp ; 这里是解密用到的KEY,怕写字符串被发现,用sprintf
0040F3CA . 8D8C24 A80000>lea ecx, [esp+A8] ; KEY地址
0040F3D1 . 8D9424 700100>lea edx, [esp+170] ; 注册码16进格式
0040F3D8 . 51 push ecx ; KEY进栈
0040F3D9 . 6A 18 push 18 ; 长度是24
0040F3DB . 52 push edx ; 注册码
0040F3DC . E8 9FDE0000 call <jmp.&encryptlib.DecodeBin> ; 解码函数,返回的值还在EDX中
0040F3E1 . 83C4 34 add esp, 34
0040F3E4 . 8D8424 4C0300>lea eax, [esp+34C] ;
0040F3EB . 6A 5C push 5C
0040F3ED . 6A 3A push 3A
0040F3EF . 6A 43 push 43
0040F3F1 . 68 905F4200 push 00425F90 ; %c%c%c
0040F3F6 . 50 push eax
0040F3F7 . FFD5 call ebp ;又是sprintf,凑成"c:\"
0040F3F9 . 83C4 14 add esp, 14
0040F3FC . 8D8C24 A40900>lea ecx, [esp+9A4]
0040F403 . 8D5424 7C lea edx, [esp+7C]
0040F407 . 8D4424 70 lea eax, [esp+70]
0040F40B . 6A 50 push 50 ; /pFileSystemNameSize = 00000050
0040F40D . 51 push ecx ; |pFileSystemNameBuffer
0040F40E . 52 push edx ; |pFileSystemFlags
0040F40F . 8D4C24 1C lea ecx, [esp+1C] ; |
0040F413 . 50 push eax ; |pMaxFilenameLength
0040F414 . 51 push ecx ; |pVolumeSerialNumber
0040F415 . 8D9424 080A00>lea edx, [esp+A08] ; |
0040F41C . 68 04010000 push 104 ; |MaxVolumeNameSize = 104 (260.)
0040F421 . 8D8424 640300>lea eax, [esp+364] ; |
0040F428 . 52 push edx ; |VolumeNameBuffer
0040F429 . 50 push eax ; |RootPathName
0040F42A . FF15 88854200 call [<&KERNEL32.GetVolumeInformation>; \GetVolumeInformationA ;取c盘卷标
0040F430 . 85C0 test eax, eax
0040F432 . 74 31 je short 0040F465
0040F434 . 8B4424 10 mov eax, [esp+10] ; C盘卷标
0040F438 . 85C0 test eax, eax
0040F43A . 75 15 jnz short 0040F451
0040F43C . 8D4C24 10 lea ecx, [esp+10]
0040F440 . 8D9424 4C0300>lea edx, [esp+34C]
0040F447 . 51 push ecx
0040F448 . 52 push edx
0040F449 . E8 611CFFFF call 004010AF
0040F44E . 83C4 08 add esp, 8
0040F451 > 8B4424 10 mov eax, [esp+10] ; C盘卷标
0040F455 . 8D8C24 800000>lea ecx, [esp+80] ; 返回地址,存放卷标16进字符串
0040F45C . 50 push eax
0040F45D . 68 88604200 push 00426088 ; %x
0040F462 . 51 push ecx
0040F463 . EB 14 jmp short 0040F479
0040F465 > FF15 84854200 call [<&KERNEL32.GetLastError>] ; [GetLastError
0040F46B . 50 push eax
0040F46C . 8D9424 840000>lea edx, [esp+84]
0040F473 . 68 88604200 push 00426088 ; %x
0040F478 . 52 push edx
0040F479 > FFD5 call ebp ;这里又一个sprintf,把c盘卷标转成16进制字符串
0040F47B . 83C4 0C add esp, 0C
0040F47E . 8D4424 28 lea eax, [esp+28]
0040F482 . 8D8C24 4C0300>lea ecx, [esp+34C]
0040F489 . C74424 28 C70>mov dword ptr [esp+28], 0C7
0040F491 . 50 push eax
0040F492 . 51 push ecx
0040F493 . FFD6 call esi ; 取计算机名
0040F495 . 8DBC24 4C0300>lea edi, [esp+34C] ; 计算机名
0040F49C . 83C9 FF or ecx, FFFFFFFF
0040F49F . 33C0 xor eax, eax
0040F4A1 . 8D9424 800000>lea edx, [esp+80] ; c盘卷标字符串
0040F4A8 . F2:AE repne scas byte ptr es:[edi]
0040F4AA . F7D1 not ecx ; 计算机名长度
0040F4AC . 2BF9 sub edi, ecx
0040F4AE . 8BF7 mov esi, edi ; 计算机名
0040F4B0 . 8BE9 mov ebp, ecx ; 计算机名长度
0040F4B2 . 8BFA mov edi, edx ; 卷标
0040F4B4 . 83C9 FF or ecx, FFFFFFFF
0040F4B7 . F2:AE repne scas byte ptr es:[edi]
0040F4B9 . 8BCD mov ecx, ebp
0040F4BB . 4F dec edi
0040F4BC . C1E9 02 shr ecx, 2
0040F4BF . F3:A5 rep movs dword ptr es:[edi], dword p>
0040F4C1 . 8BCD mov ecx, ebp
0040F4C3 . 83E1 03 and ecx, 3
0040F4C6 . F3:A4 rep movs byte ptr es:[edi], byte ptr>; 以上是把C盘卷标和计算机名连起来。保留前11位。
0040F4C8 . 888424 8B0000>mov [esp+8B], al
0040F4CF . 8D8424 800000>lea eax, [esp+80] ; 取出计算出的11位字符
0040F4D6 . 8D8C24 480100>lea ecx, [esp+148] ; 这是上面那个regcode运算后的结果
0040F4DD . 50 push eax
0040F4DE . 51 push ecx
0040F4DF . FFD3 call ebx
0040F4E1 . 83C4 08 add esp, 8 ; 看注册码计算结果中是否有C盘卷标和机器名
0040F4E4 85C0 test eax, eax ; 如果没有就是未注册的,跳走
0040F4E6 0F84 DD000000 je 0040F5C9
0040F4EC 8B35 44874200 mov esi, [<&MSVCRT.strncpy>] ; msvcrt.strncpy
0040F4F2 B9 32000000 mov ecx, 32
0040F4F7 33C0 xor eax, eax
0040F4F9 ? 8DBC24 80000000 lea edi, [esp+80] ; 卷标和机器名连接
0040F500 ? F3:AB rep stos dword ptr es:[edi] ; 如果正确,先把前面计算的卷标和计算机名清空
0040F502 . 8D9424 53010000 lea edx, [esp+153]
0040F509 ? 6A 03 push 3 ;取3个字符
0040F50B ? 8D8424 84000000 lea eax, [esp+84] ;
0040F512 . 52 push edx ;注册码计算后,第12位的指针,可以看出前11位应该 ;是C盘卷标字符和计算机名连接起来的前11位
0040F513 . 50 push eax
0040F514 . FFD6 call esi ; strncpy 从12位起取3位
0040F516 . 8B2D 48874200 mov ebp, [<&MSVCRT.atoi>] ; msvcrt.atoi
0040F51C . 8D8C24 8C0000>lea ecx, [esp+8C]
0040F523 . 51 push ecx ; /s
0040F524 . FFD5 call ebp ; \atoi
0040F526 . A3 E47A4200 mov [427AE4], eax ; 取出三位,变为整数,保存在[427AE4]处
0040F52B . B9 32000000 mov ecx, 32
0040F530 . 33C0 xor eax, eax
0040F532 . 8DBC24 900000>lea edi, [esp+90]
0040F539 . F3:AB rep stos dword ptr es:[edi]
0040F53B . 8D9424 660100>lea edx, [esp+166]
0040F542 . 6A 03 push 3
0040F544 . 8D8424 940000>lea eax, [esp+94]
0040F54B . 52 push edx
0040F54C . 50 push eax ; 再取三位
0040F54D . FFD6 call esi
0040F54F . 8D8C24 9C0000>lea ecx, [esp+9C]
0040F556 . 51 push ecx
0040F557 . FFD5 call ebp
0040F559 . A3 484C4200 mov [424C48], eax ; 再三位变整数,保存在[424C48]
0040F55E . B9 32000000 mov ecx, 32
0040F563 . 33C0 xor eax, eax
0040F565 . 8DBC24 A00000>lea edi, [esp+A0]
0040F56C . F3:AB rep stos dword ptr es:[edi]
0040F56E . 8D9424 790100>lea edx, [esp+179]
0040F575 . 6A 03 push 3
0040F577 . 8D8424 A40000>lea eax, [esp+A4]
0040F57E . 52 push edx
0040F57F . 50 push eax ; 再来三位
0040F580 . FFD6 call esi
0040F582 . 8D8C24 AC0000>lea ecx, [esp+AC]
0040F589 . 51 push ecx
0040F58A . FFD5 call ebp
0040F58C . A3 EC7A4200 mov [427AEC], eax ; 再三位变整数结果保存在[427AEC]
0040F591 . B9 32000000 mov ecx, 32
0040F596 . 33C0 xor eax, eax
0040F598 . 8DBC24 B00000>lea edi, [esp+B0]
0040F59F . F3:AB rep stos dword ptr es:[edi]
0040F5A1 . 8D9424 8C0100>lea edx, [esp+18C]
0040F5A8 . 6A 03 push 3
0040F5AA . 8D8424 B40000>lea eax, [esp+B4]
0040F5B1 . 52 push edx
0040F5B2 . 50 push eax ; 再来三位
0040F5B3 . FFD6 call esi
0040F5B5 . 8D8C24 BC0000>lea ecx, [esp+BC]
0040F5BC . 51 push ecx
0040F5BD . FFD5 call ebp
0040F5BF . 83C4 40 add esp, 40
0040F5C2 . A3 E87A4200 mov [427AE8], eax ; 变整后保存在[427AE8]
0040F5C7 . EB 20 jmp short 0040F5E9
0040F5C9 . 33C0 xor eax, eax ; 这里是上面出错后跳转的地方
0040F5CB . C705 E47A4200>mov dword ptr [427AE4], 1 ; 如果出错,这里设置默认值。
0040F5D5 . A3 E87A4200 mov [427AE8], eax ; 结合使用结果,可以看出[427AE4]处保存的就是
0040F5DA . C705 484C4200>mov dword ptr [424C48], 2DA ; 会议室最大登录的用户数。其他几个值未知
0040F5E4 . A3 EC7A4200 mov [427AEC], eax ;
0040F5E9 > B9 10000000 mov ecx, 10
0040F5EE . 33C0 xor eax, eax
0040F5F0 . 8D7C24 30 lea edi, [esp+30]
到这简单整理一下,可以得出注册码在经过call <jmp.&encryptlib.DecodeBin>计算后大概应该是这样子的:
aaaaaaaaaaabbbcccdddeee
a是11位字符串,C盘卷标16进字符串和计算记名连在一起,保留11位
b是表示会议室最大登录用户数
c,d,e数字意义未知
是不是觉得这里可以爆破了?不这才刚开始。
现在来看看encryptlib.DecodeBin是什么东西,在这里下个断点后,重新载入:
10001260 >/$ 83EC 08 sub esp, 8
10001263 |. 8B4424 0C mov eax, [esp+C] ; 注册码
10001267 |. 53 push ebx
10001268 |. 55 push ebp
10001269 |. 8B6C24 18 mov ebp, [esp+18] ; 长度
1000126D |. 56 push esi
1000126E |. 57 push edi
1000126F |. 894424 1C mov [esp+1C], eax ; 注册码地址
10001273 |> BB 08000000 /mov ebx, 8 ; 8个一计算
10001278 |. 3BEB |cmp ebp, ebx ;
1000127A |. 7D 02 |jge short 1000127E ;
1000127C |. 8BDD |mov ebx, ebp ;
1000127E |> 33C9 |xor ecx, ecx
10001280 |. 8B7424 1C |mov esi, [esp+1C] ; 注册码地址
10001284 |. 894C24 10 |mov [esp+10], ecx ;
10001288 |. 8D7C24 10 |lea edi, [esp+10] ;
1000128C |. 894C24 14 |mov [esp+14], ecx ;
10001290 |. 8BCB |mov ecx, ebx
10001292 |. 8BD1 |mov edx, ecx ;
10001294 |. 8B4424 24 |mov eax, [esp+24] ; 解密KEY
10001298 |. C1E9 02 |shr ecx, 2 ;
1000129B |. F3:A5 |rep movs dword ptr es:[edi], dword ptr [esi] ;
1000129D |. 8BCA |mov ecx, edx ;
1000129F |. 50 |push eax ; 解密KEY
100012A0 |. 83E1 03 |and ecx, 3 ;
100012A3 |. F3:A4 |rep movs byte ptr es:[edi], byte ptr [esi] ;
100012A5 |. 8D4C24 14 |lea ecx, [esp+14]
100012A9 |. 51 |push ecx ; 注册码
100012AA E8 51FFFFFF call 10001200 ; KEY和注册码进去,计算
100012AF |. 8B4424 24 |mov eax, [esp+24] ; 注册码地址
100012B3 |. 8BCB |mov ecx, ebx ;
100012B5 |. 8BD1 |mov edx, ecx
100012B7 |. 8D7424 18 |lea esi, [esp+18] ; 刚计算完的中间结果
100012BB |. 8BF8 |mov edi, eax ; 注册码
100012BD |. 2BEB |sub ebp, ebx
100012BF |. C1E9 02 |shr ecx, 2
100012C2 |. F3:A5 |rep movs dword ptr es:[edi], dword ptr [esi]
100012C4 |. 8BCA |mov ecx, edx
100012C6 |. 83C4 08 |add esp, 8
100012C9 |. 83E1 03 |and ecx, 3
100012CC |. 03C3 |add eax, ebx
100012CE |. 85ED |test ebp, ebp
100012D0 |. F3:A4 |rep movs byte ptr es:[edi], byte ptr [esi]
100012D2 |. 894424 1C |mov [esp+1C], eax
100012D6 |.^ 7F 9B \jg short 10001273
100012D8 |. 5F pop edi
100012D9 |. 5E pop esi
100012DA |. 5D pop ebp
100012DB |. 33C0 xor eax, eax
100012DD |. 5B pop ebx
100012DE |. 83C4 08 add esp, 8
100012E1 \. C3 retn
这里就是把进来的24字符分成3个8 BYTE,然后同解密KEY一起调用10001200。所以可以大概判定原始注册码应该是去掉'-'后有48个字符。
继续进到 10001200
10001200 /$ 53 push ebx
10001201 |. 56 push esi
10001202 |. 8B7424 0C mov esi, [esp+C] ; 值
10001206 |. 57 push edi
10001207 |. 8B7C24 14 mov edi, [esp+14] ; KEY
1000120B |. 6A 02 push 2
1000120D |. 57 push edi ; KEY
1000120E |. 56 push esi ; 值地址,函数返回也在这里
1000120F |. E8 3CFEFFFF call 10001050 ; 计算,取8个值同KEY异或
10001214 |. 6A 02 push 2 ; 进去个2
10001216 |. 68 20330010 push 10003320 ; 这是一个索引表的地址
1000121B |. 56 push esi ; 再算
1000121C |. E8 7FFEFFFF call 100010A0 ; 查索引表,返回值还在ESI中
10001221 |. 83C4 18 add esp, 18
10001224 |. BB 05000000 mov ebx, 5 ; 循环5次
10001229 |> 6A 02 /push 2 ; 2进去
1000122B |. 57 |push edi ; KEY
1000122C |. 56 |push esi ; 计算中间结果
1000122D |. E8 1EFEFFFF |call 10001050 ; 异或啊
10001232 |. 6A 02 |push 2 ; 2
10001234 |. 56 |push esi ; 值进去,再计算
10001235 |. E8 A6FEFFFF |call 100010E0 ; 来回查表,完事,值还在ESI中
1000123A |. 6A 02 |push 2
1000123C |. 68 20330010 |push 10003320
10001241 |. 56 |push esi
10001242 |. E8 59FEFFFF |call 100010A0 ; 算出的东西再查表
10001247 |. 83C4 20 |add esp, 20
1000124A |. 4B |dec ebx
1000124B |.^ 75 DC \jnz short 10001229
1000124D |. 6A 02 push 2
1000124F |. 57 push edi
10001250 |. 56 push esi
10001251 |. E8 FAFDFFFF call 10001050
10001256 |. 83C4 0C add esp, 0C
10001259 |. 33C0 xor eax, eax
1000125B |. 5F pop edi
1000125C |. 5E pop esi
1000125D |. 5B pop ebx
1000125E \. C3 retn
到这里,熟悉算法的人应该能大概看出是什么东西了。不过我跟的时候不熟。一直把里面的都跟完了。并把这个过程用C还原了。
我知道这个过程肯定是可逆的,但是我逆不出来。觉得应该不是作者自己开发的。所以到网上找对称算法。看到AES算法的介绍
后,里面有b,d,9,e几个参数跟100010E0里的几个对应上了才知道。
100010E0处:
100010E0 /$ 83EC 0C sub esp, 0C
100010E3 |. 8B5424 14 mov edx, [esp+14] ; 参数1
100010E7 |. 53 push ebx
100010E8 |. 55 push ebp
100010E9 |. 8B6C24 18 mov ebp, [esp+18] ; 值地址
100010ED |. 56 push esi
100010EE |. 57 push edi
100010EF |. 33FF xor edi, edi
100010F1 |. 81E2 FF000000 and edx, 0FF
100010F7 |. 895424 10 mov [esp+10], edx ; 2
100010FB |. 0F8E B9000000 jle 100011BA
10001101 |> 8D443C 14 /lea eax, [esp+edi+14] ; 地址定位
10001105 |. 8D4C24 14 |lea ecx, [esp+14]
10001109 |. 894424 24 |mov [esp+24], eax ; 地址定位
1000110D |. 8BC5 |mov eax, ebp ; 值
1000110F |. 2BC1 |sub eax, ecx ; 定位用
10001111 |. BE 03000000 |mov esi, 3 ;
10001116 |. 894424 20 |mov [esp+20], eax ; 存起来
1000111A |> 8D56 FE |/lea edx, [esi-2]
1000111D |. 81E2 03000080 ||and edx, 80000003 ; 测试是否是负数?
10001123 |. 79 05 ||jns short 1000112A ; 没有走
10001125 |. 4A ||dec edx
10001126 |. 83CA FC ||or edx, FFFFFFFC
10001129 |. 42 ||inc edx
1000112A |> 8D0457 ||lea eax, [edi+edx*2] ;
1000112D |. 8A0C28 ||mov cl, [eax+ebp] ; 取得一个索引的值
10001130 |. 51 ||push ecx ;
10001131 |. 6A 0B ||push 0B ; B
10001133 |. E8 C8FEFFFF ||call 10001000 ; a表加b表/ff 余数再查表 回AL
10001138 |. 8D56 FF ||lea edx, [esi-1]
1000113B |. 8AD8 ||mov bl, al ; 返回值,存起来
1000113D |. 81E2 03000080 ||and edx, 80000003 ; 去掉进位,只要后3位
10001143 |. 79 05 ||jns short 1000114A
10001145 |. 4A ||dec edx
10001146 |. 83CA FC ||or edx, FFFFFFFC
10001149 |. 42 ||inc edx
1000114A |> 8D0457 ||lea eax, [edi+edx*2] ;
1000114D |. 8A0C28 ||mov cl, [eax+ebp] ; 再取一位
10001150 |. 51 ||push ecx ; 值为参数1
10001151 |. 6A 0D ||push 0D ; 参数2
10001153 |. E8 A8FEFFFF ||call 10001000 ; a表加b表/ff 余数再查表 回AL
10001158 |. 8BD6 ||mov edx, esi
1000115A |. 32D8 ||xor bl, al ; 俩次结果xor,还在BL中
1000115C |. 81E2 03000080 ||and edx, 80000003
10001162 |. 79 05 ||jns short 10001169
10001164 |. 4A ||dec edx
10001165 |. 83CA FC ||or edx, FFFFFFFC
10001168 |. 42 ||inc edx
10001169 |> 8D0457 ||lea eax, [edi+edx*2]
1000116C |. 8A0C28 ||mov cl, [eax+ebp] ; 3位了
1000116F |. 51 ||push ecx
10001170 |. 6A 09 ||push 9
10001172 |. E8 89FEFFFF ||call 10001000
10001177 |. 8B5424 38 ||mov edx, [esp+38] ; 定位值
1000117B |. 32D8 ||xor bl, al ; 结果又异或
1000117D |. 8B4424 3C ||mov eax, [esp+3C] ; 取值地址。。。
10001181 |. 8A0C02 ||mov cl, [edx+eax] ; 0 位
10001184 |. 51 ||push ecx
10001185 |. 6A 0E ||push 0E
10001187 |. E8 74FEFFFF ||call 10001000 ; 再来
1000118C |. 83C4 20 ||add esp, 20
1000118F |. 32D8 ||xor bl, al ; XOR玩,4位完了
10001191 |. 8B4424 24 ||mov eax, [esp+24]
10001195 |. 46 ||inc esi
10001196 |. 8818 ||mov [eax], bl ; 值存起来
10001198 |. 8D56 FD ||lea edx, [esi-3]
1000119B |. 83C0 02 ||add eax, 2
1000119E |. 83FA 04 ||cmp edx, 4
100011A1 |. 894424 24 ||mov [esp+24], eax ; 保存值的地址?
100011A5 |.^ 0F8C 6FFFFFFF |\jl 1000111A
100011AB |. 8B4424 10 |mov eax, [esp+10]
100011AF |. 47 |inc edi
100011B0 |. 3BF8 |cmp edi, eax
100011B2 |.^ 0F8C 49FFFFFF \jl 10001101
100011B8 |. 8BD0 mov edx, eax
100011BA |> 8D4C24 14 lea ecx, [esp+14] ; 上面计算的结果
100011BE |. 8D4424 14 lea eax, [esp+14] ; 上面计算的结果
100011C2 |. 2BE9 sub ebp, ecx
100011C4 |. C74424 24 04000000 mov dword ptr [esp+24], 4 ; 循环计数
100011CC |> 85D2 /test edx, edx
100011CE |. 7E 15 |jle short 100011E5
100011D0 |. 8BCA |mov ecx, edx
100011D2 |. 8BF0 |mov esi, eax ; 上面计算的中间结果
100011D4 |. 8BD9 |mov ebx, ecx
100011D6 |. 8D3C28 |lea edi, [eax+ebp]
100011D9 |. C1E9 02 |shr ecx, 2
100011DC |. F3:A5 |rep movs dword ptr es:[edi], dword ptr [esi] ; 结果保存
100011DE |. 8BCB |mov ecx, ebx
100011E0 |. 83E1 03 |and ecx, 3
100011E3 |. F3:A4 |rep movs byte ptr es:[edi], byte ptr [esi]
100011E5 |> 8B4C24 24 |mov ecx, [esp+24]
100011E9 |. 83C0 02 |add eax, 2
100011EC |. 49 |dec ecx
100011ED |. 894C24 24 |mov [esp+24], ecx
100011F1 |.^ 75 D9 \jnz short 100011CC
100011F3 |. 5F pop edi
100011F4 |. 5E pop esi
100011F5 |. 5D pop ebp
100011F6 |. 5B pop ebx
100011F7 |. 83C4 0C add esp, 0C
100011FA \. C3 retn
这里看到b,d,9,e了。所以可以知道是AES算法的解密过程。10001000处大概可以用如下代码表示:
unsigned char GetMulCode( unsigned char k,unsigned char c )
{
return k*c==0?0:alog[ (log[k]+log[c])%0xFF ];
}
其中alog和log知道aes算法的应该都知道是什么东西,反正我跟的时候是不知道。真晕。
到这里基本上差不多了。程序好象把行列变换都放在100010E0里了。不过到现在我还对这个算法不是太明白。这个程序中间
循环的次数是5次。是变形的AES?这都有什么规律可变,请达人指教一下。
现在整一下整个注册的过程。
1,服务管理器里,会根据C盘卷标和计算机名进行运算。得到一个字符串。然后发给厂家。
2,厂家会把字符串逆出后,取前11位,然后后面再加4个3字符的数字字符串。格式:aaaaaaaaaaabbbcccdddeee
3,用这个算法的加密过程进行加密,然后同当前机器的信息相比较,若正确,则把后面几个值解析出来放到相应
的内存位置。若不正确。置默认值。
程序运行时候,还有几处调用DecodeBin,若出错,还是在相应内存处置默认值。
Dll里只有解密算法,没有加密算法,但是现在我们知道了所使用的算法和KEY。就可以得出加密过程了。
后面附有完整的代码实现(程序中有一处是错的,明白算法的自然会知道,不明白的,拿来也不能直接用)。这并不是完整的AES算
法过程,只是这个程序里的实现。
虽然可以生成注册码了。但是那个最大用户数字若超过4,程序还是会报超过最大用户数。这是体验版的限制。在初始化
每个房间的时候,用一个双向链表保存登录用户的信息,这个链表只有4项。具体如果做这里就不说了。请支持国产软件。
因为注册码是免费发放的,但是我想也是在4个范围之内。就算你有注册机,你不给钱,也不得不到正式版的程序。
#include "stdio.h"
#include "string.h"
#define ENCODE 0
#define DECODE 1
unsigned char szIndexTable[]="..."; //这个表在程序中保存,1024个字节,里面包含了log,alog,sbox和sbox的逆,就不贴了。
unsigned char *log = szIndexTable;
unsigned char *alog = szIndexTable+0x100;
unsigned char *sbox = szIndexTable+0x200;
unsigned char *invsbox= szIndexTable+0x300;
unsigned char *Key = "\x62\x31\x42\x5E\x47\x24\x3F\x3B";
int nRowsTable[8][4]={
{ 2,4,6,0 },
{ 3,5,7,1 },
{ 4,6,0,2 },
{ 5,7,1,3 },
{ 6,0,2,4 },
{ 7,1,3,5 },
{ 0,2,4,6 },
{ 1,3,5,7 }};
void AddRoundKey( unsigned char *Value,unsigned char *Key )
{
int i;
for ( i=0;i<8;i++ )
{
Value[i] ^= Key[i];
}
}
void SubBytes( unsigned char *Value,int nFlag )
{
int i;
char *table = nFlag==ENCODE?sbox:invsbox;
for( i=0;i<8;i++ )
{
Value[i] = table[ Value[i] ];
}
}
unsigned char GetMulCode( unsigned char k,unsigned char c )
{
return k*c==0?0:alog[ (log[k]+log[c])%0xFF ];
}
void MixColumns( unsigned char *Value,int nFlag )
{
int i;
unsigned char result[8];
unsigned char a,b,c,d;
a = nFlag==ENCODE?2:0xb;
b = nFlag==ENCODE?1:0xd;
c = nFlag==ENCODE?1:0x9;
d = nFlag==ENCODE?3:0xe;
for( i=0;i<8;i++ )
{
result[i] = GetMulCode( a,Value[ nRowsTable[i][0] ] )^
GetMulCode( b,Value[ nRowsTable[i][1] ] )^
GetMulCode( c,Value[ nRowsTable[i][2] ] )^
GetMulCode( d,Value[ nRowsTable[i][3] ] );
}
memcpy( Value,result,8 );
}
void AesDecode( unsigned char *Value,unsigned char *Key )
{
int i;
AddRoundKey( Value,Key );
SubBytes( Value,DECODE );
for( i=0;i<5;i++ )
{
AddRoundKey( Value,Key );
MixColumns( Value,DECODE );
SubBytes( Value,DECODE );
}
AddRoundKey( Value,Key );
}
void AesEncode( unsigned char *Value,unsigned char *Key )
{
int i;
AddRoundKey( Value,Key );
for( i=0;i<5;i++ )
{
SubBytes( Value,ENCODE );
MixColumns( Value,ENCODE );
AddRoundKey( Value,Key );
}
SubBytes( Value,ENCODE );
AddRoundKey( Value,Key );
}
int MakeHex( unsigned char *Value )
{
int i,nIndex=0;
unsigned char tmpdat[100]={0},c1,c2;
for( i=0;i<(int)strlen(Value);i++ )
{
if ( Value[i] != '-' )
{
tmpdat[nIndex++] = Value[i];
}
}
if ( strlen( tmpdat ) != 48 )
{
return -1;
}
for( i=0;i< (int)strlen(tmpdat);i+=2 )
{
c1 = tmpdat[i];
c2 = tmpdat[i+1];
if ( c1 >= '0' && c1 <= '9' )
{
c1 -= '0';
}
else if( c1 >= 'a' && c1 <= 'f' )
{
c1 -= 'a';
c1 += 10;
}
else
{
return -1;
}
if ( c2 >= '0' && c2 <= '9' )
{
c2 -= '0';
}
else if( c2 >= 'a' && c2 <= 'f' )
{
c2 -= 'a';
c2 += 10;
}
else
{
return -1;
}
tmpdat[i/2] = c1*16+c2;
}
memcpy( Value,tmpdat,24 );
return 0;
}
int MakeHexStr( unsigned char *Value,unsigned char *Output )
{
int i,nIndex=0;
unsigned char tmpdat[100]={0},c1,c2;
for( i=0;i<24;i++ )
{
c1 = Value[i]>>4;
c2 = Value[i]&0x0F;
if ( c1 >= 0 && c1 <= 9 )
{
tmpdat[i*2] = c1+'0';
}
else if( c1 >= 0xa && c1 <= 0xf )
{
tmpdat[i*2] = c1-10+'a';
}
else
{
return -1;
}
if ( c2 >= 0 && c2 <= 9 )
{
tmpdat[i*2+1] = c2 + '0';
}
else if( c2 >= 0xa && c2 <= 0xf )
{
tmpdat[i*2+1] = c2-10+'a';
}
else
{
return -1;
}
}
for( i=0;i<4;i++)
{
strncpy( Output+i*13,tmpdat+i*12,12 );
if ( i != 3 )
{
strcpy( Output+i*13+12,"-" );
}
}
*( Output+51 ) = 0;
return 0;
}
void MakeSuperVKey( unsigned char *Value,unsigned char*Key,unsigned char *OutPut,int nFlag )
{
int i;
unsigned char result[8];
unsigned char tmpdat[100];
strcpy(tmpdat,Value);
if ( nFlag == DECODE )
{
MakeHex( tmpdat );
}
for( i=0;i<3;i++ )
{
memcpy( result,tmpdat+i*8,8 );
if ( nFlag == ENCODE )
{
AesEncode( result,Key );
}
else
{
AesDecode( result,Key );
}
memcpy( tmpdat+i*8,result,8 );
}
if ( nFlag == ENCODE )
{
MakeHexStr( tmpdat,OutPut );
}
else
{
strcpy( OutPut,tmpdat );
}
}
void DecodeMathineCode( char *szMachineCode )
{
int i,nFlag,nLength;
nLength = strlen( szMachineCode );
for( i=0;i<nLength;i++ )
{
nFlag = i%2==0?1:2;
szMachineCode[i] -= nFlag;
}
if( nLength < 11 )
{
for( i=nLength;i<11;i++ )
{
szMachineCode[i] = '0';
}
}
szMachineCode[11] = 0;
}
int main()
{
char szCode[100]="...";
int val1,val2,val3,val4;
printf( "Input Machine Code : " );
scanf( "%s",szCode );
DecodeMathineCode( szCode );
printf( "Input Value 1 : " );
scanf( "%d",&val1 );
printf( "Input Value 2 : " );
scanf( "%d",&val2 );
printf( "Input Value 3 : " );
scanf( "%d",&val3 );
printf( "Input Value 4 : " );
scanf( "%d",&val4 );
sprintf( szCode+strlen(szCode),"%03d%03d%03d%03d",val1,val2,val3,val4 );
MakeSuperVKey( szCode,Key,szCode,ENCODE );
printf( "The RegCode Is : %s\n",szCode );
return 0;
}
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)