Windows强制执行READ-ONLY .text部分,甚至由ld链接器禁用

时间:2016-08-12 08:29:19

标签: windows assembly x86 gdb nasm

在下面的玩具程序中,我在.text部分声明一个变量并写入它,这会产生分段错误,因为.text部分被标记为READ-ONLY:

Breakpoint 1, 0x00401000 in start ()
(gdb) disassemble
Dump of assembler code for function start:
=> 0x00401000 <+0>:     movl   $0x2,0x40100a
End of assembler dump.
(gdb) stepi

Program received signal SIGSEGV, Segmentation fault.
0x00401000 in start ()
(gdb)

以下是objdump输出:

test.exe:     file format pei-i386

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         0000001f  00401000  00401000  00000200  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .idata        00000014  00402000  00402000  00000400  2**2
                  CONTENTS, ALLOC, LOAD, DATA

但是,使用--omagic开关进行链接(禁用READ-ONLY .text部分)会产生以下结果:

ld --omagic -o test.exe test.obj

test.exe:     file format pei-i386

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         0000001f  00401000  00401000  000001d0  2**4
                  CONTENTS, ALLOC, LOAD, CODE
  1 .idata        00000014  00402000  00402000  000003d0  2**2
                  CONTENTS, ALLOC, LOAD, DATA

但是使用GDB进行调试会产生以下(奇怪的)结果:

Breakpoint 1, 0x00401000 in start ()
(gdb) disassemble
Dump of assembler code for function start:
=> 0x00401000 <+0>:     dec    %ebp
   0x00401001 <+1>:     pop    %edx
   0x00401002 <+2>:     nop
   0x00401003 <+3>:     add    %al,(%ebx)
   0x00401005 <+5>:     add    %al,(%eax)
   0x00401007 <+7>:     add    %al,(%eax,%eax,1)
End of assembler dump.
(gdb) stepi
0x00401001 in start ()
(gdb) stepi
0x00401002 in start ()
(gdb) stepi
0x00401003 in start ()
(gdb) stepi
0x00401005 in start ()
(gdb) stepi

Program received signal SIGSEGV, Segmentation fault.
0x00401005 in start ()
(gdb)

首先,我仍然遇到分段错误,但汇编代码也改变了结构?

如何将.text部分与Windows 10 x64上的可写内容相关联?

玩具计划:

    BITS 32

    section .text
    global _start
_start:
    mov [var], dword 2
var:    dd 0
    ret

2 个答案:

答案 0 :(得分:3)

--omagic标志导致GNU链接器生成错误的PECOFF可执行文件。段必须在文件中对齐,文件对齐最小为512字节,但链接器将.text段放在文件偏移量0x1d0处。

不使用--omagic标志,而是正常生成可执行文件,然后使用objcopy更改节标题中的标记:

ld -o test-tmp.exe test.obj
$(OBJCOPY) --set-section-flags .text=code,data,alloc,contents,load test-tmp.exe test.exe

答案 1 :(得分:2)

出于某种原因,ld完全更改了使用--omagic选项链接的PE可执行文件。

使用cmp实用程序快速比较文件显示:

 137 177 222
 141   0 320
 142   6   5
 213   0 320
 214   2   1
 217 142 205
 218 154 353
 397   0 320
 398   2   1
 437   0 320
 438   4   3
 465   0 307

...

有很多差异,虽然ld原则上只应更改节标题(.text)的节标志,即设置标志IMAGE_SCN_MEM_WRITE

使用HxD手动更改标志,即将偏移量为0x19F的字节设置为0xE0可以解决问题......

enter image description here

程序的试运行,互换顺序为varret(否则程序崩溃):

Breakpoint 1, 0x00401000 in start ()
(gdb) disassemble
Dump of assembler code for function start:
=> 0x00401000 <+0>:     movl   $0x2,0x40100b
   0x0040100a <+10>:    ret
End of assembler dump.
(gdb) stepi
0x0040100a in start ()
(gdb) disassemble
Dump of assembler code for function start:
   0x00401000 <+0>:     movl   $0x2,0x40100b
=> 0x0040100a <+10>:    ret
End of assembler dump.
(gdb) x/wx var
0x40100b <var>: 0x00000002
(gdb)

我们认为事情按预期发挥作用。

我的结论是ld以某种方式生成格式错误的PE可执行文件,我看到@RossRidge有这个答案(ld不尊重各部分的文件对齐)。