吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2970|回复: 5
收起左侧

[CrackMe] 【吾爱2013CM大赛解答】-- 2013CM -TempCrackme2013 -- Rookietp 源码分析

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

作者:JoyChou
博客:http://joychou.sinaapp.com
日期:2013年12月16日

先申明,这个不能追码,原因下面再解释。

第一步:找到按钮事件,还是可以用那工具,也可以手动分析。上篇破文我已经讲过了。就不多说了。
第二步:修改关键跳,爆破成功。
[AppleScript] 纯文本查看 复制代码
00402100   .  8379 20 7B    cmp dword ptr ds:[ecx+0x20],0x7B
00402104   .  75 0E         jnz XTempCrac.00402114                   ;  nop即可
00402106   .  6A 00         push 0x0
00402108   .  6A 00         push 0x0
0040210A   .  68 28F85400   push TempCrac.0054F828                   ;  注册成功!
0040210F   .  E8 9F030000   call TempCrac.004024B3
00402114   >  C3            retn




初始化的一系列操作:
怎样找到BOOL CXXXXDlg::OnInitDialog()这个函数?
通过IDA找到CDialog::OnIntDialog地址,来到这后,ctrl+F9返回后,单步一步就可以到OnIntDialog
注意这两个OnIntDialog是不一样的。
MFC OnInitDialog代码都有类似下面的代码
[C++] 纯文本查看 复制代码
BOOL CXXXXDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();
}


