LYQingYe 发表于 2016-8-2 15:00

Okdo Document Converter Professional 二次验证算法分析

[软件名称]:OkdoDocument Converter Professional
[编译类型]:Delphi
[是否有壳]:无壳
[注册类型]:注册码注册
[作者信息]:LYQingYe:    学到东西的别忘记评分!

////相关算法帖// ZD SoftScreen Recorder v9.8算法逆向+keygenhttps://www.52hb.com/thread-26301-1-1.html PDFPassword Remover 算法逆向https://www.52hb.com/thread-26299-1-1.htmlEditPlus v4.0 算法分析+ keygen
https://www.52hb.com/thread-17607-1-1.html
**** Hidden Message *****
//第一次校验思路总结//将我们输入的Key 总共20位 “01234567890123456789”, 每次取一位 ‘0’ 调用 CharToHex 将字符串//转换为 整数(hex)数据 0 , 循环19次,将 Key的前 19为数字加起来 得到Addupdate.//余数 =Addupdate % 0XA , 然后余数跟Key第20位比较,一定要相等,否则失败,在此我们得到了 Key第20位的来源.
//且看第二次校验中的 -> 零散校验
009D5BE3   test al,al                                        ;接着上面第一次校验
009D5BE5   jnz short Converte.009D5C34
009D5BE7   mov eax,dword ptr ds:
009D5BEC   push dword ptr ds:
009D5BEE   mov eax,dword ptr ds:
009D5BF3   push dword ptr ds:
009D5BF5   push Converte.009D5FCC                   ;_regcode.ini
009D5BFA   lea eax,dword ptr ss:
009D5BFD   mov edx,0x3
009D5C02   call Converte.0040535C
009D5C07   mov eax,dword ptr ss:
009D5C0A   xor ecx,ecx
009D5C0C   xor edx,edx
009D5C0E   call Converte.007631EC
009D5C13   mov eax,dword ptr ds:
009D5C18   mov byte ptr ds:,0x0
009D5C1B   mov eax,dword ptr ds:
009D5C20   mov eax,dword ptr ds:
009D5C22   call Converte.009B4544
009D5C27   mov eax,dword ptr ss:
009D5C2A   call Converte.004A37CC
009D5C2F   jmp Converte.009D5EB5
009D5C34   lea edx,dword ptr ss:          ;EDX = NewBuffer
009D5C37   mov eax,dword ptr ds:
009D5C3C   mov eax,dword ptr ds:
009D5C3E   call Converte.0040B090                   ;生成静态字符串str 1 = “31000000”
009D5C43   mov edx,dword ptr ss:          ;EDX = Str1
009D5C46   lea ecx,dword ptr ss:          ;ECX = NewBuffer2
009D5C49   mov eax,dword ptr ds:

009D5C4E   mov eax,dword ptr ds:               ; 又得到静态字符串Str2 =
"363530353A303332363633363530363233373137343434343B36373034353736353A3034333335313B34"
009D5C50   call Converte.009D6944                   ; 得到静态字符串 Str3 = "472782104414724015356666945267547826117396"

009D5C55   mov eax,dword ptr ss:
009D5C58   lea ecx,dword ptr ss:
009D5C5B   mov edx,0xA
009D5C60   call Converte.00762F0C                        ;获得静态字符串Str4
009D5C65   mov eax,dword ptr ss:          ;Str4 = ‘267’
009D5C68   call Converte.0040B2E0                   ;CharToHex,将字符串转换为hex数据
009D5C6D   push eax
009D5C6E   lea edx,dword ptr ss:          ;NEWBUFFER
009D5C71   mov eax,dword ptr ss:
009D5C74   mov eax,dword ptr ds:
009D5C7A   call Converte.00484EB8                   ;GetKeyLength 获取Key的长度
009D5C7F   mov eax,dword ptr ss:          ;Eax -> Key
009D5C82   lea edx,dword ptr ss:          ;EDX -> Buffer
009D5C85   call Converte.0040AC10
009D5C8A   mov edx,dword ptr ss:               ; Edx -> Key
009D5C8D   mov eax,dword ptr ds:
009D5C92   mov eax,dword ptr ds:
009D5C94   pop ecx                                  ;0012FAC8
009D5C95   call Converte.008D62B4                         ;开始零散校验
009D5C9A   test al,al
009D5C9C   je Converte.009D5D76

