软件保护壳技术专题 - 反调试器技术

《Windows核心编程》读书笔记十七章 内存映射文件 第十七章 内存映射文件 本章内容 17.1 映射到内存的可执行文件和DLL 17.2 映射到内存的数据文件 17.3 使用内存映射文件 17.4 用内存映射文件来处理大文件 17.5 内存映射文件和一致性 17.6 给内存映射文件制定基地址 17.7 内存映射文件的实现细节 17.8 用内存映射文件在进程间共享数据 17.9 以页交换文件为后备存储器的内存映射文件 17.10 阅读详情

 作 者: 玩命
时 间: 2008-08-21,10:38
链 接: http://bbs.pediy.com/showthread.php?t=71113

反调试是软件保护壳的最基本的功能之一。
反调试方法也是多种多样。通过调用标准的API接口,计算指令时间差。查看当调试器加载后的
内存的一些标志,还有就是判断当前运行环境是否合乎逻辑等方法。这里收集了一些反调试的方法,其中的命名规则使用了壳狼的反调试程序的方式,希望不要和我收取版权的费用。^_^,其中借鉴了不少壳狼的函数。增加了一些,也删除了一些。大部分的参考资料来自<<脱壳的艺术>>,<<Anti-UnPacker Tricks>>与<<加密与解密第三版>>。
这里要说明的一点是。每个函数编写都是自己建立堆栈了,看的不习惯的多看下就习惯了 呵呵。
原因也很简单,MASM不允许在函数内定义函数了。
这些函数还有一个要讲的是。因为最后这些函数要在以后的章节中用到
为了能允许用户自定义反调试的功能。免去重定位的麻烦,所以
利用栈传递了API集合地址和外部函数集合的地址。
朋友们还是先看代码了。。。


利用IsDebuggerPresent确定是否存在,IsDebuggerPresent是WIN提供的一个标准调试API
用于确定是否存在调试器。这个方法很简单TRUE为存在,FASLE则为不存在。

代码:
FD_IsDebuggerPresent:
FD_IsDebugger_Arg_Win32Api      equ 04h
    mov eax, dword ptr [esp+FD_IsDebugger_Arg_Win32Api]
    assume eax : ptr WIN32APIBASE
    call dword ptr [eax].xIsDebuggerPresent
Exit_FD_IsDebuggerPresent:
    assume eax : nothing
    retn 04h
End_FD_IsDebuggerPresent:

我们更进一步的剖析IsDebuggerPresent函数,逆向它后即可得知。
这个函数读取当前进程的PEB中的BeingDebugger标志。
如果确定这个标志呢?
当进程加载的时候FS寄存器总是被设置成当前线程的TEB。这下就都OK
而在TEB的30h偏移处就是ProcessEnvironmentBlock了。
而PEB的偏移02h出就是BeingDebugged了。当BeingDebugger为0则没有调试器
不为0时则存在调试器。

代码:
FD_PEB_BeingDebuggedFlag:
    assume fs : nothing
    mov eax, fs:[30h]   ; eax = TEB.ProcessEnvironmentBlock
    inc eax
    inc eax
    mov eax, dword ptr [eax]
    and eax, 000000FFh  ; al = PEB.BeingDebugged
    test eax, eax
    jnz FD_PEB_BeingDebuggedFlag_Found
Exit_PEB_BeingDebuggedFlag:
    retn 0    
FD_PEB_BeingDebuggedFlag_Found:
    mov eax, 1
    jmp  Exit_PEB_BeingDebuggedFlag
End_FD_PEB_BeingDebuggedFlag:

在当BeingDebugged被设置为TRUE时,存在与PEB中的
NtGlobalFlag也会做出相应的改变。查看WIN2K代码的LdrpInitialize
会发现以下代码
if (Peb->BeingDebugged)
Peb->NtGlobalFlag |= ***_HEAP_ENABLE_FREE_CHECK |
                     ***_HEAP_ENABLE_TAIL_CHECK |
                     ***_HEAP_VALIDATE_PARAMETERS;
这个组合值为70h。所以我们又得到一个反调试的函数

代码:
FD_PEB_NtGlobalFlags:
    assume fs : nothing
    mov eax, fs:[30h]
    mov eax, dword ptr [eax+68h]
    and eax, 070h
    test eax, eax
    jnz FD_PEB_NtGlobalFlags_Found
Exit_FD_PEB_NtGlobalFlags:
    retn 0
FD_PEB_NtGlobalFlags_Found:
    mov eax, 1
    jmp  Exit_FD_PEB_NtGlobalFlags
End_FD_PEB_NtGlobalFlags:

BeingDebugger标志还会影响ProcessHeap.Flags
如果这个标志不为0则存在调试器。

代码:
FD_Heap_ForceFlags:
    assume fs : nothing
    mov eax, fs:[30h]
    mov eax, dword ptr [eax+18h]    ; PEB.ProcessHeap
    mov eax, dword ptr [eax+10h]    ; PEB.ProcessHeap.Flags
    test eax, eax
    jnz Found_FD_Heap_ForceFlags
Exit_FD_Heap_ForceFlag:
    retn 0
Found_FD_Heap_ForceFlags:
    mov eax, 1
    jmp Exit_FD_Heap_ForceFlag           
End_FD_Heap_ForceFlags:

在BeingDebugger下ProcessHeap.ForceFlags也受到影响
如果不为2则存在调试器。细节部分可以查看WIN2K的代码。
由于版本影响这里就不给出其中的代码了。

代码:
FD_Heap_HeapFlags:
    assume fs : nothing
    mov eax, fs:[30h]
    mov eax, dword ptr [eax+18h]    ; PEB.ProcessHeap
    mov eax, dword ptr [eax+0ch]    ; PEB.ProcessHeap.ForceFlags
    cmp eax, 2
    jnz Found_FD_Heap_HeapFlags
Exit_FD_Heap_HeapFlags:
    retn 0  
Found_FD_Heap_HeapFlags:
    mov eax, 1
    jmp Exit_FD_Heap_HeapFlags  
End_FD_Heap_HeapFlags:

通过另一个API。CheckRemoteDebuggerPresent,这个API可以检测任何进程是否被调试器
加载。这里通过GetCurrentProcess取得自身进程的句柄。进行鉴别

代码:
FD_CheckRemoteDebuggerPresent:
FD_CheckRemoteDebuggerPresent_Arg_Win32Api    equ 04h
    mov eax, dword ptr [esp+FD_CheckRemoteDebuggerPresent_Arg_Win32Api]
    assume eax : ptr WIN32APIBASE
    push esp
    push esp
    call dword ptr [eax].xGetCurrentProcess
    push eax
    call dword ptr [eax].xCheckRemoteDebuggerPresent
    pop esp
    assume eax : nothing
    retn 04h
End_FD_CheckRemoteDebuggerPresent:

如果逆向了CheckRemoteDebuggerPresent函数就可以明白,其实最终它是调用
NtQueryInformationProcess,查询进程的ProcessDebugPort。此值是用来维持系统
与调试器通讯的,在程序被调试器加载时系统会设置这个值为非0。

代码:
FD_NtQueryInfoProc_DbgPort:
FD_NtQueryInfoProc_DbgPort_Arg_Win32Api    equ 08h
FD_NtQueryInfoProc_DbgPort_StackSize    equ sizeof PROCESS_DEBUG_PORT_INFO
FD_NtQueryInfoProc_DbgPort_ProcessInfo  equ -(FD_NtQueryInfoProc_DbgPort_StackSize)
    push ebp
    mov ebp, esp
    sub esp, FD_NtQueryInfoProc_DbgPort_StackSize
    
    push ebx
    
    mov ebx, dword ptr [ebp+FD_NtQueryInfoProc_DbgPort_Arg_Win32Api]
    assume ebx : ptr WIN32APIBASE
    
    push NULL
    push sizeof PROCESS_DEBUG_PORT_INFO
    lea eax, [ebp+FD_NtQueryInfoProc_DbgPort_ProcessInfo]
    push eax
    push ProcessDebugPort
    call dword ptr [ebx].xGetCurrentProcess
    push eax
    call dword ptr [ebx].xZwQueryInformationProcess
    test eax, eax
    jnz FD_NtQueryInfoProc_DbgPort_Tmp1
    lea eax, [ebp+FD_NtQueryInfoProc_DbgPort_ProcessInfo]
    assume eax : ptr PROCESS_DEBUG_PORT_INFO
    mov eax, dword ptr [eax].DebugPort
    test eax, eax
    jnz Found_FD_NtQueryInfoProc_DbgPort
FD_NtQueryInfoProc_DbgPort_Tmp1:
    xor eax, eax
Exit_FD_NtQueryInfoProc_DbgPort:
    assume eax : nothing
    assume ebx : nothing
    
    pop ebx
    
    mov esp, ebp
    pop ebp
    retn 04h
Found_FD_NtQueryInfoProc_DbgPort:
    mov eax, 1
    jmp Exit_FD_NtQueryInfoProc_DbgPort         
End_FD_NtQueryInfoProc_DbgPort:

当Windows系统创建一个调试会话开始,一个调试对象也被创建并产生一个
调试句柄。我们可以查询这个句柄的值来确定是否存在调试器。

代码:
FD_NtQueryInfoProc_DbgObjHandle:
FD_NtQueryInfoProc_DbgObjHandle_Arg_Win32Api    equ 08h
FD_NtQueryInfoProc_DbgObjHandle_StackSize        equ sizeof PROCESS_DEBUG_OBJECTHANDLE_INFO
FD_NtQueryInfoProc_DbgObjHandle_ProcessInfo     equ -(FD_NtQueryInfoProc_DbgObjHandle_StackSize)
    push ebp
    mov ebp, esp
    sub esp, FD_NtQueryInfoProc_DbgObjHandle_StackSize
    
    push ebx
    mov ebx, dword ptr [ebp+FD_NtQueryInfoProc_DbgObjHandle_Arg_Win32Api]
    assume ebx : ptr WIN32APIBASE
    
    push NULL
    push sizeof PROCESS_DEBUG_OBJECTHANDLE_INFO
    lea eax, [ebp+FD_NtQueryInfoProc_DbgObjHandle_ProcessInfo]
    push eax    
    push SystemNotImplemented8
    call dword ptr [ebx].xGetCurrentProcess
    push eax
    call dword ptr [ebx].xZwQueryInformationProcess
    test eax, eax
    jnz FD_NtQueryInfoProc_DbgObjHandle_Tmp1
    lea eax, [ebp+FD_NtQueryInfoProc_DbgObjHandle_ProcessInfo]
    assume eax : ptr PROCESS_DEBUG_OBJECTHANDLE_INFO
    mov eax, dword ptr [eax].ObjectHandle
    test eax, eax
    jnz Found_FD_NtQueryInfoProc_DbgObjHandle
FD_NtQueryInfoProc_DbgObjHandle_Tmp1:
    xor eax, eax
Exit_FD_NtQueryInfoProc_DbgObjHandle:

    assume eax : nothing
    assume ebx : nothing
    
    pop ebx
    
    mov esp, ebp
    pop ebp
    retn 04h
Found_FD_NtQueryInfoProc_DbgObjHandle:
    mov eax, 1
    jmp Exit_FD_NtQueryInfoProc_DbgObjHandle
End_FD_NtQueryInfoProc_DbgObjHandle:

也可以通过使用ZwQueryInformationProcess函数,利用SystemNotImplemented9(1fh)
返回的PROCESS_DEBUG_FLAGS_INFO结构,如果DebugFlags返回0则检测到调试器。返回非0
则没发现调试器。

代码:
FD_NtQueryInfoProc_DbgFlags:
FD_NtQueryInfoProc_DbgFlags_Arg_Win32Api    equ 08h
FD_NtQueryInfoProc_DbgFlags_StackSize    equ sizeof PROCESS_DEBUG_FLAGS_INFO
FD_NtQueryInfoProc_DbgFlags_ProcessInfo  equ -(FD_NtQueryInfoProc_DbgFlags_StackSize)
    push ebp
    mov ebp, esp
    sub esp, FD_NtQueryInfoProc_DbgFlags_StackSize
    
    push ebx
    
    mov ebx, dword ptr [ebp+FD_NtQueryInfoProc_DbgFlags_Arg_Win32Api]
    assume ebx : ptr WIN32APIBASE
    
    push NULL
    push sizeof PROCESS_DEBUG_FLAGS_INFO
    lea eax, [ebp+FD_NtQueryInfoProc_DbgFlags_ProcessInfo]
    push eax    
    push SystemNotImplemented9
    call dword ptr [ebx].xGetCurrentProcess
    push eax
    call dword ptr [ebx].xZwQueryInformationProcess
    test eax, eax
    jnz FD_NtQueryInfoProc_DbgFlags_Tmp1
    lea eax, [ebp+FD_NtQueryInfoProc_DbgFlags_ProcessInfo]
    assume eax : ptr PROCESS_DEBUG_FLAGS_INFO
    mov eax, dword ptr [eax].DebugFlags
    test eax, eax
    jz Found_FD_NtQueryInfoProc_DbgFlags
FD_NtQueryInfoProc_DbgFlags_Tmp1: 
    xor eax, eax
Exit_FD_NtQueryInfoProc_DbgFlags:
    assume eax : nothing
    assume ebx : nothing
    
    pop ebx
    
    mov esp, ebp
    pop ebp
    retn 04h
Found_FD_NtQueryInfoProc_DbgFlags:
    mov eax, 1
    jmp Exit_FD_NtQueryInfoProc_DbgFlags
End_FD_NtQueryInfoProc_DbgFlags:

