在mov指令的图灵完备性被证明之后,就产生了一种使用mov指令代替其他各种指令的混淆机制,运算,跳转,函数调用都可以全部使用mov指令实现。
混淆器
movfuscator 可以将源码编译为mov混淆之后的程序,增加逆向成本。
git clone https://github.com/xoreaxeaxeax/movfuscator
cd movfuscator
./build.sh
sudo ./install.sh
安装时可能会出现lcc安装不成功的问题,将目录中的lcc文件夹删掉,重新下载再build和install就可以了
cd movfuscator
sudo rm -r lcc
git clone https://github.com/drh/lcc
./build.sh
sudo ./install.sh
使用指令movcc test.c -o test
生成mov混淆程序。
解混淆器
demovfuscator mov解混淆器
需要三个依赖库
libcapstone
sudo git clone https://github.com/aquynh/capstone.git
cd capstone/
make
sudo make install
libz3
sudo git clone https://github.com/Z3Prover/z3.git
cd z3
python scripts/mk_make.py
cd build
make
sudo make install
libkeystone
sudo git clone https://github.com/keystone-engine/keystone.git
cd keystone/
sudo mkdir build
cd build/
sudo ../make-share.sh
sudo make install
sudo ldconfig
下载编译
git clone https://github.com/kirschju/demovfuscator.git
make
使用时会出现出错问题
示例
写一个简单逻辑程序
#include <stdio.h>
#include <string.h>
int main(int argc,char*argv[])
{
char s[10] = {0};
int i=0;
scanf("%9s",s);
for(i=0;i<strlen(s);i++)
{
s[i] = (s[i] + 1);
}
printf("%s\n",s);
return 0;
}
另外movdefuscator编译必须严格按照c语言语法,例如什么for(int i=0;i<len;i++)
这种把类型定义放在for循环体中的,或者是for循环后不接大括号直接接一条语句的都不能正常编译
这是正常的控制流
.text:0804884A ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:0804884A public main
.text:0804884A main:
.text:0804884A mov eax, target
.text:0804884F mov edx, 8804884Ah
.text:08048854 mov alu_x, eax
.text:08048859 mov alu_y, edx
.text:0804885F mov eax, 0
.text:08048864 mov ecx, 0
.text:08048869 mov edx, 0
.text:0804886E mov al, byte ptr alu_x
.text:08048873 mov ecx, alu_eq[eax*4]
.text:0804887A mov dl, byte ptr alu_y
.text:08048880 mov dl, [ecx+edx]
.text:08048883 mov b0, edx
.text:08048889 mov al, byte ptr alu_x+1
.text:0804888E mov ecx, alu_eq[eax*4]
.text:08048895 mov dl, byte ptr alu_y+1
.text:0804889B mov dl, [ecx+edx]
.text:0804889E mov b1, edx
.text:080488A4 mov al, byte ptr alu_x+2
.text:080488A9 mov ecx, alu_eq[eax*4]
.text:080488B0 mov dl, byte ptr alu_y+2
.text:080488B6 mov dl, [ecx+edx]
.text:080488B9 mov b2, edx
.text:080488BF mov al, byte ptr alu_x+3
.text:080488C4 mov ecx, alu_eq[eax*4]
.text:080488CB mov dl, byte ptr alu_y+3
.text:080488D1 mov dl, [ecx+edx]
.text:080488D4 mov b3, edx
.text:080488DA mov eax, b0
.text:080488DF mov edx, b1
.text:080488E5 mov eax, and[eax*4]
.text:080488EC mov eax, [eax+edx*4]
.text:080488EF mov b0, eax
.text:080488F4 mov eax, b0
.text:080488F9 mov edx, b2
.text:080488FF mov eax, and[eax*4]
.text:08048906 mov eax, [eax+edx*4]
.text:08048909 mov b0, eax
.text:0804890E mov eax, b0
.text:08048913 mov edx, b3
.text:08048919 mov eax, and[eax*4]
.text:08048920 mov eax, [eax+edx*4]
.text:08048923 mov b0, eax
.text:08048928 mov eax, b0
.text:0804892D mov b0, eax
.text:08048932 mov ecx, b0
.text:08048938 mov data_p, offset R0
.text:08048942 mov eax, sel_data[ecx*4]
.text:08048949 mov edx, jmp_r0
.text:0804894F mov [eax], edx
.text:08048951 mov data_p, offset R1
.text:0804895B mov eax, sel_data[ecx*4]
.............................................................
这是鬼畜之后的部分代码
可以看到mov混淆之后所有指令都使用mov代替
正常使用解混淆器应该会遇到问题,导致段错误
需要在node.cpp打相应patch 就可以正常使用了
demov [input] -o [output]
可以看到实际上解混淆器的作用微乎其微 对于实际分析还是很难上手
结语
mov混淆在ctf赛题中可以见到,但是目前了解到相关题目的解法基本没有针对代码逻辑的逆向,毕竟成本太高,有直接找规律搜索字符的,也有当黑盒测试直接盲试的,对于mov混淆本身的逆向工作实际上没有实际推进,但鉴于这种混淆机制成本很高,程序会很臃肿,基本在现实没有实际应用,所以这方面工作还是没有多少人做,不过这个技术本身是很有意思的,简单分析一下,他的栈和内存寻址是通过几张表映射出去的,有时间可以看一看函数调用之类的功能的实现,溜溜球