Windows逆向安全(一)之基础知识(十五)

指针二

先前介绍了指针的一些基本的知识,但都没有提到地址的概念,下面承接之前的笔记,继续学习指针

下面要介绍三个相关的内容:获取变量的数据类型 、 取变量地址和取地址中存储的数据

获取变量的数据类型

在C语言中可以使用下面的方法获取一个变量的数据类型:

代码

#include "stdafx.h"
#include <typeinfo>
void function(){                
        char**** a;
        printf("%s\n",typeid(a).name());
}
int main(int argc, char* argv[])
{
        function();
        return 0;
}

运行结果

在这里插入图片描述

使用方式

通过上面的例子可以知道使用方式首先要包含一个相关的头文件typeinfo

然后使用该头文件的方法typeid(变量).name()即可获得变量对应的数据类型

取变量地址

在C语言中可以在变量前加上&符号来获取一个变量的地址

首先看看取回来地址的类型

取地址的返回类型

#include "stdafx.h"
#include <typeinfo>
void function(){                
        char a;
        short b;
        int c;
        char* d;
        printf("%s\n",typeid(&a).name());
        printf("%s\n",typeid(&b).name());        
        printf("%s\n",typeid(&c).name());
        printf("%s\n",typeid(&d).name());
}

int main(int argc, char* argv[])
{
        function();
        return 0;
}

运行结果

在这里插入图片描述
分析结果

不难发现,所有取地址返回的类型都为原本变量的类型后加个*,也契合了本笔记的主题——指针

取地址的内容

通过前面的分析得出了取出的地址类型是一个指针类型,现在要观察其存储的内容

代码

#include "stdafx.h"
#include <typeinfo>
//为了方便观察地址 先声明为全局变量
int a;
void function(){
    a=610;
        int* b=&a;
    printf("%x\n",b);
}

int main(int argc, char* argv[])
{
        function();
        return 0;
}

运行结果

在这里插入图片描述
反汇编代码

11:       a=610;
00401038   mov         dword ptr [a (00427c48)],262h
12:       int* b=&a;
00401042   mov         dword ptr [ebp-4],offset a (00427c48)
13:       printf("%x\n",b);

通过a的赋值语句可以看到a存储在00427c48这个内存地址中

11:       a=610;
00401038   mov         dword ptr [a (00427c48)],262h

再看下面的指针赋值语句

12:       int* b=&a;
00401042   mov         dword ptr [ebp-4],offset a (00427c48)

这里的offset a是vc6.0为了方便使用者查看生成的,实际上的语句为:

mov dword ptr ss:[ebp-0x4],0x427C48

也就是直接将全局变量a的地址00427c48赋给b

代码二

前面声明的变量为全局变量,现在来看看局部变量的情况:

#include "stdafx.h"
#include <typeinfo>
void function(){
    //这里a声明为局部变量
        int a=610;
        int* b=&a;
        printf("%x\n",b);
}

int main(int argc, char* argv[])
{
        function();
        return 0;
}

运行结果二

在这里插入图片描述
此时的地址显然就是一个堆栈中的地址,对应了变量存储在堆栈中

反汇编代码二

11:       int a=610;
00401038   mov         dword ptr [ebp-4],262h
12:       int* b=&a;
0040103F   lea         eax,[ebp-4]
00401042   mov         dword ptr [ebp-8],eax
13:       printf("%x\n",b);

可以看到此时是通过lea指令将变量a的地址ebp-4传给eax,然后再将eax赋值给b

取地址中存储数据

前面讲了如何获取一个变量的地址,那么在获取完地址后,再说说如何获取这地址中存储的数据

在C语言中,在一个指针类型的变量前面加上*符号,即可取出该地址里所存储的内容

取地址数据的返回类型

如法炮制,观察取地址数据的返回类型

代码

#include "stdafx.h"
#include <typeinfo>
void function(){
        int***a=(int***) 610;
        printf("%s\n",typeid(*a).name());
        printf("%s\n",typeid(**a).name());
        printf("%s\n",typeid(***a).name());
}
int main(int argc, char* argv[])
{
        function();
        return 0;
}

运行结果

在这里插入图片描述

分析结果

不难发现,所有取地址数据返回的类型都为原本变量的类型后减个*,可以说是和&取地址正好相反

不同的是对于多级指针,可以一次使用多个*来多次取地址中存储的数据

取地址数据的内容

前面了解了*符号的使用,现在来看个稍微复杂点的例子

代码

#include "stdafx.h"
#include <typeinfo>
int a;
void function(){
        a=610;
        int* b=&a;
        int** c=&b;
        int*** d=&c;
        c=*d;
        b=*c;
        a=*b;

    b=**d;
    a=**c;   

    a=***d;
}
int main(int argc, char* argv[])
{
        function();
        return 0;
}

