0%

36

1、迷失之门

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
def reverse_simulate_check(transformed_string):

​ v16 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" # 大写字母
​ v10 = "abcdefghijklmnopqrstuvwxyz" # 小写字母
​ v4 = "0123456789+/-=!#&*()?;:^%" # 特殊字符和数字
​ v3 = "DABBZXQESVFRWNGTHYJUMKIOLPC" # 转换基准

​ possible_inputs = []

# 遍历转换后的字符串

for i in range(len(transformed_string)):
​ transformed_char = transformed_string[i]
​ current_v3_char = v3[i % len(v3)]
​ possible_chars = []

# 检查 v16

for index, char in enumerate(v16):
if char == transformed_char:
​ original_char = chr(ord(current_v3_char) + index)
if 32 < ord(original_char) != 127:
​ possible_chars.append(original_char)

# 检查 v10

for index, char in enumerate(v10):
if char == transformed_char:
​ original_char = chr(ord(current_v3_char) + index + 26)
if 32 < ord(original_char) != 127:
​ possible_chars.append(original_char)

# 检查 v4

for index, char in enumerate(v4):
if char == transformed_char:
​ original_char = chr(ord(current_v3_char) + index + 52)
if 32 < ord(original_char) != 127:
​ possible_chars.append(original_char)

​ possible_inputs.append(possible_chars)

return possible_inputs

# 已转换后的字符串

transformed_string = "FSBBhKrVSGeafuZDJkuYqROaYY6"
original_input_possibilities = reverse_simulate_check(transformed_string)
for i, possibilities in enumerate(original_input_possibilities):
print(f"Character position {i+1} possible originals: {possibilities}")