再进入00401FD7      E8 B4F1FFFF   call TempCrac.00401190 这个call,重点都在里面
[AppleScript] 纯文本查看 复制代码
00401190  /$  53            push ebx
00401191  |.  56            push esi
00401192  |.  57            push edi
00401193  |.  68 4CF45400   push TempCrac.0054F44C                                   ; /ntdll.dll
00401198  |.  FF15 FC535200 call dword ptr ds:[<&KERNEL32.LoadLibraryW>]             ; \LoadLibraryW
0040119E  |.  68 7CF45400   push TempCrac.0054F47C                                   ; /RtlComputeCrc32
004011A3  |.  50            push eax                                                 ; |hModule
004011A4  |.  FF15 28545200 call dword ptr ds:[<&KERNEL32.GetProcAddress>]           ; \GetProcAddress
004011AA  |.  68 27010000   push 0x127
004011AF  |.  68 00104000   push TempCrac.00401000
004011B4  |.  8BF0          mov esi,eax
004011B6  |.  6A 00         push 0x0
004011B8  |.  FFD6          call esi                                                 ;  计算00401000到00401000+0x127的CRC32
004011BA  |.  8B3D 3C525200 mov edi,dword ptr ds:[<&KERNEL32.TerminateProcess>]      ;  kernel32.TerminateProcess
004011C0  |.  8B1D 30545200 mov ebx,dword ptr ds:[<&KERNEL32.GetCurrentProcess>]     ;  kernel32.GetCurrentProcess
004011C6  |.  3D 71196895   cmp eax,0x95681971
004011CB      74 07         je XTempCrac.004011D4                                    ;  不相等就退出
004011CD  |.  6A FF         push -0x1                                                ; /ExitCode = FFFFFFFF (-1.)
004011CF  |.  FFD3          call ebx                                                 ; |[GetCurrentProcess
004011D1  |.  50            push eax                                                 ; |hProcess
004011D2  |.  FFD7          call edi                                                 ; \TerminateProcess
004011D4  |>  68 27010000   push 0x127
004011D9  |.  68 40104000   push TempCrac.00401040
004011DE  |.  6A 00         push 0x0
004011E0  |.  FFD6          call esi                                                 ;  计算00401040到00401040+127的CRC
004011E2  |.  3D 84DC625E   cmp eax,0x5E62DC84
004011E7      74 07         je XTempCrac.004011F0                                    ;  不相等就退出
004011E9  |.  6A FF         push -0x1
004011EB  |.  FFD3          call ebx
004011ED  |.  50            push eax
004011EE  |.  FFD7          call edi
004011F0  |>  8B35 2C545200 mov esi,dword ptr ds:[<&KERNEL32.GetModuleHandleW>]      ;  kernel32.GetModuleHandleW
004011F6  |.  6A 00         push 0x0                                                 ; /pModule = NULL
004011F8  |.  FFD6          call esi                                                 ; \GetModuleHandleW
004011FA  |.  50            push eax
004011FB  |.  E8 50FEFFFF   call TempCrac.00401050                                   ;  计算当前模块的CRC32值
00401200  |.  83C4 04       add esp,0x4
00401203  |.  68 60F45400   push TempCrac.0054F460                                   ;  kernel32.dll
00401208  |.  FFD6          call esi
0040120A  |.  50            push eax
0040120B  |.  E8 40FEFFFF   call TempCrac.00401050                                   ;  计算Kernel32.dll模块的CRC32值
00401210  |.  83C4 04       add esp,0x4
00401213  |.  5F            pop edi
00401214  |.  5E            pop esi
00401215  |.  5B            pop ebx
00401216  \.  C3            retn


再看看004011FB  |.  E8 50FEFFFF   call TempCrac.00401050                                   ;  计算当前模块的CRC32值
是怎么样计算的?
这就给出源码了。
[C++] 纯文本查看 复制代码
#include <windows.h>
#include <tchar.h>
typedef VOID (__stdcall *My_CheckCRCCallBack)();
typedef VOID (__stdcall *My_Sleep)(DWORD dwMilliseconds);
//这个是一个没有定义的函数
//第一个参数为CRC初始值
typedef unsigned int (__stdcall *My_RtlComputeCrc32)(int dwInital, void* pData, int iLen);
//自己定义一个线程需要的参数      
typedef struct _THREAD_CONTEXT_
{
    My_RtlComputeCrc32 funcRtlComputeCrc32;
    My_Sleep funcSleep;
    My_CheckCRCCallBack funcCallBack;
    PVOID CheckAddress;
    int CheckSize;
}THREAD_CONTEXT, *PTHREAD_CONTEXT;
VOID __stdcall DefCallBack()
{
    MessageBox(NULL,TEXT("进程代码被修改"), NULL, MB_OK);
    TerminateProcess(GetCurrentProcess(),-1);
}
int GetShellCodeLen(BYTE *lpShell)
{
    DWORD dwStart=(DWORD)lpShell;
    int len=0;
    while(*(DWORD *)dwStart!=0xAAAAAAAA)
    {
        dwStart++;
        len++;
    }
    return len;
}
// 相当于线程函数
DWORD WINAPI CheckCRC(LPVOID ThreadContext)
{
    UINT Crc32 = 0;
    // 得到传进来的ctx结构
    PTHREAD_CONTEXT ctx = (PTHREAD_CONTEXT)ThreadContext;
    Crc32 = ctx->funcRtlComputeCrc32(0, ctx->CheckAddress, ctx->CheckSize);
    while(1)
    {
        UINT uNewCrc32 = ctx->funcRtlComputeCrc32(0, ctx->CheckAddress, ctx->CheckSize);
        if (uNewCrc32 != Crc32)
        {
            ctx->funcCallBack();
        }
        ctx->funcSleep(1000); //间隔检查时间
    }
    //结束标识
    __asm
    {
        _emit 0xAA
            _emit 0xAA
            _emit 0xAA
            _emit 0xAA
    }
    return 0;
}
VOID CreateAntiBpThread(PVOID Address, int nSize)
{
    PTHREAD_CONTEXT thcxt = (PTHREAD_CONTEXT)VirtualAllocEx(
        GetCurrentProcess(),
        NULL,
        sizeof(THREAD_CONTEXT),
        MEM_COMMIT|MEM_RESERVE,
        PAGE_EXECUTE_READWRITE);
    //给THREAD_CONTEXT结构赋值
    thcxt->funcRtlComputeCrc32 = (My_RtlComputeCrc32)GetProcAddress(
        GetModuleHandle(_T("ntdll.dll")), "RtlComputeCrc32");
    thcxt->CheckAddress = Address;
    thcxt->CheckSize = nSize;
    thcxt->funcCallBack = DefCallBack;
    thcxt->funcSleep = (My_Sleep)GetProcAddress(
        GetModuleHandle(_T("kernel32.dll")), "Sleep");
    // 计算CheckCRC函数的大小
    DWORD dwThreadSize = GetShellCodeLen((BYTE*)CheckCRC);  
    // 在当前进程申请一个CheckCRC函数大小的空间
    PVOID ThreadCode = (PVOID)VirtualAllocEx(
        GetCurrentProcess(),
        NULL,
        dwThreadSize,
        MEM_COMMIT|MEM_RESERVE,
        PAGE_EXECUTE_READWRITE);
    // 将CheckCRC函数复制到刚申请的ThreadCode空间
    // #define CopyMemory RtlCopyMemory
    RtlCopyMemory(ThreadCode,(PVOID)CheckCRC,dwThreadSize);
    //创建线程————线程函数为ThreadCode,参数为thcxt
    CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadCode, (LPVOID)thcxt, 0, NULL);
}
void SetAntiBp(PVOID ImageBase)
{
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)ImageBase;
    PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)(pDosHeader->e_lfanew + (DWORD)ImageBase);
    PIMAGE_SECTION_HEADER pFirstSecHeader = IMAGE_FIRST_SECTION(pNtHeader); 
    UINT nSecNumber = pNtHeader->FileHeader.NumberOfSections;
    //得到代码段
    for (UINT i = 0; i < nSecNumber; i++)
    {
        BOOL bIsCodeSec = FALSE;    //是否是代码段
        //得到每一个区段的指针
        PIMAGE_SECTION_HEADER pSecHeader = (PIMAGE_SECTION_HEADER)pFirstSecHeader + 
            i * sizeof(IMAGE_SECTION_HEADER);
        // 代码段是可执行、可读、包含代码、不废弃
        if ( (pSecHeader->Characteristics & IMAGE_SCN_MEM_EXECUTE) &&
            (pSecHeader->Characteristics & IMAGE_SCN_MEM_READ)    &&
            (pSecHeader->Characteristics & IMAGE_SCN_CNT_CODE)    &&
            !(pSecHeader->Characteristics & IMAGE_SCN_MEM_DISCARDABLE)  )
        {
            bIsCodeSec = 1;
        }
        if (bIsCodeSec)
        {
            MessageBox(NULL, _T("Hi"), _T("JoyChou"), 0);
            CreateAntiBpThread( (PVOID)((DWORD)ImageBase + pSecHeader->VirtualAddress), pSecHeader->Misc.VirtualSize);
        }
    }
}
int main(int argc, char *agrv[])
{
    // 当前进程
    SetAntiBp(GetModuleHandle(NULL));
    SetAntiBp(GetModuleHandle(_T("user32.dll")));
    // 要监视的代码
    int check = 1;
    if (check)
    {
        MessageBox(NULL, L"test", L"test", MB_OK);
    }
    return 0;
}


