吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 3027|回复: 13
收起左侧

[原创] 160个CrakeMe程序之007

  [复制链接]
yakov 发表于 2021-1-10 01:14
本帖最后由 yakov 于 2021-1-10 02:32 编辑

最近在做Crackme练习,虽然这160个都已经有人写过了,不过我还是先独立尝试解决,等完成后再参看其他朋友的。这个Crackme另外一个朋友的分析贴:

https://www.52pojie.cn/thread-613691-4-1.html

有些部分我觉得还没有完全分析出来,所以我也发个帖子做为补充吧。

PEID查下,Delphi程序,OD载入,搜索字符串,发现有个GREAT,跟随到函数头,下个断点,输入用户名和试练码:

用户名: yakov1
试练码: 123456

点击Register没有断下来,后来尝试点击Cancel却断下来了:
00442BBB      |. E8 8006FEFF   call aLoNg3x_.00423240                    ;  取试练码,eax返回长度
......
00442BCD     |. E8 6E06FEFF  call aLoNg3x_.00423240                    ;  取用户名,eax返回长度
......
00442BD6      |. E8 55FFFFFF  call aLoNg3x_.00442B30                    ;  跟进去
00442BDB     |. 84C0               test al,al                                            ;  al不为0就GREAT
00442BDD     |. 0F84 86000000 je aLoNg3x_.00442C69
00442BE3      |. 8D45 FC          lea eax,[local.1]
00442BE6      |. BA B02C4400  mov edx,aLoNg3x_.00442CB0            ;  ASCII "GREAT !!!"

进那个Call,再进其中一个对比的关键Call:
00403B44       /$  53                  push ebx
...
00403B4B      |.  39D0               cmp eax,edx                                      ;  Name和注册码是否相等
00403B4D      |.  0F84 8F000000 je aLoNg3x_.00403BE2
......

这里的算法其实就是判断用户名和注册码相等,相等就弹出消息框,这里似乎不是关键,继续。

再查看字符串有句提示:
00442F66       mov eax,aLoNg3x_.00443038      "You MUSTinsert a valid Long Integer Value in the Code Editor... Thank you :)"

找到函数头,点击Register断下:
00442F28       /.  55                   push ebp
......
00442F4E      |.  E8 ED02FEFF    call aLoNg3x_.00423240
00442F53       |.  8B45 F8           mov eax,[local.2]                               ;  local2是试练码,eax返回了长度6
......
00442F59       |.  E8 FAF9FBFF    call aLoNg3x_.00402958                    ;  判断试练码,要大于0
00442F60       |.  837D FC 00      cmp [local.1],0x0                               ;  不能为空
00442F64       |.  74 37               je short aLoNg3x_.00442F9D              ; 试练码要大于0
00442F66       |.  B8 38304400    mov eax,aLoNg3x_.00443038             ;  ASCII "YouMUST insert a valid Long Integer Value in the Code Editor... Thank you :)"
......
00442F81       |.  E8 06FBFFFF     call aLoNg3x_.00442A8C
00442F86       |.  A3 30584400    mov dword ptr ds:[0x445830],eax
......
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

