【多级指针】带你从反汇编角度认识指针,C语言指针,多级指针【滴水逆向三期(36)笔记】(上)

简介: 【多级指针】带你从反汇编角度认识指针,C语言指针,多级指针【滴水逆向三期(36)笔记】

数据宽度

我们先来看看C语言中不同数据类型是如何存储的:

C语言代码:

char a=100;
short b=100;
int c=100;

我们在正向学习中知道一个char类型占据一个字节,一个short类型占据两个字节,一个int类型占据四个字节;

接下来我们在visual C++ 中观察反汇编,看看他们到底占据几个字节

我们知道在调用一个空函数的时候visual c++为我们默认分配0x40个字节。

反汇编代码:

push        ebp
mov         ebp,esp
sub         esp,4Ch
push        ebx
push        esi
push        edi
lea         edi,[ebp-4Ch]
mov         ecx,13h
mov         eax,0CCCCCCCCh
rep stos    dword ptr [edi]

我们看到编译器为我们分配了0x4c个字节。所以不管是char,short,int类型,编译器为我们分配内存时都是分配4个字节,并不会节省空间,只是在使用时使用只使用1个字节,2个字节或者是4个字节。

在学习多级指针之前带大家看一看一级指针:

一级指针

C语言代码:

int a=10;
int* p;
p=&a;

我们来到反汇编观察:

反汇编代码:

mov         dword ptr [ebp-4],0Ah
lea         eax,[ebp-4]
mov         dword ptr [ebp-8],eax

我们可以观察到一级指针是把一个变量(可以是C语言的各种数据类型,也可以是一个数组的首地址,甚至通过强制转换类型我们可以存储一个整数)的地址存储到一个指针变量中。在计算机中其实并不知道他存储的是什么类型,计算机内存只负责存储,只是C语言规定我们要存储地址。

1. 数据宽度

我们通过C语言sizeof函数来看看指针类型的数据宽度。

C语言代码:

int* a;
printf("%d",sizeof(a));

通过程序输出我们能够知道指针类型占据4个字节空间。

2. 指针++,–,加或减一个整数运算

在这里我们通过数组可以更好地观察指针的运算。

C语言代码:

int number[6]={1,2,3,4,5,6};
int* p=number;

我们来观察反汇编代码:

反汇编代码:

mov         dword ptr [ebp-18h],1
mov         dword ptr [ebp-14h],2
mov         dword ptr [ebp-10h],3
mov         dword ptr [ebp-0Ch],4
mov         dword ptr [ebp-8],5
mov         dword ptr [ebp-4],6

在内存中数组的存储形式是这样的:

数据 1 2 3 4 5 6
地址 ebp-18h ebp-14h ebp-10h ebp-0ch ebp-8h ebp-4h

这是一个int类型的数组,所以每个地址之间相差4个字节。

接下来我们来看看对指针的++操作:

C语言代码:

printf("%x\n",p);
printf("%d\n",*p);
printf("%d\n",*(p+1));

我们可以观察到程序输出:

19ff1c              //该行输出的是该数组的首地址,这个地址在每个计算机可能不同
  1                   //该行输出指针p所指的地址内的数据
  2                   //我们对指针进行了+1的操作,p+1指向了数组的下一个地址

在这里实际上p+1看似指向了数组的下一个地址,其实这里是在数组的首地址上加了4才指向下一个数据,我们来观察反汇编:

反汇编代码:

mov         ecx,dword ptr [ebp-1Ch]
mov         edx,dword ptr [ecx+4]

这里首先取出了在p里存储的地址,存储到寄存器ecx中,然后该地址+4,则指向下一个数据。那么在这里我们该怎么当指针加1时,寄存器内地址到底加了多少呢,按照老师讲的方法:我们去掉一个*,* p为int * 类型,去掉一个 * 就是int类型,那么地址就应该加4。我们想想实质是什么呢,在p指向的地址内存储的数据为int类型,那么该地址+4才指向下一个数据,所以应该在该地址的基础上+4指向下一个数据。

同理,如果是char类型或者是short类型的数组,那么当指向该数组的指针+1时,该指针指向的地址+1或者+2才指向下一个数据。

由此我们可以得到当指针+n(一个整数)时,该指针指向的地址应该+(n*该指针指向的地址存储的数据类型所占据的宽度)。

