指针-字符数组

指针-字符数组

字符数组与字符串

字符数组:

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)

题目漏洞:

  1. 内存数据存在0xAAchar类型下并不能正常存储,我这里使用unsigned char模拟内存情况
  2. 内存区域大小并不能通过判断字符长度来确定

个人题解(并不标准):

#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
上一篇:西门子S7协议底层原理分析


下一篇:Keil环境下创建STM32汇编语言工程(无硬件)