跟进关键验证Call
004429A8      /$ 55                   push ebp
......
004429B1       |. 894D F8           mov [local.2],ecx                               ;  local2 = Name
004429B4       |. 8955 FC           mov [local.1],edx                               ;  local1 = 试练码
004429B7       |.  8BF8               mov edi,eax                                       ;  edi= eax, 设为KEY
......
004429D2      |. E8 5D10FCFF    call aLoNg3x_.00403A34                    ;  用户名长度
004429D7      |. 83F8 04            cmp eax,0x4                                      ;  需>=5,输入框有限制,最大为10
004429DA      |. 0F8E 82000000 jle aLoNg3x_.00442A62
......
004429EE      |. 8945 F4            mov [local.3],eax                               ;  local3 = 用户名长度
004429F1       |. BE 01000000    mov esi,0x1                                       ; esi = 1
004429F6       |> 8B45 F8          /mov eax,[local.2]                              ;  for i=1 to len(Name)
004429F9       |. E8 3610FCFF    |call aLoNg3x_.00403A34                   ;  取用户名长度
004429FE      |. 83F8 01            |cmp eax,0x1
00442A01      |. 7C 1D              |jl short aLoNg3x_.00442A20              ;  下面循环for (j=len(Name); j>0; --j)
00442A03      |> 8B55 F8          |/movedx,[local.2]
00442A06      |. 0FB65432 FF    ||movzx edx,byte ptr ds:[edx+esi-0x1] ;  edx = Name,从第1位到最后1位
00442A0B      |. 8B4D F8          ||movecx,[local.2]
00442A0E      |. 0FB64C01 FF    ||movzx ecx,byte ptr ds:[ecx+eax-0x1];  从最后依次往前取Name1位
00442A13      |. 0FAFD1            ||imul edx,ecx                                    ;  Name *= Name[长度]
00442A16      |. 0FAFD7            ||imul edx,edi                                     ;  再乘edi(KEY)
00442A19      |. 03DA               ||addebx,edx                                      ;  ebx为和,设为sum
00442A1B      |. 48                    ||dec eax
00442A1C      |. 85C0                ||test eax,eax
00442A1E      |.^ 75 E3              |\jnz short aLoNg3x_.00442A03
00442A20      |> 46                   |inc esi                                              ;  esi++
00442A21      |. FF4D F4            |dec [local.3]                                     ;  local3长度 - 1
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                              ;  ecx = 0xA2C2A(666666)
00442A32      |. 99                    cdq
00442A33      |. F7F9                 idiv ecx
00442A35      |. 8BDA               mov ebx,edx                                      ;  取余数
00442A37      |. 8B45 FC           mov eax,[local.1]                                ;  试练码
00442A3A      |. B9 59000000   mov ecx,0x59                                     ; ecx = 0x59(89)
00442A3F      |. 99                    cdq
00442A40      |. F7F9                idiv ecx                                              ;  除89
00442A42      |. 8BC8               mov ecx,eax                                       ;  ecx = 商
00442A44      |. 8B45 FC           mov eax,[local.1]
00442A47      |. BE 50000000    mov esi,0x50                                      ; esi = 0x50(80)
00442A4C      |. 99                   cdq
00442A4D      |. F7FE               idiv esi
00442A4F      |. 03CA               add ecx,edx                                       ;  前面的商+余数
00442A51      |. 41                   inc ecx                                               ;  +1
00442A52      |. 894D FC          mov [local.1],ecx
00442A55      |. 3B5D FC         cmp ebx,[local.1]                                 ;  再对比前面Name的计算结果

算法伪码:

int sum= 0;
for(i=0; i<len(Name); ++i)                 //从1取到长度
{
       for (j=len(Name)-1; j>=0; --j)     //从最后1位取到第1位
              sum += Name * Name[j] * KEY;
}

SN 整除 89 + SN % 80 +1 = sum % 0xA2C2A (666666)

如果正确,Register按钮消失 但是关键的是,上面红色004429B7那一句,每次都是0,所以上面所有计算全部没用,都为0!

向上追踪,eax的赋值是在验证Call前一句:

00442FB4      |.  A1 30584400    mov eax,dword ptr ds:[0x445830]

但是[0x445830]这里也是每次都是0,右键 -> 查找参考对象 -> 地址常数:

pic1.jpg

只有2个地方,00442F86和00443118两处,到前面再查看:

00442F66       |.  B8 38304400    mov eax,aLoNg3x_.00443038             ;  ASCII "YouMUST insert a valid Long Integer Value in the Code Editor... Thank you :)"
......
00442F81       |.  E8 06FBFFFF     callaLoNg3x_.00442A8C
00442F86       |.  A3 30584400    mov dword ptr ds:[0x445830],eax

