4.5~4.7

接着上面4.4的部分
/*下一次课的题目:目前有三组信息:
名字:tony,18,leader,口头禅“今天我必须是最帅的一个”,
名字:red,12,committee,口头禅“我必须是今天最帅的一个”,
名字:black,16,student,口头禅“今天最帅的一个必须是我”,

要求:定义一个结构体去存储这些信息,且使用尽可能少的内存区域去存储这些信息。结构体赋值和打印必须使用专门的函数。提示:可以使用各种数据类型,可以使用映射关系减少落地内存,也可以使用位操作。
程序流程:结构体初始化,结构体挨个赋值,最后是结构体信息打印输出,输出结构体信息的同时一并输出当前结构体内存大小。
而且赋值和打印,必须是你们自己写的专用函数*/
 
#include
#include 
#include 
    typedef struct Databese
    {
	char name[5];
    	int age;
    	char occupation[10];
    	char mantra[20];
	}ds;
	
    void Input(ds *member , int n);
    void Output(ds *member,int n);
  
  int main()
  {
  	ds member[3]={0};//初始化 
  	Input(member ,sizeof(member)/sizeof(member[0]));
  	Output(member,sizeof(member)/sizeof(member[0]));
  	return 0;
  }

	 void Input(ds *member , int n)
	 {
	 	int i=0;
	 	for(i=0;i<n;i++)
	 	{ 
	 	  printf("名字:");
	      scanf("%s %d %s %s",&member[i].name,&member[i].age,&member[i].occupation,&member[i].mantra);//这里没用scanf_函数
		}
	 }

     void Output(ds *member,int n)
	 {
     	int i=0;
     	int size=0;
     	for(i=0;i<n;i++)
		 {
		    size=sizeof(member[i]);
		 	printf("名字:%s %d %s %s\n",member[i].name,member[i].age,member[i].occupation,member[i].mantra);
		    printf("%d\n",size);
		 } 
	 }
	 
	 //问题:1.上面我自己没有申请空间,用堆空间,系统自动分配的栈空间,所利用的大小,是不是自动分配会可以通过自己计算规划内存呢?
	 //2.如果用单向链表,是否会减小内存的使用?
	 // 3.位操作不是很熟悉
#include
#include 
#include 
#include
#define LEN sizeof(struct Databese)
 typedef struct Databese
      {
	    char name[5];
    	int age;
    	char occupation[10];
    	char mantra[20];
    	struct Databese *next;
      }ds;
      
   ds *input();
   ds  output(ds *head);
   int main()
   {
   	ds *head;
   	head=input();
   	output(head);
   }
   
   ds*input()
   {
   	int i=0;
    char name[5]={0};
    int age=0;
    char occupation[10]={0};
    char mantra[40]={0};
    ds *head=NULL,*p=NULL,*tmp=NULL;
    p=(ds*)malloc(LEN);
    if(p==NULL)
    {
    	return 0;
	}
	printf("名字:");
	scanf("%s %d %s %s",&name,&age,&occupation,&mantra);
	strcpy(p->name,name);
	p->age=age;
	strcpy_s(p->occupation,10,occupation );
    strcpy_s(p->mantra,40,mantra );
    head=p;
    for(i=0;i<2;i++)
    {
    	 tmp=(ds*)malloc(LEN);
    	 if(tmp==NULL)
        {
    	return 0;
	    }
	    printf("名字:");
     	 scanf("%s %d %s %s",&name,&age,&occupation,&mantra);
	     strcpy(tmp->name, name);
         tmp->age=age;
	    strcpy_s(tmp->occupation,10,occupation );
        strcpy_s(tmp->mantra,40,mantra);
        p->next=tmp;
        p=p->next;
    }
	return head;
   }
    ds  output(ds *head)
    {
    	int size=0;
    	ds*p;
    	for(p = head; p != NULL; p = p->next)
    	{
    	 size=sizeof(p);
    	 printf("名字:%s %d %s %s\n",p->name,p->age,p->occupation,p->mantra);
    	 printf("%d\n",size);
    	}
}

//问题:在input里最开始mantra我写的是mantra[20],运行发现无法输出,后面改成了[40],结构体里面没做改变
//确实这里的结构体变小了
//上个代码得到的大小是44,而在这段代码中是8

