今天下雪了,所以我来看雪!!!
最近两个月我木有发帖,学校里的事比较多哈。。。第14届安徽省大学生职业规划大赛(金奖)主题就是软件逆向工程师(评委:这是啥???)。然后就是国家奖学金等。不亏,给
钱让我上大学。。。
好的,装0xD完了。进入正题。
首先我要解释一个梗:指针就是地址??? 不完全是!
指针难么?
首先我们来看指针的宽度是啥。
char a=1;
char* b=(char*)1; //下面解释
char** c=(char**)1;
a的宽度是1个字节
b的宽度是4个字节(32位)
二级指针 c也是4???
啥是二级指针 ?指向一级指针的东西???弄弄弄! 不一定是
继续,
short y;//宽度2字节
int z;//宽度4字节(32位机)
float f;//宽度4(32位机)
double d;//宽度8
加个*会怎样???
char* x;
short* y;
int* z;
float* f;
double* d;
2020年我国全面进入小康社会,所有屌丝都有女朋友!!!人人平等!
咳咳,跑题了。。。它们的宽度都是4个字节,不信?你看!
14: char* x=(char*)10;
00401048 C7 45 FC 0A 00 00 00 mov dword ptr [ebp-4],0Ah
15:
16: short* y=(short*)10;
0040104F C7 45 F8 0A 00 00 00 mov dword ptr [ebp-8],0Ah
17:
18: int* z=(int*)10;
00401056 C7 45 F4 0A 00 00 00 mov dword ptr [ebp-0Ch],0Ah
19:
20: float* f=(float*)10;
0040105D C7 45 F0 0A 00 00 00 mov dword ptr [ebp-10h],0Ah
21:
22: double* d=(double*)10;
00401064 C7 45 EC 0A 00 00 00 mov dword ptr [ebp-14h],0Ah
:
那么,二级指针是啥?恩。。。
14: char** x=(char**)10;
00401048 C7 45 FC 0A 00 00 00 mov dword ptr [ebp-4],0Ah
15:
16: short** y=(short**)10;
0040104F C7 45 F8 0A 00 00 00 mov dword ptr [ebp-8],0Ah
17:
18: int** z=(int**)10;
00401056 C7 45 F4 0A 00 00 00 mov dword ptr [ebp-0Ch],0Ah
19:
20: float** f=(float**)10;
0040105D C7 45 F0 0A 00 00 00 mov dword ptr [ebp-10h],0Ah
21:
22: double** d=(double**)10;
00401064 C7 45 EC 0A 00 00 00 mov dword ptr [ebp-14h],0Ah
恩,也是4个字节! 你爹有5个亿,你有女票。我爹是画家,我也有女票!
总结:普通类型的指针宽度都是4个字节。多级指针也是4个字节。
下面我们看看一些奇葩的指针。
1. 指针数组(是指针的数组,是数组!)
为啥? char[10]的宽度是10个字节,因为char宽度*10,那么char* [10]的宽度就是10个char*的宽度。也就是40。
人人平等,人人都有女票!
也是40个字节
那么 两个星呢?
恩,也是40个字节。
2 结构体指针
也是4个字节。 为啥? 因为这个指针通常指向了结构体变量的首地址(这个不能乱用)
3 函数指针
16: int (*pf)(int)=f;
00401088 C7 45 FC 0F 10 40 00 mov dword ptr [ebp-4],offset @ILT+10(f) (0040100f)
0040108F 8B 45 FC mov eax,dword ptr [ebp-4]
00401092 89 45 FC mov dword ptr [ebp-4],eax
宽度也是4,因为它现在指向了函数的首地址(其实是跳转表)。
指针运算
指针在做运算时,要拿砍掉一个星后的宽度然后在算。这样的运算规则便于开发寻址。
a的类型char* 宽度 砍掉一个*,变成了char。然后char的宽度是1。100+1*5=105.
以此类推。
自加
减法同理
指针与指针的运算
指针主要是用于寻址的。所以,我们假设a指向了一个变量,b也指向了一个变量,所以相减就是他们的地址差。指针与指针的运算应该先减,然后除以砍掉一个*的宽度。
同理,a-b=100,100/int的宽度4字节,最后得25。
多级指针与多级指针的运算
因为普通类型的指针宽度都是4个字节(32位机),所以我就举着一个例子吧。。
引用&的用法
引用的本质就是取地址,比如:
10: char a = 10;
00401048 C6 45 FC 0A mov byte ptr [ebp-4],0Ah
11: short b = 20;
0040104C 66 C7 45 F8 14 00 mov word ptr [ebp-8],offset main+20h (00401050)
12: int c = 30;
00401052 C7 45 F4 1E 00 00 00 mov dword ptr [ebp-0Ch],1Eh
13:
14: char* pa = (char*)&a;
00401059 8D 45 FC lea eax,[ebp-4]
0040105C 89 45 F0 mov dword ptr [ebp-10h],eax
15: short* pb = (short*)&b;
0040105F 8D 4D F8 lea ecx,[ebp-8]
00401062 89 4D EC mov dword ptr [ebp-14h],ecx
16: int* pc = (int*)&c;
00401065 8D 55 F4 lea edx,[ebp-0Ch]
00401068 89 55 E8 mov dword ptr [ebp-18h],edx
指针与引用正常情况下可以看成是一对,也就是间接寻址的引用。
比如说
10: char a = 10;
00401048 mov byte ptr [ebp-4],0Ah
11:
12:
13: char* pa = (char*)&a;//取地址
0040104C lea eax,[ebp-4]
0040104F mov dword ptr [ebp-8],eax
14:
15:
16: printf("%d ",*pa);
00401052 mov ecx,dword ptr [ebp-8]//取ebp-8的数据 然后把它当成地址来取里面的值。
00401055 movsx edx,byte ptr [ecx]
00401058 push edx
00401059 push offset string "%d " (0042e01c)
0040105E call printf (00408160)
00401063 add esp,8
17:
说的简单粗暴点就是:变量前面加一个*就是把这个变量里面的值当成地址,然后取这个地址里面的值(相当于砍掉一个*)。 变量前面加一个&就是取这个变量的地址(相当于加一个星)。
例题:
打印数组
char arr[10];
char* p = &arr[0]; //取数组第一个元素的地址
for(int k=0;k<10;k++)
{
printf("%d\n",*(p+k)); //取地址里的值
}
对应反汇编
12: char* p = &arr[0]; //取数组第一个元素的地址
00401048 lea eax,[ebp-0Ch]
0040104B mov dword ptr [ebp-10h],eax
13: for(int k=0;k<10;k++)
0040104E mov dword ptr [ebp-14h],0
00401055 jmp main+30h (00401060)
00401057 mov ecx,dword ptr [ebp-14h]
0040105A add ecx,1
0040105D mov dword ptr [ebp-14h],ecx
00401060 cmp dword ptr [ebp-14h],0Ah
00401064 jge main+4Fh (0040107f)
14: {
15: printf("%d\n",*(p+k)); //取地址里的值
00401066 mov edx,dword ptr [ebp-10h]//数组首地址
00401069 add edx,dword ptr [ebp-14h]//k变量
0040106C movsx eax,byte ptr [edx]//寻址
0040106F push eax
00401070 push offset string "%d\n" (0042e01c)
00401075 call printf (00408180)
0040107A add esp,8
16: }
0040107D jmp main+27h (00401057)
17:
指针类型
虽然指针的宽度都是4字节,但是用的时候还是与区别的.
char类型的指针一次访问内存一个字节。
Short 类型的指针一次访问内存两个字节
Int 类型的指针一次访问内存4个字节
比如:
反汇编代码:
11: int i=300;
00401048 mov dword ptr [ebp-4],12Ch
12: char* b=(char*)&i;
0040104F lea eax,[ebp-4]
00401052 mov dword ptr [ebp-8],eax
13:
14: printf("%d",*b);
00401055 mov ecx,dword ptr [ebp-8]
00401058 movsx edx,byte ptr [ecx] //这里 ,只取了1个byte
300的二进制是100101100 而char*只能取1个字节的数据,所以取低8位,也就是101100
=42。
例题
模拟实现CE的数据搜索功能:
这一堆数据中存储了角色的血值信息,假设血值的类型为int类型,值为100(10进制)
请列出所有可能的值以及该值对应的地址.
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x07,0x09,
0x00,0x20,0x10,0x03,0x03,0x0C,0x00,0x00,0x44,0x00,
0x00,0x33,0x00,0x47,0x0C,0x0E,0x00,0x0D,0x00,0x11,
0x00,0x00,0x00,0x02,0x64,0x00,0x00,0x00,0xAA,0x00,
0x00,0x00,0x64,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x02,0x00,0x74,0x0F,0x41,0x00,0x00,0x00,
0x01,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x0A,0x00,
0x00,0x02,0x74,0x0F,0x41,0x00,0x06,0x08,0x00,0x00,
0x00,0x00,0x00,0x64,0x00,0x0F,0x00,0x00,0x0D,0x00,
0x00,0x00,0x23,0x00,0x00,0x64,0x00,0x00,0x64,0x00
答案
void f(char a[],int l)
{
for(int i=0;i<l;i++)
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2020-3-18 22:05
被AMask编辑
,原因: