⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sehexcpt.dpr

📁 一本已经绝版的好书
💻 DPR
字号:

// Module name: SEHExcpt.C ->> SEHExcpt.dpr
// Notices: Copyright (c) 1995-1997 Jeffrey Richter
// Translator: 刘麻子, Liu_mazi@126.com

program SEHExcpt;

{$R 'SEHExcpt.res' 'SEHExcpt.rc'}

uses
  Windows, Messages,
  Other in '..\Other.pas', CmnHdr in '..\CmnHdr.pas', WindowsX in '..\WindowsX.pas';

const
  g_szModName = 'SEHExcpt';
  IDD_SEHEXCPT     =    1;
  IDC_NUMACCESSES  =  100;
  IDC_LOG          =  101;
  IDI_SEHEXCPT     =  101;

  // 数组结构
type
  TElement = record
    bReserved: array[0..4*1024-1] of Byte;
  end;
  PElement = ^TElement;
  TArray = array[0..0] of TElement;
  PArray = ^TArray;

  // 数组长度
const
  NUMELEMENTS  =  50;
  NUMBYTESINARRAY = SizeOf(TElement) * NUMELEMENTS;

  // 提交物理内存
procedure CommitMemory(hWndLog: HWND; var lpEP: TExceptionPointers; lpbAttemptedAddr: PByte);
var
  fAttemptedWrite: BOOL;
  szBuf: array[0..100] of Char;
begin
  // 显示异常类型(读/写)
  fAttemptedWrite := BOOL(lpEP.ExceptionRecord.ExceptionInformation[0]);
  _wvsprintf(szBuf, '---> Committing memory (%s attempted)', [DWORD(IfThen(fAttemptedWrite, 'write', 'read'))]);
  ListBox_AddString(hWndLog, szBuf);

  // 为异常地址提交内存
  VirtualAlloc(lpbAttemptedAddr, SizeOf(TElement), MEM_COMMIT, PAGE_READWRITE);
end;

  // 扩展的SEH节点
type
  PEstablisherFrame = ^TEstablisherFrame;
  TEstablisherFrame = record
    Prev: PEstablisherFrame;
    Handler: Pointer;
    SafeEip: DWORD; // 出错跳转地址
  end;

  // 线程异常回调
function PerThreadExcptionHandler(var ExceptionRecord: TExceptionRecord; var EstablisherFrame: TEstablisherFrame;
  var ContextRecord: TContext; DispatcherContext: Pointer): TExceptionDisposition; cdecl;
begin
  if (ExceptionRecord.ExceptionCode = LeaveException) then
  begin
    ContextRecord.Eip := EstablisherFrame.SafeEip; // 跳到后面
    ContextRecord.Esp := DWORD(@EstablisherFrame); // 恢复栈顶
    Result := ExceptionContinueExecution; // 已经处理, 线程按ContextRecord继续执行
  end else
    Result := ExceptionContinueSearch;    // 没有处理, 系统继续"询问"后面的SEH节点
end;

  // 异常"过滤器"
function ExpFilter(var lpEP: TExceptionPointers; lpbArray: PByte; lNumBytesInArray: DWORD; hWndLog: HWND): Integer;
label
  FinallyDo;
var
  lpbAttemptedAddr: PByte;
  dwExceptionCode: DWORD;
  nFilterResult: Integer;
begin
  asm
    MOV  nFilterResult, EXCEPTION_CONTINUE_SEARCH
  end;
  dwExceptionCode := lpEP.ExceptionRecord.ExceptionCode;

  // 异常保护 (_try)
  asm
    PUSH EBP                   // 备份 EBP
    PUSH OFFSET FinallyDo      // TEstablisherFrame.SafeEip := @FinallyDo
    PUSH OFFSET PerThreadExcptionHandler // TEstablisherFrame.Handler := @PerThreadExcptionHandler
    PUSH FS:[0]                // TEstablisherFrame.Prev := TEB.ExceptionList
    MOV  FS:[0], ESP           // TEB.ExceptionList := @TEstablisherFrame
  end;

  // 异常编码
  if (dwExceptionCode <> EXCEPTION_ACCESS_VIOLATION) then _leave;

  // 数组地址
  if (lpbArray = nil) then _leave;

  // 异常地址
  lpbAttemptedAddr := Pointer(lpEP.ExceptionRecord.ExceptionInformation[1]);

  // 在数组外
  if (DWORD(lpbAttemptedAddr) < DWORD(lpbArray)) or
     (DWORD(lpbArray) + lNumBytesInArray <= DWORD(lpbAttemptedAddr))
  then _leave;

  // 提交内存
  CommitMemory(hWndLog, lpEP, lpbAttemptedAddr);

  // 重新执行
  nFilterResult := EXCEPTION_CONTINUE_EXECUTION;

  // 去除保护 (_finally)