如果Windows以调试方式启动,并与系统调试器建立通讯。
通过ZwQuerySystemInformation对SystemKernelDebuggerInformation进行查询
系统中是否存在系统调试器。

代码:
FD_NtQueryInfoProc_SysKrlDbgInfo:
FD_NtQueryInfoProc_SysKrlDbgInfo_Arg_Win32Api    equ 08h
FD_NtQueryInfoProc_SysKrlDbgInfo_StackSize      equ sizeof PROCESS_DEBUG_FLAGS_INFO
FD_NtQueryInfoProc_SysKrlDbgInfo_Info           equ -(sizeof PROCESS_DEBUG_FLAGS_INFO)
    push ebp
    mov ebp, esp
    sub esp, FD_NtQueryInfoProc_SysKrlDbgInfo_StackSize
    
    push ebx
    
    mov ebx, dword ptr [ebp+FD_NtQueryInfoProc_SysKrlDbgInfo_Arg_Win32Api]
    assume ebx : ptr WIN32APIBASE
    
    push NULL
    push sizeof PROCESS_DEBUG_FLAGS_INFO
    lea eax, [ebp+FD_NtQueryInfoProc_SysKrlDbgInfo_Info]
    push eax    
    push SystemKernelDebuggerInformation
    call dword ptr [ebx].xGetCurrentProcess
    push eax
    call dword ptr [ebx].xZwQuerySystemInformation
    test eax, eax
    jnz FD_NtQueryInfoProc_SysKrlDbgInfo_Tmp1
    lea eax, [ebp+FD_NtQueryInfoProc_SysKrlDbgInfo_Info]
    assume eax : ptr PROCESS_DEBUG_FLAGS_INFO
    mov eax, dword ptr [eax].DebugFlags
    test eax, eax
    jz Found_FD_NtQueryInfoProc_SysKrlDbgInfo
FD_NtQueryInfoProc_SysKrlDbgInfo_Tmp1:    
    xor eax, eax
Exit_FD_NtQueryInfoProc_SysKrlDbgInfo:
    assume eax : nothing
    assume ebx : nothing
    
    pop ebx
    
    mov esp, ebp
    pop ebp
    retn 04h
Found_FD_NtQueryInfoProc_SysKrlDbgInfo:
    mov eax, 1
    jmp Exit_FD_NtQueryInfoProc_SysKrlDbgInfo
End_FD_NtQueryInfoProc_SysKrlDbgInfo:

当调试会话被创建,这个标志会影响堆的创建。初始化中的堆内存填充了
很多类似0ABABABABh,0BAADF00Dh,0FEEEFEEEh这三个值。可以通过检测内存看
是否存在过多的这样值。判断调试器的存在,而正常启动的程序则不会被填充。

代码:
FD_Heap_Magic:
FD_Heap_Magic_Arg_Win32Api        equ 04h
    mov eax, dword ptr [esp+FD_Heap_Magic_Arg_Win32Api]
    
    push ebx
    push ecx
    push edx
    push esi
    push edi
    
    mov ebx, eax
    assume ebx : ptr WIN32APIBASE
    
    push 100h
    push NULL
    call dword ptr [ebx].xGetProcessHeap
    mov edi, eax    ; HeapHandle
    push eax
    call dword ptr [ebx].xHeapAlloc
    mov esi, eax    ; HeapMem
    xor ecx, ecx
    mov edx, 100h
    cld
    FD_Heap_Magic_Loop:
    lodsd
    cmp eax, 0ABABABABh
    jnz FD_Heap_Magic_Tmp1
    inc ecx
    FD_Heap_Magic_Tmp1:
    cmp eax, 0BAADF00Dh
    jnz FD_Heap_Magic_Tmp2
    inc ecx        
    FD_Heap_Magic_Tmp2:
    cmp eax, 0FEEEFEEEh
    jnz FD_Heap_Magic_Tmp3
    inc ecx
    FD_Heap_Magic_Tmp3:
    sub edx, 04h
    jnz FD_Heap_Magic_Loop
    push ecx    
    ;; free heap
    push esi
    push HEAP_NO_SERIALIZE
    push edi
    call dword ptr [ebx].xHeapFree
    pop ecx
    ;; judge count
    cmp ecx, 10h
    jae Found_FD_Heap_Magic
    xor eax, eax
Exit_FD_Heap_Magic:    
    pop edi    
    pop esi
    pop edx
    pop ecx
    pop ebx
    assume ebx : nothing
    retn 04h
Found_FD_Heap_Magic:
    mov eax, 1
    jmp Exit_FD_Heap_Magic
End_FD_Heap_Magic:

一般程序是没有被设置SeDebugPrivilege,如果一个当前进程被设置SeDebugPrivilege后
它就拥有了完全控制CSRSS.EXE的权限。通过进程表快照取得CSRSS.EXE进程的PID,之后
通过OpenProcess以PROCESS_ALL_ACCESS打开。开是否能打开此进程。

代码:
FD_SeDebugPrivilege:
FD_SeDebugPrivilege_Arg_Win32Api    equ 08h
FD_SeDebugPrivilege_StackSize       equ 10h + sizeof PROCESSENTRY32
FD_SeDebugPrivilege_hProcessSnap    equ -04h
FD_SeDebugPrivilege_PID_csrss       equ -08h
FD_SeDebugPrivilege_FingFlag        equ -0ch
FD_SeDebugPrivilege_pe32            equ -(10h+sizeof PROCESSENTRY32)
    push ebp
    mov ebp, esp
    sub esp, FD_SeDebugPrivilege_StackSize
    
    push ebx
    push ecx
    push edi
    
    ;; clear stack
    lea edi, [ebp-FD_SeDebugPrivilege_StackSize]
    mov ecx, FD_SeDebugPrivilege_StackSize
    xor eax, eax
    cld
    rep stosb
    
    mov ebx, dword ptr [ebp+FD_SeDebugPrivilege_Arg_Win32Api]
    assume ebx : ptr WIN32APIBASE
    
    lea edi, [ebp+FD_SeDebugPrivilege_pe32]
    assume edi : ptr PROCESSENTRY32
                     
    push 0
    push TH32CS_SNAPPROCESS
    call dword ptr [ebx].xCreateToolhelp32Snapshot
    cmp eax, INVALID_HANDLE_VALUE
    jz NotFound_FD_SeDebugPrivilege
    mov dword ptr [ebp+FD_SeDebugPrivilege_hProcessSnap], eax
    push sizeof PROCESSENTRY32
    pop dword ptr [edi].dwSize
    
    push edi
    push dword ptr [ebp+FD_SeDebugPrivilege_hProcessSnap]
    call dword ptr [ebx].xProcess32First
    test eax, eax
    jnz FD_SeDebugPrivilege_Loop
    push dword ptr [ebp+FD_SeDebugPrivilege_hProcessSnap]
    call dword ptr [ebx].xCloseHandle
    jmp NotFound_FD_SeDebugPrivilege
    
    FD_SeDebugPrivilege_Loop:
    call FD_SeDebugPrivilege_Str
        db 'CSRSS.EXE',0
    FD_SeDebugPrivilege_Str:
    lea eax, [edi].szExeFile
    push eax    
    call dword ptr [ebx].xlstrcmpiA
    test eax, eax
    jnz FD_SeDebugPrivilege_Tmp2
    push dword ptr [edi].th32ProcessID
    pop dword ptr [ebp+FD_SeDebugPrivilege_PID_csrss]
    push TRUE
    pop dword ptr [ebp+FD_SeDebugPrivilege_FingFlag]
    FD_SeDebugPrivilege_Tmp2:
    mov eax, dword ptr [ebp+FD_SeDebugPrivilege_FingFlag]
    test eax, eax
    jnz FD_SeDebugPrivilege_Tmp3
    push edi
    push dword ptr [ebp+FD_SeDebugPrivilege_hProcessSnap]
    call dword ptr [ebx].xProcess32Next
    test eax, eax
    jnz FD_SeDebugPrivilege_Loop
    
    FD_SeDebugPrivilege_Tmp3:
    mov eax, dword ptr [ebp+FD_SeDebugPrivilege_FingFlag]
    test eax, eax
    jz FD_SeDebugPrivilege_Tmp4
    push dword ptr [ebp+FD_SeDebugPrivilege_PID_csrss]
    push FALSE
    push PROCESS_QUERY_INFORMATION
    call dword ptr [ebx].xOpenProcess
    test eax, eax
    jz FD_SeDebugPrivilege_Tmp4
    push dword ptr [ebp+FD_SeDebugPrivilege_hProcessSnap]
    call dword ptr [ebx].xCloseHandle
    jmp Found_FD_SeDebugPrivilege
    FD_SeDebugPrivilege_Tmp4:
    push dword ptr [ebp+FD_SeDebugPrivilege_hProcessSnap]
    call dword ptr [ebx].xCloseHandle
    jmp NotFound_FD_SeDebugPrivilege
Exit_FD_SeDebugPrivilege:
    pop edi
    pop ecx
    pop ebx
    assume ebx : nothing
    assume edi : nothing
    mov esp, ebp
    pop ebp
    retn 04h
NotFound_FD_SeDebugPrivilege:
    xor eax, eax
    jmp Exit_FD_SeDebugPrivilege
Found_FD_SeDebugPrivilege:
    mov eax, 1
    jmp Exit_FD_SeDebugPrivilege
End_FD_SeDebugPrivilege:

通过逻辑的判断也可以找到调试器所在,一般来讲程序都是有explorer.exe进程启动的(通过双击)
如果我们的进程的父进程不是explorer.exe则发现调试器。如果有调试的名称冒名是explorer.exe
那么我们判断父进程ID后进一步判断explorer.exe进程的路径是否存在于Windows目录下。如果不是
则发现调试器。此类方法也可以也被病毒用作穿透仿真机。

代码:
FD_Parent_Process:
FD_Parent_Process_Arg_Win32Api      equ 08h
FD_Parent_Process_StackSize         equ MAX_PATH + sizeof PROCESSENTRY32 + sizeof MODULEENTRY32 + 20h
FD_Parent_Process_hParnet           equ -04h
FD_Parent_Process_PIDExplorer       equ -08h
FD_Parent_Process_PIDParent         equ -0ch
FD_Parent_Process_PIDChild          equ -10h
FD_Parent_Process_hSnapshot         equ -14h
FD_Parent_Process_pe32              equ -(20h + PROCESSENTRY32)
FD_Parent_Process_me32              equ -(20h + PROCESSENTRY32 + MODULEENTRY32)
FD_Parent_Process_lpszSystemInfo    equ -(20h + PROCESSENTRY32 + MODULEENTRY32 + MAX_PATH)
    push ebp
    mov ebp, esp
    sub esp, FD_Parent_Process_StackSize
    
    push ebx
    push ecx
    push edi
    push esi
    
    ;; clear the stack
    lea edi, [ebp-FD_Parent_Process_StackSize]
    xor eax, eax
    mov ecx, FD_Parent_Process_StackSize
    cld
    rep stosb
    
    mov ebx, dword ptr [ebp+FD_Parent_Process_Arg_Win32Api]
    assume ebx : ptr WIN32APIBASE
    lea eax, [ebp+FD_Parent_Process_pe32]
    assume eax : ptr PROCESSENTRY32
    push sizeof PROCESSENTRY32
    pop dword ptr [eax].dwSize
    
    call dword ptr [ebx].xGetCurrentProcessId
    mov dword ptr [ebp+FD_Parent_Process_PIDChild], eax
    
    push 0
    push TH32CS_SNAPPROCESS
    call dword ptr [ebx].xCreateToolhelp32Snapshot
    mov dword ptr [ebp+FD_Parent_Process_hSnapshot], eax
    
    lea eax, [ebp+FD_Parent_Process_pe32]
    push eax
    push dword ptr [ebp+FD_Parent_Process_hSnapshot]
    call dword ptr [ebx].xProcess32First
    test eax, eax
    jz FD_Parent_Process_Tmp1
    FD_Parent_Process_Loop1:
    lea eax, [ebp+FD_Parent_Process_pe32]
    push eax
    push dword ptr [ebp+FD_Parent_Process_hSnapshot]
    call dword ptr [ebx].xProcess32Next
    test eax, eax
    jz FD_Parent_Process_Tmp2
    call FD_Parent_Process_Str1
        db "EXPLORER.EXE",0
    FD_Parent_Process_Str1:
    lea eax, [ebp+FD_Parent_Process_pe32]
    lea eax, [eax].szExeFile    
    push eax
    call dword ptr [ebx].xlstrcmpiA
    jnz FD_Parent_Process_Tmp3
    mov eax, dword ptr [ebp+FD_Parent_Process_PIDExplorer]
    test eax, eax
    jnz FD_Parent_Process_Tmp3
    lea eax, [ebp+FD_Parent_Process_pe32]
    assume eax : ptr PROCESSENTRY32
    push dword ptr [eax].th32ProcessID
    pop dword ptr [ebp+FD_Parent_Process_PIDExplorer]
    FD_Parent_Process_Tmp3:
    lea eax, [ebp+FD_Parent_Process_pe32]
    mov eax, dword ptr [eax].th32ProcessID
    sub eax, dword ptr [ebp+FD_Parent_Process_PIDChild]
    jnz FD_Parent_Process_Tmp4
    lea eax, [ebp+FD_Parent_Process_pe32]
    push dword ptr [eax].th32ParentProcessID
    pop dword ptr [ebp+FD_Parent_Process_PIDParent]
    FD_Parent_Process_Tmp4:
    jmp FD_Parent_Process_Loop1
    FD_Parent_Process_Tmp1:
    push dword ptr [ebp+FD_Parent_Process_hSnapshot]
    call dword ptr [ebx].xCloseHandle
    jmp NotFound_FD_Parent_Process
    FD_Parent_Process_Tmp2:
    mov eax, dword ptr [ebp+FD_Parent_Process_PIDExplorer]
    sub eax, dword ptr [ebp+FD_Parent_Process_PIDParent]
    jz FD_Parent_Process_Tmp5
    push dword ptr [ebp+FD_Parent_Process_hSnapshot]
    call dword ptr [ebx].xCloseHandle
    jmp Found_FD_Parent_Process
    FD_Parent_Process_Tmp5:
    lea eax, [ebp+FD_Parent_Process_me32]
    assume eax : ptr MODULEENTRY32
    push sizeof MODULEENTRY32
    pop dword ptr [eax].dwSize  
    push dword ptr [ebp+FD_Parent_Process_PIDExplorer]
    push TH32CS_SNAPMODULE
    call dword ptr [ebx].xCreateToolhelp32Snapshot
    mov dword ptr [ebp+FD_Parent_Process_hSnapshot], eax
    lea eax, [ebp+FD_Parent_Process_me32]
    push eax
    push dword ptr [ebp+FD_Parent_Process_hSnapshot]
    call dword ptr [ebx].xModule32First
    test eax, eax
    jz FD_Parent_Process_Tmp6
    FD_Parent_Process_Loop2:
    lea eax, [ebp+FD_Parent_Process_me32]
    mov eax, dword ptr [eax].th32ProcessID
    sub eax, dword ptr [ebp+FD_Parent_Process_PIDExplorer]
    jnz FD_Parent_Process_Tmp7
    push MAX_PATH
    lea eax, [ebp+FD_Parent_Process_lpszSystemInfo]
    push eax
    call dword ptr [ebx].xGetWindowsDirectoryA
    call FD_Parent_Process_Str2
        db '/',0
    FD_Parent_Process_Str2:
    lea eax, [ebp+FD_Parent_Process_lpszSystemInfo]
    push eax
    call dword ptr [ebx].xlstrcatA
    call FD_Parent_Process_Str3
        db "EXPLORER.EXE",0
    FD_Parent_Process_Str3:
    lea eax, [ebp+FD_Parent_Process_lpszSystemInfo]
    push eax
    call dword ptr [ebx].xlstrcatA
    lea eax, [ebp+FD_Parent_Process_lpszSystemInfo]
    push eax
    lea eax, [ebp+FD_Parent_Process_me32]
    lea eax, [eax].szExePath
    push eax
    call dword ptr [ebx].xlstrcmpiA
    test eax, eax
    jz FD_Parent_Process_Tmp6
    push dword ptr [ebp+FD_Parent_Process_hSnapshot]
    call dword ptr [ebx].xCloseHandle
    jmp Found_FD_Parent_Process
    FD_Parent_Process_Tmp7:
    lea eax, [ebp+FD_Parent_Process_me32]
    push eax
    push dword ptr [ebp+FD_Parent_Process_hSnapshot]
    call dword ptr [ebx].xModule32Next
    test eax, eax
    jnz FD_Parent_Process_Loop2
    FD_Parent_Process_Tmp6:
    push dword ptr [ebp+FD_Parent_Process_hSnapshot]
    call dword ptr [ebx].xCloseHandle
    jmp NotFound_FD_Parent_Process
