📊
CTF-All-In-One
  • 简介
  • 前言
  • 一、基础知识篇
    • 1.1 CTF 简介
    • 1.2 学习方法
    • 1.3 Linux 基础
    • 1.4 Web 安全基础
      • 1.4.1 HTML 基础
      • 1.4.2 HTTP 协议基础
      • 1.4.3 JavaScript 基础
      • 1.4.4 常见 Web 服务器基础
      • 1.4.5 OWASP Top Ten Project 漏洞基础
      • 1.4.6 PHP 源码审计基础
    • 1.5 逆向工程基础
      • 1.5.1 C/C++ 语言基础
      • 1.5.2 汇编基础
      • 1.5.3 Linux ELF
      • 1.5.4 Windows PE
      • 1.5.5 静态链接
      • 1.5.6 动态链接
      • 1.5.7 内存管理
      • 1.5.8 glibc malloc
      • 1.5.9 Linux 内核
      • 1.5.10 Windows 内核
      • 1.5.11 jemalloc
    • 1.6 密码学基础
      • 1.6.1 密码学导论
      • 1.6.2 流密码
      • 1.6.3 分组密码
      • 1.6.4 公钥密码
      • 1.6.5 消息认证和哈希函数
      • 1.6.6 数字签名
      • 1.6.7 密码协议
      • 1.6.8 密钥分配与管理
      • 1.6.9 数字货币
    • 1.7 Android 安全基础
      • 1.7.1 Android 环境搭建
      • 1.7.2 Dalvik 指令集
      • 1.7.3 ARM 汇编基础
      • 1.7.4 Android 常用工具
  • 二、工具篇
    • 虚拟化分析环境
      • 2.1.1 VirtualBox
      • 2.1.2 QEMU
      • 2.1.3 Docker
      • 2.1.4 Unicorn
    • 静态分析工具
      • 2.2.1 radare2
      • 2.2.2 IDA Pro
      • 2.2.3 JEB
      • 2.2.4 Capstone
      • 2.2.5 Keystone
      • 2.2.6 Ghidra
    • 动态分析工具
      • 2.3.1 GDB
      • 2.3.2 OllyDbg
      • 2.3.3 x64dbg
      • 2.3.4 WinDbg
      • 2.3.5 LLDB
    • 其他工具
      • 2.4.1 pwntools
      • 2.4.2 zio
      • 2.4.3 metasploit
      • 2.4.4 binwalk
      • 2.4.5 Burp Suite
      • 2.4.6 Wireshark
      • 2.4.7 Cuckoo Sandbox
  • 三、分类专题篇
    • Pwn
      • 3.1.1 格式化字符串漏洞
      • 3.1.2 整数溢出
      • 3.1.3 栈溢出
      • 3.1.4 返回导向编程(ROP)(x86)
      • 3.1.5 返回导向编程(ROP)(ARM)
      • 3.1.6 Linux 堆利用(一)
      • 3.1.7 Linux 堆利用(二)
      • 3.1.8 Linux 堆利用(三)
      • 3.1.9 Linux 堆利用(四)
      • 3.1.10 内核 ROP
      • 3.1.11 Linux 内核漏洞利用
      • 3.1.12 Windows 内核漏洞利用
      • 3.1.13 竞争条件
      • 3.1.14 虚拟机逃逸
    • Reverse
      • 3.2.1 patch 二进制文件
      • 3.2.2 脱壳技术(PE)
      • 3.2.3 脱壳技术(ELF)
      • 3.2.4 反调试技术(PE)
      • 3.2.5 反调试技术(ELF)
      • 3.2.6 指令混淆
    • Web
      • 3.3.1 SQL 注入利用
      • 3.3.2 XSS 漏洞利用
    • Crypto
    • Misc
      • 3.5.1 Lsb
    • Mobile
  • 四、技巧篇
    • 4.1 Linux 内核调试
    • 4.2 Linux 命令行技巧
    • 4.3 GCC 编译参数解析
    • 4.4 GCC 堆栈保护技术
    • 4.5 ROP 防御技术
    • 4.6 one-gadget RCE
    • 4.7 通用 gadget
    • 4.8 使用 DynELF 泄露函数地址
    • 4.9 shellcode 开发
    • 4.10 跳转导向编程(JOP)
    • 4.11 利用 mprotect 修改栈权限
    • 4.12 利用 __stack_chk_fail
    • 4.13 利用 _IO_FILE 结构
    • 4.14 glibc tcache 机制
    • 4.15 利用 vsyscall 和 vDSO
  • 五、高级篇
    • 5.0 软件漏洞分析
    • 5.1 模糊测试
      • 5.1.1 AFL fuzzer
      • 5.1.2 libFuzzer
    • 5.2 动态二进制插桩
      • 5.2.1 Pin
      • 5.2.2 DynamoRio
      • 5.2.3 Valgrind
    • 5.3 符号执行
      • 5.3.1 angr
      • 5.3.2 Triton
      • 5.3.3 KLEE
      • 5.3.4 S²E
    • 5.4 数据流分析
      • 5.4.1 Soot
    • 5.5 污点分析
      • 5.5.1 TaintCheck
    • 5.6 LLVM
      • 5.6.1 Clang
    • 5.7 程序切片
    • 5.8 SAT/SMT
      • 5.8.1 Z3
    • 5.9 基于模式的漏洞分析
    • 5.10 基于二进制比对的漏洞分析
    • 5.11 反编译技术
      • 5.11.1 RetDec
  • 六、题解篇
    • Pwn
      • 6.1.1 pwn HCTF2016 brop
      • 6.1.2 pwn NJCTF2017 pingme
      • 6.1.3 pwn XDCTF2015 pwn200
      • 6.1.4 pwn BackdoorCTF2017 Fun-Signals
      • 6.1.5 pwn GreHackCTF2017 beerfighter
      • 6.1.6 pwn DefconCTF2015 fuckup
      • 6.1.7 pwn 0CTF2015 freenote
      • 6.1.8 pwn DCTF2017 Flex
      • 6.1.9 pwn RHme3 Exploitation
      • 6.1.10 pwn 0CTF2017 BabyHeap2017
      • 6.1.11 pwn 9447CTF2015 Search-Engine
      • 6.1.12 pwn N1CTF2018 vote
      • 6.1.13 pwn 34C3CTF2017 readme_revenge
      • 6.1.14 pwn 32C3CTF2015 readme
      • 6.1.15 pwn 34C3CTF2017 SimpleGC
      • 6.1.16 pwn HITBCTF2017 1000levels
      • 6.1.17 pwn SECCONCTF2016 jmper
      • 6.1.18 pwn HITBCTF2017 Sentosa
      • 6.1.19 pwn HITBCTF2018 gundam
      • 6.1.20 pwn 33C3CTF2016 babyfengshui
      • 6.1.21 pwn HITCONCTF2016 Secret_Holder
      • 6.1.22 pwn HITCONCTF2016 Sleepy_Holder
      • 6.1.23 pwn BCTF2016 bcloud
      • 6.1.24 pwn HITCONCTF2016 House_of_Orange
      • 6.1.25 pwn HCTF2017 babyprintf
      • 6.1.26 pwn 34C3CTF2017 300
      • 6.1.27 pwn SECCONCTF2016 tinypad
      • 6.1.28 pwn ASISCTF2016 b00ks
      • 6.1.29 pwn Insomni'hack_teaserCTF2017 The_Great_Escape_part-3
      • 6.1.30 pwn HITCONCTF2017 Ghost_in_the_heap
      • 6.1.31 pwn HITBCTF2018 mutepig
      • 6.1.32 pwn SECCONCTF2017 vm_no_fun
      • 6.1.33 pwn 34C3CTF2017 LFA
      • 6.1.34 pwn N1CTF2018 memsafety
      • 6.1.35 pwn 0CTF2018 heapstorm2
      • 6.1.36 pwn NJCTF2017 messager
      • 6.1.37 pwn sixstarctf2018 babystack
      • 6.1.38 pwn HITCONCMT2017 pwn200
      • 6.1.39 pwn BCTF2018 house_of_Atum
      • 6.1.40 pwn LCTF2016 pwn200
      • 6.1.41 pwn PlaidCTF2015 PlaidDB
      • 6.1.42 pwn hacklu2015 bookstore
      • 6.1.43 pwn 0CTF2018 babyheap
      • 6.1.44 pwn ASIS2017 start_hard
      • 6.1.45 pwn LCTF2016 pwn100
    • Reverse
      • 6.2.1 re XHPCTF2017 dont_panic
      • 6.2.2 re ECTF2016 tayy
      • 6.2.3 re CodegateCTF2017 angrybird
      • 6.2.4 re CSAWCTF2015 wyvern
      • 6.2.5 re PicoCTF2014 Baleful
      • 6.2.6 re SECCONCTF2017 printf_machine
      • 6.2.7 re CodegateCTF2018 RedVelvet
      • 6.2.8 re DefcampCTF2015 entry_language
    • Web
      • 6.3.1 web HCTF2017 babycrack
    • Crypto
    • Misc
    • Mobile
  • 七、实战篇
    • CVE
      • 7.1.1 CVE-2017-11543 tcpdump sliplink_print 栈溢出漏洞
      • 7.1.2 CVE-2015-0235 glibc __nss_hostname_digits_dots 堆溢出漏洞
      • 7.1.3 CVE-2016-4971 wget 任意文件上传漏洞
      • 7.1.4 CVE-2017-13089 wget skip_short_body 栈溢出漏洞
      • 7.1.5 CVE–2018-1000001 glibc realpath 缓冲区下溢漏洞
      • 7.1.6 CVE-2017-9430 DNSTracer 栈溢出漏洞
      • 7.1.7 CVE-2018-6323 GNU binutils elf_object_p 整型溢出漏洞
      • 7.1.8 CVE-2010-2883 Adobe CoolType SING 表栈溢出漏洞
      • 7.1.9 CVE-2010-3333 Microsoft Word RTF pFragments 栈溢出漏洞
    • Malware
  • 八、学术篇
    • 8.1 The Geometry of Innocent Flesh on the Bone: Return-into-libc without Function Calls (on the x86)
    • 8.2 Return-Oriented Programming without Returns
    • 8.3 Return-Oriented Rootkits: Bypassing Kernel Code Integrity Protection Mechanisms
    • 8.4 ROPdefender: A Detection Tool to Defend Against Return-Oriented Programming Attacks
    • 8.5 Data-Oriented Programming: On the Expressiveness of Non-Control Data Attacks
    • 8.7 What Cannot Be Read, Cannot Be Leveraged? Revisiting Assumptions of JIT-ROP Defenses
    • 8.9 Symbolic Execution for Software Testing: Three Decades Later
    • 8.10 AEG: Automatic Exploit Generation
    • 8.11 Address Space Layout Permutation (ASLP): Towards Fine-Grained Randomization of Commodity Softwa
    • 8.13 New Frontiers of Reverse Engineering
    • 8.14 Who Allocated My Memory? Detecting Custom Memory Allocators in C Binaries
    • 8.21 Micro-Virtualization Memory Tracing to Detect and Prevent Spraying Attacks
    • 8.22 Practical Memory Checking With Dr. Memory
    • 8.23 Evaluating the Effectiveness of Current Anti-ROP Defenses
    • 8.24 How to Make ASLR Win the Clone Wars: Runtime Re-Randomization
    • 8.25 (State of) The Art of War: Offensive Techniques in Binary Analysis
    • 8.26 Driller: Augmenting Fuzzing Through Selective Symbolic Execution
    • 8.27 Firmalice - Automatic Detection of Authentication Bypass Vulnerabilities in Binary Firmware
    • 8.28 Cross-Architecture Bug Search in Binary Executables
    • 8.29 Dynamic Hooks: Hiding Control Flow Changes within Non-Control Data
    • 8.30 Preventing brute force attacks against stack canary protection on networking servers
    • 8.33 Under-Constrained Symbolic Execution: Correctness Checking for Real Code
    • 8.34 Enhancing Symbolic Execution with Veritesting
    • 8.38 TaintEraser: Protecting Sensitive Data Leaks Using Application-Level Taint Tracking
    • 8.39 DART: Directed Automated Random Testing
    • 8.40 EXE: Automatically Generating Inputs of Death
    • 8.41 IntPatch: Automatically Fix Integer-Overflow-to-Buffer-Overflow Vulnerability at Compile-Time
    • 8.42 Dynamic Taint Analysis for Automatic Detection, Analysis, and Signature Generation of Exploits
    • 8.43 DTA++: Dynamic Taint Analysis with Targeted Control-Flow Propagation
    • 8.44 Superset Disassembly: Statically Rewriting x86 Binaries Without Heuristics
    • 8.45 Ramblr: Making Reassembly Great Again
    • 8.46 FreeGuard: A Faster Secure Heap Allocator
    • 8.48 Reassembleable Disassembling
  • 九、附录
    • 9.1 更多 Linux 工具
    • 9.2 更多 Windows 工具
    • 9.3 更多资源
    • 9.4 Linux 系统调用表
    • 9.5 python2到3字符串转换
    • 9.6 幻灯片
