首页
社区
课程
招聘
[讨论]win32asm子程序中uses寄存器列表的实现问题
发表于: 2006-7-21 09:20 7239

[讨论]win32asm子程序中uses寄存器列表的实现问题

2006-7-21 09:20
7239

通常,有"uses 寄存器列表"的子程序会由编译器在入口处添加如下指令:
    push ebp
        mov ebp,esp
        add -(sizeof 局部变量列表)
    push 列表中的各个寄存器

在每个出口处添加:
    pop 列表中的相应寄存器
    leave
        (注:下接retn指令)

这样来实现“uses寄存器列表”是有严重安全问题的(健壮性较差)!请看:
        .386
        .model flat,stdcall
        option casemap:none

        .code
Sub1        proc uses ebx Var
        LOCAL        x
        add        ebx,Var
        mov        x,ebx
        push        x
        ret
Sub1        endp

start:        invoke        Sub1,5
        end        start

Sub1子程序执行前后ebx的内容发生了改变,违背了保护ebx的初衷;若作为回调函数提供给windows使用,将引发难以预料的恶果。
  出现这一问题的主要原因,在于进栈、出栈不平衡(不配对)。而要由程序员保证进出栈一定平衡只是一种理想,难保不出现不平衡的情况;况且在某些特定情况下(姑且留个伏笔)就不是由程序员而是要由软件使用者(即用户)来保证进出栈平衡,那就更是难上加难了。
  其实,要彻底解决这个问题也很简单,只须将“push 列表中的各个寄存器”移至子程序入口处的最前面(push ebp之前),并将“pop 列表中的相应寄存器”移至leave之后(retn指令之前),问题就得以解决!――当然,对参数的访问均需改为[参数原地址+sizeof 寄存器列表]。
  强烈建议:编译器(包括但不限于汇编编译器)开发商要对上述问题有个客观的认识,采取可靠措施积极消除安全隐患。


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 7
支持
分享
最新回复 (12)
雪    币: 2384
活跃值: (766)
能力值: (RANK:410 )
在线值:
发帖
回帖
粉丝
2
是你自己的用法有问题,你push x了一个x值,没有相应的pop出栈,倒致堆栈错乱了,当然会出错了,你如果真要反回x的值,用eax来返回。
2006-7-21 09:45
0
雪    币: 207
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
用例的目的是为了说明如何简便而又可靠地保证在堆栈不平衡的情况下,被保护的若干个寄存器在子程序返回后其值仍同子程序进入前一样,不牵涉到子程序的返回值。
2006-7-21 16:06
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
这并不是USERS的安全问题,是你自己的用法错误,你不按标准用,就不要用USES,应该自己写代码处理
2006-7-21 20:57
0
雪    币: 203
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
最初由 casn 发布
强烈建议:编译器(包括但不限于汇编编译器)开发商要对上述问题有个客观的认识,采取可靠措施积极消除安全隐患。

提高认识的应该是你自己。你自己不遵守语言的语法规则,能怪编译器?编译器的智能程度不可能那么高。
2006-7-21 21:21
0
雪    币: 222
活跃值: (10)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
6
其实我明白楼主的意思,他说的是MASM在建立STACK FRAME的顺序上有点问题,我们知道一般的编译/汇编器是按照以下顺序建立STACK FRAME的:

push ebx
push esi
push edi
push ebp
mov ebp,esp
sub esp,xxx

而MASM则是:

push ebp
mov ebp,esp
sub esp,xxx
push ebx
push esi
push edi

这样就完全抹消掉使用ebp作为LOCAL基指针的好处了,在出口处MASM首先就要pop原来保护的寄存器,如果此时堆栈没有平衡的话,pop出来的内容就会不对。
而其它的编译/汇编器会首先恢复esp,然后在原来esp的基础上恢复其它寄存器,这样即使堆栈不平衡也不会造成问题
2006-7-28 15:52
0
雪    币: 207
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
坛友drwch的理解完全正确。
理解万岁!
2006-7-29 11:21
0
雪    币: 291
活跃值: (213)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
8
反汇编一些程序就可以发现,只要是微软的编译器编译的程序,都是先构造栈帧,然后保存ebx,esi,edi等寄存器,而不是先保存寄存器。不仅仅是MASM的问题

例如,以下是kernel32.dll中的一段,可以发现它也是先构造堆栈然后才保存三个重要寄存器的

Exported fn(): LCMapStringA - Ord:023Bh
:77E2569E 55                      push ebp
:77E2569F 8BEC                    mov ebp, esp
:77E256A1 81EC08020000            sub esp, 00000208
:77E256A7 53                      push ebx
:77E256A8 56                      push esi
:77E256A9 57                      push edi
:77E256AA 8B7D0C                  mov edi, dword ptr [ebp+0C]
:77E256AD 57                      push edi
:77E256AE FF7508                  push [ebp+08]
:77E256B1 E8820BFFFF              call 77E16238
:77E256B6 33DB                    xor ebx, ebx
:77E256B8 3BC3                    cmp eax, ebx
:77E256BA 8945F8                  mov dword ptr [ebp-08], eax
:77E256BD 0F84C3000000            je 77E25786
:77E256C3 395D1C                  cmp dword ptr [ebp+1C], ebx
:77E256C6 0F8CBA000000            jl 77E25786
:77E256CC 7409                    je 77E256D7
:77E256CE 395D18                  cmp dword ptr [ebp+18], ebx
:77E256D1 0F84AF000000            je 77E25786
2006-7-29 12:28
0
雪    币: 326
活跃值: (88)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
9
最初由 drwch 发布
其实我明白楼主的意思,他说的是MASM在建立STACK FRAME的顺序上有点问题,我们知道一般的编译/汇编器是按照以下顺序建立STACK FRAME的:

push ebx
push esi
push edi
........


我好像还没有见过这种顺序,这样的话,传递给函数的参数就不能用了~
2006-7-30 07:20
0
雪    币: 222
活跃值: (10)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
10
只是指针变动一下而已,为何不能用?楼上可以试试GOASM,看看它与MASM在构造STACK FRAME上有什么区别
2006-7-30 09:41
0
雪    币: 291
活跃值: (213)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
11
用MASM也可以指定是先保存寄存器或者是先构造栈帧
使用OPTION PROLOGUE和OPTION EPILOGUE伪指令就可以做到
2006-7-30 09:50
0
雪    币: 433
活跃值: (176)
能力值: ( LV13,RANK:1250 )
在线值:
发帖
回帖
粉丝
12
push后跟ret?是在构造变形jmp吗?

另外好象MASM里凡是在子程序里用到ret指令,编译器就会马上在前面加上leave,这样想用push/ret来构造变形跳转都无法做到,因为ret指令一用就变成leave然后从子程序返回了!
2006-7-30 10:46
0
雪    币: 291
活跃值: (213)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
13
最初由 冲天剑 发布

另外好象MASM里凡是在子程序里用到ret指令,编译器就会马上在前面加上leave,这样想用push/ret来构造变形跳转都无法做到,因为ret指令一用就变成leave然后从子程序返回了!


可以做到的,用OPTION EPILOGUE:NONE就可以
2006-7-30 10:49
0
游客
登录 | 注册 方可回帖
返回
//