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

这篇具有很好参考价值的文章主要介绍了Windows逆向安全(一)之基础知识(十四)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

指针

什么是指针

一般关于指针的解释都离不开地址。这里先暂且忘记这个概念

指针其实也是一种数据类型,和先前学习的int float等数据类型没有实质上的区别,只不过这个数据类型是在先前学习的所有数据类型后面加上若干个*号,如char *,int *等等,这种数据类型被称为指针

  • 任意类型后面都可以加上*号,使其成为新的指针数据类型
  • *可以是任意多个

指针的声明

指针的声明其实在前面介绍什么是指针的时候就已经讲到了,例子如下:

struct S1{
        int a;
};

void function(){                
        char* a;
        short** b;
        int*** c;
        long**** d;
        _int64***** e;
        float****** f;
        double******* g;
        S1******** s1;
}

可以看到所有的其它数据类型(包括结构体)后面加上若干个*后就是所谓的指针了

推荐的声明方式如上

但也可以这样将*放在变量前面,但不推荐,因为这样相当于将这个数据类型拆开了,不利于理解

struct S1{
        int a;
};

void function(){                
        char *a;
        short **b;
        int ***c;
        long ****d;
        _int64 *****e;
        float ******f;
        double *******g;
        S1 ********s1;
}

指针的赋值

在说指针的赋值之前先看看先前普通变量的赋值

普通变量的赋值貌似是直接使用 变量=值即可,但其实是编译器简化了赋值的步骤,实际上在赋值前本应该加上要赋值类型

例子如下:

void function(){                
        int a;
    a=610;
    a=(int)610;
}

现在再来看指针的赋值

void function(){                
        char* a;
        a=(char*) 610;
    int** b;
    b=(int**) 610;
}

在要赋的值前面加上指针的类型即可,貌似和普通变量的赋值并无太大差别,此时也注意到这里的指针也和地址没有什么关联

指针的的类型转换这里暂且不提

指针的数据宽度

研究数据宽度方法

先前研究过其它基本变量的数据宽度,会发现char、short、int都是按照4字节来分配的(内存对齐),但实际使用的情况下则是按照其原本类型的数据宽度来赋值或进行其它操作的

如:

void function(){                
        char a;
        short b;
        int c;
        a=1;
        b=2;
        c=3;
}

其对应的反汇编代码为:

11:   void function(){
00401010   push        ebp
00401011   mov         ebp,esp
00401013   sub         esp,4Ch
00401016   push        ebx
00401017   push        esi
00401018   push        edi
00401019   lea         edi,[ebp-4Ch]
0040101C   mov         ecx,13h
00401021   mov         eax,0CCCCCCCCh
00401026   rep stos    dword ptr [edi]
12:       char a;
13:       short b;
14:       int c;
15:       a=1;
00401028   mov         byte ptr [ebp-4],1
16:       b=2;
0040102C   mov         word ptr [ebp-8],offset function+20h (00401030)
17:       c=3;
00401032   mov         dword ptr [ebp-0Ch],3
18:   }
00401039   pop         edi
0040103A   pop         esi
0040103B   pop         ebx
0040103C   mov         esp,ebp
0040103E   pop         ebp
0040103F   ret

可以注意到此时提升的堆栈为4Ch,而默认(空函数时)提升的堆栈为40h

00401013   sub         esp,4Ch

于是此时为三个变量分配的空间是:4Ch-40h=0xC=12=3×4,即为char short int都分配了4个字节

但在这三个变量赋值的时候展现出来的就是其原本的数据类型宽度了

15:       a=1;
00401028   mov         byte ptr [ebp-4],1

在char类型的a中的赋值宽度是 byte,1字节

16:       b=2;
0040102C   mov         word ptr [ebp-8],offset function+20h (00401030)

在int类型的c中的赋值宽度是dword,4字节

研究指针数据宽度

于是如法炮制,按照前面的方法来研究指针的数据宽度