Exit_FD_Parent_Process:
    pop esi
    pop edi
    pop ecx
    pop ebx
    assume eax : nothing
    assume ebx : nothing           
    mov esp, ebp
    pop ebp
    retn 04h
NotFound_FD_Parent_Process:
    xor eax, eax
    jmp Exit_FD_Parent_Process
Found_FD_Parent_Process:
    mov eax, 1
    jmp Exit_FD_Parent_Process    
End_FD_Parent_Process:

当调试会话创建,将产生一个调试对象,我们通过ntdll中的
NtQueryObject函数参看调试对象的个数是否不为零,来确定调试器的存在
以ObjectAllTypeInformation使用NtQueryObject查询后会返回一个
OBJECT_ALL_INFORMATION的结构,其中NumberOfObjectsTypes成员为所有的
对象类型在ObjectTypeInformation数组中的计数
此对象如下
typedef struct _OBJECT_ALL_INFORMATION
ULONG    NumberOfObjectsTypes;
OBJECT_TYPE_INFORMATION ObjectTypeInformation[1];
}
typedef strcut _OBJECT_TYPE_INFORMATION {
[00]UNICODE_STRING TypeName;
[08]ULONG TotalNumberofHandles;
[0c]ULONG TotalNumberofObjects;
...
}
循环遍历ObjectTypeInformation对比类型的名字,如有类型名为DebugObject则
检测TotalNumberofHandles与TotalNumberofObjects如果不为0则存在调试器。

代码:
FD_DebugObject_NtQueryObject:
FD_DebugObject_NtQueryObject_Arg_Win32Api        equ 04h
    mov eax, dword ptr [esp+FD_DebugObject_NtQueryObject_Arg_Win32Api]
        
    push ebx
    push ecx
    push edx
    push edi
    push esi
    
    mov ebx, eax
    assume ebx : ptr WIN32APIBASE
    push edx    ; alloc the stack
    
    push esp    ; ReturnLength
    push 0
    push 0
    push ObjectAllTypeInformation
    push 0
    call dword ptr [ebx].xNtQueryObject
    pop ecx
    ;; make a tmp stack
    push ebp
    mov ebp, esp
    sub esp, ecx
    mov esi, esp
    ;; ObjectInformationLength
    push 0
    push ecx
    push esi
    push ObjectAllTypeInformation
    push 0
    call dword ptr [ebx].xNtQueryObject
    cld
    ;; NumberOfObjectsTypes
    lodsd
    xchg ecx, eax ; ecx = NumberOfObjectsTypes
    FD_DebugObject_NtQueryObject_Loop:    
    ;; load string lengths
    lodsd
    movzx edx, ax
    ;; pointer to TypeName
    lodsd
    xchg esi, eax
    ;; sizeof(L"DebugObject")
    ;; avoids superstrings
    ;; like "DebugObjective"
    cmp edx, 16h
    jnz FD_DebugObject_NtQueryObject_Tmp2
    xchg ecx, edx
    FD_DebugObject_NtQueryObject_Tmp1:
    call FD_DebugObject_NtQueryObject_UnicodeStr1
        dw 'D','e','b','u','g'
        dw 'O','b','j','e','c','t'
    FD_DebugObject_NtQueryObject_UnicodeStr1:
    pop edi
    repe cmpsb
    xchg ecx, edx
    jnz FD_DebugObject_NtQueryObject_Tmp2
    ;; TotalNumberOfObjects
    cmp dword ptr [eax], edx
    jnz Found_FD_DebugObject_NtQueryObject
    ;; point to trailing  null
    FD_DebugObject_NtQueryObject_Tmp2:
    add esi, edx
    ;; round down to dword
    and esi, -4
    ;; skip trailing null
    ;; and any alignment bytes
    lodsd
    loop FD_DebugObject_NtQueryObject_Loop
    xor eax, eax
Exit_FD_DebugObject_NtQueryObject:
    ;; clear the tmp stack
    mov esp, ebp
    pop ebp
    
    pop esi
    pop edi
    pop edx
    pop ecx
    pop ebx
    assume ebx : nothing    
    retn 04h
Found_FD_DebugObject_NtQueryObject:    
    mov eax, 1
    jmp Exit_FD_DebugObject_NtQueryObject
End_FD_DebugObject_NtQueryObject:

此类方法,利用FindWindow函数通过寻找是否存在一些常见调试软件的Title。这里收集了一些
如果有其他的Title,请朋友们告知。。。

代码:
FD_Find_Debugger_Window:
FD_Find_Debugger_Window_Arg_WinApi32   equ 08h
    push ebp
    mov ebp, esp
    
    push ebx
    
    mov ebx, dword ptr [ebp+FD_Find_Debugger_Window_Arg_WinApi32]
    assume ebx : ptr WIN32APIBASE
    
    push NULL
    call FD_Find_Debugger_Window_Str1
        db "1212121",0
    FD_Find_Debugger_Window_Str1:
    call dword ptr [ebx].xFindWindowA
    test eax, eax
    jnz Found_FD_Find_Debugger_Window
    
    push NULL
    call FD_Find_Debugger_Window_Str2
        db "icu_dbg",0
    FD_Find_Debugger_Window_Str2:
    call dword ptr [ebx].xFindWindowA
    test eax, eax
    jnz Found_FD_Find_Debugger_Window    
    
    push NULL
    call FD_Find_Debugger_Window_Str3
        db "pe--diy",0
    FD_Find_Debugger_Window_Str3:
    call dword ptr [ebx].xFindWindowA
    test eax, eax
    jnz Found_FD_Find_Debugger_Window     
    
    push NULL
    call FD_Find_Debugger_Window_Str5
        db "ollydbg",0
    FD_Find_Debugger_Window_Str5:
    call dword ptr [ebx].xFindWindowA
    test eax, eax
    jnz Found_FD_Find_Debugger_Window 

    push NULL
    call FD_Find_Debugger_Window_Str6
        db "odbydyk",0
    FD_Find_Debugger_Window_Str6:
    call dword ptr [ebx].xFindWindowA
    test eax, eax
    jnz Found_FD_Find_Debugger_Window

    push NULL
    call FD_Find_Debugger_Window_Str7
        db "WinDbgFrameClass",0
    FD_Find_Debugger_Window_Str7:
    call dword ptr [ebx].xFindWindowA
    test eax, eax
    jnz Found_FD_Find_Debugger_Window

    push NULL
    call FD_Find_Debugger_Window_Str8
        db "TDeDeMainForm",0
    FD_Find_Debugger_Window_Str8:
    call dword ptr [ebx].xFindWindowA
    test eax, eax
    jnz Found_FD_Find_Debugger_Window

    push NULL
    call FD_Find_Debugger_Window_Str9
        db "TIdaWindow",0
    FD_Find_Debugger_Window_Str9:
    call dword ptr [ebx].xFindWindowA
    test eax, eax
    jnz Found_FD_Find_Debugger_Window

    push NULL
    call FD_Find_Debugger_Window_StrA
        db "TESTDBG",0
    FD_Find_Debugger_Window_StrA:
    call dword ptr [ebx].xFindWindowA
    test eax, eax
    jnz Found_FD_Find_Debugger_Window

    push NULL
    call FD_Find_Debugger_Window_StrB
        db "kk1",0
    FD_Find_Debugger_Window_StrB:
    call dword ptr [ebx].xFindWindowA
    test eax, eax
    jnz Found_FD_Find_Debugger_Window
    
    push NULL
    call FD_Find_Debugger_Window_StrC
        db "Eew75",0
    FD_Find_Debugger_Window_StrC:
    call dword ptr [ebx].xFindWindowA
    test eax, eax
    jnz Found_FD_Find_Debugger_Window  
    
    push NULL
    call FD_Find_Debugger_Window_StrD
        db "Shadow",0
    FD_Find_Debugger_Window_StrD:
    call dword ptr [ebx].xFindWindowA
    test eax, eax
    jnz Found_FD_Find_Debugger_Window       
   
    push NULL
    call FD_Find_Debugger_Window_StrE
        db "PEiD v0.94",0
    FD_Find_Debugger_Window_StrE:
    call dword ptr [ebx].xFindWindowA
    test eax, eax
    jnz Found_FD_Find_Debugger_Window    
   
    push NULL
    call FD_Find_Debugger_Window_StrF
        db "Registry Monitor - Sysinternals: www.sysinternals.com",0
    FD_Find_Debugger_Window_StrF:
    call dword ptr [ebx].xFindWindowA
    test eax, eax
    jnz Found_FD_Find_Debugger_Window    
 
    push NULL
    call FD_Find_Debugger_Window_Str10
        db "File Monitor - Sysinternals: www.sysinternals.com",0
    FD_Find_Debugger_Window_Str10:
    call dword ptr [ebx].xFindWindowA
    test eax, eax
    jnz Found_FD_Find_Debugger_Window    

    push NULL
    call FD_Find_Debugger_Window_Str11
        db "Import REConstructor v1.6 FINAL (C) 2001-2003 MackT/uCF",0
    FD_Find_Debugger_Window_Str11:
    call dword ptr [ebx].xFindWindowA
    test eax, eax
    jnz Found_FD_Find_Debugger_Window
    jmp NotFound_Found_FD_Find_Debugger_Window
Exit_FD_Find_Debugger_Window:
    pop ebx
    assume ebx : nothing
    mov esp, ebp
    pop ebp
    retn 04h
NotFound_Found_FD_Find_Debugger_Window:
    xor eax, eax
    jmp Exit_FD_Find_Debugger_Window
Found_FD_Find_Debugger_Window:
    mov eax, 1
    jmp Exit_FD_Find_Debugger_Window    
End_FD_Find_Debugger_Window:

这种方面的核心思想是比对在进程表中是否是出现了调试器进程名,如果出现则退出。
不过这种方法很容易躲过,而且也可能造成误判。

