pwn学习笔记(11)--off_by_one

pwn学习笔记(11)–off_by_one

​ 在处理for循环或者while循环的时候,有的可能会遇到如下情况:

#include<stdio.h>int main(){char buf[0x10];for (int i = 0 ; i <= 0x10 ; i ++){buf[i] = getchar();}puts(buf);}

​ 多次输入几个a之后,发现了最后输出的时候输出了17个a,我的目的仅仅只是需要16个a,结果输出了17个a,像这种,在写入字符串的时候多写入了一个字节的情况,就是off by one。

​ 在堆中,这种问题尤为严重,可能会导致输入的字符覆盖了heap info的prev_in_use或者其他的数据:

  1. 溢出字节为可控制任意字节:通过修改大小造成块结构之间出现重叠,从而泄露其他块数据,或是覆盖其他块数据。也可使用 NULL 字节溢出的方法
  2. 溢出字节为 NULL 字节:在 size 为 0x100 的时候,溢出 NULL 字节可以使得 prev_in_use 位被清,这样前块会被认为是 free 块。(1) 这时可以选择使用 unlink 方法(见 unlink 部分)进行处理。(2) 另外,这时 prev_size 域就会启用,就可以伪造 prev_size ,从而造成块之间发生重叠。此方法的关键在于 unlink 的时候没有检查按照 prev_size 找到的块的大小与prev_size 是否一致。

​ 最新版本代码中,已加入针对 2 中后一种方法的 check ,但是在 2.28 及之前版本并没有该 check 。

/* consolidate backward */if (!prev_inuse(p)) {prevsize = prev_size (p);size += prevsize;p = chunk_at_offset(p, -((long) prevsize));/* 后两行代码在最新版本中加入,则 2 的第二种方法无法使用,但是 2.28 及之前都没有问题 */if (__glibc_unlikely (chunksize(p) != prevsize))malloc_printerr ("corrupted size vs. prev_size while consolidating");unlink_chunk (av, p);}

​ 还有种情况:

#include<stdio.h>
#include<string.h>char bss[0x20] = "aaaaaaaaaaaaaaaa";int main(){char buf[0x10];if (strlen(bss) == 0x10){strcpy(buf,bss);}puts(buf);
}

​ 这种情况,乍看上去没啥问题,但是,strlen不会计算结尾的\x00,而strcpy在拷贝的时候又会多拷贝一个\x00进去,造成多写入了一个字节。

​ 上一个题:

Asis CTF 2016 b00ks(只看前面off by one的部分)

​ checksec 一下看看:

g01den@MSI:/mnt/c/Users/20820/Downloads$ checksec pwn
[*] '/mnt/c/Users/20820/Downloads/pwn'Arch:     amd64-64-littleRELRO:    Full RELROStack:    No canary foundNX:       NX enabledPIE:      PIE enabled

​ 激活了PIE,以及题目附件被strip过,抱歉,我一个菜鸡误入了大佬的世界,啥都看不懂,反编译之后看到那么抽象突然想放弃了,不过还是得做。

​ 题目是一个寻常的图书管理,有创建书,删除书,编辑描述内容,输出书籍信息,修改最近访问的作者名,退出。

​ 先不看别的,main没啥用,先看add:

__int64 sub_F55()
{int v1; // [rsp+0h] [rbp-20h] BYREFint v2; // [rsp+4h] [rbp-1Ch]void *v3; // [rsp+8h] [rbp-18h]void *ptr; // [rsp+10h] [rbp-10h]void *v5; // [rsp+18h] [rbp-8h]v1 = 0;printf("\nEnter book name size: ");__isoc99_scanf("%d", &v1);if ( v1 < 0 )goto LABEL_2;printf("Enter book name (Max 32 chars): ");ptr = malloc(v1);if ( !ptr ){printf("unable to allocate enough space");goto LABEL_17;}if ( (unsigned int)readName(ptr, v1 - 1) ){printf("fail to read name");goto LABEL_17;}v1 = 0;printf("\nEnter book description size: ");__isoc99_scanf("%d", &v1);if ( v1 < 0 ){
LABEL_2:printf("Malformed size");}else{v5 = malloc(v1);if ( v5 ){printf("Enter book description: ");if ( (unsigned int)readName(v5, v1 - 1) ){printf("Unable to read description");}else{v2 = sub_B24();if ( v2 == -1 ){printf("Library is full");}else{v3 = malloc(0x20uLL);if ( v3 ){*((_DWORD *)v3 + 6) = v1;*((_QWORD *)off_202010 + v2) = v3;*((_QWORD *)v3 + 2) = v5;*((_QWORD *)v3 + 1) = ptr;*(_DWORD *)v3 = ++unk_202024;return 0LL;}printf("Unable to allocate book struct");}}}else{printf("Fail to allocate memory");}}
LABEL_17:if ( ptr )free(ptr);if ( v5 )free(v5);if ( v3 )free(v3);return 1LL;
}