在前面的数据类型后添加*,使其成为指针类型

void function(){                
        char* a;
        short* b;
        int* c;
        a=(char*)  1;
        b= (short*) 2;
        c=(int*)  3;
}

其对应的反汇编代码为

11:   void function(){
00401010   push        ebp
00401011   mov         ebp,esp
00401013   sub         esp,4Ch
00401016   push        ebx
00401017   push        esi
00401018   push        edi
00401019   lea         edi,[ebp-4Ch]
0040101C   mov         ecx,13h
00401021   mov         eax,0CCCCCCCCh
00401026   rep stos    dword ptr [edi]
12:       char* a;
13:       short* b;
14:       int* c;
15:       a=(char*)  1;
00401028   mov         dword ptr [ebp-4],1
16:       b= (short*) 2;
0040102F   mov         dword ptr [ebp-8],2
17:       c=(int*)  3;
00401036   mov         dword ptr [ebp-0Ch],3
18:   }
0040103D   pop         edi
0040103E   pop         esi
0040103F   pop         ebx
00401040   mov         esp,ebp
00401042   pop         ebp
00401043   ret

直接观察对应的赋值语句:

15:       a=(char*)  1;
00401028   mov         dword ptr [ebp-4],1
16:       b= (short*) 2;
0040102F   mov         dword ptr [ebp-8],2
17:       c=(int*)  3;
00401036   mov         dword ptr [ebp-0Ch],3

可以看到,所有赋值的宽度都为dowrd,说明无论是char*、short、int\其数据宽度都为4字节

可以使用同样的方法研究float、double、struct等其它数据类型

并且在这里会注意到,指针类型的赋值和非指针类型的赋值在反汇编中并没有什么区别

总结

无论是什么类型,在其后面加上(无论加几个\都一样)后其数据宽度都变为4字节

指针的加减

例子

指针类型也支持加减的操作,但不支持乘和除(编译器决定的),来看例子:

#include "stdafx.h"

void function(){                
        char* a;
        short* b;
        int* c;
        a=(char*)  1;
        b= (short*) 2;
        c=(int*)  3;

        a++;
        b++;
        c++;

        printf("a:%d\t b:%d\tc:%d\n",a,b,c);

}

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

运行结果

windows软件逆向,Windows逆向,windows,安全,网络安全,Windows逆向

分析

这里会观察到结果并不是想象中的2,3,4;而是2,4,7

细心的小伙伴肯定发现了:

  • 2 = 1 + 1 (char数据宽度为1字节)
  • 4 = 2 + 2 (short数据宽度为2字节)
  • 7 = 3 + 4 (int数据宽度为4字节)

结果是加上了原本各自的数据类型的宽度

拓展例子

前面只是都是一级指针,现在将指针换为二级指针:

void function(){                
        char** a;
        short** b;
        int** c;
        a=(char**)  1;
        b= (short**) 2;
        c=(int**)  3;

        a++;
        b++;
        c++;

        printf("a:%d\t b:%d\tc:%d\n",a,b,c);

}

运行结果

windows软件逆向,Windows逆向,windows,安全,网络安全,Windows逆向

分析

此时的结果为:

  • 5= 1 + 4 (char* 数据宽度为4字节)

  • 6= 2 + 4 (short* 数据宽度为4字节)

  • 7 = 3 + 4 (int* 数据宽度为4字节)

结果为加上 去掉一个*后的数据宽度

拓展例子二

前面的加法操作都只增加了1,现在再来查看增加大于1时的情况

void function(){                
        char* a;
        short* b;
        int* c;
        a=(char*)  1;
        b= (short*) 2;
        c=(int*)  3;

        a=a+5;
        b=b+5;
        c=c+5;

        printf("a:%d\t b:%d\tc:%d\n",a,b,c);

}

运行结果

windows软件逆向,Windows逆向,windows,安全,网络安全,Windows逆向

分析

