滴水逆向笔记系列-c语言总结5-18.字符串与数组-19.指针数组_结构体指针

第十八课 c语言11 字符串与数组

这一节课b站缺失了,参考一下大佬的笔记学习,链接:https://blog.csdn.net/Edimade/article/details/124446533?spm=1001.2014.3001.5502

1.字符数组

char arr[10] = {'A','B','C','D','E','F'};   //编译器默认在结尾添加0x00
char arr[3] = {'A','B','C'}; //但是如果没有留出'\0'的空间,编译器就不会自动添加
char arr2[6] = {'A','B','C','D','E',0}; //注意区分这里的0不是'0'
char buffer[100] = ""; //定义了一个空字符串,字符串中每个字节默认初始为0x00
char buffer[] = ""; //这个数组长度只有1,且默认初始为0x00

总结:

定义字符数组来表示字符串时,一定要在结尾给'\0',我们可以手动添加,也可以不添加让编译器自己自动帮我们在结尾处添加'\0',但是一定要注意如果让编译器添加的话,要把字符数组的宽度的长度设置好,一定要预留空间给'\0'

2.字符串

也是字符数组的一种,字符串就会经常在常量区

char names[] = "ABCDE"; //可以省略数组大小,但是此时的数组大小应该6,因为编译器会自动在末尾加0x00
char* p = "ABCDE"; //这个是将常量区中存储ABCDE字符串的首地址赋给p,此时p的长度是4字节,常量区的字符
char arr1[6] = {'A','B','C','D','E','\0'};
char arr2[6] = {'A','B','C','D','E',0};  //注意区分这里的0不是'0'
char arr3[6] = {'A','B','C','D','E'};   //只要比5大,数组的长度随便
char names[] = "ABCDE";
printf("%s\n",arr1);
printf("%s\n",arr2);
printf("%s",names);
char word[8];
scanf("%7s", word);//最多读7个字符
  • %s的用法:打印一个字符串,直到内存为 0 为止。这个0相当于16进制的0,平时我们用则使用0或者'\0'来表示

3.常量区

前面有一张内存图,现在来说说之前没讲到的全局变量和常量区
image.png
这是海哥上课的例子代码

char* x = "china";  
//x中存的就是存储在常量区的china字符串的首地址,x指针型变量直接指向常量区中的存储china字符串的首地址
char y[] = "china";  
//这里也是常量区中的china字符串,但是与指针不同的是,这里会将字符串值复制一份到给y字符数组变量分配的内存中(栈)
void Func(){
	y[1] = 'A';    //可以修改
	*(x + 1) = 'A';  //无法修改
    x = "ABC";		//可以修改,相当于重新指向ABC这个新的地址
}

先从反汇编层面看看
image.png
可以看到x变量存储的直接就是china常量区的地址,而y存储的是china拷贝过来的值而且放到堆栈里,所以x无法修改但是y数组可以

总结:

  • *(x+1) = 'A'是尝试去修改常量区china字符串的值,因为常量区可读不可写,所以修改失败
  • y数组由于修改的是拷贝过来的堆栈区,所以可以修改成功
  • x = "ABC";也可以修改成功,相当于重新指向ABC这个新的地址

作业一

image.png
错误示范:
我们要用int类型搜索内容,一次搜四个字节,但是int类型+1后下一次搜索就是每隔四个字节搜一次,而我们现在需要用int类型每隔一个字节搜一次,所以出现下面的错误代码
image.png

#include "stdafx.h"

char data[100] = {  //全局变量
	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
};
int length = sizeof(data) / sizeof(data[0]);

void find_blood(int num,int width){  //输入要查找的数值,查找宽度
	if(width == 1){
		for(int i = 0;i < length - width + 1;i++){
			if(*(data + i) == num)
				printf("add:%x  num:%d\n",data + i,*(data + i));
		}
	}else if(width == 2){
		for(int i = 0;i < length - width + 1;i++){
			short* p = (short*)(data + i);  //直接使用char* data++,但是每次判断前把当前地址转型赋给一个新short* p即可,不需要上面那么麻烦
			if(*p == num){
				printf("add:%x  num:%d\n",p,*p);
			}
		}
	}else if(width == 4){
		for(int i = 0;i < length - width + 1;i++){
			int* p = (int*)(data + i);
			if(*p == num){
				printf("add:%x  num:%d\n",p,*p);
			}
		}
	}else{
        printf("宽度不符合规定");
    }
	
}

