滴水逆向 C基础(3) 指针专栏
x 86都是四字节
x64 八字节
指针存在的意义就是保存地址 故此跟地址的大小有关
2.指针的四则运算
1.指针的自加 自减
char* p= (char*) 1;
int* pp=(int *)2;
p++;
pp++;
printf("%d---%d", p, pp);
输出
//2 --6
带类型的变量,++ 或者 -- 新增(减少)的数量是去掉一个后变量的宽度
2.指针的加减法
带*类型变量 + N = 带*类型变量 + N*(去掉一个*后类型的宽度)
带*类型变量 - N = 带*类型变量 - N*(去掉一个*后类型的宽度)
char* p= (char*) 1;
int* pp=(int *)2;
p = p + 3;//1+3
pp = pp + 2;//int 类型 2+2*4(4字节是因为 pp去掉一个*后的长度)
printf("%d---%d", p, pp);
1、两个类型相同的带*类型的变量可以进行减法操作
3.类型转换 and &地址 and *变量 (省)
4.数组 结构体 做参数
class mu
{
public:
int x=2
};
void test(int arr[3],mu z)
{
}
void main() {
mu to;
int arr[3] = { 1,2,3 };
test(arr, to);
}
//反汇编
test(arr, to);
00CF512C mov eax,dword ptr [to] //this指针-对象的数据空间压栈
00CF512F push eax
00CF5130 lea ecx,[arr] //数组首地址 压栈 栈中查找
00CF5133 push ecx
00CF5134 call test (0CF1401h)
00CF5139 add esp,8
5.字符数组与字符串
char arr[3] = { 'a','b','c' };//直接赋值
004D510F mov byte ptr [ebp-0Ch],61h
004D5113 mov byte ptr [ebp-0Bh],62h
004D5117 mov byte ptr [ebp-0Ah],63h
21:
22: char name[] = "AB";
004D511B mov ax,word ptr ds:[004D7C30h] //这个地址内0x4241 存储着字符串 ax 16位 2字节
004D5121 mov word ptr [ebp-18h],ax //ax 4241给了 一个地址
004D5125 mov cl,byte ptr ds:[004D7C32h] //末尾添0
004D512B mov byte ptr [ebp-16h],cl
const char* names = "w1";
0044512E mov dword ptr [ebp-24h],447C40h //直接给地址 故此不能修改 一但修改指针错误
1、int strlen (char* s) | |||||
---|---|---|---|---|---|
返回值是字符串s的长度。不包括结束符'/0'。 | |||||
2、char* strcpy (char* dest, char* src); | |||||
复制字符串src到dest中。返回指针为dest的值。 | |||||
3、char* strcat (char* dest, char* src); | |||||
将字符串src添加到dest尾部。返回指针为dest的值。 | |||||
4、int strcmp ( char* s1, char* s2); | |||||
一样返回0 不一样返回1 |
6.指针数组
char a1 = 'A';
char a2 = 'B';
char a3 = 'C';
char a4 = 'D';
char a5 = 'E';
char* p1 = &a1;
char* p2 = &a2;
char* p3 = &a3;
char* p4 = &a4;
char* p5 = &a5;
char* arr[5] = { p1,p2,p3,p4,p5 };
for (int i = 0; i < 5; i++)
{
printf("%c\n", *(arr[i]));
}
7.结构体指针(省)
8.多级指针
一级指针
char* a=(char*)'c';
00391FF5 mov dword ptr [ebp-8],63h
16: char m=*a;
00391FFC mov eax,dword ptr [ebp-8] //将c拿出来给a
00391FFF mov cl,byte ptr [eax] //取c的地址的值 报错
00392001 mov byte ptr [ebp-11h],cl
16: char m=*(a+3);
000A1FFC mov eax,dword ptr [ebp-8]
000A1FFF mov cl,byte ptr [eax+3] //偏移取值
000A2002 mov byte ptr [ebp-11h],cl
一个* 就是取一次地址
二级指针
char** a=(char**)'c';
00F71FF5 mov dword ptr [ebp-8],63h
16: char m=*(*(a+3));
00F71FFC mov eax,dword ptr [ebp-8] //指针最开始的值
00F71FFF mov ecx,dword ptr [eax+0Ch]
00F72002 mov dl,byte ptr [ecx]
00F72004 mov byte ptr [ebp-11h],dl //变量M
我们逆向其实就是反推的过程 dl 来源ecx ->ecx=eax+0xc->eax来源 ebp-8->63h
[[ebp-8] +0c]
9.数组指针
int arr[5] = { 1,2,3,4,5 };
int* p = &arr[0];//简写arr
printf("%d %d %d\n", *(p +1), arr[1],p[1]);
都是进行首地址传递
int arr[5] = { 1,2,3,4,5 };
int(*p)[5] = (int(*)[5])arr;
printf("%d\n", *(*(p)+3));
int(*px)[2] = (int(*)[2])arr;//PX ->首地址
sizeof(px + 1);
printf("%d\n", *(*(px + 1) + 2));//px+1 =px+ 2字节 px[2]-》存储的3 拿出来后 再加2 跳到5
printf("%d\n", *(*(px + 2) + 0));//2*2 4字节 从首地址跳 跳到5
10.函数指针
1.函数指针的声明
返回类型(*函数名)(参数表)
如:int (*pFun)(int,int);
int (*pFun)(int, int);
typedef int (*Fun)(int, int);//取别名的方式 使调用方式选择更多
int mu(int, int)
{
return 7;
}
void main() {
printf("%d\n", sizeof(pFun));//获取函数指针大小
pFun = mu;//将函数给函数指针
printf("%d\n", pFun(1,2));//调用函数指针
Fun pp;//
pp = mu;
printf("%d\n", pp(1, 2));
}
11汇编中的移位指令
1.汇编中的移位指令
1、算术移位指令
指令格式:SAL/SAR Reg/Mem, CL/Imm
SAL(Shift Arithmetic Left): 算术左移
SAR(Shift Arithmetic Right): 算术右移
2、逻辑移位指令
指令格式:SHL/SHR Reg/Mem, CL/Imm
SHL(Shift Left): 逻辑左移 SHR(Shift Right): 逻辑右移
3、循环移位指令
指令格式:ROL r/m, i8 ROR r/m, CL
ROL(Rotate Left): 循环左移
ROR(Rotate Right): 循环右移
4、带进位的循环移位指令
指令格式:RCL r/m, i8 RCR r/m, CL RCL(Rotate through Carry Left): 带进位循环左移 RCR(Rotate through Carry Right): 带进位循环右移
2.C语言中的移位运算
1. 与运算&://都是1才是1
2. 或运算 or //一方为1都是1
3.非运算 | //0 变1 1变0
4.异或运算 ~ // xor 相同为0 不同为1
5.移位运算 左移<< >>
12.define 宏定义
一、无参数的宏定义的一般形式为:# define 标识符 字符序列
define DEBUG 1
#define PI 3.1415926
1、只作字符序列的替换工作,不作任何语法的检查 2、如果宏定义不当,错误要到预处理之后的编译阶段才能发现
二、带参数宏定义:#define 标识符(参数表)字符序列
注意: 1、宏名标识符与左圆括号之间不允许有空白符,应紧接在一起. 2、宏与函数的区别:函数分配额外的堆栈空间,而宏只是替换. 3、为了避免出错,宏定义中给形参加上括号. 4、末尾不需要分号. 5、define可以替代多行的代码,记得后面加 \
13.内存分配与释放
int* ptr;//声明指针
//在堆中申请内存,分配128个int
ptr = (int *)malloc(sizeof(int)*128); //申请空间
//无论申请的空间大小 一定要进行校验 判断是否申请成功
if(ptr == NULL)
{
return 0;
}
//初始化分配的内存空间
memset(ptr,0,sizeof(int)*128); //给空间分配初始值
//使用。。。
*(ptr) = 1; //空间写值
//使用完毕 释放申请的堆空间
free(ptr);
//将指针设置为NULL
ptr = NULL; exe1:4 exe2:4
笔记下载地址https://kxd.lanzoul.com/izrmx0y68i1i

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步