帮我理解这个C代码(*(void(*)())scode)()

时间:2009-09-24 02:55:16

标签: c

来源:http://milw0rm.org/papers/145

#include <stdio.h>
#include <stdlib.h>

int main()
{
 char scode[]="\x31\xc0\xb0\x01\x31\xdb\xcd\x80";
 (*(void(*) ()) scode) ();
}

本文是关于Linux平台上的shellcode的教程,但它没有解释以下语句“(*(void(*) ()) scode) ();”的工作原理。我正在使用“The C Language Programming Reference,2 by Brian.W.Kernighan,Dennis.M.Ritchie”来查找答案,但没有找到答案。可能有人可以指向正确的方向,也许是一个网站,另一个C参考书,在那里我可以找到答案。

8 个答案:

答案 0 :(得分:14)

它在scode中的机器代码(编译的汇编指令)然后它转换为可调用的void函数指针并调用它。 GMan展示了一种等效,更清晰的方法:

typedef void(*void_function)(void);
int main()
{
  char scode[]="\x31\xc0\xb0\x01\x31\xdb\xcd\x80";
  void_function f = (void_function)scode;
  f(); //or (*f)();
}

scode包含x86机器码,可以反汇编(感谢Michael Berg

31 c0        xor    %eax,%eax
b0 01        mov    $0x1,%al
31 db        xor    %ebx,%ebx
cd 80        int    $0x80

这是Linux中系统调用的代码(中断0x80)。根据{{​​3}},这是使用参数0(sys_exit())调用eax=1系统调用(ebx)。这会导致进程立即退出,就好像它调用了system call table

_exit(0)指出,这最常用于调用Jonathan Leffler,“用于利用软件漏洞的有效载荷的一小段代码。”因此,现代操作系统采取措施来防止这种情况。

如果堆栈不可执行,则此代码将失败。 shell代码被加载到堆栈中的局部变量中,然后我们跳转到该位置。如果堆栈是不可执行的,那么一旦CPU尝试执行代码就会发生某种CPU故障,并且控制将转移到内核的中断处理程序中。然后内核将以异常方式终止进程。堆栈可能不可执行的一种情况是,如果您在支持shellcode的CPU上运行,并且您在页表中设置了NX(不可执行)位。

某些CPU上可能还存在指令缓存问题 - 如果指令缓存尚未刷新,则CPU可能会读取陈旧数据(而不是我们显式加载到堆栈中的shell代码)并开始执行随机指令。

答案 1 :(得分:7)

在C:

(some_type) some_var

将some_var转换为some_type类型。

在您的代码示例中,“void(*)()”是some_type,是函数指针的签名,它不带任何参数并且不返回任何内容。 “(void(*)())scode”casts scode是一个函数指针。 “(*(void(*)())scode)”取消引用该函数指针。 final()调用scode中定义的函数。

scode中的字节反汇编到以下i386程序集:

   31 c0        xor    %eax,%eax
   b0 01        mov    $0x1,%al
   31 db        xor    %ebx,%ebx
   cd 80        int    $0x80

答案 2 :(得分:6)

这段代码的作用是分配一些机器代码(scode中的字节),然后将该代码的地址转换为void function ()类型的函数指针,然后调用它。

在C / C ++中,表达了该函数的类型定义:

typedef void (* basicFunctionPtr) (void);

答案 3 :(得分:5)

typedef有助于:

// function that takes and returns nothing
typedef void(*generic_function)(void);

// cast to function
generic_function f = (generic_function)scode;

// call
(*f)();

// same thing written differently:
// call
f();

答案 4 :(得分:3)

scode是一个地址。 (void(*)())scode强制转换为返回void且不接受任何参数的函数。前导* 调用函数指针,尾随()表示没有赋予函数参数。

答案 5 :(得分:2)

要了解有关shell编码技术的更多信息,请查看本书:

The Shellcoder's Handbook, 2nd Edn

还有其他几本类似的书 - 我认为这是最好的,但可以说服其他。您还可以通过Google和“shellcoder's handbook”找到大量相关资源(或者毫无疑问是您选择的搜索引擎)。

答案 6 :(得分:1)

字符数组包含可执行代码,而强制转换是一个函数转换。

(*(void(*) ())表示“强制转换为产生void的函数指针,即什么都没有。名称后的()是函数调用运算符。

答案 7 :(得分:1)

以scode编码的字符是某些已编译汇编代码的char / byte表示。您发布的代码采用该程序集,为简单起见,编码为字符,然后将该字符串作为函数调用。

该程序集似乎转化为:

xor %eax,
%eax mov $0x1,
%al xor %ebx,
%ebx int $0x80

是的,这确实会在Linux中创建一个shell。