首页 > 系统相关 >滴水逆向笔记系列-c语言总结6-20.多级指针 数组指针 函数指针-21.位运算-22.内存分配

滴水逆向笔记系列-c语言总结6-20.多级指针 数组指针 函数指针-21.位运算-22.内存分配

时间:2024-03-14 15:23:34浏览次数:33  
标签:fp 运算 21 22 int px 内存 指针

第二十课 c语言13 多级指针 数组指针 函数指针

1.多级指针反汇编

一二级指针

可以看到p1== *(p1+0) == p1[0]
image.png
image.png
本来一直没想懂为什么是movsx ecx,byte ptr [eax],是byte,才发现p1是char
类型,所以才得用movsx拓展
image.png
(p1+2) == p1[2],指针可以用和[]取值,他们是一样的
(((p3+1)+2)+3) == p3[1][2][3]
image.png
((p2+1)+1)中,(*(p2+1)+1)是char类型,所以他的+1等于+4,(p2+1)是char类型,他的+1就是+1*
image.png

三级指针

p3是char类型,p3是char类型,(p3)是char类型,((p3))是char类型
image.png

总结:

image.png

2.数组指针

基本特性

image.png

数组指针的*p和p

image.png
虽然*px和px的值一样,但是类型不一样,所以运算出来的值也不一样

疑问?

为什么px的值会和px一样?
看一下反汇编
image.png
px这个值的地址存放的就是1,那我
px就是取0113FD38这个地址的值,为什么不是取出1呢
写个普通的例子,他*px是会取出px的值后再取一次
image.png

px的类型是int (*)[2],所以是指向arr数组首地址,*px的类型是int [2],
还是一个数组类型,数组类型的含义还是数组的首地址,所以*px的值还是一个地址,
参考直接arr的时候,arr取值还是一个数组首地址。

总结:

  • 多去使用砍星看看目前的变量是什么类型
  • 运算才需要砍星,px的本身类型是int (*)[2],这个类型的宽度是4,虽然是数组指针但也熟是个指针类型的宽度

数组指针运算

image.png
(px+1)就先把px的类型(int ()[2])砍个星,那么现在砍完是int [2],那么(px+1)等于px+8
((px+3)+3) px+3算完是int [2]类型,要继续+3运算就继续砍星,int [2]砍完是int类型,所以(*(px+3)+3)第二个+3就是+12

总结:

  • 运算记得砍星砍类型宽度
  • ((px+3)+3)相当于px[3][3]

3.多维数组指针

一维数组

通过上面数组指针的运算已经练的很熟练了,+48,指向第49个数据也就是0xA0,但是我们的数据类型是int (*)[5],宽度为4,所以读出来的数据是000000A0
image.png

二维数组

二维数组运算

1220761906.jpg
一样砍星运算,*(px+3)要运算砍星后的类型是char [2][3],所以+3等于+18,((px+3)+2)运算砍星后的类型是char[3],所以+2等于+6

4.函数指针

代码也是数据

基础特征

函数指针宽度还是4,但是由于砍星后宽度不确定,无法进行加减运算,但是可以比较大小1220875178.jpg

赋值

定义的函数指针的返回值和参数,要和在赋值的函数的返回值和参数一样,否则一运行就挂了,可以强制转型编译成功但是一运行还是会挂
1220877199.jpg

函数也是一段数据

论证函数其实也就是一段数据,这段数据的地址被指向函数指针时,可以被当做函数执行,强转欺骗编译器
-1438804603.jpg
1221654710.jpg

作业

1220818511.jpg
1、不完全正确,不要这么理解,指针就是指针,爱指哪就指哪,指针只是操作数据的工具

第二十一课 c语言14 位运算

1.什么是位运算

  • 位运算效率高
  • 计算机的加减乘除所有运算到最后都需要位运算
  • 位运算还可以用于加密

2.汇编中的算数位移指令

  • SAL(Shift Arithmetic Left):算术左移(和SHL效果一样)
  • SAR(Shift Arithmetic Right):算术右移
  • 格式:即算数移位指令后面的第一个操作数是寄存器或者内存;第二个操作数是寄存器或者立即数

image.png

反汇编例子

0x81二进制为10000001,左移一位后为00000010,左边最高位给cf,右边最低位补0
image.png
image.png
如果是用eax寄存器的话最高位的1就直接左移,不用移到cf标志位了
image.png
0x81二进制为10000001,右移一位后为11000000,左边补最高位,右边最低为的移到cf标志位
image.png
image.png

3.逻辑移位指令

  • SHL(Shift Left):逻辑左移
  • SHR(Shift Right):逻辑右移

左移和算数移位指令一样,右移就不一样,最左边补0
image.png

4.循环移位指令

  • ROL(Rotate Left):循环左移
  • ROR(Rotate Right):循环右移

image.png

5.带进位的循环移位指令

  • RCL(Rotate through Carry Left):带进位循环左移
  • RCR(Rotate through Carry Right):带进位循环右移

image.png

作业

1246703167.jpg

