windows筛选器异常处理

筛选器异常

概念
异常默认是由操作系统处理的,现在用API设置由用户自己定义处理异常(内存访问无效,修改到常量区等错误),当发生异常的时候,系统将调用这个回调函数,并根据回调函数的返回值决定如何进行下一步操作
在进程范围内,筛选器异常处理回调函数是惟一的,设置了一个新的回调函数后,原来的就失效了
语法
设置异常发生处理器

invoke SetUnhandledExceptionFilter, offset MyFilter  //参数为异常回调处理函数

自定义异常处理异常回调处理函

.const
    ERRMSG db "由于用户操作失误!导致软件出现异常", 0
    OKMSG db "由正常操作", 0
    FORMAT db "ExceptionAddress=%p ExceptionCode=%p ExceptionFlags=%p NumberParameters:%d", 0
  
MyFilter proc ,ExceptionInfo:ptr EXCEPTION_POINTERS  
  
    mov eax, ExceptionInfo
    mov eax, [eax]
    assume eax :ptr EXCEPTION_RECORD                     ;拿到错误记录内容  
  
    invoke wsprintf, offset BUFFER, offset FORMAT,       ;格式化输出错误信息
        [eax].ExceptionAddress,
        [eax].ExceptionCode, 
        [eax].ExceptionFlags, 
        [eax].NumberParameters
    
    invoke MessageBox,NULL, offset BUFFER, NULL, MB_OK   ;弹窗提示用户
  
    mov eax, EXCEPTION_EXECUTE_HANDLER                   ;异常处理了,处理完直接退出进程
    ;mov eax, EXCEPTION_CONTINUE_SEARCH                  ;自己处理不了也就是没有处理继续查找让其他筛选器处理
    ;mov eax, EXCEPTION_CONTINUE_EXECUTION               ;异常处理了,bug修复了,继续从原出错的代码行继续执行
    ret
MyFilter endp

异常回调的参数信息

;异常信息结构体
typedef struct _EXCEPTION_POINTERS 
{ 
    PEXCEPTION_RECORD ExceptionRecord;   //保存异常信息
    PCONTEXT ContextRecord;              //保存了异常发生寄存器信息
} EXCEPTION_POINTERS;

typedef struct _EXCEPTION_RECORD 
{
    DWORD ExceptionCode;                //异常错误码
    DWORD ExceptionFlags;               //标志异常发生后是否还可以继续执行
    struct _EXCEPTION_RECORD *ExceptionRecord; 
    PVOID ExceptionAddress;             //异常发生内存位置
    DWORD NumberParameters;             //为ExceptionInformation数组的个数
    DWORD ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; //异常附加参数信息,只有当ExceptionCode为EXCEPTION_ACCESS_VIOLATION,此参数才有
} EXCEPTION_RECORD;


应用场景

反调试代码加密(加密是因为可以防止他人改eip跳过你的异常,加了密之后就算跳过看到的也是加密后的代码,执行加密的代码段也是会错的)
设计思路
代码段进行加密
代码开始产生异常报错
异常筛选器的回调内解密代码,重设eip信息
程序继续运行
优势
非调试状态能正常执行程序
调试状态不能正常执行程序(注册异常后用调试工具的话,异常会被调试工具接收,断点不了异常处理函数,也就调试不了程序,除非找到你的异常处理函数的,肉眼找代码可挺烦的)
代码示例

.data
;用一个全局变量来保存异常函数指针
ERRPRO dd offset IinitInfo

;异常处理回调函数
MyFilter proc ,ExceptionInfo:ptr EXCEPTION_POINTERS
    ;重新设置eip位置
    mov eax, [eax].ContextRecord
    assume eax :ptr CONTEXT
    add [eax].regEip, 6
    
    ;解密代码段
    mov ebx, [eax].regEip
    mov ecx, 0
LOOP1:
    xor byte ptr [ebx+ecx], 90h            ;8个字节的代码与90h异或拿到实际代码
    inc ecx
    cmp ecx, 8
    jl  LOOP1
    
    mov eax, EXCEPTION_CONTINUE_EXECUTION  ;解密完成,执行正确段的代码
    ret
MyFilter endp

;包装一个函数来注册并产生异常
IinitInfo proc
    invoke SetUnhandledExceptionFilter, offset MyFilter
    mov eax, 1
    mov dword ptr [eax], 0   
MyFilter endp


START:
  ;注册并产生异常
  mov eax,ERRPRO
  call eax
  
  mov eax, eax
  invoke MessageBox,NULL, offset OKMSG, NULL, MB_OK
  ret
end START

保存异常日志

设计思路
利用异常处理函数的参数获取参数信息
保存异常信息到文件中
示例代码

.386
.model flat, stdcall  ;32 bit memory model
option casemap :none  ;case sensitive

include windows.inc
include kernel32.inc
include user32.inc
include Stdlib.Inc
includelib KERNEL32.LIB
includeLIB user32.lib
includelib Stdlib.lib


MyTime STRUCT                   ;时间结构体
	m_Year            dd 0
	m_Month           dd 0
	m_Date            dd 0
	m_Hour            dd 0
	m_Minutue         dd 0   	
MyTime ends


.const
  ERRMSG db "由于用户操作失误!导致软件出现异常", 0
  FORMAT db "=====exception===== ",0ah,0dh,
            " OccurTime: %d-%d-%d  %d:%d",0ah,0dh,
            " FilePath: %s",0ah,0dh,
            " Address: %p",0ah,0dh,
            " Code: %p",0ah,0dh,
            " Flags: %p",0ah,0dh,
            " NumberParameters: %d", 0ah,0dh,0
  REGFORMAT db "======reginfo======= ",0ah,0dh,
            "eax: %d  ebx: %d  ecx: %d  edx: %d  esi: %d  edi: %d  ebp: %d  eip: %d  EFlags: %d",0ah,0dh,0
  STKTITLE db 0ah,0dh,"======stack======= ",0ah,0dh,0
  MEMTITLE db "======memory====== ",0ah,0dh,0

  FILENAME db "ErrorRecord.text",0