反汇编代码

11:       a=610;
00401038   mov         dword ptr [a (00427c50)],262h
12:       int* b=&a;
00401042   mov         dword ptr [ebp-4],offset a (00427c50)
13:       int** c=&b;
00401049   lea         eax,[ebp-4]
0040104C   mov         dword ptr [ebp-8],eax
14:       int*** d=&c;
0040104F   lea         ecx,[ebp-8]
00401052   mov         dword ptr [ebp-0Ch],ecx
15:       c=*d;
00401055   mov         edx,dword ptr [ebp-0Ch]
00401058   mov         eax,dword ptr [edx]
0040105A   mov         dword ptr [ebp-8],eax
16:       b=*c;
0040105D   mov         ecx,dword ptr [ebp-8]
00401060   mov         edx,dword ptr [ecx]
00401062   mov         dword ptr [ebp-4],edx
17:       a=*b;
00401065   mov         eax,dword ptr [ebp-4]
00401068   mov         ecx,dword ptr [eax]
0040106A   mov         dword ptr [a (00427c50)],ecx
18:
19:       b=**d;
00401070   mov         edx,dword ptr [ebp-0Ch]
00401073   mov         eax,dword ptr [edx]
00401075   mov         ecx,dword ptr [eax]
00401077   mov         dword ptr [ebp-4],ecx
20:       a=**c;
0040107A   mov         edx,dword ptr [ebp-8]
0040107D   mov         eax,dword ptr [edx]
0040107F   mov         ecx,dword ptr [eax]
00401081   mov         dword ptr [a (00427c50)],ecx
21:
22:       a=***d;
00401087   mov         edx,dword ptr [ebp-0Ch]
0040108A   mov         eax,dword ptr [edx]
0040108C   mov         ecx,dword ptr [eax]
0040108E   mov         edx,dword ptr [ecx]
00401090   mov         dword ptr [a (00427c50)],edx

分析反汇编

首先将各变量信息整理出来,方便后面分析:

在这里插入图片描述

代码中涉及的变量较多,这里只拿最复杂的 a=***d来作分析,其它留作样例

22:       a=***d;
00401087   mov         edx,dword ptr [ebp-0Ch]
0040108A   mov         eax,dword ptr [edx]
0040108C   mov         ecx,dword ptr [eax]
0040108E   mov         edx,dword ptr [ecx]
00401090   mov         dword ptr [a (00427c50)],edx

1.这里的ebp-0Ch对应的是d的地址,此时就是将d赋值给edx

00401087   mov         edx,dword ptr [ebp-0Ch]

在这里插入图片描述
结合内存里的数据可以得到:d的地址=ebp-0Ch=0012FF20,d=[ebp-0Ch]=0012FF24

这里的代码相当于

00401087   mov         edx,0012FF24h(d)

2.将前面edx地址里存储的数据赋值给eax,此时的[edx]存储的其实就是c

0040108A   mov         eax,dword ptr [edx]

在这里插入图片描述
结合内存里的数据可以得到:d=edx=0012FF24,[edx]=0012FF28=c

这里的代码相当于

0040108A   mov         eax,0012FF28(c)

3.将前面eax地址里存储的数据赋值给ecx,此时的[eax]存储的其实就是b

0040108C   mov         ecx,dword ptr [eax]

在这里插入图片描述结合内存里的数据可以得到:c=eax=0012FF28,b=[eax]=00427C50

这里的代码相当于

0040108C   mov         ecx,00427C50(b)

4.将前面ecx地址里存储的数据赋值给edx,此时的[ecx]存储的其实就是a

0040108E   mov         edx,dword ptr [ecx]

在这里插入图片描述
结合内存里的数据可以得到:b=ecx=00427C50,a=[ecx]=262h=610

这里的代码相当于

0040108E   mov         edx,262h

5.最后将edx赋值给a

00401090   mov         dword ptr [a (00427c50)],edx

小总结

可以看到,被赋值变量 = * 赋值变量 在汇编中的形式为:mov 被赋值变量,[赋值变量]

如果有多个*,则多执行几次来取值

总结

  • 可以在变量前加上&符号来获取变量地址

  • 取地址返回的类型都为原本变量的类型后加个*,也就是个指针类型

  • 在一个指针类型的变量前面加上*符号,即可取出该地址里所存储的内容

  • 取地址数据返回的类型都为原本变量的类型后减个*,可以说是和&取地址正好相反

  • 对于多级指针,可以一次使用多个*来多次取地址中存储的数据

posted @ 2023-04-21 14:26  私ははいしゃ敗者です  阅读(6)  评论(0编辑  收藏  举报  来源