首页
社区
课程
招聘
转载: 用其它方式检查出 OllyDbg
2004-5-5 22:43 13543
申请推荐此帖 编辑 删除

转载: 用其它方式检查出 OllyDbg

2004-5-5 22:43
13543
刚读一文,觉得大家会感兴趣,属于olly 的检测方法,故转载这里, 在 internet 上谈anti-softice的比较多, anti-olly的还是比较少。
声声慢

The other ways to detect OllyDbg by Pumqara  
作者:Pumqara

介绍
2004年, ring-3 的调试器被越来越频繁地使用。自从它们提供windows GUI 的环境,它们比起ring-0 调试器(象SoftIce)更来得得心应手。 在这篇文章里,我将谈一下关于侦查最佳的ring-3 调试器之一:OllyDbg的方法.  很多人已听说了IsDebbugerPresent fs:[20 ] 的方法, 但其它新的呢? 这里我将向您谈及一些我的独家侦查方法,我将给您一些基本的解析,您可以用您的幻想力去将它提高。

--------------------------------------------------------------------
Introduction

The year is 2004.The ring-3 debuggers are used often and often.Since they offer Windows GUI they are more handy instead of the ring-0 debuggers (like SoftIce).In this essay i will talk (write) about the detection of one of the best ring-3 debuggers - OllyDbg.Many have heard of the IsDebbugerPresent and of the fs:[20] detecting tricks, but what about some other new ones? Here I will present you some of my own detecting tricks.I will give you the general explanation so you would be able to use your fantasy to improve it yourself.

Method I: FindWindow
This method is based on the FindWindows function.As all dialogs the OllyDbg's main dialog (window ?) has its caption and Class name.Using this Api we will try to find if the OllyDbg's main window is opened.Microsoft wrote:

The FindWindow function retrieves the handle of the top-level window whose class name and window name match the specified strings. This function does not search child windows

