[软件名称] : OkdoDocument Converter Professional
[编译类型] : Delphi
[是否有壳] : 无壳
[注册类型] : 注册码注册
[作者信息] : LYQingYe [FBI Warning] : 学到东西的别忘记评分!
// //相关算法帖 // ZD SoftScreen Recorder v9.8算法逆向+keygen PDFPassword Remover 算法逆向 EditPlus v4.0 算法分析+ keygen
https://www.52hb.com/thread-17607-1-1.html
//第一次校验思路总结 //将 我们输入的Key 总共20位 “01234567890123456789” , 每次取一位 ‘0’ 调用 CharToHex 将字符串//转换为 整数(hex)数据 0 , 循环19次,将 Key的前 19为数字加起来 得到Addupdate. //余数 =Addupdate % 0XA , 然后余数跟Key第20位比较,一定要相等,否则失败,在此我们得到了 Key第20位的来源.
//且看第二次校验中的 -> 零散校验
[Asm] 纯文本查看 复制代码 009D5B84 push ebp
009D5B85 mov ebp,esp
009D5B87 mov ecx,0xD
009D5B8C push 0x0
009D5B8E push 0x0
009D5B90 dec ecx ; Converte.00653D8C
009D5B91 jnz short Converte.009D5B8C
009D5B93 push ebx
009D5B94 push esi ; Converte.0047D780
009D5B95 push edi
009D5B96 mov dword ptr ss:[ebp-0x4],eax
009D5B99 xor eax,eax
009D5B9B push ebp
009D5B9C push Converte.009D5FB6
009D5BA1 push dword ptr fs:[eax]
009D5BA4 mov dword ptr fs:[eax],esp
009D5BA7 push 0x1F4 ; /Timeout = 500. ms
009D5BAC call <jmp.&kernel32.Sleep> ; \Sleep
009D5BB1 xor eax,eax
009D5BB3 push ebp
009D5BB4 push Converte.009D5EBF
009D5BB9 push dword ptr fs:[eax]
009D5BBC mov dword ptr fs:[eax],esp
009D5BBF lea edx,dword ptr ss:[ebp-0xC]
009D5BC2 mov eax,dword ptr ss:[ebp-0x4]
009D5BC5 mov eax,dword ptr ds:[eax+0x310]
009D5BCB call Converte.00484EB8 ;获取输入Key的长度
009D5BD0 mov eax,dword ptr ss:[ebp-0xC] ;Eax -> Key
009D5BD3 lea edx,dword ptr ss:[ebp-0x8]
009D5BD6 call Converte.0040AC10
009D5BDB mov eax,dword ptr ss:[ebp-0x8] ;Eax -> key
009D5BDE call Converte.00762F98 ;第一个核心校验Call
009D5BE3 test al,al
009D5BE5 jnz short Converte.009D5C34 ;跳转则失败[/align]
[/align][align=left]//且看第一个核心校验CALL[/align]
[align=left][mw_shl_code=asm,true]00762F98 push ebp
00762F99 mov ebp,esp
00762F9B add esp,-0xC
00762F9E push ebx
00762F9F push esi ; Converte.0047D780
00762FA0 push edi
00762FA1 xor edx,edx
00762FA3 mov dword ptr ss:[ebp-0xC],edx
00762FA6 mov dword ptr ss:[ebp-0x4],eax
00762FA9 mov eax,dword ptr ss:[ebp-0x4]
00762FAC call Converte.0040548C ; LoadKey,获取输入的Key
00762FB1 xor eax,eax
00762FB3 push ebp
00762FB4 push Converte.007630BE
00762FB9 push dword ptr fs:[eax]
00762FBC mov dword ptr fs:[eax],esp
00762FBF xor eax,eax
00762FC1 push ebp
00762FC2 push Converte.00763094
00762FC7 push dword ptr fs:[eax]
00762FCA mov dword ptr fs:[eax],esp
00762FCD mov bl,0x1
00762FCF mov eax,dword ptr ss:[ebp-0x4]
00762FD2 call Converte.0040529C ; GetKeyLength,获取Key的长度
00762FD7 test eax,eax ; 判断长度是否为0
00762FD9 jnz short Converte.00762FEA
00762FDB xor ebx,ebx
00762FDD xor eax,eax
00762FDF pop edx ; 0012FBC4
00762FE0 pop ecx ; 0012FBC4
00762FE1 pop ecx ; 0012FBC4
00762FE2 mov dword ptr fs:[eax],edx
00762FE5 jmp Converte.007630A0
00762FEA mov eax,dword ptr ss:[ebp-0x4]
00762FED call Converte.0040529C ; GetKeyLength,获取Key的长度
00762FF2 cmp eax,0x14 ; 判断Key的长度是否为20
00762FF5 je short Converte.00763006 ; 若不为20,则失败
00762FF7 xor ebx,ebx
00762FF9 xor eax,eax
00762FFB pop edx ; 0012FBC4
00762FFC pop ecx ; 0012FBC4
00762FFD pop ecx ; 0012FBC4
00762FFE mov dword ptr fs:[eax],edx
00763001 jmp Converte.007630A0
00763006 xor eax,eax
00763008 mov dword ptr ss:[ebp-0x8],eax
0076300B mov esi,0x1 ; ESI = 1 ,Esi作为计数器,循环20次,遍历完整个Key
00763010 xor eax,eax
00763012 push ebp
00763013 push Converte.00763041
00763018 push dword ptr fs:[eax]
0076301B mov dword ptr fs:[eax],esp
0076301E lea eax,dword ptr ss:[ebp-0xC]
00763021 mov edx,dword ptr ss:[ebp-0x4] ; Edx -> Key
00763024 mov dl,byte ptr ds:[edx+esi-0x1] ; 每次获取一位Key数据
00763028 call Converte.004051B4 ; CopyByteDataToNewBuffer,拷贝数据到新的缓冲区
0076302D mov eax,dword ptr ss:[ebp-0xC]
00763030 call Converte.0040B2E0 ; CharToHex,将获取到的Key数据字符转换为hex数值
00763035 mov edi,eax ; EDI = Hex
00763037 xor eax,eax
00763039 pop edx ; 0012FBC4
0076303A pop ecx ; 0012FBC4
0076303B pop ecx ; 0012FBC4
0076303C mov dword ptr fs:[eax],edx
0076303F jmp short Converte.0076305C
00763041 jmp Converte.00404598
00763046 xor ebx,ebx
00763048 call Converte.004049C4
0076304D xor eax,eax
0076304F pop edx ; 0012FBC4
00763050 pop ecx ; 0012FBC4
00763051 pop ecx ; 0012FBC4
00763052 mov dword ptr fs:[eax],edx
00763055 jmp short Converte.007630A0
00763057 call Converte.004049C4
0076305C cmp esi,0x14 ; 判断是否遍历结束,20次遍历
0076305F jge short Converte.00763064 ; 是否遍历结束
00763061 add dword ptr ss:[ebp-0x8],edi ; 将获取到的hex 累加在一起
00763064 cmp esi,0x14 ; 是否循环到19次
00763067 jnz short Converte.00763084 ; Trace END ,若完成19次,则开始计算
00763069 mov eax,dword ptr ss:[ebp-0x8] ; ADD UP KEY 1~19 ,将1~19位数值加起来,称为Addupdate
0076306C mov ecx,0xA ; ECX = 0XA
00763071 cdq
00763072 idiv ecx ; 将Addupdate / 0xA ,Edx为余数
00763074 cmp edi,edx ; EDI 为KEY的最后一位,EDX为余数
00763076 je short Converte.00763084 ; 判断余数是否等于 KEY最后一位 ,一定要等于 否则失败
//上面是零散校验的准备阶段,准备阶段很简单,重要的就是 Str4 = ‘267’ ,他会被用作计算值.
//零散校验的次数有很多次,每次Str4 的值都不一样,下面看零散校验,不难和第一次校验有些区别
[Asm] 纯文本查看 复制代码 009D5BE3 test al,al ;接着上面第一次校验
009D5BE5 jnz short Converte.009D5C34
009D5BE7 mov eax,dword ptr ds:[0xA40360]
009D5BEC push dword ptr ds:[eax]
009D5BEE mov eax,dword ptr ds:[0xA40BB0]
009D5BF3 push dword ptr ds:[eax]
009D5BF5 push Converte.009D5FCC ; _regcode.ini
009D5BFA lea eax,dword ptr ss:[ebp-0x10]
009D5BFD mov edx,0x3
009D5C02 call Converte.0040535C
009D5C07 mov eax,dword ptr ss:[ebp-0x10]
009D5C0A xor ecx,ecx
009D5C0C xor edx,edx
009D5C0E call Converte.007631EC
009D5C13 mov eax,dword ptr ds:[0xA4079C]
009D5C18 mov byte ptr ds:[eax],0x0
009D5C1B mov eax,dword ptr ds:[0xA401A0]
009D5C20 mov eax,dword ptr ds:[eax]
009D5C22 call Converte.009B4544
009D5C27 mov eax,dword ptr ss:[ebp-0x4]
009D5C2A call Converte.004A37CC
009D5C2F jmp Converte.009D5EB5
009D5C34 lea edx,dword ptr ss:[ebp-0x1C] ; EDX = NewBuffer
009D5C37 mov eax,dword ptr ds:[0xA40994]
009D5C3C mov eax,dword ptr ds:[eax]
009D5C3E call Converte.0040B090 ; 生成静态字符串str 1 = “31000000”
009D5C43 mov edx,dword ptr ss:[ebp-0x1C] ; EDX = Str1
009D5C46 lea ecx,dword ptr ss:[ebp-0x18] ; ECX = NewBuffer2
009D5C49 mov eax,dword ptr ds:[0xA3FEF8]
009D5C4E mov eax,dword ptr ds:[eax] ; 又得到静态字符串Str2 =
"363530353A303332363633363530363233373137343434343B36373034353736353A3034333335313B34"
009D5C50 call Converte.009D6944 ; 得到静态字符串 Str3 = "472782104414724015356666945267547826117396"
009D5C55 mov eax,dword ptr ss:[ebp-0x18]
009D5C58 lea ecx,dword ptr ss:[ebp-0x14]
009D5C5B mov edx,0xA
009D5C60 call Converte.00762F0C ;获得静态字符串Str4
009D5C65 mov eax,dword ptr ss:[ebp-0x14] ; Str4 = ‘267’
009D5C68 call Converte.0040B2E0 ; CharToHex,将字符串转换为hex数据
009D5C6D push eax
009D5C6E lea edx,dword ptr ss:[ebp-0x24] ; NEWBUFFER
009D5C71 mov eax,dword ptr ss:[ebp-0x4]
009D5C74 mov eax,dword ptr ds:[eax+0x310]
009D5C7A call Converte.00484EB8 ; GetKeyLength 获取Key的长度
009D5C7F mov eax,dword ptr ss:[ebp-0x24] ; Eax -> Key
009D5C82 lea edx,dword ptr ss:[ebp-0x20] ; EDX -> Buffer
009D5C85 call Converte.0040AC10
009D5C8A mov edx,dword ptr ss:[ebp-0x20] ; Edx -> Key
009D5C8D mov eax,dword ptr ds:[0xA40048]
009D5C92 mov eax,dword ptr ds:[eax]
009D5C94 pop ecx ; 0012FAC8
009D5C95 call Converte.008D62B4 ; 开始零散校验
009D5C9A test al,al
009D5C9C je Converte.009D5D76
//零散校验算法总结.,零散校验1 初始化阶段会生成静态字符串Str4 = ‘267’ ,并转换为 整数 获取Key前4位转换为整数,命名为 Key4bit . 商= Key4bit / 267 余数= Key4bit % 267 余数2= (商 + 余数) % 0XA Key的第0XD位要等于余数2 ,所以我们得到的Key第14位的来源 //同样的代码校验,下面依次进行零散校验2 初始化阶段会生成静态字符串Str4 = ‘945’ ,并转换为 整数 00948860 . 8A52 0C mov dl,byte ptrds:[edx+0xC] ; 第14位 获取Key前4位转换为整数,命名为 Key4bit . 商= Key4bit / 945 余数= Key4bit % 945 余数2= (商 + 余数) % 0XA Key的第0XD位要等于余数2 ,所以我们得到的Key第14位的来源
//同样的代码校验,下面依次进行零散校验3 初始化阶段会生成静态字符串Str4 = ‘356’ ,并转换为 整数 0092E16C . 8A52 0A mov dl,byte ptrds:[edx+0xA] ; 第11位 获取Key前4位转换为整数,命名为 Key4bit . 商= Key4bit / 356 余数= Key4bit % 356 余数2= (商 + 余数) % 0XA Key的第0XB位要等于余数2 ,所以我们得到的Key第11位的来源
//有三次零散校验 分别可以得到Key的第 11, 14 ,15 位的来源 ,加上 第一次校验 可以得到 第20位的来源 //下面手动算一个注册码 随机取一个四位数字 ,例如 ‘1687’ 1687 / 267 = 6 1687 % 267 = 85 (6 + 85) % 10 = 1 所以第14位为1 继续 1687 / 945 = 1 1687 % 945 = 742 (742 + 1) % 10 = 3 所以第13位为 3 继续 1687 / 356 = 4 1687 % 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 = 82 82 % 10 = 2 所以第20位为2 组装成20位Key则为 16871234587131158742
输入Key显示成功
//但发现重启程序后还是未注册,这就触发了二次验证,可以通过,搜索字符串找到二次验证CALL
//得到重启验证CALL sub_007630D0 , 跟随后可以到达校验位置 //009A54A7 . 55 push ebp
[Asm] 纯文本查看 复制代码 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:[ebp-0x10],ebx
008D62C2 >mov dword ptr ss:[ebp-0xC],ebx
008D62C5 >mov esi,ecx
008D62C7 >mov dword ptr ss:[ebp-0x4],edx
008D62CA >mov eax,dword ptr ss:[ebp-0x4]
008D62CD >call Converte.0040548C ; GetKey 获得输入的Key,和第一次校验差不多的步骤
008D62D2 >xor eax,eax
008D62D4 >push ebp
008D62D5 >push Converte.008D63A9
008D62DA >push dword ptr fs:[eax]
008D62DD >mov dword ptr fs:[eax],esp
008D62E0 >mov byte ptr ss:[ebp-0x5],0x0
008D62E4 >mov eax,dword ptr ss:[ebp-0x4]
008D62E7 >call Converte.0040529C ;GetKeyLength 获取Key长度
008D62EC >test eax,eax ;判断长度是否为0
008D62EE >jnz short Converte.008D62F9
008D62F0 >mov byte ptr ss:[ebp-0x5],0x0
008D62F4 >jmp Converte.008D6386
008D62F9 >mov eax,dword ptr ss:[ebp-0x4]
008D62FC >call Converte.0040529C
008D6301 >cmp eax,0x14 ;判断长度是否为20,若不是则失败
008D6304 >je short Converte.008D630C
008D6306 >mov byte ptr ss:[ebp-0x5],0x0
008D630A >jmp short Converte.008D6386
008D630C >xor eax,eax
008D630E >push ebp
008D630F >push Converte.008D637C
008D6314 >push dword ptr fs:[eax]
008D6317 >mov dword ptr fs:[eax],esp
008D631A >lea eax,dword ptr ss:[ebp-0xC]
008D631D >push eax
008D631E >mov ecx,0x4
008D6323 >mov edx,0x1
008D6328 >mov eax,dword ptr ss:[ebp-0x4] : Eax -> Key
008D632B >call Converte.004054FC ; 获取KEY 前4位
008D6330 >mov eax,dword ptr ss:[ebp-0xC]
008D6333 >call Converte.0040B2E0 ; CharToHex ,将Key前四位转换为整数,我们设为key4bit
008D6338 >mov ebx,eax
008D633A >lea eax,dword ptr ss:[ebp-0x10]
008D633D >mov edx,dword ptr ss:[ebp-0x4] ; Edx ->Key
008D6340 >mov dl,byte ptr ds:[edx+0xD] ; 获取Key的 第0xD位,
008D6343 >call Converte.004051B4 ;
008D6348 >mov eax,dword ptr ss:[ebp-0x10] ; 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 ; 一定要等于,否则失败
|