第二十二课 c语言15 内存分配

1.c程序的执行步骤

  • 替换 -->编译 -->链接 -->装入内存 --> 执行

2.宏定义

无参数

#define 标识符 字符序列

#define DEBUG 1				
void Function(){		
	//....	
	if(DEBUG)
		printf("测试信息");
}	

有参数

#define 标识符(参数表) 字符序列
类似定义函数,但是define是把标识符直接替换成后面字符序列(函数执行代码),不会在堆栈创建空间

#define MAX(A,B) ((A) > (B)?(A):(B))
void Func(){
	int x = MAX(1,2);
}

注意事项:

  • 宏名标识符与左圆括号之间不允许有空白符,应紧接在一起
  • 宏与函数的区别:函数分配额外的堆栈空间,而宏只是替换
  • 为了避免出错,宏定义中给形参加上括号
  • 末尾不需要分号
  • define可以替代多行的代码,记得后面加\(一行写不下,就加\接着下一行写)
#define MALLOC(n,type)\					
		((type*)malloc((n)*sizeof(type)))

3.动态分配内存

前面学习的int x; char arr[100];都是静态申请内存,今天学学动态的申请内存

malloc函数

作用:分配所指定大小的内存空间,并返回一个指向它的指针,如果内存空间不够,则返回NULL
声明:

#include "stdlib .h"
void* malloc(size_t size)

void*

void*表示任何类型的指针,在需要的时候再去强转成我们需要的对应类型指针,比如malloc动态申请内存,要返回一个指向内存的指针,但是我们声明时不知道要用一个什么类型的指针,那么返回值可以使用void*,因此宽度就不确定,无法做加减运算

使用:

//在堆中申请内存,分配128个int
int* ptr = (int *)malloc(sizeof(int)*128);   //假设这块内存要给一个int型数组使用,将void*强转int*

//无论申请的空间大小,一定要进行校验,判断是否申请成功	
if(ptr == NULL){	
	return 0;
}
//初始化分配的内存空间,将分配的这片内存中全设为0(可以不用加,这里是害怕这块内存中有别人留下的数据)
memset(ptr,0,sizeof(int)*128);
//使用内存
*(ptr) = 1;   //使用指针来操作指向的内存中的数据
//使用完毕,释放申请的堆空间
free(ptr);
//将指针设置为NULL。因为这次我使用了ptr指针,我用完之后ptr应该还是指向了最后的内存中的地址,如果有坏蛋尝试使用了ptr指针,即用完后又使用了ptr指针,那很可能把原先指向的内存中的其他数据给读出来了,不安全。如果设置了NULL,后面不小心使用ptr,会报错
ptr = NULL;

内存泄露问题:

我们平时如果在函数外定义一个变量,分配的内存在全局区;在函数内定义一个变量,分配的内存在堆栈;使用完这个变量,也不用我们手动的去释放分配的内存空间,因为堆栈平衡等原因,使用完后这些内存中的数据就变成了垃圾,下一次再使用赋初始值覆盖这块内存中的数据即可。
但是现在如果我们使用malloc函数动态申请内存,分配的内存空间在堆中,堆有一个特点,如果此时一个数据占用了堆中的某块内存,那么操作系统就会记住这块内存已经分配出去了,其他数据就不能占用了,要么等待释放、要么此exe程序退出后,其他的数据才能再使用这块内存。
但是像服务器上运行的程序,会长时间运行,使用malloc函数申请内存,如果使用完没有释放,就会造成这块内存一直被占用,当数据庞大时,会将堆全部占住,最后内存占用率会很高,程序就会奔溃,这就是内存泄露问题(堆)。所以一定要释放内存

作业

image.pngimage.png

#pragma warning(disable:4996)//忽略函数不安全警告
int F_Size(FILE* fp)
{
	fseek(fp, 0, 2);
	int len = ftell(fp);
	fseek(fp, 0, 0);
	return len;
}

void F_exe()
{
	FILE* fp;
	fp = fopen("C:\\Windows\\notepad.exe","rb");

	char* addr = (char*)malloc(F_Size(fp));

	if (addr)
	{
		fread(addr, F_Size(fp),1,fp);
	}
	printf("%x",addr);
    free(addr);
    fclose(fp);
}

int main()
{
	F_exe();
}

ftell函数和fseek函数

返回当前文件位置指示符,可以和fseek函数联合使用,先使用fseek把文件指针定位到文件尾部,ftell就可以返回当前文件位置距离文件头还有多少字节,从而计算出文件大小

流stream 的文件位置为给定的偏移 offset,参数 offset 意味着从给定的 whence 位置查找的字节数。
  int fseek( FILE *stream, long offset, int origin );
	第一个参数stream为文件 指针
	第二个参数offset为 偏移量 ,正数表示正向偏移,负数表示负向偏移
	第三个参数origin设定从文件的哪里开始偏移,可能取值为:SEEK_CUR、 SEEK_END 或 SEEK_SET
	SEEK_SET: 文件开头
	SEEK_CUR: 当前位置
	SEEK_END: 文件结尾
	其中SEEK_SET,SEEK_CUR和SEEK_END依次为0,1和2.
	简言之:
	fseek(fp,100L,0);把文件内部 指针 移动到离文件开头100字节处;
	fseek(fp,100L,1);把文件内部 指针 移动到离文件当前位置100字节处;
	fseek(fp,-100L,2);把文件内部 指针 退回到离文件结尾100字节处。