存在的问题
为什么写了两段?
第一个没有用链表的方式,函数自动分配的空间栈区,第二个是用的单向链表,用的malloc申请的空间,堆区
但实际上堆空间,或者栈空间,其实都算存储内容的空间
链表:
其实可以通过指针的方式,达到减少内存使用的目的。代码上有代码复用,内容上也是可以通过指针的方式进行复用

补充
之前提到的VirtualAlloc中的flAllocationType,参数是可以使用位组合的方式,进行传参的,例如:flAllocationType =就可以这么填:MEM_COMMIT | MEM_RESERVE
MEM_COMMIT = 0x00001000
MEM_RESERVE = 0x00002000 其实就相当于这两个值,进行一个或运算
4.5~4.7_第1张图片https://learn.microsoft.com/zh-cn/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc
MEM_COMMIT = 0x00001000 0001000000000000
MEM_RESERVE = 0x00002000 0010000000000000
0001000000000000
0010000000000000
或运算后,得到 0011000000000000
就能达到,一个DWORD ,传递两个状态的目的
要提取一个DWORD 中的每一个状态,相应的用&运算
0011000000000000 & 0010000000000000 = 0010000000000000 就能知道当前位是由有值

typedef struct Databese
      {
     char name[5];
     int age;
     char occupation[10];
     char mantra[20];
     struct Databese *next;
      }ds;

目前你们的存储区域是事先定义好的,根据内容动态申请得到的内存才是比较小的。事先定义,都会有冗余空间出现
这个结构体,其实还有一个问题,就是年龄这一项
没必要用int
首先,年龄,是没有负数的,所以用一个带符号的类型,就欠妥了
其次是,数据表示范围
其实一个bytes 也就是UCHAR ,0-FF 完全足够表示人的年龄,开一个int 就奢侈了

第二段代码,里面的sizeof§等于8的问题?

因为你这个是一个64位的指针,所以长度恒定是8

而且上一个结构体,大小是44,你觉得是真实的大小么?44 是大了,还是小了?

typedef struct Databese
      {
     char name[5];
     int age;
     char occupation[10];
     char mantra[20];
     struct Databese *next;
      }ds;

5 + 4 + 30 + 4
内存对齐问题
https://cloud.tencent.com/developer/article/1703257
所以里面这些项改变位置之后,有可能得到sizeof的值会变
还有最后一个,我给的内容里面,口头禅,三个人其实是
一句话调换了顺序而已

11个字,那么只需要11个状态,就能把这三句话存储完成。
按照,存储最小状态所用空间* 11,就能把这三组状态值存下来
最不过,最后输出的时候,是需要在你们的自定义函数里面,把这些状态值,还原为每一个文字
这个也就是映射表的一个应用

p=(ds*)malloc(LEN);
    if(p==NULL)
    {
     return 0;
 }
 printf("名字:");
 scanf("%s %d %s %s",&name,&age,&occupation,&mantra);
 strcpy(p->name,name);
 p->age=age;
 问题:
 这个P 申请之后,记得检查参数,但是没有进行初始化,
 之前说过的ZeroMemory 或者memset

这个对齐粒度,有些系统结构体内存块,会出现空隙的
这些地方,在某些操作中是可以利用的
包括,PE文件的节布局里面也是遵循这个内存对齐粒度,所以会有很多空的内存,包括PE注入代码的load等等,都可以利用这些空间去存放代码
因为像操作系统中设计的结构体
有些项目数达几百项
所以要做到内存空间充分利用几乎是不可能的
而这个内存对齐,有个好处,就是内存块加载的时候
按对齐粒度走,会非常快
具体原因,得看到底层的内存管理算法,才能得知

最后看一个别人写得比较好的代码