此时的结果为:

  • 6= 1 + 5*1 (char 数据宽度为1字节)
  • 12= 2 + 5*2 (short 数据宽度为2字节)
  • 23 = 3 + 5*4 (int 数据宽度为4字节)

结果为加上 去掉一个*后的数据宽度 × 增加的数值

总结

无论是指针的加亦或是减(这里只演示了加法,但减法同理),其加或减的单位为去掉一个*后的数据宽度

也就是实际增减的数值=去掉一个*后的数据宽度 × 增减的数值

指针类型相减

前面提到的指针的加减都是同一个指针里的加减,但指针之间其实也支持相减操作(不支持相加)

但指针之间的加减要求指针的类型必须一致,即char类型只能和char类型相加减,不能和char**或其它类型相加减

例子

void function(){                
        char* a;
        char* b;
        short* c;
        short* d;
        int* e;
        int* f;

        a=(char*) 200;
        b=(char*) 100;

        c=(short*) 200;
        d=(short*) 100;

        e=(int*) 200;
        f=(int*) 100;

        printf("%d\n",a-b);
        printf("%d\n",c-d);
        printf("%d\n",e-f);

}

运行结果

windows软件逆向,Windows逆向,windows,安全,网络安全,Windows逆向

分析

此时的结果为:

  • 100 = (200 - 100)/1(char 数据宽度为1字节)
  • 50 = (200 - 100)/2 (short 数据宽度为2字节)
  • 25 = (200 - 100)/4 (int 数据宽度为4字节)

结果为相减完后再除以 原本各自的数据宽度

扩展例子

前面只是都是一级指针,现在将指针换为四级指针:

void function(){                
        char**** a;
        char**** b;
        short**** c;
        short**** d;
        int**** e;
        int**** f;

        a=(char****) 200;
        b=(char****) 100;

        c=(short****) 200;
        d=(short****) 100;

        e=(int****) 200;
        f=(int****) 100;

        printf("%d\n",a-b);
        printf("%d\n",c-d);
        printf("%d\n",e-f);

}

运行结果

windows软件逆向,Windows逆向,windows,安全,网络安全,Windows逆向

分析

此时的结果为:

  • 25 = (200 - 100)/4(char*** 数据宽度为4字节)
  • 25 = (200 - 100)/4 (short*** 数据宽度为4字节)
  • 25 = (200 - 100)/4 (int*** 数据宽度为4字节)

结果为相减后再除以 去掉一个*后的数据宽度

总结

指针之间的减法,其结果为相减后再除以去掉一个*后的数据宽度

指针之间的比较

指针之间也支持相互比较,但也和上面指针类型相减一样,要求指针类型一致

例子

void function(){                
        char**** a;
        char**** b;

        a=(char****) 200;
        b=(char****) 100;

        if (a>b)
        {
                printf("a>b\n");
        }else{
                printf("a<=b\n");
        }

}

运行结果

windows软件逆向,Windows逆向,windows,安全,网络安全,Windows逆向

结论

相同类型的指针之间是支持大小比较的

总结

  • 指针的数据宽度为4字节,或者说:无论是什么类型,在其后面加上(无论加几个\都一样)后其数据宽度都变为4字节

  • 指针数值支持进行加减,加减的结果=去掉一个*后的数据宽度 × 增减的数值

  • 指针之间支持减法但不支持加法,其结果为相减后再除以去掉一个*后的数据宽度

  • 指针之间支持比较大小,但要求进行比较的两个指针为相同类型文章来源地址https://www.toymoban.com/news/detail-546325.html

