首页
社区
课程
招聘
[原创]crack的分析和注册机写法
发表于: 2011-4-18 17:31 7598

[原创]crack的分析和注册机写法

2011-4-18 17:31
7598
原软件下载地址:http://crackmes.de/users/yo_mismo/crackme_v1/
注:软件下载原文说加壳了,结果下下来发现没壳。

  分析成功了之后再看这些代码感觉简单了,但是在没分析清楚之前真是累得我头晕眼花。不断地尝试之后总算完成了,大牛就不要来拍我了。
  OD载入很轻松就可以找到关键call。进入后我给予瓜分分为五个步骤:
0、对用户名、密码长度进行判定
1、对用户名前四个字符进行一次异或处理
2、对处理的四个字符进一步进行处理
3、将用户名+处理的字符(有个转化十进制的过程) == 新用户名
4、拿新用户名与密码比较。
下面进行详细分析:
0、对用户名、密码长度进行判定
strlen()然后比较,很简单就略过了。

1、对用户名前四个字符进行一次异或处理

00401302  |> /8A91 10404000 /mov     dl, byte ptr [ecx+404010]  // 取user [1-4]字符。404010==user;404020==pass
00401308  |. |8A81 13204000 |mov     al, byte ptr [ecx+402013]  // 取0X59  0X6F 0X2D 0X4D进行
0040130E  |. |30D0          |xor     al, dl                     **异或
00401310  |. |8881 30404000 |mov     byte ptr [ecx+404030], al  //将异或的值传递到pass的第[17-20]个字符
00401316  |. |41            |inc     ecx                        //ecx循环四次
00401317  |. |83F9 04       |cmp     ecx, 4
0040131A  |.^\75 E6         \jnz     short 00401302             //403030处为目前处理过后的字符串。

2、对处理的四个字符进一步进行处理
0040131C  |.  68 30404000   push    00404030                         ; /s = ""
00401321  |.  E8 CA040000   call    <jmp.&msvcrt.strlen>             ; \strlen
00401326  |.  89C2          mov     edx, eax                         ;  //将4030处字符串长度放入edx
00401328  |.  31C0          xor     eax, eax                         ;  //eax清零
0040132A  |.  31C9          xor     ecx, ecx                         ;  //ecx清零

0040132C  |> /39D1          /cmp     ecx, edx                         //循环四次
0040132E  |. |74 0A         |je      short 0040133A          
00401330  |. |66:0381 30404>|add     ax, word ptr [ecx+404030]        //[40301][40300] + [40302][40301] + [40303][40302]+[xx][0x40303]        
00401337  |. |41            |inc     ecx
00401338  |.^\EB F2         \jmp     short 0040132C                  //结果就是eax中保存了处理后的值。

0040133A  |> \69C0 66060000 imul    eax, eax, 666                          //eax *666 -》eax
00401340  |.  C1E8 02       shr     eax, 2                                 //EAX/4
00401343  |.  C1C0 0E       rol     eax, 0E                               //循环左移14位
00401346  |.  C1C8 14       ror     eax, 14                               //循环右移20位  ==> 此两步最终运算结果为将eax进行循环右移6位。

00401349  |.  6BC0 02       imul    eax, eax, 2                           //eax *2 -》eax 【溢出部分舍弃】
0040134C  |.  F7D0          not     eax                                   //取反      
0040134E  |.  05 99090000   add     eax, 999                              //eax+0x999h

【此处wsprintf的作用是将上文处理的eax的值(如今存放在404040中)转化为无符号十进制数,放入404050处】
00401353  |.  A3 40404000   mov     dword ptr [404040], eax          ; |//将处理过后的eax值放到404040处
00401358  |.  FF35 40404000 push    dword ptr [404040]               ; |/<%u> = 97F7B3D2 (2549593042.)
0040135E  |.  68 22204000   push    00402022                         ; ||Format = "%u"
00401363  |.  68 50404000   push    00404050                         ; ||s = crack_No.00404050
00401368  |.  E8 F3040000   call    <jmp.&USER32.wsprintfA>          ; |\wsprintfA

3、将用户名+处理的字符(有个转化十进制的过程) == 新用户名
【此处strcat是将输入的用户名+转化后的十进制字符串相连接。】
0040136D  |.  68 50404000   push    00404050                         ; |/src = "2549593042"
00401372  |.  68 10404000   push    00404010                         ; ||dest = "AAAAAAAA"
00401377  |.  E8 84040000   call    <jmp.&msvcrt.strcat>             ; |\strcat

4、拿新用户名与密码比较。
0040137C  |.  68 10404000   push    00404010                         ; |s1 = "AAAAAAAA"
00401381  |.  C74424 04 204>mov     dword ptr [esp+4], 00404020      ; |ASCII "BBBBBBBB"
00401389  |.  E8 52040000   call    <jmp.&msvcrt.strcmp>             ; \strcmp
0040138E  |.  83F8 00       cmp     eax, 0
00401391      74 02         je      short 00401395                   ;  //成功!

  故可以推算出一组序列号:
AAAAA
AAAAA2549593042
  注册机算法如下:

