作者: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。
所以,不能追码。 |