​ 分析一波,有一些需要记住作用的阿变量名,比如v1:

  • v1可以很明显看出来,v1是存放的是book的name的大小,ptr就是name存放的地址:

  •   v1 = 0;printf("\nEnter book name size: ");__isoc99_scanf("%d", &v1);if ( v1 < 0 )goto LABEL_2;printf("Enter book name (Max 32 chars): ");ptr = malloc(v1);
    
  • 之后重新用了v1来存放book的description的大小v5就是description存放的地址:

  • printf("\nEnter book description size: ");__isoc99_scanf("%d", &v1);if ( v1 < 0 ){
    LABEL_2:printf("Malformed size");}else{v5 = malloc(v1);
    
  • 之后开了个v3,存放了book的所有信息:

  • v3 = malloc(0x20uLL);if ( v3 ){*((_DWORD *)v3 + 6) = v1;*((_QWORD *)off_202010 + v2) = v3;*((_QWORD *)v3 + 2) = v5;*((_QWORD *)v3 + 1) = ptr;*(_DWORD *)v3 = ++unk_202024;return 0LL;}
    
  • 这里似乎,v3+6的偏移存放的是书的描述的长度,v2是与book的结构体数组头的偏移,*((_QWORD *)off_202010 + v2) = v3;这里是将新分配的结构体地址放入结构体数组指针里,之后将v5,也就是book的description的地址放给v3偏移为2的地方,ptr,也就是name的地址放入v3偏移为2的地方。

​ 这里面还存在一个函数,就是readName:

__int64 __fastcall sub_9F5(_BYTE *a1, int a2)
{int i; // [rsp+14h] [rbp-Ch]if ( a2 <= 0 )return 0LL;for ( i = 0; ; ++i ){if ( (unsigned int)read(0, a1, 1uLL) != 1 )return 1LL;if ( *a1 == 10 )break;++a1;if ( i == a2 )break;}*a1 = 0;return 0LL;
}

​ 分配两次,代码类似这样:

add(0x20,"book1_name",200,"book1_destruct")
add(0x21000,"book1_name",0x21000,"book1_destruct")

​ 这个函数存在一些问题,a1 是我们想要写入的字符串的起始地址,a2是判定边缘,但是,从0开始,一直到a2为止,很显然多进行了一次读入,因为这里的逻辑是先读入,再判断i与a2是否相等,所以这里就多循环了一次,造成了offbyone,结束循环之后,又将后一位的内存修改成了\x00,因此发生了溢出,例如一个数组是32字节,这个程序调用这个函数的时候,一直都是用的size-1,所以传入的是31,这个程序就刚好做到了让整个数组刚好可以写满,也就是写道buf[31],这里刚好写满,但是,有个关键的问题,最后一个还操作了一下,让*a1=0,这也就导致了buf[32]=0的发生,溢出了一个字节,也就造成了offbyone,或者说off by null。

​ 上gdb看看,先输入32个a作为名字之后,那段内存变成了这样:

pwndbg> search aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Searching for value: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
pwn             0x555555602040 0x6161616161616161 ('aaaaaaaa')
pwndbg> x/30gx 0x555555602040
0x555555602040: 0x6161616161616161      0x6161616161616161
0x555555602050: 0x6161616161616161      0x6161616161616161
0x555555602060: 0x0000000000000000      0x0000000000000000
0x555555602070: 0x0000000000000000      0x0000000000000000
0x555555602080: 0x0000000000000000      0x0000000000000000
0x555555602090: 0x0000000000000000      0x0000000000000000
0x5555556020a0: 0x0000000000000000      0x0000000000000000
0x5555556020b0: 0x0000000000000000      0x0000000000000000
0x5555556020c0: 0x0000000000000000      0x0000000000000000
0x5555556020d0: 0x0000000000000000      0x0000000000000000
0x5555556020e0: 0x0000000000000000      0x0000000000000000
0x5555556020f0: 0x0000000000000000      0x0000000000000000
0x555555602100: 0x0000000000000000      0x0000000000000000
0x555555602110: 0x0000000000000000      0x0000000000000000
0x555555602120: 0x0000000000000000      0x0000000000000000

​ 这里我想着直接通过IDA反编译的来确定这俩BSS段数据的地址的,结果IDA里莫名其妙的,有点怪怪的,这里就直接GDB调算偏移然后算真实地址之类的吧。首先,刚刚那里确定了作者name的那个地址为:0x555555602040,gdb里调的时候查到elf的基地址为:0x555555400000(手动计算出来的),然后算出bss里作者name的偏移为:0x202040,加起来之后和0x555555602040这个地址一样,所以,可以断定,这个地址就是存放作者名字的地方,之后,经过两次申请内存之后,再看看0x555555602040地址的内存(根据结构体指针数组在bss段上,然后暴力经过两次malloc之后查询bss段内容有无变化发现了一些少量变化,由此定位结构体指针数组的地址):

pwndbg> x/30gx 0x555555602040
0x555555602040: 0x6161616161616161      0x6161616161616161
0x555555602050: 0x6161616161616161      0x6161616161616161
0x555555602060: 0x00005555556037a0      0x00005555556037d0
0x555555602070: 0x0000000000000000      0x0000000000000000
0x555555602080: 0x0000000000000000      0x0000000000000000
0x555555602090: 0x0000000000000000      0x0000000000000000
0x5555556020a0: 0x0000000000000000      0x0000000000000000
0x5555556020b0: 0x0000000000000000      0x0000000000000000
0x5555556020c0: 0x0000000000000000      0x0000000000000000
0x5555556020d0: 0x0000000000000000      0x0000000000000000
0x5555556020e0: 0x0000000000000000      0x0000000000000000
0x5555556020f0: 0x0000000000000000      0x0000000000000000
0x555555602100: 0x0000000000000000      0x0000000000000000
0x555555602110: 0x0000000000000000      0x0000000000000000
0x555555602120: 0x0000000000000000      0x0000000000000000

​ 发现0x555555602060这个地址的内容变了,并且,还是某个书的结构体的数据域的地址:

pwndbg> x/30gx 0x00005555556037a0
0x5555556037a0: 0x0000000000000001      0x00005555556036b0
0x5555556037b0: 0x00005555556036d0      0x00000000000000c8
0x5555556037c0: 0x0000000000000000      0x0000000000000031
0x5555556037d0: 0x0000000000000002      0x00007ffff7d66010
0x5555556037e0: 0x00007ffff7d44010      0x0000000000021000
0x5555556037f0: 0x0000000000000000      0x0000000000020811
0x555555603800: 0x0000000000000000      0x0000000000000000
0x555555603810: 0x0000000000000000      0x0000000000000000
0x555555603820: 0x0000000000000000      0x0000000000000000
0x555555603830: 0x0000000000000000      0x0000000000000000
0x555555603840: 0x0000000000000000      0x0000000000000000
0x555555603850: 0x0000000000000000      0x0000000000000000
0x555555603860: 0x0000000000000000      0x0000000000000000
0x555555603870: 0x0000000000000000      0x0000000000000000
0x555555603880: 0x0000000000000000      0x0000000000000000

​ 刚好整个程序存在一个修改作者名字的功能,可以修改作者名字,进行第二次off by null,修改0x00005555556036f0为0x0000555555603600:

pwndbg> x/30gx 0x555555602040
0x555555602040: 0x6262626262626262      0x6262626262626262
0x555555602050: 0x6262626262626262      0x6262626262626262
0x555555602060: 0x0000555555603700      0x00005555556037d0
0x555555602070: 0x0000000000000000      0x0000000000000000
0x555555602080: 0x0000000000000000      0x0000000000000000
0x555555602090: 0x0000000000000000      0x0000000000000000
0x5555556020a0: 0x0000000000000000      0x0000000000000000
0x5555556020b0: 0x0000000000000000      0x0000000000000000
0x5555556020c0: 0x0000000000000000      0x0000000000000000
0x5555556020d0: 0x0000000000000000      0x0000000000000000
0x5555556020e0: 0x0000000000000000      0x0000000000000000
0x5555556020f0: 0x0000000000000000      0x0000000000000000
0x555555602100: 0x0000000000000000      0x0000000000000000
0x555555602110: 0x0000000000000000      0x0000000000000000
0x555555602120: 0x0000000000000000      0x0000000000000000

​ 那么,0x0000555555603600这个地址指向的地方是哪里呢?用heap指令看看:

pwndbg> heap
Allocated chunk | PREV_INUSE
Addr: 0x555555603000
Size: 0x290 (with flag bits: 0x291)Allocated chunk | PREV_INUSE
Addr: 0x555555603290
Size: 0x410 (with flag bits: 0x411)Allocated chunk | PREV_INUSE
Addr: 0x5555556036a0
Size: 0x20 (with flag bits: 0x21)Allocated chunk | PREV_INUSE
Addr: 0x5555556036c0
Size: 0xd0 (with flag bits: 0xd1)Allocated chunk | PREV_INUSE
Addr: 0x555555603790
Size: 0x30 (with flag bits: 0x31)Allocated chunk | PREV_INUSE
Addr: 0x5555556037c0
Size: 0x30 (with flag bits: 0x31)Top chunk | PREV_INUSE
Addr: 0x5555556037f0
Size: 0x20810 (with flag bits: 0x20811)

​ 发现这个地址是在book1_desc的中间:

pwndbg> x/50gx 0x5555556036c0
0x5555556036c0: 0x0000000000000000      0x00000000000000d1
0x5555556036d0: 0x65645f316b6f6f62      0x0000000000006373
0x5555556036e0: 0x0000000000000000      0x0000000000000000
0x5555556036f0: 0x0000000000000000      0x0000000000000000
0x555555603700: 0x0000000000000000      0x0000000000000000			<-------------------
0x555555603710: 0x0000000000000000      0x0000000000000000
0x555555603720: 0x0000000000000000      0x0000000000000000
0x555555603730: 0x0000000000000000      0x0000000000000000
0x555555603740: 0x0000000000000000      0x0000000000000000
0x555555603750: 0x0000000000000000      0x0000000000000000
0x555555603760: 0x0000000000000000      0x0000000000000000
0x555555603770: 0x0000000000000000      0x0000000000000000
0x555555603780: 0x0000000000000000      0x0000000000000000
0x555555603790: 0x0000000000000000      0x0000000000000031
0x5555556037a0: 0x0000000000000001      0x00005555556036b0
0x5555556037b0: 0x00005555556036d0      0x00000000000000c8
0x5555556037c0: 0x0000000000000000      0x0000000000000031
0x5555556037d0: 0x0000000000000002      0x00007ffff7d66010
0x5555556037e0: 0x00007ffff7d44010      0x0000000000021000
0x5555556037f0: 0x0000000000000000      0x0000000000020811
0x555555603800: 0x0000000000000000      0x0000000000000000
0x555555603810: 0x0000000000000000      0x0000000000000000
0x555555603820: 0x0000000000000000      0x0000000000000000
0x555555603830: 0x0000000000000000      0x0000000000000000
0x555555603840: 0x0000000000000000      0x0000000000000000

​ 内存布局大概有了,这里借用某位大佬的图(hollk):

在这里插入图片描述

​ 修改了book1的结构体指针地址之后,因为book1_name这里是可控的,所以可以在指向的那个地址伪造一个fake_chunk,

​ 因为后面确实对我而言有点逆天,所以之后就简述了吧,之后就是伪造chunk泄露libc地址,然后继续伪造fakechunk修改__free_hook为one_gadget,即可拿到shell。

 0x0000000000000000

0x555555603830: 0x0000000000000000 0x0000000000000000
0x555555603840: 0x0000000000000000 0x0000000000000000


​		内存布局大概有了,这里借用某位大佬的图(hollk):[外链图片转存中...(img-sbaqzceF-1731158930159)]​		修改了book1的结构体指针地址之后,因为book1_name这里是可控的,所以可以在指向的那个地址伪造一个fake_chunk,​		因为后面确实对我而言有点逆天,所以之后就简述了吧,之后就是伪造chunk泄露libc地址,然后继续伪造fakechunk修改`__free_hook`为one_gadget,即可拿到shell。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/10023.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

YOLOv8模型改进 第十九讲 添加倒置残差移动块iRMB(Inverted Residual Mobile Block,) 去除图像噪声

本文这次分享的是倒置残差移动块iRMB&#xff0c;iRMB&#xff08;Inverted Residual Mobile Block&#xff09;的作用主要是在神经网络中实现高效的特征提取&#xff0c;它融合了卷积神经网络&#xff08;CNN&#xff09;捕捉局部特征的高效性和 Transformer 动态建模长距离交…

express项目中使用MySQL

一、安装mysql 模块 1.1 先配置包管理工具 npm init -y1.2、安装mysql 模块 npm install mysql2二、配置mysql // 1、导入mysql模块 const mysql require("mysql2");// 2、建立与mysql 数据库的链接 const db mysql.createPool({host: "127.0.0.1", …

泛微E9 OA与金蝶云的差旅费报销接口集成

FD001-差旅费报销申请 泛微>金蝶--498 集成案例分享 在企业日常运营中&#xff0c;差旅费报销申请的处理效率直接影响到员工满意度和财务管理的精确性。为了实现泛微OA-Http系统与金蝶云星空平台之间的数据无缝对接&#xff0c;我们设计并实施了FD001-差旅费报销申请集成方…

新疆高校大数据实验室案例分享

高校大数据实验室建设&#xff0c;企业可以提供技术支持、实训平台和项目案例&#xff0c;高校则提供科研和教学资源&#xff0c;实现产学研一体化。不仅有利于大数据技术的应用和人才培养也有利于区域发展。 泰迪与新疆合作的院校包括新疆大学、昌吉学院等 新疆大…

11.9.2024刷华为

文章目录 HJ31 单词倒排HJ32 密码提取语法知识记录 傻逼OD题目又不全又要收费&#xff0c;看毛线&#xff0c;莫名奇妙 HW这叼机构别搁这儿害人得不得&#xff1f; 我觉得我刷完原来的题目 过一遍华为机考的ED卷出处&#xff0c;就行了 HJ31 单词倒排 游戏本做过了好像 HJ3…

C语言--结构体的大小与内存对齐,位段详解

一.前言 为了保证文章的质量和长度&#xff0c;小编将会分两篇介绍&#xff0c;思维导图如下&#xff0c;上篇已经讲过了概念部分&#xff0c;本文主要讲解剩余部分&#xff0c;希望大家有所收获&#x1f339;&#x1f339; 二.结构体的大小与内存对齐 2.1 存在对齐的原因 平…

腾讯混元3D模型Hunyuan3D-1.0部署与推理优化指南

腾讯混元3D模型Hunyuan3D-1.0部署与推理优化指南 摘要&#xff1a; 本文将详细介绍如何部署腾讯混元3D模型Hunyuan3D-1.0&#xff0c;并针对不同硬件配置提供优化的推理方案。我们将探讨如何在有限的GPU内存下&#xff0c;通过调整配置来优化模型的推理性能。 1. 项目概览 腾…

第18篇 :深入剖析systemverilog中 randomize 失败案例启示录(二)

今天我们继续修改之前的例子&#xff0c;你会有意想不到的收获。程序源代码&#xff0c;和上一节文章一样。 症状3&#xff1a; 这里&#xff0c;我们没有显式调用类的randomize() 函数&#xff0c;而是定义了一个类函数。在函数中 &#xff0c;重新约束了类内的随机变量。请…

CC音乐 1.0 | 纯净版音乐软件,内置3条音源,支持无损和母带下载

CC音乐是一款全新上架的第三方音乐软件&#xff0c;界面纯净简洁且无广告。内置三条音源接口&#xff0c;用户可以畅听全网音乐。软件涵盖了电台、排行榜、歌单分类、视频、歌手等多个栏目&#xff0c;即使是会员和灰色歌曲也能随意畅听。此外&#xff0c;CC音乐还支持下载无损…

【销帮帮-注册_登录安全分析报告-试用页面存在安全隐患】

联通支付注册/登录安全分析报告 前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨…

windows中docker安装redis和redisinsight记录

创建一个Redis运行容器&#xff0c;命令如下 docker run -it -d --name redis -p 6379:6379 redis --bind 0.0.0.0 --protected-mode no -d 代表Redis容器后台运行 --name redis 给创建好的容器起名叫redis -p 6379:6379 将容器的6379端口映射到宿主机的6379端口&#xff0c;注…

问题排查:C++ exception with description “getrandom“ thrown in the test body

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。 本作品 (李兆龙 博文, 由 李兆龙 创作)&#xff0c;由 李兆龙 确认&#xff0c;转载请注明版权。 文章目录 MotivationProcess Motivation 最近在做一个复杂系统集成到 Bazel 的工作。 在编译…

C++中类的默认成员函数

默认成员函数 1.构造函数2.析构函数3.拷贝构造函数4.赋值运算符重载4.1运算符重载4.2赋值运算符重载 #mermaid-svg-oipiwg9stvONvYK0 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-oipiwg9stvONvYK0 .error-icon{f…

从0开始学习机器学习--Day20--优化算法的思路

确定执行的优先级(Prioritizing what to work on : Spam classification example) 在建立学习系统前&#xff0c;我们不仅要梳理框架&#xff0c;更重要的是我们要弄清楚有哪些事情是要优先做的&#xff0c;这可以帮我们节约大量的时间。 以垃圾邮件为例&#xff0c;按照之前…

利用JS实现图片轮播(示例)

我们平时在逛购物网站的时候会看到页面内的商品图片自动轮播&#xff0c;二要想实现着中效果应该如何做呢&#xff1f;下面详细讲解代码的运用&#xff0c;实现下面视频的效果。大家也可以自己试试看&#xff0c;或者复制最后的完整代码运行一下&#xff01; 图片自动轮播效果 …

关于99.9% 达成读码率方案

1.标签样式 2.尺寸大小 长30mm*宽30mm 至 长40mm*宽40mm ; 3.位置 标签位置在箱体中间,可以误差5mm; 4.质量要求 ①无遮挡,标签不允许任何介质在上面,尤其是塑料片 ②平整,必须和箱子壁贴平,不允许翻边,飘荡。 ③码不能有模糊,手机摄像头扫码可以…

w~视觉~合集20~SAM

我自己的原文哦~ https://blog.51cto.com/whaosoft/12500982 #SAM 今天&#xff0c;Meta发布史上首个图像分割基础模型SAM&#xff0c;将NLP领域的prompt范式引进CV&#xff0c;让模型可以通过prompt一键抠图。网友直呼&#xff1a;CV不存在了! 就在刚刚&#xff0c;Meta AI…

三、直流有刷电机H桥驱动原理

1、H桥简介 H桥驱动电路&#xff1a;是一种用于控制直流电机正反转及速度的电路&#xff0c;其名称来源于其电路结构类似于字母“H”。H桥驱动电路由四个开关元件&#xff08;如晶体管、MOSFET等&#xff09;组成&#xff0c;这些开关元件被配置成可以控制电机两端电流的方向&…

Leetcode刷题

题目如下&#xff1a; 这道题呢&#xff0c;这里我写出了两种解决办法&#xff0c;一种遍历链表来得出中间结点&#xff0c;一种通过快慢指针来得出中间结点 第一种&#xff1a; 遍历&#xff1a; 首先我们设置一个计数器count&#xff0c;来记录链表的长度&#xff0c;写一…

游戏开发--C#面试题

游戏开发--C#面试题 C#1. 值类型和引用类型的区别2. 重载和重写的区别3. ArrayList和List的区别4. List底层是什么实现的&#xff1f;5. 抽象类和接口的区别6. 静态成员和⾮静态成员的区别7. 装箱和拆箱是指什么&#xff1f;8. 值和引用类型在变量赋值时的区别是什么&#xff1…