首页
论坛
课程
招聘
[分享]关于UEH异常处理的踩坑记录
2021-12-8 12:45 5501

[分享]关于UEH异常处理的踩坑记录

2021-12-8 12:45
5501

0x00背景

昨天遇到了一个很有意思的CrackMe小demo,其实想要破解它还是很简单的,但是想要弄清楚它的机制,对于我这个新手来说还是有点麻烦的,为了弄清它的原理,故记录一下探索过程。

0x01 分析过程

看起来就是个破解密码的小demo,也没啥玄机,用resource hacker看看有没有什么隐藏的组件之类的。

 

image-20211208104045998

 

这个应该是密码输入正确后显示的图片,也就是没有我们想要的MessageBox,不能直接找上面的过程分析了。

 

image-20211208104216928

 

image-20211208104405489

 

看起来资源也没有多少,看看组件的ID就行,在后面可能会用到,然后我们打开OD,找找在哪里用到了这个组件ID,首先猜想一下至少会在获取组件的输入的时候用到,也就是GetDlgItemTextA/W这里。

 

找到了,接下来我们在这儿下个断点,看看数据是怎么走向的。

 

image-20211208104851120

 

image-20211208105121888

 

接下来单步步过一下:

 

image-20211208105233741

 

可以看到,EIP就突变了,一下子不知道跑哪儿去了,我到这里的时候有点懵,看来直接上OD不太行,然后我就打开IDA静态分析一下这个程序的结构是怎样的。

 

image-20211208105527460

 

我们一下子就能定位到GetDlgItemTextA这个函数,双击来到代码段,然后Ctrl+x看看交叉引用,很好,逻辑块尽收眼底,接下来我们看看有什么奥秘:

 

image-20211208105649081

 

先看看调用函数的地方干了什么,毕竟它要验证我们输入的密码对不对,就必然会有字符串的比较,C/C++有strcmp,但是这没有,所以应该是汇编语言最原始的ESI/EDI的字符一个个比较。

 

我们 按下空格,看看代码:image-20211208110051201

 

发现了一个异常,我们再次按空格回到逻辑图,看看有没有处理异常的地方:

 

image-20211208110217942

 

这里有一个异常处理函数,而且是UEH,只要产生了异常,并且没有处理函数能处理,都会调用这个函数指定的回调函数去处理,也就是说这个函数的参数时真正处理异常的函数的地址。也就是loc_40334A,我们跟进到这个函数看看这里是啥,怎么处理的异常数据。

 

SetUnhandledExceptionFilter function (errhandlingapi.h) - Win32 apps |微软文档 (microsoft.com);k(SetUnhandledExceptionFilter);k(DevLang-C%2B%2B);k(TargetOS-Windows)%26rd%3Dtrue)

 

image-20211208111602149

 

可是当我们来到这里的时候却一下子懵了,这都是什么鬼啊,往左边一看,发现是.data也就是数据段,这些所谓的db就是它的二进制代码,还好IDA智能,我们可以选中这块区域,按c和p键将它转化成汇编代码:

 

image-20211208111025174

 

看吧,这就好分析多了:

 

image-20211208111425642

0x011 误入歧途

然后我就跑到OD去找这个函数了,毕竟这样看也能什么线索。

 

一步步单步走下来发现了这些东西,这里[EBP + 0x8]是进入此函数的第一个参数

 

image-20211208112424581

 

到这里,就又不得不提一下UEH指定的顶级异常处理函数了,这里是它的函数原型,参数是

 

image-20211208111953828

 

它的参数是一个指向异常信息的结构体指针,也就是这样的:

 

EXCEPTION_POINTERS (winnt.h) - Win32 应用|微软文档 (microsoft.com);k(_EXCEPTION_POINTERS);k(DevLang-C%2B%2B);k(TargetOS-Windows)%26rd%3Dtrue)

 

image-20211208112705562

 

​ 然后它的第一个字段是image-20211208112736942

 

​ 再看看这个结构体,它的第一个字段又是异常码:

 

image-20211208112856742

 

然后结合OD步过到这里的EAX看这个错误码刚好是0xC0000005,刚好就是内存访问异常:

 

image-20211208113044248

 

image-20211208113357651

 

所以到这里就很顺了,自己找的没错,也就是我们无论输入什么,异常处理函数的前几句话都是把0xC00000050x00DEADFF按位与一下然后左移5位得到0xA0,继续往下走就出现了字符串magic,把这个字符串保存在某个地方,然后结合这张图就会认为之前之前跟fubar比较后来变成了跟magic比较,关键是此时magic确实就是正确的答案。可是为什么呢?我们在异常处理函数内部并没有发现EDI的变化呀。

 

image-20211208113951782

 

今天来探究一下,到底在哪里神不知鬼不觉改了EDI的值,导致我们不跟“fubar”比较了,变成了跟“magic”比较。

0x012 步入正轨

image-20211208121926352

 

前景回顾一下,刚刚进入这个终极异常处理函数的时候,ESI是第一个参数的解引用,也就是ExceptionRecord字段,经过LODSD操作后把ESI的数据转移到EAX中了,然后解了一次引用,此时的EAX保存的是异常码,然后EAX经过按位与和左移操作之后变成了0xA0,关键就是这里的LEA指令的这一块地方,还有上面的LODSD指令:

 

上面不是把ESI的值转移到EAX中了吗,有一个细节就是ESI此时已经不是ExceptionRecord的地址了,因为它已经发生了这个结构体大小的偏移,也就是说它现在是ExceptionPointers的第二个字段:PCONTEXT,它是另一个结构体的指针:

 

image-20211208122849226

 

image-20211208122815495

 

紧接着ESI就解了一次引用,来到了Context结构体,有好多字段,看起来都是一些寄存器之类的:

 

CONTEXT (winnt.h) - Win32 应用|微软文档 (microsoft.com)

 

image-20211208122956809

 

然后这个地址加了一个0x9C:

 

image-20211208123142235

 

来看看是啥被改了?可不就是它么?

 

image-20211208123226698

 

原来一直没有被发现的EDI突变发生在了这里,之前计算得到的EAX的值被赋值给了EDI,然后出了这个函数就被还原到了各个寄存器,我们看一下之前计算得到的地址是不是“magic”字符串的地址:

 

image-20211208123931133

0x02 小结

千万不能“想当然”,不能放过一丝细节,不要我们觉得合理了就不管了,当然,最重要的还是基础要牢固,这次的坑就挖在了LODSx指令上了,完全没有在意它的涵义。

 

至此程序分析完了,分享一下思路,同时也是教训。


恭喜ID[飞翔的猫咪]获看雪安卓应用安全能力认证高级安全工程师!!

上传的附件:
收藏
点赞1
打赏
分享
最新回复 (1)
雪    币: 616
活跃值: 活跃值 (610)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
wx_Van_Zovy 活跃值 2021-12-8 19:32
2
0
前来学习
游客
登录 | 注册 方可回帖
返回