SEH 结构化异常处理

SEH 结构化异常处理
SEH 结构化异常处理

标题:【原创】加密与解密二版菜鸟学习笔记(2) - SEH 结构化异常处理

作者:ytcswb

时间: 2005-02-01,16:40:24

链接: https://www.360docs.net/doc/bd10027709.html,/showthread.php?t=10651

看学加密与解密二版学习笔记(2) - SEH 结构化异常处理

[ 工具] flyod1.10

[ 目的] 学习SEH的手法,另书中是用SoftICE调试的,看起来不习惯.根据原文内容重新整理一下,便于和我一样的菜鸟们一起学习.

今天下决心,好好学习,这是就算是个开始吧!感觉学明白的确很不容易!

[ 注释] ?--为不能理解的地方,请大侠们指点一下.学习过程中,有理解错误的地方,肯请大侠们多多指教.

[练习对象] 加密与加密二版第10章,光盘配套的练习软件:seh.exe seh2.exe

[ writer ] ytcswb 2005.2.1 感谢看学及论坛的大侠们为我们提供这么好的学习资料。

1.例子seh.exe学习:

00401000 > $ 8D4424 F8 lea eax,dword ptr ss:[esp-8] //程序入口!根据下面的代码分析,这里显然可以

//理解为开辟8字节的空间,并把栈顶指针保存到eax

//相当于sub esp,8 ; lea eax,dword ptr ss:[esp]

00401004 . 64:8705 00000>xchg dword ptr fs:[0],eax //记住fs[0]永远是指向当前err结构的指针,

//执行完成后,fs[0]指向栈顶,准备在堆栈中构造1个err结构

//eax等于原fs[0],即指向原来的err结构的指针,即那个err结构的地址

0040100B . BB 2E104000 mov ebx,Seh.0040102E //地址40102e-->ebx,建议在此地址上设断点,才能正常跟踪入seh代码中

00401010 . 53 push ebx //压入堆栈,即当前err结构的handler成员,当前异常处理代码的入口地址

00401011 . 50 push eax //压入原fs[0],即当前err结构的prev成员,即下一个err结构的地址

此时堆栈:

0012FFBC 0012FFE0 指针到下一个SEH 记录//0012FFE0是个指针,看看就知道指向下一个err结构,数值上等于下一个err结构的地址

0012FFC0 0040102E SE 句柄//建立了1个当前的err结构

0012FFE0 FFFFFFFF SEH 链尾部

0012FFE4 77E74809 SE 句柄

err结构的定义[在Essup.INC源文件中定义的---VC++ CRT(CRT含义:C++RunTime library)]: _EXCEPTION _REGISTERA TION stru

prev dd ? //指向下一个err结构的指针,数值上等于下一个err结构的首地址(在堆栈中) handler dd ? //指向异常处理代码的指针,数值上等于异常处理代码的入口地址即首地址

_EXCEPTION _REGISTERA TION ends

00401012 . BE 00000000 mov esi,0 //简单的赋值语句00401017 . 8B06 mov eax,dword ptr ds:[esi] //读取线性地址0,产生异常

//执行后,windows检查到异常,执行线程马上被中段,从用户模式转到内核模式

//控制权交到操作系统的异常调试程序(exception dispatcher),由它负责找到

//处理这个异常的方法,即所有应用程序的异常最终都是由windwos来处理的,

//同一个版本的windows 有固定的异常处理代码.

//如果你把这句nop掉了,也就等于去除了异常.会接着执行到下面的代码,并显示"SEH Fail"!

00401019 . 6A00 push 0 ; /Style = MB_OK|MB_APPLMODAL

0040101B . 68 00304000 push Seh.00403000 ; |Title = "OK" 00401020 . 68 10304000 push Seh.00403010 ; |Text = "SEH Fail"

00401025 . 6A00 push 0 ; |hOwner = NULL

00401027 . E8 1C000000 call ; \MessageBoxA

0040102C . EB 13 jmp short Seh.00401041

0040102E . 6A00 push 0 ; /Style = MB_OK|MB_APPLMODAL

00401030 . 68 00304000 push Seh.00403000 ; |Title = "OK" 00401035 . 68 03304000 push Seh.00403003 ; |Text = "SEH Succeed "

0040103A. 6A00 push 0 ; |hOwner = NULL

0040103C . E8 07000000 call ; \MessageBoxA

00401041 > 6A 00 push 0 ; /ExitCode = 0

00401043 . E8 06000000 call ; \ExitProcess 00401048 $- FF25 08204000 jmp dword ptr ds:[<&USER32.MessageBoxA>] ; USER32.MessageBoxA

0040104E .- FF25 00204000 jmp dword ptr ds:[<&KERNEL32.ExitProcess>; kernel32.ExitProcess

00401054 00 db 00

00401055 00 db 00

---------------------------------------------------------------------------------------------------

00401017 . 8B06 mov eax,dword ptr ds:[esi]

//读取线性地址0,产生异常

//执行完这1条指令,od的状态行可以看到,产生了什么异常.状态行的内容如下:

//访问违反:读取[00000000],使用shift+F7/F8/F9键跳过异常以继续执行程序.

//windows检测到了这个异常,就会向堆栈压入3个结构.压入顺序为EXCEPTION_RECORD,EXCEPTION_CONTEXT,EXCEPTION_POINTERS

//EXCEPTION_POINTERS结构就在栈顶,其定义如下:

typedef strut_EXCEPTION_POINTERS{

+0 pEXCEPTION_RECORD ExceptionRecord DWORD ? //指针,指向EXCEPTION_RECORD 结构,即EXCEPTION_RECORD的首地址

+4 pCONTEXT ContextRecord DWORD ? //指针,指向EXCEPTION_CONTEXT 结构,即EXCEPTION_CONTEXT的首地址

}_EXCEPTION_POINTERS ends

在看看EXCEPTION_RECORD结构:

EXCEPTION_RECORD struct{ //共6个成员

+0 DWORD ExceptionCode //异常代码,定义了产生异常的原因

+4 DWORD ExceptionFlags //异常标志?

+8 struct EXCEPTION_RECORD //指针,指向另一个EXCEPTION_RECORD结构

+C DVOID ExceptionAddress //异常发生的地址

+10 DWORD NumberParameters //与异常联系的参数个数(0~15)一般=0 ?

+14 ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS] //异常信息?

}EXCEPTION_RECORD ends

//执行完401017指令后,我们在od的代码窗口的看到代码如下:

77FB4DAF > 8B4C24 04 mov ecx,dword ptr ss:[esp+4]

77FB4DB3 8B1C24 mov ebx,dword ptr ss:[esp] //来到了ntdll领空,即系统领空{

//马上看看堆栈:

0012FCCC 0012FCD4 -| //指针,指向EXCEPTION_RECORD结构,即EXCEPTION_RECORD的首地址-----\这就是EXCEPTION_POINTERS

0012FCD0 0012FCF0 -| //指针,指向EXCEPTION_CONTEXT结构,即EXCEPTION_CONTEXT的首地址---\

0012FCD4 C0000005---------------\1--异常代码.这里开始就是EXCEPTION_RECORD结构

0012FCD8 00000000 \2--异常标志=0

0012FCDC 00000000 \3--指针,指向另一个EXCEPTION_RECORD结构,这里=0

没有另一个EXCEPTION_RECORD 结构,为NULL指针.

0012FCE0 00401017 Seh.00401017 \4--异常发生的地址,这就是发生异常的那条指令的地址.

0012FCE4 00000002 \5--与异常联系的参数个数=2 ?

0012FCE8 00000000 \6--异常信息?

0012FCEC 00000000---------------\

0012FCF0 0001003F---------------\这里开始就是EXCEPTION_CONTEXT结构,ContextFlags

0012FCF4 00000000 \Dr0

0012FCF8 00000000 \Dr1

0012FCFC 00000000 \Dr2

0012FD00 00000000 \Dr3

0012FD04 0000A000 \Dr6

0012FD08 00000000 \Dr7

我们重点看看0012FCF0 +B8=12FDA8

0012FDA4 0012FFF0

0012FDA8 00401017 Seh.00401017 \异常发生的地址,这就是发生异常的那条指令的地址.

0012FDAC 0000001B

}

继续跟踪:

77FB4DB6 51 push ecx //指针,指向EXCEPTION_CONTEXT结构

77FB4DB7 53 push ebx //指针,指向EXCEPTION_RECORD结构

77FB4DB8 E8 ACBDFAFF call ntdll.77F60B69 //如果f8过,会出现SEH succeed 提示窗口,即执行了程序自己的异常代码,

//为了看系统是如何处理的,我们f7进入

77FB4DBD 0AC0 or al,al

77FB4DBF 74 0C je short ntdll.77FB4DCD

77FB4DC1 5B pop ebx

77FB4DC2 59 pop ecx

77FB4DC3 6A 00 push 0

77FB4DC5 51 push ecx

77FB4DC6 E8 480BFCFF call ntdll.ZwContinue

77FB4DCB EB 0B jmp short ntdll.77F B4DD8

77FB4DCD 5B pop ebx

77FB4DCE 59 pop ecx

77FB4DCF 6A 00 push 0

77FB4DD1 51 push ecx

77FB4DD2 53 push ebx

77FB4DD3 E8 F213FCFF call ntdll.ZwRaiseException

77FB4DD8 83C4 EC add esp,-14

77FB4DDB 890424 mov dword ptr ss:[esp],eax

77FB4DDE C74424 04 01000>mov dword ptr ss:[esp+4],1