代码:
FD_Find_Debugger_Process:
FD_Find_Debugger_Process_Arg_Win32Api   equ 08h
FD_Find_Debugger_Process_StackSize      equ 10h + sizeof PROCESSENTRY32
FD_Find_Debugger_Process_hSnapshot      equ -04h
FD_Find_Debugger_Process_hParnet        equ -08h
FD_Find_Debugger_Process_pe32           equ -(10+sizeof PROCESSENTRY32)

    push ebp
    mov ebp, esp
    sub esp, FD_Find_Debugger_Process_StackSize
    
    push edi
    push esi
    push edx
    push ecx
    push ebx
    
    ;; clear the stack
      lea edi, [ebp-FD_Find_Debugger_Process_StackSize]
      mov ecx, FD_Find_Debugger_Process_StackSize
      xor eax, eax
      cld
      rep stosb
    
    mov ebx, dword ptr [ebp+FD_Find_Debugger_Process_Arg_Win32Api]
    assume ebx : ptr WIN32APIBASE
    
    lea esi, [ebp+FD_Find_Debugger_Process_pe32]
    assume esi : ptr PROCESSENTRY32
    push sizeof PROCESSENTRY32
    pop dword ptr [esi].dwSize
    
    push 0
    push TH32CS_SNAPPROCESS
    call dword ptr [ebx].xCreateToolhelp32Snapshot
    mov dword ptr [ebp+FD_Find_Debugger_Process_hSnapshot], eax
    lea eax, [ebp+FD_Find_Debugger_Process_pe32]
    push eax
    push dword ptr [ebp+FD_Find_Debugger_Process_hSnapshot]
    call dword ptr [ebx].xProcess32First
    test eax, eax
    jz NotFound_FD_Find_Debugger_Process
    FD_Find_Debugger_Process_Loop:
    lea eax, [esi].szExeFile
    mov edi, eax
    call FD_Find_Debugger_Process_Str1
        db "OLLYICE.EXE",0
    FD_Find_Debugger_Process_Str1:
    push edi
    call dword ptr [ebx].xlstrcmpiA
    test eax, eax
    jz Found_FD_Find_Debugger_Process
    
    call FD_Find_Debugger_Process_Str2
        db "IDAG.EXE",0
    FD_Find_Debugger_Process_Str2:
    push edi
    call dword ptr [ebx].xlstrcmpiA
    test eax, eax
    jz Found_FD_Find_Debugger_Process 
    
    call FD_Find_Debugger_Process_Str3
        db "OLLYDBG.EXE",0
    FD_Find_Debugger_Process_Str3:
    push edi
    call dword ptr [ebx].xlstrcmpiA
    test eax, eax
    jz Found_FD_Find_Debugger_Process    
    
    call FD_Find_Debugger_Process_Str4
        db "PEID.EXE",0
    FD_Find_Debugger_Process_Str4:
    push edi
    call dword ptr [ebx].xlstrcmpiA
    test eax, eax
    jz Found_FD_Find_Debugger_Process    
    
    call FD_Find_Debugger_Process_Str5
        db "SOFTICE.EXE",0
    FD_Find_Debugger_Process_Str5:
    push edi
    call dword ptr [ebx].xlstrcmpiA
    test eax, eax
    jz Found_FD_Find_Debugger_Process

    call FD_Find_Debugger_Process_Str6
        db "LORDPE.EXE",0
    FD_Find_Debugger_Process_Str6:
    push edi
    call dword ptr [ebx].xlstrcmpiA
    test eax, eax
    jz Found_FD_Find_Debugger_Process

    call FD_Find_Debugger_Process_Str7
        db "IMPORTREC.EXE",0
    FD_Find_Debugger_Process_Str7:
    push edi
    call dword ptr [ebx].xlstrcmpiA
    test eax, eax
    jz Found_FD_Find_Debugger_Process
    
    call FD_Find_Debugger_Process_Str8
        db "W32DSM89.EXE",0
    FD_Find_Debugger_Process_Str8:
    push edi
    call dword ptr [ebx].xlstrcmpiA
    test eax, eax
    jz Found_FD_Find_Debugger_Process    
    
    call FD_Find_Debugger_Process_Str9
        db "WINDBG.EXE",0
    FD_Find_Debugger_Process_Str9:
    push edi
    call dword ptr [ebx].xlstrcmpiA
    test eax, eax
    jz Found_FD_Find_Debugger_Process
    lea eax, [ebp+FD_Find_Debugger_Process_pe32]
    push eax
    push dword ptr [ebp+FD_Find_Debugger_Process_hSnapshot]
    call dword ptr [ebx].xProcess32Next
    test eax, eax
    jnz FD_Find_Debugger_Process_Loop
    jmp NotFound_FD_Find_Debugger_Process
Exit_FD_Find_Debugger_Process:
    ;; close the Shotsnap handle
    push dword ptr [ebp+FD_Find_Debugger_Process_hSnapshot]
    call dword ptr [ebx].xCloseHandle
    
    pop edi
    pop esi
    pop edx
    pop ecx
    pop ebx
    assume ebx : nothing
    assume esi : nothing
    mov esp, ebp
    pop ebp 
    retn 04h
NotFound_FD_Find_Debugger_Process:
    xor eax, eax
    jmp Exit_FD_Find_Debugger_Process
Found_FD_Find_Debugger_Process:
    mov eax, 1
    jmp Exit_FD_Find_Debugger_Process        
End_FD_Find_Debugger_Process:

这种方法通过打开一些调试软件加载到系统中驱动的句柄,从而判断是否有
调试软件的存在。

代码:
FD_Find_Device_Driver:
FD_Find_Device_Driver_Arg_Win32Api      equ 08h

    push ebp
    mov ebp, esp
    
    push ebx
    push ecx
    push edx
    push esi
    push edi
    
    mov ebx, dword ptr [ebp+FD_Find_Device_Driver_Arg_Win32Api]
    assume ebx : ptr WIN32APIBASE
    
    ;; check softice on unknow system
    push NULL
    push FILE_ATTRIBUTE_NORMAL
    push OPEN_EXISTING
    push NULL
    push FILE_SHARE_READ + FILE_SHARE_WRITE
    push GENERIC_READ + GENERIC_WRITE
    call FD_Find_Device_Driver_Str1
        db "//./SIWVID",0
    FD_Find_Device_Driver_Str1:
    call dword ptr [ebx].xCreateFileA
    cmp eax, INVALID_HANDLE_VALUE
    jnz Found_FD_Find_Device_Driver
    
    ;; check softice 4.05 on win2k
    push NULL
    push FILE_ATTRIBUTE_NORMAL
    push OPEN_EXISTING
    push NULL
    push FILE_SHARE_READ + FILE_SHARE_WRITE
    push GENERIC_READ + GENERIC_WRITE
    call FD_Find_Device_Driver_Str2
        db "//./NTICE",0
    FD_Find_Device_Driver_Str2:
    call dword ptr [ebx].xCreateFileA
    cmp eax, INVALID_HANDLE_VALUE
    jnz Found_FD_Find_Device_Driver
    
    ;; check softice on win9x
    push NULL
    push FILE_ATTRIBUTE_NORMAL
    push OPEN_EXISTING
    push NULL
    push FILE_SHARE_READ + FILE_SHARE_WRITE
    push GENERIC_READ + GENERIC_WRITE
    call FD_Find_Device_Driver_Str3
        db "//./SICE",0
    FD_Find_Device_Driver_Str3:
    call dword ptr [ebx].xCreateFileA
    cmp eax, INVALID_HANDLE_VALUE
    jnz Found_FD_Find_Device_Driver    
    
    ;; check softice on win9x
    push NULL
    push FILE_ATTRIBUTE_NORMAL
    push OPEN_EXISTING
    push NULL
    push FILE_SHARE_READ + FILE_SHARE_WRITE
    push GENERIC_READ + GENERIC_WRITE
    call FD_Find_Device_Driver_Str4
        db "//./SIWDEBUG",0
    FD_Find_Device_Driver_Str4:
    call dword ptr [ebx].xCreateFileA
    push eax
    call dword ptr [ebx].xGetLastError
    test al, 032h
    pop eax
    jz Found_FD_Find_Device_Driver
    
    ;; check regmon on win9x
    push NULL
    push FILE_ATTRIBUTE_NORMAL
    push OPEN_EXISTING
    push NULL
    push FILE_SHARE_READ + FILE_SHARE_WRITE
    push GENERIC_READ + GENERIC_WRITE
    call FD_Find_Device_Driver_Str5
        db "//./REGVXD",0
    FD_Find_Device_Driver_Str5:
    call dword ptr [ebx].xCreateFileA    
    cmp eax, INVALID_HANDLE_VALUE
    jnz Found_FD_Find_Device_Driver
    
    ;; check RegMON
    push NULL
    push FILE_ATTRIBUTE_NORMAL
    push OPEN_EXISTING
    push NULL
    push FILE_SHARE_READ + FILE_SHARE_WRITE
    push GENERIC_READ + GENERIC_WRITE
    call FD_Find_Device_Driver_Str6
        db "//./FILEM",0
    FD_Find_Device_Driver_Str6:
    call dword ptr [ebx].xCreateFileA      
    cmp eax, INVALID_HANDLE_VALUE
    jnz Found_FD_Find_Device_Driver
    
    ;; check TRW
    push NULL
    push FILE_ATTRIBUTE_NORMAL
    push OPEN_EXISTING
    push NULL
    push FILE_SHARE_READ + FILE_SHARE_WRITE
    push GENERIC_READ + GENERIC_WRITE
    call FD_Find_Device_Driver_Str7
        db "//./TRW",0
    FD_Find_Device_Driver_Str7:
    call dword ptr [ebx].xCreateFileA      
    cmp eax, INVALID_HANDLE_VALUE
    jnz Found_FD_Find_Device_Driver       
    
    ;; check softice extender
    push NULL
    push FILE_ATTRIBUTE_NORMAL
    push OPEN_EXISTING
    push NULL
    push FILE_SHARE_READ + FILE_SHARE_WRITE
    push GENERIC_READ + GENERIC_WRITE
    call FD_Find_Device_Driver_Str8
        db "//./ICEEXT",0
    FD_Find_Device_Driver_Str8:
    call dword ptr [ebx].xCreateFileA      
    cmp eax, INVALID_HANDLE_VALUE
    jnz Found_FD_Find_Device_Driver 
    jmp NotFound_FD_Find_Device_Driver
    
Exit_FD_Find_Device_Driver:    
    pop edi
    pop esi
    pop edx
    pop ecx
    pop ebx
    assume ebx : nothing    
    mov esp, ebp
    pop ebp
    retn 04h
NotFound_FD_Find_Device_Driver:
    xor eax, eax
    jmp Exit_FD_Find_Device_Driver
Found_FD_Find_Device_Driver:
    push eax
    assume ebx : ptr WIN32APIBASE
    call dword ptr [ebx].xCloseHandle
    assume ebx : nothing
    mov eax, 1
    jmp Exit_FD_Find_Device_Driver
End_FD_Find_Device_Driver:

利用int3中断引起异常。如果,正常运行则触发异常。

代码:
FD_Exception_Int3:
    call Get_FD_Exception_Int3_Eip
    Get_FD_Exception_Int3_Eip:
    pop eax
    add eax, offset FD_Exception_Int3_Exception - offset Get_FD_Exception_Int3_Eip
    ;; setup exception
    assume fs : nothing
    push eax
    push dword ptr fs : [0]
    mov dword ptr fs : [0], esp
    ;; reset eax
    xor eax, eax
    int 03h
    ;; unsetup exception
    pop dword ptr fs : [0]
    add esp, 04h
    
    ;; check the flag
    test eax, eax
    jz Found_FD_Exception_Int3
    jmp NotFound_FD_Exception_Int3
FD_Exception_Int3_Exception:
    mov eax, dword ptr [esp+0ch]
    ;; eax = ContextRecord
    assume eax : ptr CONTEXT
    mov dword ptr [eax].regEax, 0FFFFFFFFh
    inc dword ptr [eax].regEip
    xor eax, eax
    assume eax : nothing
    retn
Exit_FD_Exception_Int3:
    retn 0h
NotFound_FD_Exception_Int3:
    xor eax, eax
    jmp Exit_FD_Exception_Int3
Found_FD_Exception_Int3:
    mov eax, 1
    jmp Exit_FD_Exception_Int3        
End_FD_Exception_Int3:

通过对EFLAGS中的TF的检测来确定是否存在调试器。当TF=1的时会触发一个
单步执行异常,可以通过安装异常处理针来捕获。

代码:
FD_Exception_Popf:
    push ebx

    call Get_FD_Exception_Popf_Eip
    Get_FD_Exception_Popf_Eip:
    pop eax
    add eax, offset FD_Exception_Popf_Exception - offset Get_FD_Exception_Popf_Eip
    assume fs : nothing    
    push eax
    push dword ptr fs:[0]
    mov dword ptr fs:[0], esp
    ;; reset eax
    xor eax, eax
    pushf
    mov dword ptr [esp], 0100h
    popf
    nop
FD_Exception_Popf_NextEip:
    pop dword ptr fs:[0]
    add esp, 04h
    
    ;; check the flag
    test eax, eax
    jz Found_FD_Exception_Popf
    jmp NotFound_FD_Exception_Popf
    
FD_Exception_Popf_Exception:
    mov eax, dword ptr [esp+0ch]
    assume eax : ptr CONTEXT
    mov dword ptr [eax].regEax, 0FFFFFFFFh
    call Get_FD_Exception_Popf_Exception_Eip2
    Get_FD_Exception_Popf_Exception_Eip2:
    pop ebx
    sub ebx, offset Get_FD_Exception_Popf_Exception_Eip2 - offset FD_Exception_Popf_NextEip
    mov dword ptr [eax].regEip, ebx
    xor eax, eax
    retn
    assume eax : nothing
Exit_FD_Exception_Popf:
    pop ebx
    retn 0h
NotFound_FD_Exception_Popf:
    xor eax, eax
    jmp Exit_FD_Exception_Popf
Found_FD_Exception_Popf:
    mov eax, 1
    jmp Exit_FD_Exception_Popf
End_FD_Exception_Popf:

触发OutputDebugString的错误。如果调试器存在则GetLastError为0。

