BrainFuck转C
前言
今天看到了帖子
记一次brainfuck的解密思路
https://www.52pojie.cn/thread-1441720-1-1.html
(出处: 吾爱破解论坛)
我居然才知道这语言竟然还能和脱壳破解挂上钩,这帖子里是将brainfuck转了python分析,我技术差,就转c,并稍微完善了下(相当于一个简单的解释器了)
本来想着和那贴一样发到脱壳破解区的,后来想想就这么简单个小程序就不碰瓷论坛技术大区了
Brainfuck简介
它是一种是一种极小化的程序语言,一种简单的,可以用最小的编译器来实现的,符合图灵完全思想的编程语言,后缀一般为.brainfuck
或.bf
它只有8个运算符,即
>
或<
: 指针加减1
+
或-
: 指针所指的字节的值加减1
,
或.
: 读取或输出指针所指字节内容(ASCII码)
[
或]
: 若指针所指字节的值为零,则向前/后跳转,跳转到其对应的[
或]
的下一个指令处
代码实现
实现命令行读取
这部分代码异常简单,我这里只有sys库提供的功能实现
import sys
if len(sys.argv) == 1:
print(f"Usage: {sys.argv[0]} input_file output_file")
sys.exit(1)
elif len(sys.argv) != 3 and len(sys.argv) != 2:
print("no input files")
sys.exit(1)
input_file = sys.argv[1]
try:
output_file = sys.argv[2]
except IndexError:
output_file = "a.c"
try:
with open(input_file, "r") as in_file:
program = in_file.read()
except IOError:
print(f"Cannot open input file: {input_file}")
sys.exit(2)
转化部分
根据刚才的对于运算符的解释,我们很容易得到它与c语言的对应关系,那么我先准备了一个字典,当然我这里使用了typing库来做了一些增加可读性的操作
from typing import Dict, List
CHAR_TO_OUTPUT: Dict[str, str] = {
">": "\t++ptr;\n",
"<": "\t--ptr;\n",
"+": "\t++*ptr;\n",
"-": "\t--*ptr;\n",
".": "\tputchar(*ptr);\n",
",": "\t*ptr = getchar();\n",
"[": "\twhile (*ptr) {\n",
"]": "\t}\n",
}
继续往下,我定义了一个列表来存放输出并添加必要的头文件和声明,以及定义一个长度为30000的字符数组array
和一个指针ptr
,用来模拟bf的内存空间
output: List[str] = []
output.append("#include <stdio.h>\n\n")
output.append("int main(void)\n")
output.append("{\n")
output.append("\tchar array[30000] = {0};\n")
output.append("\tchar *ptr = array;\n\n")
接下去,刚才已经定义好字典了,那我们只需简单的用循环来遍历bf的程序,并使用CHAR_TO_OUTPUT
字典来获取对应的字符串,然后添加到output
就好了
for c in program:
if c in CHAR_TO_OUTPUT:
output.append(CHAR_TO_OUTPUT[c])
最后,添加一些必要的结束语句,并将列表中的元素用换行符连接起来就好了
output.append("\n\treturn 0;\n")
output.append("}\n")
output_str = "\n".join(output)
结束
当然也不要忘了对输出文件做处理
try:
with open(output_file, "w") as out_file:
out_file.write(output_str)
except IOError:
print(f"Cannot open output file: {output_file}")
sys.exit(3)
sys.exit(0)
示例
用一个简单的HelloWorld程序测试下
++++++++++[>+++++++>++++++++++>+++>+<<<<-]
>++.>+.+++++++..+++.>++.<<+++++++++++++++.
>.+++.------.--------.>+.>.
来到终端
PS [private]\BrainFuck> python main.py hello.bf hello.c
PS [private]\BrainFuck> gcc hello.c -o hello
PS [private]\BrainFuck> ./hello
Hello World!
PS [private]\BrainFuck>
测试成功!
完整代码
import sys
from typing import Dict, List
CHAR_TO_OUTPUT: Dict[str, str] = {
">": "\t++ptr;\n",
"<": "\t--ptr;\n",
"+": "\t++*ptr;\n",
"-": "\t--*ptr;\n",
".": "\tputchar(*ptr);\n",
",": "\t*ptr = getchar();\n",
"[": "\twhile (*ptr) {\n",
"]": "\t}\n",
}
if len(sys.argv) == 1:
print(f"Usage: {sys.argv[0]} input_file output_file")
sys.exit(1)
elif len(sys.argv) != 3 and len(sys.argv) != 2:
print("no input files")
sys.exit(1)
input_file = sys.argv[1]
try:
output_file = sys.argv[2]
except IndexError:
output_file = "a.c"
try:
with open(input_file, "r") as in_file:
program = in_file.read()
except IOError:
print(f"Cannot open input file: {input_file}")
sys.exit(2)
output: List[str] = []
output.append("#include <stdio.h>\n\n")
output.append("int main(void)\n")
output.append("{\n")
output.append("\tchar array[30000] = {0};\n")
output.append("\tchar *ptr = array;\n\n")
for c in program:
if c in CHAR_TO_OUTPUT:
output.append(CHAR_TO_OUTPUT[c])
output.append("\n\treturn 0;\n")
output.append("}\n")
output_str = "\n".join(output)
try:
with open(output_file, "w") as out_file:
out_file.write(output_str)
except IOError:
print(f"Cannot open output file: {output_file}")
sys.exit(3)
sys.exit(0)