Powered by GitBook
On this page
  • 题目解析
  • 参考资料

Was this helpful?

  1. 六、题解篇
  2. Reverse

6.2.2 re ECTF2016 tayy

Previous6.2.1 re XHPCTF2017 dont_panicNext6.2.3 re CodegateCTF2017 angrybird

Last updated 3 years ago

Was this helpful?

章节 5.8.1 中讲解了 Z3 约束求解器的基本使用方法,通过这一题,我们可以更进一步地熟悉它。

题目解析

Tayy is the future of AI. She is a next level chatbot developed by pro h4ckers at NIA Labs. But Tayy hides a flag. Can you convince her to give it you?
$ file tayy
tayy: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=1fcd1c49eae4807f77d51227a3b457d8874170b4, not stripped
$ ./tayy
=============================================================
Welcome to the future of AI, developed by NIA Research, Tayy!
=============================================================
1. Talk to Tayy.
2. Flag?
0. Exit.
> 2
Flag: EEXL�▒#@N5&[g,q2H7?09:G>4!O]iJ('
V
=============================================================
1. Talk to Tayy.
2. Flag?
0. Exit.
> 1
=============================================================
1. Ayy lmao, Tayy lmao.
2. You are very cruel.
3. Memes are lyf.
4. Go away!.
5. zzzz
6. Cats > Dogs.
7. Dogs > Cats.
8. AI is overrated?.
9. I dont like you.
0. <exit to menu>
> 1
Tayy: Die, human!
=============================================================
1. Talk to Tayy.
2. Flag?
0. Exit.
> 2
Flag: EFZO�*$IX@2hv<�D[KTFPR`XO=l{�jII-z
=============================================================

玩了一会儿我们发现:

  1. 每次我们与 Tayy 交谈后,flag 就会变

  2. 最多可以交谈 8 次,然后程序退出

通过调试,我们首先发现了 flag 的初始值:

gdb-peda$ n
[----------------------------------registers-----------------------------------]
RAX: 0x0
RBX: 0x0
RCX: 0x0
RDX: 0x7ffff7dd4710 --> 0x0
RSI: 0x7fffffffe460 --> 0x231819834c584545
RDI: 0x400d2c ("Flag: %s\n")
RBP: 0x7fffffffe490 --> 0x400a70 (<__libc_csu_init>:    push   r15)
RSP: 0x7fffffffe450 --> 0x2
RIP: 0x4009e5 (<main+292>:      call   0x4005c0 <printf@plt>)
R8 : 0x7fffffffdf11 --> 0x3f00007ffff7ff00
R9 : 0xa ('\n')
R10: 0x0
R11: 0xa ('\n')
R12: 0x400630 (<_start>:        xor    ebp,ebp)
R13: 0x7fffffffe570 --> 0x1
R14: 0x0
R15: 0x0
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x4009d8 <main+279>: mov    rsi,rax
   0x4009db <main+282>: mov    edi,0x400d2c
   0x4009e0 <main+287>: mov    eax,0x0
=> 0x4009e5 <main+292>: call   0x4005c0 <printf@plt>
   0x4009ea <main+297>: jmp    0x4009f6 <main+309>
   0x4009ec <main+299>: mov    edi,0x400d38
   0x4009f1 <main+304>: call   0x4005a0 <puts@plt>
   0x4009f6 <main+309>: mov    eax,DWORD PTR [rip+0x201688]        # 0x602084 <num2>
Guessed arguments:
arg[0]: 0x400d2c ("Flag: %s\n")
arg[1]: 0x7fffffffe460 --> 0x231819834c584545
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffe450 --> 0x2
0008| 0x7fffffffe458 --> 0x7fffffffe460 --> 0x231819834c584545
0016| 0x7fffffffe460 --> 0x231819834c584545
0024| 0x7fffffffe468 --> 0x67035b26354e401c
0032| 0x7fffffffe470 (",q2H7?09:G>4!O]iJ('\nV")
0040| 0x7fffffffe478 (":G>4!O]iJ('\nV")
0048| 0x7fffffffe480 --> 0x560a27284a ("J('\nV")
0056| 0x7fffffffe488 --> 0x74941753df1a500
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x00000000004009e5 in main ()
gdb-peda$ x/s 0x7fffffffe460
0x7fffffffe460: "EEXL\203\031\030#\034@N5&[\003g,q2H7?09:G>4!O]iJ('\nV"
gdb-peda$ x/37x 0x7fffffffe460
0x7fffffffe460: 0x45    0x45    0x58    0x4c    0x83    0x19    0x18    0x23
0x7fffffffe468: 0x1c    0x40    0x4e    0x35    0x26    0x5b    0x03    0x67
0x7fffffffe470: 0x2c    0x71    0x32    0x48    0x37    0x3f    0x30    0x39
0x7fffffffe478: 0x3a    0x47    0x3e    0x34    0x21    0x4f    0x5d    0x69
0x7fffffffe480: 0x4a    0x28    0x27    0x0a    0x56

然后是一个有趣的函数 giff_flag,它在每次交谈是被调用,作用是修改 flag。

[0x00400630]> pdf @ sym.giff_flag
/ (fcn) sym.giff_flag 264
|   sym.giff_flag ();
|           ; var int local_1ch @ rbp-0x1c
|           ; var int local_18h @ rbp-0x18
|           ; var int local_4h @ rbp-0x4
|              ; CALL XREF from 0x004009c3 (main)
|           0x004007b9      55             push rbp
|           0x004007ba      4889e5         mov rbp, rsp
|           0x004007bd      48897de8       mov qword [local_18h], rdi
|           0x004007c1      8975e4         mov dword [local_1ch], esi
|           0x004007c4      c745fc000000.  mov dword [local_4h], 0
|       ,=< 0x004007cb      e9d6000000     jmp 0x4008a6
|       |      ; JMP XREF from 0x004008aa (sym.giff_flag)
|      .--> 0x004007d0      8b05ae182000   mov eax, dword [obj.num2]    ; eax = num2 ; num2 是交流次数,最大为 8
|      :|   0x004007d6      99             cdq
|      :|   0x004007d7      c1ea1f         shr edx, 0x1f
|      :|   0x004007da      01d0           add eax, edx
|      :|   0x004007dc      83e001         and eax, 1                   ; eax = eax & 1 = num2 % 2
|      :|   0x004007df      29d0           sub eax, edx
|      :|   0x004007e1      85c0           test eax, eax
|     ,===< 0x004007e3      740a           je 0x4007ef                  ; eax == 0 时跳转,即 num2 % 2 == 0
|     |:|   0x004007e5      83f801         cmp eax, 1                  ; 1
|    ,====< 0x004007e8      745e           je 0x400848                  ; eax == 1 时跳转
|   ,=====< 0x004007ea      e9b3000000     jmp 0x4008a2
|   |||:|      ; JMP XREF from 0x004007e3 (sym.giff_flag)   ; 情况一:num2 % 2 != 1
|   ||`---> 0x004007ef      8b45fc         mov eax, dword [local_4h]    ; eax = i ; i 是循环计数
|   || :|   0x004007f2      4863d0         movsxd rdx, eax              ; rdx = eax = i
|   || :|   0x004007f5      488b45e8       mov rax, qword [local_18h]   ; rax = &flag
|   || :|   0x004007f9      488d3402       lea rsi, [rdx + rax]         ; rsi = &flag + i = &flag[i]
|   || :|   0x004007fd      8b45fc         mov eax, dword [local_4h]    ; eax = i
|   || :|   0x00400800      4863d0         movsxd rdx, eax              ; rdx = eax = i
|   || :|   0x00400803      488b45e8       mov rax, qword [local_18h]   ; rax = &flag
|   || :|   0x00400807      4801d0         add rax, rdx                 ; rax = &flag + i
|   || :|   0x0040080a      0fb600         movzx eax, byte [rax]        ; eax = flag[i]
|   || :|   0x0040080d      89c7           mov edi, eax                 ; edi = eax = flag[i]
|   || :|   0x0040080f      8b45e4         mov eax, dword [local_1ch]   ; eax = key ; key 是交谈语句的序号
|   || :|   0x00400812      0faf45fc       imul eax, dword [local_4h]   ; eax = eax * i = key * i
|   || :|   0x00400816      89c1           mov ecx, eax                 ; ecx = eax = key * i
|   || :|   0x00400818      baa7c867dd     mov edx, 0xdd67c8a7
|   || :|   0x0040081d      89c8           mov eax, ecx
|   || :|   0x0040081f      f7ea           imul edx
|   || :|   0x00400821      8d040a         lea eax, [rdx + rcx]
|   || :|   0x00400824      c1f805         sar eax, 5
|   || :|   0x00400827      89c2           mov edx, eax
|   || :|   0x00400829      89c8           mov eax, ecx
|   || :|   0x0040082b      c1f81f         sar eax, 0x1f
|   || :|   0x0040082e      29c2           sub edx, eax
|   || :|   0x00400830      89d0           mov eax, edx
|   || :|   0x00400832      c1e003         shl eax, 3
|   || :|   0x00400835      01d0           add eax, edx
|   || :|   0x00400837      c1e002         shl eax, 2
|   || :|   0x0040083a      01d0           add eax, edx
|   || :|   0x0040083c      29c1           sub ecx, eax
|   || :|   0x0040083e      89ca           mov edx, ecx                 ; edx = ecx = key * i
|   || :|   0x00400840      89d0           mov eax, edx                 ; eax = edx = key * i
|   || :|   0x00400842      01f8           add eax, edi                 ; eax = eax + edi = flag[i] + input * i
|   || :|   0x00400844      8806           mov byte [rsi], al           ; flag[i] = flag[i] + input * i
|   ||,===< 0x00400846      eb5a           jmp 0x4008a2
|   |||:|      ; JMP XREF from 0x004007e8 (sym.giff_flag)   ; 情况二:num2 % 2 == 1
|   |`----> 0x00400848      8b45fc         mov eax, dword [local_4h]    ; eax = i
|   | |:|   0x0040084b      4863d0         movsxd rdx, eax              ; rdx = eax = i
|   | |:|   0x0040084e      488b45e8       mov rax, qword [local_18h]   ; rax = &flag
|   | |:|   0x00400852      488d3402       lea rsi, [rdx + rax]         ; rsi = &flag + i = &flag[i]
|   | |:|   0x00400856      8b45fc         mov eax, dword [local_4h]    ; eax = i
|   | |:|   0x00400859      4863d0         movsxd rdx, eax              ; rdx = eax = i
|   | |:|   0x0040085c      488b45e8       mov rax, qword [local_18h]   ; rax = &flag
|   | |:|   0x00400860      4801d0         add rax, rdx                 ; rax = &flag + i
|   | |:|   0x00400863      0fb600         movzx eax, byte [rax]        ; eax = flag[i]
|   | |:|   0x00400866      89c7           mov edi, eax                 ; edi = eax = flag[i]
|   | |:|   0x00400868      8b45e4         mov eax, dword [local_1ch]   ; eax = key
|   | |:|   0x0040086b      0faf45fc       imul eax, dword [local_4h]   ; eax = eax * i = key * i
|   | |:|   0x0040086f      89c1           mov ecx, eax                 ; ecx = eax = key * i
|   | |:|   0x00400871      baa7c867dd     mov edx, 0xdd67c8a7
|   | |:|   0x00400876      89c8           mov eax, ecx
|   | |:|   0x00400878      f7ea           imul edx
|   | |:|   0x0040087a      8d040a         lea eax, [rdx + rcx]
|   | |:|   0x0040087d      c1f805         sar eax, 5
|   | |:|   0x00400880      89c2           mov edx, eax
|   | |:|   0x00400882      89c8           mov eax, ecx
|   | |:|   0x00400884      c1f81f         sar eax, 0x1f
|   | |:|   0x00400887      29c2           sub edx, eax
|   | |:|   0x00400889      89d0           mov eax, edx
|   | |:|   0x0040088b      c1e003         shl eax, 3
|   | |:|   0x0040088e      01d0           add eax, edx
|   | |:|   0x00400890      c1e002         shl eax, 2
|   | |:|   0x00400893      01d0           add eax, edx
|   | |:|   0x00400895      29c1           sub ecx, eax                 ; ecx = (key * i) % 37
|   | |:|   0x00400897      89ca           mov edx, ecx                 ; edx = ecx
|   | |:|   0x00400899      89d0           mov eax, edx                 ; eax = edx = ecx
|   | |:|   0x0040089b      29c7           sub edi, eax                 ; edi = edi - eax = flag[i] - key * i % 37
|   | |:|   0x0040089d      89f8           mov eax, edi                 ; eax = edi
|   | |:|   0x0040089f      8806           mov byte [rsi], al           ; flag[i] = flag[i] - key * i % 37
|   | |:|   0x004008a1      90             nop
|   | |:|      ; JMP XREF from 0x00400846 (sym.giff_flag)
|   | |:|      ; JMP XREF from 0x004007ea (sym.giff_flag)
|   `-`---> 0x004008a2      8345fc01       add dword [local_4h], 1      ; i = i + 1
|      :|      ; JMP XREF from 0x004007cb (sym.giff_flag)
|      :`-> 0x004008a6      837dfc24       cmp dword [local_4h], 0x24  ; [0x24:4]=-1 ; '$' ; 36
|      `==< 0x004008aa      0f8e20ffffff   jle 0x4007d0                 ; i <= 36 时跳转
|           0x004008b0      8b05ce172000   mov eax, dword [obj.num2]   ; [0x602084:4]=0
|           0x004008b6      83c001         add eax, 1
|           0x004008b9      8905c5172000   mov dword [obj.num2], eax   ; [0x602084:4]=0
|           0x004008bf      5d             pop rbp
\           0x004008c0      c3             ret

该函数的汇编代码大概可以整理成下面的伪代码:

int num2 = 0;  // 交谈次数
void giff_flag(&flag, int key) {
    for(int i = 0; i <= 36; i++) {
        if (num2 % 2 == 1) {
            flag[i] = flag[i] - i * key % 37;
        } else {
            flag[i] = flag[i] + i * key % 37;
        }
    }
    num2++;
}

我们知道 flag 的格式应该是 ECTF{...},所以只要初始 flag 在多次转换后出现这几个字符,就很可能是最终的 flag 了。我们已经理清了算法,接下来的事情就交给 Z3 了。

参考资料

下载文件
题目解析
参考资料