有关怎么计算这个CRC32校验值,可以看http://joychou.sinaapp.com/index.php/Reverse/CRC.html有详细分析。

最后还有为什么不能追码?
cmp dword ptr ds:[ecx+0x20],0x7B这是关键比较,在这个程序中0012FE60一直都是这个地址。
当初始化函数的时候,可以看到0012FE60这个地址的值已经被赋值,继续运行到按钮事件处,这个值却没有变!
这说明了这个值根本和我们输入无关。而且这个值永远不会等于0x7B。
所以,不能追码。

本帖子中包含更多资源

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

x

免费评分

参与人数 1热心值 +1 收起 理由
Chief + 1 吾爱破解2013CM大赛,有你更精彩!

查看全部评分

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

 楼主| JoyChou 发表于 2013-12-16 22:43
沙发自己坐。
头像被屏蔽
夜的静night 发表于 2013-12-16 23:28
空心 发表于 2013-12-16 23:36
我是用户 发表于 2013-12-20 20:34
看雪V校发的飘动线程代码,线程的地址是随机的。
 楼主| JoyChou 发表于 2013-12-20 22:07
我是用户 发表于 2013-12-20 20:34
看雪V校发的飘动线程代码,线程的地址是随机的。

恩.是的
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2024-11-25 00:09

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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