铁棒计划<1>
kflnig
有比cracker更加了解破解所在吗?所以就让我这个cracker来谈谈软件保护的方法。本文基于borland c++6.0调试通过。你最好懂点内联汇编。如有错误告诉我。我家里没有上网,手头的开发资料只有borland的帮助文档(其实很不错)。
首先是anti OD。
1、IsDebuggerPresent
BOOL IsDebuggerPresent(VOID)
这个函数相信大家用得最多。但是也没有什么用处。随便都可以被搞定。
微软说:
If the current process is running in the context of a debugger, the return value is nonzero.
If the current process is not running in the context of a debugger, the return value is zero.
翻译过来就是:
如果当前的应用程序在调试器下运行,则返回值不为0,如果不在调试器下运行,则返回值为0。
通常我们可以这么写:
bool isdebuggeron;
isdebuggeron=IsDebuggerPresent();
if (isdebuggeron)
{……
}
省略号表示你想要的代码。当然傻子才会这么写。我们用OD一调试就可以在输入函数中看到IsDebuggerPresent,而IsDebuggerPresent的作用只有用来发现调试器。所以,这个东西绝对不可以出现在输入函数列表之中。
让它不显示在输入表中方法很多,我来介绍一种不常用的。
我们用IDA分析kernel32.dll。找到IsDebuggerPresent如下:
; BOOL IsDebuggerPresent(void)
.text:7C812E03 public IsDebuggerPresent
.text:7C812E03 IsDebuggerPresent proc near ; CODE XREF: .text:loc_7C874FB1 p
.text:7C812E03 mov eax, large fs:18h
.text:7C812E09 mov eax, [eax+30h]
.text:7C812E0C movzx eax, byte ptr [eax+2]
.text:7C812E10 retn
.text:7C812E10
.text:7C812E10 IsDebuggerPresent endp
然后我们来自己写一个my IsDebuggerPresent函数。
bool my IsDebuggerPresent ()
{
__asm
{
mov eax, large fs:18h
mov eax, [eax+30h]
movzx eax, byte ptr [eax+2]
}
}
这个就是我们自己的 IsDebuggerPresent,不会再在输入表中出现 IsDebuggerPresent啦!
简单实用!
2、FindWindow
HWND FindWindow(
LPCTSTR lpClassName, // pointer to class name
LPCTSTR lpWindowName // pointer to window name
);
Parameters
lpClassName
Points to a null-terminated string that specifies the class name or is an atom that identifies the class-name string. If this parameter is an atom, it must be a global atom created by a previous call to the GlobalAddAtom function. The atom, a 16-bit value, must be placed in the low-order word of lpClassName; the high-order word must be zero.
lpWindowName
Points to a null-terminated string that specifies the window name (the window's title). If this parameter is NULL, all window names match.
Return Values
If the function succeeds, the return value is the handle to the window that has the specified class name and window name.
If the function fails, the return value is NULL. To get extended error information, call GetLastError.
上面的是很简单的英语。
lpClassName是指向类名字符串的指针。
lpWindowName是窗口标题。如果这个参数值为NULL,则所有的类名都会受到检测。
返回值,如果函数调用成功,返回窗口的句柄。如果不成功,返回NULL。
我们用OD自己的插件窗口工具,就可以知道,它的类名是OllyDBG。lpWindowName我们传入NULL就好了。
char *str="OllyDBG";
h_od=FindWindow(str,NULL);
if (h_od)
{
……
}
这样写就好了。如果OD开着,那么,我们就可以发现它。
3、GetTickCount
这个可是老牌的检测方法了。老,但是经典。
我们可以根据因为在调试的时候,在某些地方时间和原来的直接载入相比暂停太多了。所以可以根据时间的长短来猜测是否被调试。我这边设置的是1s。
int t1,t2;
t1=GetTickCount();
……
t2=GetTickCount();
if (t2-t1>1000)
{
……
}