大神论坛

找回密码
快速注册
查看: 625 | 回复: 0

[语言编程类] 大神论坛 逆向脱壳分析基础学习笔记二十一 汇编 指针(二)

主题

帖子

5

积分

初入江湖

UID
20
积分
5
精华
威望
10 点
违规
大神币
68 枚
注册时间
2021-03-14 10:40
发表于 2021-03-14 23:46
本帖最后由 kay2kay 于 2021-03-14 23:46 编辑

本文为本人的滴水逆向破解脱壳学习笔记之一,为本人对以往所学的回顾和总结,可能会有谬误之处,欢迎大家指出。
陆续将不断有笔记放出,希望能对想要入门的萌新有所帮助,一起进步


所有笔记链接:

大神论坛 逆向脱壳分析基础学习笔记一 进制篇
大神论坛 逆向脱壳分析基础学习笔记二 数据宽度和逻辑运算
大神论坛 逆向脱壳分析基础学习笔记三 通用寄存器和内存读写
大神论坛 逆向脱壳分析基础学习笔记四 堆栈篇
大神论坛 逆向脱壳分析基础学习笔记五 标志寄存器 
大神论坛 逆向脱壳分析基础学习笔记六 汇编跳转和比较指令
大神论坛 逆向脱壳分析基础学习笔记七 堆栈图(重点)(需登录才能访问)
大神论坛 逆向脱壳分析基础学习笔记八 反汇编分析C语言
大神论坛 逆向脱壳分析基础学习笔记九 C语言内联汇编和调用协定
大神论坛 逆向脱壳分析基础学习笔记十 汇编寻找C程序入口(需登录才能访问)
大神论坛 逆向脱壳分析基础学习笔记十一 汇编C语言基本类型
大神论坛 逆向脱壳分析基础学习笔记十二 汇编 全局和局部 变量(需登录才能访问)
大神论坛 逆向脱壳分析基础学习笔记十三 汇编C语言类型转换(需登录才能访问)
大神论坛 逆向脱壳分析基础学习笔记十四 汇编嵌套if else(需登录才能访问)
大神论坛 逆向脱壳分析基础学习笔记十五 汇编比较三种循环(需登录才能访问)
大神论坛 逆向脱壳分析基础学习笔记十六 汇编一维数组(需登录才能访问)
大神论坛 逆向脱壳分析基础学习笔记十七 汇编二维数组 位移 乘法(需登录才能访问)
大神论坛 逆向脱壳分析基础学习笔记十八 汇编 结构体和内存对齐(需登录才能访问)
大神论坛 逆向脱壳分析基础学习笔记十九 汇编switch比较if else(需登录才能访问)
大神论坛 逆向脱壳分析基础学习笔记二十 汇编 指针(一)(需登录才能访问)
大神论坛 逆向脱壳分析基础学习笔记二十一 汇编 指针(二)(需登录才能访问)
大神论坛 逆向脱壳分析基础学习笔记二十二 汇编 指针(三)(需登录才能访问)
大神论坛 逆向脱壳分析基础学习笔记二十三 汇编 指针(四)(需登录才能访问)
大神论坛 逆向脱壳分析基础学习笔记二十四 汇编 指针(五) 系列完结(需登录才能访问)

更多逆向脱壳资源,请访问  大神论坛

指针二

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

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

获取变量的数据类型

在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;
}

运行结果

image-20210309223919194

使用方式

通过上面的例子可以知道使用方式首先要包含一个相关的头文件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;
}

运行结果

image-20210309224811959


分析结果

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

取地址的内容

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

代码

#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;
}

运行结果

image-20210309231812753

反汇编代码

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;
}

运行结果二

image-20210309235502045

此时的地址显然就是一个堆栈中的地址,对应了变量存储在堆栈中

反汇编代码二

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;
}

运行结果

image-20210310000600529


分析结果

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

不同的是对于多级指针,可以一次使用多个*来多次取地址中存储的数据#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

分析反汇编

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

变量变量地址变量内容/地址的值(十六进制)
a00427c50262(对应十进制为610)
bebp-4 = 0012FF2800427C50
cebp-8 = 0012FF240012FF28
debp-0Ch = 0012FF200012FF24

代码中涉及的变量较多,这里只拿最复杂的 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]

image-20210310002638753

结合内存里的数据可以得到:d的地址=ebp-0Ch=0012FF20,d=[ebp-0Ch]=0012FF24

这里的代码相当于

00401087   mov         edx,0012FF24h(d)

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

0040108A   mov         eax,dword ptr [edx]

image-20210310002914650

结合内存里的数据可以得到:d=edx=0012FF24,[edx]=0012FF28=c

这里的代码相当于

0040108A   mov         eax,0012FF28(c)

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

0040108C   mov         ecx,dword ptr [eax]

image-20210310003238462

结合内存里的数据可以得到:c=eax=0012FF28,b=[eax]=00427C50

这里的代码相当于

0040108C   mov         ecx,00427C50(b)

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

0040108E   mov         edx,dword ptr [ecx]

image-20210310004636277

结合内存里的数据可以得到:b=ecx=00427C50,a=[ecx]=262h=610

这里的代码相当于

0040108E   mov         edx,262h

5.最后将edx赋值给a

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

小总结

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

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

总结

  • 可以在变量前加上&符号来获取变量地址
  • 取地址返回的类型都为原本变量的类型后加个*,也就是个指针类型
  • 在一个指针类型的变量前面加上*符号,即可取出该地址里所存储的内容
  • 取地址数据返回的类型都为原本变量的类型后减个*,可以说是和&取地址正好相反
  • 对于多级指针,可以一次使用多个*来多次取地址中存储的数据

版权声明:本文由 lyl610abc 原创,欢迎分享本文,转载请保留出处

返回顶部