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

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

指针三

通过先前指针的学习,了解了指针和地址以及数据的关系,现在结合先前的知识继续学习巩固

指针遍历数组

有了先前的基础,再来看看如何用指针遍历数组

代码

#include "stdafx.h"
void function(){
        short arr[5]={1,2,3,4,5};

        short* p=&arr[0];
        short* p2=arr;

        if(p==p2){
                printf("equal\n");
        }else{
                printf("not equal\n");
        }

        int i;
        for(i=0;i<5;i++){
                int j=*(p+i);
                printf("addr:%x value:%d\n",p+i,j);
        }        
}
int main(int argc, char* argv[])
{
        function();
        return 0;
}

代码说明

稍微说明的一下代码部分

主要是声明了一个数组,然后用两种方法取得数组的首地址,一种是&arr[0],另一种则直接是arr

后面则是通过循环配合指针遍历数组成员并输出

按顺序依次涉及先前指针笔记的知识点:

  1. 取变量地址
  2. 指针赋值
  3. 指针之间的比较
  4. 取地址中存储数据
  5. 指针的加减

运行结果

Windows逆向安全(一)之基础知识(十六)
可以看到通过&arr[0]和arr取数组首地址得到的结果是一致的

并且能够通过指针来输出数组成员的地址和对应的数据

这里还会观察到数组里的每个地址都相差2(short类型的数据宽度),和先前数组的学习又匹配上了

反汇编代码

11:       short arr[5]={1,2,3,4,5};
0040D7A8   mov         word ptr [ebp-0Ch],offset function+1Ch (0040d7ac)
0040D7AE   mov         word ptr [ebp-0Ah],offset function+22h (0040d7b2)
0040D7B4   mov         word ptr [ebp-8],offset function+28h (0040d7b8)
0040D7BA   mov         word ptr [ebp-6],offset function+2Eh (0040d7be)
0040D7C0   mov         word ptr [ebp-4],offset function+34h (0040d7c4)
12:
13:       short* p=&arr[0];
0040D7C6   lea         eax,[ebp-0Ch]
0040D7C9   mov         dword ptr [ebp-10h],eax
14:       short* p2=arr;
0040D7CC   lea         ecx,[ebp-0Ch]
0040D7CF   mov         dword ptr [ebp-14h],ecx
15:
16:       if(p==p2){
0040D7D2   mov         edx,dword ptr [ebp-10h]
0040D7D5   cmp         edx,dword ptr [ebp-14h]
0040D7D8   jne         function+59h (0040d7e9)
17:           printf("equal\n");
0040D7DA   push        offset string "equal\n" (00422fbc)
0040D7DF   call        printf (0040d710)
0040D7E4   add         esp,4
18:       }else{
0040D7E7   jmp         function+66h (0040d7f6)
19:           printf("not equal\n");
0040D7E9   push        offset string "not equal\n" (00422fb0)
0040D7EE   call        printf (0040d710)
0040D7F3   add         esp,4
20:       }
21:
22:       int i;
23:
24:       for(i=0;i<5;i++){
0040D7F6   mov         dword ptr [ebp-18h],0
0040D7FD   jmp         function+78h (0040d808)
0040D7FF   mov         eax,dword ptr [ebp-18h]
0040D802   add         eax,1
0040D805   mov         dword ptr [ebp-18h],eax
0040D808   cmp         dword ptr [ebp-18h],5
0040D80C   jge         function+0A8h (0040d838)
25:           int j=*(p+i);
0040D80E   mov         ecx,dword ptr [ebp-18h]
0040D811   mov         edx,dword ptr [ebp-10h]
0040D814   movsx       eax,word ptr [edx+ecx*2]
0040D818   mov         dword ptr [j],eax
26:           printf("addr:%x value:%d\n",p+i,j);
0040D81B   mov         ecx,dword ptr [j]
0040D81E   push        ecx
0040D81F   mov         edx,dword ptr [ebp-18h]
0040D822   mov         eax,dword ptr [ebp-10h]
0040D825   lea         ecx,[eax+edx*2]
0040D828   push        ecx
0040D829   push        offset string "addr:%x value%d:\n" (00422f9c)
0040D82E   call        printf (0040d710)
0040D833   add         esp,0Ch
27:       }
0040D836   jmp         function+6Fh (0040d7ff)
28:
29:   }

反汇编分析

由于循环和数组等相关的知识在先前的笔记已经详细学习过了,这里就直接看指针相关的代码

25:           int j=*(p+i);
0040D80E   mov         ecx,dword ptr [ebp-18h]
0040D811   mov         edx,dword ptr [ebp-10h]
0040D814   movsx       eax,word ptr [edx+ecx*2]
0040D818   mov         dword ptr [j],eax

