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
精彩分析,不给精华天理难容哇!
{:6_224:} 算发帖基本没人看啊 要仔细学习了 Very_good 发表于 2016-8-2 17:38
要仔细学习了
{:6_224:} 多谢大哥赏脸 这些代码 你说一般人是看不懂的。膜拜玩C的
大牛 论坛有你这种人才 才叫论坛评分走一波 LYQingYe 发表于 2016-8-2 17:36
算发帖基本没人看啊
相对来讲看懂的人少,我建议增加寻找关键CALL的部分。{:6_208:} Shark恒 发表于 2016-8-3 08:11
相对来讲看懂的人少,我建议增加寻找关键CALL的部分。
{:6_197:} 好 算法太过高深 一脸懵逼的新人看着一连串的英文字母表示不懂