CTF逆向陷阱:函数HOOK让异或算法瞬间失效,手把手教你揪出真flag

admin 2026-05-14 13:18:08 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文通过一道CTF逆向题目,详细解析了函数HOOK技术如何使异或加密失效的反调试手法。文章揭示了程序通过VirtualProtect修改内存权限,利用ReadProcessMemory/WriteProcessMemory动态替换关键数据,并最终发现真实加密算法为魔改XXTEA。关键发现包括HOOK点定位、内存修改分析流程,并提供了完整的动态调试方法和Python解密脚本,成功获取flag。 综合评分: 85 文章分类: CTF,逆向分析,红队,漏洞分析,WEB安全


cover_image

CTF逆向陷阱:函数HOOK让异或算法瞬间失效,手把手教你揪出真flag

原创

小话安全 小话安全

小话安全

2026年5月14日 00:17 山东

在小说阅读器读本章

去阅读

在CTF逆向中,异或(XOR) 算法简单到几乎“有手就行”——找到key和密文,一行Python脚本就能爆flag。

但如果出题人偷偷用了函数HOOK呢?

你在IDA里提取的key是假的,密文是错的,甚至比较函数都被替换了。

VirtualProtect、ReadProcessMemory、WriteProcessMemory

 特别是当这三个“危险函数”联手登场时,静态分析直接沦为废铁。

本文通过一道真实CTF题目,带你彻底搞懂这种XOR + HOOK的反调试与反静态分析手法。

打开程序看到了三个危险函数

分析主程序

设置断点进行调试

根据题目要求输入flag,长度是40

将我们的输入改成00 00 00 以获取第一个异或的数值

执行完第一次异或后0变成了s,因此异或的变量为0x73

导出加密后数据和密钥

编写脚本解密

我们发现这个flag是错误的,为什么错误呢,我们看最开始的那几个危险函数。

各步骤行为分析

  1. VirtualProtect(lpAddress, 0x1000, 0x40, &flOldProtect)
  • 0x40 = PAGE_EXECUTE_READWRITE
  • 将目标内存页(很可能是 .text 代码段或 .data 数据段)设置为可读可写可执行,暂时解除写保护。
  • 目的是为了后续能够改写内存中的指令或数据。
  1. ReadProcessMemory(hProcess, lpBaseAddress, Buffer, 8, NULL)
  • 从自身进程(hProcess 通常是 GetCurrentProcess())中读取 lpBaseAddress 处的 8字节 内容,保存到 Buffer
  • 这8字节原本是指令或原始数据,先备份起来,以便后续恢复(或用于校验)。
  1. VWriteProcessMemory(hProcess, (LPVOID)lpBaseAddress, &v13, 8, NULL)
  • 将局部变量 v13 的8字节内容写入到 lpBaseAddress 处。
  • 这就是HOOK的核心:用新数据覆盖原位置。
  • 如果 lpBaseAddress 指向代码段,则相当于动态修改指令(比如把 xor eax, eax 改成 mov eax, 1)。
  • 如果指向数据段(如 key 或 enc 数组),则直接替换全局变量。
  1. VirtualProtect(lpAddress, 0x1000, flOldProtect, &flOldProtect)
  • 恢复内存页的原始属性(通常是 PAGE_READONLY 或 PAGE_EXECUTE_READ)。
  • 目的是隐藏修改痕迹,让静态分析或后续的内存扫描难以察觉。

V13是a1,找到a1

查看函数的交叉引用

strcpy(LibFileName, "User32.dll");strcpy(ProcName, "MessageBoxA");hProcess = GetCurrentProcess();ModuleHandleW = GetModuleHandleW(0i64);hModule = LoadLibraryA(LibFileName);if (!hModule) exit(0);ProcAddress = GetProcAddress(hModule, ProcName);
  • 准备目标DLL名 User32.dll 和函数名 MessageBoxA
  • 获取当前进程句柄(用于后续 ReadProcessMemory/WriteProcessMemory)。
  • ModuleHandleW = 当前进程的基址(EXE的基址)。
  • 加载 User32.dll 并获取 MessageBoxA 的真实地址(ProcAddress)。

也就是程序在弹窗提示正确或错误时执行了别的函数

分析执行的函数,对之前的加密进行了反向操作,获取到了输入数据的值

分析加密函数,这是一个魔改的XXTEA

设置断点导出加密后的数据和密钥

用AI编写解密脚本获得flag

