吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 8024|回复: 23
收起左侧

[CrackMe] 吾爱破解2012CM大赛破文-LittleFater

[复制链接]
willJ 发表于 2012-5-8 22:51
CM是什么?Crackme是什么?这是什么东西?楼主发的什么?
他们都是一些公开给别人尝试破解的小程序,制作 Crackme 的人可能是程序员,想测试一下自己的软件保护技术,也可能是一位 Cracker,想挑战一下其它 Cracker 的破解实力,也可能是一些正在学习破解的人,自己编一些小程序给自己破解,KeyGenMe是要求别人做出它的 keygen (序号产生器), ReverseMe 要求别人把它的算法做出逆向分析, UnpackMe 是要求别人把它成功脱壳,本版块禁止回复非技术无关水贴。

本帖最后由 willJ 于 2012-5-8 22:57 编辑

【文章标题】: 吾爱破解2012CM大赛破文-LittleFater
【文章作者】:willJ
【难度】:      
       大家都知道这个是基于驱动来验证的。那就直接开始分析吧。这个程序是不能爆破的,因为它的成功字符串是被加密了的,所以理论上只能输入正确的解密因子才能弹出正确来。
一:应用层:
       OD载入,直接下段bp CreateFileA,因为要释放驱动,这个目的是为了抓出驱动来。F9运行起来,输入willJ,回车,断了下来:
7C801A28 >  8BFF            mov edi,edi
7C801A2A    55              push ebp
7C801A2B    8BEC            mov ebp,esp
7C801A2D    FF75 08         push dword ptr ss:[ebp+0x8]
7C801A30    E8 CFC60000     call kernel32.7C80E104
7C801A35    85C0            test eax,eax
7C801A37    74 1E           je Xkernel32.7C801A57
7C801A39    FF75 20         push dword ptr ss:[ebp+0x20]
7C801A3C    FF75 1C         push dword ptr ss:[ebp+0x1C]
7C801A3F    FF75 18         push dword ptr ss:[ebp+0x18]
7C801A42    FF75 14         push dword ptr ss:[ebp+0x14]
7C801A45    FF75 10         push dword ptr ss:[ebp+0x10]
7C801A48    FF75 0C         push dword ptr ss:[ebp+0xC]
7C801A4B    FF70 04         push dword ptr ds:[eax+0x4]
7C801A4E    E8 9DED0000     call kernel32.CreateFileW
7C801A53    5D              pop ebp
7C801A54    C2 1C00         retn 0x1C


