N1CTF2020 oflo:花指令、自修改代码与 ptrace 反调试分析

拿到题目先查壳和文件类型 发现是个elf文件,没用壳。直接用IDA打开。 在ODA里面找到main函数,发现不能直接转换为伪代码。 直接看汇编指令。在0000000000400BB1处IDA解析的汇编有问题,依据loc_400BB1+1,将400BB1处第一个字节nop,继续往下看 ,看到一个奇怪的调用( call loc_400BBF), call 400BBF 执行时会将下一条指令地址 400BBC 压入栈中,随后 pop rax 将该返回地址取出,再通过 add rax, 1 将其修改为 400BBD,最终通过 retn 将执行流转移到 400BBD。 已知从400BBD开始,所以将400BBD开始的内容转换为code,400BBC直接nop. 这里直接跟进loc_400BD1, 这里看到三个函数sub_4008B9,loc_400BEF,loc_400CAC,通过跟进函数可以发现sub_4008B9,loc_400BEF这两个函数都没用问题,但是loc_400CAC处有和之前相似的花指令。 直接用之前的方法,把 400CB5-400CBA 和400CBD-400CCE 全部patch 为nop。 出现 jmp short loc_400CCF 继续跟进这个跳转。 这里可以看到 在 0x400D04 又发现一个非常经典的花指令,还是直接将第一个字节 patch 为 nop。 这样看起来就像一个正常的函数结尾了。 现在返回400B54(main的开头),先 p 一下重新建立函数,之后就可以正常 F5 反编译了 。 main函数的主要流程: 首先调用sub_4008B9;接着接收输入的19个字符;随后调用mprotect,修改sub_400B54 & 0xFFFFC000为首页地址区域的权限,将其改为 r | w | x ;紧跟着是改变400A69处的前10个字节;最终是调用sub_400A69检查flag是否正确。 程序开始 ↓ 调用 sub_4008B9 ↓ 接收用户输入 19 个字符 ↓ 调用 mprotect ↓ 将代码所在内存页权限修改为 R | W | X ↓ 使用输入的前 5 个字符 循环 XOR 修改 sub_400A69 的前 10 个字节 ↓ 恢复出运行时真正执行的代码 ↓ 调用 sub_400A69 ↓ 进行 Flag 校验 ↓ ┌───────────────┐ │ 校验是否正确 │ └───────┬───────┘ ↓ 正确 错误 ↓ ↓ 输出 Cong! 返回失败 由于题目是:N1CTF2020 - oflo,所以输入的前5个字符是n1ctf, ...

September 22, 2026 · 1 min

RC4 + VM 逆向分析

RC4 + VM 逆向分析 题目地址 首先,拿到题目查看是否有壳从区段中能看到题目没有壳。 然后用IDA打开题目,一打开就是程序的主函数。 看主要的函数,首先是lpAddress_1,开辟了一个空间,通过Size可以看到大小是0xD2Bh,继续往下看if判断是否开辟空间成功。memcpy让lpAddress_1指向unk_140005000这个地址。跟进这个地址发现是数据,但是在主函数上有lpAddress_1(v14),说明这里是能传入一个参数的,这里就不可能是数据,肯定是代码。选定unk_140005000,按"C"就能将数据转换为代码。看这个函数的伪代码 根据函数的特征可以确定是RC4。 Key 地址: 0x14000528A Key: centralCEE_33x000333 Key 长度: 0x14 = 20 bytes 待解密数据: 0x14000529E 长度: 0xA8D = 2701 bytes 算出需要解密的范围 0x14000529E + 0xA8D = 0x140005D2B 先将需要的代码dump,在IDA自带的python写脚本。然后再对保存的文件进行RC4解密。 start = 0x7FF79548529E size = 0xA8D data = ida_bytes.get_bytes(start, size) if data is None: print("读取失败!") else: print("成功读取:", len(data), "bytes") with open(r"D:\rc4_data.bin", "wb") as f: f.write(data) print("已保存到 D:\\rc4_data.bin") def rc4(key, data): S = list(range(256)) j = 0 # KSA for i in range(256): j = (j + S[i] + key[i % len(key)]) & 0xFF S[i], S[j] = S[j], S[i] # PRGA i = 0 j = 0 result = bytearray() for byte in data: i = (i + 1) & 0xFF j = (j + S[i]) & 0xFF S[i], S[j] = S[j], S[i] k = S[(S[i] + S[j]) & 0xFF] result.append(byte ^ k) return bytes(result) with open(r"D:\rc4_data.bin", "rb") as f: ciphertext = f.read() key = b"centralCEE_33x000333" plaintext = rc4(key, ciphertext) with open(r"D:\rc4_decrypted.bin", "wb") as f: f.write(plaintext) print("输入数据:", len(ciphertext), "bytes") print("解密数据:", len(plaintext), "bytes") print("已保存到 D:\\rc4_decrypted.bin") 现在得到的文件就是解密好的,将文件拖入IDA中,选择64-bit mode。 ...

September 15, 2026 · 11 min