int main(int argc, char* argv[])
{
	printf("%x\n",data);
	find_blood(256,2);
	getchar();
	return 0;
}

这把借鉴作业了
还有个改进前的思路也可以看看

void findblood(int size){
	
	if(size == 2){   //数值类型为short时,即2字节
		short* temp = (short*)blood;    //因为每次定位到一个地址,要查的数是从这往后2字节,所以先强转
		for(int i = 0;i < 100 - size + 1;i++){
			if(*(temp) == 100){         //因为temp是short*类型,所以取的地址宽度为2字节
				printf("%x\t%d\n",temp,*temp);
			}
			char* temp2 = (char*)temp;  //因为要一个一个地址挨着找,所以先转换成char*类型,如果拿				short*的temp直接++,那么结果就是源temp中地址+2*1,就不是依次逐个地址找了,就是跳了一个
			temp2++;                   //那么char*变量在++时,结果为:地址 + char宽度,即下一个地址
			temp = (short*)temp2;//然后再将下一个地址的值赋给temp,下次比较就是从temp往后数2字节是否								   是0x0064
		}
	}else if(size == 4){    //数值类型为int时,即4字节
		int* temp = (int*)blood;
		for(int i = 0;i < 100 - size + 1;i++){  //因为如果4字节为单位,则查到倒数第4个地址就是最后													一个地址了,就不用继续我往后查了
			if(*(temp) == 100){
				printf("%x\t%d\n",temp,*temp);
			}
			char* temp2 = (char*)temp;
			temp2++;
			temp = (int*)temp2;
		}

作业二

image.png
1、image.png2、image.png
3、image.png
注意:x数组需要给大一点的空间,否则在y赋值过去后,没有足够的空间来容纳两个字符串的拼接结果,可能会导致超出数组界限的访问,进而引发未定义的行为。
image.png
记录一下自己第一次打印调试出错误
image.png
虽然我感觉我理解错题意了下面代码,不过就这样吧

char datas[] = { 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 };

int length = sizeof(datas) / sizeof(datas[0]);

void FindNameAddr(char* pData, char* pName,int width)
{
	
	if (width == 1)
	{
		for (int i = 0; i < length - width + 1; i++)
		{
			if (*(pData+i) == *pName)
			{
				if(*(pData + i +1) == *(pName+1))
					if (*(pData + i + 2) == *(pName + 2))
						printf("addr:%x\n",pData+i);
			}
		}
	}
	else if (width == 2)
	{

		for (int i = 0; i < length - width + 1; i++)
		{
			short* ret = (short*)(pData+i);
			if (*ret == *((short*)pName))
			{
				if(*(ret+1) == *((short*)pName+1))
					printf("addr:%x\n", pData + i);
			}
		}
	}
	else if (width == 4)
	{
		for (int i = 0; i < length - width + 1; i++)
		{
			int* ret = (int*)(pData + i);
			if (*ret == *((int*)pName))
			{
				printf("addr:%x\n", pData + i);
			}
		}
	}
	else
	{
		printf("宽度输入错误");
	}
}

int main()
{	
	FindNameAddr(datas, (char*)"WOW", 4);
}


第十九课 c语言12 指针数组 结构体指针

1.指针数组

赋值

image.png

常见的指针数组

把"if""for"这些常量的地址放入数组
image.pngimage.png

2.结构体指针

赋值取值

image.png
思维不被限制,结构体指针指向的地址不是结构体也可以,只是他的内存宽度对应不上,但是强转后编译器能编译通过,不管指向的地址后面是什么都打印出来就完事了
image.png

作业

image.png
1、image.pngimage.png

image.png
image.png

总结:

结构体指针和结构体的取值也不一样,ret->id和p.id

posted @ 2024-03-14 14:51  小新07  阅读(28)  评论(0编辑  收藏  举报