我们一般在查找软件的注册关键点时,常用的手段有:
1、查找提示字符
2、F12堆栈暂停法
3、常用的API函数,如GetDlgItemTextA(W)、GetWindowTextA(W)等
针对第1点,一般的方法是采用字符串加密的方法,对关键的字符串,进行加密,如这个CrackMe里一样:
char strErr1[]="\x21\x17\x0D\x0A\x58\x36\x19\x15\x1D\x58\x11\x0B\x58\x16\x17\x0C\x58\x3D\x15\x08\x0C\x01\x54\x28\x14\x1D\x19\x0B\x1D\x58\x11\x16\x08\x0D\x0C\x59"; //经过加密的字符串
我这里是用自己写的一个小工具加密的,如图:
然后在调用时解密:
TCHAR szContent[1024];
memset(szContent,0,1024);
for(int i=0;strErr1[i];i++)
szContent[i]=strErr1[i]^0x78;
MessageBox(hDlg,szContent,szContent,0);
而针对F12堆栈法,就需要打破程序的运行路径,如用异常捕获、专用的验证线程,这个CrackMe采用的是专用的验证线程:
1、首先在生成一个验证线程,可以在主界面生成之前,也可以在对话框的初始化过程中,这里的一个好处就是可以把对话框的句柄传递给生成的验证线程:
case WM_INITDIALOG:
CreateThread(NULL,0,VerifyThread,(LPVOID)hDlg,0,&dwThreadId);
2、激活线程需要判断何时开始验证,当然也可以一开始生成验证线程时,采用CREATE_SUSPENDED标记,让线程挂起,然后再通过调用ResumeThread()来激活。不过这样较明显,这里采用了事件等待。
g_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
…………
SetEvent(g_hEvent);
然后在验证线程里等待:
WaitForSingleObject(g_hEvent,INFINITE);
//开始验证…………
3、在开始验证前,还可以人为的设置一些反跟踪的陷阱,如这里的对MessageBoxA函数是有下有F2断点的测试:
BYTE *dwAddr=(BYTE*)GetProcAddress(GetModuleHandle("user32.dll"),"MessageBoxA");
//测试MessageBoxA()函数前5个字节是否下有断点,有则退出
for(int i=0;i<10;i++){
if(*dwAddr == 0xCC)
ExitProcess(0);
dwAddr++;
}
你可以判断更多的地方,呵呵……
4、补充一下异常的捕获验证,如下代码:
__try{
//初步判断用户名与注册码
_asm int 3 //使用内联汇编来人为设置int 3异常
}
//捕获异常,是int 3中断异常则开始验证
__except(EXCEPTION_BREAKPOINT==GetExceptionCode()){
//开始验证
VerifyUserCode();
}
源码见论坛:http://bbs.7softs.com/read.php?tid=31967
压缩包解压密码为:[size=3]b1NYzvsaq8GODPyH[/size]