【文章标题】: riijj crackme 16 花指令系统 - 制作原理及方法
【文章作者】: riijj
【文章对象】: 初入门新手
【作者声明】: 本文章为了推动大家对软件保护方法的研究, 吸引大家产生兴趣。如内容有错误或不足之处, 欢迎提点, 谢谢。
Part 1.
序
本篇文章会很简单地解释 riijj crackme 16 (包括 E 版和 G 版) 的制作过程, 运作原理, 并分享一些设计的思路。希望看雪论坛的各位兄弟, 可以从中激发起一些创新想法, 提起软件保护技术和 crackme 制作的兴趣。
Part 2.
目标
相信有玩过这个 crackme 的朋友, 在 OD 打开它的时候, 第一个反应就是 : “呵, 全都是数据, 全都花了 ?!”
对, 这个 crackme 很简单, 它的主要保护方式, 是传统的花指令 (junk code) 和 代码乱序。
花指令是保护软件的最基础方法。所有软件加壳保护, 都会用花指令的方法来编写壳代码。使用花指令就是要让 debugger (调试器) 反汇编的时候出现混乱。
在软件保护的众多方法之中, 花指令和 SMC, 是最基本的。
所以, 我们在使用各种软件保护方法 (包括各种 anti) 的时候, 如果能够使用花指令来保护所有代码, 这是最基本要求。
新型软件保护, 有 vm (virtual machine), 它的作用是使得我们反汇编的时候不能显示出人类所能理解的指令意义。相同地, 使用花指令是为了阻止破解者得到最基本的指令意义
如果, 能够使反汇编引擎, 失败的话, 我们的任务便完成。(其它的软件保护技术, 包括各种 anti, 都由作者自行安排加入。我们的任务, 只是使反汇编器混乱)
如果, 使用 10 条花指令, 比使用 1 条更难令人理解的话, 我会考虑使用 1000 条。
Part 3.
设计
我们需要一个工具, 可以把一个 exe 程序变成充满花指令的 “花园”。
第一步, 我考虑了写一个工具, 读取 exe, 并且重新安排插入花指令, 再组合成新的 exe 程序:
S: 源码
E: 原程序 exe
X: 加入了花指令的 exe, 最终成品
E = compile(S) , 我们把程序编译好, 成为了普通 exe
X = flower(E) , 把 exe 放入花指令工具, 得到了受到保护的 exe (X)
后来, 我发现这个方法, 需要很大的劳动:
1. 要写一个反汇编引擎, 读取 Exe 的内容, 进行反汇编
2. 要写一个工具直接处理读取换来的一条条 opcode指令, 非常低层次的工具
3. 要写一个极麻烦的工具, 把加入了花的指令, 重新合体成 exe
想到这里, 我放弃了。
--------------------------------
第二步, 我想想怎样可以简化这个工作, 而获得相同效果:
S: 源码
E: 原程序 exe
X: 加入了花指令的 exe, 最终成品
D: 反汇编出来的 asm代码
D = OllyDbg( E) , 使用 OD 来把 exe 反汇编好, 然后储存做文字文件 (D).
D2 = flower(D) , 做一个工具, 把文字文件 D 读取, 建立数据, 加入花指令, 重组成一推 opcode, 是一个 binary
X = flower2(D2) , 把重组了的指令, 强行填进去原程序的指令 (.code) 部份
这个方法, 十分落后, 花了很多时间 (2 个星期以上), 最后制作成了我的 riijj crackme 15。
------------------------------
第三步,
如果, 我们有方法, 可以在早期便加入花指令, 然后才送去 compiler 编成 exe, 这样大家都快乐了。
S: 源码
E: 原程序 exe
X: 加入了花指令的 exe, 最终成品
A: 编译器产生的 asm 码
A = compile(S)
A2 = flower(A)
X = compile(A2)
寻找了很久, 我希望找一个方式, 使 compiler 产生 asm 指令文文件。
(给初学者 : compiler 的工作, 是产生出 asm 码, linker 的工作, 才是产生出 object (executable))
第一次, 试了 VC6 , Visual studio 各版本, 效果不理想。
第二次, 试了著名的 gcc, 发现可用, 而且 gcc 的各种设计非常灵活, 是制作这种程序的良好工具。
(gcc 就是 Linux 的 compiler, 它是世界上最强的 C 和 C++ 编译工具。)
在 windows 下, 我们需要使用 mingw 套装, 它是 windows 版的 gcc。
再花了一些时间研究 gcc, 得出结果
gcc -mwindows -S c16.c -masm=intel -o c16.s
这样可以产生出一个完整性 100% 的 intel 格式 asm 源码 (c16.s), 这个源码可以直接编成 exe, 不需任何特别处理, 嗯, 就是要找到你了。
gcc -mwindows c16.s aaa.o -o c16.exe
当中的 aaa.o 是 crackme 的 resource file, 使用 windres得到。
成功得到 exe 后, 再使用 strip c16.exe 来把 exe 减去垃圾部份, 便大功告成了。
-----------------------------
第四步,
我们可以开始着手, 去弄一个工具, 它可以读取 asm 源码, 并且放入花指令。我想, 怎样写这个工具呢 ? 可是, 今次我们不应该用 C 语言。
C 语言是一个非常强悍的工具, 我是非常热爱 C 语言, 认识我的朋友都知道,
但是, C 语言是一个系统编程语言。处理 binary 数据, 它是强的, 处理文字的话,有点吓人。它绝对不适合处理一些文书性的东西。
所以, 我决定使用一个有趣的方法, 它就是处理文字的高手 : php
我写了一个 php 网页, 来产生加入花指令的 asm。这个网页很简单, 它读取 c16.s, 并产生 c16x.s 的文字文件。
Part 4.
实践
第一步, 是了解 php。
php 的确比 C 语言慢很多, 可是, 大家绝对不要小看它。
- 在一个普通 PC 上 (我的家庭计算机), 做一个 array, 对它插入数据 20000 次, 不需要 1 秒钟
- Sorting 重新排列一个数万行的 array 巨型数据, 不需要 1/10 秒。
大家都是写系统编程出身的, 可能会想 : 写一个 C 程序才是工具, 才是快速高效。
但是, 我今次的目的, 主要是一个实验 : 要知道这样的花指令, 有真正强度吗 ?
如果, 说修改程序的容易性, 方便性, 复杂流程的控制, php 绝对比 C 程序强 10 倍。
今次的目标是 riijj crackme 16, 使用 php, 进行以下动作:
Step 1: 读取源码, 并把它变成数据 (lines array)
Step 2: 每一行 asm 指令作为一个独立单位, 原码中所有 jmp 的 target label 位置, 会特别留意
Step 3: 重复动作 : 随机挑选出一行, 把它移到到另一个新的随机位置, 插入 jmp 指令作为连结
Step 4: 移动后的指令, 分别在 jmp部份, 和目的地, 插入花指令, 花指令以一些随机产生的 binary 结合一些固定指令而成。包括了一些令 OD 头晕的 call 指令。
Step 5: 重复以上动作, 再挑选下一条指令, 指令的选择范围包含了刚刚加入的花指令, 也是说, 花指令本身也会被进一步移动, 及「花」化。
Step 6: 完成第一阶段, 第二阶段, 在现在的指令中,随机挑选一些指令进行「花」化, 进一步使程序复杂化。
Step 7: 完成, 输出 asm 文件
这个程序, 重复 1000 次, 便成为了 riijj crackme 16。
后来, 因为编写时的问题, 发生了一些不稳定情况, 后来再编出 riijj crackme 16e 修正版本。
当然, 还有后来的 G 版本, 那个 riijj crackme 16g 是一个执行了 50000 次花的巨型版本, 也换了新算法
(关于那个算法, 要将来再跟大家分享了, ccfer 大侠发现了算法有 2000个指令, 是对的, 而且, 这 2000 个指令, 都不是写的, 也是产生的, 呵)
Part 5.
总结
写这一篇, 是希望提起大家的兴趣。如果这个 crackme 16g 没有人能破解的话, 或许会吸引我写一个 C 语言的工具出来, 给大家测试玩。但是, 这个 crackme 很快便完蛋了 (多谢 ccfer 和 sessiondiy 兄弟)。
大家也应该找到了自己的方法来做下一个 crackme 了, 不一定要跟我相同, 重点是, 你可以想象到有多远。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课