HWND FindWindow(

LPCTSTR lpClassName, // address of class name
LPCTSTR lpWindowName // address of 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 Value

If the function succeeds, the return value is the handle of 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

And my code snippet is:

.data
strOllyClsName db "OLLYDBG",0

.code
invoke FindWindow, ADDR strOllyClsName, NULL
cmp eax, 00000000h
jne Olly_Detected/

[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

收藏
点赞6
打赏
分享
最新回复 (20)
雪    币:
能力值: (RANK: )
在线值:
发帖
回帖
粉丝
游客 2004-5-5 22:44
2
0
Method II: CreateToolhelp32Snapshot, Process32First/Next

This is an interesting method.It is based on 4 apis (CreateToolhelp32Snapshot, Process32First, Process32Next, GetCurrentProcessId) and 1 structure ( PROCESSENTRY32 ).I will tell you what MSDN says first:

[CreateToolhelp32Snapshot]

The CreateToolhelp32Snapshot function takes a snapshot of the specified processes in the system, as well as the heaps, modules, and threads used by these processes.

HANDLE WINAPI CreateToolhelp32Snapshot(
DWORD dwFlags,
DWORD th32ProcessID
);

Parameters

dwFlags
[in] Portions of the system to include in the snapshot. This parameter can be one of the following values.

TH32CS_INHERIT - Indicates that the snapshot handle is to be inheritable.
TH32CS_SNAPALL - Includes all processes and threads in the system, plus the heaps and modules of the process specified in th32ProcessID.
TH32CS_SNAPHEAPLIST - Includes all heaps of the process specified in th32ProcessID in the snapshot. To enumerate the heaps, see Heap32ListFirst.
TH32CS_SNAPMODULE - Includes all modules of the process specified in th32ProcessID in the snapshot. To enumerate the modules, see Module32First.
TH32CS_SNAPPROCESS - Includes all processes in the system in the snapshot. To enumerate the processes, see Process32First.
TH32CS_SNAPTHREAD - Includes all threads in the system in the snapshot. To enumerate the threads, see Thread32First.

th32ProcessID
[in] Process identifier of the process to be included in the snapshot. This parameter can be zero to indicate the current process. This parameter is used when the TH32CS_SNAPHEAPLIST, TH32CS_SNAPMODULE, or TH32CS_SNAPALL value is specified. Otherwise, it is ignored and all processes are included in the snapshot.

Return Values

If the function succeeds, it returns an open handle to the specified snapshot.
If the function fails, it returns INVALID_HANDLE_VALUE. To get extended error information, call GetLastError.

Remarks

The snapshot taken by this function is examined by the other tool help functions to provide their results. Access to the snapshot is read only. The snapshot handle acts like an object handle and is subject to the same rules regarding which processes and threads it is valid in.

To enumerate the heap or module states for all processes, specify TH32CS_SNAPALL and set th32ProcessID to zero. Then, for each additional process in the snapshot, call CreateToolhelp32Snapshot again, specifying its process identifier and the TH32CS_SNAPHEAPLIST or TH32_SNAPMODULE value.

To destroy the snapshot, use the CloseHandle function.

[Process32First]

Process32First retrieves information about the first process encountered in a system snapshot.

BOOL WINAPI Process32First(
HANDLE hSnapshot,
LPPROCESSENTRY32 lppe
);

Parameters

hSnapshot
[in] Handle to the snapshot returned from a previous call to the CreateToolhelp32Snapshot function.

lppe
[in, out] Pointer to a PROCESSENTRY32 structure.

Return Values

Returns TRUE if the first entry of the process list has been copied to the buffer or FALSE otherwise. The ERROR_NO_MORE_FILES error value is returned by the GetLastError function if no processes exist or the snapshot does not contain process information.

Remarks

The calling application must set the dwSize member of PROCESSENTRY32 to the size, in bytes, of the structure. Process32First changes dwSize to the number of bytes written to the structure. This will never be greater than the initial value of dwSize, but it may be smaller. If the value is smaller, do not rely on the values of any members whose offsets are greater than this value.

To retrieve information about other processes recorded in the same snapshot, use the Process32Next function.

[Process32Next]

Process32Next Retrieves information about the next process recorded in a system snapshot.

BOOL WINAPI Process32Next(
HANDLE hSnapshot,
LPPROCESSENTRY32 lppe
);

Parameters

hSnapshot
[in] Handle to the snapshot returned from a previous call to the CreateToolhelp32Snapshot function.

lppe
[out] Pointer to a PROCESSENTRY32 structure.

Return Values

Returns TRUE if the next entry of the process list has been copied to the buffer or FALSE otherwise. The ERROR_NO_MORE_FILES error value is returned by the GetLastError function if no processes exist or the snapshot does not contain process information.

Remarks

To retrieve information about the first process recorded in a snapshot, use the Process32First function.

[PROCESSENTRY32]

PROCESSENTRY32 describes an entry from a list that enumerates the processes residing in the system address space when a snapshot was taken.

typedef struct tagPROCESSENTRY32 {
DWORD dwSize;
DWORD cntUsage;
DWORD th32ProcessID;
ULONG_PTR th32DefaultHeapID;
DWORD th32ModuleID;
DWORD cntThreads;
DWORD th32ParentProcessID;
LONG pcPriClassBase;
DWORD dwFlags;
TCHAR szExeFile[MAX_PATH];

} PROCESSENTRY32, *PPROCESSENTRY32;

Members

dwSize
Size of the structure, in bytes. Before calling the Process32First function, set this member to sizeof (PROCESSENTRY32). If you do not initialize dwSize, Process32First will fail.

cntUsage
Number of references to the process. A process exists as long as its usage count is nonzero. As soon as its usage count becomes zero, a process terminates.

th32ProcessID
Identifier of the process.

th32DefaultHeapID
Identifier of the default heap for the process. The contents of this member has meaning only to the tool help functions. It is not a handle, nor is it usable by functions other than the ToolHelp functions.

th32ModuleID
Module identifier of the process. The contents of this member has meaning only to the tool help functions. It is not a handle, nor is it usable by functions other than the ToolHelp functions.

cntThreads
Number of execution threads started by the process.

th32ParentProcessID
Identifier of the process that created the process being examined.

pcPriClassBase
Base priority of any threads created by this process
.
dwFlags
Reserved; do not use.

szExeFile
Pointer to a null-terminated string that specifies the name of the executable file for the process.

Windows Me/98/95: The file name includes the path.

[GetCurrentProcessId]

The GetCurrentProcessId function returns the process identifier of the calling process.

DWORD GetCurrentProcessId(VOID)

Parameters

This function has no parameters.

Return Value

The return value is the process identifier of the calling process.

Remarks

Until the process terminates, the process identifier uniquely identifies the process throughout the system.

Here our target is the parent procces of our program.We check if the parent process is OllyDbg.

The plan:

1.) Get the ProcessId of our program using GetCurrentProcessId .
2.) Begin a loop of CreateToolhelp32Snapshot and Process32First/Next and compare every th32ProcessID member of the PROCESSENTRY32 structure with our ProcessId from GetCurrentProcessId till we find it.
3.) Get the value of the th32ParentProcessID member of the PROCESSENTRY32.
4.) Begin a new CreateToolhelp32Snapshot and Process32First/Next loop, but this time compare the th32ProcessID member with the th32ParentProcessID, which we got in 3.) till we find it.
5.) Go to the szExeFile member of the PROCESSENTRY32 and scan the name string for "Ollydbg.exe"
6.) If we find it we will know that our program is running under OllyDbg.