Alt + F9执行到返回,走几步就到释放的地方了:
0040279E  |.  51            push ecx                                 ; /ResourceType
0040279F  |.  52            push edx                                 ; |ResourceName
004027A0  |.  6A 00         push 0x0                                 ; |hModule = NULL
004027A2  |.  FF15 38945100 call dword ptr ds:[<&KERNEL32.FindResour>; \FindResourceA
004027A8  |.  8BF8          mov edi,eax
004027AA  |.  57            push edi                                 ; /hResource
004027AB  |.  6A 00         push 0x0                                 ; |hModule = NULL
004027AD  |.  FF15 5C945100 call dword ptr ds:[<&KERNEL32.LoadResour>; \LoadResource
004027B3  |.  57            push edi                                 ; /hResource
004027B4  |.  6A 00         push 0x0                                 ; |hModule = NULL
004027B6  |.  8BD8          mov ebx,eax                              ; |
004027B8  |.  FF15 64945100 call dword ptr ds:[<&KERNEL32.SizeofReso>; \SizeofResource
004027BE  |.  6A 00         push 0x0                                 ; /pOverlapped = NULL
004027C0  |.  8D4D FC       lea ecx,[local.1]                        ; |
004027C3  |.  51            push ecx                                 ; |pBytesWritten
004027C4  |.  50            push eax                                 ; |nBytesToWrite
004027C5  |.  53            push ebx                                 ; |Buffer
004027C6  |.  56            push esi                                 ; |hFile
004027C7  |.  FF15 34945100 call dword ptr ds:[<&KERNEL32.WriteFile>>; \WriteFile
004027CD  |.  56            push esi                                 ; /hObject
004027CE  |.  FF15 48945100 call dword ptr ds:[<&KERNEL32.CloseHandl>; \CloseHandle

运行到4027ce,就可以在C:\windows\system32\drivers得到驱动,名字是CrackMe.sys,得保存下来,因为程序做了删除操作的。
继续往下面走就看见了与驱动交互的API了:
00402638  |.  6A 00         push 0x0                                 ; /pOverlapped = NULL
0040263A  |.  8D95 B0FDFFFF lea edx,[local.148]                      ; |
00402640  |.  52            push edx                                 ; |pBytesReturned
00402641  |.  56            push esi                                 ; |OutBufferSize
00402642  |.  8BF8          mov edi,eax                              ; |
00402644  |.  57            push edi                                 ; |OutBuffer
00402645  |.  56            push esi                                 ; |InBufferSize
00402646  |.  53            push ebx                                 ; |InBuffer
00402647  |.  8B9D ACFDFFFF mov ebx,[local.149]                      ; |
0040264D  |.  68 00202200   push 0x222000                            ; |IoControlCode = 222000
00402652  |.  53            push ebx                                 ; |hDevice
00402653  |.  FF15 40945100 call dword ptr ds:[<&KERNEL32.DeviceIoCo>; \DeviceIoControl


在数据窗口我们跟随下传入的字符串:
本来输入的willJ,变成了vhmkK,说明应用层也做了对输入字符串的加密,通过下段 GetWindowTextA可以得到作者即时的对输入的数据进行了inbufer =  inbufer + i;然后在后面又对字符窜做了inbufer = inbufer ^ (i+1)的操作才输入驱动层的
这里比较简单,有兴趣的朋友可以跟下。
二.驱动层:
驱动层的主要函数:
先进入初始化函数:
signed int __stdcall InitDriver(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
  signed int result; // eax@5
  int v3; // edx@10
  int v4; // edx@10
  UNICODE_STRING SymbolicLinkName; // [sp+0h] [bp-48h]@1
  PVOID v6; // [sp+8h] [bp-40h]@10
  NTSTATUS v7; // [sp+Ch] [bp-3Ch]@4
  UNICODE_STRING DestinationString; // [sp+10h] [bp-38h]@1
  PDEVICE_OBJECT DeviceObject; // [sp+18h] [bp-30h]@1
  int v10; // [sp+1Ch] [bp-2Ch]@1
  int v11; // [sp+20h] [bp-28h]@1
  int v12; // [sp+24h] [bp-24h]@1
  int v13; // [sp+28h] [bp-20h]@1
  int v14; // [sp+2Ch] [bp-1Ch]@1
  int v15; // [sp+30h] [bp-18h]@1
  int v16; // [sp+34h] [bp-14h]@1
  int v17; // [sp+38h] [bp-10h]@1
  int v18; // [sp+3Ch] [bp-Ch]@1
  int v19; // [sp+40h] [bp-8h]@1
  unsigned int i; // [sp+44h] [bp-4h]@1

  DeviceObject = 0;
  v10 = (int)"52Crackme";
  v11 = 122;
  v12 = 5;
  v13 = 62;
  v14 = 22;
  v15 = 41;
  v16 = 30;
  v17 = 88;
  v18 = 31;
  v19 = 13;
  RtlInitUnicodeString(&DestinationString, L"\\Device\\CrackMe0");
  RtlInitUnicodeString(&SymbolicLinkName, L"\\DosDevices\\CrackMe0");
  for ( i = 0; i <= 0x1B; ++i )
    DriverObject->MajorFunction[i] = (PDRIVER_DISPATCH)sub_11250;
  DriverObject->MajorFunction[0] = (PDRIVER_DISPATCH)sub_11220;
  DriverObject->MajorFunction[2] = (PDRIVER_DISPATCH)sub_11220;
  DriverObject->MajorFunction[14] = (PDRIVER_DISPATCH)DishpathCtrol;
  DriverObject->DriverUnload = (PDRIVER_UNLOAD)UnloadDriver;
  v7 = IoCreateDevice(DriverObject, 0x38u, &DestinationString, 0x22u, 0, 0, &DeviceObject);
  if ( v7 >= 0 )
  {
    if ( DeviceObject )
    {
      DeviceObject->Flags |= 4u;
      DeviceObject->AlignmentRequirement = 1;
      v7 = IoCreateSymbolicLink(&SymbolicLinkName, &DestinationString);
      if ( v7 >= 0 )
      {
        DeviceObject->Flags &= 0xFFFFFF7Fu;
        v6 = DeviceObject->DeviceExtension;
        v3 = (int)v6;
        *(_DWORD *)v6 = *(_DWORD *)&DestinationString;
        *(_DWORD *)(v3 + 4) = DestinationString.Buffer;
        v4 = (int)v6;
        *((_DWORD *)v6 + 2) = *(_DWORD *)&SymbolicLinkName;
        *(_DWORD *)(v4 + 12) = SymbolicLinkName.Buffer;
        *((_DWORD *)v6 + 4) = v10;              // V6+4出为52Crackme
        for ( i = 0; i < 9; ++i )
          *((_DWORD *)v6 + i + 5) = *(&v11 + i);// 给V6[i+5]起循环负值,分别为V11[i],因为上面变量依次压栈
        DbgPrint("Driver Successfully Loaded");
        result = 0;
      }
      else
      {
        result = v7;
      }
    }
    else
    {
      result = -1073741591;
    }
  }
  else
  {
    result = v7;
  }
  return result;
}


就是驱动相应的一些初始化操作,不过这里有几个关键的地方:
  v10 =(int)"52Crackme";
  v11 = 122;
  v12 = 5;
  v13 = 62;
  v14 = 22;
  v15 = 41;
  v16 = 30;
  v17 = 88;
  v18 = 31;
  v19 = 13;
这个是在算法里会用到的。
然后就是进入关键的分发函数(关键的所在):
signed int __stdcall DishpathCtrol(PDEVICE_OBJECT a1, int Irp)
{
  char v2; // ST13_1@2
  int v4; // [sp+14h] [bp-38h]@1
  unsigned int i; // [sp+18h] [bp-34h]@6
  PVOID v6; // [sp+1Ch] [bp-30h]@1
  signed int v7; // [sp+20h] [bp-2Ch]@1
  unsigned int v8; // [sp+24h] [bp-28h]@3
  char *v9; // [sp+34h] [bp-18h]@1
  char *v10; // [sp+3Ch] [bp-10h]@3
  int irpStack; // [sp+40h] [bp-Ch]@1
  unsigned int v12; // [sp+44h] [bp-8h]@3
  char *v13; // [sp+48h] [bp-4h]@3

  v7 = 0;
  irpStack = sub_113F0(Irp);                    // PIO_STACK_LOCATION irpStack获取当前IPR设备栈
  v6 = a1->DeviceExtension;                     // 获取设备扩展,在入口函数初始化的
  v9 = (char *)*((_DWORD *)v6 + 4);             // 获取52Crackme
  v4 = *((_DWORD *)v6 + 4);
  do
    v2 = *(_BYTE *)v4++;                        // 计算52CracKme的长度
  while ( v2 );
  v13 = *(char **)(Irp + 12);                   // buffer
  v12 = *(_DWORD *)(irpStack + 8);              // inputBufferLength
  v10 = *(char **)(Irp + 12);                   // buffer
  v8 = *(_DWORD *)(irpStack + 4);               // outBufferLenth
  if ( *(_DWORD *)(irpStack + 12) == 0x222000 ) // ioc 控制码
  {
    if ( v4 - (_DWORD)(v9 + 1) == v12 )         // 判断输入长度
    {
      for ( i = 0; i < v12; ++i )
      {
        if ( v9[i] != (*((_DWORD *)v6 + i + 5) ^ (2 * i + 2) ^ v13[i]) )// 用这个算法推出V13[i]的值
        {                                       // (*((_DWORD *)v6 + i + 5)依次取出V6[i+5]
          v8 = 0;
          break;
        }
        v10[i] = v13[i] + 2 * i;
        v8 = i;
      }
    }
  }
  else
  {
    v7 = -1073741262;
  }
  *(_DWORD *)(Irp + 24) = v7;                   // 返回状态
  *(_DWORD *)(Irp + 28) = v8;                   // inputBufferLength  实际返回长度
  IofCompleteRequest((PIRP)Irp, 0);             // 表示完成
  return v7;
}




然后我用C语言还原下KEY吧:
#include <stdio.h>
#include <string.h>

int main(int argc, char* argv[])
{
        char *key = "52Crackme";
        int Value[9] = {122, 5, 62, 22, 41, 30, 88, 31, 13};
        int Strlen_Key = 0, i, j;
        Strlen_Key = strlen(key);
        char Result[100] = {0};
        
        for ( i = 0; i < Strlen_Key; i++)//驱动层算法
        {
                Result[i] = key[i] ^ Value[i] ^ (2 *(i + 1));

        }
        for ( j = 0; j < Strlen_Key; j++)//应用层算法
        {
                Result[j] = Result[j] ^ (j + 1);
                Result[j] = Result[j] - j;
                printf ("%c", Result[j]);
        }
        printf("\n");
        return 0;
}





本人很菜啊,第一次在贵宝地发帖,很多分析不到位,还请xiaobang,klxnw1,Peace 等各大牛多多指教

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册[Register]

x

免费评分

参与人数 4热心值 +4 收起 理由
KaQqi + 1 已答复!
sunflover + 1 我很赞同!
tk86935367 + 1 膜拜高手,驱动偶们不懂
Peace + 1 膜拜强大帅气猥琐

查看全部评分

本帖被以下淘专辑推荐:

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

linwenlin 发表于 2012-5-8 22:55
我是沙发呀,来学习下
Rookietp 发表于 2012-5-8 22:56
ainddky 发表于 2012-5-8 22:56
厉害啊  现在都应用到 驱动层了  小菜不及  感谢楼主详细分解
statlove 发表于 2012-5-8 22:58
太深奥了 根本不懂~
 楼主| willJ 发表于 2012-5-8 22:58
xiaobang 发表于 2012-5-8 22:56
沙发继续膜拜J牛

我还得多多向bang姐学习{:1_930:}

点评

J大的水平一如既往的彪悍啊。  发表于 2012-5-8 23:57
真心没想到这个CM应用到了驱动外还加解码式,让小菜我情何以堪,你说是吧,师傅  发表于 2012-5-8 23:00
Chief 发表于 2012-5-8 23:04
willJ老师果断威武,涉及到驱动了。
分析的太精彩了。
19nuclear91 发表于 2012-5-8 23:25
膜拜willJ大大
HadgeROL 发表于 2012-5-8 23:31
膜拜J大{:1_931:}
Kavia 发表于 2012-5-8 23:45
J牛,你才把答案放出来。。。。放出来我也看不懂。哈哈
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2024-11-24 22:36

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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