滴水逆向 C基础(3) 指针专栏

1.指针宽度

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 标识符(参数表)字符序列
 # define MAX(A,B) ((A) > (B)?(A):(B))
 代码 x= MAX( p, q)将被替换成 y=((p) >(q)?(p):(q)

注意: 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
posted @ 2023-05-23 23:22  大橘|博客  阅读(63)  评论(0)    收藏  举报