首页
社区
课程
招聘
[原创]SMC的CrackMe,设计思路+源码(应该不能爆破吧)
发表于: 2009-8-4 22:26 12357

[原创]SMC的CrackMe,设计思路+源码(应该不能爆破吧)

2009-8-4 22:26
12357

前几天看了 zenghw 兄的 “SMC与算法结合的快速运用 VC++” 后,也有个类似的想法,于是这两天折腾了一个SMC的CM。
其中验证和弹出注册提示部分就是用SMC加密过的,只有输入正确的序列号才能还原成可执行的代码

主要是想验证下这样的SMC加密是否有效,所以欢迎爆破。加密方式比较随意,不过配合SMC,想来比较猥琐

// 验证输入 [COLOR="red"]00469088
procedure TForm1.KenGen(Name, Serial: String);
label
  Err_Input;
var
  S1, S2: Integer;
begin
  if (Length(Name) < 4) then goto Err_Input;          // 所以说用户名是摆设
  if Length(Serial) <> 16 then goto Err_Input;

  // 序列号16个字节,只能输入0-9,A-F (16进制数值),分成前后两部分存入S1, S2
  // 如果 TryStrToInt() 转换失败(说明输入的序列号不是以上字符),跳向错误提示
  if Not TryStrToInt('$'+Copy(Serial, 1, 8), S1) then goto Err_Input;
  if Not TryStrToInt('$'+Copy(Serial, 9, 8), S2) then goto Err_Input;

  { 初始化 }
  // 这里倒是我最头疼的事情,到底怎么给参数赋初值,混沌公式
  //   P(n+1) = A*P(n) * sin( 1-u*P(n) )
  // 不用50轮,A*P(n) 就溢出了(中间存储用的double型),所以这里要缩小 P0 和 A 的值
  Chaos_P0 := S1 shr 8;
  // 反正是测试,限制A在0-255之间算了
  // 注意:这样会使函数振幅过小,想稳妥点就要看大数计算方面的东西了
  Chaos_A := ((S1 shl 3) or (S2 and $07)) and $FF;
  Chaos_u := S2*0.23;

  try
    // 加密开始位置
    {$I ChaosEncryptBegin.pas}
    // 这个文件在编译时只是一个桩,处理后替换成调用解密函数的15字节
004691E7   .  68 FA000000   PUSH 0FA                                 ; /dwLength = 000000FA     (待解密块长度)
004691EC   .  68 F6914600   PUSH SMC_Crac.004691F6                   ; |dwStart = 004691F6      (起始地址)
004691F1   .  E8 0AFEFFFF   CALL SMC_Crac.00469000                   ; \call SMC_DecryptBlock() (解密函数,这个后面再说)

    // [COLOR="Blue"]这里没有用循环效验,而是利用了SEH的特性
    // 解密的结果只有两种 可以执行 or 发生异常
    // 这样就避免了用循环效验,没有效验值能够反推
    
    // 再次验证一下P0或者别的值,看看是否正确解出
    // ChainDataWithData(Chaos_P0, Addr) = $3EC12C17
    if (Chaos_P0 = $3EC12C17) then
    begin
      // OK,注册提示
      Timer_Tips.Enabled := False;
      Label_Info.Caption := Format('[已注册] Name: %s, Serial:%s', ['TEST', Serial]);
      asm
        pushad
        // Delphi的常量字符串处理起来比较麻烦,提示信息硬编码了
        db $EB, 70
        // -----------------
        {+ 7} db '恭喜你',0                                                // 07
        {+18} db '注册成功!',0                                            // 11
        {+70} db '如果是爆破的,请务必将爆破方法告诉我。',13,10,'木桩(2009)',0,$90 // 52
        call @@eip_caller
      @@eip_caller:
        pop ebx
        push 0
        sub ebx, 5+70         // Title
        push ebx
        add ebx, 7            // Text
        push ebx
        push 0
        call MessageBoxA
        push 0
        push ebx
        add ebx, 11
        push ebx
        push 0
        call MessageBoxA
        popad
      end;
      Panel1.Visible := False;
      Form1.Height := Form1.Height - Panel1.Height;
    end;
    // 加密段结束标记
    {$I ChaosEncryptEnd.pas}
  except
    // [COLOR="blue"]如果里面代码执行不正常,说明解密不正确
    // [COLOR="blue"]会因为SEH跳到这里,给出个消息提示下
    MessageBox(Handle, 'STOP!注册码错误。', '注册失败', MB_OK);
  end;
  // 插桩:还原之前解密的内容,不然注册码输错一次,就没法还原了
  [COLOR="Purple"]// 附带的测试程序没有Patch掉这个桩,可以试试看
  {$I ChaosEncryptEnd.pas}
  Exit;

