能力值:
( LV9,RANK:280 )
|
-
-
2 楼
cs在32位兼容模式下 高32位寄存器根本不可见 完全透明 何来清零一说?
|
能力值:
( 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编辑
,原因:
|
能力值:
( LV2,RANK:10 )
|
-
-
4 楼
retf 都进64模式了,已经不是32模式了,你还是写64汇编吧,在x86dbg里面直接写几句运行一下就知懂结果哦了
|
能力值:
( 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位模式居然也是这样
|
能力值:
( LV3,RANK:30 )
|
-
-
6 楼
hhkqqs
hzqst
cs在32位兼容模式下 高32位寄存器根本不可见 完全透明 何来清零一说?
我在内嵌汇编里面试了一下,事实是32位兼容模式下进行mov&am ...
你VS是怎么用内联汇编的? 我x64用__asm 提示无法使用内联汇编. 是需要设置什么吗?
|
能力值:
( LV5,RANK:60 )
|
-
-
7 楼
ezrealik
你VS是怎么用内联汇编的? 我x64用__asm 提示无法使用内联汇编. 是需要设置什么吗?
我用的win32平台,上面那个代码是用来32位切换到64位写汇编的
|
能力值:
( LV5,RANK:60 )
|
-
-
8 楼
66666
|
能力值:
( LV3,RANK:30 )
|
-
-
9 楼
使用Windbg跟踪一下就很容易看到结果:
查询微软的文档(x64指令)可以看出,使用mov指令传送32位数据将会自动零扩展高32位,并没有说在哪个特定的处理器模式。
|
能力值:
( LV5,RANK:60 )
|
-
-
10 楼
Boring勇哥
使用Windbg跟踪一下就很容易看到结果:查询微软的文档(x64指令)可以看出,使用mov指令传送32位数据将会自动零扩展高32位,并没有说在哪个特定的处理器模式。
巨硬和Intel的文档我都看过,他们明显只针对64位模式下没有movzxd给出零扩展的说法,压根没提过86兼容模式也会影响到完全不可见的高32位
|
能力值:
( LV2,RANK:10 )
|
-
-
11 楼
严格说这个X64不是真正的64位,只是32位扩展。地址也没64位,立即数不能直接64位,要分二次附值。只是寄存器是64位而已。 add rax,1等于add eax,1 ;xor rax,rax 等同于xor eax,eax。
|
能力值:
( LV3,RANK:30 )
|
-
-
12 楼
hhkqqs
巨硬和Intel的文档我都看过,他们明显只针对64位模式下没有movzxd给出零扩展的说法,压根没提过86兼容模式也会影响到完全不可见的高32位
这可能就是传说中的“未定义行为”
|
能力值:
( 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.
|
能力值:
( LV5,RANK:60 )
|
-
-
14 楼
tDasm
1.对32位寄存器的写操作和运算操作,则会对相应的64位寄存器的高32位清零。
如在x64dbg上实验,mov eax, 1和add eax, 1会使rax的高32位清零;
xor eax ...
你说的这些都是手册上的,完全没解释我主贴说的这种现象,86兼容模式能影响寄存器的高32位从未在任何官方手册出现过
|
能力值:
( 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位程序
|
能力值:
( LV5,RANK:60 )
|
-
-
16 楼
yy虫子yy
其实严格来说,不是86兼容模式,而是Windows下cs=23h表示32位代码段
mov eax, 1
32位代码段模式下对32位寄存器的操作会视为全长
而这时候64位CPU内部会自动对齐到8字 ...
我也感觉是设计上统一了两种模式部分指令的实现机制,只不过Intel没有写进手册而已
|
能力值:
( 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编辑
,原因:
|
|
|