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

简介: 【多级指针】带你从反汇编角度认识指针,C语言指针,多级指针【滴水逆向三期(36)笔记】(下)
3. *( *(p2+1)+1)反汇编
//C语言代码:
short** p2;
printf("%d",*(*(p2+1)+1));

我们还是直接来到反汇编窗口来观察:

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

大家可以从下面这张图中来理解:

该图中,蓝色为未作任何操作时二级指针示意图,较细箭头为给p2+1时的指向,加粗箭头为最终指向

我们来逐步分析对*( *(p2+1)+1)取值的过程:

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

2.将eax内存放的数据当作地址,在该地址基础上+4,取出该地址内存放的数据,放入ecx(第一次取出的数据,是一个地址,指向第一个一级指针,如图所示,将二级指针+1,实际上就是要指向本来要指向的一级指针(一级指针1)的下一个(一级指针2),由于一级指针占据4个字节,所以要在二级指针内存放的数据+4(4 * 1))

3.将ecx中的值+2,再当作一个地址,取出该地址中存放的数据,放入edx(由于一级指针2本来指向的是数据2(short类型,占据2字节),所以要在一级指针内存放的地址上+2(2 * 1))

4. *( *(p2+2)+3)

这里其实是前三个的运用,为了加深理解,我们来定义char**类型的二级指针。

//C语言代码
char** p2;
printf("%d",*(*(p2+2)+3));
//反汇编代码
mov         eax,dword ptr [ebp-4]
mov         ecx,dword ptr [eax+8]
movsx       edx,byte ptr [ecx+3]

我们继续以画内存图的方式来为大家讲解:

该图中蓝色箭头为二级指针未作任何操作时的指向,较细橙色箭头为对二级指针操作后的指向,较粗箭头为对一级指针操作后的指向。

我们来逐步分析对*( *(p2+2)+3)取值的过程

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

2.将eax中的值+8,将得到的值看作地址,取出该地址中存放的数据,放入ecx(第一次取出的地址指向一级指针,所以对二级指针+2的操作实际上是让改二级指针指向原本指向的一级地址再向后便宜两个一级指针,所以就是二级指针内存放的数据+8(4 * 2))

3.将ecx中的值+3,将得到的值看作地址,取出该地址内存取的数据,放入edx(由于ecx内存取的是一个地址(可以看作一级指针),指向char类型的数据,所以对一级指针+3的操作实际上是对一级指针内存放的数据+3(3 * 1))。

三级指针

我们先来了解一下三级指针:

//C语言代码:
char a=1;
char* p1=&a;
char** p2=&p1;
char*** p3=&p2;

这里我们定义一个char类型的变量a,定义一个char*类型的变量(一级指针)p1存放a的地址,定义一个char * *类型的变量(二级指针)存放p1的地址,再定义一个char * * *类型的变量存(三级指针)放p2的地址。

//反汇编代码:
mov         byte ptr [ebp-4],1
lea         eax,[ebp-4]
mov         dword ptr [ebp-8],eax
lea         ecx,[ebp-8]
mov         dword ptr [ebp-0Ch],ecx
lea         edx,[ebp-0Ch]
mov         dword ptr [ebp-10h],edx

根据反汇编分析:

将1存进a[ebp-4]中

将a[ebp-4]的地址存入eax,将eax存入p1[ebp-8]中————>一级指针

将p1[ebp-8]的地址存入ecx,将ecx存入p2[ebp-0ch]—————>二级指针

将p2[ebp-0ch]的地址存入edx,将edx存入p3[ebp-10h]——————>三级指针

1. 数据宽度

我们通过C语言sizeof函数可以得到三级指针所占据的数据宽度:

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

我们可以看到在程序输出框里输出:

4

所以三级指针占据4个字节存储空间,在C语言编译器中,我们有数据类型之分,但是实际在电脑内存中,内存条根本没有数据类型之分,它只负责存储数据。

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