Err_Input:
  MessageBox(Handle, '用户名或注册码错误!', '注册失败 :(', MB_OK);
end;
var
  Chaos_P0: DWORD;            // [全局变量]存放P0
  Chaos_A, Chaos_u: Double;   // [全局变量]混沌公式的参数A, u

// 将数据A与B相关
procedure ChainDataWithData(var A: DWORD; B: DWORD; cMode: Integer = 1); stdcall;
var
  tmpD: DWORD;
begin
  case cMode of
    0: // 逆向还原
    begin
      // 循环右移3
      asm
        push eax
        mov eax, B
        ror eax, 11
        mov tmpD, eax
        pop eax
      end;
      A := A - tmpD;
    end;
    1: // 正向相关
    begin
      asm
        push eax
        mov eax, B
        ror eax, 11
        mov tmpD, eax
        pop eax
      end;
      A := A + tmpD;
    end;
  end;
end;

// 由 P(n) 计算 P(n+1)
function ChaoStreamGener(Pn: DWORD): DWORD;
var
  tmpExt: Double;
begin
  // 最简单的混沌公式:P(n) = A*f(P(n-1))
  // [COLOR="Red"]P(n+1) = A*P(n) * sin( 1-u*P(n) )
  tmpExt := Chaos_A*Pn * Sin( 1-Chaos_u*Pn );

  // 没办法,如果用double且不限制范围的话,不要几轮就溢出了
  // 取整
  Result := Abs(Round(tmpExt)) mod $FFFFFFFF;
end;

// Self Modifying Code Decrypt
procedure SMC_DecryptBlock(dwStart, dwLength: DWORD); stdcall;
label
  Magic_End;
var
  dwTLen: DWORD;
  dbRnd: BYTE;
  dwOldProtect: DWORD;
begin
  if (Chaos_P0 = Chaos_Magic) then goto Magic_End;

  dwTLen := dwLength div 4;     // 对4取整,计算异或次数
  // 计算地址与Key的相关数,放入Chaos_P0
  ChainDataWithData(Chaos_P0, dwStart, 1);

  // 开写保护                         // PAGE_EXECUTE_READWRITE
  asm
    pushad
    dw $310F        // rdtsc - EAX=LO, EDX=HI
    shr eax, 28
    mov dbRnd, al   // dbRnd = (LO shr 28)
    popad
  end;
  // 加个随机数 dbRnd,让IDA看不到地址信息
  VirtualProtect(Pointer(dwStart+dbRnd), 1, PAGE_READWRITE, @dwOldProtect);

  asm
    pushad
    mov edx, dwStart
    mov ecx, dwTLen
    mov eax, Chaos_P0            // eax = 初值

  @@Encrypt_Loop:
    push edx
    push ecx
    push ebx
    // 生成P(n)
    call ChaoStreamGener        // fastcall - IN eax, OUT eax
    pop ebx
    pop ecx
    pop edx

    xor dword ptr [edx], eax
    add edx, 4                  // 指向下一个DWORD
    loop @@Encrypt_Loop         // 继续

    popad
  end;
  // 如果不是4的整数倍
  // if (dwTLen*4 <> dwLength) then
  // 不管了 :P
  // 反正就1-3字节

  // 关写保护
  VirtualProtect(Pointer(dwStart+dbRnd), 1, dwOldProtect, @dwOldProtect);

Magic_End:
end;

[培训]科锐逆向工程师培训第53期2025年7月8日开班!