得到flag ISCC{b|Ze\dlv|`WQ}xmw\Widh}

37

  1. 函数声明:这是main函数的入口,采用标准的C++形式,接收命令行参数。

  2. 关键逻辑分析

    • if (strlen(Buffer) <= 0x1B)
      

      :这个条件检查输入的长度是否小于等于27个字符。

      • 如果是,进入循环检查Buffer中的字符:

        • 循环从索引5到25,检查字符是否是小写字母或下划线(islower(Buffer[i]) || Buffer[i] == '_')。如果不是,v7设为0。
        • 调用check(Buffer)函数,此函数可能是用来检查Buffer中是否包含有效的flag。
    • 如果输入长度超过27个字符,输出一条错误消息并暂停。

Check

38

初始化了三个字符数组:

  • v16 存储大写字母 A-Z。

  • v10 存储小写字母 a-z。

  • v4 存储数字和特殊字符。

  • v3 存储了一个特定的字母序列 “DABBZXQESVFRWNGTHYJUMKIOLPC”,看起来像是一个密钥或映射。

  • 循环遍历输入字符串 a1

    ,对每个字符进行检查和变换:

    • 跳过ASCII值为127和小于等于32的字符(控制字符和空白)。
    • 对于其他字符,根据与v3中对应位置字符的差值,进行替换:
      • 如果差值小于或等于0,输出”flag is wrong”。
      • 如果差值在1到25之间,使用 v16(大写字母)中对应的字符替换。
      • 如果差值在26到51之间,使用 v10(小写字母)中对应的字符替换。
      • 如果差值大于51,使用 v4(数字和特殊字符)中对应的字符替换。

check2

39

验证输出,这里相当于直接告诉你flag要求了,写个脚本秒了

transformed_string = “FSBBhKrVSGeafuZDJkuYqROaYY6”

image-20240510231929311

image-20240510232036513

####队列

目录

一、队列的概念

二、入队

三、出队

四、获取队首元素

一、队列的概念

​ 队列是仅限在表尾进行插入,表头进行删除的线性表它遵循先进先出(First-In-First-Out,FIFO)的原则。队列就像排队等候的人群一样,最先进入队列的元素将首先被处理或移除。

​ 在计算机科学中,队列通常用于实现 排队系统、任务调度、消息传递(消息队列可用于进程间通信)。我们一般可以用 顺序表 或者 链表 来实现队列。

二、入队

1、入队的概念

​ 队列的插入操作叫做入队,它是将数据元素从队尾进行插入的过程。

2、入队的图解

​ 如图所示,4 号元素是原先的队尾,在它后面插入一个元素 6,就完成了入队的过程。

21

3、入队的步骤

​ 第1步、将元素添加到队列尾部,更新队尾指针(适用于链表)或者索引(适用于顺序表)。

​ 第2步、队列大小增加 1。

三、出队

1、出队的概念

​ 队列的删除操作叫做出队,它是将队首元素进行删除的过程。

2、出队的图解

​ 如图所示,直接删除队首的元素,并且更新为新的队首即可。

22

3、出队的步骤

​ 第1步、删除队首元素,更新队首指针(适用于链表)或者索引(适用于顺序表)。

​ 第2步、队列的大小减小 1。

四、获取队首元素

1、获取队首元素的概念

​ 返回队首指针(或者索引)指向的元素的值,无论是链表还是顺序表,都可以通过队首指针(或者索引)在 O(1) 的时间复杂度获取到队首元素。

2、获取队首元素的图解

​ 如图所示,直接通过队首指针(或者索引)获取队首元素。

23

3、获取队首元素的步骤

​ 第1步、利用队首指针(或者索引)获取队首元素并返回。由于是查询操作,所以不会改变队列本身的数据;

一、数据结构

对于模拟题而言,最关键的其实是数据结构,看到一个问题,选择合适的数据结构,然后根据问题来实现对应的功能。模拟题的常见数据结构主要就是:数组、字符串、矩阵、链表、二叉树 等等。

1、基于数组

利用数组的数据结构,根据题目要求,去实现算法,如:1920.基于排列构建数组、1389.按既定顺序创建目标数组、1603.设计停车系统、2149.按符号重排数组、2221.数组的三角和

2、基于字符串

利用字符串的数据结构,根据题目要求,去实现算法,如:2011.执行操作后的变量值、2744.最大字符串配对数目、LCP 17.速算机器人、537.复数乘法

3、基于链表

利用链表的数据结构,根据题目要求,去实现算法,如:2181.合并零之间的节点、1823.找出游戏的获胜者

4、基于矩阵

利用矩阵的数据结构,根据题目要求,去实现算法,如:2120.执行所有后缀指令、1252.奇数值单元格的数目、832.翻转图像、657.机器人能否返回原点、289.生命游戏、59.螺旋矩阵 II、885.螺旋矩阵 III

5、基于栈

利用栈的数据结构,如:1441.用栈操作构建数组

6、基于队列

利用队列的数据结构,如:1700.无法吃午餐的学生数量

二、算法技巧

模拟时一般会用到一些算法技巧,或者说混合算法,比如 排序、递归、迭代 等等。

1、排序

排序后,干一件事情,如:950.按递增顺序显示卡牌

2、递归

需要借助递归来实现,如:1688.比赛中的配对次数 、2169.得到 0 的操作数、258.各位相加

3、迭代

不断迭代求解,其实就是利用 while 循环来实现功能,如:1860.增长的内存泄露、258.各位相加

1

2

![Pasted image 20240309212457](/_posts/roulette/roulette/Pasted image 20240309212457.png)

![Pasted image 20240309212250](/_posts/roulette/roulette/Pasted image 20240309215815.png)![Pasted image 20240309215815 - 副本](/_posts/roulette/roulette/Pasted image 20240309215815 - 副本.png)9

![](/_posts/roulette/roulette/Pasted image 20240309215657.png)

6

![Pasted image 20240309215755](/pic/Pasted image 20240309215755.png)![0](/pic/Pasted image 20240309215921.png)

16520

6

7

8

9

10

11

12

顺序表

概念

顺序表是一种线性的数据结构,其中数据元素按照特定的顺序依次存储在连续的内存空间中。它由一系列元素组成,每个元素都与唯一的索引(或者叫下标)相关联,索引从 0 开始递增。

面向对象

类(实例)

构成

  • 对象(object)
    对象是类的一个实例

    • new调用类的构造器
      var p = new Person()

      • 声明

        • Person p;
      • 实例化

        • p变量(引用变量)只在栈内存中存储了一个地址值
          可以有多个指向同一个对象

        • Person
          对象存放在堆
          (heap)内存
          无指向时被回收

      • 初始化

        • p = new Person();
    • 对象的属性

      • 成员变量(域)field

        • 用于定义该类或该类的实例所包含的状态数据
          [修饰符] 类型 成员变量名 [=默认值]

          • 实例变量(对象属性) instance 独立

            • 实例.实例变量
              类.类变量
              实例.类变量(不推荐)

            • setter和getter方法

              • setXxx()
                getXxx()

              • 用于操作对象属性的常见模式,允许访问封装对象的状态并提供对属性的控制和访问

              • setter和getter方法合起来变成属性,如果只有getter方法,则是只读属性

          • 类变量(static)共享

    • 对象的作用

      • 封装数据和行为

      • 访问对象的实例变量

      • 调用对象的方法

    • this关键字

      • 让类中一个方法,访问该类里的另一个方法或实例变量

      • 所代表的只能是当前
        类的实例

      • this作为对象的默认引用

        • 构造器中引用该构造器正在初始化的对象

        • 方法中引用调用该方法的对象

      • 一个方法访问该类中定义的其他方法、成员变量时,
        加不加this前缀的效果是完全一样的,this仍然存在

      • static修饰的方法中不能使用this引用
        静态成员不能
        直接访问非静态成员

      • 如果构造器中有一个与成员变量同名的局部变量,又必须在构造器中访问这个被覆盖的成员变量,则必须使用this前缀

    • 实例初始化块

      • 用于初始化对象的实例成员变量,在构造器执行之前执行

      • 实例初始化块是在创建Java对象时隐式执行的,
        总是全部执行,因此可以把多个实例初始化块合并成一个实例
        初始化块,从而可以让程序更加简洁,可读性更强。

      • 如果有一段初始化处理代码对所有对象完全相同,且无须接收
        任何参数,就可以把这段初始化处理代码提取到实例初始化块中

  • 对象调用方法
    方法属于对象

  • 方法(method)(形参)
    类似于函数、但必须包含在类里

    • 方法的参数传递方式只有一种:值传递。就是将实际参数值的副本(复制品)传入方法内,而参数本身不会受到任何影响。

    • [修饰符] 方法返回值类型(void) 方法名(形参列表)
      {
      可执行性语句组成的方法体
      }

    • 执行方法

      • 类调用(static)

      • 对象调用

    • 定义局部变量

      • 形参(方法签名中定义)

方法局部变量(方法内定义)

代码块局部变量(代码块内定义)

        - 局部变量不属于任何类或实例,总是保存在栈内存中,保存基本变量的值和引用变量的地址

        - 局部变量定义后,必须经过显式初始化后才能使用

        - 能用代码块局部变量就不用方法局部变量

            - 扩大了变量的作用域,这不利于提高程序的内聚性。

            - 增大了变量的生存时间,这将导致更大的内存开销。

- 在方法中创建实例 var p = new Person()
                                   实例化

- 个数可变的形参(只能有一个)

- 递归方法

    - 基准情形

    - 不断推进

        - 向已知基准情形推进

    - 设计法则

        - 假设所有的递归调用都能执行

    - 合成效益法则

        - 求解同一问题时,切勿做重复性的工作

- 方法重载(Overload)

    - 只要形参列表不同 ,可以有多个同名方法

    - 两同一不同

        - 方法名必须相同("两同"),但参数列表必须不同("一不同")

    - 返回值不能区分重载

- toString()方法

    - 返回对象的类名,后跟对象的散列码(hash code)

    - 所有的Java对象都可以和字符串进行连接运算,系统自动调用Java对象

toString()方法的返回值和字符串进行连接运算

- equals()方法

    - Object类提供的一个实例方法,经常被重写使用

        -  ➢自反性:对任意x, x.equals(x)一定返回true

        - ➢ 对称性 : 对任意x和y, 如果y.equals(x)返回 true,则x.equals(y)也返回true

        - ➢ 传 递 性 : 对任意x,y,z,如果x.equals(y)返回ture,y.equals(z)返回true,则x.equals(z)一定返回true

        - ➢ 一致性:对任意x和y, 如果对象中用于等价比较的信息没有改变, 那么无论调用x.equals(y)多少次,返回的结果应该保持一致,要么一直是true,要么一直是false

        - ➢ 对任何不是null的x, x.equals(null)一定返回false

成员

  •             类成员
                (必须通过类来访问、调用)
    
                - 类成员(包括成员变量、方法、初始化块、内部类和内部枚举)不能访问
                  实例成员(包括成员变量、方法、初始化块、内部类和内部枚举)
    
                - 类方法
    
                  - 修饰符 static (void)方法名(形参列表){
                    }
                    public static void test(){}
    
                - 类变量
    
                  - public(修饰符) static 变量名(abcABC) 
                    [=默认值]
    
                  - 类变量生存范围几乎等同于该类的生存范围
    
                  - 类变量必须通过类来访问
    
                - 类初始化块 
    
                  - 负责对类进行初始化,总是比实例初始化块先执行
    
                  - 执行类初始化块时,系统会按照继承关系逐级上溯(到java.lang.Object类),执行每个父类的类初始化块,然后才执行当前类的类初始化块。
    
                  - static {可执行性代码}
    
                    - 初始化块的修饰符只能是static,使用static修饰的初始化块被
                      称为类初始化块(静态初始化块),没有static修饰的初始化块被称
                      为实例初始化块(非静态初始化块)
    
                - 构造器
    
                  - public(修饰符) 构造器名(形参列表)
                    {构造器执行体}(构造器必须与类名相同)
    
                    - 没有定义构造器,系统将为它提供一个默
                      认的构造器,系统提供的构造器总是没有参数的
    
                    - 通过new关键字来调用构造器,从而返回该类
                      的实例
    
                    - 一旦为一个类提供了构造器,系统将不再为该类提供构造
                      器
    
                    - 返回值是隐式的
    
                  - 构造器是创建对象的重要途径,Java类必须包含一个或一个以上的构造器。
    
                  - 构造器的重载
    
                    - 如果一个构造器B完全包含了另一个构造器A,可以使用this关键字来调用构造器A,不会创建新的对象实例。这称为构造器重载,在一个构造器中调用另一个构造器以共享初始化代码。可以避免重复的初始化代码,并确保对象的一致性。
    
                - 内部类
    
                  - public class OuterClass
                    {
                    //此处可以定义内部类
                    }
    
                  - 作用
    
                    - ➢ 内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类。假设需要创建Cow类,Cow类需要组合一个CowLeg对象,CowLeg类只有在Cow类里才有效,离开了Cow类之后没有任何意义。在这种情况下,就可把CowLeg定义成Cow的内部类,不允许其他类访问CowLeg
    
                    - ➢ 内部类成员可以直接访问外部类的私有数据,因为内部类被当成其外部类成员,同一个类的成员之间可以互相访问。但外部类不能访问内部类的实现细节,例如内部类的成员变量
    
                    - ➢ 匿名内部类适合用于创建那些仅需要一次使用的类。对于前面介绍的命令模式,当需要传入一个Command对象时,重新专门定义PrintCommand和SquareCommand两个实现类可能没有太大的意义,因为这两个实现类可能仅需要使用一次。在这种情况下,使用匿名内部类将更方便
    
                  - 区别
    
                    - ➢ 内部类比外部类可以多使用三个修饰符:private 、protected、static.外部类不可以使用这三个修饰符
    
                    - ➢ 非静态内部类不能拥有静态成员
    
                  - 4个作用域:同一个类、同一个包、父子类和任何位置,可以使用任意访问控制符
                    如private、protected和public等修饰
    
                  - 成员内部类
    
                    - class文件总是这种形式 :
                      OuterClass$InnerClass.class
    
                    - 非静态内部类
    
                      - 可以直接访问外部类的private成
                        员
    
                      - 保存
                        了一个它所寄生的外部类对象的引用(当调用非静态内部类的实例方
                        法时,必须有一个非静态内部类实例,非静态内部类实例必须寄生在
                        外部类实例里)
    
                      - 访问某个变量时,方法内-内部类内-包含内部类的外部类内
    
                      - 如果外部类成员变量、内部类成员变量与内部类里方法的
                        局部变量同名,则可通过使用this、外部类类名.this作为限定来区
                        分
    
                      - 非静态内部类可以访问外部类的实例成员,但外部类无法直接访问非静态内部类的实例成员。如果外部类需要访问非静态内部类的实例成员,必须通过创建内部类的实例来实现
    
                        - 当外部类对象被实例化时,非静态内部类的对象并不会自动存在或被创建
    
                      - 创建一个非静态内部类的实例,那么它一定会关联到一个外部类对象
    
                        - 外部类可以独立存在,而不包含内部类的实例
    
                      - 不允许在外部类的静态成员中直接使用非
                        静态内部类
    
                      - 不允许在非静态内部类里定义静态成员
    
                      - 不可以有静态初始化块,但可以包含普通初始
                        化块。非静态内部类普通初始化块的作用与外部类初始化块的作用
                        完全相同
    
                    - 静态内部类(static
                      修饰,类内部类)
                      使用static修饰可以将内部类变成外部类
                      相关,而不是外部类实例相关
    
                      - 类可以包含静态成员,也可以包含非静态成员
    
                      - 静态内部类不能访问外部类的实
                        例成员,只能访问外部类的类成员
    
                      - 即使是静态内部类的实例方法也
                        不能访问外部类的实例成员,只能访问外部类的静态成员
    
                      - 静态内部类对象只持有外部类的类引用,没有
                        持有外部类对象的引用
    
                      - 允许在接口里定义内部类,接口里定义的内部
                        类默认使用public static修饰,也就是说,接口内部类只能是静态内
                        部类
    
                  - 使用内部类
    
                    - 在外部类内部使用内部类
    
                      - 通过 new 关键字调用内部类的构造器来创建实例
    
                      - 不要在外部类的静态成员(包括静态方
                        法和静态初始化块)中使用非静态内部类
    
                      - 可以在外部类内部定义内部类的子类
    
                    - 在外部类以外使用非静态内部类
    
                      - 访问控制权限
    
                        - Private访问控制权限:不允许在外部类以外访问
    
                        - Public访问控制权限:允许在任何地方访问。
    
                        - 省略访问控制符:只能在与外部类位于同一包中的其他类中访问。
    
                        - Protected访问控制权限:允许在与外部类位于同一包中的其他类和外部类的子类中访问
    
                      - 内部类的完整类名
    
                        - 在外部类以外使用内部类时,内部类的完整类名:OuterClass.InnerClass varName。如果外部类有包名,则还应该增加包名前缀
    
                      - 创建非静态内部类的实例
    
                        - 在外部类以外创建非静态内部类的实例时,需要使用外部类实例和 new 调用内部类的构造器
                          outerInstance.new InnerConstructor()
    
                      - 创建非静态内部类的子类的实例
    
                        - 当创建非静态内部类的子类时,子类的构造器需要调用父类内部类的构造器,并且在构造子类的实例时需要确保外部类的实例存在
    
                      - 注意事项
    
                        - 静态成员无法访问非静态内部类,因为非静态内部类依赖于外部类对象的存在,而静态成员不依赖于具体对象的存在
    
                        - 在创建非静态内部类的子类实例时,需要确保父类内部类的构造器可以被调用,这要求外部类对象必须存在
    
                        - 如果有一个非静态内部类的子类对象存在,则一定存在一个对应的外部类对象
    
                    - 在外部类以外使用静态内部类
    
                      - OuterClass.StaticInnerClass obj = new OuterClass.StaticInnerClass();
    
                      - 创建内部类对象时,静态
                        内部类只需使用外部类即可调用构造器,而非静态内部类必须使用外
                        部类对象来调用构造器
    
                      - 相比之下,使用静态内部类比使用非静态内部类要简单很多,
                        只要把外部类当成静态内部类的包空间即可。因此当程序需要使用
                        内部类时,应该优先考虑使用静态内部类
    
                      - 内部类的类名不再是简单地由内
                        部类的类名组成,它实际上还把外部类的类名作为一个命名空间,作
                        为内部类类名的限制。因此子类中的内部类和父类中的内部类不能
                        完全同名,即使二者所包含的内部类的类名相同,但因为它们所处的
                        外部类空间不同,所以它们不可能完全同名,也就不可能重写。
    
                  - 局部内部类
    
                    - 作用范围仅限于包含它的方法内部,在方法的外部无法使用它。由于其作用范围的限制,局部内部类不能使用访问控制符或 static 修饰符
    
                    - 作用域限制
    
                      - 生命周期仅限于方法的调用和执行过程。
    
                    - 局部内部类因其局部性质,在实际开发中很少被使用。由于其作用域限制,无法离开定义它的方法,因此大部分情况下,定义一个类后希望该类能够被多次复用,而局部内部类无法满足这种需求
    
                    - 局部内部类的class文件
                      总是遵循如下命名格式:OuterClass$NInnerClass.class
    
                      - N是一个数字,表示不同方法中的局部内部类
    
                      - 同一个类里不可能有两个同名的成员内部类,但在同一个类里可以有两个以上同名的局部内部类(位于不同方法中)
    
                  - 匿名内部类
    
                    - new 实现接口( )或 父类构造器(实参列表)
                      {
                      //匿名内部类的类体部分
                      }
    
                      - 通常用于一次性的类实例创建
                        但由于其局限性,不适用于需要多次复用的情况
    
                    - 匿名内部类必须继承一个父类或实现一个接口,但最多只能继承一个父类或实现一个接口
    
                    - 规则限制
    
                      - 匿名内部类不能是抽象类,因为它会立即创建匿名内部类的对象
    
                      - 匿名内部类不能定义构造器,但可以使用实例初始化块来完成构造器的功能
    
                    - 实现接口的匿名内部类
    
                      - 匿名内部类可以实现接口并且可以重写接口中的方法
    
                      - 对于接口的匿名内部类,不能显式定义构造器,只能通过无参构造器创建实例
    
                    - 继承父类的匿名内部类
    
                      - 匿名内部类可以继承一个父类并重写父类中的方法
    
                      - 对于继承父类的匿名内部类,可以有和父类相似的构造器,根据需要传入参数或不传参数
    
                    - 从Java 8开始,被匿名内部类访问的局部变量可以被隐式视为 final,但不能重新赋值
    
  •             包装类(Wrapper Class)
    
                - Java中一组用于包装基本数据类型的类,这些基本数据类型包括整数、浮点数、字符、布尔值等。包装类的主要作用是将基本数据类型转换为对象
    
                - 可以直接将基本数据类型赋给包装类
                  必须注意类型匹配,Java会自动进行转换
    
                  - 自动装箱(Autoboxing)
    
                    - 把一个基本类型变量直接赋给对应的包装类变量,或者赋给Object变量(Object是所有类的父类,子类对象可以直接赋给父类变量)
    
                  - 自动拆箱(AutoUnboxing)
    
                    - 允许直接把包装类对象直
                      接赋给一个对应的基本类型变量
    
                    - 比较包装类实例与数值类型的值
    
                      - Integer num = 42;  // 创建一个Integer对象
                        int value = 42;    // 创建一个int值
    

if (num == value) {
System.out.println(“相等”);
} else {
System.out.println(“不相等”);
}

- 实现基本类型变量和字符串之间的转换

    - 利用包装类提供的parseXxx(String s)静态方法

( 除Character之外的所有包装类都提供了该方法)

        - String str = "123";

int num = Integer.parseInt(str);
将字符串转换为整数类型

    - 利用包装类提供的valueOf(String s)静态方法

        - String str = "123";

Integer num = Integer.valueOf(str);
将字符串转换为 Integer 对象

    - 整数隐式转换为字符串

        - int number = 42;

String str = number + “”; // 将int转换为字符串

  • 单例类(Singleton)

    • 一个类始终只能创建一个实例,则这个类被称为单例类

      • 将类的构造器私有化,以防止外部类创建对象

      • 提供一个public静态方法作为该类的访问点,在这个方法中创建实例对象

        • 只能通过 Singleton.getInstance() 方法来获取单例对象
      • 使用一个静态变量来缓存已创建的对象,确保每次调用 getInstance() 方法时都返回相同的实例

      • 必须缓存已经创建的对象,否则该类无法知道
        是否曾经创建过对象,也就无法保证只创建一个对象

        • 需要
          使用一个成员变量来保存曾经创建的对象,因为该成员变量需要被上
          面的静态方法访问,故该成员变量必须使用static修饰
  • final修饰符

    • 定义

      • 既可以修饰成员变量(包括类变量和实例变量),也可以修饰局
        部变量、形参

        • ➢ 类变量:必须在静态初始化块中指定初始值或声明该类变量时
          指定初始值,而且只能在两个地方的其中之一指定

        • ➢ 实例变量:必须在非静态初始化块、声明该实例变量或构造器
          中指定初始值,而且只能在三个地方的其中之一指定

      • final修饰的变量不可被改变,一旦获得
        了初始值,该final变量的值就不能被重新赋值

      • final修饰的成员变量必须
        由程序员显式地指定初始值
        对于final成员变
        量,程序当然希望总是能访问到它固定的、显式初始化的值

      • final 成员变量必须在对象构造过程中确保被初始化。如果在构造器、初始化块中对 final 成员变量进行初始化,确保在使用之前初始化,否则会出现默认初始化的情况

    • final局部变量

      • 如果final修饰的局部变量在定义时没有指定默认值,则可以在后
        面代码中对该final变量赋初始值,但只能一次,不能重复赋值
    • final只保证这个引用类型变量所引用的地址不会改变,即一直引用同一个对象,但这个对象完全可以发生改变

    • 可执行“宏替换”的final变量

      • 定义一个final变量并在声明时指定一个编译时确定的初始值,编译器在编译时将使用宏变量的地方直接替换为其值,以提高性能和减少代码的复杂性
    • 当一个变量满足下面三个条件时,它被认为是一个常量(constant)或直接量(literal)

      • ➢ 使用final修饰符修饰。

      • ➢ 在定义该final变量时指定了初始值。

      • ➢ 该初始值可以在编译时就被确定下来。

    • Java会使用常量池来管理曾经用过的字符串直接量,例如执行var a=”java”;语句之后,常量池中就会缓存一个字符串”java”;如果程序再次执行var b=”java”;,系统将会让b直接指向常量池中的”java”字符串,因此a==b将会返回true

    • final方法

      • final修饰的方法不可被重写
    • final类

      • final修饰的类不可以有子类
  • 不可变类

    • 创建该类的实例后,该实例的实例变量是不可改变的

    • 创建自定义的不可变类

      • ➢ 使用private和final修饰符来修饰该类的成员变量。

      • ➢ 提供带参数的构造器(或返回该实例的类方法),用于根据传入参数来初始化类里的成员变量。

      • ➢ 仅为该类的成员变量提供getter方法,不要为该类的成员变量提供setter方法,因为普通方法无法修改final修饰的成员变量

      • 如果有必要,重写Object类的hashCode()和equals()方法
        equals()方法根据
        关键成员变量来作为两个对象是否相等的标准,除此之外,还
        应该保证两个用equals()方法判断为相等的对象的hashCode()
        也相等

    • 缓存实例的不可变类

      • 缓存实现

        • 使用valueOf()方法生成对象,系统是否重新生成新对象取决于缓存池中是否已经存在相同对象

        • private修饰符隐藏构造器,程序只能通过提供的valueOf()方法来获取实例

      • 先进先出(FIFO)规则

        • 当缓存池已满时,最先进入缓存的对象会被最先移除,而最后进入缓存的对象会被保留
      • 是否隐藏构造器

        • 需要控制对象创建

        • 需要维护缓存

          • 计划在类内部使用缓存来管理对象实例,那么通常需要隐藏构造器,以确保所有对象都经过缓存池的管理
        • 控制不可变性

          • 隐藏构造器可以确保在对象创建后不再被修改
      • 计划在类内部使用缓存来管理对象实例,那么通常需要隐藏构造器,以确保所有对象都经过缓存池的管理

  • 接口和抽象类

    • 抽象类

      • 抽象方法和抽象类必须使用abstract修饰符来定义,有抽象方法
        的类只能被定义成抽象类,抽象类里可以没有抽象方法

      • 规则“有得有失”

        • 抽象方法没有方法体

          • public
            abstract void test()没有一对花括号
        • 抽象类不能被实例化,它存在主要是为了被继承。即使抽象类没有抽象方法,也不能创建实例

        • 抽象类可以包含成员变量、方法(普通方法和抽象方法)、构造器、初始化块、内部类(接口、枚举)


        • 象类的构造器不能用于创建实例,主要是用于被其子类调用

        • 一个类如果包含抽象方法(直接定义、继承抽象父类但没有实现父类的抽象方法、或者实现接口但没有完全实现接口的抽象方法),那么该类必须声明为抽象类,除非它的子类提供了具体的实现

      • abstract关键字

        • abstract关键字修饰的方法必须被其子类重写才有意义,否则
          这个方法将永远不会有方法体,因此abstract方法不能定义为
          private访问权限,即private和abstract不能同时修饰方法

        • abstract不能用于修饰成员变量,不能用于修饰局部变量,即
          没有抽象变量、没有抽象成员变量等说法;abstract也不能用于修
          饰构造器,没有抽象构造器,抽象类里定义的构造器只能是普通构
          造器

        • static和abstract并不是绝对互斥的,static和abstract虽然
          不能同时修饰某个方法,但它们可以同时修饰内部类

      • 模板模式

        • 有助于提供通用的框架,同时允许不同的子类提供各自的实现
      • 抽象类的作用

        • 模板模式

          • ➢ 抽象父类可以只定义需要使用的某些方法,把不能实现的部分抽象成抽象方法,留给其子类去实现。

          • ➢ 父类中可能包含需要调用其他系列方法的方法,这些被调方法既可以由父类实现,也可以由其子类实现。父类里提供的方法只是定义了一个通用算法,其实现也许并不完全由自身实现,而必须依赖于其子类的辅助

    • 接口

      • 接口是从多个相似类中抽象出来的规范,接口不提供任何实现。接口体现的是规范和实现分离的设计哲学

      • 一个Java
        源文件里最多只能有一个public接口,如果一个Java源文件里定义
        了一个public接口,则该源文件的主文件名必须与该接口名相同

      • [修饰符] interface 接口名 extends 父接口1, 父接口2…
        {
        零个到多个常量定义(只能是静态常量)
        零个到多个抽象方法定义
        (只
        能是抽象实例方法、类方法、默认方法或私有方法)
        零个到多个内部类、接口、枚举定义
        零个到多个私有方法、默认方法或类方法定义
        接口里不能包含构造器和初始
        化块定义
        }

        • 修饰符可以是public或者省略,如果省略了public访问控制
          符,则默认采用包权限访问控制符,即只有在相同包结构下才
          可以访问该接口

        • 接口名应与类名采用相同的命名规则

        • 一个接口可以有多个直接父接口,但接口只能继承接口,不能
          继承类

        • 接口里的常量、方法、内部类和内部枚举都是public访问权限

      • 私有方法

        • 在接口内部定义私有方法,这些方法只能被接口中的其他默认方法或静态方法所使用,而无法被接口的实现类直接调用

        • 作为工具方法,为接口中的默认方法或类方法提供支持

          • 用于在接口内部共享代码逻辑
        • 私有
          方法可以拥有方法体,但私有方法不能使用default修饰。私有方法可
          以使用static修饰,也就是说,私有方法既可是类方法,也可是实例
          方法

      • 静态常量


        • 接口中定义成员变量时,不管是否使用public static final修饰符,
          接口里的成员变量总是使用这三个修饰符来修饰
      • 在接口中定义的

        • 内部类、内部接口、内部枚举,默认都采用public
          static两个修饰符

        • 方法,只能是抽象方法、类方法、默认方法或私有方
          法,自动为
          普通方法增加abstract修饰符

          • 类方法、默认方法、私有方法都必须有方法实现(方法体)

            • 默认方法就是有方法体的实例方法
        • 普通方法,接口里的普通方法总是使用public
          abstract来修饰

          • 接口里的普通方法不能有方法实现(方法体)
        • 成员变量,不管是否使用public static final修饰符,
          接口里的成员变量总是使用这三个修饰符来修饰

      • 完全支持多继承

        • 子接口扩展某个父接口,将
          会获得父接口里定义的所有抽象方法、常量

        • 子接口可以通过使用 extends 关键字继承多个父接口

      • 使用接口

        • 主要用途

          • ➢ 定义变量,也可用于进行强制类型转换。

          • ➢ 调用接口中定义的常量。

          • ➢ 被其他类实现。

        • 类实现接口

          • 弥补单继承的不足

          • implements关键字

            • 继承使用extends关键字,实现
              则使用implements关键字
          • public class MyClass extends 父类 implements Interface1, Interface2, Interface3 {
            // 类的实现
            }

          • 一个类实现了一个或多个接口之后,这个类必须完全实现这些接
            口里所定义的全部抽象方法(也就是重写这些抽象方法);否则,该
            类将保留从父接口那里继承到的抽象方法,该类也必须定义成抽象

          • 实现接口方法时,必须使用 public 访问修饰符。因为子类(或者实现类)重写父类的方法时,访问权限只能更大或相等,所以实现类实现接口方法时只能使用 public 访问权限

          • 接口不能显式继承任何类,但所有接口类型的引用变量都可以直
            接赋给Object类型的引用变量

          • Java 中所有对象最终都是 Object 类的子类。当一个类实现了接口,这个类的实例本质上是 Object 类的子类,因为 Object 类是Java类层级结构的根类

        • 接口内部可以嵌套其他接口。默认情况下,接口内部的接口自动具有 public 和 static 两个修饰符。这表示内部接口默认是静态的,可以直接通过外部接口名访问,并且也是公开可访问的

    • 接口和抽象类

      • 接口:作为系统与外界交互的规范,规定了实现者必须向外提供哪些服务(方法),以及调用者可以如何调用这些服务。在程序中使用接口时,它是多个模块间的耦合标准。在多个应用程序之间使用接口时,它是多个程序之间的通信标准。接口类似于整个系统的“总纲”,制定了系统各模块应该遵循的标准。因此,一旦接口被改变,对整个系统或其他系统的影响将是辐射式的,可能导致系统中大部分类都需要修改

      • 抽象类:作为系统中多个子类的共同父类,体现了一种模板式设计。抽象类是系统实现过程中的中间产品,它已经实现了系统的部分功能(那些已提供实现的方法)。然而,这个中间产品依然不能作为最终产品,需要有进一步的完善

      • 相同

        • ➢ 接口和抽象类都不能被实例化,它们都位于继承树的顶端,用
          于被其他类实现和继承

        • ➢ 接口和抽象类都可以包含抽象方法,实现接口或继承抽象类的
          普通子类都必须实现这些抽象方法

      • 差别

        • ➢ 接口里只能包含抽象方法、静态方法、默认方法和私有方法,不能为普通方法提供方法实现;抽象类则完全可以包含普通方法

        • ➢ 接口里只能定义静态常量,不能定义普通成员变量;抽象类里则既可以定义普通成员变量,也可以定义静态常量。

        • ➢ 接口里不包含构造器;抽象类里可以包含构造器,抽象类里的构造器并不是用于创建对象,而是让其子类调用这些构造器来完成属于抽象类的初始化操作。

        • ➢ 接口里不能包含初始化块;但抽象类则完全可以包含初始化块

        • ➢ 一个类最多只能有一个直接父类,包括抽象类;但一个类可以直接实现多个接口,通过实现多个接口可以弥补Java单继承的不足

Lambda表达式

Lambda表达式基本结构

  • 形参列表: 允许省略类型,如果只有一个参数可以省略括号

  • 箭头符号 ->:将参数列表与Lambda表达式的主体分隔开

  • 主体: 包含Lambda表达式要执行的语句

  • 如果Lambda表达式只有一个语句,可以省略花括号 {}

  • 如果Lambda表达式只包含一条返回语句,可以省略 return 关键字
    Lambda表达式需要返回值,而它的代码块中仅有一条
    省略了return的语句,Lambda表达式会自动返回这条语句的

  • Eatable eat = () -> System.out.println(“Eating”); // 一个没有参数的Lambda表达式
    eat.eat();

Flyable fly = distance -> System.out.println(“Flying “ + distance + “ miles”); // 一个带有一个参数的Lambda表达式
fly.fly(1000);

Addable add = (a, b) -> a + b; // 一个带有两个参数的Lambda表达式
System.out.println(add.add(5, 3));

Lambda表达式与函数式接口

  • 特点

    • 目标类型:Lambda 表达式的类型,也就是它的目标类型,必须是函数式接口

    • 函数式接口:函数式接口代表只有一个抽象方法的接口。Lambda 表达式实现的是这个唯一的抽象方法

    • @FunctionalInterface注解:这个注解放在接口定义前,用于告诉编译器该接口必须是函数式接口。如果接口不符合函数式接口的条件,编译器会报错

  • 限制

    • ➢ Lambda表达式的目标类型必须是明确的函数式接口

    • ➢ Lambda表达式只能为函数式接口创建对象。Lambda表达式只能
      实现一个方法,因此它只能为只有一个抽象方法的接口(函数
      式接口)创建对象

  • 确保 Lambda 表达式的目标类型是函数式接口

    • ➢ 将Lambda表达式赋值给函数式接口类型的变量
      Runnable r = () -> System.out.println(“Running…”);

      • ➢ 将Lambda表达式作为函数式接口类型的参数传给某个方法

public void execute(Runnable r) {
r.run();
}

execute(() -> System.out.println(“Executing…”));

- ➢ 使用函数式接口对Lambda表达式进行强制类型转换

Object obj = (Runnable)() -> System.out.println(“Converting to Runnable…”);

  • java.util.function包下预定义了大量函数式接口

    • ➢ XxxFunction:这类接口中通常包含一个apply()抽象方法,该
      方法对参数进行处理、转换(apply()方法的处理逻辑由Lambda
      表达式来实现),然后返回一个新的值。该函数式接口通常用
      于对指定数据进行转换处理。
      ➢ XxxConsumer:这类接口中通常包含一个accept()抽象方法,
      该方法与XxxFunction接口中的apply()方法基本相似,也负责
      对参数进行处理,只是该方法不会返回处理结果。
      ➢ XxxxPredicate:这类接口中通常包含一个test()抽象方法,
      该方法通常用来对参数进行某种判断(test()方法的判断逻辑
      由Lambda表达式来实现),然后返回一个boolean值。该接口通
      常用于判断参数是否满足特定条件,经常用于进行筛滤数据
      ➢ XxxSupplier:这类接口中通常包含一个getAsXxx()抽象方
      法 , 该 方 法 不 需 要 输 入 参数 ,该方法会按某种逻辑算法
      (getAsXxx ()方法的逻辑算法由Lambda表达式来实现)返回一
      个数据

在Lambda表达式中使用var

  • Predicate myLambda = (String str) -> str.length() > 5;
    必须明确指定Lambda表达式的目标类型

    • BiFunction<Integer, Integer, Integer> adder = (@Nonnull Integer a, @Nonnull Integer b) -> a + b;

      能省略Lambda表达式的形参类型—因为注解只能被放在形参类型之

方法引用与构造器引用

    • 方法引用的格式为 ClassName::methodName

      • 引用类方法

        • 在Lambda表达式中使用类的静态方法Integer::parseInt
      • 引用特定对象的实例方法

        • 允许将特定对象的方法作为Lambda表达式的参数传递
          object::methodName
      • 引用某类对象的实例方法

        • Lambda表达式提供的参数是用于调用方法的对象
          String::substring
    • 构造器引用可以用于创建对象,语法是 ClassName::new

与匿名内部类的联系和区别

  • 访问变量:两者都可以直接访问外部的局部变量,但这些变量必须是 effectively final(实质上是 final 的,即一旦赋值就不会再被修改)

  • 默认方法:Lambda表达式和匿名内部类都可以直接调用从接口中继承的默认方法

  • 区别

    • 适用范围

      • Lambda表达式只适用于函数式接口,即接口中只包含一个抽象方法的接口

      • 匿名内部类可以为任意接口创建实例,无论接口中有多少个抽象方法

    • 对默认方法的访问

      • 匿名内部类可以在实现抽象方法的方法体中调用接口中定义的默认方法

      • Lambda表达式的代码块不允许直接调用接口中的默认方法

使用Lambda表达式调用Arrays的类方法

面向接口编程

简单工厂模式

  • 对创建对象过程的封装。通过简单工厂,可以将对象的创建逻辑集中管理,提高系统的灵活性

命令模式

  • 使用一个Command接口来定义一个方法,用这个方法来封
    装“处理行为”

    • public interface Command
      {
      //接口里定义的process方法用于封装“处理行为”
      void process(int element);
      }

三大特征

封装

  • 目的

    • 隐藏类的实现细节

    • 通过事先预定的方法来访问数据,在方法里加入控制逻辑,限制对成员变量的不合理访问

    • 可进行数据检查,有利于保证对象信息的完整性

    • 便于修改,提高代码的可维护性

  • 隐藏和封装

    • 将对象的成员变量和实现细节隐藏起来,不允许外部直接访问

    • 把方法暴露出来,让方法来控制对这些成员变量进行安全的访问和操作

    • private(当前类访问权限):只能在当前类的内部被访问

    • default(包访问权限):不使用任何访问控制符
      修饰
      访问控制的成员或外部
      类可以被相同包下的其他类访问

    • protected(子类访问权限):那么这
      个成员既可以被同一个包中的其他类访问,也可以被不同包中
      的子类访问,通常是希望其子类来重写这个方法。

    • public(公共访问权限):如果一个成员(包括成员变量、方法和构造器等)或者一个外
      部类使用public访问控制符修饰,那么这个成员或外部类就可
      以被所有类访问

  • 访问控制符的使用

    • 类里的绝大部分成员变量都应该使用private修饰,只有一些
      static修饰的、类似全局变量的成员变量,才可能考虑使用
      public修饰。

    • 有些方法只用于辅助实现该类的其他
      方法,这些方法被称为工具方法,工具方法也应该使用private
      修饰。

    • 如果某个类主要用做其他类的父类,该类里包含的大部分方法
      可能仅希望被其子类重写,而不想被外界直接调用,则应该使
      用protected修饰这些方法

    • 希望暴露出来给其他类自由调用的方法应该使用public修饰。

多态(Polymorphism)

  • 相同类型的变量、
    调用同一个方法时呈现出多种不同的行为特征

  • 引用变量在编译阶段只能调用其编译时类型所具有的方法,但
    运行时则执行它运行时类型所具有的方法

    • 引用变量只能调用声明该变量时所用类里包含的方法。例如,
      通过Object p=new Person()代码定义一个变量p,则这个p只能调用
      Object类的方法,而不能调用Person类里定义的方法。

      • 通过引用变量来访问其包含的实例变量时,系统总是试图访问

它编译时类型所定义的成员变量,而不是它运行时类型所定义的成
员变量。

  • 方法重写(override)

    • 子类中定义一个与父类中已有的方法名称、参数列表和返回类型相同的方法。子类方法的实现将替代父类方法的实现。方法重写必须保持方法签名的一致性,包括方法名称、参数列表和返回类型。

    • 使用 @Override 注解来标记重写方法

    • 动态绑定,指的是在运行时,根据对象的实际类型来确定要调用的方法实现。这允许在父类引用对象的情况下调用子类的方法,实现多态性

  • 向上转型

    • Java允许将子类对象直接赋给父类引用变量,无需任何显式类型转换。这个过程被称为向上转型(Upcasting),向上转型由系统自动完成
  • 引用变量的强制类型转换

    • 类型转换运算符是小括号,类型转换运算符的用 法是:
      (type)variable,这种用法可以将variable变量转换成一个type类型
      的变量

    • 类型转换运算符还可以将一个引用类型变量转换
      成其子类类型

      • 基本类型之间的转换只能在数值类型之间进行,数值类型和布尔类型
        之间不能进行类型转换。

      • 引用类型之间的转换只能在具有继承关系的两个类型之间进
        行,如果是两个没有任何继承关系的类型,则无法进行类型转
        换,否则编译时就会出现错误。

      • 如果试图把一个父类实例转换
        成子类类型,则这个对象必须实际上是子类实例才行(即编译
        时类型为父类类型,而运行时类型是子类类型),否则将在运
        行时引发ClassCastException异常。

      • 对象 ’instanceof‘ 类型(返回布尔值)
        instanceof运算符通常用于在进行向下转型之前检查对象的类型,以确保转型是安全的。

        • instanceof运算符前面操
          作数的编译时类型要么与后面的类相同,要么与后面的类具有父子继
          承关系

继承

  • 类的继承

    • 每个子类只有一个直接父类

    • public class 子类名 extends 父类名 {
      // 子类的成员变量和方法 }

    • 子类只能从被扩展的父类获得成员变量、方法和内部类(包括
      内部接口、枚举),不能获得构造器和初始化块。

    • 继承适用于那些具有”is-a”关系的类,即子类是父类的一种特例。

  • 重写父类的方法

    • 子类包含与父类同名方法的现象被称为方法重写(Override)。

      • 子类提供了与父类相同名称、参数列表和返回类型的方法,以提供自己的实现。使得子类能够在继承的基础上自定义或修改方法的行为。

      • “两同两小一大”规则

        • 方法名相
          同、形参列表相同

        • 子类方法返回值类型应比父类方
          法返回值类型更小或相等,子类方法声明抛出的异常类应比父类方法
          声明抛出的异常类更小或相等

        • 子类方法的访问权限
          应比父类方法的访问权限更大或相等

      • 覆盖方法和被覆盖方法必须具有相同的方法类型,即它们要么都是类方法,要么都是实例方法

    • 当子类覆盖了父类的方法后,子类对象默认无法直接访问父类中被覆盖的方法

      • 在子类方法内使用 super 关键字(如果被覆盖的方法是实例方法)

        • super用于限定该对象调用它从
          父类继承得到的实例变量或方法

        • super不能出现在static修饰的方法中。static修饰的
          方法是属于类的,该方法的调用者可能是一个类,而不是对象

        • 在构造器中使用super,则super用于限定该构造器初始化的
          是该对象从父类继承得到的实例变量,而不是该类自己定义的实例变
          量。

      • 使用父类的类名(如果被覆盖的方法是类方法)来调用父类中被覆盖的方法。

  • 调用父类构造器

    • 在一个构造器中调用另一个重载的构造器使用this调用来完成

    • 在子类构造器中调用父类构造器使用super调用来完成

  • 继承与组合(类复用)

    • 父类应有良好的封装性,不会被子类随意改变

      • 尽量隐藏父类的内部数据

      • 不要让子类可以随意访问、修改父类的方法

      • 尽量不要在父类构造器中调用将要被子类重写的方法

    • 何时需要从父类派生新的子类

      • 子类需要额外增加成员变量,而不仅仅是变量值的改变。

      • 子类需要增加自己独有的行为方式(包括增加新的方法或重写
        父类的方法)

    • 利用组合实现复用

      • 组合是将一个类的对象作为另一个类的成员。这允许新类直接复用现有类的公共方法,而不必继承其全部行为。组合通常适用于那些具有”has-a”关系的类,即一个类包含另一个类的实例作为其一部分。

      • 把旧类对象作为新类的成员变量组合进来,用以实现新类的功能

      • 继承设计与组合设计的
        系统开销不会有本质的差别

这只是一个测试,在之后会完善

HSCCTF{FAKE_FLAG!}
![[Pasted image 20240309212250.png]]
blowfish加密
![[Pasted image 20240309212457.png]]

  1. 函数调用 (1): 类似于上一个函数,它调用 j___CheckForDebuggerJustMyCode (不清楚具体用途)。
  2. 循环 (1): 该循环一直迭代直到满足条件:
    • 它使用 j_strlen (可能是获取字符串长度的函数) 获取输入字符串 (a1) 的长度。
    • 它将 a1 的长度与另一个字符串 (aHscctfFakeFlag) 的长度进行比较,并将较小的长度存储在 v6 中。
    • 它检查循环计数器 i 是否大于 v6。如果是,则跳出循环。
    • 在循环内部,它对 a1 的每个字符和对应位置的 aHscctfFakeFlag 的字符执行按位异或操作 (i)。结果存储回 a1 中。
  3. 循环 (2): 该循环类似于循环 (1):
    • 它获取 a1 的长度。
    • 它将 a1 的长度与 aHscctfFakeFlag 的长度进行比较,并将较小的长度存储在 v7 中。
    • 它检查循环计数器 j 是否大于 v7 减 1。如果是,则跳出循环。(这样做的一个原因可能是因为 aHscctfFakeFlag 可能比需要的长一个字符)。
    • 在循环内部,它对 a1 的每个字符和紧跟在 aHscctfFakeFlag 对应字符后面的字符 (j + 1) 执行按位异或操作。结果存储回 a1 中。

总体:

该函数可能采用一个字符串 (a1) 作为输入,并通过将其与包含伪标志的另一个字符串 (aHscctfFakeFlag) 进行异或运算来修改它。这种混淆操作使得更难理解标志的实际内容。

main代码概述

这段代码似乎与在多线程环境中处理传入的 TCP 连接有关。让我们逐步分析代码:

初始化

  1. 声明变量以保存各种数据结构,如套接字、线程和通道。
  2. 使用 core::fmt::Arguments 对象 (v10) 格式化字符串。
  3. 创建 std::net::tcp::TcpListener 对象 (listener) 以侦听特定端口上的传入连接。

主循环

  1. 代码进入一个循环,该循环迭代直到没有更多连接可接受。
  2. 在循环内,代码使用 std::net::tcp::Incoming::next 接受新连接。
  3. 如果没有更多连接可接受,则循环中断。
  4. 创建新的 core::result::Result 对象 (v20) 来存储接受连接的结果。
  5. 准备一个名为 http_proxy::main::_closure_env_0 的自定义结构(可能包含与连接相关的数据)(joba)。
  6. 使用线程池 (v14) 在单独的线程中执行函数 (threadpool::ThreadPool::execute)。此函数可能处理已接受连接的处理。
  7. 在线程生成后,代码清理与接收客户端消息相关的资源 (recv_chan)。

线程函数(未显示)

  1. 线程函数(未在提供的代码中显示)可能使用提供的通道 (recv_chan) 从客户端检索消息。
  2. 它可能会处理接收到的消息并向客户端发送回执。

清理

  1. 循环退出后,使用 core::ptr::drop_in_place 清理各种对象,例如线程池、通道和侦听器套接字。

总体而言,此代码片段似乎是一个工作函数,它侦听传入的 TCP 连接、生成线程来处理每个连接并在处理完所有连接后清理资源。

ELF 可执行文件中的过程链接表 (PLT) 和全局偏移表 (GOT) 相关部分。

内存布局解析:

  • org 3FE8h: 该指令将以下代码的起始地址设置为内存地址 0x3FE8
  • .got.plt 段:
    • 该段包含 GOT (全局偏移表) 和 PLT (过程链接表) 的条目。这些表对于在动态链接程序中解析外部函数调用至关重要。
    • 此处显示的特定条目(从地址 0x3FE80x3FF0 和 0x3FF8 开始)全部初始化为零 (00 00 00 00 00 00 00 00)。
      • _GLOBAL_OFFSET_TABLE_ dq offset _DYNAMIC: 该行可能定义了一个名为 _GLOBAL_OFFSET_TABLE_ 的符号,指向另一个名为 _DYNAMIC 的符号的地址。_DYNAMIC 的详细信息取决于特定的 ELF 实现。
  • qword_3FF0 和 qword_3FF8:
    • 它们分别是名为 qword_3FF0 和 qword_3FF8 的数据元素(四字节,64 位值)。它们被初始化为零 (dq 0)。
    • 数据段 (.data) 从地址 0x4000 开始,指示这些数据元素位于单独的内存区域。
    • 存在来自 PLT 段地址 0x1020 到 qword_3FF0 的数据交叉引用(由 ↑r 指示),以及另一个来自 0x1026 到 qword_3FF8 的交叉引用。这表明 PLT 代码可能与这些数据元素交互。

上下文和推断:

如果没有更多代码,很难确切地说这些部分做什么。但是,根据 GOT 和 PLT 的存在,我们可以推断该代码片段是依赖动态链接(运行时加载库)的程序的一部分。

  • GOT 条目中的初始零表明程序尚未解析其调用的外部函数的地址。
  • 数据元素 qword_3FF0 和 qword_3FF8 可能会用于在解析函数地址或执行与动态链接相关的其他任务的过程中存储临时值或标志。
  • 来自 PLT 到这些数据元素的交叉引用进一步支持了它们在动态链接过程中发挥作用的想法。

总体而言,该代码片段让我们了解了 ELF 可执行文件中动态链接的内存布局。它突出了 GOT 和 PLT 在解析外部函数调用中的作用,并暗示了数据元素 qword_3FF0qword_3FF8 在此过程中的潜在参与。