Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 气体汇编程序不使用2字节相对JMP位移编码(仅1字节或4字节)_Assembly_X86_Gnu Assembler_Shellcode_Machine Code - Fatal编程技术网

Assembly 气体汇编程序不使用2字节相对JMP位移编码(仅1字节或4字节)

Assembly 气体汇编程序不使用2字节相对JMP位移编码(仅1字节或4字节),assembly,x86,gnu-assembler,shellcode,machine-code,Assembly,X86,Gnu Assembler,Shellcode,Machine Code,我正在尝试为不允许0x00字节(它将被解释为终止符)的CTF质询编写外壳代码。由于挑战的限制,我必须这样做: [shellcode bulk] [(0x514 - sizeof(shellcode bulk)) filler bytes] [fixed constant data to overwrite global symbols] [shellcode data] 看起来像这样 .intel_syntax noprefix .code32 shellcode: jmp sc_d

我正在尝试为不允许0x00字节(它将被解释为终止符)的CTF质询编写外壳代码。由于挑战的限制,我必须这样做:

[shellcode bulk]
[(0x514 - sizeof(shellcode bulk)) filler bytes]
[fixed constant data to overwrite global symbols]
[shellcode data]
看起来像这样

.intel_syntax noprefix
.code32

shellcode:
    jmp sc_data

shellcode_main:
    #open
    xor eax, eax
    pop ebx         //file string
    xor ecx, ecx    //flags
    xor edx, edx    //mode
    mov al, 5       //sys_OPEN
    int 0x80

    ...  // more shellcode

.org 514, 0x41     // filler bytes
.long 0xffffffff   // bss constant overwrite

sc_data:
    call shellcode_main
    .asciz "/path/to/fs/file"
如果
sc_数据
shell代码
的127字节范围内,则此功能运行良好。在这种情况下,汇编程序(GAS)将输出一个短跳转格式:

Opcode  Mnemonic
EB cb   JMP rel8
但是,由于我有一个硬限制,即大容量外壳代码和填充字节需要0x514字节,因此此相对偏移量将至少需要2个字节。这也是可行的,因为
jmp
指令有一个2字节的相对编码:

Opcode  Mnemonic
E9 cw   JMP rel16
不幸的是,GAS没有输出这种编码。而是使用4字节偏移量编码:

Opcode  Mnemonic
E9 cd   JMP rel32
这将导致两个MSB字节的零。类似于:

e9 01 02 00

我的问题是:GAS可以被迫输出
jmp
指令的2字节变量吗?
我曾尝试过多个较小的1字节
jmp
s,但GAS一直输出4字节变量。我还尝试使用
-Os
调用GCC来优化大小,但它坚持使用4字节相对偏移量编码


英特尔跳转操作码定义供参考。

jmp rel16
仅可在操作数大小为16时进行编码,这会将EIP截断为16位。(在32位和64位模式下,编码需要
66
操作数大小前缀)。如您链接的指令集参考中所述,或者,
jmp
does
EIP← 坦佩普和0000FFFFH当操作数大小为16时。这就是为什么汇编器从不使用它,除非您手动请求它1,以及为什么您不能在32位或64位代码中使用
jmp rel16
,除非在非常罕见的情况下,目标映射到虚拟地址空间2的低64kiB


避免
jmp rel32
您只需向前跳,就可以使用
call rel32
推送数据的地址,因为您希望数据始终位于长填充负载的末尾

您可以使用
push imm32/imm8/reg
mov ebx,esp
在堆栈上构造字符串。(您已经有了一个调零寄存器,您可以将其推送到终止的零字节)

如果您不想在堆栈上构造数据,而是使用作为有效负载一部分的数据,请使用位置无关的代码/相对寻址可能您的寄存器中有一个值,该值是EIP的已知偏移量,例如,如果您的攻击代码是通过
jmp esp
或其他ret-2-reg攻击到达的。在这种情况下,您可能只需要
mov-ecx,0x12345678
/
shr-ecx,16
/
lea-ebx,[esp+ecx]

或者,如果您必须使用NOP底座,并且您不知道EIP相对于任何寄存器值的确切值,您可以使用带负位移的
调用
指令获得EIP的当前值向前跳过
调用
目标,然后
调用
返回目标。
您可以将数据放在该
调用
之后。(但是在数据中避免零字节是不方便的;一旦得到指向它的指针,就可以存储一些字节。)

或者使用RIP相对LEA获取标签地址,并使用一些避免零的方法向其添加一个立即常数,以获取有效负载末尾的标签地址

  .Lbase:
      lea  rdi, [RIP + .Lbase]
      xor  ecx,ecx
      mov  cx, .Lpath - .Lbase
      add  rdi, rcx          # RDI = .Lpath address
      ...
      syscall

       ...   # more than 128 bytes
   .Lpath:
       .asciz "/foo/bar"

如果您真的需要跳转很远,而不是仅仅定位遥远的“静态”数据的独立寻址。

一连串的短距离向前跳跃会起作用

或者使用上述任何方法在寄存器中查找后续标签的地址,并使用
jmp eax


保存代码字节: 在您的情况下,保存代码大小并不能帮助您避免跳远位移,但对于其他一些人可能会:

您可以使用以下方法保存代码字节:

  • xor-eax,eax
    /
    cdq
    xor-edx,edx
    节省1个字节
  • xor ecx,ecx
    /
    mul ecx
    将三个寄存器归零为4个字节(ecx和EDX:EAX)
  • 实际上,对于
    int0x80
    设置,您的最佳选择可能是
    xor ecx,ecx
    (2B)/
    leaeax,[ecx+5]
    (3B)/
    cdq
    (1B),并且根本不要使用
    mov al,5
    。您可以使用
    push imm8
    /
    pop
    ,或使用一个
    lea
    ,如果您有另一个具有已知值的寄存器,则可以在寄存器中以仅3个字节的时间放置任意小常量

脚注1:要求汇编程序在16位模式之外编码
jmp rel16

NASM(在16、32或64位模式下)

AT&T语法:

objdump-d
将其解码为
jmpw
:对于组装成32位静态ELF二进制的上述NASM源,
objdump-drwC foo
显示EIP的截断:

0000000000400080 <addr>:
  400080:       66 e9 fc ff             jmpw   80 <addr-0x400000>
请参阅-GAS处理AT&T语法的这种疯狂的不一致性甚至适用于
jmpl
。在16位模式下组装时,普通的
jmp 0x400
将相对跳转到该绝对偏移量

在极不可能的情况下,您需要在其他模式下使用
jmprel16
,您必须自己使用
.byte
.short
组装它。我认为甚至没有办法让汇编程序为您发出它


脚注2:您不能在32/64位代码中使用
jmp rel16
,除非您正在攻击某些映射到低64kiB虚拟地址空间的代码,例如,可能是在DOSEMU或WINE下运行的代码。Linux的默认设置是65536,而不是0,因此通常情况下,即使您想加载内存,也无法
mmap
,或者可能无法加载其文本segm
  .Lbase:
      lea  rdi, [RIP + .Lbase]
      xor  ecx,ecx
      mov  cx, .Lpath - .Lbase
      add  rdi, rcx          # RDI = .Lpath address
      ...
      syscall

       ...   # more than 128 bytes
   .Lpath:
       .asciz "/foo/bar"
addr:
; times 256 db 0      ; padding to make it jump farther.
o16 jmp near addr     ; force 16-bit operand-size and near (not short) displacement
0000000000400080 <addr>:
  400080:       66 e9 fc ff             jmpw   80 <addr-0x400000>
480:   66 ff 25 00 04 00 00    jmpw   *0x400   483: R_386_32   .text