And here is my example:

.586
.model flat, stdcall
option casemap:none
include d:\masm32\INCLUDE\Windows.inc
include d:\masm32\INCLUDE\user32.inc
include d:\masm32\INCLUDE\kernel32.inc
includelib d:\masm32\lib\user32.lib
includelib d:\masm32\lib\kernel32.lib

.data
strCaption db "OllyDbg Detector!",0
strFound db "OllyDbg found!",0
strNotFound db "OllyDbg NOT found!",0
strOllyDbg db "OLLYDBG.EXE",0h
valCurrentPiD dd 0
valParentPiD dd 0
hSnapShot dd 0

.data?
proces PROCESSENTRY32 <>

.code
start:
; Create the snapshot
invoke CreateToolhelp32Snapshot, TH32CS_SNAPPROCESS,NULL
mov hSnapShot,eax

;Get the ProcessId of the Current Process
invoke GetCurrentProcessId
mov valCurrentPiD,eax

lea esi,offset proces
assume esi:ptr PROCESSENTRY32
mov [esi].dwSize,sizeof PROCESSENTRY32

;Begin the first Loop and find the current process
;using the valCurrentPiD
invoke Process32First,hSnapShot,addr proces

lea esi,offset proces
assume esi:ptr PROCESSENTRY32
mov ebx,valCurrentPiD

cmp ebx,[esi].th32ProcessID
jne nope1

nope1:
invoke Process32Next,hSnapShot,addr proces

lea esi,offset proces
assume esi:ptr PROCESSENTRY32

mov ebx,valCurrentPiD
cmp ebx,[esi].th32ProcessID
jne nope1

push [esi].th32ParentProcessID
pop valParentPiD
invoke CloseHandle,hSnapShot

; Create the snapshot again
invoke CreateToolhelp32Snapshot, TH32CS_SNAPPROCESS,NULL
mov hSnapShot,eax

mov [esi].dwSize,sizeof PROCESSENTRY32

; Begin the second Loop and find the parent
; process using the valParentPiD
invoke Process32First,hSnapShot,addr proces

lea esi,offset proces
assume esi:ptr PROCESSENTRY32
mov ebx,valParentPiD

cmp ebx,[esi].th32ProcessID
jne nope2

nope2:

invoke Process32Next,hSnapShot,addr proces
lea esi,offset proces
assume esi:ptr PROCESSENTRY32
mov ebx,valParentPiD
cmp ebx,[esi].th32ProcessID
jne nope2

; Extract filename of the Parent Process from the whole string
lea eax, [esi].szExeFile
push eax
invoke lstrlen,eax
sub eax,11
pop ebx
add ebx,eax

; Case Upper the string and compare it with "OLLYDBG.EXE"
invoke CharUpper,ebx
invoke lstrcmp,ebx,addr strOllyDbg

.IF eax==0
invoke MessageBox,0,addr strFound,addr strCaption,0
.ELSE
invoke MessageBox,0,addr strNotFound,addr strCaption,0
.ENDIF

invoke CloseHandle,hSnapShot
invoke ExitProcess,0