正好在提示非法输入的地方,上面有个Call,会生成一个值,然后赋值给这个地址。尝试先输入一次错误的,让提示出现,然后再点Register,果然有值了!

现在猜测,这个[0x445830]就是个动态密钥KEY,由用户输入一个不是longinteger的值动态生成,经检测,合法值并不是提示的long integer,而是32位整数值! 先跟进00442F81,确定密钥的生成:

00442AB4      |. 83F8 05           cmp eax,0x5                                      ;  输入的密钥要大于等于6
00442AB7      |.  7E3D              jle short aLoNg3x_.00442AF6
00442AB9      |. BE 7B030000   mov esi,0x37B                                    ;  esi = 37B
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]                              ;  for i=1 to len(Key)-1
00442AD5      |. 0FB60408        |movzx eax,byte ptr ds:[eax+ecx]       ;  key[i+1]
00442AD9      |. BF 11000000    |mov edi,0x11                                    ; edi = 17
00442ADE     |. 33D2                |xor edx,edx
00442AE0      |. F7F7                |div edi                                                ; key[i+1] % 17
00442AE2      |. 42                   |inc edx                                               ;  余数+1
00442AE3      |. 8B45 FC           |mov eax,[local.1]
00442AE6      |. 0FB64408 FF    |movzx eax,byte ptr ds:[eax+ecx-0x1]  ;  key
00442AEB      |. 0FAFD0           |imul edx,eax                                       ;  再乘余数
00442AEE      |. 03F2                |add esi,edx                                         ;  esi(初值37B) += edx
00442AF0      |. 41                   |inc ecx
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                                  ;  0x7148
00442AFF       |.  99                   cdq
00442B00       |.  F7F9               idiv ecx
00442B02       |.  8BC2               mov eax,edx                                      ;  取余数放入eax
00442B04       |.  99                   cdq
00442B05       |.  33C2               xoreax,edx                                         ;  eax, edx异或
00442B07       |.  2BC2               sub eax,edx                                        ;  eax -= edx

eax就是生成的密钥
算法:
1、输入长度>=6;
2、
esi = 37B

for (i=0; i<len(Key); ++i)
       esi+= (key[i+1] % 17 + 1) * key;
esi %= 0x7148;

if (esi>=0)
       edx= 0;
else
       edx= -1;

esi ^= edx;
esi -= edx;

现在再按上面算法自成的注册码输入,点击Register,按键消失,左边Logo露出,用户名变灰,表示不能再变了。右边又出现一个按键,还得继续。

刚才找那个[0x445830]赋值地址时,有两个,另外一个是:00443118,这里的调用和刚才是同一个的,我们找它的注册码验证算法就行了:

004430F8       |.  B8 44324400    mov eax,aLoNg3x_.00443244             ;  ASCII "You MUST insert a valid LongInteger Value in the Code Editor... Thank you :)"
004430FD      |.  E8 6EF4FFFF     call aLoNg3x_.00442570
00443102       |.  8D55 F4           lea edx,[local.3]
00443105       |.  8B83 DC020000 mov eax,dword ptr ds:[ebx+0x2DC]
0044310B       |.  E8 3001FEFF    call aLoNg3x_.00423240
00443110       |. 8B45 F4            mov eax,[local.3]
00443113       |. E8 74F9FFFF      call aLoNg3x_.00442A8C
00443118       |.  A3 30584400    movdword ptr ds:[0x445830],eax        ;  生成的密钥赋值
0044311D      |.  BA 9C324400   movedx,aLoNg3x_.0044329C
00443122       |.  8B83 DC020000 mov eax,dword ptrds:[ebx+0x2DC]
00443128       |.  E8 4301FEFF     call aLoNg3x_.00423270                    ;  这里下断
0044312D      |.  E9 DD000000    jmp aLoNg3x_.0044320F
00443132       |>  85F6                test esi,esi
00443134       |.  0F8E C4000000  jle aLoNg3x_.004431FE