#include 
#include 
#include 
#include 
struct student
{
    unsigned short id : 2;        // min = 0 max = 3
    unsigned short ageOffset : 3; // min = 12 max = 12+7 XDDDDDD who thought this ???
    unsigned short tag1 : 3;
    unsigned short tag2 : 3;
    unsigned short tag3 : 3;
    unsigned short tag4 : 3;
    unsigned short tag5 : 3;
    unsigned short unused : 4; // align
};
static char globalNames[] = "tony\0red\0black";
static char globalTags[] = "今天\0我\0必须\0是\0最帅的一个";
// static wchar_t globalTags[] = "今天\0我\0必须\0是\0最帅的一个";
static char globalPositions[] = "leader\0committee\0student";
void initStruct(struct student *students, int count)
{
    // strcpy_s(students->name, 5, "tony");
    students->id = 0;
    students->ageOffset = 6;
    students->tag1 = 0;
    students->tag2 = 1;
    students->tag3 = 2;
    students->tag4 = 3;
    students->tag5 = 4;
    students++;
    // strcpy_s(students->name, 5, "red");
    students->id = 1;
    students->ageOffset = 0;
    students->tag1 = 1;
    students->tag2 = 2;
    students->tag3 = 3;
    students->tag4 = 0;
    students->tag5 = 4;
    students++;
    // strcpy_s(students->name, 6, "black"); // \0 is unnecessary, XD
    students->id = 2;
    students->ageOffset = 4;
    students->tag1 = 0;
    students->tag2 = 4;
    students->tag3 = 2;
    students->tag4 = 3;
    students->tag5 = 1;
}
char *getCharByOffest(char *globalChar, unsigned int offest)
{
    char *p = globalChar;
    for (unsigned int i = 0; i < offest; i++)
    {
        while (*p != '\0')
        {
            p++;
        }
        p++;
    }
    return p;
}
// wchar_t *getTag(short tag)
// {
//     wchar_t *tagPointer = &globalTags;
//     for (short i = 0; i < tag; i++)
//     {
//         while (*tagPointer != L'\0')
//         {
//             tagPointer++;
//         }
//         tagPointer++;
//     }
//     return tagPointer;
// }
void printStruct(struct student *students, int count)
{
    for (int i = 0; i < count; i++, students++)
    {
        printf("name:%s\n", getCharByOffest(globalNames, students->id));
        wprintf(L"age:%d\n", students->ageOffset + 12);
        printf("position:%s\n", getCharByOffest(globalPositions, students->id));
        printf("tag:%s%s%s%s%s\n",
               getCharByOffest(globalTags, students->tag1),
               getCharByOffest(globalTags, students->tag2),
               getCharByOffest(globalTags, students->tag3),
               getCharByOffest(globalTags, students->tag4),
               getCharByOffest(globalTags, students->tag5));
        // wprintf(L"tag:%ls%ls%ls%ls%ls\n",
        //         getTag(students->tag1),
        //         getTag(students->tag2),
        //         getTag(students->tag3),
        //         getTag(students->tag4),
        //         getTag(students->tag5));
        wprintf(L"\n");
    }
    wprintf(L"sizeof(struct students) == %d\n", sizeof(struct student));
}

int main(int argc, char const *argv[])
{
    // printf("welcome?\n");
    // char a[] = "hello世界";
    // printf("%s\n",a);
    // wprintf(L"你好世界%s\n",a);
    // return 0;

    // printf("welcome?\n");
    // wchar_t a[] = L"hello世界";
    // printf("%ls\n",a);
    // wprintf(L"你好世界%ls\n",a);
    // return 0;

    // printf("welcome?\n");
    // wchar_t b[10];
    // ZeroMemory(b,20);
    // mbstowcs(b,"测试",10);
    // wprintf(L"你好世界,%ls\n",b);
    // return 0;

    struct student *students = (struct student *)malloc(sizeof(struct student) * 3);
    initStruct(students, 3);
    printStruct(students, 3);
    return 0;
}

其实就是存储空间复用
结构体中,只保存索引
这种模式,在很多程序中,非常常见
要从汇编层面,去解读,首先你得知道有种模式
这个函数就是根据索引去局部变量存储区域去拿对应的字符串
wprintf(L"age:%d\n", students->ageOffset + 12); 这个 age 的最终打印
其实和跳转表构建的思路差不多
三个值,砍掉公共部分,剩下的就按顺序放入case 跳转数组里面
https://blog.csdn.net/qq_44372652/article/details/109799099
在这里插入图片描述但参数检查,这块还是没有注意
内存对齐,于正常程序而已,可以加快加载的速度,但是从攻击角度看,对齐后多多少少都会有冗余空间,
这些内存空间,就可以存放shellcode 而且是不被其他代码干扰的空间
能够长时间存活的
这些冗余空间足够的话,甚至都不用调用内存申请接口去要新的空间
这里涉及一个检测点,在细粒度的监控程序中,其实进程的所有内存申请操作是会被监控的
由于内存监控,会影响程序性能,往往是采用异步的方式
所以,在实施攻击的代码中,尽可能少的做动作,有利于,存活
计算机攻防,就是在这种一个个技术背景下,逐个展开的,不同层面,涉及的问题不同而已

你可能感兴趣的:(上课内容,c语言,学习)