IR0NBYTE/Karukatta
GitHub: IR0NBYTE/Karukatta
一款内置混淆的原生机器码编译型语言,探索底层编译原理并生成难以逆向的小型可执行文件。
Stars: 6 | Forks: 0
# Karukatta
一种生成原生机器码并内置混淆功能的编译型语言。不需要汇编器,也不需要链接器——直接将原始字节输出为可执行文件。
同时支持 **x86-64 Linux** 和 **ARM64 macOS**(Apple Silicon)。
## 这是什么?
Karukatta 是一个小型语言,我编写它是为了探索编译器是如何在底层工作的——从解析到最终对每条机器指令进行编码。特点是:它生成的每个二进制文件都可以在出厂时进行混淆。控制流平坦化、死代码注入、指令替换等功能都内置于编译器流水线中。
编译器全权负责所有流程。在 Linux 上,它直接写入 ELF 二进制文件(无需 NASM、无需 LD、没有任何中间工具)。在 macOS 上,它生成原始 ARM64 机器码并交给系统链接器进行代码签名。
## 快速开始
```
git clone https://github.com/IR0NBYTE/Karukatta.git
cd Karukatta
./runner.sh
```
编写程序:
```
let a = 5;
let b = 3;
let result = a * 2 + b;
exit(result); // exits with 13
```
编译并运行:
```
./build/karukatta program.kar -o program
./program
echo $? # 13
```
启用混淆编译:
```
# level 1: instruction substitution
./build/karukatta program.kar -o program --obf=1
# level 2: control flow flattening + dead code injection
./build/karukatta program.kar -o program --obf=2
# different seed = different binary, same behavior
./build/karukatta program.kar -o program --obf=2 --seed=1337
```
## 语言特性
目前功能较为基础——支持整数、变量、比较、分支和循环。
```
let score = 75;
if (score >= 90) {
exit(1); // A
} else {
if (score >= 70) {
exit(2); // B
} else {
exit(3); // C
}
}
```
```
// all the comparison operators work
let a = 10;
let b = 20;
let eq = a == b; // 0
let ne = a != b; // 1
let lt = a < b; // 1
let sum = eq + ne + lt;
exit(sum); // 2
```
```
// while loops
let flag = 1;
while (flag) {
exit(42);
}
```
**当前支持:**
- `let` 绑定(不可变)
- `+` `-` `*` `/` 算术运算
- `==` `!=` `<` `<=` `>` `>=` 比较运算
- `if` / `else`
- `while` 循环
- `{ }` 作用域块(支持变量遮蔽)
- `//` 注释
- `exit(n)` 设置进程退出码
**尚未支持:**
- 函数
- 字符串
- 数组
- 可变变量
- 标准库
## 编译器工作原理
```
source.kar
|
v
[Lexer] tokenizes the source
|
v
[Parser] builds an AST (Pratt parsing for expressions)
|
v
[IR] lowers to three-address code with virtual registers
|
v
[Passes] optimization + obfuscation (if enabled)
|
v
[Backend] encodes to real machine instructions
| (x86-64: REX + opcode + ModR/M + SIB)
| (ARM64: fixed 32-bit instruction encoding)
v
[Emitter] wraps in ELF (Linux) or Mach-O (macOS)
|
v
executable
```
在 Linux 平台上,编译器完全不依赖外部工具——它直接将 ELF 头、程序头表以及机器码字节写入文件,最终生成可执行文件。
## 混淆功能
这是最有趣的部分。编译器包含一个 IR 传递系统,其中部分传递专门用于使输出更难以逆向工程。
**`--obf=1`** - 指令替换。简单操作会被替换为等价但更复杂的序列。例如 `ADD a, b` 可能变为 `SUB a, NEG(b)` 或 `a + b + noise - noise`。每次使用不同的 `--seed` 都会产生不同的替换策略。
**`--obf=2`** - 在 Level 1 基础上,增加控制流平坦化和死代码注入。CFF 将所有基本块重写为一个状态机调度器——每个块转移都通过一个对随机化状态变量的中央 `switch` 完成。死代码插入会在不影响输出的情况下,随处散布虚假计算。
结果:相同的源代码,每次编译都会生成截然不同的二进制文件。试试看:
```
./build/karukatta example.kar -o bin1 --obf=2 --seed=111
./build/karukatta example.kar -o bin2 --obf=2 --seed=222
# both produce the same exit code, but:
diff <(xxd bin1) <(xxd bin2) # completely different binaries
```
## 跨平台编译
编译器会自动检测当前平台,但你也可以手动指定目标:
```
# compile for x86-64 Linux (produces a standalone ELF, no dependencies)
./build/karukatta program.kar -o program --target=x86_64-linux
# compile for ARM64 macOS
./build/karukatta program.kar -o program --target=arm64-macos
# dump the IR to see what the compiler is doing
./build/karukatta program.kar -o program --dump-ir
```
## 构建
你只需要一个 C++17 编译器。仅此而已。
```
./runner.sh
```
或者手动构建:
```
g++ -std=c++17 main.cpp -o build/karukatta
```
在 macOS 上测试 Linux 二进制文件,请使用 Docker:
```
./build/karukatta program.kar -o build/program --target=x86_64-linux
docker run --rm -v $(pwd)/build:/app ubuntu:22.04 sh -c '/app/program; echo $?'
```
## 项目结构
```
Karukatta/
├── main.cpp # compiler driver + CLI
├── pkg/
│ ├── lexer.hpp # tokenizer
│ ├── parser.hpp # recursive descent + Pratt parsing
│ ├── arena.hpp # bump allocator for AST nodes
│ ├── ir.hpp # intermediate representation
│ ├── ir_builder.hpp # AST -> IR lowering
│ ├── target/
│ │ ├── x86_64.hpp # x86-64 instruction encoder
│ │ └── arm64.hpp # ARM64 instruction encoder
│ ├── emit/
│ │ ├── elf.hpp # ELF64 binary writer
│ │ └── macho.hpp # Mach-O binary writer
│ └── passes/
│ ├── pass.hpp # pass interface + seeded RNG
│ ├── cff.hpp # control flow flattening
│ ├── insn_sub.hpp # instruction substitution
│ └── dead_insert.hpp # dead code insertion
├── example/ # test programs
├── docs/ # language spec + architecture docs
└── runner.sh # build script
```
## 语法定义
```
program ::= statement*
statement ::= exit_stmt | let_stmt | scope | if_stmt | while_stmt
exit_stmt ::= "exit" "(" expression ")" ";"
let_stmt ::= "let" identifier "=" expression ";"
scope ::= "{" statement* "}"
if_stmt ::= "if" "(" expression ")" scope ("else" scope)?
while_stmt ::= "while" "(" expression ")" scope
expression ::= term (operator term)*
operator ::= "+" | "-" | "*" | "/" | "==" | "!=" | "<" | "<=" | ">" | ">="
term ::= integer_literal | identifier | "(" expression ")"
```
## 许可证
MIT
标签:Apple Silicon, ARM64, ARM64 macOS, compiled language, native code, obfuscation, x86-64, x86-64 Linux, 二进制混淆, 代码混淆, 原生机器码, 可执行文件, 可执行混淆, 底层编码, 指令替换, 指令混淆, 控制流平坦化, 无汇编器, 无链接器, 机器码生成, 死代码注入, 直接编码, 种子随机化, 程序混淆, 编译器内置混淆, 编译器探索, 编译语言, 自编译