FinallyDo:
  asm
    POP  FS:[0]                // TEB.ExceptionList := TEstablisherFrame.Prev
    ADD  ESP, TYPE Pointer * 2 // 恢复栈顶
    POP  EBP                   // 恢复 EBP
  end;

  Result := nFilterResult;
end;

  // 顶层异常回调
function TopLevelExceptionHandler(var pep: TExceptionPointers): LongInt; stdcall;
begin
  Result := ExpFilter(pep, PByte(pep.ContextRecord.Ebp), NUMBYTESINARRAY, PDWORD(pep.ContextRecord.Esp)^);
  // 注: 此处参数依Dlg_ReserveArrayAndAccessIt()函数的汇编代码而定
end;

  // 访问保留内存
procedure Dlg_ReserveArrayAndAccessIt(hWndLog: HWND; nNumAccesses: Integer);
var
  lpArray: PArray;
  Element: TElement;
  szBuf: array[0..100] of Char;
  nElementNum: Integer;
begin
  ListBox_ResetContent(hWndLog);
  ListBox_AddString(hWndLog, 'Execution started');

  // 保留内存
  lpArray := VirtualAlloc(nil, NUMBYTESINARRAY, MEM_RESERVE, PAGE_NOACCESS);

  // 随机访问
  while (nNumAccesses > 0) do
  begin
    Dec(nNumAccesses);

    // 数组下标
    nElementNum := Random(NUMELEMENTS);

    // 正要访问
    _wvsprintf(szBuf, 'Writing index: %d', [nElementNum]);
    ListBox_AddString(hWndLog, szBuf);

    // 尝试写入
    lpArray[nElementNum] := Element;
  end;

  ListBox_AddString(hWndLog, 'Execution ended');

  // 释放内存
  VirtualFree(lpArray, 0, MEM_RELEASE);
end;

  // WM_INITDIALOG
function Dlg_OnInitDialog(hWnd, hWndFocus: HWND; lParam: LPARAM): BOOL;
begin
  chSETDLGICONS(hWnd, IDI_SEHEXCPT, IDI_SEHEXCPT);
  SetDlgItemInt(hWnd, IDC_NUMACCESSES, 100, FALSE);
  Result := TRUE;
end;

  // WM_COMMAND
procedure Dlg_OnCommand(hWnd: HWND; id: Integer; hWndCtl: HWND; codeNotify: UINT);
var
  nNumAccesses: Integer;
  fTranslated: BOOL;
begin
  case (id) of
    IDOK:
      begin
        nNumAccesses := GetDlgItemInt(hWnd, IDC_NUMACCESSES, fTranslated, FALSE);

        if (fTranslated) then
          Dlg_ReserveArrayAndAccessIt(GetDlgItem(hWnd, IDC_LOG), nNumAccesses)
        else
          chMB('Invalid number of accesses ', g_szModName);
      end;

    IDCANCEL:
      begin
        EndDialog(hWnd, id);
      end;
  end;
end;

  // 对话框回调
function Dlg_Proc(hWnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM): BOOL; stdcall;
begin
  case (uMsg) of
    WM_INITDIALOG:
      begin
        Result := SetDlgMsgResult(hWnd, LRESULT(Dlg_OnInitDialog(hWnd, wParam, lParam)));
      end;

    WM_COMMAND:
      begin
        Dlg_OnCommand(hWnd, LOWORD(wParam), lParam, HIWORD(wParam));
        Result := TRUE;
      end;

    else Result := FALSE;
  end;
end;

  // 程序入口
begin
  RemoveCurrentThreadOtherSEH(); // 去掉SetExceptionHandler()安装的线程异常处理节点
  SetUnhandledExceptionFilter(@TopLevelExceptionHandler); // 安装顶层异常处理回调

  chWARNIFUNICODEUNDERWIN95();
  DialogBox(HInstance, MakeIntResource(IDD_SEHEXCPT), 0, @Dlg_Proc);
end.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -