首页
社区
课程
招聘
3
[原创]riijj crackme 1 算法分析
发表于: 2014-8-20 23:26 7233

[原创]riijj crackme 1 算法分析

2014-8-20 23:26
7233

【破解作者】 Night
【作者主页】 http://www.freecracker.com
【使用工具】 OD
【破解平台】 Win7
【软件名称】 ncrackme.exe
------------------------------------------------------------------------------------------------------------

1.使用OD附加程序,使用 bp GetDlgItemTextA  下断点 程序来到下面的地址处。

00401230  /$  8B0D BC564000 mov ecx,dword ptr ds:[0x4056BC]
00401236  |.  83EC 30              sub esp,0x30
00401239  |.  8D4424 00          lea eax,dword ptr ss:[esp]
0040123D  |.  53                       push ebx
0040123E  |.  56                       push esi
0040123F  |.  8B35 94404000  mov esi,dword ptr ds:[<&USER32.GetDlgIte>;  user32.GetDlgItemTextA
00401245  |.  6A 10                  push 0x10                                ; /Count = 10 (16.)
00401247  |.  50                       push eax                                 ; |Buffer
00401248  |.  68 E8030000      push 0x3E8                               ; |ControlID = 3E8 (1000.)
0040124D  |.  51                       push ecx                                 ; |hWnd => 000B0674 (class='#32770',parent=000B0638)
0040124E  |.  33DB                   xor ebx,ebx                              ; |
00401250  |.  FFD6                   call esi                                 ; \GetDlgItemTextA
00401252  |.  83F8 03              cmp eax,0x3                              ;  用户名不能少于三位
00401255  |.  73 0B                  jnb Xncrackme.00401262
00401257  |.  5E                       pop esi
00401258  |.  B8 01000000      mov eax,0x1
0040125D  |.  5B                       pop ebx
0040125E  |.  83C4 30              add esp,0x30
00401261  |.  C3                       retn

2.由上面代码可以判断出程序读取用户所输入的用户名 并且判断用户名不能少于三位,当用户输入的数据满足条件的情况下程序会跳到下面的代码处

00401262  |> \A1 BC564000   mov eax,dword ptr ds:[0x4056BC]          ;  
00401267  |.  8D5424 28         lea edx,dword ptr ss:[esp+0x28]             ;  
0040126B  |.  6A 10                 push 0x10
0040126D  |.  52                      push edx
0040126E  |.  68 E9030000     push 0x3E9
00401273  |.  50                      push eax
00401274  |.  FFD6                  call esi                                 ;  获取Key值
00401276  |.  0FBE4424 08     movsx eax,byte ptr ss:[esp+0x8]          ;  获取用户名第一位
0040127B  |.  0FBE4C24 09     movsx ecx,byte ptr ss:[esp+0x9]          ;  获取用户名第二位
00401280  |.  99                      cdq                                      ;  把edx扩展为eax的高位
00401281  |.  F7F9                   idiv ecx                                 ;  用户名的第一位与用户名的第二位相除 商存放在eax中 ,余数存放在edx中
00401283  |.  8BCA                  mov ecx,edx                              ;  ecx中保存的是计算出的余数
00401285  |.  83C8 FF             or eax,0xFFFFFFFF                        ;  用商 与 0xFFFFFFFF 取或运算 结果存放到eax中
00401288  |.  0FBE5424 0A     movsx edx,byte ptr ss:[esp+0xA]          ;  保存用户名的第三位
0040128D  |.  0FAFCA              imul ecx,edx                             ;  用余数与用户名的第三位做乘法运算 结果保存到ecx中
00401290  |.  41                      inc ecx                                  ;  ecx = ecx + 1
00401291  |.  33D2                  xor edx,edx                              ;  清空edx
00401293  |.  F7F1                  div ecx                                  ;  eax / ecx   商存放到 eax  中    余数存放到edx中
00401295  |.  50                     push eax                                 ;  把上次计算出的商压入栈
00401296  |.  E8 A5000000    call ncrackme.00401340                   ;  保存eax中的结果到0x4050AC
0040129B  |.  83C4 04            add esp,0x4
0040129E  |.  33F6                  xor esi,esi
004012A0  |>  E8 A5000000   /call ncrackme.0040134A
 {
0040134A  /$  A1 AC504000   mov eax,dword ptr ds:[0x4050AC]          ;  获取0x4050AC中数据存放到eax中
0040134F  |.  69C0 FD430300 imul eax,eax,0x343FD                     ;  eax = eax * 0x343FD
00401355  |.  05 C39E2600    add eax,0x269EC3                         ;  eax = eax + 0x269EC3
0040135A  |.  A3 AC504000    mov dword ptr ds:[0x4050AC],eax          ;  保存eax中的数据到 0x4050AC中
0040135F  |.  C1F8 10             sar eax,0x10                             ;  eax = eax >> 0x10
00401362  |.  25 FF7F0000     and eax,0x7FFF                           ;  eax = eax & 0x7FFF
00401367  \.  C3            retn

 }
004012A5  |.  99                    |cdq                                     ;  把edx扩展为eax的高位
004012A6  |.  B9 1A000000   |mov ecx,0x1A                            ;  ecx = 0x1A
004012AB  |.  F7F9                 |idiv ecx                                ;  eax / ecx  商保存到eax 中  余数保存到edx中
004012AD  |.  80C2 41           |add dl,0x41                             ;  把余数的低16位与0x41 求和
004012B0  |.  885434 18        |mov byte ptr ss:[esp+esi+0x18],dl       ;  保存上次计算的结果
004012B4  |.  46                     |inc esi
004012B5  |.  83FE 0F            |cmp esi,0xF
004012B8  |.^ 72 E6              \jb Xncrackme.004012A0
004012BA  |.  57                    push edi
004012BB  |.  8D7C24 0C      lea edi,dword ptr ss:[esp+0xC]           ;  edi 指向 用户名
004012BF  |.  83C9 FF           or ecx,0xFFFFFFFF                        ;  ecx = ecx | 0xFFFFFFFF
004012C2  |.  33C0               xor eax,eax                              ;  eax = 0
004012C4  |.  33F6               xor esi,esi                              ;  esi = 0
004012C6  |.  F2:AE              repne scas byte ptr es:[edi]             ;  和下面两条汇编指令联合使用 求用户名长度  保存到 ecx 中
004012C8  |.  F7D1               not ecx
004012CA  |.  49                   dec ecx
004012CB  |.  74 59              je Xncrackme.00401326                    ;  用户名长度不能为 0
004012CD  |>  8A4434 0C     /mov al,byte ptr ss:[esp+esi+0xC]        ;  获取用户名第一位保存到al 中
004012D1  |.  C0F8 05          |sar al,0x5                              ;  al = al >> 0x5
004012D4  |.  0FBEC0           |movsx eax,al                            ;  al 保存到 eax  中
004012D7  |.  8D1480           |lea edx,dword ptr ds:[eax+eax*4]        ;  edx = eax + eax * 4
004012DA  |.  8D04D0          |lea eax,dword ptr ds:[eax+edx*8]        ;  eax = eax + edx * 8
004012DD  |.  8D0440          |lea eax,dword ptr ds:[eax+eax*2]        ;  eax = eax + eax * 2
004012E0  |.  85C0               |test eax,eax                            ;  判断eax 是否为 0
004012E2  |.  7E 0A              |jle Xncrackme.004012EE
004012E4  |.  8BF8               |mov edi,eax                             ;  edi = eax  做为循环次数
004012E6  |>  E8 5F000000   |/call ncrackme.0040134A
004012EB  |.  4F                     ||dec edi
004012EC  |.^ 75 F8              |\jnz Xncrackme.004012E6
004012EE  |>  E8 57000000  |call ncrackme.0040134A
004012F3  |.  99                     |cdq
004012F4  |.  B9 1A000000    |mov ecx,0x1A                            ;  ecx = 0x1A
004012F9  |.  8D7C24 0C       |lea edi,dword ptr ss:[esp+0xC]              ;  edi 指向用户名
004012FD  |.  F7F9                 |idiv ecx                                ;  eax / ecx   商存放到 eax  中    余数存放到edx中
004012FF  |.  0FBE4C34 2C    |movsx ecx,byte ptr ss:[esp+esi+0x2C]        ;  获取key值的第一位
00401304  |.  80C2 41            |add dl,0x41                             ;    dl = dl + 0x41   dl 是余数
00401307  |.  0FBEC2             |movsx eax,dl                            ;  把计算后的dl 存放到 eax中
0040130A  |.  2BC1                 |sub eax,ecx                             ;  eax = eax - ecx    eax是计算后的dl  ecx 是key值的第一位
0040130C  |.  885434 1C        |mov byte ptr ss:[esp+esi+0x1C],dl            ;  保存dl的值
00401310  |.  99                      |cdq
00401311  |.  33C2                  |xor eax,edx                             ;  eax = eax ^ edx
00401313  |.  83C9 FF             |or ecx,0xFFFFFFFF                       ;  ecx = ecx | 0xFFFFFFFF   ecx是用户名的第一位
00401316  |.  2BC2                  |sub eax,edx                             ;  eax = eax - edx
00401318  |.  03D8                  |add ebx,eax                             ;  ebx = ebx + eax
0040131A  |.  33C0                  |xor eax,eax                             ;  eax = 0
0040131C  |.  46                      |inc esi                                  ;  esi = esi + 1
0040131D  |.  F2:AE                 |repne scas byte ptr es:[edi]                 ;  求用户名长度
0040131F  |.  F7D1                  |not ecx
00401321  |.  49                      |dec ecx
00401322  |.  3BF1                  |cmp esi,ecx
00401324  |.^ 72 A7               \jb Xncrackme.004012CD
00401326  |>  5F                     pop edi                                  ;  0012FB18
00401327  |.  8BC3                 mov eax,ebx
00401329  |.  5E                     pop esi
0040132A  |.  5B                     pop ebx
0040132B  |.  83C4 30           add esp,0x30
0040132E  \.  C3                    retn

经过分析得知这一段应该就是程序的算法部分了。具体分析过程都写到了注释中。注释中涉及到的循环代码都是第一轮循环的的内容。

3.注册机实现如下:
// CrackMe1.cpp : 定义控制台应用程序的入口点。
//
/***
*    ncrackme.exe 程序注册机  
*   完成时间: 2014年8月20日  17:30   
*    完成人  : Night
*/

#include "stdafx.h"
#include "string.h"

int fun0040134A(unsigned int *result)
{
  unsigned int value  = 0;
  *result = (*result) * 0x343FD;
  *result = (*result) + 0x269EC3;
  value   = * result ;
  value   = value >> 0x10;
  value   = value & 0x7FFF;
  return  value;
}
int _tmain(int argc, _TCHAR* argv[])
{
  //存放用户名
  char userName [100]       = { 0 };
  //获取Key值
  char keyValue [100]         = { 0 };
  //商 
  unsigned int quotient       = 0 ;
  //余数
  unsigned int mod              = 0 ;
  //临时存放计算变量
  unsigned int value           = 0 ;
  unsigned int value1          = 0 ;
  unsigned int result            = 0 ;
  unsigned int retValue        = 0 ;
  //存放结果 
  int  decodeValue[0xF]       = {0} ;
  //循环变量
  int i = 0;
  //存放用户名长度
  int userNameLen      = 0;
  //输入用户名
  printf("请输入用户名:");
  gets_s(userName);
  printf("\n请输入Key值:");
  //输入Key值
  gets_s(keyValue);

   if(strlen(userName)< 3)
  {
     printf("用户名不能少于三位!");
    return 0;
         }
   quotient = userName[0] / userName[1];
   mod      = userName[0] % userName[1];
     value    = quotient | 0xFFFFFFFF;
   value1   = mod * userName[2];
   value1   = value1 + 1 ;

   quotient = value / value1 ;
   mod         = value % value1 ;

   result     = quotient ;

   do
   {
      retValue  = fun0040134A(&result);
      value       = 0x1A;
      quotient  = retValue / value ;
      mod         = retValue % value ;
      mod         = mod + 0x41;
      decodeValue[i] = mod; 
       i++;
    } while (i<0xF);
  
   userNameLen = strlen(userName);
   if (userNameLen == 0)
   {
    printf("用户名长度不能为0!");
    return 0;
   }
  i = 0;
   do
   {
     value  = userName[i] >> 0x5 ;
     value1 = value + value  * 4; 
     value  = value + value1 * 8;
     value  = value + value  * 2;

    if (value == 0)
     {
       printf("计算的数据不能为0 !");
       return 0;
     }
     do
     {
            retValue = fun0040134A(&result);
            value -- ;
    } while (value);
    
     retValue = fun0040134A(&result);
     value      = 0x1A;
     quotient = retValue / value;
     mod       = retValue % value;

     value     = keyValue[i];
     value1   = mod+0x41;

    decodeValue[i] = value1;

    value1    = value1 ^ 0;
     i++;
  } while (i<strlen(userName));
  
  for (int i = 0; i < 0xF; i++)
  {
    printf("%X\t",decodeValue[i]);
    if((i+1)%8 == 0 )
     {
       printf("\n");
     }
  }
   printf("\n注册码为:\n");
  for (int i = 0; i < 0xF; i++)
   {
    printf("%c",decodeValue[i]);
   }
   printf("\n");
   return 0;
}
PS:编译环境是VS2010  新手练习之作,有哪里不正确请大神指教。


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 3
支持
分享
赞赏记录
参与人
雪币
留言
时间
飘零丶
为你点赞~
2024-5-31 03:24
shinratensei
为你点赞~
2024-5-31 03:08
PLEBFE
为你点赞~
2023-3-3 04:29
最新回复 (8)
雪    币: 13516
活跃值: (3801)
能力值: (RANK:520 )
在线值:
发帖
回帖
粉丝
2
比较认真详细 适合初学者参考学习

加油,这里是CRACK 进阶的第一梯
2014-8-20 23:46
0
雪    币: 3411
活跃值: (2132)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
传说中的精华贴征兆。
2014-8-21 00:01
0
雪    币: 645
活跃值: (45)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
这个CM很亲切啊 呵呵 riijj的CM系列都不错
2014-8-21 21:43
0
雪    币: 340
活跃值: (71)
能力值: ( LV9,RANK:140 )
在线值:
发帖
回帖
粉丝
5
谢谢 各位大神,我会努力的。
2014-8-21 22:50
0
雪    币: 110
活跃值: (373)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
没有crackme.exe程序下载啊
2014-8-22 07:48
0
雪    币: 19
活跃值: (74)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
你好,哥们,看到你分析的crack me,我想问个问题,你win32汇编学了没?应该学了吧,要不你怎么在OD中分析呢?请问你看的谁的书?能否详细说一下,我目前只看完了王爽的书,不怎么会分析,求哥们指点一二。谢谢了。
2014-8-22 09:32
0
雪    币: 6
活跃值: (60)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
8
排版都乱了...
另外上面的那个函数是个随机函数rand()

1
2
3
4
5
int __cdecl rand()
{
  dword_4050AC = 0x343FD * dword_4050AC + 0x269EC3;
  return (dword_4050AC >> 16) & 0x7FFF;
}
2014-8-22 22:18
0
雪    币: 195
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
我也试试
2014-8-30 17:39
0
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册