【问题标题】:Calling goto on a wide-char string in C (GCC)在 C (GCC) 中对宽字符字符串调用 goto
【发布时间】:2018-02-03 03:46:04
【问题描述】:

我找到了这段代码:

goto*&L"\xfeeb";

它导致程序永远挂起,显然是通过调用 x64 指令 0xEB0xFE(按此顺序,由于 x64 的小端序)。 0xEB 是根据 x86 Opcode and Instruction Reference 的 JMP。

我理解代码的作用,它相当于一个运行指令0xEB 0xFE的函数,所以也可以写成int (*foo)() = L"\xfeeb"; foo();,或者如果我们真的想得到混淆,((int(*)())L"\xfeeb")();。这是因为字符串在 Linux 上默认标记为可执行。

不过,goto 真的很严格。我不明白为什么goto*&L"\xfeeb"; 完全有效,或者疯狂的指针魔术*& 在做什么,或者为什么需要宽标记L。谁能解释一下?

【问题讨论】:

标签: c gcc binary goto opcode


【解决方案1】:

如果我冒险猜测,编写代码的人正在滥用GCC's Labels as Values extension。此功能旨在制作跳转表或可移植 JIT 编译器或其他 switch...case 太慢的东西。

C 让你goto 一个标签。

label1:
...
goto label1;

GCC 允许您使用&& 运算符获取标签的地址。要跳转到地址foo,您只需goto *foo;

label1:
void *ptr = &&label1;
...
goto *ptr;

回顾一下,C 标准规定goto 语句后面的参数是label 类型的标记。 GCC 添加了一个扩展,其中goto 语句后面的参数也可能是一个指向可执行代码指针的指针

因此,您可以goto 任何您有指针的内存。在 Linux 上,这包括字符串文字。

goto *&"\xe8\r\0\0\0Hello, World!Yj\1[j\rZj\4X\xcd\x80,\f\xcd\x80";

Try it online!

L"\xfeeb" 是一个宽字符串文字,由wchar_t 类型的字符组成,而不是char。写成老式的字符串文字,它将是"\xeb\xfe"。我怀疑您的字符串文字中的 L 是为了达到 MacGuffin 的目的。

【讨论】:

  • “写代码的人”ಠ_ಠ
  • gcc 扩展允许goto *foo;,其中foo 的类型为void*。由于一个错误,它似乎允许foovoid* 以外的指针类型。另见this questionmy answer
猜你喜欢
  • 2012-10-09
  • 2012-11-04
  • 1970-01-01
  • 2022-01-23
  • 2016-08-21
  • 2011-02-16
  • 2017-01-14
  • 2010-12-09
  • 1970-01-01
相关资源
最近更新 更多