//C语言代码:
char*** a=(char***)100;
printf("%d",a++);

我们能够观察到在程序输出窗口输出:

104

char ***内存储的是一个char **类型变量的地址,对char ***类型+1,实际上是要char ***指向原本指向数据的下一个数据,而char **类型占据4个字节,所以要在原本char ***基础上+4(4 * 1)。

反汇编代码:

//反汇编代码:
mov         dword ptr [ebp-4],64h
mov         eax,dword ptr [ebp-4]
add         eax,4

我们来分析整个过程:

定义了一个char ***类型的变量,通过强制转换类型将100转换为char ***类型。然后对该变量里存储的值+4(在内存并不认为它是地址,只是编译器和我们认为它是地址,内存只负责存储,在内存眼里所有数据都一样)。

3. 三级指针反汇编

1. *(*p3)反汇编

C语言代码:

char*** p3;
printf("%d",*(*p3));

我们知道在带 *的数据类型前面加 *得到的数据类型就是原本的类型去掉一个 *,所以我们这里取到了一级指针,并没有取到一级指针所指的空间里所存储的数据。

反汇编代码:

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

我们来逐步分析对*(*p3)取值的过程:

1.取出变量pa[ebp-4]内存储的数据,放入eax

2.将eax中的数据当作地址,取出该地址内存储的数据,放入ecx

3.将ecx中的数据当作地址,取出该地址中存储的数据,放入edx

2. *( *(*p3))反汇编

C语言代码:

char*** p3;
printf("%d",*(*(*p3)));

反汇编代码:

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

我们来逐步分析对*( *(*p3))取值的过程:

1.取出p3[ebp-4]中的数据,放入寄存器eax

2.将寄存器eax中存储的数据当作地址,取出该地址中存储的数据,放入寄存器ecx

3.将寄存器ecx中存储的数据当作地址,取出该地址中存储的数据,放入寄存器edx

4.将寄存器edx中存储的数据当作地址,取出该地址中存储的数据,放入寄存器eax

3. *( *( *( *p3+1)+2)+3)反汇编

C语言代码:

char*** p3;
printf("%d",*(*(*(p3+1)+2)+3));

反汇编代码:

mov         eax,dword ptr [ebp-4]
mov         ecx,dword ptr [eax+4]
mov         edx,dword ptr [ecx+8]
movsx       eax,byte ptr [edx+3]

我们来逐步分析对 *( *( *(p3+1)+2)+3)取值的过程:

由于此过程有点繁琐,我才用画内存图的方法带大家了解:

图中,蓝色箭头为未作任何操作时,三级指针的分别指向,较细橙色箭头为+1操作后三级指针指向的变化,较粗橙色箭头为+2操作后二级指针指向变化,绿色箭头为+3操作后一级指针指向的不安话

1.取出p3[ebp-4]中的数据,放入寄存器eax

