第七个软件与第六个类似,同一个作者,软件界面如下:
软件有两个文本框,三个按钮,点击说明按钮时,和上一个软件的提示类似,也是要求隐藏下面的按钮,使下面的Logo显示完全才算破解。
这个软件也是使用Delphi写的,那么我们直接使用Delphi专用的逆向软件分析下事件:
通过分析发现,程序隐藏了一个按钮,按按钮的意思,就应该是先单击Register按钮,然后再单击again按钮完成破解,接下来我们就用OD具体分析下:
我们先用OD载入,然后在按钮单击事件那下断,然后输入11111和22222,单击按钮,在按钮事件处断下:
00442F28 /. 55 push ebp ; 注册按钮单击
00442F29 |. 8BEC mov ebp,esp
00442F2B |. 83C4 F8 add esp,-0x8
00442F2E |. 53 push ebx
00442F2F |. 56 push esi
00442F30 |. 33C9 xor ecx,ecx ; aLoNg3x_.0041E570
00442F32 |. 894D F8 mov [local.2],ecx ; aLoNg3x_.0041E570
00442F35 |. 8BD8 mov ebx,eax
00442F37 |. 33C0 xor eax,eax
00442F39 |. 55 push ebp
00442F3A |. 68 22304400 push aLoNg3x_.00443022
00442F3F |. 64:FF30 push dword ptr fs:[eax]
00442F42 |. 64:8920 mov dword ptr fs:[eax],esp
00442F45 |. 8D55 F8 lea edx,[local.2]
00442F48 |. 8B83 DC020000 mov eax,dword ptr ds:[ebx+0x2DC] ; codice文本框ID
00442F4E |. E8 ED02FEFF call aLoNg3x_.00423240 ; 获取codice输入字符串
00442F53 |. 8B45 F8 mov eax,[local.2] ; 字符串
00442F56 |. 8D55 FC lea edx,[local.1]
00442F59 |. E8 FAF9FBFF call aLoNg3x_.00402958 ; 判断文本框2,正常返回0
00442F5E |. 8BF0 mov esi,eax
00442F60 |. 837D FC 00 cmp [local.1],0x0 ; 如果输入合法就跳转
00442F64 |. 74 37 je short aLoNg3x_.00442F9D
00442F66 |. B8 38304400 mov eax,aLoNg3x_.00443038 ; ASCII 59,"ou MUST insert a valid Long Integer Value in the Code Editor... Thank you :)"
00442F6B |. E8 00F6FFFF call aLoNg3x_.00442570
00442F70 |. 8D55 F8 lea edx,[local.2]
00442F73 |. 8B83 DC020000 mov eax,dword ptr ds:[ebx+0x2DC]
00442F79 |. E8 C202FEFF call aLoNg3x_.00423240
00442F7E |. 8B45 F8 mov eax,[local.2] ; user32.777678CB
00442F81 |. E8 06FBFFFF call aLoNg3x_.00442A8C ; 关键
00442F86 |. A3 30584400 mov dword ptr ds:[0x445830],eax
00442F8B |. BA 90304400 mov edx,aLoNg3x_.00443090 ; UNICODE "0"
00442F90 |. 8B83 DC020000 mov eax,dword ptr ds:[ebx+0x2DC]
00442F96 |. E8 D502FEFF call aLoNg3x_.00423270
00442F9B |. EB 6F jmp short aLoNg3x_.0044300C
00442F9D |> 85F6 test esi,esi
00442F9F |. 7E 5A jle short aLoNg3x_.00442FFB
00442FA1 |. 8D55 F8 lea edx,[local.2]
00442FA4 |. 8B83 D8020000 mov eax,dword ptr ds:[ebx+0x2D8]
00442FAA |. E8 9102FEFF call aLoNg3x_.00423240
00442FAF |. 8B4D F8 mov ecx,[local.2] ; user32.777678CB
00442FB2 |. 8BD6 mov edx,esi
00442FB4 |. A1 30584400 mov eax,dword ptr ds:[0x445830]
00442FB9 |. E8 EAF9FFFF call aLoNg3x_.004429A8 ; 关键的call
00442FBE |. 84C0 test al,al ; 关键比较
00442FC0 |. 74 30 je short aLoNg3x_.00442FF2
00442FC2 |. 33D2 xor edx,edx
00442FC4 |. 8B83 CC020000 mov eax,dword ptr ds:[ebx+0x2CC] ; 左边按钮id
00442FCA |. E8 6101FEFF call aLoNg3x_.00423130 ; 隐藏按钮
00442FCF |. B2 01 mov dl,0x1
00442FD1 |. 8B83 E8020000 mov eax,dword ptr ds:[ebx+0x2E8]
00442FD7 |. E8 5401FEFF call aLoNg3x_.00423130
按钮单击事件里面主要做的是:获取下面文本框输入的数,然后判断输入是否异常,如果正常就跳到下面继续执行,如果异常,会弹出异常提示。
那么在正常处执行时,有一个关键比较test al,al,很明显上面就是关键call,我们先不管关键call里面是什么,就看比较后面的跳转,如果没有跳转,就会隐藏左边的按钮,然后显示右边的按钮,我们我们必须在关键call里使返回的al值不为0就好了。
关键call的代码如下:
004429A8 /$ 55 push ebp ; 关键call
004429A9 |. 8BEC mov ebp,esp
004429AB |. 83C4 F4 add esp,-0xC
004429AE |. 53 push ebx
004429AF |. 56 push esi
004429B0 |. 57 push edi
004429B1 |. 894D F8 mov [local.2],ecx ; aLoNg3x_.0041E570
004429B4 |. 8955 FC mov [local.1],edx
004429B7 |. 8BF8 mov edi,eax
004429B9 |. 8B45 F8 mov eax,[local.2] ; user32.777678CB
004429BC |. E8 2712FCFF call aLoNg3x_.00403BE8
004429C1 |. 33C0 xor eax,eax
004429C3 |. 55 push ebp
004429C4 |. 68 7A2A4400 push aLoNg3x_.00442A7A
004429C9 |. 64:FF30 push dword ptr fs:[eax]
004429CC |. 64:8920 mov dword ptr fs:[eax],esp
004429CF |. 8B45 F8 mov eax,[local.2] ; user32.777678CB
004429D2 |. E8 5D10FCFF call aLoNg3x_.00403A34
004429D7 |. 83F8 04 cmp eax,0x4 ; 输入长度大于4
004429DA |. 0F8E 82000000 jle aLoNg3x_.00442A62
004429E0 |. 33DB xor ebx,ebx
004429E2 |. 8B45 F8 mov eax,[local.2] ; user32.777678CB
004429E5 |. E8 4A10FCFF call aLoNg3x_.00403A34
004429EA |. 85C0 test eax,eax
004429EC |. 7E 38 jle short aLoNg3x_.00442A26
004429EE |. 8945 F4 mov [local.3],eax
004429F1 |. BE 01000000 mov esi,0x1
004429F6 |> 8B45 F8 /mov eax,[local.2] ; nome字符串
004429F9 |. E8 3610FCFF |call aLoNg3x_.00403A34 ; 获取长度
004429FE |. 83F8 01 |cmp eax,0x1
00442A01 |. 7C 1D |jl short aLoNg3x_.00442A20
00442A03 |> 8B55 F8 |/mov edx,[local.2] ; user32.777678CB
00442A06 |. 0FB65432 FF ||movzx edx,byte ptr ds:[edx+esi-0x1]
00442A0B |. 8B4D F8 ||mov ecx,[local.2] ; user32.777678CB
00442A0E |. 0FB64C01 FF ||movzx ecx,byte ptr ds:[ecx+eax-0x1]
00442A13 |. 0FAFD1 ||imul edx,ecx ; aLoNg3x_.0041E570
00442A16 |. 0FAFD7 ||imul edx,edi
00442A19 |. 03DA ||add ebx,edx
00442A1B |. 48 ||dec eax
00442A1C |. 85C0 ||test eax,eax
00442A1E |.^ 75 E3 |\jnz short aLoNg3x_.00442A03
00442A20 |> 46 |inc esi
00442A21 |. FF4D F4 |dec [local.3]
00442A24 |.^ 75 D0 \jnz short aLoNg3x_.004429F6
00442A26 |> 8BC3 mov eax,ebx
00442A28 |. 99 cdq
00442A29 |. 33C2 xor eax,edx
00442A2B |. 2BC2 sub eax,edx
00442A2D |. B9 2A2C0A00 mov ecx,0xA2C2A
00442A32 |. 99 cdq
00442A33 |. F7F9 idiv ecx ; aLoNg3x_.0041E570
00442A35 |. 8BDA mov ebx,edx
00442A37 |. 8B45 FC mov eax,[local.1]
00442A3A |. B9 59000000 mov ecx,0x59
00442A3F |. 99 cdq
00442A40 |. F7F9 idiv ecx ; aLoNg3x_.0041E570
00442A42 |. 8BC8 mov ecx,eax
00442A44 |. 8B45 FC mov eax,[local.1]
00442A47 |. BE 50000000 mov esi,0x50
00442A4C |. 99 cdq
00442A4D |. F7FE idiv esi
00442A4F |. 03CA add ecx,edx ; 取膜
00442A51 |. 41 inc ecx ; aLoNg3x_.0041E570
00442A52 |. 894D FC mov [local.1],ecx ; aLoNg3x_.0041E570
00442A55 |. 3B5D FC cmp ebx,[local.1]
00442A58 |. 75 04 jnz short aLoNg3x_.00442A5E
00442A5A |. B3 01 mov bl,0x1
00442A5C |. EB 06 jmp short aLoNg3x_.00442A64
00442A5E |> 33DB xor ebx,ebx
00442A60 |. EB 02 jmp short aLoNg3x_.00442A64
00442A62 |> 33DB xor ebx,ebx
00442A64 |> 33C0 xor eax,eax
00442A66 |. 5A pop edx ; aLoNg3x_.004245C0
00442A67 |. 59 pop ecx ; aLoNg3x_.004245C0
00442A68 |. 59 pop ecx ; aLoNg3x_.004245C0
00442A69 |. 64:8910 mov dword ptr fs:[eax],edx
00442A6C |. 68 812A4400 push aLoNg3x_.00442A81
00442A71 |> 8D45 F8 lea eax,[local.2]
00442A74 |. E8 3F0DFCFF call aLoNg3x_.004037B8
00442A79 \. C3 retn
00442A7A .^ E9 F907FCFF jmp aLoNg3x_.00403278
00442A7F .^ EB F0 jmp short aLoNg3x_.00442A71
00442A81 . 8BC3 mov eax,ebx
00442A83 . 5F pop edi ; aLoNg3x_.004245C0
00442A84 . 5E pop esi ; aLoNg3x_.004245C0
00442A85 . 5B pop ebx ; aLoNg3x_.004245C0
00442A86 . 8BE5 mov esp,ebp
00442A88 . 5D pop ebp ; aLoNg3x_.004245C0
00442A89 . C3 retn
在关键call里,要求第一个文本框输入的长度大于4,然后后面有一套有两个循环的计算流程,这里的计算与两个值有关,一个是第一个文本框的输入,一个是寄存器edi的值,但是这里寄存器edi的值始终为0,所以计算得到的值始终为0,计算后的值保存在寄存器ebx中,这里ebx为0。
在关键call循环计算的后面,又有一个计算,先获取文本框2的输入数字,然后用这个数字除以0x59,然后用这个数与0x50取膜,将计算的这两个结果相加,然后加1,将这最后的结果与ebx比较,如果相等,这个关键call返回的结果就是1,否则关键call返回0,因此我们必须保证这两个值相等,后面的破解就成功了一步。
那么我们就来看这里的edi寄存器在前面是怎么被赋值的,在这个关键call里 edi 的值从eax寄存器获得,那么我们就看在调用关键call前eax寄存器的值,在调用这个关键call前面是mov eax,dword ptr ds:[0x445830],eax的值从这个内存地址获得,但是通过搜索这个内存地址发现,这个地址的值在上面输入异常跳转中被赋值。
所以现在要做的就是判断这个内存的值是怎么赋值的,当下面的文本框输入的数比较大时就会判断输入异常,我们具体看判断异常的部分,在上面的代码中有备注为判断文本框2:
004029A6 |> 84DB test bl,bl ; Default case of switch 00402975
004029A8 |. |74 34 je short aLoNg3x_.004029DE
004029AA |> |80EB 30 /sub bl,0x30
004029AD |. |80FB 09 |cmp bl,0x9
004029B0 |. |77 2C |ja short aLoNg3x_.004029DE
004029B2 |. |39F8 |cmp eax,edi
004029B4 |. |77 28 |ja short aLoNg3x_.004029DE
004029B6 |. |8D0480 |lea eax,dword ptr ds:[eax+eax*4]
004029B9 |. |01C0 |add eax,eax
004029BB |. |01D8 |add eax,ebx
004029BD |. |8A1E |mov bl,byte ptr ds:[esi]
004029BF |. |46 |inc esi
004029C0 |. |84DB |test bl,bl
004029C2 |.^|75 E6 \jnz short aLoNg3x_.004029AA
004029C4 |> |FECD dec ch
004029C6 |. |74 10 je short aLoNg3x_.004029D8
004029C8 |. |85C0 test eax,eax
004029CA |. |7C 12 jl short aLoNg3x_.004029DE
004029CC |> |59 pop ecx ; SogouPY.101A6679
004029CD |. |31F6 xor esi,esi
004029CF |> |8932 mov dword ptr ds:[edx],esi
004029D1 |. |5F pop edi ; SogouPY.101A6679
004029D2 |. |5E pop esi ; SogouPY.101A6679
004029D3 |. |5B pop ebx ; SogouPY.101A6679
004029D4 |. |C3 retn
004029D5 |> |46 inc esi
004029D6 |. |EB 06 jmp short aLoNg3x_.004029DE
004029D8 |> |F7D8 neg eax
上面贴出的是代码的关键部分,如果上面的循环正常执行完的话,返回的就是0,也就是没有异常,如果从前面的ja跳转,那么返回的就不是0,很明显我们只要输入一个ASCII码大于0x39的数就会从ja跳转,0x39就是9,即我们输入A就会跳转,或者,通过计算累计的值大于edi寄存器的值也会跳转,edi寄存器的值固定为0xCCCCCCC,那么我们在文本框输入一个比较大的值如:12345678910,再调试。
测试发现,弹出了异常如下:
提示要输入一个有效的整数,我们继续跟进,发现获取了第二个文本框输入的值保存在eax中,然后调用了一个函数,我们跟进这个函数,代码如下:
00442A8C /$ 55 push ebp
00442A8D |. 8BEC mov ebp,esp
00442A8F |. 51 push ecx ; user32.777678F4
00442A90 |. 53 push ebx
00442A91 |. 56 push esi
00442A92 |. 57 push edi
00442A93 |. 8945 FC mov [local.1],eax
00442A96 |. 8B45 FC mov eax,[local.1]
00442A99 |. E8 4A11FCFF call aLoNg3x_.00403BE8
00442A9E |. 33C0 xor eax,eax
00442AA0 |. 55 push ebp
00442AA1 |. 68 212B4400 push aLoNg3x_.00442B21
00442AA6 |. 64:FF30 push dword ptr fs:[eax]
00442AA9 |. 64:8920 mov dword ptr fs:[eax],esp
00442AAC |. 8B45 FC mov eax,[local.1]
00442AAF |. E8 800FFCFF call aLoNg3x_.00403A34
00442AB4 |. 83F8 05 cmp eax,0x5
00442AB7 |. 7E 3D jle short aLoNg3x_.00442AF6
00442AB9 |. BE 7B030000 mov esi,0x37B
00442ABE |. 8B45 FC mov eax,[local.1]
00442AC1 |. E8 6E0FFCFF call aLoNg3x_.00403A34
00442AC6 |. 8BD8 mov ebx,eax
00442AC8 |. 4B dec ebx
00442AC9 |. 85DB test ebx,ebx
00442ACB |. 7E 2B jle short aLoNg3x_.00442AF8
00442ACD |. B9 01000000 mov ecx,0x1
00442AD2 |> 8B45 FC /mov eax,[local.1]
00442AD5 |. 0FB60408 |movzx eax,byte ptr ds:[eax+ecx]
00442AD9 |. BF 11000000 |mov edi,0x11
00442ADE |. 33D2 |xor edx,edx
00442AE0 |. F7F7 |div edi
00442AE2 |. 42 |inc edx
00442AE3 |. 8B45 FC |mov eax,[local.1]
00442AE6 |. 0FB64408 FF |movzx eax,byte ptr ds:[eax+ecx-0x1]
00442AEB |. 0FAFD0 |imul edx,eax
00442AEE |. 03F2 |add esi,edx
00442AF0 |. 41 |inc ecx ; user32.777678F4
00442AF1 |. 4B |dec ebx
00442AF2 |.^ 75 DE \jnz short aLoNg3x_.00442AD2
00442AF4 |. EB 02 jmp short aLoNg3x_.00442AF8
00442AF6 |> 33F6 xor esi,esi
00442AF8 |> 8BC6 mov eax,esi
00442AFA |. B9 48710000 mov ecx,0x7148
00442AFF |. 99 cdq
00442B00 |. F7F9 idiv ecx ; user32.777678F4
00442B02 |. 8BC2 mov eax,edx
00442B04 |. 99 cdq
00442B05 |. 33C2 xor eax,edx
00442B07 |. 2BC2 sub eax,edx
00442B09 |. 8BD8 mov ebx,eax
00442B0B |. 33C0 xor eax,eax
00442B0D |. 5A pop edx ; aLoNg3x_.00442F86
00442B0E |. 59 pop ecx ; aLoNg3x_.00442F86
00442B0F |. 59 pop ecx ; aLoNg3x_.00442F86
00442B10 |. 64:8910 mov dword ptr fs:[eax],edx
00442B13 |. 68 282B4400 push aLoNg3x_.00442B28
00442B18 |> 8D45 FC lea eax,[local.1]
00442B1B |. E8 980CFCFF call aLoNg3x_.004037B8
00442B20 \. C3 retn
00442B21 .^ E9 5207FCFF jmp aLoNg3x_.00403278
00442B26 .^ EB F0 jmp short aLoNg3x_.00442B18
00442B28 . 8BC3 mov eax,ebx
00442B2A . 5F pop edi ; aLoNg3x_.00442F86
00442B2B . 5E pop esi ; aLoNg3x_.00442F86
00442B2C . 5B pop ebx ; aLoNg3x_.00442F86
00442B2D . 59 pop ecx ; aLoNg3x_.00442F86
00442B2E . 5D pop ebp ; aLoNg3x_.00442F86
00442B2F . C3 retn
这个函数的作用也就是根据第二个文本框输入的值,计算得到一个值然后保存在eax中再返回,计算的值与第一个文本框的值有关,在一个循环里取值然后获取字节ASCII吗再计算,例如我这里输入22222,计算得到0x1313,也就是后面关键call的edi寄存器的值是0x1313。然后在关键call中根据22222和edi的值计算得到的值是0x7F3B2,即如果我们输入的第二个文本框的值通过计算后的值也是0x7F3B2,那么就会得到想要的结果。通过计算得到这个值是46381121(十六进制2C3B841),即0x 2C3B841/0x59+0x2C3B841%50+1=0x7F3B2。
输入后我们发现程序变成了上面的样子,第一个文本框变成了禁用状态,左边的按钮被隐藏了,右边的按钮被激活。,那么我们对右边的按钮函数下断,发现右边按钮的函数和左边按钮的函数是类似的,是一个重复的过程,那么我们可以总结如下:
1、输入一个使文本框2提示异常的数,如12345678910,文本框1输入一个正常的数如22222,会根据22222的值计算得到一个值edi
2、文本框2输入一个值使得计算后得到的值和文本框1与edi计算得到的值相等,这里是46381121
3、重复上面两步一遍,结果如下:
有了上面的思路,写注册机比较容易了,就不写了