shellcode跳转笔记

如果选用jmp esp作为定位shellcode的跳板,那么在函数返回后要根据缓冲区大小、所需shellcode长短等实际情况灵活地布置缓冲区。送入缓冲区的数据可以分为以下几种。

(1)填充物:可以是任何值,但是一般用NOP指令对应的0x90来填充缓冲区,并把shellcode布置于其后。这样即使不能准确地跳转到shellcode的开始,只要能跳进填充区,处理器最终也能顺序执行到shellcode,就是esp地址的下面是shellcode,而上面的地址是shellcode的短程jmp,在上面就全部是Nop填充。

(2)淹没返回地址的数据:可以是跳转指令的地址、shellcode起始地址,甚至是一个近似的shellcode地址。

(3)shellcode:可执行的机器代码。

在缓冲区中怎样摆放shellcode对exploit的成功至关重要。

shellcode比较少的话,比如shellcode只有几十个字节,我们干脆把它直接放在缓冲区里,所以shellcode位于函数返回地址之前。

我们也可以使用跳转指令jmp esp来定位shellcode,所以在溢出时我们多覆盖了一片内存空间,把shellcode恰好布置在函数返回地址之后。

把shellcode布置在函数返回地址之后的好处(不用担心自身被压栈数据破坏)。但是,超过函数返回地址以后将是前栈帧数据(栈的方向,内存高址),而一个实用的shellcode往往需要几百个字节,这样大范围地破坏前栈帧数据有可能引发一些其他问题。例如,若想在执行完shellcode后通过修复寄存器的值,让函数正常返回继续执行原程序,就不能随意破坏前栈帧的数据。

当缓冲区较大时,把shellcode布置在缓冲区内。这样做有以下好处。

(1)合理利用缓冲区,使攻击串的总长度减小:对于远程攻击,有时所有数据必须包含在个数据包中!

(2)对程序破坏小,比较稳定:溢出基本发生在当前栈帧内,不会大范围破坏前栈帧。

当然,即便是使用跳转指令来定位shellcode,我们也可以把缓冲区布置成类似shellcode起始地址这种组织方式,在返回地址之后再多淹没一点,并在那里布置一个仅仅几个字节的“shellcode header”,引导处理器跳转到位于缓冲区中那一大片真正的shellcode中去。(我的理解是,“shellcode header”就是一个短程jmp,刚好跳到shellcode的地址)

将shelcode布置在缓冲区中虽然有不少好处,但是也会产生问题。函数返回时,当前栈帧被弹出、这时缓冲区位于栈顶esp之上的内存区域。在弹出栈帧时只是改变了esp寄存器中的值,逻辑上,esp以上的内存空间的数据已经作度;物理上,这些数据并没有被销毁。如果shellkeode中没有压栈指令向栈中写入数据还没有太大影响:但如果使用push 指令在栈中暂存数据,压栈数据很可能会破坏到shelleode本身。

当缓冲区相对shellcode 较大时,把shellcode布置在缓冲区的“前端”(内存低址方向)。这时shellcode 离栈顶较远,几次压找可能只会破坏到一些填充值nop:但是,如果缓冲区已经被shellcode 占满,则shellcode离栈顶比较近,这时的情况就比较危险了。

为了使shellcode具有较强的通用性,我们通常会在shellcode一开始就大范围抬高栈顶(先用sub esp,100h之类的指令把栈抬高)。把shellcode“藏”在栈内,从而达到保护自身安全的目的。
使用其他跳转指令

使用jmp esp做“跳板”的方法是最简单,也是最常用的定位shellcode的方法。在实际的漏洞利用过程中,应当注意观察漏洞函数返回时所有寄存器的值。往往除了esp之外,eax、ebx、esi等寄存器也会指向栈顶附近,故在选择跳转指令地址时也可以灵活一些,除了jmp esp之外,mov eax、esp和jmp eax等指令序列也可以完成进入栈区的功能。

常用跳转指令与机器码的对应关系
机器码 指令 机器码 指令
FF E0 jmp eax FF D0 call eax
FF E1 jmp ecx FF D1 call ecx
FF E2 jmp edx FF D2 call edx
FF E3 jmp ebx FF D3 call ebx
FF E4 jmp esp FF D4 call esp
FF E5 jmp ebp FF D5 call ebp
FF E6 jmp esi FF D6 call esi
FF E7 jmp edi FF D7 call edi

不使用跳转指令

个别有苛刻的限制条件的漏洞不允许我们使用跳转指令精确定位shellcode,而使用shellcode的静态地址来覆盖又不够准确,这时我们可以做一个折中:如果能够淹没大片的内存区域,可以将shellcode布置在一大段nop之后。这时定位shellcode时,只要能跳进这一大片nop中,shellcode就可以最终得到执行。这种方法好像蒙着眼睛射击,如果靶子无比大,那么枪枪命中也不是没有可能。