//上面是零散校验的准备阶段,准备阶段很简单,重要的就是 Str4 = ‘267’ ,他会被用作计算值.
//零散校验的次数有很多次,每次Str4 的值都不一样,下面看零散校验,不难和第一次校验有些区别
008D62B4    >push ebp
008D62B5    >mov ebp,esp
008D62B7    >add esp,-0x10
008D62BA    >push ebx
008D62BB    >push esi
008D62BC    >push edi
008D62BD    >xor ebx,ebx
008D62BF    >mov dword ptr ss:,ebx
008D62C2    >mov dword ptr ss:,ebx
008D62C5    >mov esi,ecx
008D62C7    >mov dword ptr ss:,edx
008D62CA    >mov eax,dword ptr ss:
008D62CD    >call Converte.0040548C                   ;GetKey 获得输入的Key,和第一次校验差不多的步骤
008D62D2    >xor eax,eax
008D62D4    >push ebp
008D62D5    >push Converte.008D63A9
008D62DA    >push dword ptr fs:
008D62DD    >mov dword ptr fs:,esp
008D62E0    >mov byte ptr ss:,0x0
008D62E4    >mov eax,dword ptr ss:
008D62E7    >call Converte.0040529C                        ;GetKeyLength 获取Key长度
008D62EC    >test eax,eax                              ;判断长度是否为0
008D62EE    >jnz short Converte.008D62F9               
008D62F0    >mov byte ptr ss:,0x0
008D62F4    >jmp Converte.008D6386
008D62F9    >mov eax,dword ptr ss:
008D62FC    >call Converte.0040529C
008D6301    >cmp eax,0x14                              ;判断长度是否为20,若不是则失败
008D6304    >je short Converte.008D630C
008D6306    >mov byte ptr ss:,0x0
008D630A    >jmp short Converte.008D6386
008D630C    >xor eax,eax
008D630E    >push ebp
008D630F    >push Converte.008D637C
008D6314    >push dword ptr fs:
008D6317    >mov dword ptr fs:,esp
008D631A    >lea eax,dword ptr ss:
008D631D    >push eax
008D631E    >mov ecx,0x4
008D6323    >mov edx,0x1
008D6328    >mov eax,dword ptr ss:                   : Eax -> Key         
008D632B    >call Converte.004054FC                   ;获取KEY 前4位
008D6330    >mov eax,dword ptr ss:
008D6333    >call Converte.0040B2E0                   ;CharToHex ,将Key前四位转换为整数,我们设为key4bit
008D6338    >mov ebx,eax
008D633A    >lea eax,dword ptr ss:
008D633D    >mov edx,dword ptr ss:                   ; Edx ->Key      
008D6340    >mov dl,byte ptr ds:             ;获取Key的 第0xD位,
008D6343    >call Converte.004051B4                   ;
008D6348    >mov eax,dword ptr ss:         ;Key的第 0xE位      
008D634B    >call Converte.0040B2E0                   ;CharToHex ,将第0xD位转换为整数
008D6350    >mov ecx,eax                              ;ECX = Key的0XD位
008D6352    >mov eax,ebx                                 ;EAX= key4bit      
008D6354    >cdq
008D6355    >idiv esi                                 ; Esi 为零散校验前初始化的Str4 ‘267’ 对应的整数 267
008D6357    >mov edi,eax                              ; edi =key4bit / 267 ,Edi存放商
008D6359    >mov eax,ebx
008D635B    >cdq
008D635C    >idiv esi                                 ;再次计算 key4bit / 267 ,EDX为余数
008D635E    >add edi,edx                              ;calc = 余数 + 商
008D6360    >mov eax,edi                                 ;Eax = calc
008D6362    >mov ebx,0xA                              ;EBX = 0XA
008D6367    >cdq
008D6368    >idiv ebx                                           ;余数2 = calc % 0XA      
008D636A    >cmp ecx,edx                              ;判断余数2是否等于Key的0XD位
008D636C    >jnz short Converte.008D6372                   ; 一定要等于,否则失败

