首页 > 其他分享 >滴水逆向笔记系列-c语言总结5-

滴水逆向笔记系列-c语言总结5-

时间:2024-03-14 14:56:46浏览次数:27  
标签:逆向 temp int 滴水 0x00 笔记 char width printf

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

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

1.字符数组

:::info
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.字符串

也是字符数组的一种,字符串就会经常在常量区
:::info
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

标签:逆向,temp,int,滴水,0x00,笔记,char,width,printf
From: https://www.cnblogs.com/xiaoxin07/p/18072853

相关文章

  • 学习笔记-华为IPD转型2020:3,IPD的实施
    3.IPD的实施 1999年开始的IPD转型是计划中的多个转型项目中的第一个(Liu,2015)。华为为此次转型成立了一个专门的团队,从大约20人开始,他们是华为第一产业的高层领导。董事会主席孙雅芳是这个团队的负责人。该团队拥有充足的资源,最多包括70名来自IBM的顾问。这个联合团队......
  • Java复习第二天学习笔记,附有道云笔记链接
    【有道云笔记】二3.13https://note.youdao.com/s/RWOQv0g一、运算符1.基本运算符+-*/@Testpublicvoidtest2(){System.out.println("运算符.test2");//双目运算符intnum1=3,num2=5;intresult=num1+num2;System.out.println(result);System.out.prin......
  • 滴水逆向笔记系列-c语言总结2-10.变量-11.if逆向-12.正向基础
    第十课c语言31.编码ASCII标准的ASCII编码只需要七位,第八位在拓展ASCII编码使用GB23122.局部变量和全局变量下面代码输出结果为1111(x=11改变了全局的x)第十一课c语言41.内存图2.逆向参数个数3.简单逆向if代码4.if...else...反汇编判断跳转执行一部分代......
  • 滴水逆向笔记系列-7.堆栈图-8.c语言反汇编-9.数据类型
    第七课堆栈图1.函数函数的入口汇编中的函数函数有入口出口,但不一定有返回值和参数2、堆栈windows堆栈:什么是堆栈平衡:第八课c语言分析这段代码的反编译有时候跟反汇编不一定要进函数看,有时候从上下文就能大概猜出函数的作用第九课c语言21、什么是裸函数可以看到......
  • 深度学习入门(鱼书)笔记(持续更新)
    深度学习入门笔记python基础知识numpy库importnumpyasnpnumpy数组(numpy.ndarray):np.array(list)np数组算术运算需元素个数相同,否则报错。np数组间的算术运算为element-wise,即对应元素的运算。np数组与单一数值(标量)的运算为广播,即标量自动补全与数组各元素计算。......
  • (笔记)FPGA多周期路径及set_multicycle_path详解
    默认情况下综合工具会把每条路径定义为单周期路径,即源触发器在时钟的任一边沿启动(launch)的数据都应该由目的触发器在时钟的下一上升沿捕获(capture)。有的设计可能存在时序例外(timingexceptions),如多周期路径、虚假路径等。数据从起点到终点的传输时间需要一个时钟周期以上才能稳定......
  • Git详细入门笔记
    主要分为两个一个是可视化软件,一个就是鼠标右键选择GitBash一、可视化软件1、文件操作点击file选项,可以选择添加clone,也可以add或者newnew完文件之后,可以点击图形界面中的showinexplorer,直接进入文件夹在文件夹中操作,然后回到图形界面2、分支操作分支操作就......
  • 滴水逆向笔记系列 - 4.内存地址_堆栈-5.标志寄存器-6.JCC命令
    第四课内存地址_堆栈内存地址db与dd命令db:d表示查找,b表示bytedd:d表示查找,d表示dworddb命令在数据区找出目的内存地址,发现数据区内和堆栈区显示的是相反的反汇编窗口和寄存器窗口的都是从高位到低位,数据区反之(比如数据0x12345678,12是高位,8是低位)所以0012FFDC这块内存(1字节)......
  • 滴水逆向笔记系列-1.进制-2.数据宽度_逻辑运算-3.通用寄存器_内存读写
    第一课进制这节课讲进制计算的核心就是查表例:3+5,就是从上表的3开始往后数五个数,10例:46则是看作6+6+6+6,6+6由上表可知为14,14再往后数12个数得出为46=30八进制复杂计算(文字比较难说明,但是大致还是和我们十进制的计算方式一样,只是九九乘法表换成上面三张表作业1.成立。可以以5......
  • Windows逆向之配置虚拟机环境
    安装虚拟机环境首先下载吾爱破解论坛专用版虚拟机软件VMWareWorkstation12,注册成功;再通过虚拟机启动论坛提供的WinXP系统镜像,在我的win11上完美运行。实现文件互传为了实验方便,下面要配置物理机和虚拟机之间的文件互传功能。我尝试用过VMware自带的共享文件夹和复制粘贴,但出......