77FB4DE6 895C24 08 mov dword ptr ss:[esp+8],ebx

77FB4DEA C74424 10 00000>mov dword ptr ss:[esp+10],0

77FB4DF2 54 push esp

77FB4DF3 E8 AFC2F9FF call ntdll.RtlRaiseException

77FB4DF8 C2 0800 retn 8

继续跟到这段代码里:

77F79B7E 55 push ebp

77F79B7F 8BEC mov ebp,esp

77F79B81 FF75 0C push dword ptr ss:[ebp+C]

77F79B84 52 push edx

77F79B85 64:FF35 0000000>push dword ptr fs:[0]

77F79B8C 64:8925 0000000>mov dword ptr fs:[0],esp

{

//堆栈建立了1个err结构

0012FC04 0012FFBC 指针到下一个SEH 记录//enter键看看

0012FC08 77F79BB8 SE 句柄

0012FFBC 0012FFE0 指针到下一个SEH 记录

0012FFC0 0040102E SE 句柄// 熟悉这个地址吧

0012FFE0 FFFFFFFF SEH 链尾部

0012FFE4 77E74809 SE 句柄

}

77F79B93 FF75 14 push dword ptr ss:[ebp+14]

77F79B96 FF75 10 push dword ptr ss:[ebp+10]

77F79B99 FF75 0C push dword ptr ss:[ebp+C]

77F79B9C FF75 08 push dword ptr ss:[ebp+8]

77F79B9F 8B4D 18 mov ecx,dword ptr ss:[ebp+18]

{

//此时我们马上看看堆栈:

0012FBF4 0012FCD4 //指针,指向EXCEPTION_RECORD结构,即EXCEPTION_RECORD的首地址-----回调函数的参数1

0012FBF8 0012FFBC //指向err结构.可以看看上面我们截取的SEH链表-----回调函数的参数2

0012FBFC 0012FCF0 //指针,指向EXCEPTION_CONTEXT结构,即EXCEPTION_CONTEXT的首地址-----回调函数的参数3

0012FC00 0012FCAC //参数4 _lpDispatchrContext ? 最先被压入堆栈.

0012FC04 0012FFBC 指针到下一个SEH 记录

0012FC08 77F79BB8 SE 句柄

0012FC0C 0012FFBC

}

77F79BA2 FFD1 call ecx //Seh.0040102E到这里执行,就是程序的自己的异常处理代码,f7

//这就是异常处理回调函数,其参数含义请往下看.