代码:
FD_OutputDebugString:
FD_OutputDebugString_Arg_Win32Api       equ 04h
    
    mov eax, dword ptr [esp+FD_OutputDebugString_Arg_Win32Api]
    push ebx
    mov ebx, eax
    assume ebx : ptr WIN32APIBASE
    call FD_OutputDebugString_Str
        db 0
    FD_OutputDebugString_Str:
    call dword ptr [ebx].xOutputDebugStringA
    call dword ptr [ebx].xGetLastError 
    test eax, eax   
    jnz NotFound_FD_OutputDebugString
    inc eax
    pop ebx
    assume ebx : nothing
    retn 04h
NotFound_FD_OutputDebugString:
    pop ebx
    xor eax, eax
    retn 04h
    
End_FD_OutputDebugString:

Ollydbg允许设置一个内存访问/写入断点。它通过页面保护来实现。
页面保护提供了当应用程序的某块内存被访问时获得通知。
页面保护通过PAGE_GUARD页面保护修改符来设置。如果访问的内存
是受保护的将会产生一个STATUS_GUARD_PAGE_VIOLATION(0x80000001)异常
如果进程被Ollydbg调试并且受保护的页面被访问,将不会抛出异常。访问
将会被当作内存断点来处理。

代码:
FS_OD_Exception_GuardPages:
FS_OD_Exception_GuardPages_Arg_Win32Api     equ 04h

    mov eax, dword ptr [esp+FS_OD_Exception_GuardPages_Arg_Win32Api]
    
    push edi    ; pAllocatedMem
    push ebx
    
    mov ebx, eax
    assume ebx : ptr WIN32APIBASE
     
    push PAGE_READWRITE
    push MEM_COMMIT
    push 01000h
    push NULL
    call dword ptr [ebx].xVirtualAlloc
    test eax, eax
    jz NotFound_FS_OD_Exception_GuardPages
    mov edi, eax
    ;; store a RENT on the allocated memory
    mov byte ptr [edi], 0c3h
    push edi        ; alloc stack
    
    push esp
    push PAGE_EXECUTE_READ + PAGE_GUARD
    push 01000h
    push edi
    call dword ptr [ebx].xVirtualProtect
    ;; set eax to 0
    xor eax, eax
    ;; trigger a STATUS_GUARD_PAGE_VIOLATION exception
    ;; setup expcetion
    call Get_FS_OD_Exception_GuardPages_Eip
    Get_FS_OD_Exception_GuardPages_Eip:
    pop eax
    add eax, offset FS_OD_Exception_GuardPages_Exception - offset Get_FS_OD_Exception_GuardPages_Eip
    assume fs : nothing
    push eax
    push dword ptr fs:[0]
    mov dword ptr fs:[0], esp
    call edi
FS_OD_Exception_GuardPages_Continue:
    pop edi
    ;; unsetup exception
    pop dword ptr fs:[0]
    add esp, 04h
    test eax, eax
    jz Found_FS_OD_Exception_GuardPages
    jmp NotFound_FS_OD_Exception_GuardPages
FS_OD_Exception_GuardPages_Exception:
    mov eax, dword ptr [esp+0ch]
    assume eax : ptr CONTEXT
    mov dword ptr [eax].regEax, 0FFFFFFFFh
    call Get_FS_OD_Exception_GuardPages_Exception_Eip
    Get_FS_OD_Exception_GuardPages_Exception_Eip:
    pop ebx
    sub ebx, offset Get_FS_OD_Exception_GuardPages_Exception_Eip - offset FS_OD_Exception_GuardPages_Continue  
    mov dword ptr [eax].regEip, ebx
    assume eax : nothing
    xor eax, eax
    retn
    
Exit_FS_OD_Exception_GuardPages:
    pop ebx
    pop edi
    assume ebx : nothing
    retn 04h
    
NotFound_FS_OD_Exception_GuardPages:
    assume ebx : ptr WIN32APIBASE
    push MEM_DECOMMIT
    push 01000h
    push edi
    call dword ptr [ebx].xVirtualFree
    assume ebx : nothing
    xor eax, eax
    jmp Exit_FS_OD_Exception_GuardPages
Found_FS_OD_Exception_GuardPages:
    assume ebx : ptr WIN32APIBASE
    push MEM_DECOMMIT
    push 01000h
    push edi
    call dword ptr [ebx].xVirtualFree
    assume ebx : nothing
    mov eax, 1
    jmp Exit_FS_OD_Exception_GuardPages
End_FS_OD_Exception_GuardPages:

Softice调试器会对UnhandleExceptionFilter进行修改,将第一个字节修改为CCh(int 3)

代码:
FS_SI_UnhandledExceptionFilter:
FS_SI_UnhandledExceptionFilter_Arg_Win32Api     equ 04h
    mov eax, dword ptr [esp+FS_SI_UnhandledExceptionFilter_Arg_Win32Api]
    assume eax : ptr WIN32APIBASE
    mov eax, dword ptr [eax].xUnhandledExceptionFilter
    mov al, byte ptr [eax]
    sub al, 0cch
    jz Found_FS_SI_UnhandledExceptionFilter
    xor eax, eax
Exit_FS_SI_UnhandledExceptionFilter:   
    assume eax : nothing
    retn 04h
Found_FS_SI_UnhandledExceptionFilter:
    mov eax, 1
    jmp Exit_FS_SI_UnhandledExceptionFilter    
End_FS_SI_UnhandledExceptionFilter:

Ollydbg的插件对几个函数的首部进行修改。通过对齐的检测来判断系统中是否存在调试器

代码:
FS_ODP_Process32NextW:
FS_ODP_Process32NextW_Arg_Win32Api          equ 04h
    mov eax, dword ptr [esp+FS_ODP_Process32NextW_Arg_Win32Api]
    assume eax : ptr WIN32APIBASE
    mov eax, dword ptr [eax].xProcess32NextW
    mov ax, word ptr [eax]
    sub ax, 0FF88h
    jnz Found_FS_ODP_Process32NextW
    xor eax, eax
Exit_FS_ODP_Process32NextW:
    assume eax : nothing 
    retn 04h
Found_FS_ODP_Process32NextW:
    mov eax, 1
    jmp Exit_FS_ODP_Process32NextW
End_FS_ODP_Process32NextW:


FS_ODP_OutputDebugStringA:
FS_ODP_OutputDebugStringA_Arg_Win32Api      equ 04h
    mov eax, dword ptr [ebp+FS_ODP_OutputDebugStringA_Arg_Win32Api]
    assume eax : ptr WIN32APIBASE
    mov eax, dword ptr [eax].xOutputDebugStringA
    mov ax, word ptr [eax]
    sub ax, 03468h
    jnz Found_FS_ODP_OutputDebugStringA
    xor eax, eax
Exit_FS_ODP_OutputDebugStringA:
    assume eax : nothing
    retn 04h
Found_FS_ODP_OutputDebugStringA:
    mov eax, 1
    jmp Exit_FS_ODP_OutputDebugStringA            
End_FS_ODP_OutputDebugStringA:


FS_ODP_OpenProcess:
FS_ODP_OpenProcess_Arg_Win32Api     equ 04h
    mov eax, dword ptr [ebp+FS_ODP_OpenProcess_Arg_Win32Api]
    assume eax : ptr WIN32APIBASE
    mov eax, dword ptr [eax].xOpenProcess
    mov al, byte ptr [eax+06h]
    ;; Hide Debugger Plugin of OD is present
    sub al, 0eah
    jnz Found_FS_ODP_OpenProcess
    xor eax, eax
Exit_FS_ODP_OpenProcess:
    assume eax : nothing
    retn 04h  
Found_FS_ODP_OpenProcess:
    mov eax, 1
    jmp Exit_FS_ODP_OpenProcess      
End_FS_ODP_OpenProcess:

FB_HWBP_Exception:
    call Get_FB_HWBP_Exception_Eip
    Get_FB_HWBP_Exception_Eip:
    pop eax
    add eax, offset FB_HWBP_Exception_Exception - offset FB_HWBP_Exception
    assume fs : nothing
    push eax
    push fs:[0]
    mov dword ptr fs:[0], esp
    ;; reset eax
    xor eax, eax
    int 01h
    pop dword ptr fs:[0]
    add esp, 04h
    test eax, eax
    jnz Found_FB_HWBP_Exception
    jmp NotFound_FB_HWBP_Exception
FB_HWBP_Exception_Exception:
    mov eax, dword ptr [esp+0ch]
    assume eax : ptr CONTEXT
    ;; check if debug Registers Context.Dr0-Dr3 is not zero
    cmp dword ptr [eax].iDr0, 0
    jnz FB_HWBP_Exception_HardwareBp_Found
    cmp dword ptr [eax].iDr1, 0
    jnz FB_HWBP_Exception_HardwareBp_Found  
    cmp dword ptr [eax].iDr2, 0
    jnz FB_HWBP_Exception_HardwareBp_Found
    cmp dword ptr [eax].iDr3, 0
    jnz FB_HWBP_Exception_HardwareBp_Found
    jmp FB_HWBP_Exception_Exception_Ret     
FB_HWBP_Exception_HardwareBp_Found:
    ;; set Context.Eax to signal breakpoint found
    mov dword ptr [eax].regEax, 0FFFFFFFFh
FB_HWBP_Exception_Exception_Ret:
    ;; set Context.Eip upon return
    add dword ptr [eax].regEip, 02h
    xor eax, eax
    retn
Exit_FB_HWBP_Exception:
    retn 0h
NotFound_FB_HWBP_Exception:
    xor eax, eax
    jmp Exit_FB_HWBP_Exception
Found_FB_HWBP_Exception:
    mov eax, 1
    jmp Exit_FB_HWBP_Exception                
End_FB_HWBP_Exception:

通过对代码节做CRC值的验证来判断是否存在内存补丁

代码:
FB_SWBP_Memory_CRC:
FB_SWBP_Memory_CRC_Arg_Win32Api         equ 08h
FB_SWBP_Memory_CRC_Arg_FuncAddr         equ 0ch
FB_SWBP_Memory_CRC_StackSize            equ 10h+MAX_PATH
FB_SWBP_Memory_CRC_fileSize             equ -04h
FB_SWBP_Memory_CRC_NumberOfBytesRW      equ -08h
FB_SWBP_Memory_CRC_pBuffer              equ -0ch
FB_SWBP_Memory_CRC_szFileName           equ -(10h+MAX_PATH)
    push ebp
    mov ebp, esp
    sub esp, FB_SWBP_Memory_CRC_StackSize
    
    push esi
    push edi
    push ecx
    push edx
    push ebx
    
    
    ;; clear the stack
    lea edi, [ebp+FB_SWBP_Memory_CRC_szFileName]
    mov ecx, FB_SWBP_Memory_CRC_StackSize
    xor eax, eax
    cld
    rep stosb
    
    
    mov ebx, dword ptr [ebp+FB_SWBP_Memory_CRC_Arg_Win32Api]
    assume ebx : ptr WIN32APIBASE
    push MAX_PATH
    lea eax, [ebp+FB_SWBP_Memory_CRC_szFileName]
    push eax
    push NULL
    call dword ptr [ebx].xGetModuleFileNameA
    ;; open file
    push NULL
    push FILE_ATTRIBUTE_NORMAL
    push OPEN_EXISTING
    push NULL
    push FILE_SHARE_READ
    push GENERIC_READ
    lea eax, [ebp+FB_SWBP_Memory_CRC_szFileName]
    push eax
    call dword ptr [ebx].xCreateFileA
    cmp eax, INVALID_HANDLE_VALUE
    jz Error_FB_SWBP_Memory_CRC
    mov edi, eax
    push NULL
    push eax
    call dword ptr [ebx].xGetFileSize
;    cmp eax, INVALID_FILE_SIZE
;    jz Error_FB_SWBP_Memory_CRC    
    mov dword ptr [ebp+FB_SWBP_Memory_CRC_fileSize], eax
    push PAGE_READWRITE
    push MEM_COMMIT
    push eax
    push NULL
    call dword ptr [ebx].xVirtualAlloc
    mov dword ptr [ebp+FB_SWBP_Memory_CRC_pBuffer], eax
    push NULL
    lea eax, [ebp+FB_SWBP_Memory_CRC_NumberOfBytesRW]
    push eax
    push dword ptr [ebp+FB_SWBP_Memory_CRC_fileSize]
    push dword ptr [ebp+FB_SWBP_Memory_CRC_pBuffer]
    push edi
    call dword ptr [ebx].xReadFile
    push edi
    call dword ptr [ebx].xCloseHandle
        
    mov esi, dword ptr [ebp+FB_SWBP_Memory_CRC_pBuffer]
    add esi, dword ptr [esi+3ch]
    assume esi : ptr IMAGE_NT_HEADERS
    mov edx, dword ptr [esi].OptionalHeader.ImageBase
    mov eax, dword ptr [esi].OptionalHeader.AddressOfEntryPoint
    add eax, edx
    mov cx, word ptr [esi].FileHeader.NumberOfSections
    movzx ecx, cx
    mov edi, esi
    add edi, sizeof IMAGE_NT_HEADERS
    assume edi : ptr IMAGE_SECTION_HEADER
    ;; find the entry section
    ;; eax = AddressOfEntryPoint
    ;; ebx = Each Section Virtual Address
    ;; ecx = NumberOfSections    
    ;; edx = ImageBase
    ;; edi = Section Table Point
    FB_SWBP_Memory_CRC_Loop:
    mov ebx, dword ptr [edi].VirtualAddress
    add ebx, edx
    cmp ebx, eax
    jz FB_SWBP_Memory_CRC_Loop_End
    add edi, sizeof IMAGE_SECTION_HEADER
    dec ecx
    jnz FB_SWBP_Memory_CRC_Loop
    jmp Error_FB_SWBP_Memory_CRC
    FB_SWBP_Memory_CRC_Loop_End:
    mov edi, dword ptr [edi].Misc.VirtualSize
    mov esi, eax
    ;; alloc the memory
    push MEM_DECOMMIT
    push dword ptr [ebp+FB_SWBP_Memory_CRC_fileSize]
    push dword ptr [ebp+FB_SWBP_Memory_CRC_pBuffer]
    mov ebx, dword ptr [ebp+FB_SWBP_Memory_CRC_Arg_Win32Api]
    assume ebx : ptr WIN32APIBASE
    call dword ptr [ebx].xVirtualFree
    mov edx, dword ptr [ebp+FB_SWBP_Memory_CRC_Arg_FuncAddr]
    assume edx : ptr FUNCADDRTBL
    push edi
    push esi
    call dword ptr [edx].xCRC32
    call Get_FB_SWBP_Memory_CRC_Eip
    Get_FB_SWBP_Memory_CRC_Eip:
    pop ecx
    add ecx, offset FB_SWBP_Memory_CRC_Orig_CRC - offset Get_FB_SWBP_Memory_CRC_Eip
    cmp eax, ecx
    jz NotFound_FB_SWBP_Memory_CRC
    jmp Found_FB_SWBP_Memory_CRC