2.将eax中存放的数据+4后当作地址,取出该地址中存放的数据,放入寄存器ecx(因为给变量p3本身+1,就是要三级指针指向原本指向的下一个数据,而三级指针指向的是二级指针类型,占据4个字节,所以给三级指针+1的操作事实上是给三级指针内存放的数据+4(4 * 1)

3.将寄存器ecx中的值+8后当作地址,取出该地址中存放的数据,放入寄存器edx(给二级指针+2的操作,就是要二级指针指向原本指向数据向再后偏移2个数据,所以事实上就是给二级指针内存放的数据+8(4 * 2)

4.将寄存器edx中存放的值+3后当作地址,取出该地址中存放的数据,放入寄存器eax(给一级指针+3的操作,就是要让指针指向原本指向数据再向后偏移三个数据,而此一级指针指向的数据为char类型,所以给该一级指针+3的操作,事实上是给该一级指针内存放的数据+3(1 * 3)

4. p3[1][2][3]反汇编

C语言代码:

char*** p3;
printf("%d",p3[1][2][3]);

反汇编代码:

mov         eax,dword ptr [ebp-4]
mov         ecx,dword ptr [eax+4]
mov         edx,dword ptr [ecx+8]
movsx       eax,byte ptr [edx+3]

我们来与*( *( *(p3+1)+2)+3的反汇编代码做个比较,发现它俩的反汇编代码竟惊人地相同!

在讲二级指针时我们已经讲过这个知识点,我们在这里就不再啰嗦了。

直接给出结论:

*(*(*(*(*(p+m) +n) +i) +j) +k)与p[m][n][i][j][k]可以互换

OK今天我们就学习到这里,当然希望大家可以指出此篇笔记的不足或者错误之处,当然希望我们能够共同学习,共同进步!!!

相关文章
|
2月前
|
C语言
【c语言】指针就该这么学(1)
本文详细介绍了C语言中的指针概念及其基本操作。首先通过生活中的例子解释了指针的概念,即内存地址。接着,文章逐步讲解了指针变量的定义、取地址操作符`&`、解引用操作符`*`、指针变量的大小以及不同类型的指针变量的意义。此外,还介绍了`const`修饰符在指针中的应用,指针的运算(包括指针加减整数、指针相减和指针的大小比较),以及野指针的概念和如何规避野指针。最后,通过具体的代码示例帮助读者更好地理解和掌握指针的使用方法。
54 0
|
18天前
|
存储 NoSQL 编译器
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
指针是一个变量,它存储另一个变量的内存地址。换句话说,指针“指向”存储在内存中的某个数据。
71 3
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
|
18天前
|
存储 编译器 C语言
【C语言】指针大小知多少 ?一场探寻C语言深处的冒险 !
在C语言中,指针的大小(即指针变量占用的内存大小)是由计算机的体系结构(例如32位还是64位)和编译器决定的。
44 9
|
18天前
|
安全 程序员 C语言
【C语言】指针的爱恨纠葛:常量指针vs指向常量的指针
在C语言中,“常量指针”和“指向常量的指针”是两个重要的指针概念。它们在控制指针的行为和数据的可修改性方面发挥着关键作用。理解这两个概念有助于编写更安全、有效的代码。本文将深入探讨这两个概念,包括定义、语法、实际应用、复杂示例、最佳实践以及常见问题。
40 7
|
28天前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
100 13
|
21天前
|
存储 程序员 编译器
C 语言数组与指针的深度剖析与应用
在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
|
22天前
|
算法 C语言
C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项
本文深入讲解了C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项,通过实例演示了文件操作的基本流程,帮助读者掌握这一重要技能,提升程序开发能力。
67 3
|
22天前
|
存储 算法 程序员
C 语言指针详解 —— 内存操控的魔法棒
《C 语言指针详解》深入浅出地讲解了指针的概念、使用方法及其在内存操作中的重要作用,被誉为程序员手中的“内存操控魔法棒”。本书适合C语言初学者及希望深化理解指针机制的开发者阅读。
|
28天前
|
存储 C语言 开发者
C 语言指针与内存管理
C语言中的指针与内存管理是编程的核心概念。指针用于存储变量的内存地址,实现数据的间接访问和操作;内存管理涉及动态分配(如malloc、free函数)和释放内存,确保程序高效运行并避免内存泄漏。掌握这两者对于编写高质量的C语言程序至关重要。
52 11
|
22天前
|
程序员 C语言
C语言中的指针既强大又具挑战性,它像一把钥匙,开启程序世界的隐秘之门
C语言中的指针既强大又具挑战性,它像一把钥匙,开启程序世界的隐秘之门。本文深入探讨了指针的基本概念、声明方式、动态内存分配、函数参数传递、指针运算及与数组和函数的关系,强调了正确使用指针的重要性,并鼓励读者通过实践掌握这一关键技能。
34 1