{

0040102C . /EB 13 jmp short Seh.00401041

0040102E . |6A00 push 0 ; /Style = MB_OK|MB_APPLMODAL

00401030 . |68 00304000 push Seh.00403000 ; |Title = "OK"

00401035 . |68 03304000 push Seh.00403003 ; |Text = "SEH Succeed "

0040103A. |6A 00 push 0 ; |hOwner = NULL

0040103C . |E8 07000000 call ; \MessageBoxA

00401041 > \6A 00 push 0 ; /ExitCode = 0

00401043 . E8 06000000 call ; \ExitProcess

00401048 $- FF25 08204000 jmp dword ptr ds:[<&USER32.MessageBoxA>] ; USER32.MessageBoxA

0040104E .- FF25 00204000 jmp dword ptr ds:[<&KERNEL32.ExitProcess>; kernel32.ExitProcess

}

77F79BA4 64:8B25 0000000>mov esp,dword ptr fs:[0]

77F79BAB 64:8F05 0000000>pop dword ptr fs:[0]

77F79BB2 8BE5 mov esp,ebp

77F79BB4 5D pop ebp

77F79BB5 C2 1400 retn 14

[总结]

//读取线性地址0,产生异常

//执行后,windows检查到异常,执行线程马上被中段,从用户模式转到内核模式

//控制权交到操作系统的异常调试程序(exception dispatcher),由它负责找到

//处理这个异常的方法,即所有应用程序的异常最终都是由windwos来处理的,

//那么同一个版本的windows就有固定的异常处理代码.跟踪seh保护的程序时,以此为切入点,可以轻而一举地找到关键!

2.例子seh2.exe学习:

00401000 >/$ 68 51104000 push seh2.00401051 ; SE handler installation发生异常后到这里执行

//看学强调:提前在这个handler设个断点,否则程序容易跑飞!

//只有这样才能正常跟进seh处理代码!

00401005 |. 64:FF35 00000>push dword ptr fs:[0]

0040100C |. 64:8925 00000>mov dword ptr fs:[0],esp //构造1个err结构

0012FFBC 0012FFE0 指针到下一个SEH 记录//fs:[0]=esp=0x0012FFBC

0012FFC0 00401051 SE 句柄

0012FFE0 FFFFFFFF SEH 链尾部

0012FFE4 77E74809 SE 句柄

00401013 |. BE 00000000 mov esi,0

00401018 |. 8B06 mov eax,dword ptr ds:[esi] //产生异常

//这里实际是故意引发一个异常,为的就是通过修改CONTEXT,来实现反跟踪及改变程序流程(设置暗桩吗?)

0040101A|. 6A00 push 0 ; /Style = MB_OK|MB_APPLMODAL

0040101C |. 68 00304000 push seh2.00403000 ; |Title = "SEH" 00401021 |. 68 0F304000 push seh2.0040300F ; |Text = "SEH 程序没有运行"

00401026 |. 6A00 push 0 ; |hOwner = NULL

00401028 |. E8 57000000 call ; \MessageBoxA

0040102D |. 6A00 push 0 ; /Style = MB_OK|MB_APPLMODAL

0040102F |. 68 00304000 push seh2.00403000 ; |Title = "SEH" 00401034 |. 68 04304000 push seh2.00403004 ; |Text = "Hello,SEH!"

00401039 |. 6A00 push 0 ; |hOwner = NULL

0040103B |. E8 44000000 call ; \MessageBoxA

00401040 |. 64:8F05 00000>pop dword ptr fs:[0]

00401047 |. 83C4 04 add esp,4

0040104A|. 6A00 push 0 ; /ExitCode = 0

0040104C \. E8 39000000 call ; \ExitProcess 00401051 /$ 55 push ebp ; Structured exception handler

00401052 |. 8BEC mov ebp,esp

00401054 |. 53 push ebx

00401055 |. 8B45 10 mov eax,dword ptr ss:[ebp+10]

00401058 |. 8D1D 2D104000 lea ebx,dword ptr ds:[40102D]

0040105E |. 8998 B8000000 mov dword ptr ds:[eax+B8],ebx

00401064 |. 33DB xor ebx,ebx

00401066 |. 8958 04 mov dword ptr ds:[eax+4],ebx

00401069 |. 8958 08 mov dword ptr ds:[eax+8],ebx

0040106C |. 8958 0C mov dword ptr ds:[eax+C],ebx

0040106F |. 8958 10 mov dword ptr ds:[eax+10],ebx

00401072 |. C740 18 55010>mov dword ptr ds:[eax+18],155

00401079 |. B8 00000000 mov eax,0

0040107E |. 5B pop ebx

0040107F |. C9 leave

00401080 \. C2 1000 retn 10

00401083 CC int3

发生异常,就来到这里:

看堆栈:

0012FCCC 0012FCD4 //指针,指向EXCEPTION_RECORD结构,即EXCEPTION_RECORD的首地址-----\这就是EXCEPTION_POINTERS

0012FCD0 0012FCF0 //指针,指向EXCEPTION_CONTEXT结构,即EXCEPTION_CONTEXT的首地址---\

0012FCD4 C0000005 ---------------\1--异常代码.这里开始就是EXCEPTION_RECORD结构

0012FCD8 00000000

0012FCDC 00000000

0012FCE0 00401018 seh2.00401018 \4--异常发生的地址,这就是发生异常的那条指令的地址.

0012FCE4 00000002

0012FCE8 00000000

0012FCEC 00000000

0012FCF0 0001003F ---------------\这里开始就是EXCEPTION_CONTEXT结构,ContextFlags

0012FCF4 00000000 //dr0

0012FCF8 00000000 //dr1

0012FCFC 00000000 //dr2

0012FD00 00000000 //dr3

0012FD04 0000A000 //dr6

0012FD08 00000000 //dr7

0012FD0C FFFF027F

77FB4DB3 8B1C24 mov ebx,dword ptr ss:[esp]

77FB4DB6 51 push ecx

77FB4DB7 53 push ebx

77FB4DB8 E8 ACBDFAFF call ntdll.77F60B69 //f7

77FB4DBD 0AC0 or al,al

77FB4DBF 74 0C je short ntdll.77FB4DCD

77FB4DC1 5B pop ebx

77FB4DC2 59 pop ecx

77FB4DC3 6A 00 push 0

77FB4DC5 51 push ecx

77FB4DC6 E8 480BFCFF call ntdll.ZwContinue

77FB4DCB EB 0B jmp short ntdll.77FB4DD8

77FB4DCD 5B pop ebx

77FB4DCE 59 pop ecx

77FB4DCF 6A 00 push 0

77FB4DD1 51 push ecx

77FB4DD2 53 push ebx

77FB4DD3 E8 F213FCFF call ntdll.ZwRaiseException

77FB4DD8 83C4 EC add esp,-14

77FB4DDB 890424 mov dword ptr ss:[esp],eax

77FB4DDE C74424 04 01000>mov dword ptr ss:[esp+4],1

77FB4DE6 895C24 08 mov dword ptr ss:[esp+8],ebx

77FB4DEA C74424 10 00000>mov dword ptr ss:[esp+10],0

77FB4DF2 54 push esp

77FB4DF3 E8 AFC2F9FF call ntdll.RtlRaiseException

77FB4DF8 C2 0800 retn 8

77FB4DFB >^ E9 7DBCFAFF jmp ntdll.77F60A7D

77F79B7E 55 push ebp

77F79B7F 8BEC mov ebp,esp

77F79B81 FF75 0C push dword ptr ss:[ebp+C]

77F79B84 52 push edx

77F79B85 64:FF35 0000000>push dword ptr fs:[0]

77F79B8C 64:8925 0000000>mov dword ptr fs:[0],esp

77F79B93 FF75 14 push dword ptr ss:[ebp+14] //参数4 _lpDispatchrContext ? 77F79B96 FF75 10 push dword ptr ss:[ebp+10] //参数 3 _lpDContext,指向Context结构

77F79B99 FF75 0C push dword ptr ss:[ebp+C] //参数2 _lpSEH ,指向ERR结构

77F79B9C FF75 08 push dword ptr ss:[ebp+8] //参数1 _lpExceptionRecord ,指向ExceptionRecord结构

77F79B9F 8B4D 18 mov ecx,dword ptr ss:[ebp+18]

77F79BA2 FFD1 call ecx ; seh2.00401051 转到这里了f7

//这就是异常处理回调函数,执行当前异常处理代码即401051处

//注:回调函数都是由windows调用的!

//看学强调: 在此回调函数上设断点,可以轻易地对付一些加壳的反跟踪代码!!!!!

77F79BA4 64:8B25 0000000>mov esp,dword ptr fs:[0] //恢复原来的SEH链表

77F79BAB 64:8F05 0000000>pop dword ptr fs:[0]

77F79BB2 8BE5 mov esp,ebp

77F79BB4 5D pop ebp

77F79BB5 C2 1400 retn 14

00401051 /$ 55 push ebp ; Structured exception handler

00401052 |. 8BEC mov ebp,esp

00401054 |. 53 push ebx

00401055 |. 8B45 10 mov eax,dword ptr ss:[ebp+10] // eax是CONTEXT结构的指针00401058 |. 8D1D 2D104000 lea ebx,dword ptr ds:[40102D] //通过修改CONTEXT.EIP,希望到这里执行!

0040105E |. 8998 B8000000 mov dword ptr ds:[eax+B8],ebx //修改CONTEXT.EIP,改变程序执行线路,这大概就是利用seh的常用手法!

//没改时,是401018即发生异常的指令地址,经过1轮处理又会到这里执行

//又产生异常00401064 |. 33DB xor ebx,ebx

00401066 |. 8958 04 mov dword ptr ds:[eax+4],ebx //DR0 清零,使断点失效,这大概也是利用seh的常用手法,实现反跟踪!

00401069 |. 8958 08 mov dword ptr ds:[eax+8],ebx //DR1

0040106C |. 8958 0C mov dword ptr ds:[eax+C],ebx //DR2

0040106F |. 8958 10 mov dword ptr ds:[eax+10],ebx//DR3

00401072 |. C740 18 55010>mov dword ptr ds:[eax+18],155 //DR7

00401079 |. B8 00000000 mov eax,0 //回调处理函数的返回值ExceptionContinueExcetion-->eax

//ExceptionContinueExcetion=0 回调函数返回后,系统将线程环境恢复到_lpContext参数指定的CONTEXT结构并继续执行.

即,表示已经修复,从异常处继续执行,如果前面没有修改CONTEXT.EIP的值,就会到401018即异常发生处

继续执行,由于前面修改了CONTEXT.EIP=40102D,所以就转到40102D处继续执行了.

//ExceptionContinueExcetion=1 回调函数拒绝处理这个异常,系统将通过err结构的prev指针得到前一个回掉函数的地址并继续执行它

也就是转到前一个err结构的异常处理代码处继续执行. //ExceptionContinueExcetion=2 回调函数在执行中又发生了异常,即嵌套异常

//ExceptionContinueExcetion=3 发生嵌套的展开操作?

0040107E |. 5B pop ebx

0040107F |. C9 leave

00401080 \. C2 1000 retn 10

[总结]

//看学强调: 在此回调函数上设断点,可以轻易地对付一些加壳的反跟踪代码!!!!!

//看学强调: 要提前在err结构的handler地址上设断点,否则代码就可能跑飞跟踪seh的关键断点!!!!

//看学提示: 可修改CONTEXT结构成员,来实现反跟踪及改变程序流程(设置暗桩吗?)

******************************************************************************* *******************************

[附录] 跟踪到异常处理回调函数的过程:

注: windows xp-sp1平台.只要是同样平台,就可以按下面步骤,来到系统的异常处理回调函数.

熟悉一下这段代码,应该有好处,当发生异常时,可以快速找到那个call ecx异常处理回调函数,从而找到程序自己的异常处理代码。

00401000 >/$ 68 51104000 push seh2.00401051 // SE handler installation

//只有在这个401051上设断点,才能跟到异常处理代码(SEH代码)处.

//即要提前在err结构的handler地址上设断点,否则代码就可能跑飞!

//跟踪seh的关键断点!!!! 00401005 |. 64:FF35 00000>push dword ptr fs:[0]

0040100C |. 64:8925 00000>mov dword ptr fs:[0],esp

00401013 |. BE 00000000 mov esi,0

00401018 |. 8B06 mov eax,dword ptr ds:[esi] //产生异常,来到代码[1] 0040101A|. 6A00 push 0 ; /Style = MB_OK|MB_APPLMODAL

0040101C |. 68 00304000 push seh2.00403000 ; |Title = "SEH"

00401021 |. 68 0F304000 push seh2.0040300F ; |Text = "SEH程序没有运行"

00401026 |. 6A00 push 0 ; |hOwner = NULL

00401028 |. E8 57000000 call ; \MessageBoxA

0040102D |. 6A00 push 0 ; /Style = MB_OK|MB_APPLMODAL

0040102F |. 68 00304000 push seh2.00403000 ; |Title = "SEH"

00401034 |. 68 04304000 push seh2.00403004 ; |Text = "Hello,SEH!"

00401039 |. 6A00 push 0 ; |hOwner = NULL

0040103B |. E8 44000000 call ; \MessageBoxA

00401040 |. 64:8F05 00000>pop dword ptr fs:[0]

00401047 |. 83C4 04 add esp,4

0040104A|. 6A00 push 0 ; /ExitCode = 0

0040104C \. E8 39000000 call ; \ExitProcess

00401051 /$ 55 push ebp ; Structured exception handler

00401052 |. 8BEC mov ebp,esp

00401054 |. 53 push ebx

00401055 |. 8B45 10 mov eax,dword ptr ss:[ebp+10]

00401058 |. 8D1D 2D104000 lea ebx,dword ptr ds:[40102D]

0040105E 8998 B8000000 mov dword ptr ds:[eax+B8],ebx

00401064 |. 33DB xor ebx,ebx

00401066 |. 8958 04 mov dword ptr ds:[eax+4],ebx

00401069 |. 8958 08 mov dword ptr ds:[eax+8],ebx

0040106C |. 8958 0C mov dword ptr ds:[eax+C],ebx

0040106F |. 8958 10 mov dword ptr ds:[eax+10],ebx

00401072 |. C740 18 55010>mov dword ptr ds:[eax+18],155

00401079 |. B8 00000000 mov eax,0

0040107E |. 5B pop ebx

0040107F |. C9 leave

00401080 \. C2 1000 retn 10

代码[1]

77FB4DB3 8B1C24 mov ebx,dword ptr ss:[esp]

77FB4DB6 51 push ecx

77FB4DB7 53 push ebx

77FB4DB8 E8 ACBDFAFF call ntdll.77F60B69 //F7 进入,来到代码[2]

77FB4DBD 0AC0 or al,al

77FB4DBF 74 0C je short ntdll.77FB4DCD

77FB4DC1 5B pop ebx

77FB4DC2 59 pop ecx

77FB4DC3 6A 00 push 0

77FB4DC5 51 push ecx

77FB4DC6 E8 480BFCFF call ntdll.ZwContinue //代码[5],F7进入,回到代码[6]

77FB4DCB EB 0B jmp short ntdll.77FB4DD8

77FB4DCD 5B pop ebx

77FB4DCE 59 pop ecx

77FB4DCF 6A 00 push 0

77FB4DD1 51 push ecx

77FB4DD2 53 push ebx

77FB4DD3 E8 F213FCFF call ntdll.ZwRaiseException

77FB4DD8 83C4 EC add esp,-14

77FB4DDB 890424 mov dword ptr ss:[esp],eax

77FB4DDE C74424 04 01000>mov dword ptr ss:[esp+4],1

77FB4DE6 895C24 08 mov dword ptr ss:[esp+8],ebx

77FB4DEA C74424 10 00000>mov dword ptr ss:[esp+10],0

77FB4DF3 E8 AFC2F9FF call ntdll.RtlRaiseException 77FB4DF8 C2 0800 retn 8

77FB4DFB >^ E9 7DBCFAFF jmp ntdll.77F60A7D

代码[2]

77F60B69 55 push ebp

77F60B6A8BEC mov ebp,esp

77F60B6C 83EC 60 sub esp,60

77F60B6F 56 push esi

77F60B70 FF75 0C push dword ptr ss:[ebp+C]

77F60B73 8B75 08 mov esi,dword ptr ss:[ebp+8] 77F60B76 56 push esi

77F60B77 E8 AA000000 call ntdll.77F60C26

77F60B7C 84C0 test al,al

77F60B7E 0F85 EB6F0200 jnz ntdll.77F87B6F

77F60B84 53 push ebx

77F60B85 57 push edi

77F60B86 8D45 F8 lea eax,dword ptr ss:[ebp-8]

77F60B89 50 push eax

77F60B8A8D45 FC lea eax,dword ptr ss:[ebp-4] 77F60B8D 50 push eax

77F60B8E E8 3C910100 call ntdll.77F79CCF

77F60B93 E8 52910100 call ntdll.77F79CEA

77F60B98 8365 08 00 and dword ptr ss:[ebp+8],0

77F60B9C 8BD8 mov ebx,eax

77F60B9E 83FB FF cmp ebx,-1

77F60BA1 0F84 4A1C0100 je ntdll.77F727F1

77F60BA7 3B5D FC cmp ebx,dword ptr ss:[ebp-4] 77F60BAA0F82 481C0100 jb ntdll.77F727F8

77F60BB0 8D43 08 lea eax,dword ptr ds:[ebx+8] 77F60BB3 3B45 F8 cmp eax,dword ptr ss:[ebp-8] 77F60BB6 0F87 3C1C0100 ja ntdll.77F727F8

77F60BBC F6C3 03 test bl,3

77F60BBF 0F85 331C0100 jnz ntdll.77F727F8

77F60BC5 8B43 04 mov eax,dword ptr ds:[ebx+4] 77F60BC8 3B45 FC cmp eax,dword ptr ss:[ebp-4] 77F60BCB 72 09 jb short ntdll.77F60BD6

77F60BCD 3B45 F8 cmp eax,dword ptr ss:[ebp-8] 77F60BD0 0F82 221C0100 jb ntdll.77F727F8

77F60BD6 F605 4A32FC77 8>test byte ptr ds:[77FC324A],80 77F60BDD 0F85 936F0200 jnz ntdll.77F87B76

77F60BE3 FF73 04 push dword ptr ds:[ebx+4]

77F60BE6 8D45 F0 lea eax,dword ptr ss:[ebp-10]

77F60BEA FF75 0C push dword ptr ss:[ebp+C]

77F60BED 53 push ebx

77F60BEE 56 push esi

77F60BEF E8 528F0100 call ntdll.77F79B46 // F4下,F7进入,来到代码[3] 77F60BF4 F605 4A32FC77 8>test byte ptr ds:[77FC324A],80

77F60BFB 8BF8 mov edi,eax

77F60BFD 0F85 896F0200 jnz ntdll.77F87B8C

77F60C03 395D 08 cmp dword ptr ss:[ebp+8],ebx

77F60C06 0F84 8E6F0200 je ntdll.77F87B9A

77F60C0C 8BC7 mov eax,edi

77F60C0E 33C9 xor ecx,ecx

77F60C10 2BC1 sub eax,ecx

77F60C12 0F84 3E340100 je ntdll.77F74056

77F60C18 48 dec eax

77F60C19 0F85 886F0200 jnz ntdll.77F87BA7

77F60C1F 8B1B mov ebx,dword ptr ds:[ebx]

77F60C21 ^ E9 78FFFFFF jmp ntdll.77F60B9E

77F60C26 55 push ebp

77F60C27 8BEC mov ebp,esp

77F60C29 51 push ecx

77F60C2A51 push ecx

77F60C2B 57 push edi

77F60C2C BF 1032FC77 mov edi,ntdll.77FC3210

77F60C31 393D 1032FC77 cmp dword ptr ds:[77FC3210],edi

77F60C37 0F85 48E80100 jnz ntdll.77F7F485

77F60C3D 32C0 xor al,al

77F60C3F 5F pop edi

77F60C40 C9 leave

77F60C41 C2 0800 retn 8

77F60C44 > 55 push ebp

代码[3]

77F79B46 BA B89BF777 mov edx,ntdll.77F79BB8

77F79B4B EB 07 jmp short ntdll.77F79B54

77F79B4D BA DF9BF777 mov edx,ntdll.77F79BDF

77F79B52 8D09 lea ecx,dword ptr ds:[ecx]

77F79B54 53 push ebx

77F79B55 56 push esi

77F79B56 57 push edi

77F79B57 33C0 xor eax,eax

77F79B59 33DB xor ebx,ebx

77F79B5B 33F6 xor esi,esi

77F79B5D 33FF xor edi,edi

77F79B5F FF7424 20 push dword ptr ss:[esp+20]

77F79B63 FF7424 20 push dword ptr ss:[esp+20]

77F79B67 FF7424 20 push dword ptr ss:[esp+20]

77F79B6B FF7424 20 push dword ptr ss:[esp+20]

77F79B6F FF7424 20 push dword ptr ss:[esp+20]

77F79B73 E8 06000000 call ntdll.77F79B7E //// F4下,F7进入,来到代码[4]

77F79B78 5F pop edi

77F79B79 5E pop esi

77F79B7A5B pop ebx

77F79B7B C2 1400 retn 14

代码[4]

77F79B7E 55 push ebp

77F79B7F 8BEC mov ebp,esp

77F79B81 FF75 0C push dword ptr ss:[ebp+C]

77F79B84 52 push edx

77F79B85 64:FF35 0000000>push dword ptr fs:[0]

77F79B8C 64:8925 0000000>mov dword ptr fs:[0],esp

77F79B93 FF75 14 push dword ptr ss:[ebp+14]

77F79B96 FF75 10 push dword ptr ss:[ebp+10]

77F79B99 FF75 0C push dword ptr ss:[ebp+C]

77F79B9C FF75 08 push dword ptr ss:[ebp+8]

77F79B9F 8B4D 18 mov ecx,dword ptr ss:[ebp+18]

77F79BA2 FFD1 call ecx //这就是异常处理回调函数!

77F79BA4 64:8B25 0000000>mov esp,dword ptr fs:[0]

77F79BAB 64:8F05 0000000>pop dword ptr fs:[0]

77F79BB2 8BE5 mov esp,ebp

77F79BB4 5D pop ebp

77F79BB5 C2 1400 retn 14 //返回后继续跟,回到代码[5]处

代码[6]

77F75913 > B8 20000000 mov eax,20

77F75918 BA 0003FE7F mov edx,7FFE0300

77F7591D FFD2 call edx //f7,到代码[8]

77F7591F C2 0800 retn 8

代码[8]

7FFE0300 8BD4 mov edx,esp

7FFE0302 0F34 sysenter

7FFE0304 C3 retn //返回到代码[9]

代码[9]

0040102F |. 68 00304000 push seh2.00403000 ; |Title = "SEH"

00401034 |. 68 04304000 push seh2.00403004 ;

|Text = "Hello,SEH!"

00401039 |. 6A00 push 0 ; |hOwner = NULL

0040103B |. E8 44000000 call ; \MessageBoxA

00401040 |. 64:8F05 00000>pop dword ptr fs:[0]

00401047 |. 83C4 04 add esp,4

0040104A|. 6A00 push 0 ; /ExitCode = 0

0040104C \. E8 39000000 call ; \ExitProcess //f7,进入,到代码[10]

代码[10]-----这段代码,任何程序只要执行了exitprocess都会看到!留个印象吧!

77E598FD > 55 push ebp

77E598FE 8BEC mov ebp,esp

77E59900 6A FF push -1

77E59902 68 B0F3E877 push kernel32.77E8F3B0

77E59907 FF75 08 push dword ptr ss:[ebp+8]

77E5990A E8 86FFFFFF call kernel32.77E59895 // 结束了应用程序的生命!

77E5990F ^ E9 A47DFEFF jmp kernel32.TerminateProcess

77E59914 - FF25 F413E477 jmp dword ptr ds:[<&ntdll.LdrShutdownProcess>] ; ntdll.LdrShutdownProcess

77E5991A391D A470EB77 cmp dword ptr ds:[77EB70A4],ebx

77E59920 0F84 99150000 je kernel32.77E5AEBF

77E59926 53 push ebx

77E59927 53 push ebx

77E59928 53 push ebx

77E59929 E8 D2F4FEFF call kernel32.WriteProfileStringW

77E5992E E9 8C150000 jmp kernel32.77E5AEBF

77E59933 > 837C24 04 00 cmp dword ptr ss:[esp+4],0

77E59938 0F84 C4730200 je kernel32.77E80D02

77E5993E FF7424 08 push dword ptr ss:[esp+8]

77E59942 FF7424 08 push dword ptr ss:[esp+8]

77E59946 FF15 6814E477 call dword ptr ds:[<&ntdll.NtTerminateThread>] ; ntdll.ZwTerminateThread

77E5994C 85C0 test eax,eax

77E5994E 0F8C B7730200 jl kernel32.77E80D0B

77E59954 33C0 xor eax,eax

77E59956 40 inc eax

77E59957 C2 0800 retn 8

******************************************************************************* *******************************

Java异常处理的最佳实践归纳

异常处理的关键就在于知道何时处理异常以及如何使用异常。这篇文章,我会提到一些最佳的异常处理方法。我也会总结checked exception 的用法。 我们程序员都想写出高质量的代码来解决问题。但是,异常有时会给我们的代码带来副作用。没有人喜欢副作用,所以我们很快找到了方法来改善它们。我看见过许多java招聘问这样的问题,聪明的程序员通常这样来处理异常: 1 2 3 4 5 6 7 public void consumeAndForgetAllExceptions (){ try { ...some code that throws exceptions } catch (Exception ex){ ex.printStacktrace (); } } 上面的代码有什么错误? 当异常被抛出后,正常的程序执行过程中断,控制权交给catch 段,catch 段会catch 异 常,然后抑制异常的进一步扩大。然后接着catch 段之后程序继续执行,好像什么都没发生过一样。 下面的代码呢? 1 2 public void someMethod () throws Exception{ } 这个方法内没有代码,是个空方法。一个空方法怎么能抛出异常呢?Java 并没有说不 让这么做。最近,我遇到过类似的代码,方法抛出了异常,而其中的代码实际上并不产生那个异常。当我问这个程序员Java异常为何要这么做,他回答道“我知道,虽然这样做破坏了API,但我习惯这么做,而且这样也可行。” C++社区用了许多年才确定如何使用异常机制。这个争论刚刚在Java 社区展开。我见到一些Java 程序员正在和异常进行顽强抗争。如果用法不当的话,会拖慢程序,因为创建、抛出和接住异常都会占用内存。如果过多的使用异常的话,代码会变得很难阅读,对要使用API 的程序员来说无疑会增加挫败感。我们知道挫败感会令我们写出很烂的代码。有的程序员会刻意回避这个问题,忽略异常或随意抛出异常,就像上面的两个例子一样。 异常的本质 广义的讲,抛出异常分三种不同的情况: - 编程错误导致的异常:在这个类别里,异常的出现是由于代码的错误(譬如NullPointerException 和IllegalArgumentException)。代码通常对编程错误没有什么对策。 - 客户端的错误导致的异常:客户端代码试图违背制定的规则,调用API 不支持的资源。如果在异常中显示有效信息的话,客户端可以采取其他的补救方法。例如:解析一个格式不正确的XML 文档时会抛出异常,异常中含有有效的信息。客户端可以利用这个有效信息来采取恢复的步骤。 - 资源错误导致的异常:当获取资源错误时引发的异常。例如,系统内存不足,或者网

数据中异常值的处理方法_总

数据中异常值的检测与处理方法 一、数据中的异常值 各种类型的异常值: 数据输入错误:数据收集,记录或输入过程中出现的人为错误可能导致数据异常。例如:一个客户的年收入是$ 100,000。数据输入运算符偶然会在图中增加一个零。现在收入是100万美元,是现在的10倍。显然,与其他人口相比,这将是异常值。 测量误差:这是最常见的异常值来源。这是在使用的测量仪器出现故障时引起的。例如:有10台称重机。其中9个是正确的,1个是错误的。 有问题的机器上的人测量的重量将比组中其他人的更高/更低。在错误的机器上测量的重量可能导致异常值。 实验错误:异常值的另一个原因是实验错误。举例来说:在七名跑步者的100米短跑中,一名跑步者错过了专注于“出发”的信号,导致他迟到。 因此,这导致跑步者的跑步时间比其他跑步者多。他的总运行时间可能是一个离群值。 故意的异常值:这在涉及敏感数据的自我报告的度量中通常被发现。例如:青少年通常会假报他们消耗的酒精量。只有一小部分会报告实际价值。 这里的实际值可能看起来像异常值,因为其余的青少年正在假报消费量。 数据处理错误:当我们进行数据挖掘时,我们从多个来源提取数据。某些操作或提取错误可能会导致数据集中的异常值。 抽样错误:例如,我们必须测量运动员的身高。错误地,我们在样本中包括一些篮球运动员。这个包含可能会导致数据集中的异常值。 自然异常值:当异常值不是人为的(由于错误),这是一个自然的异常值。例如:保险公司的前50名理财顾问的表现远远高于其他人。令人惊讶的是,这不是由于任何错误。因此,进行任何数据挖掘时,我们会分别处理这个细分的数据。

在以上的异常值类型中,对于房地产数据,可能出现的异常值类型主 要有:(1)数据输入错误,例如房产经纪人在发布房源信息时由于输入错误,而导致房价、面积等相关信息的异常;在数据的提取过程中也可能会出现异常值,比如在提取出售二手房单价时,遇到“1室7800元/m 2”,提取其中的数字结果为“17800”,这样就造成了该条案例的单价远远异常于同一小区的其他房源价格,如果没有去掉这个异常值,将会导致整个小区的房屋单价均值偏高,与实际不符。(2)故意的异常值,可能会存在一些人,为了吸引别人来电询问房源,故意把价格压低,比如房屋单价为1元等等;(3)自然异常值。房价中也会有一些实际就是比普通住宅价格高很多的真实价格,这个就需要根据实际请况进行判断,或在有需求时单独分析。 二、数据中异常值的检测 各种类型的异常值检测: 1、四分位数展布法 方法[1]:大于下四分位数加倍四分位距或小于上四分位数减倍。 把数据按照从小到大排序,其中25%为下四分位用FL 表示,75%处为上四分位用FU 表示。 计算展布为:L U F F F d -=,展布(间距)为上四分位数减去下四分位数。 最小估计值(下截断点):F L d F 5.1- 最大估计值(上截断点):F U d F 5.1+ 数据集中任意数用X 表示,F U F L d F X d F 5.15.1+<<-, 上面的参数不是绝对的,而是根据经验,但是效果很好。计算的是中度异常,参数等于3时,计算的是极度异常。我们把异常值定义为小于下截断点,或者大于上截断点的数据称为异常值。

单元测试实践的主要问题与解决

单元测试实践的主要问题与解决 一、单元测试概述 1.1 什么是单元测试 单元测试,就是针对代码单元的独立测试。为什么需要单元测试呢?这是代码的基本特性决定了的。代码有一个基本特性,就是对数据分类处理。 代码通常会有很多的判定。一个判定,就是一次分类。嵌套的判定,会使分类次数的翻倍。 如果我们在写代码的时候,有一个分类漏掉了,就会产生一个Bug;如果一个分类,虽然写了代码,但是处理不正确,也会产生一个Bug。一个函数要没有错误,必须做到两点:1,对数据的分类必须完整;2,每一个分类的处理必须正确。做到了这两点,就可以说,代码的功能逻辑是正确的。 那么,如何检测代码的功能逻辑是否正确呢? 调试,是临时的,且不完整的,例如,一个函数有十种

输入,调试能覆盖五六种就不错了。而系统测试,并不针对某个具体的函数,不关注某个函数的功能逻辑是否正确。 要检测某个函数的功能逻辑,就必须要依照分类列出数据,检测代码是否对每一个分类都做了处理,而且每一个分类的处理是否正确。 ——这就是单元测试。 1.2 单元测试的基本方法 由上面的分析可以看出,单元测试的基本方法就是:依数据的分类列出输入,执行被测试程序,然后,判断输出是否符合预期。 单元测试能达到什么样的效果呢?那就是:无论别人怎么样,我总是对的! 这里的“别人”,是指关联代码。“我”,是指当前正在编写或测试的代码。单元测试要做到的是,无论关联代码是否有错,都要保证我是对的。具体来说,我要考虑关联代码会产生什么样的数据,这些数据要如何分类处理,只要我的分类和处理是正确的,那么,无论别人怎么样,我总是对的。

1.3 单元测试的效益 单元测试的效益可以说是立竿见影,并且会推动整个开发过程的改进。 首先,单元测试可以保证代码的质量。因为只有单元测试,能够全面检测代码单元的功能逻辑,排除代码中大量的、细小的错误。 其次,排错成本最小。如果在编码阶段同时进行单元测试,排错成本可以忽略不计。但若到了后期,排错成本可能会增长上百倍,要是产品已经到了用户手里,那造成的损失就更难说了。 第三,提升开发效率。单元测试可以让程序行为一目了然,也就是程序行为可视化。什么叫程序行为呢?就是什么输入下,会执行哪些代码,会产生什么输出。如下图,黑色的代码是当前输入下所执行代码。

第6章 Delphi程序异常处理与调试技术

第六章程序异常处理与调试技术 在Delphi中有两种程序错误,一种是编译错误,在程序编辑阶段就可以由编译器发现并给出提示。另外一种是运行错误,这类错误不能在编译阶段查出,只能在程序执行时发现,称为运行错误。 Delphi提供了一种机制来处理运行错误,保护程序的正常执行,这种机制就是异常处理。异常处理的方法是把正常的执行程序同错误的处理程序分离开来,这样可以保证在没有错误时,程序正常执行,当发生错误时,执行错误处理部分的程序,然后程序跳出保护模块,继续执行后续的程序。 6.1 Object Pascal异常的种类 异常的种类:Delphi内建的异常类,程序员自定义的异常类。 异常基类及其属性和主要方法:在Delphi中,所有异常的基类是Exception 类。所有其他异常类都是由该类派生而来。 1. exception属性 该类有两个基本属性:HelpContext和Message。 (1)Exception.HelpContext属性 该属性的定义如下: ?Type ThelpContext= -MaxLongint..MaxLongint; ?Property HelpContext:ThelpContext; HelpContext是ThelpContext类的一个实例,它提供了与异常对象联系在一起的上下文相关帮助信息的序列号。该序列号决定当发生异常时用户按F1键显

示的一个异常错误的帮助信息。 (2)Exception.Message属性 该属性的定义如下: property Message: string 该属性存储异常发生时的错误信息。可以通过该属性在提示错误对话框中显示错误信息字符串。 2.exception方法 (1)Exception.Create方法 该方法的定义形式为: Constructor Create(Const Msg: String); 该方法用来产生一个带有一条简单提示信息的对话框,对话框中的提示内容由Msg提供 (2)Exception.CreateFmt方法 该方法的定义格式如下: Constructor CreateFmt(Const Msg:String;Const Args:Array of Const) ; 该方法用来产生一个带有格式化字符串提示信息的对话框,格式化的字符串由Msg和Args数组共同提供,其中数组Args负责提供用于格式化的数值。 (3)Exception.CreatHelp方法 该方法的定义格式如下: Constructor CreateHelp(Const Msg:String; AhelpContsxt:Integer) ; 该方法产生一个带有一条简单提示信息和上下文帮助序列号的提示对话框。其中Msg参数包含了显示在异常对话框中的运行错误信息。AhelpContext参数包

数据库异常处理答案

. 一、 一、实验/实习过程 实验题1在程序中产生一个ArithmeticException类型被0除的异常,并用catch 语句捕获这个异常。最后通过ArithmeticException类的对象e 的方法getMessage给出异常的具体类型并显示出来。 package Package1; public class除数0 { public static void main(String args[]){ try{ int a=10; int b=0; System.out.println("输出结果为:"+a/b); } catch(ArithmeticException e){ System.out.println("除数不能为0"+e.getMessage()); } } } 实验题2在一个类的静态方法methodOne()方法内使用throw 产生

ArithmeticException异常,使用throws子句抛出methodOne()的异常,在main方法中捕获处理ArithmeticException异常。 package Package1; public class抛出异常 { static void methodOne() throws ArithmeticException{ System.out.println("在methodOne中"); throw new ArithmeticException("除数为0"); } public static void main(String args[]){ try{ int a=10; int b=0; int c=1; System.out.println("输出结果为:"+a/b); } catch(ArithmeticException e){ System.out.println("除数不能为0"+e.getMessage()); } } }

JAVA基础第6章异常处理机制_练习题

第6章异常处理机制 一、选择题 1.下列关于异常的说法正确的是(B)。 A.异常是编译时的错误 B.异常是运行时出现的错误 C.异常就是程序错误,程序错误就是异常 D.以上都不对 2.下列哪个类是异常类的父类(根类)(A)。 A.Exception B.ArithmeticException C.NullPointerException D.ArrayIndexOutofBoundException 3.有关下列异常处理机制叙述正确的是(C)。 try{ 可能产生异常的语句块; }catch(exceptiontype1 e){ 处理异常e的语句块; }catch(exceptiontype2 e){ 处理异常e的语句块; } …… finally{ 最终处理语句块; } A.try子句可能有多个,catch子句可能有多个,finally子句必须有。 B.多个catch参数中的异常类可以有父子关系,但父类异常的catch子句应该在子类异常的catch子句前面。 C.如果try子句没有抛出任何异常,则跳过catch子句,转移到finally子句继续执行。 D.当try子句监视的语句块抛出异常时,运行时系统会根据catch子句的顺序,从第一个开始,逐个查找能够捕获该异常的catch子句并执行catch子句内的语句块以完成对异常的处理,然后继续执行后面的catch子句,最后转移到finally子句,执行该子句中的语句块。4.有关throw和throws的说法中不正确的是(C)。 A.throw的作用是抛出异常,后面加的是异常类的对象。 B.throws的作用是向外抛出异常即声明要产生的若干异常,后面加的是异常类的类名。 C.throws只能声明要产生的自定义异常,也就是后面只能加自定义异常类。 D.以上都不对。 5.下列程序运行结果是(C)。 public class E { public static void main(String argv[]){ E m = new E(); System.out.println(m.amethod()); } public int amethod(){

数据库异常处理答案

、实验/实习过程 实验题 1在程序中产生一个ArithmeticException 类型被0除的异常, 并用catch 语句捕获这个异常。最后通过 ArithmeticException 类的对象 e 的方法getMessage 给出异常的具体类型并显示出来 [j'.除数U j av?風 package Package1; public? class 除数匚i { puljJ.ic static: void tnain (Str args [ ] ) { try : int 3=10; int b=D; System- on t . pr intln ( n 输出结果肯:fr 4-a/b); System- t . pr ("除數不能为□**+&. gets Message ; E Console X 事氏囲 ^t^rminated)-際數。[java A.ppli csiti on J C : S.Pr ograim F i 1 e E V J avaSt j ireB \b i IL \ J avaw . es:e ?C13-10-25 package Packagel; catch (ArithmetlcExcEption e)( 除数不能为叩 by sexo public class 除数0 { public static void mai n(Stri ng args[]){ try { int a=10; int b=0; System. out .println( } catch (ArithmeticException e){ System. out .println( } } 输岀结果为:"+a/b); "除数不能为 0" +e.getMessage()); }

java考试题库第六章.docx

第六章异常和异常处理 一选择题 6?1 .下列关于异常的描述中,错误的是(B) A.异常是一种经过修正后程序仍可执行的错误 B.异常是一种程序在运行中出现的不可恢复执行的错误 C.不仅Java语言有异常处理,C++语言也有异常处理 D.岀现异常不是简单结束程序,而是执行某种处理异常的代码,设法恢复程序的执行 6?2.下列关于异常处理的描述中,错误的是(D) A.程序运行时异常由Java虚拟机自动进行处理 B.使用try-catch-finally语句捕获异常 C.使用throw语句抛出异常 D.捕获到的异常只能用当前方法中处理,不能用其他方法中处理 6?3.下列关于try-catch-finally语句的描述中,错误的是(A) A?try语句后面的程序段将给出处理异常的语句 B?catch ()方法跟在try语句后面,它可以是一个或多个 C. catch ()方法有一个参数,该参数是某种异常类的对彖 D?finally语句后面的程序段总是被执行的,该语句起到提供统一接口的作用 6?4.下列关于抛出异常的描述中,错误的是(D) A.捕捉到发牛的异常可在当前方法中处理,也可以抛到调用该方法的方法中处理 B.在说明要抛出异常的方法吋应加关键字throw<异常列表〉 C.v异常列表〉中可以有多个用逗号分隔的异常 D.抛岀异常的方法中要使用下述抛出异常语句:throw<异常名〉;其中,v异常名>是异常类的类名6?5.下列关于用户创建自己的异常描述中,错误的是(D) A.创建自己的异常应先创建一个异常类 B.为实现抛出异常,须在可能抛出异常的方法中书写throw语句 C.捕捉异常的方法是使用try-catch-finally语句格式 D.使用异常处理不会使整个系统更加安全和稳定 二判断题 6?1 .异常是一种特殊的运行错误的对象。(对) 62异常处理可以使整个系统更加安全和稳定。(对) 6?3.异常处理是在编译时进行的。(错) 6-4.Java语言中异常类都是https://www.360docs.net/doc/bd10027709.html,ng.Throwable的子类。(对) 6-5.Throwable类有两个子类:Enor类和Exception类。前者由系统保留,后者供应用程序使用。(对)6?6.异常通常是指Error类和Exception类。(错) 6-7.Exception 类只有一个子类为RuntimeException o(错) 68在异常处理屮,出现异常和抛出异常是一回事。(错) 6?9.运行时异常是在运行时系统检测并处理的。(错) 6-10.使用try-catch-finally语句只能捕获一个异常。(错) 6?11 ?捕获异常时try语句后面通常跟有一个或多个catch ()方法用来处理try块内牛成的异常事件。(对)6?12?使用finally语句的程序代码为该程序提供一个统一的的出口。(对) 6?13.抛出异常的方法说明中要加关键字throws,并在该方法屮还应添加throw语句。(对) 6?14.创建异常类时要给出该异常类的父类。(对) 6J5.如果异常类没有被捕获将会产生不正常的终止。(对) 三分析程序的输出结果 6?1. Exer6_l.java public class Exer6_l

数据库异常处理答案

一、实验/实习过程 实验题1在程序中产生一个ArithmeticException类型被0除的异常,并用catch 语句捕获这个异常。最后通过ArithmeticException类的对象e 的方法getMessage给出异常的具体类型并显示出来。 package Package1; public class除数0 { public static void main(String args[]){ try{ int a=10; int b=0; System.out.println("输出结果为:"+a/b); } catch(ArithmeticException e){ System.out.println("除数不能为0"+e.getMessage()); } } } 实验题2在一个类的静态方法methodOne()方法内使用throw 产生ArithmeticException异常,使用throws子句抛出methodOne()的异常,

在main方法中捕获处理ArithmeticException异常。 package Package1; public class抛出异常 { static void methodOne() throws ArithmeticException{ System.out.println("在methodOne中"); throw new ArithmeticException("除数为0"); } public static void main(String args[]){ try{ int a=10; int b=0; int c=1; System.out.println("输出结果为:"+a/b); } catch(ArithmeticException e){ System.out.println("除数不能为0"+e.getMessage()); } } }

C语言程序编辑或调试中常见的错误

常见错误和程序分析 (1)忘记定义变量。例如: void main() { x=3; y=6; printf(“%d\n”,x+y); } C要求对程序中用到的美一个变量都必须定义其类型,上面程序中没有对x,y 进行定义。应在函数体的开头加int x,y; (2)输入输出的数据类型与所用格式说明符不一致。例如,若a已定义为整数,b已定义为实型: a=3;b=4.5; /*对a和b赋值*/ printf(“%f %d\n”,a,b); 编译时不给出出错信息,但运行结果将与原意不符,输出为0.000000 16402它们并不是按照赋值的规则进行转换(如把4.5转换为4),而是将数据在存储单元中的形式按格式符的要求组织输出(如b占4个字节,只把最后2个字节中的数据按%d作为整数输出)。 (3)未注意int型的数据的数值范围。Turbo C等编译系统,对一个整型数据分配2个字节。因此一个整数的范围为-2的13次方到2的15次方减1,即-32768~32767常见这样的程序段: int num; num=89101; printf(“%d”,num); 得到的却是23565,原因是89101已超过32767。2个字节容纳不下89101,则将高位截去,即将超过低16位的数截去,也即89101-65536=23565,有时还会出现负数。这种情况应改为: Long int num; num=89101; printf(“%ld”,num); 注意,如果只定义num为long型,而在输出时扔用%d说明符,也会出现以上错误。 (4)在输出语句scanf中忘记使用变量的地址符。例如: scanf(“%d%d”,a,b); 这是很多初学者刚学C语言时常见的疏忽,应写为scanf(“%d%d”,&a,&b); (5)输入数据的形式与要求不符。例如有以下scanf函数: scanf(“%d%d”,&a,&b); 有人输入 3 , 4 ,这是错的数据间应该用空格来分隔,读者可以用printf(“%d%d”,a,b);来验证下。应该输入 3 4,除非函数是scanf(“%d,%d”,&a,&b); 还应注意不能企图用

SEH 结构化异常处理

标题:【原创】加密与解密二版菜鸟学习笔记(2) - SEH 结构化异常处理 作者:ytcswb 时间: 2005-02-01,16:40:24 链接: https://www.360docs.net/doc/bd10027709.html,/showthread.php?t=10651 看学加密与解密二版学习笔记(2) - SEH 结构化异常处理 [ 工具] flyod1.10 [ 目的] 学习SEH的手法,另书中是用SoftICE调试的,看起来不习惯.根据原文内容重新整理一下,便于和我一样的菜鸟们一起学习. 今天下决心,好好学习,这是就算是个开始吧!感觉学明白的确很不容易! [ 注释] ?--为不能理解的地方,请大侠们指点一下.学习过程中,有理解错误的地方,肯请大侠们多多指教. [练习对象] 加密与加密二版第10章,光盘配套的练习软件:seh.exe seh2.exe [ writer ] ytcswb 2005.2.1 感谢看学及论坛的大侠们为我们提供这么好的学习资料。 1.例子seh.exe学习: 00401000 > $ 8D4424 F8 lea eax,dword ptr ss:[esp-8] //程序入口!根据下面的代码分析,这里显然可以 //理解为开辟8字节的空间,并把栈顶指针保存到eax //相当于sub esp,8 ; lea eax,dword ptr ss:[esp] 00401004 . 64:8705 00000>xchg dword ptr fs:[0],eax //记住fs[0]永远是指向当前err结构的指针, //执行完成后,fs[0]指向栈顶,准备在堆栈中构造1个err结构 //eax等于原fs[0],即指向原来的err结构的指针,即那个err结构的地址 0040100B . BB 2E104000 mov ebx,Seh.0040102E //地址40102e-->ebx,建议在此地址上设断点,才能正常跟踪入seh代码中 00401010 . 53 push ebx //压入堆栈,即当前err结构的handler成员,当前异常处理代码的入口地址 00401011 . 50 push eax //压入原fs[0],即当前err结构的prev成员,即下一个err结构的地址 此时堆栈: 0012FFBC 0012FFE0 指针到下一个SEH 记录//0012FFE0是个指针,看看就知道指向下一个err结构,数值上等于下一个err结构的地址 0012FFC0 0040102E SE 句柄//建立了1个当前的err结构 0012FFE0 FFFFFFFF SEH 链尾部

AOI测试异常处理

AOI测试异常处理.txt不怕偷儿带工具,就怕偷儿懂科技! 1品味生活,完善人性。存在就是机会,思考才能提高。人需要不断打碎自己,更应该重新组装自己。AOI测试异常处理参照: 1.TR7500机台异常故障处理方法: 1.连接中断: 显示:重试 -- 暂停 -- 复归 1.出现此情况后,测试人员首先点击“重试”按钮一次,查看机器是否恢复正常测试。 2.若“重试”无效,则再次点击“复归”按钮,选择“是”。让机板从机器内流至轨道出口,将机板取出。 3.机器进行“复归”以后,在看到LCD屏幕上会显示“开始测试 -- 复归”,我们选择“开始测试”--“是”。回复正常测试。 4.此取出机板没有经过测试并无资料,所以我们需重新进行测试。 2.机器马达未到位: 显示:“机器马达并未到位”的字样,并只有一个“复归”选项。 1.先将卡在轨道入口的机板取出,并按下“急停按钮”,防止再次有机板进入影响测试。 2.直接点击“复归”--“是”,让机器回复到正常测试。 3.若放入机板进行测试还是出现以上情况,则联系AOI程式人员或线外人员,对TR7500机台的轨道进行调节。 4.此取出机板没有经过测试并无资料,所以我们需重新进行测试。 3.感应器X或者X未检测到机板: 显示:“感应器2或者3未检测到机板”的字样,并只有一个“复归”选项。 1.检查机板是否卡在轨道内,或者放入机板方式有错误(在机板经过感应器后又被拿出)。 2.直接点击“复归”--“是”,让机器回复到正常测试。 3.此取出机板没有经过测试并无资料,所以我们需重新进行测试。 4.条码错误: 显示: 1.“条码错误”的字样,并只有一个“复归”选项。 2. TR7500机台显示屏上也会出现一个条码框。

Retrofit响应数据及异常处理策略

今天我们来谈谈客户端对通讯协议的处理,主要分为三部分:约定响应数据格式,响应数据的自动映射以及错误处理三部分。由于数据协议采用json的居多,因此我们在此基础上进行说明。 约定响应数据格式 协议格式 通常来说,你拿到的设计文档中会存在通信协议的说明,对于客户端来说,一个良好的通信协议需要能描述操作状态(操作码+操作提示)以操作结果,因此,常见的响应数据的格式如下: { "code": 0, "msg": "正常", "data": { "id": 1, "account": "121313", "accountName": "alipay", "income": "" } } code定义 code为我们自定义的操作状态码,首先来看我们常用的定义: msg定义 msg为服务器端返回的操作信息。 无论操作成功与否,客户端都应该根据业务给出准确的提示,客户端则根据实际情况选择展示与否。 data 定义 data则是请求返回的具体内容,通常data根据请求接口的不同最终会被解析成不同的实体类。 示例 下面我们以获取消息列表和消息详情两个接口返回的响应数据作为示例: 消息列表: {

"code": 0, "data": { "list": [ { "content": "你参加的活动已经开始了...", "createtime": "2016-09-23 16:44:02", "id": "4480", "status": 0, "title": "活动开始", "type": "1" }, { "content": "你参加的活动已经结束...", "createtime": "2016-09-19 14:30:02", "id": "4444", "status": 0, "title": "活动结束", "type": "1" } ], "total": 2 }, "msg": "正常" } 消息详情 { "code": 0, "data": { "detail": { "content": "你参加的活动已经开始了,请准时到你的活动中去执行", "createtime": "2016-09-23 16:44:02", "id": "4480", "status": 0, "title": "活动开始", "type": "1" }, }, "msg": "正常" }

如何进行单元测试

如何进行单元测试 1.摘要: 单元测试是软件测试的基础,本文详细的论述了单元测试的两个步骤人工静态检查法与动态执行跟踪法,所需执行的工作项目及相关的策略和方法。通过对这两个步骤的描述作者将多年的单元测试经验及测试理论注入于全文。 关键词:单元测试、人工检查、白盒测试、测试用例、跟踪调试 2.概述 单元测试是针对软件设计的最小单位——程序模块,进行正确性检验的测试工作。其目的在于发现每个程序模块内部可能存在的差错。 单元测试也是程序员的一项基本职责,程序员必须对自己所编写的代码保持认真负责的态度,这是也程序员的基本职业素质之一。同时单元测试能力也是程序员的一项基本能力,能力的高低直接影响到程序员的工作效率与软件的质量。 在编码的过程中作单元测试,其花费是最小的,而回报却特别优厚的。在编码的过程中考虑测试问题,得到的将是更优质的代码,因为在这时您对代码应该做些什么了解得最清楚。如果不这样做,而是一直等到某个模块崩溃了,到那时您可能已经忘记了代码是怎样工作的。即使是在强大的工作压力下,您也必须重新把它弄清楚,这又要花费许多时间。进一步说,这样做出的更正往往不会那么彻底,可能更脆弱,因为您唤回的理解可能不那么完全。 通常合格的代码应该具备以下性质:正确性、清晰性、规范性、一致性、高效性等(根据优先级别排序)。 1. 正确性是指代码逻辑必须正确,能够实现预期的功能。 2. 清晰性是指代码必须简明、易懂,注释准确没有歧义。 3. 规范性是指代码必须符合企业或部门所定义的共同规范包括命名规则,代码风格等 4. 一致性指代码必须在命名(如:相同功能采用相同变量标示符)、风格上保持统一 5. 高效性是指代码不但要满足以上性质,而且需要尽可能降低代码的执行时间。 3.单元测试步骤 在代码编写完成后的单元测试工作主要分为两个步骤:人工静态检查和动态执行跟踪。 人工静态检查是测试的第一步,这个阶段工作主要是保证代码算法的逻辑正确性(尽量通过人工检查发现代码的逻辑错误)、清晰性、规范性、一致性、算法高效性。并尽可能的发现程序中没有发现的错误。 第二步是通过设计测试用例,执行待测程序来跟踪比较实际结果与预期结果来发现错误。经验表明,使用人工静态检查法能够有效的发现30%到70%的逻辑设计和编码错误。但是代码中仍会有大量的隐性错误无法通过视觉检查发现,必须通过跟踪调试法细心分析才能够捕捉到。所以,动态跟踪调试方法也成了单元测试的重点与难点。

试验数据异常值的检验及剔除方法

目录 摘要......................................................................... I 关键词...................................................................... I 1引言 (1) 2异常值的判别方法 (1) 检验(3S)准则 (1) 狄克松(Dixon)准则 (2) 格拉布斯(Grubbs)准则 (2) 指数分布时异常值检验 (3) 莱茵达准则(PanTa) (3) 肖维勒准则(Chauvenet) (4) 3 实验异常数据的处理 (4) 4 结束语 (5) 参考文献 (6)

试验数据异常值的检验及剔除方法 摘要:在实验中不可避免会存在一些异常数据,而异常数据的存在会掩盖研究对象的变化规律和对分析结果产生重要的影响,异常值的检验与正确处理是保证原始数据可靠性、平均值与标准差计算准确性的前提.本文简述判别测量值异常的几种统计学方法,并利用DPS软件检验及剔除实验数据中异常值,此方法简单、直观、快捷,适合实验者用于实验的数据处理和分析. 关键词:异常值检验;异常值剔除;DPS;测量数据

1 引言 在实验中,由于测量产生误差,从而导致个别数据出现异常,往往导致结果产生较大的误差,即出现数据的异常.而异常数据的出现会掩盖实验数据的变化规律,以致使研究对象变化规律异常,得出错误结论.因此,正确分析并剔除异常值有助于提高实验精度. 判别实验数据中异常值的步骤是先要检验和分析原始数据的记录、操作方法、实验条件等过程,找出异常值出现的原因并予以剔除. 利用计算机剔除异常值的方法许多专家做了详细的文献[1] 报告.如王鑫,吴先球,用Origin 剔除线形拟合中实验数据的异常值;严昌顺.用计算机快速剔除含粗大误差的“环值”;运用了统计学中各种判别异常值的准则,各种准则的优劣程度将体现在下文. 2 异常值的判别方法 判别异常值的准则很多,常用的有t 检验(3S )准则、狄克松(Dixon )准则、格拉布斯(Grubbs )准则等准则.下面将一一简要介绍. 2.1 检验(3S )准则 t 检验准则又称罗曼诺夫斯基准则,它是按t 分布的实际误差分布范围来判别异常值,对重复测量次数较少的情况比较合理. 基本思想:首先剔除一个可疑值,然后安t 分布来检验被剔除的值是否为异常值. 设样本数据为123,,n x x x x ,若认j x 为可疑值.计算余下1n -个数据平均值 1n x -及标准差1n s - ,即2 111,1,1n n i n i i j x x s n --=≠=-∑. 然后,按t 分布来判别被剔除的值j x 是否为异常值. 若1(,)n j x x kn a -->,则j x 为异常值,应予剔除,否则为正常值,应予以保留.其中:a 为显著水平;n 数据个数;(,)k n a 为检验系数,可通过查表得到.

第六章错账更正练习题

第六章错账更正练习题 某企业将账簿记录与记账凭证进行核对时,发现下列经济业务的凭证内容或账簿记录有误:(1)开出现金支票180元,支付企业行政管理部门的日常零星开支。原编制记账凭证的会计分录为: 借:管理费用180 贷:库存现金180 (2)结算本月应付职工工资,其中生产工人工资18000元,车间管理人员工资2000元,企业行政部门工资为4300元。原编制记账凭证的会计分录为: 借:生产成本18000 制造费用2000 管理费用4300 贷:应付职工薪酬24300 该记账凭证在登记总账时,其“管理费用”科目借方所记金额为3400元。 (3)以银行存款支付广告费100000元。原编制记账凭证的会计分录为: 借:销售费用10000 贷:银行存款10000 (4)车间管理人员出差回来报销差旅费2100元,原预支2200元,交回100元。原编制记账凭证的会计分录为: 借:管理费用2100 库存现金100 贷:其他应收款2200 (5)结转本月实际完工产品的生产成本共计5400元。原编制记账凭证的会计分录为:借:库存商品4500 贷:生产成本4500 (6)收到购货单位偿还上月所欠货款8700元存入银行。原编制记账凭证的会计分录为:借:银行存款8700 贷:应付账款8700 (7)结转本期主营业务成本30000元。原编制记账凭证的会计分录如下: 借:主营业务成本300000 贷:本年利润300000 (8)出售原材料1000元,增值税税率17%,货款已收到,存入银行。 借:银行存款1170 贷:主营业务收入1000 应交税费——应交增值税(销项税额)170 要求:上列各项经济业务账簿处理错误,分别采用适当的更正错账方法,予以更正。

BCB讲座第十三讲异常处理

异常处理 在程序设计过程中,我们不仅仅要考虑如何实现程序的功能,还要防止可能出现的异常情况,所谓异常情况就是指在程序运行过程中出现的不正常或不可预料的情况,例如打开的文件不存在、不能分配所需的内存等等。特别是当一个软件要面向大量用户时,它所遇到的运行情况可能千差万别,如果不能够应付各种异常情况,其功能再好再强大也难以弥被这样的缺陷。本讲要介绍的就是如何在CBuilder中实现异常处理,并为Mp3Collect添加异常处理代码。 ●传统的异常处理方法 为了应付可能出现的不正常情况,传统的方法主要是通过条件判断语句来检查是否产生异常的事件。例如,在MP3Collect程序的SaveFile函数中,我们添加了如下的条件语句,以处理可能产生的打开文件错误: if(fp==NULL) { ShowMessage("不能打开文件Mp3Collect.sav,请检查是否为共享冲突"); return; } 在检测到了异常事件后,一般需要做两件事,一是显示错误的信息,例如以上代码中对ShowMessage()函数的调用,再一个就是中断程序原有的执行流程,因为异常的发生已经使得程序无法满足继续执行原有流程的条件,在SaveFile()函数中,如果文件打开失败,就不能继续后面的写文件操作,因此在异常处理中用return语句直接返回,中断了保存文件的操作。 这种异常处理的方法当然最容易理解,但在大型的软件开发项目中,需要考虑的异常情况非常多,如果每个地方都使用if语句来检查错误并处理异常,就会使编程工作变得非常繁杂,源代码的可读性也会大大降低。为了解决这一问题,人们在面向对象编程中找到了更加结构化和更简便的方法来实现异常处理。 ●CBuilder中的异常处理机制 CBuilder支持多种异常处理机制,其中包括符合ANSI标准的C++异常处理机制,微软公司提供的Win32结构化异常处理机制,以及基于VCL的异常处理机制,后者是Borland公司建议在CBuilder编程中采用的异常处理方式。 基于VCL的典型异常处理结构的形式如下所示: try{ //可能引起异常的代码段 } catch(Exception &e){ //对异常进行处理的代码 } 其中try和catch为C++关键字。try用于标志可能产生异常的代码段(Block),该代码段用try 后紧跟的一对大括号{}包括在内。如果这段程序在运行时产生了异常,系统会中止try代码段中的代码执行,并查找相应的catch代码段,如果找到了合适的catch代码段,即表示错误被捕捉到,这时相应的catch代码段被执行,如果没有找到合适的catch代码段,即错误始终没有被捕捉到,则系统会调用VCL库按照缺省的方法来处理异常。当然,如果try代码段在运行时一切正常,则catch代码段是不会被调用的。 在上面的异常处理结构中,我们看到,catch语句带有一个参数Exception &e,该参数是一个异

异常数据的处理(标准格式处理)

异常数据的处理 在使用“税务稽查查账软件”的过程中,其前提工作就是“企业数据采集”。通常可以使用奇星查账软件的“数据采集软件”完成企业电子账务数据的采集工作。但实际工作中,由于企业相关人员对“采集行为”的不理解、目前相关政策法规的不明确、企业服务器放在异地等情况,会造成无法通过“数据采集软件”完成正常的数据采集。这就需要通过一些技术手段,人工处理了。 通常对于无法正常采集的企业数据,我们采用下述三个环节进行处理: 一、要求企业从财务软件中,导出“余额表”及“序时账簿” 二、对企业提供的两个电子表进行格式化处理 三、将格式化处理的电子表利用查账软件中的“万能数据导入”还原到查账软件中,生 成电子账簿

出的格式会存在差异,我们对企业给出了规范性要求: 其一:余额表必须是对应数据年度的“一月份期初余额表”,表中所涉的会计科目应该“包含所有科目”,且所涉的会计科目级次应该是从“一级”到“最深科目级次”。并以Excel格式保存。 其二:序时账簿要求企业查询全年凭证,并根据数据量不同,按年、按季或分月导出为Excel。

需要进行处理后,才可使用 (一)处理“余额表” 企业提供的“余额表”中,应该含有科目代码、科目名称、借方余额、贷方余 额,如下图所示: 1、根据“查账软件”万能数据导入功能的要求,“科目名称”中不能含有科目代码信息,可通过Excel的替换功能,进行如下图所示操作,将类似“1002.01/”的信息清除掉

结果如下图所示 2、根据“查账软件”万能数据导入功能的要求,需要手工定义“科目性质”,即“资产”、“负债”、“所有者权益”等,在会计制度科目体系下,分别用“1——5”表示,在新准则下,分别用“1——6”表示 处理方法,通过Excel 的LEFT函数,取科目代码的“第一位”作为科目性质代码,如下图所示

相关文档
最新文档