尝试追码过程做个笔记。第一次写算法。也是第一次接触算法。写的不是很好,看的懂的就勉强看。看不懂和大牛请忽略.
接着单步F8往下跟踪到下图这里,这里是关键的循环验证流程。
验证流程是循环取每一位假key和正确key作比较,如有一位不相等第一组key就会验证失败
通过上图的循环可以看到这里是明码比较 第一组key = ITN3UXJGJ
二.验证(52pojie.ini)
继续验证第二组key(52pojie.ini)里面的内容。
这里我用到第五课教程的第二个函数断点:GetPrivateProfileStringA 读取ini文件
OD重新载入程序下好断点。F9运行程序,输入第一组正确的key
例如key:ITN3UXJGJ-123456789-abcdefg 后面两组key输入自己容易记住辨认的就行。
让程序先把第一组正确key写入到验证里,下次验证就可以直接忽略第一组key
F9运行3次后断在了这里(我这里是运行3次才断在下图位置)
在红色代码处继续 右键 >> 跟随到反汇编窗口
来到反汇编窗口后F2下断点,继续F9运行,断在了我们下段的地方。下面进入循环获取解码后的正确key和假key逐位比较。
到此已经成功获取到第二组key = jN2UXJxEjM2UXJ
三.验证(注册表)。
接着继续获取第三组key。(注册表验证)
注册表位置:HKEY_CURRENT_USER\Software\52Pojie
继续F9运行程序,然后输入前两组正确key,
例如key:ITN3UXJGJ-jN2UXJxEjM2UXJ-123456789
这次用的的函数断点还是第五课教程说到的:RegOpenKeyA 打开注册表,既然要验证注册表里的信息,就需要先打开然后读取里面的信息,所以用到该函数。
Od载入程序下好断点。然后继续F9运行2次后,断在了下图位置,在test eax eax处下F2断点。
F9运行,断在了test eax eax。继续单步F8跟踪
来到下列代码位置处:
文字代码对应上图:
004022D0 |. FF50 0C call dword ptr ds:[eax+0xC]
004022D3 |. 8A95 F8FEFFFF mov dl,byte ptr ss:[ebp-0x108] ; 取假key中间一位传递给dl
004022D9 |. 8D70 10 lea esi,dword ptr ds:[eax+0x10]
004022DC |. 0FBE85 F4FEFF>movsx eax,byte ptr ss:[ebp-0x10C] ; 取假key第一位传递给eax
004022E3 |. 0FBECA movsx ecx,dl ; 把假key中间一位也就是dl传递给ecx
004022E6 |. 48 dec eax ; eax减一 也就是假key的第一位减一
004022E7 |. 89B5 E4FEFFFF mov [local.71],esi ; 52PoJie?0058E5F0
004022ED |. 3BC1 cmp eax,ecx ; 假key第一位减一后 和 中间 一位做比较 不相等跳走
004022EF |. 75 69 jnz short 52PoJie?0040235A
004022F1 |. 0FBE85 FCFEFF>movsx eax,byte ptr ss:[ebp-0x104] ; 取假key的最后一位传递给eax
004022F8 |. 83C1 02 add ecx,0x2 ; ecx加2 也就是假key中间一位加2
004022FB |. 3BC8 cmp ecx,eax ; 假key中间一位加 2 后 和 最后一位做比较。不相等跳走
004022FD |. 75 5B jnz short 52PoJie?0040235A ; 不相等跳转 跳走验证就失败
004022FF |. 80F2 54 xor dl,0x54 ; 取假key中间一位 和 0x54 异或
00402302 |. 80FA 66 cmp dl,0x66 ; 假key中间一位异或后 和 66 比较 不相等跳转。
32,十六进制 32 转字符 “2”
00402305 |. 75 53 jnz short 52PoJie?0040235A ; 不相等这里跳走。跳走验证失败。
代码分析过程:
1.
00402302 |. 80FA 66 cmp dl,0x66 ; 假key中间一位异或后 和 66 比较 不相等跳转。
到这里后可以看出key是以中间一位和第一位和第三位做比较的。 到这里后中间一位必须为与0x54 异或后 = 66 否者验证就会失败 这里我们必须先确定中间一位是什么,用系统自带的计算机以十六进制计算 用66 xor 54 = 32,十六进制为32 转ASCLL码为“2”
这里确定中间一位 =“2”
2.
004022ED |. 3BC1 cmp eax,ecx ; 假key第一位减一后 和 中间 一位做比较 不相等跳走
上面确定了中间一位为ASCLL码“2” 十六进制为32
那么这里第一位减一后必须等于ASCLL码“2” 例如3 - 1 = 2 十六进制为33 - 1 = 32
到了这里确定第一位必须是ASCLL码“3” 十六进制为33
这里确定第一位 =“3”
3.
004022FB |. 3BC8 cmp ecx,eax ; 假key中间一位加 2 后 和 最后一位做比较。不相等跳走
这里是中间一位加 2 后 和 最后一位比较 例如2 + 2 = 4 十六进制为32 + 2 = 34
ASCLL码为“4” 十六进制为34
到此确定了第一位为“3” 中间一位为“2” 最后一位为“4”
接着继续单步F8跟踪下面的关键比较
文字代码部分对应上图:
00402307 |. 6A 03 push 0x3 ; 把 3 压入栈
00402309 |. 8D85 F5FEFFFF lea eax,dword ptr ss:[ebp-0x10B] ; 这里把假key 第二位开始(23456789)传递给eax
0040230F |. 68 3C465400 push 52PoJie?0054463C ; 把 MjM 压入栈
00402314 |. 50 push eax ; 把假key eax压入栈
00402315 |. E8 76991100 call 52PoJie?0051BC90 ; 关键call F7跟进去
0040231A |. 83C4 0C add esp,0xC
0040231D |. 85C0 test eax,eax ; 52PoJie?0058E5E0
0040231F |. 75 39 jnz short 52PoJie?0040235A
00402321 |. 6A 03 push 0x3 ; 把 3 压入栈
00402323 |. 8D85 F9FEFFFF lea eax,dword ptr ss:[ebp-0x107] ; 把假key的 后四位(6789)压入栈
00402329 |. 68 40465400 push 52PoJie?00544640 ; 把 UXJ 压入栈
0040232E |. 50 push eax ; 52PoJie?0058E5E0
0040232F |. E8 5C991100 call 52PoJie?0051BC90 ; 这里的验证流程和上面的关键call是一样的。
这里先分析上半段call里的验证流程,F7跟进关键call:
文字代码对应上图
0051BC90 /$ 53 push ebx
0051BC91 |. 56 push esi ; 52PoJie?0058E5F0
0051BC92 |. 8B4C24 0C mov ecx,dword ptr ss:[esp+0xC] ; 把假key (23456789)传递给ecx
0051BC96 |. 8B5424 10 mov edx,dword ptr ss:[esp+0x10] ; 把 MjM 传递给edx
0051BC9A |. 8B5C24 14 mov ebx,dword ptr ss:[esp+0x14] ; 把 3 传递给ebx
0051BC9E |. F7C3 FFFFFFFF test ebx,-0x1 ; ebx和负一比较相等跳转(验证就失败)
0051BCA4 |. 74 51 je short 52PoJie?0051BCF7
0051BCA6 |. 2BCA sub ecx,edx
0051BCA8 |. F7C2 03000000 test edx,0x3
0051BCAE |. 74 18 je short 52PoJie?0051BCC8
0051BCB0 |> 0FB6040A /movzx eax,byte ptr ds:[edx+ecx] ; 依次把假key “2”“3”“4”“5”单个传递给eax
0051BCB4 |. 3A02 |cmp al,byte ptr ds:[edx] ; 比较(2345)中的“2” 和 (MjM)的第一位“M”比较不相等跳过(验证就会失败)
这里会比较三次,分别是(2345)中的“2” “3” “4” 和(MjM)中的“M” “j” “M”做比较
0051BCB6 |. 75 48 |jnz short 52PoJie?0051BD00 不相等就跳向验证失败
0051BCB8 |. 85C0 |test eax,eax
0051BCBA |. 0F44D8 |cmove ebx,eax
0051BCBD |. 42 |inc edx ; (MjM)向右移动一位
0051BCBE |. 83EB 01 |sub ebx,0x1 ; ebx减一,初始复制ebx=3,也就是取(2345)的前三位
0051BCC1 |. 76 34 |jbe short 52PoJie?0051BCF7 ; 当ebx=0跳转实现
0051BCC3 |. F6C2 03 |test dl,0x3
0051BCC6 |.^ 75 E8 \jnz short 52PoJie?0051BCB0
0051BCC8 |> 8D040A /lea eax,dword ptr ds:[edx+ecx]
0051BCCB |. 25 FF0F0000 |and eax,0xFFF ; eax加0xFFF 后 =2AD
0051BCD0 |. 3D FC0F0000 |cmp eax,0xFFC ; eax 和0xFFC比较 高于不低于0xFFC就跳转
0051BCD5 |.^ 77 D9 |ja short 52PoJie?0051BCB0
0051BCD7 |. 8B040A |mov eax,dword ptr ds:[edx+ecx] ; 取(23456789)的前四位也就是(2345)传递给eax
0051BCDA |. 3B02 |cmp eax,dword ptr ds:[edx] ; eax =(2345)和 [edx] =(MjM)比较,不相等跳转
0051BCDC |.^ 75 D2 |jnz short 52PoJie?0051BCB0
00402315 |. E8 76991100 call 52PoJie?0051BC90 ; 关键call F7跟进去
这个call第一次是取假key 2345的前三位234和(MjM)作比较。只要有任何一位比较不相等就跳向失败
0040232F |. E8 5C991100 call 52PoJie?0051BC90 ; 这里的验证流程和上面的关键call是一样的。
Call的第二次是取假key(6789)也是取前三位678和(UXJ)作比较,同样是有任何一位比较不相等的话就跳向失败。
上面的两处验证完毕后 分别是MjM 和UXJ这两个
通过上面的验证我们知道正确key的第一位是“3”+ MjM + 中间一位是“2”+ UXJ +最后一位是“4”
最终组合成第三组正确的key = 3MjM2UXJ4
最终正确key = ITN3UXJGJ-jN2UXJxEjM2UXJ-3MjM2UXJ4
总结一下:注册表的验证流程就是先验证key的第一位和中间一位和最后一位。如果正确继续往下验证第一位和中间一位之间的部分(MjM)。接着再验证中间一位和最后一位之间的部分(UXJ)