end start
雪    币: 411
活跃值: (1160)
能力值: ( LV9,RANK:810 )
在线值:
发帖
回帖
粉丝
David 20 2004-5-5 22:46
3
0
最初由 声声慢 发布

end start


请你翻译一下好吗,看不懂.
雪    币:
能力值: (RANK: )
在线值:
发帖
回帖
粉丝
游客 2004-5-5 22:47
4
0
Method III: SetUnhandledExceptionFilter

This is a very interesting method of detecting OllyDbg.It is based on Microsoft's SetUnhandledExceptionFilter function:

The SetUnhandledExceptionFilter function lets an application supersede the top-level exception handler that Win32 places at the top of each thread and process.

After calling this function, if an exception occurs in a process that is not being debugged, and the exception makes it to the Win32 unhandled exception filter, that filter will call the exception filter function specified by the lpTopLevelExceptionFilter parameter.

LPTOP_LEVEL_EXCEPTION_FILTER SetUnhandledExceptionFilter(

LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter // exception filter function
);

Parameters

lpTopLevelExceptionFilter
Supplies the address of a top-level exception filter function that will be called whenever the UnhandledExceptionFilter function gets control, and the process is not being debugged. A value of NULL for this parameter specifies default handling within UnhandledExceptionFilter.
The filter function has syntax congruent to that of UnhandledExceptionFilter: It takes a single parameter of type LPEXCEPTION_POINTERS, and returns a value of type LONG. The filter function should return one of the following values:

Value Meaning

EXCEPTION_EXECUTE_HANDLER
Return from UnhandledExceptionFilter and execute the associated exception handler. This usually results in process termination.

EXCEPTION_CONTINUE_EXECUTION
Return from UnhandledExceptionFilter and continue execution from the point of the exception. Note that the filter function is free to modify the continuation state by modifying the exception information supplied through its LPEXCEPTION_POINTERS parameter.

EXCEPTION_CONTINUE_SEARCH
Proceed with normal execution of UnhandledExceptionFilter . That means obeying the SetErrorMod flags, or invoking the Application Error pop-up message box.

Return Value

The SetUnhandledExceptionFilter function returns the address of the previous exception filter established with the function. A NULL return value means that there is no current top-level exception handler.

Remarks

Issuing SetUnhandledExceptionFilter replaces the existing top-level exception filter for all existing and all future threads in the calling process.
The exception handler specified by lpTopLevelExceptionFilter is executed in the context of the thread that caused the fault. This can affect the exception handler's ability to recover from certain exceptions, such as an invalid stack.

So.The main idea is that we set an exception filter with this api function.After that we cause a small and shy exception.If you have read the blue paragraph you will understand that if the program is debugged the exception will not be passed to the exception handler.We will use exactly this! The debugger will not know what to do and the program will crash! If the program is running standalone it will work normally.

What do i understand under normally? It will enter the Exception Handler, in there it will change the EIP value from the context structure with the address of the next safe command, which will be used to continue the program from there.Before I give you my example I will need to explain you the basic of Exception Handling.When the program enters the Exception Handler the stack looks like this:

[ Return EiP ]
[ Pointer to EXCEPTION_POINTERS structure ]
[ ... ]
[ ... ]

And the EXCEPTION_POINTERS structure is defined like this:

EXCEPTION_POINTERS STRUCT
pExceptionRecord DWORD ?
ContextRecord DWORD ?
EXCEPTION_POINTERS ENDS

What we need from it is the ContextRecord pointer.Which points to the CONTEXT structure:

CONTEXT STRUCT
ContextFlags DWORD ?
iDr0 DWORD ?
iDr1 DWORD ?
iDr2 DWORD ?
iDr3 DWORD ?
iDr6 DWORD ?
iDr7 DWORD ?
FloatSave FLOATING_SAVE_AREA <>
regGs DWORD ?
regFs DWORD ?
regEs DWORD ?
regDs DWORD ?
regEdi DWORD ?
regEsi DWORD ?
regEbx DWORD ?
regEdx DWORD ?
regEcx DWORD ?
regEax DWORD ?
regEbp DWORD ?
regEip DWORD ?
regCs DWORD ?
regFlag DWORD ?
regEsp DWORD ?
regSs DWORD ?
ExtendedRegisters db MAXIMUM_SUPPORTED_EXTENSION dup(?)
CONTEXT ENDS

