160个crackme 之152---The AntiXryst 的MD5注册分析和注册机实现
本帖最后由 solly 于 2019-4-13 16:22 编辑看看160个crackme集合大多数都在这里有教程,只有少数几个没有,选择了一个没有的试一下。
我选择了第152个,The AntiXryst,好象这个还没有教程,于是动手了。
这个程序在 CHM集合的列表中説是delphi编写的。先检查一下看看。
没检测到壳,省事不少。
有个RCDATA资源表,并含有一个TFORM1的资源,再通过UltraEdit看一下:
标准的Delphi程序第1节内容,是Delphi编写没有错了,通过 DeDeDark打开程序文件:
只有一个表单,而且只有一个事件 OnTimer,一看就是定时器事件,进入事件:
记住事件的起始地址:0x00457AF8。并记住一些delphi的系统调用,这些系统调用在OD中就不用去跟踪了。
启动OD,载入Crackme程序,直接右键”转到->表达式“,输入前面的地址:
来到 OnTimer 事件处理程序,先不下断,F9进入程序,输入一个用户名。
这个crackme的注册码通过一个checkbox矩陈来输入注册码。
回到OD下断,稍等一下OD就断下了程序,原来是通过定时器不停的来验证注册码。
下面是其汇编代码:
; 以下是 Timer 的事件处理函数
00457AF8/.55 push ebp
00457AF9|.8BEC mov ebp, esp
00457AFB|.83C4 8C add esp, -74
00457AFE|.53 push ebx
00457AFF|.56 push esi
00457B00|.57 push edi
00457B01|.33C9 xor ecx, ecx
00457B03|.894D 8C mov dword ptr , ecx
00457B06|.894D F8 mov dword ptr , ecx
00457B09|.8BD8 mov ebx, eax
00457B0B|.33C0 xor eax, eax
00457B0D|.55 push ebp
00457B0E|.68 337C4500 push 00457C33 ;SEH 地址
00457B13|.64:FF30 push dword ptr fs: ;保存上一个SEH地址
00457B16|.64:8920 mov dword ptr fs:, esp ;设置当前SEH地址为 0x00457C33
00457B19|.8D55 F8 lea edx, dword ptr
00457B1C|.8B83 68040000 mov eax, dword ptr
00457B22|.E8 A9F4FDFF call 00436FD0 ;GetText,读取注册名
00457B27|.8D55 8C lea edx, dword ptr
00457B2A|.8B45 F8 mov eax, dword ptr ;eax==>注册名
00457B2D|.E8 16FBFAFF call 00407648 ;Delphi 函数:Trim()
00457B32|.837D 8C 00 cmp dword ptr , 0 ;是否空串
00457B36|.0F84 D9000000 je 00457C15
00457B3C|.8D45 A0 lea eax, dword ptr
00457B3F|.E8 0CE9FFFF call 00456450 ;MD5初始化,4个DWORD引子
00457B44|.8B45 F8 mov eax, dword ptr ;eax==>注册名
00457B47|.E8 8CBFFAFF call 00403AD8 ;取注册码名的长度
00457B4C|.83F8 40 cmp eax, 40 ;eax=注册码的长度
00457B4F|.7D 18 jge short 00457B69 ;长度大于或等于0x40则跳过注册名复制加长
00457B51|>8D45 F8 /lea eax, dword ptr
00457B54|.8B55 F8 |mov edx, dword ptr ;edx==>注册名
00457B57|.E8 84BFFAFF |call 00403AE0 ;复制用户名并连接成一个新串,regName = regName + regName
00457B5C|.8B45 F8 |mov eax, dword ptr ;eax==>克隆后的注册名
00457B5F|.E8 74BFFAFF |call 00403AD8 ;重新计算长度
00457B64|.83F8 40 |cmp eax, 40 ;eax 由 5,10,20,40,80...递增
00457B67|.^ 7E E8 \jle short 00457B51
00457B69|>8B45 F8 mov eax, dword ptr
00457B6C|.E8 67BFFAFF call 00403AD8 ;最后取得克隆后的字符串长度
00457B71|.83F8 40 cmp eax, 40 ;eax==0x50==80
00457B74|.7E 24 jle short 00457B9A ;长度小于或等于则跳转
00457B76|>8B45 F8 /mov eax, dword ptr ;eax==>克隆加长后的注册名
00457B79|.E8 5ABFFAFF |call 00403AD8 ;取长度
00457B7E|.8BD0 |mov edx, eax
00457B80|.8D45 F8 |lea eax, dword ptr
00457B83|.B9 01000000 |mov ecx, 1 ;删除的字符数
00457B88|.E8 8FC1FAFF |call 00403D1C ;删除注册名最后1个字符
00457B8D|.8B45 F8 |mov eax, dword ptr
00457B90|.E8 43BFFAFF |call 00403AD8 ;计算长度
00457B95|.83F8 40 |cmp eax, 40 ;是否长度为0x40
00457B98|.^ 75 DC \jnz short 00457B76 ;不是0x40则继续去删除最后1个字符
00457B9A|>33D2 xor edx, edx ;int i = 0
00457B9C|.8D45 B0 lea eax, dword ptr ;指向字符串第0字节,即delphi短String类型的保存长度的位置
00457B9F|>8B4D F8 /mov ecx, dword ptr ;ecx==>缩短后注册名,长度为0x40
00457BA2|.8A4C11 FF |mov cl, byte ptr ;取string(i-1)位置字符, 第1次读取的字符为delphi字符串长度的高8位,为0
00457BA6|.8808 |mov byte ptr , cl ;复制注册名,第1个字节为'\0',前面缩短的注册名最后1字节没有复制
00457BA8|.42 |inc edx
00457BA9|.40 |inc eax
00457BAA|.83FA 40 |cmp edx, 40
00457BAD|.^ 75 F0 \jnz short 00457B9F
00457BAF|.8D55 A0 lea edx, dword ptr ;edx==>MD5算法引子,0019FCD8:01 23 45 67 89 AB CD EF FE DC BA 98 76 54 32 10
00457BB2|.8D45 B0 lea eax, dword ptr ;eax==>'\0' + 注册名前0x3F个字符
00457BB5|.E8 FEE8FFFF call 004564B8 ;MD5运算
00457BBA|.8D75 A0 lea esi, dword ptr ;esi==>MD5计算后的值
00457BBD|.8D7D 90 lea edi, dword ptr
00457BC0|.B9 04000000 mov ecx, 4
00457BC5|.F3:A5 rep movs dword ptr es:, dword ptr
00457BC7|.8D55 90 lea edx, dword ptr ;edx==>前面MD5计算值,当作下一次的MD5引子
00457BCA|.8D45 B0 lea eax, dword ptr ;eax==>'\0' + 注册名前0x3F个字符
00457BCD|.E8 E6E8FFFF call 004564B8 ;MD5运算
00457BD2|.8B45 A0 mov eax, dword ptr ;EAX=MD5_1,即第1次计算后的MD5第1个整数
00457BD5|.2B45 A4 sub eax, dword ptr ;EAX=MD5_1 - MD5_1
00457BD8|.2B45 A8 sub eax, dword ptr ;EAX=MD5_1 - MD5_1 - MD5_1
00457BDB|.0345 AC add eax, dword ptr ;EAX=MD5_1 - MD5_1 - MD5_1 + MD5_1
00457BDE|.8945 A0 mov dword ptr , eax ;=MD5_1 - MD5_1 - MD5_1 + MD5_1, 保存第1个SN整数
00457BE1|.8B45 90 mov eax, dword ptr ;EAX=MD5_2,即第2次计算后的MD5第1个整数
00457BE4|.2B45 94 sub eax, dword ptr ;EAX=MD5_2 - MD5_2
00457BE7|.2B45 98 sub eax, dword ptr ;EAX=MD5_2 - MD5_2 - MD5_2
00457BEA|.0345 9C add eax, dword ptr ;EAX=MD5_2 - MD5_2 - MD5_2 + MD5_2
00457BED|.8945 90 mov dword ptr , eax ;=MD5_2 - MD5_2 - MD5_2 + MD5_2,保存第2个SN整数
00457BF0|.8D55 F0 lea edx, dword ptr ;eax,edx两个整数缓冲区,用来保存checkbox的状态
00457BF3|.8D45 F4 lea eax, dword ptr
00457BF6|.E8 B1F8FFFF call 004574AC ;取 CheckBox 的状态,生成两个32位无符号数,过程简单统一,不深入解释了
00457BFB|.8B45 F0 mov eax, dword ptr ;参数4,第2个checkbox状态值
00457BFE|.50 push eax
00457BFF|.8B4D F4 mov ecx, dword ptr ;参数3,第1个checkbox状态值
00457C02|.8B55 90 mov edx, dword ptr ;参数2,第2个MD5计算值变形运算后的数值
00457C05|.8B45 A0 mov eax, dword ptr ;参数1,第1个MD5运算值变形运算后的数值
00457C08|.E8 AFFEFFFF call 00457ABC ;注册码比较调用,对比两组整数,不相等则用随机数取得一个索引地址
00457C0D|.8945 FC mov dword ptr , eax ; eax 为上面调用通过查表返回的一个地址
00457C10|.8B45 FC mov eax, dword ptr ; eax为调用入口地址,注册不成功是地址范围 0x0045746C~004574A8 内的一个随机地址,成功则是 0x004573C8
00457C13|.FFD0 call eax ;如果注册成功,则显示成功注册,不然就继续显示失败。
00457C15|>33C0 xor eax, eax ;指示 SEH 头的索引
00457C17|.5A pop edx ;取保存的SEH地址
00457C18|.59 pop ecx
00457C19|.59 pop ecx
00457C1A|.64:8910 mov dword ptr fs:, edx ;恢复SEH
00457C1D|.68 3A7C4500 push 00457C3A ;下面的 retn 返回地址
00457C22|>8D45 8C lea eax, dword ptr
00457C25|.E8 32BCFAFF call 0040385C ;Delphi 资源释放过程
00457C2A|.8D45 F8 lea eax, dword ptr
00457C2D|.E8 2ABCFAFF call 0040385C ;Delphi 资源释放过程
00457C32\.C3 retn ;跳转到 0x00457C3A
00457C33 .^ E9 E4B6FAFF jmp 0040331C ;SEH 异常处理
00457C38 .^ EB E8 jmp short 00457C22 ;SEH 处理完成后,跳回到这里
00457C3A .5F pop edi
00457C3B .5E pop esi
00457C3C .5B pop ebx
00457C3D .8BE5 mov esp, ebp
00457C3F .5D pop ebp
00457C40 .C3 retn
以上是主验证过程,其取得用户名,如果长度没有64个字符,就一直重复拼接直到超过64个字符,然后再截短为64个字符。
再进行MD5处理。不过,其传入的用户名在进行MD5处理时,只取了前63个字符填充在MD5输入缓冲区的后63字节中,而缓冲区第1个字符位置填充的是'\0'(这个在C/C++中就不好计算长度了,需要从第2个字符开始处理)。
这个生成的'\0' + 重复注册名字符串,进行两次 MD5处理,头一次是标准的,并且不需要padding填充。第二次直接用第一次的MD5码作为初始化引子,进行MD5计算。
下面是MD 5 运算调用的过程,汇编代码太长,反正是一个标准过程,因此中间删除了一部分,免得显示得太长:
0045646C/$53 push ebx
0045646D|.56 push esi
0045646E|.57 push edi
0045646F|.83C4 C0 add esp, -40
00456472|.8BF0 mov esi, eax
00456474|.8D3C24 lea edi, dword ptr
00456477|.B9 10000000 mov ecx, 10 ;长度,16 * 4 字节
0045647C|.F3:A5 rep movs dword ptr es:, dword ptr ;一次移动4字节,一共移动16次
0045647E|.BB 10000000 mov ebx, 10 ;循环16次 int n = 16
00456483|.8BC4 mov eax, esp
00456485|.8BCA mov ecx, edx
00456487|>0FB630 /movzx esi, byte ptr ;读取注册名第1个字符,第1个是'\0'
0045648A|.0FB678 01 |movzx edi, byte ptr ;读取注册名第2个字符,其实就是注册名的第1个字符
0045648E|.C1E7 08 |shl edi, 8
00456491|.0BF7 |or esi, edi
00456493|.0FB678 02 |movzx edi, byte ptr ;第3个
00456497|.C1E7 10 |shl edi, 10
0045649A|.0BF7 |or esi, edi
0045649C|.0FB678 03 |movzx edi, byte ptr ;第4个
004564A0|.C1E7 18 |shl edi, 18
004564A3|.0BF7 |or esi, edi
004564A5|.8931 |mov dword ptr , esi ;将每4字节一组转换成16进制数字保存
004564A7|.83C1 04 |add ecx, 4
004564AA|.83C0 04 |add eax, 4
004564AD|.4B |dec ebx ;n--
004564AE|.^ 75 D7 \jnz short 00456487 ;循环转换
004564B0|.83C4 40 add esp, 40
004564B3|.5F pop edi
004564B4|.5E pop esi
004564B5|.5B pop ebx
004564B6\.C3 retn
004564B7 90 nop
004564B8/$55 push ebp
004564B9|.8BEC mov ebp, esp
004564BB|.81C4 64FFFFFF add esp, -9C
004564C1|.53 push ebx
004564C2|.56 push esi
004564C3|.57 push edi
004564C4|.33C9 xor ecx, ecx
004564C6|.894D E4 mov dword ptr , ecx ; = 0
004564C9|.8BF0 mov esi, eax ;esi==>'\0' + 注册名前0x3F字符
004564CB|.8D7D A4 lea edi, dword ptr ;edi=0x0019FC48
004564CE|.B9 10000000 mov ecx, 10
004564D3|.F3:A5 rep movs dword ptr es:, dword ptr ;复制16*4字节注册名
004564D5|.8955 FC mov dword ptr , edx ;==>MD5引子
004564D8|.33C0 xor eax, eax
004564DA|.55 push ebp
004564DB|.68 B9734500 push 004573B9
004564E0|.64:FF30 push dword ptr fs:
004564E3|.64:8920 mov dword ptr fs:, esp
004564E6|.8D95 64FFFFFF lea edx, dword ptr
004564EC|.8D45 A4 lea eax, dword ptr ;eax==>注册名
004564EF|.E8 78FFFFFF call 0045646C ;字符串复制,复制64字节
004564F4|.E8 13C3FAFF call 0040280C ;随机数引子初始化,即当前时间的毫秒值
004564F9|.8B45 FC mov eax, dword ptr ;EAX==>MD5算法引子
004564FC|.8B00 mov eax, dword ptr ;eax=第1个整数,0x67452301
004564FE|.8945 F8 mov dword ptr , eax
00456501|.8B45 FC mov eax, dword ptr
00456504|.8B40 04 mov eax, dword ptr
00456507|.8945 F0 mov dword ptr , eax
0045650A|.8B75 FC mov esi, dword ptr
0045650D|.8B76 08 mov esi, dword ptr
00456510|.8B5D FC mov ebx, dword ptr
00456513|.8B5B 0C mov ebx, dword ptr
00456516|.8B45 F0 mov eax, dword ptr
00456519|.8945 F4 mov dword ptr , eax
0045651C|.8B7D F8 mov edi, dword ptr
0045651F|.8975 F8 mov dword ptr , esi
00456522|.F755 F4 not dword ptr
00456525|.8B45 F0 mov eax, dword ptr
00456528|.2145 F8 and dword ptr , eax
0045652B|.215D F4 and dword ptr , ebx
0045652E|.8B45 F4 mov eax, dword ptr
00456531|.0945 F8 or dword ptr , eax
00456534|.B8 65000000 mov eax, 65
00456539|.E8 92C4FAFF call 004029D0 ;生成0~100的随机数
0045653E|.8B1485 F09245>mov edx, dword ptr ;查一个表(0~0x64)取地址,不过该表保存是同一个地址0x0045642C,该地址(edx)指向“MatrixxxMadness1 - UNREGISTERED!”
00456545|.8D45 E4 lea eax, dword ptr ;保存上面读取到的字符串地址
00456548|.E8 A7D3FAFF call 004038F4 ;保存地址到
0045654D|.8B85 64FFFFFF mov eax, dword ptr
00456553|.8945 F4 mov dword ptr , eax
00456556|.8B45 F4 mov eax, dword ptr
00456559|.0145 F8 add dword ptr , eax
0045655C|.037D F8 add edi, dword ptr
0045655F|.81EF 885B9528 sub edi, 28955B88 ; MD5 标准写法是加法,因此这里实际上是 edi += 0xd76aa478
00456565|.897D F4 mov dword ptr , edi
00456568|.8B45 F4 mov eax, dword ptr
0045656B|.8945 F8 mov dword ptr , eax
0045656E|.C165 F8 07 shl dword ptr , 7 ;左7右25,模拟循环左移7位
00456572|.C16D F4 19 shr dword ptr , 19
00456576|.8B45 F4 mov eax, dword ptr
00456579|.0945 F8 or dword ptr , eax
0045657C|.8B45 F0 mov eax, dword ptr
0045657F|.8945 F4 mov dword ptr , eax
00456582|.8B45 F0 mov eax, dword ptr
00456585|.0145 F8 add dword ptr , eax
00456588|.8B7D F8 mov edi, dword ptr
0045658B|.8B45 F8 mov eax, dword ptr
0045658E|.2145 F4 and dword ptr , eax
00456591|.F7D7 not edi
00456593|.23FE and edi, esi
00456595|.097D F4 or dword ptr , edi
00456598|.8BBD 68FFFFFF mov edi, dword ptr
0045659E|.017D F4 add dword ptr , edi
;
;此处省略n行汇编代码,都是MD5算法的代码
;
004572EC|.0375 F8 add esi, dword ptr
004572EF|.81C6 BBD2D72A add esi, 2AD7D2BB
004572F5|.8B5D 88 mov ebx, dword ptr
004572F8|.8975 F8 mov dword ptr , esi
004572FB|.C165 F8 0F shl dword ptr , 0F
004572FF|.C1EE 11 shr esi, 11
00457302|.0975 F8 or dword ptr , esi
00457305|.8BF7 mov esi, edi
00457307|.8B45 F0 mov eax, dword ptr
0045730A|.0145 F8 add dword ptr , eax
0045730D|.F7D6 not esi
0045730F|.0B75 F8 or esi, dword ptr
00457312|.3375 F0 xor esi, dword ptr
00457315|.03F3 add esi, ebx
00457317|.B8 65000000 mov eax, 65
0045731C|.E8 AFB6FAFF call 004029D0
00457321|.8B1485 F09245>mov edx, dword ptr
00457328|.8D45 E4 lea eax, dword ptr
0045732B|.E8 C4C5FAFF call 004038F4
00457330|.8B5D FC mov ebx, dword ptr
00457333|.8B1B mov ebx, dword ptr
00457335|.03DF add ebx, edi
00457337|.0375 F4 add esi, dword ptr
0045733A|.81EE 6F2C7914 sub esi, 14792C6F
00457340|.8975 F4 mov dword ptr , esi
00457343|.8B75 FC mov esi, dword ptr
00457346|.8B76 04 mov esi, dword ptr
00457349|.8B7D F4 mov edi, dword ptr
0045734C|.8B45 FC mov eax, dword ptr
0045734F|.8918 mov dword ptr , ebx
00457351|.C1EF 0B shr edi, 0B
00457354|.C165 F4 15 shl dword ptr , 15
00457358|.0B7D F4 or edi, dword ptr
0045735B|.8B45 FC mov eax, dword ptr
0045735E|.8B40 08 mov eax, dword ptr
00457361|.8945 F4 mov dword ptr , eax
00457364|.037D F8 add edi, dword ptr
00457367|.8B45 F8 mov eax, dword ptr
0045736A|.0145 F4 add dword ptr , eax
0045736D|.8B45 FC mov eax, dword ptr
00457370|.8B40 0C mov eax, dword ptr
00457373|.8945 F8 mov dword ptr , eax
00457376|.03F7 add esi, edi
00457378|.8B45 F0 mov eax, dword ptr
0045737B|.0145 F8 add dword ptr , eax
0045737E|.8B45 FC mov eax, dword ptr
00457381|.8B55 F4 mov edx, dword ptr
00457384|.8950 08 mov dword ptr , edx
00457387|.8B45 FC mov eax, dword ptr
0045738A|.8B55 F8 mov edx, dword ptr
0045738D|.8950 0C mov dword ptr , edx
00457390|.8B45 FC mov eax, dword ptr
00457393|.8970 04 mov dword ptr , esi
00457396|.8B55 E4 mov edx, dword ptr ;edx==>“MatrixxxMadness1 - UNREGISTERED!”
00457399|.A1 08A84500 mov eax, dword ptr
0045739E|.E8 5DFCFDFF call 00437000 ;SetText,显示上面的字符串
004573A3|.33C0 xor eax, eax
004573A5|.5A pop edx
004573A6|.59 pop ecx
004573A7|.59 pop ecx
004573A8|.64:8910 mov dword ptr fs:, edx
004573AB|.68 C0734500 push 004573C0
004573B0|>8D45 E4 lea eax, dword ptr
004573B3|.E8 A4C4FAFF call 0040385C
004573B8\.C3 retn
004573B9 .^ E9 5EBFFAFF jmp 0040331C
004573BE .^ EB F0 jmp short 004573B0
004573C0 .5F pop edi
004573C1 .5E pop esi
004573C2 .5B pop ebx
004573C3 .8BE5 mov esp, ebp
004573C5 .5D pop ebp
004573C6 .C3 retn
下面是注册码比较过程:
00457ABC/$55 push ebp
00457ABD|.8BEC mov ebp, esp
00457ABF|.53 push ebx
00457AC0|.56 push esi
00457AC1|.57 push edi
00457AC2|.8BF9 mov edi, ecx ;参数3,第1个checkbox状态值
00457AC4|.8BF2 mov esi, edx ;参数2,第2个MD5计算值变形运算后的数值
00457AC6|.8BD8 mov ebx, eax ;参数1,第1个MD5运算值变形运算后的数值
00457AC8|.E8 3FADFAFF call 0040280C
00457ACD|.2BDF sub ebx, edi ;参数1与参数3比较
00457ACF|.75 09 jnz short 00457ADA
00457AD1|.2B75 08 sub esi, dword ptr ;参数2与参数4比较,为参数4,第2个checkbox状态值
00457AD4|.75 04 jnz short 00457ADA
00457AD6|.33C0 xor eax, eax ;都相等则生成索引 0
00457AD8|.EB 0A jmp short 00457AE4
00457ADA|>B8 00010000 mov eax, 100 ;生成0~0xFF范围内的随机数
00457ADF|.E8 ECAEFAFF call 004029D0 ;生成随机数
00457AE4|>25 FF000000 and eax, 0FF ; 限制索引在0~0xFF范围内
00457AE9|.8B0485 849445>mov eax, dword ptr ; 通过索引查表返回调用地址
00457AF0|.5F pop edi
00457AF1|.5E pop esi
00457AF2|.5B pop ebx
00457AF3|.5D pop ebp
00457AF4\.C2 0400 retn 4
如果注册码不相等,则会调用下面这些函数,都是空函数,只有一个retn:
///////////////// 注册失败时的 call eax 调用的函数列表 ////////////////////////
0045746C .C3 retn
0045746D 8D40 00 lea eax, dword ptr
00457470 .C3 retn
00457471 8D40 00 lea eax, dword ptr
00457474 .C3 retn
00457475 8D40 00 lea eax, dword ptr
00457478 .C3 retn
00457479 8D40 00 lea eax, dword ptr
0045747C .C3 retn
0045747D 8D40 00 lea eax, dword ptr
00457480 .C3 retn
00457481 8D40 00 lea eax, dword ptr
00457484 .C3 retn
00457485 8D40 00 lea eax, dword ptr
00457488 .C3 retn
00457489 8D40 00 lea eax, dword ptr
0045748C .C3 retn
0045748D 8D40 00 lea eax, dword ptr
00457490 .C3 retn
00457491 8D40 00 lea eax, dword ptr
00457494 .C3 retn
00457495 8D40 00 lea eax, dword ptr
00457498 .C3 retn
00457499 8D40 00 lea eax, dword ptr
0045749C .C3 retn
0045749D 8D40 00 lea eax, dword ptr
004574A0 .C3 retn
004574A1 8D40 00 lea eax, dword ptr
004574A4 .C3 retn
004574A5 8D40 00 lea eax, dword ptr
004574A8 .C3 retn
004574A9 8D40 00 lea eax, dword ptr
这个Crackme 输入注册码的方式比较特别,是通过一个checkbox矩陈来输入的。
序列号共两个整数,每个整数32bits,分成4行,每行输入8bits,一起8行x8位,完成SN的输入。
通过上面分析,输入用户名:solly,得到SN:919D5B79-3826ACAC,再转成二进制矩陈显示如下,”1“表示选中,”0“表示不选中:
SN Matrix:
10010001
10011101
01011011
01111001
00111000
00100110
10101100
10101100
输入注册码,成功画面如下:
注册码验证过程分析完毕,以下是注册机,其中MD5代码参考网上代码,并按crackme的要求作一定修改,源码如下,共3个文件:
/*
main.cpp
*/
#include <stdio.h>
#include <stdlib.h>
#include "MD5.hpp"
int main(int argc, char** argv) {
unsigned char decrypt;
//unsigned char regname[] = "\0sollysollysollysollysollysollysollysollysollysollysollysollysol";
char temp;
char regname;
printf("Keygen for 152 - 'The AntiXryst' of 160 crackme.\n");
//// 输入用户名
printf("Enter your name: ");
gets(temp); //// 输入用户名
//// 用户名处理
int n = strlen(temp);
char * p = regname; /// 从第2个字节开始保存连接的用户名
strncpy(p, temp, 64);
int m = n;
while(m<63) {
strcat(p+n, temp);
m += n;
}
regname= '\0';/// 第1个字节设为'\0'
regname = '\0';/// 字符串null结束符
//printf("Name: %s\n", p);
////MD5算法
int len = 0x40; /// 固定长度为64
MD5_CTX md5;
MD5Init(&md5);
MD5Update(&md5, (unsigned char *)regname, len);
MD5Final(&md5, decrypt);
//////
unsigned int sn;
sn = md5.state2 - md5.state2 - md5.state2 + md5.state2;
sn = md5.state - md5.state - md5.state + md5.state;
////
printf("\n\nSN: %08X-%08X\n", sn, sn);
printf("SN Matrix:\n");
for(int i=0; i<2; i++) {
unsigned int a = sn;
unsigned int b = 0x80000000;
for(int j=1; j<=32; j++) {
if(a & b) {
printf("1");
} else {
printf("0");
}
b >>=1;
if((j % 8) == 0) {
printf("\n");
}
}
}
system("pause");
return 0;
}
第二个是 MD5.cpp:
#include "Md5.hpp"
unsigned char PADDING[] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
void MD5Init(MD5_CTX *context){
context->count=0;
context->count=0;
context->state=0x67452301;
context->state=0xEFCDAB89;
context->state=0x98BADCFE;
context->state=0x10325476;
//// context->buffer;
}
void MD5Update(MD5_CTX *context, unsigned char *input, unsigned int inputlen){
unsigned int i=0,index=0,partlen=0;
index=(context->count>>3)&0x3F;
partlen=64-index;
context->count+=inputlen<<3;
if(context->count<(inputlen<<3)) context->count++;
context->count+=inputlen>>29;
if(inputlen>=partlen){
memcpy(&context->buffer, input, partlen);
MD5Transform(context->state, context->buffer);
for(i=partlen;i+64<=inputlen;i+=64) MD5Transform(context->state,&input);
index=0;
//// 相对标准MD5第1处改动, 在第1次基础上直接进行第2次MD5计算/////////////
context->state2 = context->state; //// 保存第1次的MD5值
context->state2 = context->state; //// 保存第1次的MD5值
context->state2 = context->state; //// 保存第1次的MD5值
context->state2 = context->state; //// 保存第1次的MD5值
MD5Transform(context->state, context->buffer);
for(i=partlen;i+64<=inputlen;i+=64) MD5Transform(context->state,&input);
index=0;
//////////////////////////////////////////////////////////////////////////
}
else i=0;
memcpy(&context->buffer, &input, inputlen-i);
}
void MD5Final(MD5_CTX *context, unsigned char digest){
unsigned int index=0,padlen=0;
unsigned char bits;
index=(context->count>>3)&0x3F;
padlen=(index<56)?(56-index):(120-index);
////// 相对标准MD5第2处改动, 因为主注册名已经有64字节,并且由于其第1字节为'\0',会padding掉全部内容,所以不进行Padding处理
// MD5Update(context,PADDING,padlen); //// no padding, comments by solly
//////////////////////////////////////////////////////////////////////////////////
MD5Update(context,bits,8);//index=0
/////
MD5Encode(digest,context->state,16);
}
void MD5Encode(unsigned char *output, unsigned int *input, unsigned int len){
unsigned int i = 0, j = 0;
while (j<len){
output=input & 0xFF;
output=(input>>8)&0xFF;
output=(input>>16)&0xFF;
output=(input>>24)&0xFF;
i++;
j += 4;
}
}
void MD5Decode(unsigned int *output, unsigned char *input, unsigned int len){
unsigned int i = 0, j = 0;
while (j < len){
output = (input) |
(input << 8) |
(input << 16) |
(input << 24);
i++;
j += 4;
}
}
void MD5Transform(unsigned int state, unsigned char block){
unsigned int a = state;
unsigned int b = state;
unsigned int c = state;
unsigned int d = state;
unsigned int x;
MD5Decode(x, block, 64);
FF(a, b, c, d, x, 7, 0xd76aa478);
FF(d, a, b, c, x, 12, 0xe8c7b756);
FF(c, d, a, b, x, 17, 0x242070db);
FF(b, c, d, a, x, 22, 0xc1bdceee);
FF(a, b, c, d, x, 7, 0xf57c0faf);
FF(d, a, b, c, x, 12, 0x4787c62a);
FF(c, d, a, b, x, 17, 0xa8304613);
FF(b, c, d, a, x, 22, 0xfd469501);
FF(a, b, c, d, x, 7, 0x698098d8);
FF(d, a, b, c, x, 12, 0x8b44f7af);
FF(c, d, a, b, x, 17, 0xffff5bb1);
FF(b, c, d, a, x, 22, 0x895cd7be);
FF(a, b, c, d, x, 7, 0x6b901122);
FF(d, a, b, c, x, 12, 0xfd987193);
FF(c, d, a, b, x, 17, 0xa679438e);
FF(b, c, d, a, x, 22, 0x49b40821);
GG(a, b, c, d, x, 5, 0xf61e2562);
GG(d, a, b, c, x, 9, 0xc040b340);
GG(c, d, a, b, x, 14, 0x265e5a51);
GG(b, c, d, a, x, 20, 0xe9b6c7aa);
GG(a, b, c, d, x, 5, 0xd62f105d);
GG(d, a, b, c, x, 9, 0x2441453);
GG(c, d, a, b, x, 14, 0xd8a1e681);
GG(b, c, d, a, x, 20, 0xe7d3fbc8);
GG(a, b, c, d, x, 5, 0x21e1cde6);
GG(d, a, b, c, x, 9, 0xc33707d6);
GG(c, d, a, b, x, 14, 0xf4d50d87);
GG(b, c, d, a, x, 20, 0x455a14ed);
GG(a, b, c, d, x, 5, 0xa9e3e905);
GG(d, a, b, c, x, 9, 0xfcefa3f8);
GG(c, d, a, b, x, 14, 0x676f02d9);
GG(b, c, d, a, x, 20, 0x8d2a4c8a);
HH(a, b, c, d, x, 4, 0xfffa3942);
HH(d, a, b, c, x, 11, 0x8771f681);
HH(c, d, a, b, x, 16, 0x6d9d6122);
HH(b, c, d, a, x, 23, 0xfde5380c);
HH(a, b, c, d, x, 4, 0xa4beea44);
HH(d, a, b, c, x, 11, 0x4bdecfa9);
HH(c, d, a, b, x, 16, 0xf6bb4b60);
HH(b, c, d, a, x, 23, 0xbebfbc70);
HH(a, b, c, d, x, 4, 0x289b7ec6);
HH(d, a, b, c, x, 11, 0xeaa127fa);
HH(c, d, a, b, x, 16, 0xd4ef3085);
HH(b, c, d, a, x, 23, 0x4881d05);
HH(a, b, c, d, x, 4, 0xd9d4d039);
HH(d, a, b, c, x, 11, 0xe6db99e5);
HH(c, d, a, b, x, 16, 0x1fa27cf8);
HH(b, c, d, a, x, 23, 0xc4ac5665);
II(a, b, c, d, x, 6, 0xf4292244);
II(d, a, b, c, x, 10, 0x432aff97);
II(c, d, a, b, x, 15, 0xab9423a7);
II(b, c, d, a, x, 21, 0xfc93a039);
II(a, b, c, d, x, 6, 0x655b59c3);
II(d, a, b, c, x, 10, 0x8f0ccc92);
II(c, d, a, b, x, 15, 0xffeff47d);
II(b, c, d, a, x, 21, 0x85845dd1);
II(a, b, c, d, x, 6, 0x6fa87e4f);
II(d, a, b, c, x, 10, 0xfe2ce6e0);
II(c, d, a, b, x, 15, 0xa3014314);
II(b, c, d, a, x, 21, 0x4e0811a1);
II(a, b, c, d, x, 6, 0xf7537e82);
II(d, a, b, c, x, 10, 0xbd3af235);
II(c, d, a, b, x, 15, 0x2ad7d2bb);
II(b, c, d, a, x, 21, 0xeb86d391);
state += a;
state += b;
state += c;
state += d;
}
第三个是 MD5.hpp:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<iostream>
#include<cmath>
typedef struct{
unsigned int count;
unsigned int state;
unsigned char buffer;
unsigned int state2;//// 这里是改动之三,不对算法产生影响,只是用来备份第1次MD5结果
} MD5_CTX;
#define F(x,y,z) ((x&y)|(~x&z))
#define G(x,y,z) ((x&z)|(y&~z))
#define H(x,y,z) (x^y^z)
#define I(x,y,z) (y^(x|~z))
#define ROTATE_LEFT(x,n) ((x<<n)|(x>>(32-n)))
#define FF(a,b,c,d,x,s,ac) { a+=F(b,c,d)+x+ac; a=ROTATE_LEFT(a,s); a+=b;}
#define GG(a,b,c,d,x,s,ac) { a+=G(b,c,d)+x+ac; a=ROTATE_LEFT(a,s); a+=b;}
#define HH(a,b,c,d,x,s,ac) { a+=H(b,c,d)+x+ac; a=ROTATE_LEFT(a,s); a+=b;}
#define II(a,b,c,d,x,s,ac) { a+=I(b,c,d)+x+ac; a=ROTATE_LEFT(a,s); a+=b;}
void MD5Init(MD5_CTX *context);
void MD5Update(MD5_CTX *context, unsigned char *input, unsigned int inputlen);
void MD5Final(MD5_CTX *context, unsigned char digest);
void MD5Transform(unsigned int state, unsigned char block);
void MD5Encode(unsigned char *output, unsigned int *input, unsigned int len);
void MD5Decode(unsigned int *output, unsigned char *input, unsigned int len);
以上代码是在 Dev-C++上调试通过的。
///////
完毕,码字不易!!!!评分免费!!!!
楼主辛苦了,虽然我不懂这个 这个厉害,膜拜大神~~~
页:
[1]