关于C指针的各种用法的具体值分析

| categories c/c++  | tags c/c++ 

在学习堆漏洞方面的知识时,会遇到各种指针,用于修改内存中的值,一直很混淆,因此在此进行了一个小实验,对C语言中指针的各种用法,具体值如何,做了一个比较详尽的实验。虽然花费了很长时间,但是很好地提高了对指针的理解。

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define malloc_size 0x80

uint64_t *chunk0_ptr;
uint64_t *chunk1_ptr;

int main(){
    chunk0_ptr = (uint64_t*)malloc(malloc_size);//chunk a
    chunk1_ptr = (uint64_t*)malloc(malloc_size);//chunk b


    printf("&chunk0_ptr = %p\n", &chunk0_ptr);
    printf("&chunk1_ptr = %p\n", &chunk1_ptr);
    printf("结论: &p 为 p 在bss段(全局变量在bss段,局部变量在栈上) 的存储地址,且指针长度为4bytes\n");
    printf("chunk0_ptr = %p\n", chunk0_ptr);
    printf("chunk1_ptr = %p\n", chunk1_ptr);
    printf("结论: p 为 p 所指向的结构体 在堆上 的地址,且成员长度为8bytes\n");

    printf("Before *chunk0_ptr = 0x50\n");
    printf("*chunk_ptr = %p\n", *chunk0_ptr);
    printf("*chunk_ptr = %x\n", *chunk0_ptr);
    *chunk0_ptr = 0x50;
    printf("After *chunk0_ptr = 0x50\n");
    printf("*chunk_ptr = %p\n", *chunk0_ptr);
    printf("*chunk_ptr = %x\n", *chunk0_ptr);

    printf("结论: *p 用%%p 和 %%x输出均为所指向内容的值\n");

    printf("chunk0_ptr = %p\n", chunk0_ptr);
    printf("chunk0_ptr + 1 =%p\n", chunk0_ptr+1);
    printf("sizeof(uint64_t) = %p\n", sizeof(uint64_t));
    printf("chunk0_ptr + sizeof(uint64_t) = %p\n", chunk0_ptr+sizeof(uint64_t));
    printf("&chunk0_ptr + sizeof(uint64_t) = %p\n", &chunk0_ptr+sizeof(uint64_t));
    printf("结论: p+1 根据p这个指针的字节长度算,比如p指针长度8bytes,那么p+1就会根据p指向的堆地址+8\n");

    chunk0_ptr[1] = 0x10;
    printf("chunk0_ptr[1] = %p\n", chunk0_ptr[1]);
    printf("&chunk0_ptr[1] = %p\n", &chunk0_ptr[1]);
    printf("*(chunk0_ptr+1) = %p\n", *(chunk0_ptr+1));
    printf("结论: chunk0_ptr[1]指向堆结构的成员的值,且p[1] = *(p+1)\n");

    printf("&chunk0_ptr = %p\n", &chunk0_ptr);
    printf("(uint64_t)&chunk0_ptr = %p\n", (uint64_t)&chunk0_ptr);
    printf("&chunk0_ptr-sizeof(uint64_t) = %p\n", &chunk0_ptr-(sizeof(uint64_t)));
    printf("(uint64_t) &chunk0_ptr-(sizeof(uint64_t)) = %p\n", (uint64_t) &chunk0_ptr-(sizeof(uint64_t)) );
    printf("(uint64_t)( &chunk0_ptr-(sizeof(uint64_t)) )= %p\n", (uint64_t)( &chunk0_ptr-(sizeof(uint64_t)) ));
    printf("结论: 指针前加(uint64_t)会变为整数,进行整数运算,否则会根据指针自身长度进行加减\n");

    printf("chunk0_ptr = %p\n", chunk0_ptr);
    printf("chunk0_ptr[0] = %p\n", chunk0_ptr[0]);
    printf("chunk0_ptr[1] = %p\n", chunk0_ptr[1]);
    printf("(void*)chunk0_ptr[1] = %p\n", (void*)chunk0_ptr[1]);
    printf("(void*)chunk0_ptr[1] + sizeof(uint64_t)= %p\n", (void*)chunk0_ptr[1]+sizeof(uint64_t));
    printf("结论: chunk0_ptr[1]实际上是整数,*pvoid+8结果是其增大了8\n");

    printf("(void*)chunk0_ptr = %p\n", (void*)chunk0_ptr);
    printf("(void*)chunk0_ptr + 1 = %p\n", (void*)chunk0_ptr+1);
    printf("(char*)chunk0_ptr + 1 = %p\n", (char*)chunk0_ptr+1);
    printf("(void*)(chunk0_ptr + 1)= %p\n", (void*)(chunk0_ptr+1));
    printf("(char*)(chunk0_ptr + 1)= %p\n", (char*)(chunk0_ptr+1));
    printf("sizeof(void*) = %p\n", sizeof(void*));
    printf("sizeof(char*) = %p\n", sizeof(char*));
    printf("结论: GNU标准认定void*和char*一样,*pvoid++的结果是其增大了1\n");

    printf("(uint64_t*)chunk0_ptr = %p\n", (uint64_t*)chunk0_ptr);
    printf("(uint64_t*)chunk0_ptr + 1= %p\n", (uint64_t*)chunk0_ptr+1);
    printf("(uint64_t*)(chunk0_ptr + 1)= %p\n", (uint64_t*)(chunk0_ptr+1));
    printf("sizeof(uint64_t*) = %p\n", sizeof(uint64_t*));
    printf("结论: 这里依旧是符合之前实验的结果,不再做分析\n");


    printf("chunk0_ptr = %p\n", chunk0_ptr);
    printf("++chunk0_ptr = %p\n", ++chunk0_ptr);
    printf("chunk0_ptr = %p\n", chunk0_ptr);
    printf("chunk0_ptr + 1 = %p\n", chunk0_ptr + 1);
    printf("结论: ++p 和 p+=1 均是加上指针的size\n");
}