At the end of the handler EAX must contain the value which tells Windows what to do next.For us this will be:

EXCEPTION_CONTINUE_EXECUTION equ -1

So here is the plan of the protection:

1.) Install the Exception Handler using the SetUnhandledExceptionFilter Api
2.) Cause exception and go to the Exception Handler only if there is not a debugger.
3.) In the handler - get from stack the pointer to the EXCEPTION_POINTERS structure
4.) Get from the EXCEPTION_POINTERS structure the pointer to the CONTEXT structure
5.) Change the regEip member of the CONTEXT to the safe address, from where the program will continue
6.) Set the EXCEPTION_CONTINUE_EXECUTION flag in EAX
7.) Normalize stack and continue to safe address

And here is the example:

.586
.model flat, stdcall
option casemap:none

include d:\masm32\INCLUDE\Windows.inc
include d:\masm32\INCLUDE\user32.inc
include d:\masm32\INCLUDE\kernel32.inc
includelib d:\masm32\lib\user32.lib
includelib d:\masm32\lib\kernel32.lib

.data
strCaption db "OllyDbg Detector",0
strNotFound db "OllyDbg NOT found!",0

.code
ExcpHandler proc
mov eax, dword ptr [esp+4] ; eax = EXCEPTION_POINTERS
mov eax, [eax+4] ; eax = CONTEXT

assume eax:ptr CONTEXT
mov [eax].regEip, offset safe_address ; Change regEip
pushad
invoke MessageBox,0,addr strNotFound,addr strCaption,0
popad
xor eax, eax ;\
; ) Set EXCEPTION_CONTINUE_EXECUTION
dec eax ;/

retn 4 ; Normalize stack and return
ExcpHandler endp

start:
invoke SetUnhandledExceptionFilter,offset ExcpHandler

mov ebx,dword ptr [0FFFFFFFFh] ;Exception is here!

safe_address:
invoke ExitProcess,0

end start

Method IV: APi Redirection
One of my own tricks.It is based on the way OllyDbg handles called api functions.Oleh Yuschuk (the author of OllyDbg) has decided to use total api redirection in his debugger, when the debugged program is calling an api function.Here is an example:

00401000 >PUSH ASD.00403033 ; /FileName = "kernel32.dll"
00401005 CALL ; \LoadLibraryA
|
|
'--> 0040105C JMP DWORD PTR DS:[402004] ; JMP DWORD PTR DS:[<&KERNEL32.LoadLibraryA>]
|
|
'--> 87FF4120 PUSH BFF776D0 ; PUSH KERNEL32.LoadLibraryA
87FF4125 JMP KERNEL32.BFF957CA

So it seems that he manually loads the Import Table and manually fills the IAT, where all api addresses are redirected to an allocated buffer.In this buffer he calls the api functions in a strange way.But there is one more thing, more important for us.He also emulates (?) the GetProcAddress function so it returnes redirected addresses.For example the real address of IsDebuggerPresent in memory is BFF946F6, but the function returns 87FF4110, which is the redirected address.How are we going to use this as OllyDbg detection trick? Well in many ways.I will give you the shortest.

The plan:

1.) Load the kernel32.dll Library, which will return its Image Base (the location where it is loaded in memory)
2.) Call GetProcAddress for function ExitProcess
3.) Compare the return value (address of api function) from GetProcAddress with the Image Base of kernel32.dll
4.) If it is greater than the Image Base we will be sure that the api function is called directly from kernel32.dll.Else we will be sure that there is api redirection.

The example:

.586
.model flat, stdcall
option casemap:none

include d:\masm32\INCLUDE\Windows.inc
include d:\masm32\INCLUDE\user32.inc
include d:\masm32\INCLUDE\kernel32.inc
includelib d:\masm32\lib\user32.lib
includelib d:\masm32\lib\kernel32.lib

.data
strCaption db "OllyDbg Detector",0
strFound db "OllyDbg found!",0
strNotFound db "OllyDbg NOT found!",0
strLibrary db "kernel32.dll",0
strFunction db "ExitProcess",0

.code
start:
invoke LoadLibrary,addr strLibrary
push eax ; eax = kernel32.dll's Image Base

