【多级指针】带你从反汇编角度认识指针,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),指向第二个一级指针,第二个一级指针指向第二个数据)

相关文章
|
1月前
|
存储 编译器 C语言
【C语言】【指针1】指针难?看这个就够了!
【C语言】【指针1】指针难?看这个就够了!
|
16天前
|
存储 C语言
【C语言基础】一篇文章搞懂指针的基本使用
本文介绍了指针的概念及其在编程中的应用。指针本质上是内存地址,通过指针变量存储并间接访问内存中的值。定义指针变量的基本格式为 `基类型 *指针变量名`。取地址操作符`&`用于获取变量地址,取值操作符`*`用于获取地址对应的数据。指针的应用场景包括传递变量地址以实现在函数间修改值,以及通过对指针进行偏移来访问数组元素等。此外,还介绍了如何使用`malloc`动态申请堆内存,并需手动释放。
|
19天前
|
存储 人工智能 C语言
C语言程序设计核心详解 第八章 指针超详细讲解_指针变量_二维数组指针_指向字符串指针
本文详细讲解了C语言中的指针,包括指针变量的定义与引用、指向数组及字符串的指针变量等。首先介绍了指针变量的基本概念和定义格式,随后通过多个示例展示了如何使用指针变量来操作普通变量、数组和字符串。文章还深入探讨了指向函数的指针变量以及指针数组的概念,并解释了空指针的意义和使用场景。通过丰富的代码示例和图形化展示,帮助读者更好地理解和掌握C语言中的指针知识。
|
1月前
|
C语言
C语言------指针
这篇文章是关于C语言中指针的实训,通过示例代码展示了指针的基本概念、定义、赋值、使用和传递,以及指针运算和指针在函数参数中的应用,如交换两个变量的值和找出两个数中的较小值。
C语言------指针
|
24天前
|
存储 安全 C语言
C语言 二级指针应用场景
本文介绍了二级指针在 C 语言中的应用,
|
1月前
|
存储 编译器 C语言
【C语言篇】深入理解指针2
代码 const char* pstr = "hello world."; 特别容易让初学者以为是把字符串 hello world.放 到字符指针 pstr ⾥了,但是本质是把字符串 hello world. 首字符的地址放到了pstr中。
|
1月前
|
存储 程序员 编译器
【C语言篇】深入理解指针1
assert.h 头⽂件定义了宏 assert() ,⽤于在运⾏时确保程序符合指定条件,如果不符合,就报错终⽌运⾏。这个宏常常被称为“断⾔”。
|
1月前
|
存储 搜索推荐 C语言
C语言中的指针函数:深入探索与应用
C语言中的指针函数:深入探索与应用
|
1月前
|
存储 编译器 C语言
【C语言】指针练习题目
【C语言】指针练习题目
|
1月前
|
C语言 Python
C语言指针(2)
C语言指针(2)
25 5