【文章标题】: U盘加密软件的破解
【文章作者】: Thomasyzh
【作者邮箱】: machinesy@gmail.com
【软件名称】: U盘超级加密
【软件大小】: 944 
【下载地址】: 自己搜索下载
【加壳方式】: ASProtect 1.2x - 1.3x
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
  很久没发技术上的一些文章了。因为看了下,很多的学习和建树在pediy上超越我的文章实在太多了,所以一直没有发什么技术
  性的文章。今年没有太多的机会去研究很底层的东西,大多时候是转向应用了。所以更加多的时候是在学习别人如何很方便的很
  高效的完成一个任务或者工作。所以没有什么沉淀,也就不好意思发出来了。也就一直没发。
  前段时间帮一个人做了一个外包。500元破解了一个软件,然后改改界面,再写个注册机。用了几个小时帮他怎了,后来他也没
  继续联系我。引导引导新手吧,就把这个发出做一篇初级破文。
  通常不是很恶心的壳,我现在都是带壳调试。其实和本生调试是没有什么区别的。到内存后,都是解开了的。选择用od,start
  process然后勾取hide od就OK。
  我没有去逆算法,其实去逆算法也不困难。承包方的需求是,制作注册机,然后修改界面。完美的做法是完全修复和脱去壳,完
  全替换点资源和软件界面,然后把注册机写出来。我的做法是,暴力破解掉软件功能部分,然后外挂软件功能部分,动态替换掉
  软件资源。
  非专业脱壳人事,会尽量靠近我这样的做法。做pe修复如果对壳的解密流程不是很熟悉,那么做起来会想很多。
  1以试用版进去后观察程序行为。发现点部分功能,会有MessageBoxW提示 所以bp user32!MessageBoxW,这里我给大家一个温馨提
  示IDA能识别很多静态库函数,而OD不能。你可以选择把内存dump出来,用ida和od对着看,这样更加方便你操作。
  
  点功能:全盘解密 然后Ctrl+F9一路往上。因为会遇到一个模态对话框,你再把那个模态对话框点了,就能来到代码这里。
  
  0046EF19  |.  56            push    esi
  0046EF1A  |.  0F87 C4000000 ja      0046EFE4
  0046EF20  |.  FF2485 EFEF46>jmp     dword ptr [eax*4+46EFEF]
  0046EF27  |>  FF55 14       call    dword ptr [ebp+14]               ;  UDE.0040E3B0; Case 38 ('8') of switch 0046EF13
  0046EF2A  |.  E9 B1000000   jmp     0046EFE0
  0046EF2F  |>  FF55 14       call    dword ptr [ebp+14]               ;  Case 39 ('9') of switch 0046EF13
  0046EF32  |.  E9 A7000000   jmp     0046EFDE
  0046EF37  |>  FF75 0C       push    dword ptr [ebp+C]                ;  Case 3A (':') of switch 0046EF13
  0046EF3A  |>  FF55 14       call    dword ptr [ebp+14]
  
  
  这里是个switch case的地方。一般switch case都是处理一些固定的流程的逻辑分支,大多书时候也是一个逻辑开始的地方。
  所以从这里下去能看见大多数的功能。
  
  F7,跟入Function
  0040E3B0  |> /55            push    ebp
  0040E3B1  |. |8BEC          mov     ebp, esp
  0040E3B3  |. |83E4 F8       and     esp, FFFFFFF8
  0040E3B6  |. |6A FF         push    -1
  0040E3B8  |. |68 FD4E4A00   push    004A4EFD
  0040E3BD  |. |64:A1 0000000>mov     eax, dword ptr fs:[0]
  0040E3C3  |. |50            push    eax
  0040E3C4  |. |81EC 58030000 sub     esp, 358
  0040E3CA  |. |A1 18C64C00   mov     eax, dword ptr [4CC618]
  0040E3CF  |. |33C4          xor     eax, esp
  0040E3D1  |. |898424 500300>mov     dword ptr [esp+350], eax
  0040E3D8  |. |53            push    ebx
  0040E3D9  |. |56            push    esi
  0040E3DA  |. |57            push    edi
  0040E3DB  |. |A1 18C64C00   mov     eax, dword ptr [4CC618]
  0040E3E0  |. |33C4          xor     eax, esp
  0040E3E2  |. |50            push    eax
  0040E3E3  |. |8D8424 680300>lea     eax, dword ptr [esp+368]
  0040E3EA  |. |64:A3 0000000>mov     dword ptr fs:[0], eax
  0040E3F0  |. |33F6          xor     esi, esi
  0040E3F2  |. |8D4424 10     lea     eax, dword ptr [esp+10]
  0040E3F6  |. |8BF9          mov     edi, ecx
  0040E3F8  |. |897424 10     mov     dword ptr [esp+10], esi
  0040E3FC  |. |E8 1FAEFFFF   call    00409220                ;这个函数就是功能验证函数
  0040E401  |. |3BC6          cmp     eax, esi
  0040E403  |. |0F84 96020000 je      0040E69F
  0040E409  |. |837C24 10 58  cmp     dword ptr [esp+10], 58
  
  
  嗯,是的,那个函数就是功能函数,至于如何发现的,我通常是比较关注分支的不同跑法,根据外部环境。实际上很容易分析出。
  然后进去读这个函数。
  seg002:00409220 56                                                              push    esi
  seg002:00409221 8B F0                                                           mov     esi, eax
  seg002:00409223 E8 28 01 00 00                                                  call    sub_409350
  seg002:00409228 85 C0                                                           test    eax, eax
  seg002:0040922A 74 07                                                           jz      short loc_409233
  seg002:0040922C E8 2F FF FF FF                                                  call    sub_409160
  seg002:00409231 5E                                                              pop     esi
  seg002:00409232 C3                                                              retn
  seg002:00409233                                                 ; ---------------------------------------------------------------------------
  seg002:00409233
  seg002:00409233                                                 loc_409233:                             ; CODE XREF: Check_Fun+Aj
  seg002:00409233 52                                                              push    edx
  seg002:00409234 57                                                              push    edi
  seg002:00409235 83 CA 49                                                        or      edx, 49h
  seg002:00409238 83 EA 45                                                        sub     edx, 45h
  seg002:0040923B 03 D5                                                           add     edx, ebp
  seg002:0040923D 33 D3                                                           xor     edx, ebx
  seg002:0040923F 8D 94 39 8D 2A 41 00                                            lea     edx, loc_412A8D[ecx+edi]
  seg002:00409246 2B D7                                                           sub     edx, edi
  seg002:00409248 2B D1                                                           sub     edx, ecx
  seg002:0040924A FF 32                                                           push    dword ptr [edx]
  seg002:0040924C BA 76 41 44 00                                                  mov     edx, (offset loc_444171+5)
  seg002:00409251 03 54 24 38                                                     add     edx, [esp+10h+arg_24]
  seg002:00409255 5A                                                              pop     edx
  seg002:00409256 0F B6 FA                                                        movzx   edi, dl
  seg002:00409259 33 54 24 08                                                     xor     edx, [esp+0Ch+var_4]
  seg002:0040925D BA 2A 47 47 00                                                  mov     edx, (offset loc_474729+1)
  seg002:00409262 81 EA 86 1B C0 BE                                               sub     edx, 0BEC01B86h
  seg002:00409268 8D 54 4B 4A                                                     lea     edx, [ebx+ecx*2+4Ah]
  seg002:0040926C 8D 94 39 50 9F E5 8A                                            lea     edx, [ecx+edi-751A60B0h]
  seg002:00409273 2B D7                                                           sub     edx, edi
  seg002:00409275 2B D1                                                           sub     edx, ecx
  seg002:00409277 8D BC 0F C8 5F 1A 75                                            lea     edi, [edi+ecx+751A5FC8h]
  seg002:0040927E 2B F9                                                           sub     edi, ecx
  seg002:00409280 03 FA                                                           add     edi, edx
  seg002:00409282 0B FF                                                           or      edi, edi
  seg002:00409284 90                                                              nop
  seg002:00409285 E9 1F 00 00 00                                                  jmp     loc_4092A9
  seg002:0040928A                                                 ; ---------------------------------------------------------------------------
  seg002:0040928A 81 C5 7E AE A4 09                                               add     ebp, 9A4AE7Eh
  seg002:00409290 BE AE E6 45 00                                                  mov     esi, offset loc_45E6AE
  seg002:00409295 83 CE 73                                                        or      esi, 73h
  seg002:00409298 81 C7 10 B5 87 C3                                               add     edi, 0C387B510h
  seg002:0040929E 68 1C 37 5C BC                                                  push    0BC5C371Ch
  seg002:004092A3 52                                                              push    edx
  seg002:004092A4 E9 00 00 00 00                                                  jmp     $+5
  seg002:004092A9
  seg002:004092A9                                                 loc_4092A9:                             ; CODE XREF: Check_Fun+65j
  seg002:004092A9 5F                                                              pop     edi
  seg002:004092AA 5A                                                              pop     edx
  seg002:004092AB E9 93 00 00 00                                                  jmp     loc_409343
  
  
  
  这个函数call了两个函数,进去看函数1个一个读。
  首先进入读函数sub_409350
  seg002:00409350 53                                                              push    ebx
  seg002:00409351 56                                                              push    esi
  seg002:00409352 1B DF                                                           sbb     ebx, edi        ; nop
  seg002:00409354 8D 5C 35 BD                                                     lea     ebx, [ebp+esi-43h] ; nop
  seg002:00409358 8D 99 04 66 41 00                                               lea     ebx, loc_416604[ecx]
  seg002:0040935E 2B D9                                                           sub     ebx, ecx
  seg002:00409360 FF 33                                                           push    dword ptr [ebx]
  seg002:00409362 83 DB 19                                                        sbb     ebx, 19h        ; nop
  seg002:00409365 BB 2A 1C 44 00                                                  mov     ebx, offset loc_441C2A ; nop
  seg002:0040936A 5B                                                              pop     ebx
  seg002:0040936B 0F B6 F3                                                        movzx   esi, bl
  seg002:0040936E 03 5C 24 38                                                     add     ebx, [esp+8+arg_2C] ; nop
  seg002:00409372 BB 46 88 42 00                                                  mov     ebx, (offset loc_428845+1) ; nop
  seg002:00409377 68 EF 0F D2 30                                                  push    30D20FEFh
  seg002:0040937C 8D 1C 0B                                                        lea     ebx, [ebx+ecx]  ; nop
  seg002:0040937F 5B                                                              pop     ebx
  seg002:00409380 8D B6 29 EF 2D CF                                               lea     esi, [esi-30D210D7h]
  seg002:00409386 03 F3                                                           add     esi, ebx
  seg002:00409388 85 F6                                                           test    esi, esi
  seg002:0040938A 0F 85 2D 00 00 00                                               jnz     loc_4093BD      ; nop
  seg002:00409390 C1 C6 E7                                                        rol     esi, 0E7h       ; nop
  seg002:00409393 BE 06 DC 40 00                                                  mov     esi, (offset loc_40DC01+5) ; nop
  seg002:00409398 33 F6                                                           xor     esi, esi
  seg002:0040939A 8D 44 47 65                                                     lea     eax, [edi+eax*2+65h] ; nop
  seg002:0040939E B8 B2 C7 46 00                                                  mov     eax, (offset loc_46C7B0+2) ; nop
  seg002:004093A3 B8 AA 7F 49 00                                                  mov     eax, (offset loc_497FA7+3) ; nop
  seg002:004093A8 81 D8 C6 00 3F 15                                               sbb     eax, 153F00C6h  ; nop
  seg002:004093AE 8D 44 0E 1B                                                     lea     eax, [esi+ecx+1Bh]
  seg002:004093B2 2B C1                                                           sub     eax, ecx
  seg002:004093B4 83 E8 1B                                                        sub     eax, 1Bh
  seg002:004093B7 40                                                              inc     eax
  seg002:004093B8 E9 10 00 00 00                                                  jmp     loc_4093CD
  seg002:004093BD                                                 ; ---------------------------------------------------------------------------
  seg002:004093BD
  seg002:004093BD                                                 loc_4093BD:                             ; CODE XREF: sub_409350+3Aj
  seg002:004093BD B8 02 D3 48 00                                                  mov     eax, (offset loc_48D301+1) ; nop
  seg002:004093C2 33 44 24 28                                                     xor     eax, [esp+8+arg_1C] ; nop
  seg002:004093C6 33 C0                                                           xor     eax, eax
  seg002:004093C8 E9 00 00 00 00                                                  jmp     $+5
  seg002:004093CD
  seg002:004093CD                                                 loc_4093CD:                             ; CODE XREF: sub_409350+68j
  seg002:004093CD 5E                                                              pop     esi
  seg002:004093CE 5B                                                              pop     ebx
  seg002:004093CF E9 8C 00 00 00                                                  jmp     locret_409460
  其实它就是加了点花,我写了下把那些该nop的nop掉,要不看到恶心。
  
  然后真相就出来了只需要对0x4d1cfc写0x58,以及对0x4d1cec写非0x2c,软件就有全功能了。OK。破解功能到这里就完成了。去花后同学们就明白了。
  然后我们要写一个注册程序和修改程序算法。
  我是直接外挂了程序的注册部分实现自己的注册。全代码如下。
  
  #include "OhYe.h"
  #include "md5.h"
  #include <tchar.h>
  
  Environ  allEnvir;
  char   szFileName[MAX_PATH];
  int WINAPI DllMain(_In_ void * _HDllHandle, _In_ unsigned _Reason, _In_opt_ void * _Reserved)
  {
    
    if (_Reason == DLL_PROCESS_ATTACH)
    {
      
      memset(szFileName,0,MAX_PATH);
      GetModuleFileNameA(NULL,szFileName,MAX_PATH);
      DWORD dwThreadID = 0;
      CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)WorkThread,NULL,NULL,&dwThreadID);
    }
    
    return TRUE;
  }
  
  int WINAPI WorkThread(LPARAM lParam)
  {
    
    InitEnviron(allEnvir);
    Sleep(1000);
    InlineHook(0x407539,(DWORD)SetStrInput,5);
    ChageRes();
    //MessageBoxA(NULL,"debug","debug",MB_OK);
  
    DWORD* addr1 =(DWORD*) 0x4d2718;
    DWORD* addr2 = (DWORD*)(*(addr1)+0x24);
    //MessageBoxW(NULL,(LPCTSTR)(*(addr2)),(LPCTSTR)(*(addr2)),MB_OK);
    
    WCHAR *wszDiskData = (WCHAR*)(*(addr2));
    USES_CONVERSION;
    char szoutmd5[33];
    memset(szoutmd5,0,33);
    char* pstring =  W2A(wszDiskData);
    pstring[0] = 'U';
    pstring[1] = 'E';
    pstring[3] = pstring[3]+1;
    pstring[4] = pstring[4]+3;
    pstring[5] = pstring[5]+2;
  
    char* pstrmd5 = MD5String(pstring,szoutmd5);
    char szBuffer[MAX_PATH];
    GetPrivateProfileStringA("KEY","register","yeallright",szBuffer,MAX_PATH,allEnvir.szIniFileName);
    if (stricmp(szBuffer,pstrmd5)!=0)
    {
      MessageBoxA(NULL,"注册码错误,请从新联系QQ:516674080 注册使用","注册码错误,请从新联系QQ:516674080 注册使用",MB_OK);
      //ExitProcess(0);
      return 0;
    }
    
    DWORD* dwWirteAddr = 0;
    
    while(TRUE)
    {
    
      dwWirteAddr = (DWORD*)0x4d1cec;
      *(dwWirteAddr) = 0x2D;
      dwWirteAddr = (DWORD*)0x4d1cfc;
      *(dwWirteAddr) = 0x58;
      VIRTUALIZER_END
    }
  
    return 0;
    
  }
  
  WCHAR* pwstr;
  __declspec(naked) void SetStrInput()
  {
    __asm
    {
      pushad
      pushfd
      mov pwstr,ecx
    }
      
    WritePrivateProfileStringW(_T("KEY"),_T("register"),pwstr,allEnvir.wscIniFileName);
    __asm
    {
      popfd
      popad
      mov eax,0x40753e
      push eax
      mov eax,0x407900
      jmp eax
    }
  }
  void add()
  {
    return;
  }
  
  void ChageRes()
  {
      HANDLE hFile = CreateFileA(allEnvir.szResFileName,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
      SetFilePointer(hFile,0xd4000,NULL,FILE_BEGIN);
      DWORD dwRead = 0;
      DWORD dwReadLen = 0x10;
      DWORD dwWriteAddr = 0x4d4000;
      char szBuffer[0x11];
      for(int i = 0;i<0x4cff0;i=i+0x10)
      {
        memset(szBuffer,0,0x11);
        ReadFile(hFile,szBuffer,dwReadLen,&dwRead,NULL);    
        GetLastError();
        memcpy((void*)dwWriteAddr,szBuffer,0x10);
        dwWriteAddr=dwWriteAddr +0x10;
      }
  }
  
  
  代码写的很乱,情况大概是这样的。在注册部分的时候,是直接挂接程序的0x00407539  
  
  
  00407530  |.  894C24 18     mov     dword ptr [esp+18], ecx
  00407534  |.  E8 11470600   call    0046BC4A
  00407539  |.  E8 C2030000   call    00407900                         ;  getstring
  0040753E  |.  8BDF          mov     ebx, edi
  00407540  |.  E8 3B030000   call    00407880
  
  挂成这个函数
  
  __declspec(naked) void SetStrInput()
  {
    __asm
    {
      pushad
      pushfd
      mov pwstr,ecx
    }
      
    WritePrivateProfileStringW(_T("KEY"),_T("register"),pwstr,allEnvir.wscIniFileName);
    __asm
    {
      popfd
      popad
      mov eax,0x40753e
      push eax
      mov eax,0x407900
      jmp eax
    }
  }
  
  这个函数的本意就是相当于复用了它的注册框,把用户输入的注册码取出来,然后写到一个配置文件里。
  
    DWORD* addr1 =(DWORD*) 0x4d2718;
    DWORD* addr2 = (DWORD*)(*(addr1)+0x24);
    //MessageBoxW(NULL,(LPCTSTR)(*(addr2)),(LPCTSTR)(*(addr2)),MB_OK);
    
    WCHAR *wszDiskData = (WCHAR*)(*(addr2));
    USES_CONVERSION;
    char szoutmd5[33];
    memset(szoutmd5,0,33);
    char* pstring =  W2A(wszDiskData);
    pstring[0] = 'U';
    pstring[1] = 'E';
    pstring[3] = pstring[3]+1;
    pstring[4] = pstring[4]+3;
    pstring[5] = pstring[5]+2;
  
    char* pstrmd5 = MD5String(pstring,szoutmd5);
    char szBuffer[MAX_PATH];
    GetPrivateProfileStringA("KEY","register","yeallright",szBuffer,MAX_PATH,allEnvir.szIniFileName);
    if (stricmp(szBuffer,pstrmd5)!=0)
    {
      MessageBoxA(NULL,"注册码错误,请从新联系QQ:516674080 注册使用","注册码错误,请从新联系QQ:516674080 注册使用",MB_OK);
      //ExitProcess(0);
      return 0;
    }
  
  这断代码是验证部分代码,首先我分析出了他自己的程序验证取硬件特征码的固定偏移量,大概是这样的
  
    DWORD* addr1 =(DWORD*) 0x4d2718;
    DWORD* addr2 = (DWORD*)(*(addr1)+0x24);
  这个地方取出来的就是个地址。这个地址就是个机器码
  
  然后处理处理,做个和配置文件中的注册码取出来一个stricmp就OK了。(有没有什么更加简单的?能不写代码就能生成注册过程的东西???我还是觉得这样太麻烦了)
  接下来是处理资源。
  因为程序是加了壳的,而我们又没完全脱壳。所以我们不能静态的时候就把资源换了。因为程序静态的时候资源还没解密。
  
  我是难的去怎一切难的怎的事了,能猥琐就猥琐。于是就这样处理的。直接在程序动态解密完后,把内存中的资源直接替换调。替换成我们用eXeScope修改后的资源。
  代码如下:
  void ChageRes()
  {
      HANDLE hFile = CreateFileA(allEnvir.szResFileName,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
      SetFilePointer(hFile,0xd4000,NULL,FILE_BEGIN);
      DWORD dwRead = 0;
      DWORD dwReadLen = 0x10;
      DWORD dwWriteAddr = 0x4d4000;
      char szBuffer[0x11];
      for(int i = 0;i<0x4cff0;i=i+0x10)
      {
        memset(szBuffer,0,0x11);
        ReadFile(hFile,szBuffer,dwReadLen,&dwRead,NULL);    
        GetLastError();
        memcpy((void*)dwWriteAddr,szBuffer,0x10);
        dwWriteAddr=dwWriteAddr +0x10;
      }
  }
  0x4d4000是资源节,然后文件的0xd4000也是资源节。基本上资源部分的替换就用eXeScope就KO了。
  

对了还有个事,把这个dll感染到那个pe里就OK了。直接用LoadPE,就完成了这功能。
  
  
--------------------------------------------------------------------------------
【经验总结】
  字就码完了。感觉没啥可说的。近来全走的是猥琐路子,没沉淀。最近在做虚拟机还原的一些积累。还做的不好,都还在学
  习阶段。怎完了大家一起分享起。
  
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!

                                                       2011年02月01日 1:50:33

http://bbs.pediy.com/attachment.php?...1&d=1296497066

http://bbs.pediy.com/attachment.php?...1&d=1296497153

上传的附件 OhYe.rar