invoke GetProcAddress,eax,addr strFunction
; eax = ExitProcess's address or redirector ?
; ebx = kernel32.dll's Image Base

pop ebx
cmp eax,ebx ; Address of ExitProcess < Kernel32.dll's
; Image Base ?
jl Olly_Detected
invoke MessageBox,0,addr strNotFound,addr strCaption,NULL
invoke ExitProcess,0

Olly_Detected:
invoke MessageBox,0,addr strFound,addr strCaption,NULL
invoke ExitProcess,0

end start

Final Words

Hope you enjoyed reading this.Greeting, Pumqara.

Many have heard of the IsDebbugerPresent and of the fs:[20] detecting tricks, but what about some other new ones? Here I will present you the other wasy to detect OllyDbg.

detect,ollydbg,pumqara,protection,protect,debugger,ring3
雪    币:
能力值: (RANK: )
在线值:
发帖
回帖
粉丝
游客 2004-5-5 23:04
5
0
David,
我刚开始翻译,却发现文章很长, 我没有勇气继续下去,也怕会词不达意啊... :(
雪    币: 896
活跃值: (4039)
能力值: ( LV9,RANK:3410 )
在线值:
发帖
回帖
粉丝
fly 85 2004-5-5 23:06
6
0
thanks

麻烦 声声慢 有空时翻译一下吧  :D
雪    币: 411
活跃值: (1160)
能力值: ( LV9,RANK:810 )
在线值:
发帖
回帖
粉丝
David 20 2004-5-5 23:45
7
0
最初由 声声慢 发布
David,
我刚开始翻译,却发现文章很长, 我没有勇气继续下去,也怕会词不达意啊... :(


众望所归,声兄就不要推辞了.
雪    币: 2367
活跃值: (756)
能力值: (RANK:410 )
在线值:
发帖
回帖
粉丝
小虾 10 2004-5-6 00:12
8
0
~~晕,全是E文,看不懂???
雪    币: 674
活跃值: (1684)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
daxia200N 6 2004-5-6 13:44
9
0
谢谢,有时间帮着翻译一下
雪    币:
能力值: (RANK: )
在线值:
发帖
回帖
粉丝
游客 2004-5-6 19:27
10
0
各位朋友,
真对不起让大家失望了,不是我懒,这篇文章对我来说,真的挺难,有太多的计算机技术词汇,我都不知道如何翻译。。。
声声慢
雪    币: 213
活跃值: (96)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
云重 1 2004-5-6 23:42
11
0
都翻工作量是不小.我是不太敢翻译,怕人笑.其实俄语英语我都能找到专业翻译,不过他们只是翻译不是学计算机的让人家翻这个东西不好意思.也不是很恰当,我翻译水平也不好,不如一人部分如何?这里人这么多,
雪    币: 213
活跃值: (96)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
云重 1 2004-5-7 00:36
12
0
Method I: FindWindow
This method is based on the FindWindows function.As all dialogs the OllyDbg's main dialog
(window ?) has its caption and Class name.Using this Api we will try to find if the OllyDbg's main window is opened.Microsoft wrote:

方法1 :FindWindow
这个方法是在使用Findwindow函数基础上的。 与所有对话框一样 OllyDbg的主对话框(或者说主窗口)
有它的窗口标题和窗口类名称。如果OllyDbg的主窗口已经打开,用这个API函数我们将能设法找到它。
微软写的资料(函数功能)

The FindWindow function retrieves the handle of the top-level window whose class name and window name match the specified strings. This function does not search child windows

这个FindWindow 函数返回值是一个顶层窗口的句柄,该窗口的类名和窗口名与给定的字符串相匹配。这个函数不查找子窗口。(注意: 在查找时不区分大小写。)

HWND FindWindow(

LPCTSTR lpClassName, // address of class name 窗口类名的地址。//我理解为是指向字符串的指针
LPCTSTR lpWindowName // address of 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.
指向一个指定了类名的空结束字符串,或一个标识类名字符串的成员的指针。如果该参数为一个成员,则它必须为前次调用theGlobafAddAtom函数产生的全局成员。该成员为16位,必须位于IpClassName的低 16位,高位必须为 0。

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 Value
If the function succeeds, the return value is the handle of 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

返回值
如果函数成功,返回值为具有指定类名和窗口名的窗口句柄;如果函数失败,返回值为NULL。如果你想获得更多错误信息,请调用GetLastError函数。

And my code snippet is:
以下是我的部分代码:

.data 数据定义
strOllyClsName db "OLLYDBG",0     ;字符串定义也就是 OLLYDBG的窗口类名

.code
invoke FindWindow, ADDR strOllyClsName, NULL   ;第2个参数是NULL表示接收任何窗口标题
cmp eax, 00000000h   ;比较函数返回值,如果eax-0 后ZF 标志被置1说明没有OLLYDBG调试器运行
jne Olly_Detected/   ;不相等说明EAX里面是句柄,请跳到你自己写的对付OLLYDBG代码,是停止运行还是破坏自己去想吧
雪    币:
能力值: (RANK: )
在线值:
发帖
回帖
粉丝
游客 2004-5-7 15:14
13
0
谢谢云重,毕竟是学计算机的,这么快。
我琢磨了半天也不知道null-terminated string 等词怎么译。
雪    币: 207
活跃值: (40)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
StudentII 2004-5-7 17:52
14
0
文章中说的四种方案中最后一种对2k(xp)无效。第一方案很低级,不信看看fly大虾的脱文http://bbs.pediy.com/showthread.php?s=&threadid=307就清楚了;第二种方案在acproctet里已经用烂了;第三种方案只要监视SetUnhandledExceptionFilter就能应付,有点像对付IsDebugPresent。
雪    币: 213
活跃值: (96)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
云重 1 2004-5-7 18:54
15
0
其实技术就是这么回事本来就没什么,现在回忆小学很简单吧,但是为什么你还要读6年呢,直接读高中算了,不过是一个成长过程而已,每个资料和书籍都有潜在的读者群,你认为数学家会看高中的数奥书吗,其实上面的几种方法都很简单,不过是给特定阶段水平人看的东西,但是我不希望大学毕业的人说小学的东西简单,没用,没必要学.这个论坛的人水平差距很大,难的东西初学者不会看,简单的吧水平高的不会看.其实熟悉这些东西的或者说玩烂了的东西不是你一个人,互相照顾点,不要辜负声声慢的好心,其实后几种方法我也没翻译的必要,本来我就掌握.不过温故知新是良好的学习习惯.认为主题健康向上的就支持下.(@_@)(#_#) ;

寻寻觅觅,
冷冷清清,
??惨惨戚戚。
乍暖还寒时侯,
最难将息。
三杯两盏淡酒,
怎敌他、
晚来风急?
雁过也,
正伤心,
却是旧时相识。
雪    币: 513
活跃值: (2228)
能力值: ( LV9,RANK:2130 )
在线值:
发帖
回帖
粉丝
loveboom 53 2004-5-7 19:08
16
0
支持归支持(说支持我100个支持的说),技术归技术,说白一点,这样的东西一点也不新鲜,这篇文章里全部anti ring3级调试器的方法,我都遇过,意思就是说,不是新鲜事来的,没什么价值。倒是xport还是比较神秘的说,不知什么时候有只巨牛能揭开它的面纱。
雪    币: 279
活跃值: (435)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
MengLong 6 2004-5-7 19:42
17
0
好像没翻译完呢。继续啊。基础的知识是要的,不要因为有人会了就不讲了。
还有很多不会的人呢。教教初学者有什么不好呢?
雪    币: 207
活跃值: (40)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
StudentII 2004-5-7 20:43
18
0
哇,一不小心得罪大虾了,我可不是那个意思的。

其实何必那么伤感,我还是比较喜欢:

生当作人杰,死亦为鬼雄。
雪    币: 126
活跃值: (48)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
zhouzhen 1 2004-5-7 21:43
19
0
呵呵。翻译一下。看不太懂。
雪    币: 279
活跃值: (375)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
lordor 6 2004-5-8 11:47
20
0
要翻译,用google试一下,可以转换好几种语言,不过专业术语就不行了
雪    币: 227
活跃值: (164)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
damen 2004-5-8 17:36
21
0
assume eax:ptr context
都变形了。
都变成表情符号了。
游客
登录 | 注册 方可回帖
返回