/*crack_1
*name cr_1_noname
*author houlen
*date 2011-4-18
*/
#include <stdio.h>
#define MAX 100
int main()
{
  char user[MAX], str[MAX];
  int i=0, cat[4], sum =0;

  printf("User:");
  scanf("%s",user);
  if(strlen(user) <4 )
  {
    printf("the len of user is too low\n");
    return 0;
  }
    cat[0] = (int)user[0]^0x59;
  cat[1] = (int)user[1]^0x6f;
  cat[2] = (int)user[2]^0x2d;
  cat[3] = (int)user[3]^0x4d;
  
  for(i=0; i<3; i++)
  {
    sum+= cat[i+1]*16*16+cat[i];
    
  }
  sum+= cat[3];
  sum*= 0x666;
  sum=sum>>2;
  _asm
  {
    push eax;
    mov eax,sum;
    ror eax,6;
    imul eax,eax,2
    not eax;
    add eax,0x999;
      mov sum,eax;
    pop eax;

  }
  
  sprintf(str, "%u", sum);
  strcat(user, str);
  printf("Serial: %s\n", user);
  getchar();
  return 0;
}


在分析这个crackme的过程中遇到的几个问题,可能新手都会有这类疑问,1、ror、rol是循环右移,左移。2、wsprintf函数在本软件作用是将数字转化为字符串。3、IA-32机的小头问题,别弄错了顺序。4、c语言中的异或操作符"^"移位“>>”.5、嵌入汇编注意保护寄存器

原软件包好像有源码,但是自始至终没看过它的源代码,所以分析起来很辛苦,但是分析出来也很有成就感。。哈哈
~

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 0
支持
分享
最新回复 (8)
雪    币: 967
活跃值: (1138)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
2
#include "stdio.h"
#include <Windows.h>
#include <shlwapi.h>
char User[MAX_PATH];
char Pass[MAX_PATH];
char First[MAX_PATH];
const char cStr[]="Yo-Mismo";
DWORD Sec;
char Thr[MAX_PATH];
BOOL test()
{
        BOOL bResult=FALSE;
        int i=0;
        int ieax=0,iecx=0;
        int ifirstlen=0;
        printf("Usuario:");
        scanf("%s",User);
        if (strlen(User)<4)
        goto Finally;
                printf("Serial:");
                scanf("%s",Pass);
                if (strlen(Pass)<4)
                goto Finally;
                do
                {
                        First[i]=User[i] ^cStr[i];
                        i++;
                } while (i!=4);
    ifirstlen=strlen(First);
        for (i=0;i<ifirstlen;i++)
        {
                ieax+=*((WORD *)(First+i));
        }
        __asm
        {
                push eax
                        push edx
                        mov eax,ieax
                imul    eax, 666h
                        shr     eax, 2
                        rol     eax, 0Eh
                        ror     eax, 14h
                        imul    eax, 2
                        not     eax
                        add     eax, 999h
                        mov ieax,eax
                        pop edx
   pop eax
        }
        Sec=ieax;
        wsprintfA(Thr,"%u",Sec);
        StrCatA(User,Thr);
        if (StrCmpA(User,Pass))
        goto Finally;
printf("--------------------\nFelicidades, crack");

Finally:
        return bResult;
}
void main()
{
        test();

}
2011-4-18 19:28
0
雪    币: 967
活跃值: (1138)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
3
汗 我真无聊啊
2011-4-18 19:29
0
雪    币: 1149
活跃值: (888)
能力值: ( LV13,RANK:260 )
在线值:
发帖
回帖
粉丝
4
整副帖子,你一个人发言,看的出你灰常无聊......
2011-4-18 19:39
0
雪    币: 72
活跃值: (60)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
5
[QUOTE=elianmeng;949326]#include "stdio.h"
#include <Windows.h>
#include <shlwapi.h>
char User[MAX_PATH];
char Pass[MAX_PATH];
char First[MAX_PATH];
const char cStr[]="...[/QUOTE]

怎么了?我看着代码也能写出来。可是你确定你能够逆向出来吗?
2011-4-18 22:43
0
雪    币: 967
活跃值: (1138)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
6
我写的就是源码
我不写破文,我只写别人的源码

个人认为破解的最高境界就是:拿出别人的源码
没必要写什么过程
比较改什么跳转之类
这样在工作中才有意义
2011-4-19 07:29
0
雪    币: 967
活跃值: (1138)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
7
我还是犯了老毛病,容易激动汗
都是我的错
2011-4-19 07:50
0
雪    币: 21
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
我是菜鸟,如果能写出来肯定很高兴,我相信很多小菜看此文也是有借鉴的地方的。

我觉得做人的最高境界是:利人利己

自己能分享些东西就多分享,互相帮助。多鼓励,尽量少的去鄙视或者打击别人。
2011-4-19 09:49
0
雪    币: 278
活跃值: (709)
能力值: ( LV15,RANK:520 )
在线值:
发帖
回帖
粉丝
9
都是非一般的人,膜拜
2011-4-23 09:47
0
游客
登录 | 注册 方可回帖
返回
//