标签:fp,运算,21,22,int,px,内存,指针
From: https://www.cnblogs.com/xiaoxin07/p/18072924

相关文章

  • 深入C语言指针,使代码更加灵活(二)
    一、数组名的理解前面我们在使用指针访问数组内容的时候,有这样的代码:intarr[10]={1,2,3,4,5,6,7,8,9,10};int*p=&arr[0];在这里我们使用&arr[0]的方式拿到了数组第⼀个元素的地址,但是其实数组名本来就是地址,而且是数组首元素的地址。我们来进行测试:#d......
  • C++——智能指针
    本章代码Gitee仓库:智能指针文章目录1.为什么要有智能指针2.RAII机制3.智能指针原理4.auto_ptr(c++98)5.unique_ptr(c++11)6.shared_ptr(c++11)6.1shared_ptr线程安全问题6.2shared_ptr循环引用6.3定制删除器7.weak_ptr(c++11)8.C/C++动态内存1.......
  • 滴水逆向笔记系列-c语言总结4-15.switch语句反汇编-16.指针1-17.指针2
    第十五课c语言8switch语句初步测试感觉switch在反汇编的语句和if语句的唯一差别就是jcc语句比较集中当分支大于四条时,switch的反汇编开始变3为switch传入的值,1是case最小值,4是case最大值减1,算出偏移量后通过偏移量4加上基址就可以在大表中获取要输出的case语句的地址当现在case......
  • LeetCode225.队列实现栈
    ques:用两个队列模拟栈(我用的是一个)ans:用的C++标准库里面的Queue模板类创建实例,主要思路就是push函数里面做文章,其余函数pop/top/empty都正常实现。根据栈和队列的特性,插入点不变,只能是队尾,但每次插入队尾总想把他放在栈顶,所以就让队列前面的元素依次出队并排在队尾,即可......
  • XM22010-3直流电源设备:开启高效稳定供电
    XM22010-3直流电源设备:稳定输出,高效供电新典范在直流电源领域,稳定、高效的供电设备是确保各类电子设备正常运行的关键。XM22010-3直流电源设备以其出色的稳定性和高效性,成为市场上的佼佼者。XM22010-3直流电源设备采用了先进的电源转换技术和智能控制算法,能够实现稳定、连续......
  • ND22030-3B自冷电源模块:高效稳定供电,静音散热
    ND22030-3B自冷电源模块:高效稳定,静音散热新标杆在电力供应领域,电源模块的稳定性和散热性能至关重要。ND22030-3B自冷电源模块以其高效稳定的工作性能和独特的静音散热设计,成为了市场上的佼佼者。ND22030-3B自冷电源模块采用了先进的电源转换技术和自冷散热技术,实现了高效稳定......
  • C语言从入门到实战————数组和指针的深入理解
    前言在C语言中,数组和指针有的密切得联系,因为数组名本身就相当于一个指针常量。指针是一个变量,专门用来存储另一个变量的内存地址,通过这个地址可以访问和操作该变量的值,同时也包括数组。数组是一组连续存储的同类型数据的集合,它允许通过索引快速访问各个元素。同时数组名也是数......
  • HS6621Cx 一款低功耗蓝牙SoC芯片 应用于键盘、鼠标和遥控器消费类产品
    HS6621Cx是一款功耗优化的真正片上系统(SOC)解决方案,适用于低功耗蓝牙和专有2.4GHz应用。它集成了高性能、低功耗射频收发器,具有蓝牙基带和丰富的外设IO扩展。HS6621Cx还集成了电源管理功能,可提供高效的电源管理。它面向2.4GHz蓝牙低功耗系统、专有2.4GHz系统、人机接口设备(键盘......
  • SMK20-12255保护测控装置电源板:功能特性与广泛应用解析
    SMK20-12255保护测控装置电源板:功能特性与应用解析SMK20-12255保护测控装置电源板是一种专用于电力系统的高性能电源供应与监测控制设备。它以其稳定可靠的电源供应、精准实时的电力参数监测以及快速响应的保护机制,为电力系统的安全稳定运行提供了重要保障。一、功能特性高......
  • 【5V 转 3.3V,3V,2.5V芯片首选】PW2162高效恒压转换器,外围电路超简单
    在现代电子设备高速发展的今天,一款高效、稳定的电源管理芯片对于设备的性能至关重要。PW2162,作为一款完全集成、高效的2A同步整流降压转换器,凭借其出色的性能和广泛的应用领域,正引领着电源管理领域的新纪元。首先,让我们深入了解一下PW2162的独特之处。这款转换器在宽输出电流负载......