注册码也是和上面一样的,等于再重复一次刚才的就可以了,到现在logo完全露出来了。


这个Crackme最大的特点,就是它采用了一个密钥,由用户动态输入的值计算出的密钥参与运算!



附上一个MFC的注册机代码,写得不是很理想,注册码不能为负,这个没自动实现,得人工判断:

void CKeygenDlg::OnGen()
{
        UpdateData(TRUE);
        if (m_szKeyin.GetLength()<6)
        {
                AfxMessageBox("密钥长度>=6");
                return;
        }

        if (m_szKeyin.SpanIncluding("1234567890")==m_szKeyin)
        {
                int x = atoi((LPSTR)(LPCTSTR)m_szKeyin);
                CString s;
                s.Format("%d", x);
                if (s==m_szKeyin)
                {
                        AfxMessageBox("请输入一个非32位整数的值,包含字符,或者不是32位整数的数值");
                        return;
                }
        }

        if (m_szName.GetLength()<6||m_szName.GetLength()>10)
        {
                AfxMessageBox("Name长度>=6且<=10");
                return;
        }
        
        int esi = 0x37B, i, edx;
        for (i=0; i<m_szKeyin.GetLength()-1; ++i)
                esi += (m_szKeyin.GetAt(i+1) % 17 + 1) * m_szKeyin.GetAt(i);

        esi %= 0x7148;
        if (esi>=0)
                edx = 0;
        else
                edx = -1;
        
        esi ^= edx;
        esi -= edx;
        
        m_nKey = esi;

        int sum = 0, j, a, b;
        for (i=0; i<m_szName.GetLength(); ++i)                     //从1取到长度
        {
                for (j=m_szName.GetLength()-1; j>=0; --j)         //从最后1位取到第1位
                {
                        a = m_szName.GetAt(i);
                        b = m_szName.GetAt(j);
                        sum += m_szName.GetAt(i) * m_szName.GetAt(j) * m_nKey;
                }
        }
        
        sum %= 666666;

        edx = sum / 89 + sum % 80;
        while (1)
        {
                if (edx / 89 + edx % 80 + 1 == sum)
                        break;
                else
                {
                        if (sum>=0)
                                ++edx;
                        else
                                --edx;
                }
        }
        
        m_szSN.Format("%d", edx);
        
        UpdateData(FALSE);
        if (edx<=0)
        {
                AfxMessageBox("输入不合法, 要保证SN是大于0的,密钥生成值取6-8位大写字母,或者11-12位数字一般都可以,或者用户名尽量用大写字母和数字!");
                return;
        }
}

免费评分

参与人数 6威望 +1 吾爱币 +25 热心值 +5 收起 理由
Hmily + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
我是东软的学生 + 1 用心讨论,共获提升!
抱薪风雪雾 + 1 + 1 谢谢@Thanks!
solly + 1 + 1 用心讨论,共获提升!
woyucheng + 1 + 1 用心讨论,共获提升!
zhourunfav + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

zhourunfav 发表于 2021-1-10 04:47
谢谢分享,52有你而精彩
krolenspark 发表于 2021-1-10 06:44
biostu 发表于 2021-1-10 11:20
唯爱丶雪 发表于 2021-1-10 13:37
谢谢大佬分享,我最近都在玩这个破解
我在B站撸猫 发表于 2021-1-10 16:00
谢谢分享
Aloneranger 发表于 2021-1-10 16:16
学习了  感谢分享
dipper 发表于 2021-1-10 16:38
谢谢分享
guangzisam 发表于 2021-1-10 18:19
把一些功底,比我强
SuperZc 发表于 2021-1-10 18:25

谢谢分享,不错,学习中。52有你而精彩
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-27 00:13

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表