function chu(a,b:extended):extended; begin try result:=a/b; except on EDivZero do result:=0; end; end
1步:让我们的异常处理过程最早执行,也就是在Try指定的处理过程之前执行(我的方法是:In Line Hook ntdll.KiUserExceptionDispatcher,然后Hook中替换首个SEH过程(FS:[0])为指定的过程,然后继续执行.在这个指定的过程中,还原FS:[0],并判断PExceptionRecord.ExceptionCode=$C0000094(整除0) $C000008E(浮点计算除0)如果是进入除0异常处理,如果不是转入原异常处理过程处理.) 2步:除0异常处理过程,首先取出异常地址处的机器码长度,把Context.EIP+指令长度(跳过异常的指令),然后模拟异常处的指令(由于你想把 n / 0 = 0,因此这里能模拟的),模拟分以下情况: 1.DIV或者IDIV指令(整除0),把Context.Eax,Edx置0即可,Eax为商,Edx为余数; 2.FDIV m32/m64/m80 把ST(0)置0 3.FDIV ST(i) 把 ST(i)置0即可 4.FDIV ST(i),ST(0) 把ST(i)置0 5.FDIVP ST(i), ST(0) 把ST(i)置0,并Pop一次, 6.FIDIV... ...这里情况有点多,需要逐个模拟指令的执行结果即可,浮点异常处理的最后记得把FPU的异常标志去掉这样处理的结果是: var i , n : integer; begin i := 100; n := 0; try if (i DIV n)=0 then ShowMessage('i Div n 结果为 0'); except ShowMessage('i Div n发生异常'); end; end; 如果未经过前面的处理,执行这代码,显示异常,经过上面的处理,显示 结果为0,而 异常 的消息时不会显示的.
要么try except, 没别的好办法
你可以把计算过程放在一个函数内, 这样灵活性, 安全性会好些
begin
try
result:=a/b;
except
on EDivZero do result:=0;
end;
end
2步:除0异常处理过程,首先取出异常地址处的机器码长度,把Context.EIP+指令长度(跳过异常的指令),然后模拟异常处的指令(由于你想把 n / 0 = 0,因此这里能模拟的),模拟分以下情况:
1.DIV或者IDIV指令(整除0),把Context.Eax,Edx置0即可,Eax为商,Edx为余数;
2.FDIV m32/m64/m80 把ST(0)置0
3.FDIV ST(i) 把 ST(i)置0即可
4.FDIV ST(i),ST(0) 把ST(i)置0
5.FDIVP ST(i), ST(0) 把ST(i)置0,并Pop一次,
6.FIDIV...
...这里情况有点多,需要逐个模拟指令的执行结果即可,浮点异常处理的最后记得把FPU的异常标志去掉这样处理的结果是:
var i , n : integer;
begin
i := 100;
n := 0;
try
if (i DIV n)=0 then ShowMessage('i Div n 结果为 0');
except
ShowMessage('i Div n发生异常');
end;
end;
如果未经过前面的处理,执行这代码,显示异常,经过上面的处理,显示 结果为0,而 异常 的消息时不会显示的.