示例输出:我这里的编译命令是gcc point.c -o point -m32

&chunk0_ptr = 0x804b030
&chunk1_ptr = 0x804b02c
结论: &p 为 p 在bss段(全局变量在bss段,局部变量在栈上) 的存储地址,且指针长度为4bytes
chunk0_ptr = 0x8b40008
chunk1_ptr = 0x8b40090
结论: p 为 p 所指向的结构体 在堆上 的地址,且成员长度为8bytes
Before *chunk0_ptr = 0x50
*chunk_ptr = (nil)
*chunk_ptr = 0
After *chunk0_ptr = 0x50
*chunk_ptr = 0x50
*chunk_ptr = 50
结论: *p 用%p 和 %x输出均为所指向内容的值
chunk0_ptr = 0x8b40008
chunk0_ptr + 1 =0x8b40010
sizeof(uint64_t) = 0x8
chunk0_ptr + sizeof(uint64_t) = 0x8b40048
&chunk0_ptr + sizeof(uint64_t) = 0x804b050
结论: p+1 根据p这个指针的字节长度算,比如p指针长度8bytes,那么p+1就会根据p指向的堆地址+8
chunk0_ptr[1] = 0x10
&chunk0_ptr[1] = 0x8b40010
*(chunk0_ptr+1) = 0x10
结论: chunk0_ptr[1]指向堆结构的成员的值,且p[1] = *(p+1)
&chunk0_ptr = 0x804b030
(uint64_t)&chunk0_ptr = 0x804b030
&chunk0_ptr-sizeof(uint64_t) = 0x804b010
(uint64_t) &chunk0_ptr-(sizeof(uint64_t)) = 0x804b028
(uint64_t)( &chunk0_ptr-(sizeof(uint64_t)) )= 0x804b010
结论: 指针前加(uint64_t)会变为整数,进行整数运算,否则会根据指针自身长度进行加减
chunk0_ptr = 0x8b40008
chunk0_ptr[0] = 0x50
chunk0_ptr[1] = 0x10
(void*)chunk0_ptr[1] = 0x10
(void*)chunk0_ptr[1] + sizeof(uint64_t)= 0x18
结论: chunk0_ptr[1]实际上是整数,*pvoid+8结果是其增大了8
(void*)chunk0_ptr = 0x8b40008
(void*)chunk0_ptr + 1 = 0x8b40009
(char*)chunk0_ptr + 1 = 0x8b40009
(void*)(chunk0_ptr + 1)= 0x8b40010
(char*)(chunk0_ptr + 1)= 0x8b40010
sizeof(void*) = 0x4
sizeof(char*) = 0x4
结论: GNU标准认定void*和char*一样,*pvoid++的结果是其增大了1
(uint64_t*)chunk0_ptr = 0x8b40008
(uint64_t*)chunk0_ptr + 1= 0x8b40010
(uint64_t*)(chunk0_ptr + 1)= 0x8b40010
sizeof(uint64_t*) = 0x4
结论: 这里依旧是符合之前实验的结果,不再做分析
chunk0_ptr = 0x8b40008
++chunk0_ptr = 0x8b40010
chunk0_ptr = 0x8b40010
chunk0_ptr + 1 = 0x8b40018
结论: ++p 和 p+=1 均是加上指针的size

Previous     Next