import struct
def&nbsp;bytes_to_uint32_le(data):&nbsp; &nbsp;&nbsp;"""将字节数组(小端序)转换为32位无符号整数列表"""&nbsp; &nbsp; n =&nbsp;len(data) //&nbsp;4&nbsp; &nbsp;&nbsp;return&nbsp;[struct.unpack('<I', data[i*4:(i+1)*4])[0]&nbsp;for&nbsp;i&nbsp;in&nbsp;range(n)]
def&nbsp;uint32_to_bytes_le(v):&nbsp; &nbsp;&nbsp;"""将32位无符号整数列表转换为小端序字节数组"""&nbsp; &nbsp;&nbsp;return&nbsp;b''.join(struct.pack('<I', x)&nbsp;for&nbsp;x&nbsp;in&nbsp;v)
def&nbsp;xxtea_decrypt(v, key):&nbsp; &nbsp;&nbsp;"""&nbsp; &nbsp; XXTEA解密&nbsp; &nbsp; v: 32位无符号整数列表(密文)&nbsp; &nbsp; key: 4个32位无符号整数列表(密钥)&nbsp; &nbsp; 返回解密后的整数列表&nbsp; &nbsp; """&nbsp; &nbsp; n =&nbsp;len(v)&nbsp; &nbsp;&nbsp;if&nbsp;n <&nbsp;2:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;v &nbsp;# 长度至少为2,否则无需处理
&nbsp; &nbsp; delta =&nbsp;0x11451981&nbsp;#注意值会变&nbsp; &nbsp; rounds =&nbsp;6&nbsp;+&nbsp;52&nbsp;// n&nbsp; &nbsp;&nbsp;# 初始sum = rounds * delta,并保证32位无符号&nbsp; &nbsp; total_sum = (rounds * delta) &&nbsp;0xFFFFFFFF&nbsp; &nbsp; y = v[0]&nbsp; &nbsp;&nbsp;while&nbsp;rounds >&nbsp;0:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 每轮的sum用于计算e&nbsp; &nbsp; &nbsp; &nbsp; e = (total_sum >>&nbsp;2) &&nbsp;3&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;for&nbsp;p&nbsp;in&nbsp;range(n-1,&nbsp;0, -1):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; z = v[p-1]&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# MX宏的计算,所有运算均在32位无符号范围内&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mx = (((z >>&nbsp;5) ^ (y <<&nbsp;2)) + ((y >>&nbsp;3) ^ (z <<&nbsp;4))) ^ ((total_sum ^ y) + (key[(p &&nbsp;3) ^ e] ^ z))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; v[p] = (v[p] - mx) &&nbsp;0xFFFFFFFF&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; y = v[p]&nbsp; &nbsp; &nbsp; &nbsp; z = v[n-1]&nbsp; &nbsp; &nbsp; &nbsp; mx = (((z >>&nbsp;5) ^ (y <<&nbsp;2)) + ((y >>&nbsp;3) ^ (z <<&nbsp;4))) ^ ((total_sum ^ y) + (key[(0&nbsp;&&nbsp;3) ^ e] ^ z))&nbsp; &nbsp; &nbsp; &nbsp; v[0] = (v[0] - mx) &&nbsp;0xFFFFFFFF&nbsp; &nbsp; &nbsp; &nbsp; y = v[0]&nbsp; &nbsp; &nbsp; &nbsp; total_sum = (total_sum - delta) &&nbsp;0xFFFFFFFF&nbsp; &nbsp; &nbsp; &nbsp; rounds -=&nbsp;1&nbsp; &nbsp;&nbsp;return&nbsp;v
def&nbsp;main():&nbsp; &nbsp;&nbsp;# 密文字节数组 &nbsp;//IDA动态调试导出&nbsp; &nbsp; a = [&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;0xE4,&nbsp;0xE7,&nbsp;0xFE,&nbsp;0xE3,&nbsp;0x17,&nbsp;0x1C,&nbsp;0xDE,&nbsp;0x32,&nbsp;0xE6,&nbsp;0xB8,&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;0x68,&nbsp;0x40,&nbsp;0x40,&nbsp;0xD8,&nbsp;0x72,&nbsp;0xFA,&nbsp;0x88,&nbsp;0x14,&nbsp;0xE1,&nbsp;0x85,&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;0xCD,&nbsp;0x81,&nbsp;0xAA,&nbsp;0xDE,&nbsp;0x1D,&nbsp;0xE8,&nbsp;0x92,&nbsp;0x41,&nbsp;0xB8,&nbsp;0x1E,&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;0x5E,&nbsp;0xCF,&nbsp;0xCE,&nbsp;0x49,&nbsp;0x27,&nbsp;0x22,&nbsp;0x39,&nbsp;0x7D,&nbsp;0x50,&nbsp;0xDA&nbsp; &nbsp; ]&nbsp; &nbsp;&nbsp;# 密钥字节数组&nbsp; &nbsp; b = [&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;0x48,&nbsp;0x65,&nbsp;0x31,&nbsp;0x6C,&nbsp;0x30,&nbsp;0x4E,&nbsp;0x73,&nbsp;0x53,&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;0x21,&nbsp;0x11,&nbsp;0x45,&nbsp;0x14,&nbsp;0x19,&nbsp;0x19,&nbsp;0x81,&nbsp;0x00&nbsp; &nbsp; ]
&nbsp; &nbsp;&nbsp;# 转换为小端序32位整数&nbsp; &nbsp; cipher_int = bytes_to_uint32_le(bytes(a))&nbsp; &nbsp; key_int = bytes_to_uint32_le(bytes(b))
&nbsp; &nbsp;&nbsp;# 解密&nbsp; &nbsp; plain_int = xxtea_decrypt(cipher_int, key_int)
&nbsp; &nbsp;&nbsp;# 转换回字节&nbsp; &nbsp; plain_bytes = uint32_to_bytes_le(plain_int)
&nbsp; &nbsp;&nbsp;# 尝试解码为UTF-8文本(如失败则显示十六进制)&nbsp; &nbsp;&nbsp;try:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(plain_bytes.decode('utf-8'))&nbsp; &nbsp;&nbsp;except&nbsp;UnicodeDecodeError:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("解密结果(十六进制):", plain_bytes.hex())
if&nbsp;__name__ ==&nbsp;"__main__":&nbsp; &nbsp; main()
NSSCTF{C0ngr@tulat1ons!H0Ok_bY_1t_s3lf!}

免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:小话安全 小话安全 小话安全《CTF逆向陷阱:函数HOOK让异或算法瞬间失效,手把手教你揪出真flag》

评论:0   参与:  0