DASCTF 2023 10 wp
DASCTF 2023 10 wp
auuuu3
通过解析autoit动态脚本语言执行命令,先安装这个工具
https://github.com/nazywam/AutoIt-Ripper
在Scripts文件夹中找到autoit-ripper.exe
程序,按照语法输入得到script.au3文件
得到的au3文件分析加密的流程:
1 | Func ENC ( $DATA , $KEY ) |
定义一个机器码 OPCODE
1 | Local $OPCODE = "0x83EC14B83400000099..." |
- 这是嵌入在脚本里的 x86汇编机器码。
- 实际上就是一个加密函数的实现(比如某种对称加密:TEA、XTEA 或 AES 的变种)。
- 脚本不会自己实现算法,而是通过调用这段机器码来执行。
创建结构体作为缓冲区
$CODEBUFFER
:存储这段机器码。$V
:存储待加密的数据,补齐到 4 字节对齐。$K
:存储 16 字节的密钥。
1 | import binascii |
把机器码携带文件方便我们IDA打开分析
xxtea
6
是 XXTEA 设计里保证最小轮数的常数,目的是给最少轮数的安全保证(6 + 52/n
)。
n = 10
是因为密文长 40 字节,而 XXTEA 的处理单位是 4 字节一个 uint32
,所以需要 40 ÷ 4 = 10 个元素。
1 | v = struct.unpack('<10I', ct) |
<
表示 小端序(least-significant byte first,和 x86/Windows 一致)。
10I
表示读取 **10 个 unsigned int (32 位无符号整数)**。
dis 模块是 Python 的字节码反汇编器,用于分析 CPython 的字节码。字节码是 Python 代码在解释器中运行的中间形式,dis 模块可以帮助开发者理解代码的底层执行逻辑,尤其在性能优化和调试中非常有用。
exp:
1 | import binascii |
marshal
1 | import marshal |
之前做过一道类似的题在seccon里
用 marshal.loads
把 CodeObject 加载出来,但不要执行。
然后用 dis.dis()
(反汇编)或者 uncompyle6 / decompyle3
把字节码翻译成人能读的 Python 伪代码。
1 | print(dis.dis(l)) |
发现中间有一大块
定义了 Sbox
(16 项,正好是 PRESENT 密码的 S 盒)
定义了 PBox
(64 项,正好是 PRESENT 的 64-bit 置换层)以及各自的逆表 Sbox_inv
、PBox_inv
在常量 #68 里塞了“第二层”字节码(一个更长的 b'c\x00\x00...'
),然后 marshal.loads(...); exec(...)
去执行它
1 | import marshal |
…非常的又臭又长
解密Exp:
1 | SBOX = [12,5,6,11,9,0,10,13,3,14,15,8,4,7,1,2] |
1 | Sbox = [12, 5, 6, 11, 9, 0, 10, 13, 3, 14, 15, 8, 4, 7, 1, 2] |
vm_flutter
flutter然后java层打开发现了类似虚拟机的东西
有类似密文的东西
这里可以看到是比如S(来自dex),他是因为反编译器有多个S方法所以改成了m1944S,我们要进行hook,要对这个原来的方法进行hook,而dex本来就是被混淆过的,但是不影响我们hook
在 Frida 里要 hook 的是真实 dex 里的方法名 h
,不是 jadx 生成的 m1037h
。
如果觉得反混淆难看直接关了就行
1 | let C0434b = Java.use("k.b"); |
好久没做安卓逆向的frida题了命令都快忘了
1 | frida-ps -u -a 是 Frida 工具中的一个命令,用于列出通过 USB 连接的设备上所有运行的进程,并显示详细信息。 |
hook一下
1 | function hook(){ |
只打印、不执行原逻辑:把
k.b
的方法全部拦截后没有调用原始实现(没orig.apply(...)
),所以 VM 不会真正 push/pop/load/store,最终f741b
也不会被写,S()
基本过不去。它适合“只想看指令序列”的场景
output:
1 | push 48 |
可以发现有规律的
1 | push 48 |
官解的似乎不是很详细,我这完善了一份更详细的
1 | // hook_vm_final.js — 打印+透传所有 k.b 指令,并在 S 返回后 dump f741b(最终内存) |
运行后为
1 | push 48 |
1 | push 48 |
观察其实就是做了个add 然后 xor
1 | 48 + 11 = 59 |
我把两种都放在了下面其实一样
1 | import re |