首页
社区
课程
招聘
未解决 [求助]关于64位处理器运行32位指令的疑问
发表于: 2019-6-1 16:53 3701

未解决 [求助]关于64位处理器运行32位指令的疑问

2019-6-1 16:53
3701
在32位汇编模式下我发现对eax、ecx、edx寄存器进行mov的操作,rax、rcx、rdx的高32位都是被清零的,我只知道在64位汇编下,对低32位寄存器进行类似操作会自动将高32位清零,在32位下是不是也是一样的呢?

[招生]系统0day安全班,企业级设备固件漏洞挖掘,Linux平台漏洞挖掘!

收藏
免费 0
支持
分享
最新回复 (16)
雪    币: 12857
活跃值: (9172)
能力值: ( LV9,RANK:280 )
在线值:
发帖
回帖
粉丝
2
cs在32位兼容模式下 高32位寄存器根本不可见 完全透明 何来清零一说?
2019-6-1 22:11
0
雪    币: 12547
活跃值: (6044)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
3
hzqst cs在32位兼容模式下 高32位寄存器根本不可见 完全透明 何来清零一说?
我在内嵌汇编里面试了一下,事实是32位兼容模式下进行mov eax, [esp + n]之类的操作,会把rax高32位自动清零,也就是说不论是不是32位兼容模式,对低32位寄存器进行mov操作,高32位都会被自动扩展为0
#define db(a) __asm __emit(a)
       DWORD a = 1;
       __asm
       {
               push 0x33
               push x64Enter1
               retf
x64Enter1:
               db(0x48) db(0x33) db(0xC0) //xor rax, rax
               db(0x48) db(0xF7) db(0xD0) //not rax
               push x64Exit1
               db(0xC6) db(0x44) db(0x24) db(0x04) db(0x23) //mov byte ptr[rsp + 4], 023h
               retf
x64Exit1:
               mov eax, a
               push 0x33
               push x64Enter2
               retf
x64Enter2:
               db(0x48) db(0xC1) db(0xE8) db(0x20) //shr rax, 20h
               push x64Exit2
               db(0xC6) db(0x44) db(0x24) db(0x04) db(0x23) //mov byte ptr[rsp + 4], 023h
               retf
x64Exit2:
               mov a, eax
       }
       printf("%X\n", a);
这段代码我在VS上试过,结果为0
最后于 2019-6-2 00:23 被hhkqqs编辑 ,原因:
2019-6-2 00:22
0
雪    币: 6
活跃值: (3480)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
retf  都进64模式了,已经不是32模式了,你还是写64汇编吧,在x86dbg里面直接写几句运行一下就知懂结果哦了
2019-6-2 03:05
0
雪    币: 12547
活跃值: (6044)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
5
咖啡_741298 retf 都进64模式了,已经不是32模式了,你还是写64汇编吧,在x86dbg里面直接写几句运行一下就知懂结果哦了
我上面的asm先切换到64位,让rax为0xFFFFFFFFFFFFFFFF,然后切回32位,对eax赋值为dword ptr[esp],然后切回64位让rax右移32位,按理来说这时候eax应该是0xFFFFFFFF,但结果却是0(如果注释掉mov eax, a,结果是0xFFFFFFFF没毛病),说明32位下mov的赋值直接把rax高32位清零了,本来这种现象我只在64位模式下见过,没想到32位模式居然也是这样
2019-6-2 03:27
0
雪    币: 1570
活跃值: (383)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
6
hhkqqs hzqst cs在32位兼容模式下 高32位寄存器根本不可见 完全透明 何来清零一说? 我在内嵌汇编里面试了一下,事实是32位兼容模式下进行mov&am ...
你VS是怎么用内联汇编的?  我x64用__asm 提示无法使用内联汇编. 是需要设置什么吗?
2019-6-2 09:17
0
雪    币: 12547
活跃值: (6044)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
7
ezrealik 你VS是怎么用内联汇编的? 我x64用__asm 提示无法使用内联汇编. 是需要设置什么吗?
我用的win32平台,上面那个代码是用来32位切换到64位写汇编的
2019-6-2 13:38
1
雪    币: 2674
活跃值: (2304)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
8

66666

2020-10-30 10:23
0
雪    币: 4157
活跃值: (1540)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
9

使用Windbg跟踪一下就很容易看到结果:

查询微软的文档(x64指令)可以看出,使用mov指令传送32位数据将会自动零扩展高32位,并没有说在哪个特定的处理器模式。

2020-11-1 16:25
0
雪    币: 12547
活跃值: (6044)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
10
Boring勇哥 使用Windbg跟踪一下就很容易看到结果:查询微软的文档(x64指令)可以看出,使用mov指令传送32位数据将会自动零扩展高32位,并没有说在哪个特定的处理器模式。
巨硬和Intel的文档我都看过,他们明显只针对64位模式下没有movzxd给出零扩展的说法,压根没提过86兼容模式也会影响到完全不可见的高32位
2020-11-1 17:26
0
雪    币: 15039
活跃值: (6253)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
严格说这个X64不是真正的64位,只是32位扩展。地址也没64位,立即数不能直接64位,要分二次附值。只是寄存器是64位而已。
add rax,1等于add eax,1 ;xor rax,rax 等同于xor eax,eax。
2020-11-1 18:06
0
雪    币: 4157
活跃值: (1540)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
12
hhkqqs 巨硬和Intel的文档我都看过,他们明显只针对64位模式下没有movzxd给出零扩展的说法,压根没提过86兼容模式也会影响到完全不可见的高32位
这可能就是传说中的“未定义行为”
2020-11-1 18:09
0
雪    币: 15039
活跃值: (6253)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
1.对32位寄存器的写操作和运算操作,则会对相应的64位寄存器的高32位清零。