Exit_FB_SWBP_Memory_CRC:
    pop ebx
    pop edx
    pop ecx
    pop edi
    pop esi
    assume ebx : nothing
    assume edx : nothing
    assume edi : nothing
    assume esi : nothing
    mov esp, ebp
    pop ebp
    retn 08h
Error_FB_SWBP_Memory_CRC:
    mov eax, dword ptr [ebp+FB_SWBP_Memory_CRC_pBuffer]
    test eax, eax
    jz Error_FB_SWBP_Memory_CRC_Continue
    push MEM_DECOMMIT
    push dword ptr [ebp+FB_SWBP_Memory_CRC_fileSize]
    push dword ptr [ebp+FB_SWBP_Memory_CRC_pBuffer]
    mov ebx, dword ptr [ebp+FB_SWBP_Memory_CRC_Arg_Win32Api]
    assume ebx : ptr WIN32APIBASE    
    call dword ptr [ebx].xVirtualFree
    assume ebx : nothing
    Error_FB_SWBP_Memory_CRC_Continue:
    xor eax, eax
    jmp Exit_FB_SWBP_Memory_CRC
Found_FB_SWBP_Memory_CRC:
    push MEM_DECOMMIT
    push dword ptr [ebp+FB_SWBP_Memory_CRC_fileSize]
    push dword ptr [ebp+FB_SWBP_Memory_CRC_pBuffer]
    mov ebx, dword ptr [ebp+FB_SWBP_Memory_CRC_Arg_Win32Api]
    assume ebx : ptr WIN32APIBASE    
    call dword ptr [ebx].xVirtualFree
    assume ebx : nothing
    mov eax, 1
    jmp Exit_FB_SWBP_Memory_CRC
NotFound_FB_SWBP_Memory_CRC:
    push MEM_DECOMMIT
    push dword ptr [ebp+FB_SWBP_Memory_CRC_fileSize]
    push dword ptr [ebp+FB_SWBP_Memory_CRC_pBuffer]
    mov ebx, dword ptr [ebp+FB_SWBP_Memory_CRC_Arg_Win32Api]
    assume ebx : ptr WIN32APIBASE    
    call dword ptr [ebx].xVirtualFree
    assume ebx : nothing
    xor eax, eax
    jmp Exit_FB_SWBP_Memory_CRC        
FB_SWBP_Memory_CRC_Orig_CRC:
    dd 0   
End_FB_SWBP_Memory_CRC:

通过检测标志位来检测是否存在单步运行标志

代码:
FT_PushSS_PopSS:
    ;; release version
    push ebp
    mov ebp, esp
    push ss
    pop ss
    pushf
    pop eax
    and eax, 00000100h
    jnz Found_FT_PushSS_PopSS
Exit_FT_PushSS_PopSS:
    xor eax, eax
    mov esp, ebp
    pop ebp
    retn 0h    
Found_FT_PushSS_PopSS:
    mov eax, 1
    jmp Exit_FT_PushSS_PopSS   
End_FT_PushSS_PopSS:

以下三个函数都是通过调用取单步运行时间差的原理来检测是否进行单步运行的
分别使用了rdtsc,GetTickCount,timeGetTime三个函数来确定

代码:
FT_RDTSC:
    push ecx
      rdtsc
    xchg ecx, eax
    rdtsc
    sub eax, ecx
    cmp eax, 500h
    jnbe Found_FT_RDTSC
    xor eax, eax
Exit_FT_RDTSC:
    pop ecx
    retn 0h
Found_FT_RDTSC:
    mov eax, 1
    jmp Exit_FT_RDTSC
End_FT_RDTSC:

FT_GetTickCount:
FT_GetTickCount_Arg_Win32Api        equ 04h
    mov eax, dword ptr [esp+FT_GetTickCount_Arg_Win32Api]
    push ebx
    push ecx
    mov ebx, eax
    assume ebx : ptr WIN32APIBASE
    call dword ptr [ebx].xGetTickCount
    xchg ecx, eax
    call dword ptr [ebx].xGetTickCount
    sub eax, ebx
    cmp eax, 1
    jnb Found_FT_GetTickCount
    xor eax, eax
Exit_FT_GetTickCount:
    pop ecx
    pop ebx
    assume ebx : nothing
    retn 04h    
Found_FT_GetTickCount:
    mov eax, 1
    jmp Exit_FT_GetTickCount    
End_FT_GetTickCount:

FT_timeGetTime:
FT_timeGetTime_Arg_Win32Api            equ 04h
    mov eax, dword ptr [esp+FT_timeGetTime_Arg_Win32Api]
    push ebx
    push ecx
    mov ebx, eax
    assume ebx : ptr WIN32APIBASE
    call dword ptr [ebx].xtimeGetTime
    xchg ecx, eax
    call dword ptr [ebx].xtimeGetTime
    sub eax, ebx
    cmp eax, 10h
    jnb Found_FT_timeGetTime
    xor eax, eax
Exit_FT_timeGetTime:
    pop ecx
    pop ebx
    assume ebx : nothing
    retn 04h    
Found_FT_timeGetTime:
    mov eax, 1
    jmp Exit_FT_timeGetTime
End_FT_timeGetTime:

手动检测位于7FFE0000h地址的SharedUserData数据结构的TickCoutLow与TickCountMultipiler字段
来获取单步运行时间差。

代码:
FT_SharedUserData_TickCount:
    push ecx
    push edx    
    mov edx, 07FFE0000h
    mov eax, dword ptr [edx]
    imul dword ptr [edx+04h]
    shrd eax, edx, 018h
    xchg eax, ecx
    mov edx, 07FFE0000h
    mov eax, dword ptr [edx]
    imul dword ptr [edx+04h]
    shrd eax, edx, 018h
    sub eax, ecx
       cmp eax, 500h
       jnbe Found_FT_SharedUserData_TickCount
       xor eax, eax
Exit_FT_SharedUserData_TickCount:
    pop edx
    pop ecx
    retn 0h
Found_FT_SharedUserData_TickCount:
    mov eax, 1
    jmp Exit_FT_SharedUserData_TickCount    
End_FT_SharedUserData_TickCount:

中断1不能从r3下调用。如果从r3下调用,将产生一个EXECEPTION_ACCESS_VIOLATION(0x0C0000005)的异常。
如果softice存在,它HOOK了中断1并且使它的DPL(descriptor privilege level)到环3下
使得softice能单步处理用户态的程序。如果程序使用中断1,softice不检查它是否在单步运行或者是一软中断。
softice总是调用原始的中断1处理函数。并且使用EXCEPTION_SINGLE_STEP(0x80000004)异常替换原本的EXECEPTION_ACCESS_VIOLATION
(0xC0000005)异常。

代码:
FT_INT1_IceBreakpoint:
    push ebp
    mov ebp, esp
    call Get_FT_INT1_IceBreakpoint_Eip
    Get_FT_INT1_IceBreakpoint_Eip:
    pop eax
    add eax, offset FT_INT1_IceBreakpoint_Exception - offset Get_FT_INT1_IceBreakpoint_Eip
    push eax
    assume fs : nothing
    push dword ptr fs:[0]
    mov dword ptr fs:[0], esp
    ;; reset eax
    xor eax, eax
    db 0CDh, 01h    ; int 1
    pop dword ptr fs:[0]
    add esp, 04h
    test eax, eax
    jz Found_FT_INT1_IceBreakpoint
    jmp NotFound_FT_INT1_IceBreakpoint
FT_INT1_IceBreakpoint_Exception:
    ;mov eax, dword ptr [esp+04h]
    ;cmp dword ptr [eax], 80000004h
    mov eax, dword ptr [esp+0ch]
    assume eax : ptr CONTEXT 
    mov dword ptr [eax].regEax, 1
    inc dword ptr [eax].regEip
    xor eax, eax
    retn
Exit_FT_INT1_IceBreakpoint:
    mov esp, ebp
    pop ebp
    retn 0h
NotFound_FT_INT1_IceBreakpoint:
    xor eax, eax
    jmp Exit_FT_INT1_IceBreakpoint
Found_FT_INT1_IceBreakpoint:
    mov eax, 1
    jmp Exit_FT_INT1_IceBreakpoint
End_FT_INT1_IceBreakpoint:

以下为检测Virtual PC 与 VMWARE的两个例子,这类检测技术大多都是通过与真实环境中不同的
异常,指令实现的。严格的描述可以在其规定的文档中找到。

代码:
FV_VPC_Exception: 

    push ebx
    push ecx
   
    call Get_FV_VPC_Exception_Eip
    Get_FV_VPC_Exception_Eip:
    pop ecx
    add ecx, offset FV_VPC_Exception_Exception - offset Get_FV_VPC_Exception_Eip
    assume fs : nothing        
    push ecx
    push dword ptr fs:[0]
    mov dword ptr fs:[0], esp
    
    ;; Flag
    xor ebx, ebx
    ;; VPC function number
    mov eax, 1
    
    ;; call VPC
    db 0Fh,3Fh,07h,0Bh
    
    pop dword ptr fs:[0]
    add esp, 04h    
    test ebx, ebx
    setz al
    
    pop ecx
    pop ebx    
    retn 0h
    
FV_VPC_Exception_Exception:    
    mov ecx, dword ptr [esp+0ch]
    assume ecx : ptr CONTEXT
    ;; ebx = -1 : not running
    ;; ebx = 0 : running
    mov dword ptr [ecx].regEbx, -1
    ;; skip past the call to VPC
    add dword ptr [ecx].regEip, 04h
    xor eax, eax
    retn
End_FV_VPC_Exception:

FV_VMWare_VMX:
    
    call IsInsideVMWare
    retn 0h
IsInsideVMWare:

    push ebx
    push ecx
    push edx

    assume fs : nothing
    call Get_IsInsideVMWare_Eip
    Get_IsInsideVMWare_Eip:
    pop eax
    add eax, offset IsInsideVMWare_Exception - offset Get_IsInsideVMWare_Eip
    push eax
    push dword ptr fs:[0]
    mov dword ptr fs:[0], esp
    
    mov    eax, 'VMXh'
    mov    ebx, 0         ; any value but MAGIC VALUE
    mov    ecx, 10        ; get VMWare version
    mov    edx, 'VX'     ; port number
    in     eax, dx         ; read port
                           ; on return EAX returns the VERSION
    cmp    ebx, 'VMXh'     ; is it a reply from VMWare?
    setz   al             ; set return value
    movzx eax, al

    pop dword ptr fs:[0]
    add esp, 04h
    
    pop edx
    pop ecx
    pop ebx
    
    retn 0h
IsInsideVMWare_Exception:
    mov eax, dword ptr [esp+0ch]
    assume eax : ptr CONTEXT
    inc dword ptr [eax].regEip
    retn       
End_IsInsideVMWare:
    
End_FV_VMWare_VMX:

通过计算文件的长度与原先的对比,来确定是否进行过修改。来发现补丁。

代码:
FP_Check_FileSize:
FP_Check_FileSize_Arg_Win32Api      equ 08h
FP_Check_FileSize_StackSize         equ MAX_PATH
FP_Check_FileSize_szPath            equ -MAX_PATH
    push ebp
    mov ebp, esp
    sub esp, FP_Check_FileSize_StackSize
    
    push ebx
    push ecx
    push edx
    mov ebx, dword ptr [ebp+FP_Check_FileSize_Arg_Win32Api]
    assume ebx : ptr WIN32APIBASE
    
    push MAX_PATH
    lea eax, [ebp+FP_Check_FileSize_szPath]
    push eax
    push NULL
    call dword ptr [ebx].xGetModuleFileNameA
    test eax, eax
    jz NotFound_FP_Check_FileSize
    
    ;; create file
    push NULL
    push FILE_ATTRIBUTE_NORMAL
    push OPEN_ALWAYS
    push NULL
    push FILE_SHARE_READ
    push GENERIC_READ
    lea eax, [ebp+FP_Check_FileSize_szPath]
    push eax
    call dword ptr [ebx].xCreateFileA
    cmp eax, INVALID_HANDLE_VALUE
    jz NotFound_FP_Check_FileSize
    mov ecx, eax
    
    push NULL
    push eax
    call dword ptr [ebx].xGetFileSize
    mov edx, eax
    
    push ecx
    call dword ptr [ebx].xCloseHandle
    
    call Get_FP_Check_FileSize_Eip
    Get_FP_Check_FileSize_Eip:
    pop eax
    add eax, offset FP_Check_FileSize_Orig_Size - offset Get_FP_Check_FileSize_Eip
    cmp edx, eax
    jnz Found_FP_Check_FileSize
    jmp NotFound_FP_Check_FileSize