.data
  g_Test dd(0cccccccch)
  g_Test2 db 50 dup(0ch)
  
  g_Buffer db 300 dup(0)
  g_FileName db 100 dup(0)
  g_RegInfo db  100 dup(0)



; 异常处理函数
MyFilter proc ,ExceptionInfo:ptr EXCEPTION_POINTERS 
  LOCAL @tTime:SYSTEMTIME
  LOCAL @tagMyTime:MyTime
  LOCAL @ats:SECURITY_ATTRIBUTES
  LOCAL @hFile:HANDLE
  LOCAL @dwWrite:DWORD
  LOCAL @dwBytesToWrited:DWORD
  LOCAL @dwStackLocate:DWORD
  ;@nSize:DWORD

  ;初始化文件句柄
  mov @hFile,0

  ;拿到发生错误的时间
  invoke GetLocalTime,addr @tTime
  
  ;拿到发生错误的文件路径
  invoke GetModuleFileName,NULL,offset g_FileName,100
  
  ;拿到错误信息结构体
  mov eax,ExceptionInfo
  mov eax, [eax]
  assume eax :ptr EXCEPTION_RECORD  
  
  lea ebx,@tTime
  assume ebx:ptr SYSTEMTIME
  

  mov ecx,0
  mov cx,[ebx].wYear
  mov @tagMyTime.m_Year,ecx
  mov cx,[ebx].wMonth
  mov @tagMyTime.m_Month,ecx
  mov cx,[ebx].wDay
  mov @tagMyTime.m_Date,ecx
  mov cx,[ebx].wHour
  mov @tagMyTime.m_Hour,ecx
  mov cx,[ebx].wMinute
  mov @tagMyTime.m_Minutue,ecx


  invoke wsprintf, offset g_Buffer, offset FORMAT,
                   @tagMyTime.m_Year,@tagMyTime.m_Month,@tagMyTime.m_Date, @tagMyTime.m_Hour,@tagMyTime.m_Minutue,
                   offset g_FileName,
                   [eax].ExceptionAddress,              ;异常发生内存位置
                   [eax].ExceptionCode,                 ;异常错误码
                   [eax].ExceptionFlags,                ;标志异常发生后是否还可以继续执行
                   [eax].NumberParameters               ;异常附加参数信息,只有当ExceptionCode为EXCEPTION_ACCESS_VIOLATION,此参数才有用
       
  ;invoke MessageBox,NULL, offset g_Buffer, NULL, MB_OK                 
  
  ;取消假设        
  assume ebx:nothing
                     
  ;拿到寄存器信息结构体
  mov eax,ExceptionInfo
  assume eax:ptr EXCEPTION_POINTERS
  mov eax,[eax].ContextRecord
  assume eax:ptr CONTEXT
  
  ;保存栈的位置
  mov ebx,[eax].regEbp
  mov @dwStackLocate,ebx
  
  ;保存寄存器信息
  invoke wsprintf,offset g_RegInfo,offset REGFORMAT,
                [eax].regEax,[eax].regEbx,[eax].regEcx,[eax].regEdx,
                [eax].regEsi,[eax].regEdi,[eax].regEbp,[eax].regEsp,
                [eax].regFlag
                
  assume eax:nothing
  
  ;invoke MessageBox,NULL, offset g_RegInfo, NULL, MB_OK
  
  ;新建日志文件
  mov @ats.nLength,sizeof @ats
  mov @ats.bInheritHandle,TRUE
  mov @ats.lpSecurityDescriptor,NULL
  
  invoke CreateFile,offset FILENAME,GENERIC_WRITE,FILE_SHARE_WRITE,addr @ats,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL
  .if eax == NULL
    jmp SAFE_EXIT
  .endif
  mov @hFile,eax
  
  ;写入异常信息
  invoke StrLen,offset g_Buffer
  mov @dwWrite,eax
  invoke WriteFile,@hFile,offset g_Buffer,@dwWrite,addr @dwBytesToWrited,NULL
  
  ;写入寄存器信息
  invoke StrLen,offset g_RegInfo
  mov @dwWrite,eax
  invoke WriteFile,@hFile,offset g_RegInfo,@dwWrite,addr @dwBytesToWrited,NULL
  
  ;写入内存信息
  invoke StrLen,offset MEMTITLE
  mov @dwWrite,eax
  invoke WriteFile,@hFile,offset MEMTITLE,@dwWrite,addr @dwBytesToWrited,NULL
  
  mov @dwWrite,50
  invoke WriteFile,@hFile,offset g_Test,@dwWrite,addr @dwBytesToWrited,NULL
  
  ;写入堆栈信息
  invoke StrLen,offset STKTITLE
  mov @dwWrite,eax
  invoke WriteFile,@hFile,offset STKTITLE,@dwWrite,addr @dwBytesToWrited,NULL
  
  mov @dwWrite,50h
  invoke WriteFile,@hFile,@dwStackLocate,@dwWrite,addr @dwBytesToWrited,NULL
  
       
SAFE_EXIT:
  .if @hFile != NULL
    invoke CloseHandle,@hFile         ;关闭文件
  .endif

  mov eax, EXCEPTION_EXECUTE_HANDLER  ;退出进程
  
  ret
MyFilter endp
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值