如在x64dbg上实验,mov eax, 1和add eax, 1会使rax的高32位清零;

xor eax, eax是对eax的清零运算操作,所以xor rax, rax会被编译器优化为指令更短的xor eax, eax因为二者在x64汇编中的效果是一样的;

但是mov ax,1和mov al, 1不会对rax的高32位进行清零的操作。

2.立即数的使用,优先使用32位扩展,64位的立即数使用较少。

push指令和对内存的写操作只支持4字节的立即数数据,比如push 0x12345678和mov qword ptr [rax], 0x12345678是合法的,但是如果要对长度长于4字节的

立即数使用(比如0x2134567890),就需要分两步进行,借用寄存器进行操作,如需要将0x1234567890压栈,应当:mov rax, 0x2134567890; push rax.
2020-11-1 18:10
0
雪    币: 12547
活跃值: (6044)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
14
tDasm 1.对32位寄存器的写操作和运算操作,则会对相应的64位寄存器的高32位清零。 如在x64dbg上实验,mov eax, 1和add eax, 1会使rax的高32位清零; xor eax ...
你说的这些都是手册上的,完全没解释我主贴说的这种现象,86兼容模式能影响寄存器的高32位从未在任何官方手册出现过
2020-11-1 19:50
0
雪    币: 248
活跃值: (3789)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
hhkqqs 你说的这些都是手册上的,完全没解释我主贴说的这种现象,86兼容模式能影响寄存器的高32位从未在任何官方手册出现过
其实严格来说,不是86兼容模式,而是Windows下cs=23h表示32位代码段
mov eax, 1
32位代码段模式下对32位寄存器的操作会视为全长
而这时候64位CPU内部会自动对齐到8字节的rax,只是我们看不到高32位
64位CPU也只有这样设计才能支持32位程序
2020-11-1 20:47
0
雪    币: 12547
活跃值: (6044)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
16
yy虫子yy 其实严格来说,不是86兼容模式,而是Windows下cs=23h表示32位代码段 mov eax, 1 32位代码段模式下对32位寄存器的操作会视为全长 而这时候64位CPU内部会自动对齐到8字 ...
我也感觉是设计上统一了两种模式部分指令的实现机制,只不过Intel没有写进手册而已
2020-11-1 21:39
0
雪    币: 2674
活跃值: (2304)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
17

又仔细调试了下大佬的代码:

一. 不屏蔽mov eax,a

源码

#define db(a) __asm __emit(a)
       DWORD a = 1;
       __asm
       {
               push 0x33
               push x64Enter1
               retf
x64Enter1:
               db(0x48) db(0x33) db(0xC0) //xor rax, rax
               db(0x48) db(0xF7) db(0xD0) //not rax
               push x64Exit1
               db(0xC6) db(0x44) db(0x24) db(0x04) db(0x23) //mov byte ptr[rsp + 4], 023h
               retf
x64Exit1:
               mov eax, a
               push 0x33
               push x64Enter2
               retf
x64Enter2:
               db(0x48) db(0xC1) db(0xE8) db(0x20) //shr rax, 20h
               push x64Exit2
               db(0xC6) db(0x44) db(0x24) db(0x04) db(0x23) //mov byte ptr[rsp + 4], 023h
               retf
x64Exit2:
               mov a, eax
       }
       printf("%X\n", a);

DEBUG版调试结果:


一. 屏蔽mov eax,a


源码

#define db(a) __asm __emit(a)
       DWORD a = 1;
       __asm
       {
               push 0x33
               push x64Enter1
               retf
x64Enter1:
               db(0x48) db(0x33) db(0xC0) //xor rax, rax
               db(0x48) db(0xF7) db(0xD0) //not rax
               push x64Exit1
               db(0xC6) db(0x44) db(0x24) db(0x04) db(0x23) //mov byte ptr[rsp + 4], 023h
               retf
x64Exit1:
               ; mov eax, a ;屏蔽掉这句
               push 0x33
               push x64Enter2
               retf
x64Enter2:
               db(0x48) db(0xC1) db(0xE8) db(0x20) //shr rax, 20h
               push x64Exit2
               db(0xC6) db(0x44) db(0x24) db(0x04) db(0x23) //mov byte ptr[rsp + 4], 023h
               retf
x64Exit2:
               mov a, eax
       }
       printf("%X\n", a);

DEBUG版调试结果

rax寄存器的高32位对于WOW64兼容模式下运行的32位进程仍然是不可见的(在mov dword ptr ss:[ebp-c],eax这下个断点就可以看到eax的准确值了,我这个是调试得太块,直接F9步过了,但逻辑正确,只管结果就行了),这里是通过改变段选择子并进行远返回来进行x86/x64切换得出的。

好了!开会去咯!



最后于 2020-11-2 11:44 被低调putchar编辑 ,原因:
2020-11-2 09:57
0
游客
登录 | 注册 方可回帖
返回
//