0%

手脱Yoda's Protector v1.3(Yoda's Crypter)

OD加载程序,发现入口处有PUSHAD指令,尝试一下ESP定律

image-20211227102347793

断在了这里,我们可以看到这里将给SEH链添加一个新的节点(**注意看fs:[]**),接着通过JMP指令跳转到下面引发一个异常,我们跟到JMP指令处。点击view-SEH chain查看,可以看到刚刚安装的异常处理程序入口地址为46590B。

image-20211227102521443

image-20211227112158637

​ 不出意外的话到达该异常处理程序,随后就会到达OEP,这里OEP为4271B0(其实和之前的exe一样,只是加壳程序不一样)

image-20211227112410090

修复IAT

​ 和之前一样,我们看一下数据窗口以及find reference,看到这些IAT项目都和之前提到的IAT重定向一样,下图中00590000处的大小在壳执行之前长度为3000字节,但是壳执行以后,该区段变成了47000字节,即可壳将该区段增大了,并且增大的部分供自己使用。

image-20211227142202869

image-20211227142320524

右键Follow,看看被重定向到了哪里

image-20211227143744907

我们先试一下Imprec自带的trace能否修复,show invalid—右键Trace Level1,可以看到修复了一部分

image-20211227144522856

关键跳

先让程序停在OEP处,然后随便定位一个重定向过的IAT项。我们给460ECC这一项设置硬件写入断点,接着如果我们重启OD的话,硬件断点依然存在。重启运行起来,断在了这里

image-20211227150716051

EDX的值460ECC,即指向了之前我们设置了硬件断点的那个重定向的IAT项,这里其被写入的是正确的值,随后会被修改为重定向过的值,我们继续往下跟,看看会发生什么。

到了这里,460ECC处的值有了变化,这里460ECC中被写入重定向过的值,ESI此时保存的就是重定向过的值。

image-20211227154801878

也就是说正常的IAT项只会被写入一次,而需要被重定向的项将被写入两次。正常的IAT项在46577F的跳转处会直接跳转到4657B1,这里我们可以看到46577F这一处JMP指令,其将跳过红色箭头标注的设置为重定向值的指令,所以这里是关键跳,之前还有几处条件跳转,这里我们来尝试NOP掉写入重定向值的指令,看看效果如何。

但是我们首先需要给465799这条指令设置硬件执行断点,这里我们并不向想其被写入重定向的值,所以给其上一行设置硬件执行断点。然后重新加载程序运行起来,断了下来,我们将写入重定向值的指令NOP掉。

image-20211227161144403

删除硬件断点后,运行起来发现行不通,再次回到关键跳处,可以看到46577D处的条件跳转将直接跳到下面,这样46577F处的关键跳将得不到执行,接着将被写入重定向的值,我们尝试将46577D这处条件跳转NOP掉,让其直接执行46577F处的JMP指令,我们来看看效果。

image-20211227161910326

发现依旧不行,那么我们来看看IAT吧,我们可以看到IAT项都被修复了,都是正确的。这里我们有两种选择: 一,再开一个OD,加载该CrackMe的另一个实例,直接跟到OEP处,不修改任何东西,然后将当前我们这个实例的正确的IAT复制出来,覆盖掉新开的这个实例的IAT,注意是二进制复制,这个方法比较简单。二,直接用IMP REC定位到CrackMe的进程,此时IAT全部被写入正确的值了,但是还未到达OEP处,我们直接填上OEP,RVA,SIZE等数据,没有到达OEP处没有关系。以此来进行修复。

SEH链

​ 每次我们定义了一个新的SEH异常处理回调函数,EXCEPTION_REGISTRATION结构的prev字段都被要求填写上一个EXCEPTION_REGISTRATION结构的地址,随着应用程序对模块的调用一层层深入下去的时候,那么最后回调函数会形成一个SEH链.
从数据结构的角度来讲,SEH链就是一个只允许在链表头部进行增加和删除节点操作的单向链表,且链表头部永远保存在fs:[0]处的TEB结构中。
详细请看SEH笔记。

段寄存器

cs是代码段寄存器

1
存放当前正在运行的程序代码所在段的段基址,表示当前使用的指令代码可以从该段寄存器指定的存储器段中取得,相应的偏移量则由IP提供。

ds是数据段寄存器

1
当前程序使用的数据所存放段的最低地址,即存放数据段的段基址.

ss是堆栈段寄存器

1
当前堆栈的底部地址,即存放堆栈段的段基址。

es是扩展段寄存器

1
当前程序使用附加数据段的段基址,该段是串操作指令中目的串所在的段

fs是标志段寄存器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
fs是80386起增加的两个辅助段寄存器之一,在这之前只有一个辅助段寄存器ES
FS寄存器指向当前活动线程的TEB结构(线程结构)
偏移 说明
000 指向SEH链指针
004 线程堆栈顶部
008 线程堆栈底部
00C SubSystemTib
010 FiberData
014 ArbitraryUserPointer
018 FS段寄存器在内存中的镜像地址
020 进程PID
024 线程ID
02C 指向线程局部存储指针
030 PEB结构地址(进程结构)
034 上个错误号

gs是全局段寄存器

1
gs是80386起增加的两个辅助段寄存器之一,在这之前只有一个辅助段寄存器ES
**ps:在x86平台的用户模式下,Windows将FS段选择器指向当前线程的TEB数据,即TEB总是由**fs:[0]**指向的,在x64平台上,这个指向关系变成了**gs:[0]**。**