指针-字符数组
字符数组与字符串
字符数组:
char arr[6] = {'A','B','C','D','E','F'};
字符串
char names[] = "ABCDEF";
//编译器会在后面添一个00作为字符串的结束标记
测试:
char arr[6] = {'A','B','C','D','E','\0'}; //也可以直接写0
char names[] = "ABCDE";
printf("%s\n",arr);
printf("%s\n",names);
//%s打印一个字符串,直到内存为0
常量区
内存分布图
字符串修改实验
判断哪个能够修改一
char* x = "china";
char y[] = "china";
void Function() {
*(x+1) = 'A';
y[1] = 'A';
}
//反汇编
//*(x+1) = 'A'
00401038 mov eax,[x (00424a30)]
0040103D mov byte ptr [eax+1],41h
对全局的char*
修改失败(0xC0000005 访问错误)
//y[1] = 'A';
00401038 mov byte ptr [y+1 (00424a35)],41h
修改成功
判断哪个能够修改二
void Function() {
char* x = "china";
char y[] = "china";
*(x+1) = 'A';
y[1] = 'A';
}
同上方一样,char*
的x
不能修改,char[]
的y
可以修改
原因:
-
char*
是一个字符指针,其值是一个常量区的地址,常量区可读不可写(char*
在局部变量会在堆栈分配4
字节的空间) -
char[]
是字符数组,它将常量区的值copy
到栈内,char[]
在定义为局部变量会在栈分配字符长度个字节空间(遵循本机字长规则) -
char*
不会拷贝常量字符串,只是单纯的指向常量字符串的首地址
练习-字符串函数编写
作为参数传入的
char*
是字符数组的首地址
strlen
int strlen(char *s) {
int res = 0;
char* temp = s;
while(*temp++ != 0) res++;
return res;
}
strcpy
char* strcpy(char* dest, char* src) {
char* r = dest;
while(*r++ = *src++);
return dest;
}
strcat
//目标字符数组的大小需要大于两个字符串长度的和
char* strcat(char* dest, char* src) {
char* r = dest;
while(*r != 0) r++;
while(*r++ = *src++);
return dest;
}
strcmp
//比较两个字符串的大小(不是比较长度)
int strcmp(char* p1, char* p2) {
char* s1 = p1;
char* s2 = p2;
char c1,c2;
do {
c1 = *s1++;
c2 = *s2++;
if(c1 == 0) return c1-c2;
} while(c1 == c2);
return c1-c2;
}
练习-在内存搜索字符串
题目:
这一堆数据中存储了角色的名字信息(WOW),请列出角色名的内存地址.
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,0x57,0x4F,0x57,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
编写函数,返回角色名字信息的地址,如果没有返回0
函数名:void* FindRoleNameAddr(char* pData, char* pRoleName)
题目漏洞:
- 内存数据存在
0xAA
在char
类型下并不能正常存储,我这里使用unsigned char
模拟内存情况 - 内存区域大小并不能通过判断字符长度来确定
个人题解(并不标准):
#include "bits/stdc++.h"
using namespace std;
unsigned char mem[] = {
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,0x57,0x4F,0x57,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
};
unsigned char name[] = "WOW";
void FindRoleNameAddr(unsigned char* pData, unsigned char* pRoleName) {
int i, j, len_Name = 0, len_Data = 100;
unsigned char* p = pRoleName;
while(*p++ != 0) len_Name++;
int n = len_Data - len_Name;
for (i = 0; i < n; i++) {
p = pData + i;
for (j = 0; j < len_Name; j++) {
if (*(p+j) != *(pRoleName+j)) break;
}
if (!(i-j)) printf("%x\n",p);
}
return ;
}
int main(int argc, char* argv[]) {
FindRoleNameAddr(mem,name);
return 0;
}
0x00424A30