【问题标题】:Shellcode in C programC程序中的Shellcode
【发布时间】:2013-05-13 16:09:39
【问题描述】:

Demystifying the Execve Shellcode 中解释了一种编写 execve shellcode 的方法:

#include<stdio.h>
#include<string.h>

unsigned char code[] = 
"\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80";

main()
{

    printf("Shellcode Length: %d\n", strlen(code));

    int (*ret)() = (int(*)())code;

    ret();
}

int (*ret)() = (int(*)())code; 行有什么作用?

【问题讨论】:

  • cdecl 说:将代码转换为指向返回 int 的函数的指针
  • 我不明白 ret 之后的 () 和 code 之前的 int()()。
  • 为了能够在头部解析这样的结构,通过顺时针/螺旋规则:c-faq.com/decl/spiral.anderson.html
  • 顺便说一句:在 W^X 操作系统上默认禁用此方法。在现代处理器上的 64 位 OS X 上运行 nop (0x90)EXC_BAD_ACCESS 因为内核不会从 .bss、.text 或堆中运行任何代码,因为这些区域引用了 o PAE/长模式页表条目位 63 设置 (NX)。它可能适用于非 PAE/非长模式操作系统,而无需像 DOS 这样古老的东西中的 PAX/ExecShield。写入代码区域也不起作用(在一堆 C 内联 asm nops 上自我变异)。最好制作一个为给定平台生成最小可执行文件并运行它的程序。

标签: c shellcode


【解决方案1】:
    (*(void(*)())shellcode)()

==

    p = (void(*)()) shellcode;
    (*p)();

【讨论】:

    【解决方案2】:

    这个函数指针部分可以改写成更简单的形式吗?

    我不知道你是否认为这更简单,但也许:

    #include <stdio.h>
    #include <string.h>
    
    unsigned char code[] = 
    "\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80";
    
    typedef int(*shellcode_t)();
    
    int main(int argc, char ** argv) {
        printf("Shellcode Length: %ld\n", strlen(code));
    
        shellcode_t ret = (shellcode_t)code;
    
        ret();
    }
    

    【讨论】:

      【解决方案3】:
        int (*ret)() = (int(*)())code;
        ~~~~~~~~~~~~   ~~~~~~~~~~~~~~
              1              2
      
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                     3
      
      1. 它将ret定义为一个指向没有参数()并返回int的函数的指针。所以,那些()表示函数的参数定义。

      2. 用于将code 转换为指向没有参数() 并返回int 的函数的指针。

      3. code 转换为函数并将其分配给ret。之后您可以拨打ret();

       

      unsigned char code[] =  "\x31\xc0\x50\x68\x6e\x2f\...
      

      它是由十六进制值表示的机器指令序列。它将作为函数注入到代码中。

      【讨论】:

      • 所以,当调用 ret() 时,代码实际上是如何“运行”的,因为我没有看到 C 调用“加载”shellcode 并运行它?
      • @user85030,是的,在ret() 中调用了“load”,google 为“指向函数的指针”
      • 您提供的link 分11 个步骤进行解释。该机器指令序列所做的一切都与调用过程所需的一样。
      • 好的。所以我阅读了函数指针并理解了第 1 部分)。第 2 部分)可以写成 (int* ()) 代码而不是 (int(*)()) 代码吗?重新表述我的问题,如何将变量转换为函数? (因为我们将左侧的函数指针分配给右侧的函数。
      • 你不能使用(int* ()),因为它不是声明函数指针的方式。想想地址,在C语言中所有的对象都有地址,它只是将code的地址转换为函数的地址。
      【解决方案4】:

      int 行声明了 ret() 函数,通过指向 code[] 数组;也就是说,函数映射到code[]二进制指令。

      \x 构造是在字符串中嵌入十六进制字符的安全方法。例如,您可以将“\x31”替换为“1”,因为“1”的字符代码是 49,或十六进制 31。

      【讨论】:

      • 我不明白 ret 之后的 () 和 code 之前的 int()()。
      • ret 是一个函数指针 (en.wikipedia.org/wiki/Function_pointer),指向具有未定义数量参数 (()) 的函数,该函数返回 int(int(*) () ) 它是根据函数指针地址强制转换 code 函数地址,该地址接受未定义数量的参数,这就是 ret 的声明方式。
      • 这个函数指针部分可以改写成更简单的形式吗?
      猜你喜欢
      • 1970-01-01
      • 2015-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多