到了这里,关于Windows逆向安全(一)之基础知识(十四)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Windows逆向安全(一)之基础知识(八)

    这次来研究if else嵌套在汇编中的表现形式,本次以获取三个数中最大的数这个函数为例子,分析if else的汇编形式 首先贴上代码: 先验证执行的结果是正确的: 确认可以函数是可以取出三个数的最大值的,于是开始分析该函数 为方便观看,将多余的验证删去,直接改为 然后

    2024年02月12日
    浏览(33)
  • Windows安全基础:认证基础知识

    目录 Windows凭据 Windows访问控制模型 访问令牌: 安全标识符(SID): 安全描述符: 令牌安全防御 1、禁止域管理员异机登录 2、开启“审核进程创建”策略 SSPI(Security Support Provider Interface ,安全支持提供程序接口):是windows操作系统中用于执行各种安全相关操作的公用API,

    2024年02月02日
    浏览(45)
  • windows pwn 基础知识

    winchecksec winchecksec 是 windows 版的 checksec ,不过有时候结果不太准确。 checksec(x64dbg) x64dbg 的插件 checksec 检查效果比较准确,并且可以连同加载的 dll 一起检测。 将 release 的插件按 32 和 64 位分别放到 x32dbg 和 x64dbg 的 plugins 目录,如果找不到 plugins 目录则打开调试器然后关闭

    2024年02月15日
    浏览(46)
  • Windows Api 学习笔记 1——基础知识(上)

    推荐阅读《深入浅出:Windows Api 程序设计》。《深入浅出:Windows Api 程序设计》是 王端明 先生的著作,是2022年人民邮电出版社出版的图书。 Microsoft Windows是美国微软公司开发的一套操作系统。自1985年问世以来,随着软硬件的升级,Microsoft Windows不断迭代更新,变得更加人性

    2024年02月08日
    浏览(55)
  • MySQL基础知识(一)-超详细Windows系统安装MySQL详细教程

    1.简介 原计划,今天这篇想要给小伙伴们讲解一下python操作mysql数据库,但是由于近期换了一台新的电脑,所以一看mysql数据库都没安装,所有才有了这篇文章。尽管网上不乏此类型的文章,但是刚好自己要安装,所以就总结和分享一下下了 这篇博文看起来可能有点长,那是

    2024年02月13日
    浏览(42)
  • 【STM32】基础知识 第十四课 串口通信: 深入探究与应用

    在嵌入式系统中, 串口通信是一种常见的通信方式, 特别是在单片机领域. STM32 系列单片机提供了强大的串口 (UART) 功能, 可支持多种通信模式. 今天小白将带领大家深入探讨 STM32 的串口通信, 包括其基本原理, 配置方法, 中断处理及实际应用示例. 串口通信 (Serial Communication) 是一

    2024年02月15日
    浏览(31)
  • 【前端知识】React 基础巩固(十四)——JSX 的转换过程和声明式编程

    jsx 仅仅只是 React.createElement(component, props, …children)函数的语法糖 所有的 jsx 最终都会被转换成 React.createElement 的函数调用 createElement 需要传递三个参数: type 当前 ReactElement 的类型 如果是标签元素,那么就使用字符串表示 “div” 如果是组件元素,那么就直接使用组件的名称

    2024年02月09日
    浏览(72)
  • 【前端知识】React 基础巩固(三十四)——组件中的异步操作及优化

    通过组件的生命周期来完成网络请求,网络请求的异步代码直接放在组件中 通过redux来管理异步网络请求 在store中引入中间件 redux-thunk 构建 fetchHomeMultidataAction ,将原本在组件中的异步请求代码放入到actionCreators.js中 改写原来的category.jsx,派发异步请求的dispatch 查看运行结果

    2024年02月15日
    浏览(52)
  • 【前端知识】React 基础巩固(四十四)——其他Hooks(useContext、useReducer、useCallback)

    在类组件开发时,我们通过 类名.contextType = MyContext 的方式,在类中获取context,多个Context或者在函数式组件中通过 MyContext.Consumer 方式共享context: 可以看到,当我们需要使用多个Context时,存在大量繁琐的嵌套代码;而Context Hook能够让我们通过Hook直接获取某个Context的值,如

    2024年02月14日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包