Exit_FP_Check_FileSize:
    pop edx
    pop ecx
    pop ebx
    assume ebx : nothing
    
    mov esp, ebp
    pop ebp
    retn 04h
NotFound_FP_Check_FileSize:
    xor eax, eax
    jmp Exit_FP_Check_FileSize
Found_FP_Check_FileSize:
    mov eax, 1
    jmp Exit_FP_Check_FileSize
FP_Check_FileSize_Orig_Size:
    dd 0   
End_FP_Check_FileSize:

通过计算文件的CRC值来对比是否被Cracker进行过修改打过补丁。

代码:
FP_Check_FileHashValue_CRC:
FP_Check_FileHashValue_CRC_Arg_Win32Api         equ 08h
FP_Check_FileHashValue_CRC_Arg_FuncAddr            equ 0ch
FP_Check_FileHashValue_CRC_StackSize            equ 20h+MAX_PATH
FP_Check_FileHashValue_CRC_fileSize             equ -04h
FP_Check_FileHashValue_CRC_NumberOfBytesRW      equ -08h
FP_Check_FileHashValue_CRC_CRCVALUE_current     equ -0ch
FP_Check_FileHashValue_CRC_pBuffer              equ -10h
FP_Check_FileHashValue_CRC_hFile                equ -14h
FP_Check_FileHashValue_CRC_szFileName           equ -(20h+MAX_PATH)
    
    push ebp
    mov ebp, esp
    sub esp, FP_Check_FileHashValue_CRC_StackSize
    
    push ebx
    push ecx
    push edx
    push esi
    push edi
    
    ;; clear the stack
    lea edi, [ebp-FP_Check_FileHashValue_CRC_StackSize]
    mov ecx, FP_Check_FileHashValue_CRC_StackSize
    xor eax, eax
    cld
    rep stosb
    
    mov ebx, dword ptr [ebp+FP_Check_FileHashValue_CRC_Arg_Win32Api]
    assume ebx : ptr WIN32APIBASE
    
    push MAX_PATH
    lea eax, [ebp+FP_Check_FileHashValue_CRC_szFileName]
    push eax
    push NULL
    call dword ptr [ebx].xGetModuleFileNameA
    
    push NULL
    push FILE_ATTRIBUTE_NORMAL
    push OPEN_EXISTING
    push NULL
    push FILE_SHARE_READ
    push GENERIC_READ
    lea eax, [ebp+FP_Check_FileHashValue_CRC_szFileName]
    push eax
    call dword ptr [ebx].xCreateFileA
    cmp eax, INVALID_HANDLE_VALUE
    jz NotFound_FP_Check_FileHashValue_CRC
    mov dword ptr [ebp+FP_Check_FileHashValue_CRC_hFile], eax
    
    push NULL
    push dword ptr [ebp+FP_Check_FileHashValue_CRC_hFile]
    call dword ptr [ebx].xGetFileSize
    ;cmp eax, INVALID_FILE_SIZE
    ;jz NotFound_FP_Check_FileHashValue_CRC
    mov dword ptr [ebp+FP_Check_FileHashValue_CRC_fileSize], eax
    
    push PAGE_READWRITE
    push MEM_COMMIT
    push eax
    push NULL
    call dword ptr [ebx].xVirtualAlloc
    mov dword ptr [ebp+FP_Check_FileHashValue_CRC_pBuffer], eax
    
    ;; read file
    push NULL
    lea eax, [ebp+FP_Check_FileHashValue_CRC_NumberOfBytesRW]
    push eax
    push dword ptr [ebp+FP_Check_FileHashValue_CRC_fileSize]
    push dword ptr [ebp+FP_Check_FileHashValue_CRC_pBuffer]
    push dword ptr [ebp+FP_Check_FileHashValue_CRC_hFile]
    call dword ptr [ebx].xReadFile
    
    push dword ptr [ebp+FP_Check_FileHashValue_CRC_hFile]
    call dword ptr [ebx].xCloseHandle
    
    ;; get CRC value
    push dword ptr [ebp+FP_Check_FileHashValue_CRC_fileSize]
    push dword ptr [ebp+FP_Check_FileHashValue_CRC_pBuffer]
    mov eax, dword ptr [ebp+FP_Check_FileHashValue_CRC_Arg_FuncAddr]
    assume eax : ptr FUNCADDRTBL
    call dword ptr [eax].xCRC32
    mov esi, eax
    
    ;; release the memory
    push MEM_RELEASE
    push dword ptr [ebp+FP_Check_FileHashValue_CRC_fileSize]
    push dword ptr [ebp+FP_Check_FileHashValue_CRC_pBuffer]
    call dword ptr [ebx].xVirtualFree    
    
    call Get_FP_Check_FileHashValue_CRC_Eip
    Get_FP_Check_FileHashValue_CRC_Eip:
    pop edi
    add edi, offset FP_Check_FileHashValue_Orig_CRC - offset Get_FP_Check_FileHashValue_CRC_Eip
    sub edi, esi
    jz NotFound_FP_Check_FileHashValue_CRC
    jmp Found_FP_Check_FileHashValue_CRC
    
Exit_FP_Check_FileHashValue_CRC:
    pop edi
    pop esi
    pop edx
    pop ecx
    pop ebx
    assume eax : nothing
    assume ebx : nothing
    mov esp, ebp
    pop ebp
    retn 08h
NotFound_FP_Check_FileHashValue_CRC:
    xor eax, eax
    jmp  Exit_FP_Check_FileHashValue_CRC
Found_FP_Check_FileHashValue_CRC:
    mov eax, 1
    jmp  Exit_FP_Check_FileHashValue_CRC
FP_Check_FileHashValue_Orig_CRC:
    dd 0   
End_FP_Check_FileHashValue_CRC:

Windows NT系列平台支持一个会话多个桌面,将线程的桌面交换到自己的桌面。
目前还没有有效的方法转换到旧的桌面。

代码:
AD_SwitchDesktop:
AD_SwitchDesktop_Arg_Win32Api            equ 04h
    mov eax, dword ptr [esp+AD_SwitchDesktop_Arg_Win32Api]
    
    push ebx
    push ecx
    push edx
    push edi
    push esi
    
    mov ebx, eax
    assume ebx : ptr WIN32APIBASE
    
    call dword ptr [ebx].xGetCurrentThreadId
    push eax
    call dword ptr [ebx].xGetThreadDesktop
    mov ecx, eax
    
    push DESKTOP_SWITCHDESKTOP
    push FALSE
    push 0
    call dword ptr [ebx].xOpenInputDesktop
    mov edx, eax
    
    push NULL
    push GENERIC_ALL
    push 0
    push NULL
    push NULL
    call AD_SwitchDesktop_Str
        db "MyDesktop",0
    AD_SwitchDesktop_Str:
    call dword ptr [ebx].xCreateDesktopA
    mov esi, eax
    
    push esi
    call dword ptr [ebx].xSetThreadDesktop
    
    push esi
    call dword ptr [ebx].xSwitchDesktop
    
    push 5000
    call dword ptr [ebx].xSleep
    
    push edx
    call dword ptr [ebx].xSwitchDesktop
    
    push ecx
    call dword ptr [ebx].xSetThreadDesktop
    
    push esi
    call dword ptr [ebx].xCloseDesktop
    
    mov eax, 1
    
    pop esi
    pop edi
    pop edx
    pop ecx
    pop ebx
    assume ebx : nothing
    retn 04h
End_AD_SwitchDesktop:

BlockInput函数阻止了鼠标和键盘事件到达应用程序。

代码:
AD_BlockInput:
AD_BlockInput_Arg_Win32Api        equ 04h
    mov eax, dword ptr [esp+AD_BlockInput_Arg_Win32Api]
    
    push ebx
    mov ebx, eax
    assume ebx : ptr WIN32APIBASE
    
    push TRUE
    call dword ptr [ebx].xBlockInput
    test eax, eax
    jz Exit_AD_BlockInput
    push 5000
    call dword ptr [ebx].xSleep
    
    push FALSE
    call dword ptr [ebx].xBlockInput
    xor eax, eax
Exit_AD_BlockInput:
    pop ebx
    assume ebx : nothing
    retn 04h
End_AD_BlockInput:

利用Nativa API函数ZwSetInformationThread函数通过ThreadHideFromDebugger来达到隐藏调试器的目的

代码:
AD_ZwSetInfomationThread:
AD_ZwSetInfomationThread_Arg_Win32Api        equ 04h
    mov eax, dword ptr [esp+AD_ZwSetInfomationThread_Arg_Win32Api]
    push ebx
    mov ebx, eax
    assume ebx : ptr WIN32APIBASE
    
    push 0
    push NULL
    push ThreadHideFromDebugger
    call dword ptr [ebx].xGetCurrentThread
    push eax
    call dword ptr [ebx].xZwSetInformationThread
    cmp eax, STATUS_SUCCESS
Exit_AD_ZwSetInfomationThread:
    pop ebx
    assume ebx : nothing
    retn 04h
End_AD_ZwSetInfomationThread:

通过系统索引号调用NtSetInformationThread使用ThreadHideFromDebugger来达到隐藏调试器的目的

代码:
AD_INT_2e:
AD_INT_2e_Arg_Win32Api            equ 08h
AD_INT_2e_StackSize                equ 10h + sizeof OSVERSIONINFOEX
AD_INT_2e_bOsVersionInfoEx      equ -04h
AD_INT_2e_osvi                  equ -(10h+sizeof OSVERSIONINFOEX)
    push ebp
    mov ebp, esp
    sub esp, AD_INT_2e_StackSize
    
    push ebx
    push ecx
    push edx
    push edi
    push esi
    
    mov ebx, dword ptr [ebp+AD_INT_2e_Arg_Win32Api]
    assume ebx : ptr WIN32APIBASE
    
    lea edx, [ebp+AD_INT_2e_osvi]
    assume edx : ptr OSVERSIONINFOEX
    
    ;; clear the stack
    lea edi, [ebp-AD_INT_2e_StackSize]
    mov ecx, AD_INT_2e_StackSize
    xor eax, eax
    cld
    rep stosb
    
    push sizeof OSVERSIONINFOEX
    pop dword ptr [edx].dwOSVersionInfoSize
    
    call dword ptr [ebx].xGetCurrentThread
    mov esi, eax
    
    lea edx, [ebp+AD_INT_2e_osvi]
    push edx
    call dword ptr [ebx].xGetVersionExA
    test eax, eax
    jz Exit_AD_INT_2e
    ;; Test for the Windows NT product family
    lea edx, [ebp+AD_INT_2e_osvi]    
    cmp dword ptr [edx].dwPlatformId, VER_PLATFORM_WIN32_NT
    jnz Exit_AD_INT_2e
    push 0
    push 0
    push ThreadHideFromDebugger
    push esi
    mov eax, 0EEh        ; NtSetInformationThread
    mov edx, esp
    int 2eh
    add esp, 10h
    
    push 0
    push 0
    push ThreadHideFromDebugger
    push esi
    mov eax, 0E5h        ; NtSetInformationThread
    mov edx, esp
    int 2eh
    add esp, 10h
    ;jmp Found_AD_INT_2e
    ;AD_INT_2e_Tmp1:
    ;; Test for the Windows 95 product family
    ;cmp dword ptr [edx].dwPlatformId, VER_PLATFORM_WIN32_WINDOWS
    ;jnz AD_INT_2e_Tmp2
    ;AD_INT_2e_Tmp2:
    ;; Microsoft Win32s
Exit_AD_INT_2e:
    xor eax, eax
    pop esi
    pop edi
    pop edx
    pop ecx
    pop ebx
    assume ebx : nothing
    assume edx : nothing
    mov esp, ebp
    pop ebp
    retn 04h
End_AD_INT_2e:

Ollydbg传递用户定义的数据给msvcrt的vsprintf函数,如果这些数据包含
格式字符串标记.如果包换多个%s标记,这样会指向一个无效的内存导致
ollydbg失效。

代码:
AS_OD_OutputDebugString:
AS_OD_OutputDebugString_Arg_Win32Api        equ 04h
    mov eax, dword ptr [esp+AS_OD_OutputDebugString_Arg_Win32Api]
    assume eax : ptr WIN32APIBASE
    call AS_OD_OutputDebugString_Str
        db "%s%s",0
    AS_OD_OutputDebugString_Str:
    call dword ptr [eax].xOutputDebugStringA
    xor eax, eax
    assume eax : nothing
    retn 04h
End_AS_OD_OutputDebugString:

通过触发异常进入异常处理程序,将调试寄存器清0,清除断点。
Dr0,Dr1,Dr2,Dr3,Dr6和Dr7。Dr0-Dr3用作一般的线性地址,Dr6为调试状态寄存器
Dr7为调试控制寄存器。

代码:
AB_HWP_CLR_Exception:
    call Get_AB_HWP_CLR_Exception_Eip
    Get_AB_HWP_CLR_Exception_Eip:
    pop eax
    add eax, offset AB_HWP_CLR_Exception_Exception - offset Get_AB_HWP_CLR_Exception_Eip
    push eax
    assume fs : nothing
    push dword ptr fs:[0]
    mov dword ptr fs:[0], esp
    xor eax, eax
    ;; throw an exception
    div eax
    ;; restore exception handler
    pop dword ptr fs:[0]
    add esp, 04h
    jmp Exit_AB_HWP_CLR_Exception