3. 同类型指针做加减法

同类型的指针是可以做加减运算的,我们来看看:

C语言代码:

int* p1=(int*)100;
int* p2=(int*)200;//这里我们通过强制转换类型将100和200分别存入指针p1和p2中,站在编译器的角度,100和200都是地址
printf("%d",p1-p2);

在程序输出窗口我们可以看到输出:

25

那么这个25到底是怎么计算出来的呢,根据老师讲的,这里输出的实际上是100/4。

p1和p2都是int类型,那么在p1和p2所指的地址内存储的数据应该是int类型,就是占据4个字节,指针p1与p2相减,实际上是输出该段地址内一共能存储多少个同类型(指针为int,则为int类型,如果指针为char*类型,则为char类型)的数据。

在这里我们载介绍指针加(减)一个整数的另一种写法:

//C语言代码
int number[6]={1,2,3,4,5,6};
int* p=number;
printf("%d\n",*p);
printf("%d\n",*(p+1));
printf("%d\n",p[1]);

我们可以观察到程序输出框里输出:

1
2
2

我们可以看到*(p+1)和p[1]输出完全相同的值,我们继续查看反汇编:

反汇编代码:
mov         eax,dword ptr [ebp-1Ch]
mov         ecx,dword ptr [eax+4]
push        ecx
p[1]的反汇编代码:
mov         edx,dword ptr [ebp-1Ch]
mov         eax,dword ptr [edx+4]
push        eax

我们能够清楚的看到 * (p+1)和p[1]的反汇编代码完全相同,则p[1]可以代替*(p+1)。

二级指针

为了大家更好地理解,我们二级指针使用short类型的数组。

//C语言代码
short number[5]={1,2,3,4,5};
short* p1=number;
short** p2=&p1;

我们来到反汇编观察:

mov         word ptr [ebp-0Ch],offset main+1Ch (0040d41c)
mov         word ptr [ebp-0Ah],offset main+22h (0040d422)
mov         word ptr [ebp-8],offset main+28h (0040d428)
mov         word ptr [ebp-6],offset main+2Eh (0040d42e)
mov         word ptr [ebp-4],offset main+34h (0040d434)
lea         eax,[ebp-0Ch]
mov         dword ptr [ebp-10h],eax
lea         ecx,[ebp-10h]
mov         dword ptr [ebp-14h],ecx
1 2 3 4 5
ebp-1Ch ebp-0Ah ebp-8 ebp-6 ebp-4

由于是short类型数组,我们可以观察到每个数据之间地址相差2。

通过反汇编我们可以观察到:

指针p1里存的是该数组的首地址,p2里存的是p1的地址,这里p2我们成为二级指针。

1. 数据宽度

通过C语言的sizeof函数我们来看看二级指针的数据宽度:

//C语言代码:
short number[5]={1,2,3,4,5};
short* p1=number;
short** p2=&p1;
printf("%d",sizeof(p2));

在程序输出窗口我们可以看到输出:

4

不管是几级指针,它里面存储的都是地址,所以指针本身都占据4个字节。

2. 二级指针++,–,加或减一个整数运算

C语言代码:

short** p=(short**)100;
printf("%d\n",p);
printf("%d\n",p+1);

在这里我们通过强制类型转换把100转换成short**类型存储到二级指针p中。

在程序输出窗口我们可以看到输出:

//程序输出窗口
  100
  104

我们再来到反汇编看一看:

mov         ecx,dword ptr [ebp-4]
 add         ecx,4
 push        ecx

在这里我们看到二级指针+1是在该二级指针指向的地址基础上再加4。看到这里大家可能还是不太明白,接下来带大家到反汇编一探究竟:

3. 二级指针反汇编

1. *(*p2)反汇编:
//C语言代码
short** p2;
printf("%d",*(*p2));

在使用指针时,在变量前面加一个 * 就相当于数据本身减掉一个 * ,比如这里的*(*p2):

我们定义的p2为short**类型, * p2就是short * 类型,在 *short前再加一个 *,就是 *(*p2),为short类型。我们来观察反汇编:

mov         eax,dword ptr [ebp-4]
mov         ecx,dword ptr [eax]
movsx       edx,word ptr [ecx]

我们来看看在反汇编里对 *( *p2 )取值的过程:

1.取出指针变量p2里存的地址,放入eax

2.把eax里存的数据当作地址,取出该地址里存的数据放入ecx

3.把ecx里存的数据当地址,取出该地址内存放的数据放入edx

接下来我们可以在自己编译器里看到是push edx(将edx压入栈),接下来就是调用printf函数的过程了,在这里我们不再做介绍。

2. *( *(p2+1))反汇编:

C语言代码:

short** p2;
printf("%d",*(*(p2+1)));
• 1
• 2

我们直接从反汇编角度来分析对*(*(p2+1))取值的过程:

//反汇编代码:
mov         eax,dword ptr [ebp-4]
mov         ecx,dword ptr [eax+4]
movsx       edx,word ptr [ecx]

大家可以从下面贴出来的图片中加强理解,蓝色为对二级指针未作任何操作,橙色为*( *(p2+1))

1.取出指针变量p2中存放的数据放入eax

2.将取出的数据+4,将得到的值看作地址,将该地址中的数据放入ecx(二级指针本来指向第一个一级指针,因为二级指针内存放的还是地址,所以对二级指针+1实质上还是在内存上+4(4 *1)个字节,指向第二个一级指针)

3.将ecx中的数据当作地址,取出该地址中存放的数据,放入edx(二级指针内存放的数据+4(4 * 1),指向第二个一级指针,第二个一级指针指向第二个数据)

相关文章
|
22天前
|
C语言
【c语言】指针就该这么学(1)
本文详细介绍了C语言中的指针概念及其基本操作。首先通过生活中的例子解释了指针的概念,即内存地址。接着,文章逐步讲解了指针变量的定义、取地址操作符`&`、解引用操作符`*`、指针变量的大小以及不同类型的指针变量的意义。此外,还介绍了`const`修饰符在指针中的应用,指针的运算(包括指针加减整数、指针相减和指针的大小比较),以及野指针的概念和如何规避野指针。最后,通过具体的代码示例帮助读者更好地理解和掌握指针的使用方法。
44 0
|
21天前
|
C语言
【c语言】指针就该这么学(3)
本文介绍了C语言中的函数指针、typedef关键字及函数指针数组的概念与应用。首先讲解了函数指针的创建与使用,接着通过typedef简化复杂类型定义,最后探讨了函数指针数组及其在转移表中的应用,通过实例展示了如何利用这些特性实现更简洁高效的代码。
15 2
|
22天前
|
C语言
如何避免 C 语言中的野指针问题?
在C语言中,野指针是指向未知内存地址的指针,可能引发程序崩溃或数据损坏。避免野指针的方法包括:初始化指针为NULL、使用完毕后将指针置为NULL、检查指针是否为空以及合理管理动态分配的内存。
|
22天前
|
C语言
C语言:哪些情况下会出现野指针
C语言中,野指针是指指向未知地址的指针,通常由以下情况产生:1) 指针被声明但未初始化;2) 指针指向的内存已被释放或重新分配;3) 指针指向局部变量,而该变量已超出作用域。使用野指针可能导致程序崩溃或不可预测的行为。
|
28天前
|
存储 C语言
C语言32位或64位平台下指针的大小
在32位平台上,C语言中指针的大小通常为4字节;而在64位平台上,指针的大小通常为8字节。这反映了不同平台对内存地址空间的不同处理方式。
|
28天前
|
存储 算法 C语言
C语言:什么是指针数组,它有什么用
指针数组是C语言中一种特殊的数据结构,每个元素都是一个指针。它用于存储多个内存地址,方便对多个变量或数组进行操作,常用于字符串处理、动态内存分配等场景。
|
28天前
|
存储 C语言
C语言指针与指针变量的区别指针
指针是C语言中的重要概念,用于存储内存地址。指针变量是一种特殊的变量,用于存放其他变量的内存地址,通过指针可以间接访问和修改该变量的值。指针与指针变量的主要区别在于:指针是一个泛指的概念,而指针变量是具体的实现形式。
|
29天前
|
C语言
C语言指针(3)
C语言指针(3)
11 1
|
29天前
|
C语言
C语言指针(2)
C语言指针(2)
13 1
|
1月前
|
存储 搜索推荐 C语言
深入C语言指针,使代码更加灵活(二)
深入C语言指针,使代码更加灵活(二)