上传的附件:
收藏
免费 7
支持
分享
最新回复 (14)
雪    币: 7357
活跃值: (3878)
能力值: (RANK:1130 )
在线值:
发帖
回帖
粉丝
2
恩,你可以参加比赛了
2009-8-4 23:26
0
雪    币: 7357
活跃值: (3878)
能力值: (RANK:1130 )
在线值:
发帖
回帖
粉丝
3
忘记传附件了,不好意思
我不懂爆破
上传的附件:
2009-8-4 23:33
0
雪    币: 2067
活跃值: (82)
能力值: ( LV9,RANK:180 )
在线值:
发帖
回帖
粉丝
4
太无敌了..
2009-8-4 23:55
0
雪    币: 418
活跃值: (63)
能力值: ( LV12,RANK:260 )
在线值:
发帖
回帖
粉丝
5
嘻嘻。。我也觉得SMC很好用
2009-8-5 00:12
0
雪    币: 232
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
6
LZ这是猜密码...
2009-8-5 09:23
0
雪    币: 1596
活跃值: (35)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
7
我个人认为,以下是不可逆的
00469056  |> /52            /push    edx
00469057  |. |51            |push    ecx
00469058  |. |53            |push    ebx
00469059  |. |E8 76FEFFFF   |call    00468ED4
0046905E  |. |5B            |pop     ebx
0046905F  |. |59            |pop     ecx
00469060  |. |5A            |pop     edx
00469061  |. |3102          |xor     dword ptr [edx], eax
00469063  |. |83C2 04       |add     edx, 4
00469066  |.^\E2 EE         \loopd   short 00469056


2009-8-5 10:30
0
雪    币: 418
活跃值: (63)
能力值: ( LV12,RANK:260 )
在线值:
发帖
回帖
粉丝
8
附件是我前几天发的SMC DEMO里面的程序,请海风月影兄尝试破解一下!
源程序和制作流程网址(SDK):
http://bbs.pediy.com/showthread.php?t=94701
上传的附件:
2009-8-5 16:15
0
雪    币: 7357
活跃值: (3878)
能力值: (RANK:1130 )
在线值:
发帖
回帖
粉丝
9
123456
上传的附件:
2009-8-5 17:03
0
雪    币: 418
活跃值: (63)
能力值: ( LV12,RANK:260 )
在线值:
发帖
回帖
粉丝
10
压缩文件的密码是??
2009-8-5 17:10
0
雪    币: 296
活跃值: (89)
能力值: ( LV15,RANK:340 )
在线值:
发帖
回帖
粉丝
11
海风大侠说笑了 我接触这方面很少,头一次写CM,可能很多地方不符合规则。
本来只是想放出来让大牛们看看这样加密是否不妥,所以更想知道SMC加密后有没有可以绕过的地方,比如通过猜测被加密代码的头几个字节来反推流密钥发生函数的参数值。

我的设想是用SMC来保护部分功能,让不知道密码的人无法使用它们(这部分代码只有输入正确密码才能还原出来,所以应该很“安全”)。不知道这个思路是否真的和看上去那样不可逆?



应该把。那个call就是流密钥的发生函数了,而且这里用了 P(n) = A*f(P(n-1)) 类型的混沌密码公式,生成的密钥流在循环一定次数后是不可预测的。
这个代码也没什么好藏着腋着的,干脆整理整理发出来算了。
2009-8-5 20:06
0
雪    币: 7357
活跃值: (3878)
能力值: (RANK:1130 )
在线值:
发帖
回帖
粉丝
12
密码: 爆破
2009-8-5 21:42
0
雪    币: 296
活跃值: (89)
能力值: ( LV15,RANK:340 )
在线值:
发帖
回帖
粉丝
13
[QUOTE=海风月影;666836]密码: 爆破[/QUOTE]

原来如此,受教了
2009-8-5 21:55
0
雪    币: 264
活跃值: (11)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
14
对于你一直提到的这个是算法很有兴趣..
2009-8-5 23:14
0
雪    币: 220
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
呵呵 不错 不错
2011-3-2 14:28
0
游客
登录 | 注册 方可回帖
返回