AB_HWP_CLR_Exception_Exception:
    mov eax, dword ptr [esp+0ch]
    assume eax : ptr CONTEXT
    ;; clr debug registers context Dr0-Dr3
    mov dword ptr [eax].iDr0, 0
    mov dword ptr [eax].iDr1, 0
    mov dword ptr [eax].iDr2, 0
    mov dword ptr [eax].iDr3, 0
    mov dword ptr [eax].iDr6, 0
    mov dword ptr [eax].iDr7, 0
    ;; set eip upon return
    add dword ptr [eax].regEip, 02h
    xor eax, eax
    retn
Exit_AB_HWP_CLR_Exception:
    xor eax, eax
    assume eax : nothing
    retn 0h
End_AB_HWP_CLR_Exception:

还有很多反调试的方法没有归结到上面,一开始想做的全些。但是后来发现,太多了。还是以后慢慢归纳吧。
附件中的程序是一个可以添加反调试代码到其他程序的一个小玩意。
使用命令为AntiDebugger 1 2 3 4 file.exe 类似这样 ^_^
终于写完了,累吖。。。

 

上传的附件
文件类型: rarAntiDebugger_bin.rar (5.9 KB, 360 次下载) [谁下载?]
文件类型: rarAntiDebugger_src.rar (17.4 KB, 365 次下载) [谁下载?]
第十一章 软件保护技术(一)(软件保护技术简介) 文章目录软件保护技术软件保护技术简介 软件保护技术 伴随软件破解技术发展 经历软件安全对抗技术的演变,向信息安全技术标准化和安全服务产业化的方向发展 (Android 平台)包括通用软件保护技术和特定平台的软件保护技术 软件保护技术简介 按不同授权类别,软件分为: 专属软件 拥有此类授权的软件不允许用户随意复制、研究、修改和发布它,违反此类授权违法 传统商业软件采用此类授权 自由软... 阅读详情

相关推荐

Themida是先进的Windows软件保护系统

​ 借助 Themida®,我们将重点放在软件保护程序的主要弱点上,从而提供了一个完整的解决方案来克服这些问题。Themida® 使用 SecureEngine® 保护技术,当以最高优先级运行时,实施前所未有的保护技术来保护应用程序免受高级软件破解。 ​

goldksoft的博客 1100

脱壳的艺术

脱壳的艺术 Mark Vincent Yason 概述:脱壳是门艺术——脱壳既是一种心理挑战,同时也是逆向领域最为激动人心的智力游戏之一。为了甄别或解决非常难的反逆向技巧,逆向分析人员有时不得不了解操作系统的一些底层知识,聪明和耐心也是成功脱壳的关键。这个挑战既牵涉到壳的创建者,也牵涉到那些决心躲过这些保护的脱壳者。 本文主要目的是介绍壳常用的反逆向技术,同时也探讨了可以用来躲过或禁用这些保

小丢的专栏 7937

第十二章 软件壳(一)(Android 软件壳)

文章目录软件壳Android 软件壳 软件壳 Windows 平台的软件壳 压缩壳 着重于减小软件体积 代表 UPX ASPack NSPack 不采用软件保护技术 没有用于进行调试器检测的代码 加密壳 产品众多 大多被恶意软件用来对抗杀软查杀 可配合压缩壳进行多次加密,达到较高强度的加密效果 保护壳 比加密壳更难脱壳 强调高强度的代码保护,包括对调用 API 的方法抽取、多进程保护、内存校验、反调试器与虚拟机、系统注入等 代表 Armadillo ASProtect SafeGu

zlmm741的博客 667

栈又溢出了

stackoverflow again! 编译器什么时候会生成检查栈的代码呢?_chkstk 内部都做了哪些事呢?该如何避免呢?本文以一个实际项目中的栈溢出为出发点,尽量挖掘出栈溢出背后的一些逻辑。欢迎留言交流!

493

软件保护之注册算法篇

软件保护之注册算法篇fangle 2003一、前言通常地,软件保护可分为三大环节:反调试、抗分析、防爆破1、反调试,给你的软件引入非常规的运行机制,例如加壳,来限制调试工具对你的软件的掌控   能力。如今调试工具越来越强大,但调试工具的设计目标毕竟是光明正大的,大多不会专门   防备反调试技术。所以反调试技术还是相当重要的:它能够大大减少你的潜在对手。毕竟,   如果调试工具能够很轻易

不甘碌碌老,结庐铸宝刀 5669

69、软件保护与防篡改技术解析

本文深入解析了软件保护与防篡改技术,涵盖常见的保护方法如输入验证、硬件验证、网络验证、环境验证和完整性验证,并分析了它们的优缺点及绕过方式。同时探讨了针对不同破解者的应对策略,以及防篡改技术的综合运用与未来发展趋势,旨在帮助开发者构建更安全的软件保护机制。

u0v1w2x3的博客 139

windows-rs内存保护:设置页面属性与Guard Pages

在Windows系统中,内存保护是保障程序稳定性和安全性的核心机制。通过设置内存页面属性,开发者可以控制程序对特定内存区域的访问权限,防止非法读写操作导致的崩溃或安全漏洞。Guard Pages(防护页)作为一种特殊的内存保护技术,能够在内存溢出发生时提供即时检测能力,是防御缓冲区溢出攻击的重要手段。 windows-rs库通过`windows_sys`模块提供了对Windows内存管理API的...

gitblog_01197的博客 910

Fluent VOF造波从入门到放弃?手把手教你用k-w SST模型搞定波浪模拟

本文详细介绍了使用Fluent VOF和k-w SST模型进行波浪模拟的实战技巧,从参数设置到结果优化,帮助用户避开常见误区。通过工业项目验证的配置方案,提升波浪模拟的准确性和计算效率,特别适合处理多相流和复杂湍流场景。

weixin_27102543的博客 422

灰帽子Python 学习记录 8 内存断点

内存断点原理:就是通过设置内存块页面的权限,使其成为保护页。这样当CPU访问该页面时,就会触发保护页的访问异常,产生中断。需要调用异常处理函数将权限恢复从而继续执行。 实现步骤: 1. 找函数的地址还是和前面一样 2. 通过VirtualQueryEx传入地址,获取一个填充好的MEMORY_BASIC_INFORMATION结构,里面包含页基址、页大小等信息。 3. Virtu

MarStarck的专栏 751

解锁微信小程序Camera组件的隐藏技能:连续扫码背后的逻辑与陷阱

本文深入解析微信小程序Camera组件在连续扫码功能中的技术原理与优化方案,涵盖识别率提升、内存管理策略及典型问题排查。通过实战参数对比和代码示例,帮助开发者解决扫码枪应用中的性能损耗与界面卡顿问题,提升零售、物流等场景的工作效率。

weixin_29019241的博客 494

全志V3S开发板实战:从零构建嵌入式Linux系统

本文提供了一份针对全志V3S开发板(如LicheePi Zero)的零基础教程,详细指导如何从零开始构建嵌入式Linux系统。内容涵盖编译环境搭建、交叉工具链配置、U-Boot引导程序编译与烧录、Linux内核定制与编译,以及使用Buildroot构建根文件系统,最终实现系统成功启动,帮助开发者深入理解嵌入式系统构建全流程。

tensor9flow的博客 575

软件保护技术

本文已收录至《全国计算机等级考试——信息 安全技术》专栏。

2302_76241188的博客 1546

展锐双摄帧同步实战:从配置到调试的完整避坑指南

本文深入剖析了在展锐平台上实现双摄帧同步的完整流程与核心技术。详细对比了硬件帧同步与软件帧同步的差异、应用场景及核心挑战,提供了从XML配置、驱动层适配到调试验证的实战指南。重点强调了硬件帧同步必须与固定帧率强绑定这一关键避坑点,并分享了针对景深虚化等场景的同步质量验证方法及长稳测试策略。

kiwi8的博客 402

基于虚拟机的软件保护技术

导读 基于虚拟机的软件保护技术不确定是否首先由vmprotect提出,但vmprotect毫无疑问是将这项技术大力推广至人所周知。现在基于虚拟机的软件保护技术已经成为现代软件安全防护的必备功能之一。 本文并不打算对vmprotect或其它某款软件安全套件进行深入讨论,而着眼于研究基于虚拟机的软件保护技术的起源、思想和实现。 现有软件保护技术概述 传统的软件保

Jack__CJ的博客 1075

【全局路径规划模块运动学算法】无人机Kinodynamic A*算法、Kinodynamic RRT*算法(附C++代码)

认知有限,望大家多多包涵,有什么问题也希望能够与大家多交流,共同成长!本文先对Kinodynamic A*算法做个简单的介绍,具体内容后续再更,其他模块可以参考去我其他文章提示:以下是本篇文章正文内容啃这个Kinodynamic A_star算法,建议先啃一啃高飞fast_planner那篇论文,把理论打好,如果还是比较迷,就先看Dijksta、再看A_star、再看hybrid A_star 三个的流程,因为往上资料比较多,再看这个Kinodynamic A_star算法,流程已经很相像了。如果。

qq_35635374的博客 2604

DeepSeek赋能公文写作:从高效成文到精准传情的全维度指南

摘要:AI赋能公文写作的精准化实践 公文写作长期面临框架混乱、素材匮乏、表达不规范、修改低效等痛点。DeepSeek等AI工具通过"精准指令+分步赋能"模式实现突破:首先明确公文的目的性、逻辑性和规范性特征;其次采用包含场景、类型、目的等要素的指令模板;再分四步实施:框架搭建确保层次分明,内容填充解决素材问题,表达优化适配不同语体,合规校验把关格式规范。典型案例显示,AI能将数据罗列转化为"数据+成果+价值"的生动表述,使公文既规范又具感染力。这种AI赋能的写作方法显

通俗易懂学IT 233

hook与注入&& 软件保护技术 &&软件壳

hook的类型 java层:1.Dalvik hook 2.ART hook Native层: 1.LD_PRELOAD_Hook 2.Inline hook hook框架xposed 吐了 老是报错l…为什么。。。 https://blog.youkuaiyun.com/tanmx219/article/details/81369229【已解决】

qq_37439229的博客 398

基于 高斯过程回归(Gaussian Process Regression, GPR) 的 时间序列区间预测 的 MATLAB 示例代码

基于 高斯过程回归(Gaussian Process Regression, GPR) 的 时间序列区间预测 的 MATLAB 示例代码

算法如诗的博客 155

细说软件保护

随着计算机与互联网相关技术的蓬勃高速发展,计算机已不再是“专业人员”的独有工具软件应用也逐渐与人们的日常生活深度绑定。如何妥善的保护软件,让软件安全运行在用户/客户的设备上,更好的服务大众助力业务稳定发展,软件保护自始至终都是一个重要的问题。从软件保护的视角来看,可以笼统的分为应用保护、代码保护、算法保护,本文也将从这 3 个纬度进行阐述软件保护相关的问题。

2401_88326591的博客 1369

基于 ESP32 的智能药盒提醒装置设计与实现

本装置基于 ESP32 实现了智能药盒的核心功能,硬件选型兼顾成本与实用性,软件设计模块化、易拓展。后续可通过 ESP32 的 WiFi 模块接入物联网平台(如阿里云、OneNet),实现远程设置提醒、服药状态反馈等功能,进一步提升智能化水平。该装置能有效解决老人忘服药问题,具有较高的实用价值与推广潜力。

weixin_42300449的博客 1045

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

[逆向工程]基于x32dbg的软件保护机制分析(八)

软件逆向工程的标准工作流x32dbg的高级调试技巧软件保护与破解的攻防对抗本质欢迎在评论区交流技术问题(严禁讨论非法用途),关注作者获取更多逆向工程实战教程。

曼岛_的博客 2424

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

细说软件保护:从应用保护到算法保护

随着计算机与互联网相关技术的蓬勃高速发展,计算机已不再是“专业人员”的独有工具软件应用也逐渐与人们的日常生活深度绑定。如何妥善的保护软件,让软件安全运行在用户/客户的设备上,更好的服务大众助力业务稳定发展,软件保护自始至终都是一个重要的问题。从软件保护的视角来看,可以笼统的分为应用保护、代码保护、算法保护,本文也将从这 3 个纬度进行阐述软件保护相关的问题。

2503_90751938的博客 1277

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

050_软件保护与逆向分析的博弈:高级反调试、加密与代码混淆技术实战指南

在当今数字化时代,软件已成为企业和个人的核心资产。然而,随着逆向工程技术的不断发展,软件面临着前所未有的安全挑战。软件保护不仅关系到知识产权保护,还涉及到商业利益、数据安全和用户隐私等多个方面。

欢迎来到智能安全前线!这里是AI与信息安全交汇之地。我们以代码为武器,深入大模型攻防实战,破解系统漏洞。追踪OpenAI、Meta前沿动态,用红蓝对抗思维,锻造智能时代的坚盾与利矛。 1750

全面的牛壳介绍

ASProtect:无可争议的外壳界老大,它开创了壳的新时代,SEH 与各种流行反跟踪技术、多态变形引擎的使用(准确来说是从病毒中借用)、BPM 断点清除等都出自于此;更为有名的当属 RSA 算法的使用,使得 DEMO 版无法被破解成完整版;Code Dips也源于这里;输入表处理即使现在看来仍很强劲。开发壳应该学习它各种算法的熟练运用,而它最失败之处就是反跟踪过于温柔,令破解者轻松研究。tELo

不论你在什么时候开始,重要的是开始之后就不要停止。 1886
上一篇: 增加区段的VC嵌汇编代码
下一篇: fs TIB TEB PEB
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值