//零散校验算法总结.,零散校验1初始化阶段会生成静态字符串Str4 = ‘267’ ,并转换为 整数获取Key前4位转换为整数,命名为 Key4bit .商= Key4bit / 267余数= Key4bit % 267 余数2= (商 + 余数) % 0XAKey的第0XD位要等于余数2 ,所以我们得到的Key第14位的来源//同样的代码校验,下面依次进行零散校验2初始化阶段会生成静态字符串Str4 = ‘945’ ,并转换为 整数00948860    . 8A52 0C   mov dl,byte ptrds:             ;第14位获取Key前4位转换为整数,命名为 Key4bit .商= Key4bit / 945余数= Key4bit % 945 余数2= (商 + 余数) % 0XAKey的第0XD位要等于余数2 ,所以我们得到的Key第14位的来源
//同样的代码校验,下面依次进行零散校验3初始化阶段会生成静态字符串Str4 = ‘356’ ,并转换为 整数0092E16C    . 8A52 0A   mov dl,byte ptrds:      ; 第11位获取Key前4位转换为整数,命名为 Key4bit .商= Key4bit / 356余数= Key4bit % 356 余数2= (商 + 余数) % 0XAKey的第0XB位要等于余数2 ,所以我们得到的Key第11位的来源
//有三次零散校验分别可以得到Key的第 11, 14 ,15 位的来源 ,加上 第一次校验 可以得到 第20位的来源//下面手动算一个注册码随机取一个四位数字 ,例如 ‘1687’ 1687 / 267 = 61687 % 267 = 85(6 + 85) % 10 = 1所以第14位为1继续1687 / 945= 11687 % 945 = 742(742 + 1) % 10 = 3 所以第13位为 3继续1687 / 356 = 41687 % 356 = 263(4 + 263) % 10 = 7 所以第11位为 7这样我们可以生成一个 19位的 Key其它位用随机值 填充1687 1234 58 7 1311 5874 下面计算20位Addupdate = 1 + 6 + 8 + 7 + 1 + 2+ 3 + 4 + 5 + 8 + 7 + 1 + 3 + 1+ 1+ 5 + 8 + 7 + 4        = 8282 % 10 = 2 所以第20位为2组装成20位Key则为16871234587131158742
输入Key显示成功


//但发现重启程序后还是未注册,这就触发了二次验证,可以通过,搜索字符串找到二次验证CALL

//得到重启验证CALL sub_007630D0, 跟随后可以到达校验位置//009A54A7    . 55      push ebp
009A5536   lea edx,dword ptr ss:
009A5539   mov eax,dword ptr ds:
009A553E   mov eax,dword ptr ds:
009A5540   call Converte.0040B090                        ;生成静态字符串str 1 = “31000000”
009A5545   mov edx,dword ptr ss:                ; EDX = Str1
009A5548   lea ecx,dword ptr ss:                ;ECX = NewBuffer2
009A554B   mov eax,dword ptr ds:
009A5550   call Converte.009D6944
009A5555   mov eax,dword ptr ss:
009A5558   lea ecx,dword ptr ss:
009A555B   mov edx,0x8
009A5560   call Converte.00762F0C
009A5565   mov eax,dword ptr ss:
009A5568   call Converte.0040B2E0                   ;;获得静态字符串Str4 = “666”
009A556D   mov ecx,eax
009A556F   mov eax,dword ptr ds:
009A5574   mov eax,dword ptr ds:
009A5576   mov edx,dword ptr ds:
009A557C   call Converte.0091E888                        ;最后一次校验
009A5581   test al,al
009A5583   jnz short Converte.009A55B5
//这个校验和上面的零散校验一样,
0091E914    .8A52 0B         mov dl,byte ptr ds:;取Key12位校验
1687 / 666 = 2
1687 % 666 = 355
(2 + 355) % 10 = 7所以第12位为7

//所以最终的Key为 ,测试一下
16871234587731158748


Shark恒 发表于 2016-8-2 17:05

精彩分析,不给精华天理难容哇!

LYQingYe 发表于 2016-8-2 17:36

Shark恒 发表于 2016-8-2 17:05
精彩分析,不给精华天理难容哇!

{:6_224:} 算发帖基本没人看啊

Very_good 发表于 2016-8-2 17:38

要仔细学习了

LYQingYe 发表于 2016-8-2 17:44

Very_good 发表于 2016-8-2 17:38
要仔细学习了

{:6_224:} 多谢大哥赏脸

小彬来了 发表于 2016-8-2 17:49

这些代码 你说一般人是看不懂的。膜拜玩C的
大牛 论坛有你这种人才 才叫论坛评分走一波

Shark恒 发表于 2016-8-3 08:11

LYQingYe 发表于 2016-8-2 17:36
算发帖基本没人看啊

相对来讲看懂的人少,我建议增加寻找关键CALL的部分。{:6_208:}

LYQingYe 发表于 2016-8-3 08:46

Shark恒 发表于 2016-8-3 08:11
相对来讲看懂的人少,我建议增加寻找关键CALL的部分。

{:6_197:} 好

jiajiayu 发表于 2016-8-3 10:12

算法太过高深

2570505044 发表于 2016-8-3 10:16

一脸懵逼的新人看着一连串的英文字母表示不懂
页: [1] 2 3 4 5
查看完整版本: Okdo Document Converter Professional 二次验证算法分析