1.将ebp-18h里的值赋值给ecx,这里的[ebp-18h]其实对应的就是 i

0040D80E   mov         ecx,dword ptr [ebp-18h] (i)

2.将ebp-10h里的值赋值给edx,这里的[ebp-10h]其实对应的是p,即数组首地址

0040D811   mov         edx,dword ptr [ebp-10h] (p)

3.movsx是带符号扩展赋值,将edx+ecx2,也就是p+i\数据宽度地址里存储的值赋给eax

0040D814   movsx       eax,word ptr [edx+ecx*2]

为什么要使用movsx指令?

内存对齐的结果,先前的笔记就提到过:char short 在计算时都会转变为dword宽度来进行计算

4.将前面暂存在寄存器中的值赋给变量j

0040D818   mov         dword ptr [j],eax

指针翻转数组

翻转数组思想

翻转数组的思想就是从数组两端(数组首部和数组尾部)开始然后逐渐向中间靠拢,相互交换数组中的内容

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

代码

#include "stdafx.h"
void function(){
        int arr[5]={1,2,3,4,5};

        int* begin=&arr[0];
        int* end=begin+4;

        while(begin<end){
                int tmp=*begin;
                *begin=*end;
                *end=tmp;
                begin++;
                end--;
        }

        int i;
        for(i=0;i<5;i++){
                printf("%d\n",arr[i]);
        }        

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

代码分析

数组翻转的关键代码是:

int* begin=&arr[0];
int* end=begin+4;

while(begin<end){
        int tmp=*begin;
        *begin=*end;
        *end=tmp;
        begin++;
        end--;
}

1.获取数组首地址和尾地址

int* begin=&arr[0];
int* end=begin+4;

2.循环直到所有数组成员交换结束

while(begin<end){
}

3.取出begin中的数据放在临时变量中

int tmp=*begin;

4.用end里存储的值覆盖begin

*begin=*end;

5.将原本备份的begin的变量tmp赋值给end,此时已经完成了交换

*end=tmp;

6.继续交换,让指针向数组中间靠拢

begin++;
end--;

运行结果

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

可以看到,数组成功翻转了

反汇编实现翻转数组

前面使用指针实现了数组的翻转,为进一步了解其本质,自己手写汇编代码实现翻转数组

下面的汇编代码中省略了 dword ptr ds:[],默认就是取dword

代码

#include "stdafx.h"
void function(){
        int arr[5]={1,2,3,4,5};        
        int len=sizeof(arr)/sizeof(int)-1;        
        __asm{
                xor ecx,ecx
_begin:
                mov eax,len
                sub eax,ecx

                lea edx,[arr+ecx*4]        
                push edx
                mov edx,[edx]
                lea ebx,[arr+4*eax]
                push ebx
                mov ebx,[ebx]
                xchg [arr+ecx*4],ebx
                pop ebx

                mov [ebx],edx
                pop edx
                inc ecx

                cmp edx,ebx
                jb _begin

        }
        int i;
        for(i=0;i<5;i++){
                printf("%d\n",arr[i]);
        }        

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

运行结果

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

能够正确地实现相同的功能

反汇编代码分析

__asm{
                xor ecx,ecx
_begin:
                mov eax,len
                sub eax,ecx

                lea edx,[arr+ecx*4]        
                push edx
                mov edx,[edx]
                lea ebx,[arr+4*eax]
                push ebx
                mov ebx,[ebx]
                xchg [arr+ecx*4],ebx
                pop ebx

                mov [ebx],edx
                pop edx
                inc ecx

                cmp edx,ebx
                jb _begin

        }

1.将ecx清零,初始化ecx,ecx在这里是作为偏移量来使用的(刚开始为首地址的偏移,后来慢慢往中间靠拢)

xor ecx,ecx

2.声明一个程序段,后续跳转会用到

_begin:

3.将数组的长度减1的值赋给eax,因为数组从0开始,所以要减1

mov eax,len

4.用先前的eax减去ecx获得偏移(刚开始为尾地址的偏移,后来慢慢往中间靠拢)

sub eax,ecx

5.通过数组首地址加上ecx偏移取得地址,刚开始取得的为首地址,相当于edx=begin

lea edx,[arr+ecx*4]        

6.将前面获得的地址edx放入堆栈中

push edx

7.取出edx中的值,这里相当于edx=*begin=tmp

mov edx,[edx]

8.通过数组首地址加上偏移eax取得地址,刚开始取得的为尾地址,相当于ebx=end

lea ebx,[arr+4*eax]

9.将前面获得的地址ebx放入堆栈中

push ebx

10.取出ebx中的值,这里对相当于ebx=*end

mov ebx,[ebx]

11.交换arr+ecx*4(*begin)和ebx(end)里存储的值,这里相当于begin=*end

xchg [arr+ecx*4],ebx

12.将先前的push的end的地址恢复到ebx,使得ebx=end

pop ebx

13.这里相当于*end=tmp,此时数组中的两个成员就已经交换完毕了

mov [ebx],edx

14.将先前push的begin的地址恢复到edx,使得edx=begin

pop edx

15.让ecx自增一,这里相当于begin++;end–; 因为这里end的偏移是通过len-begin的偏移得到的

inc ecx

16.比较edx和ebx

jb:jump below,小于则跳转(无符号),这里相当于while(begin<end)中的比较

如果begin<end则继续跳回去执行文章来源地址https://www.toymoban.com/news/detail-448643.html

cmp edx,ebx
jb _begin

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

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

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

相关文章

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

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

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

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

    2024年02月02日
    浏览(58)
  • 【前端知识】React 基础巩固(二十六)——Portals 的使用

    通常,组件会渲染到 root 节点下。可使用 Portals 将组件渲染至其他节点。 添加 id 为 more、modal 的 div 元素 构建 Modal.jsx, 通过 createPortal 把组件渲染到指定的 modal 节点下 构建 App.jsx 查看渲染结果

    2024年02月16日
    浏览(49)
  • 【前端知识】React 基础巩固(四十六)——自定义Hook的应用

    自定义Hook本质上只是一种函数代码逻辑的抽取,严格意义上而言,它并不算React的特性。 实现组件创建/销毁时打印日志 实现Context共享 封装 TokenContext 和 UserContext 两个Context在自定义Hook useUserToken 中,通过使用 userUserToken 同时获取两个Context的内容: 实现获取滚动位置 封装滚

    2024年02月14日
    浏览(47)
  • 【前端知识】React 基础巩固(三十六)——RTK中的异步操作

    引入RTK中的createAsyncThunk,在extraReducers中监听执行状态 在界面中引入所需的异步操作Action 查看运行结果 extraReducer还可以传入一个函数,函数接受一个builder参数: 查看运行结果,与之前的写法结果一致

    2024年02月15日
    浏览(50)
  • 【STM32】基础知识 第十六课 窗口看门狗 WWDG 深入浅出

    在嵌入式开发中, 可靠性和稳定性是至关重要的. 这就是为什么许多单片机, 比如 STM32, 提供了窗口看门狗 (Window Watchdog, WWDF) 的功能. WWDG 是一种硬件定时器, 其目的在于防止软件错误导致的系统故障. WWDG 是通过监控软件运行的正常新, 并在检测到异常情况时自动重启系统, 从而

    2024年02月16日
    浏览(35)
  • Hive基础知识(十六):Hive-SQL分区表使用与优化

    分区表实际上就是对应一个 HDFS 文件系统上的独立的文件夹,该文件夹下是该分区所有的数据文件。 Hive 中的分区就是分目录 ,把一个大的数据集根据业务需要分割成小的数据集。在查询时通过 WHERE 子句中的表达式选择查询所需要的指定的分区,这样的 查询效率会提高很多

    2024年01月18日
    浏览(40)
  • 【C语言初阶】带你轻松掌握指针基础知识完结篇——野指针,指针运算,指针和数组,二级指针

    君兮_的个人主页 勤时当勉励 岁月不待人 C/C++ 游戏开发 Hello,这里是君兮_,今天继续给大家更新0基础入门C语言的内容,我们这次主要更新的依然是初阶指针的基础知识 废话不多说咱们直接开始吧!! 概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有

    2024年02月16日
    浏览(47)
  • 【C语言初阶】带你轻松掌握指针基础知识(1)——指针的定义,类型,大小

    君兮_的个人主页 勤时当勉励 岁月不待人 C/C++ 游戏开发 Hello,这里是君兮_,最近刚回家有点懒,从今天开始恢复更新并开始更新新的刷题系列,我们先继续更新0基础入门C语言的内容,今天给大家带来的是指针方面的内容,但由于是初阶,一些高级的用法我们放在进阶篇再讲

    2024年02月12日
    浏览(44)
  • DS作业0-C语言基础知识复习(含指针与链表)

    判断题: 1.直接访问就是直接利用变量的地址直接进行访问。T 2.可以用一个指针变量指向一个函数,然后通过该指针变量调用此函数。T 3.int (*p)[4]它表示p是一个指针数组,它包含4个指针变量元素。F (是int类型数组,里面有4个指针变量元素) 4.结构体变量可以作数组元素。

    2024年02月04日
    浏览(45)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包