自写x86代码变异混淆器及其相关思路

前言


  1. 作为一个学习/练手的项目,自发写了一个保护x86的exe/dll的变异混淆器(Mutation),类似于CodeVirtualizer的那种(不过CV是VM保护,而且还支持sys)。分别用到了capstone、asmjit和cyxvc大佬的部分库。实现了代码多重变异,代码乱序,jcc指令转换,假分支干扰等功能。

  2. 相比VMP/TMD的变异保护,强度还可以。但是兼容性比较差,没有考虑程序的异常处理而且没经过大规模测试,可能会有很多bug,仅供参考学习。

  3. 本文仅分享一下我写Mutation混淆器的一些思路,希望能抛砖引玉。

正文


1.变异的基本思想(扫盲)

代码变异/代码混淆的根本思想都是**“等价替换”。在等价替换的前提下借用寄存器、栈、堆**等来膨胀代码,将1条指令替换成多条指令。

例如以下的mov指令

mov eax,ebx

可以借用ecx寄存器,将其变异成

mov ecx,ebx
mov eax,ecx

但是这样还不行,因为我们破坏了ecx的环境。还必须要先对ecx做一个保存,事后还原它。

push ecx
mov ecx,ebx
mov eax,ecx
pop ecx

这样一个最简单的代码变异就完成了。

2.指令分析处理的思路

要想写出自动化的变异工具,第一步就要先对目标指令进行逐步地拆解分析。

除了少部分没有Operand的指令(syscall等等),大部分指令都可以分为助记符(OP)+Operand的形式。即我们先在助记符这个方向上初步区分出指令来,再在此基础上从Operand的方向进一步拆分出指令的具体类型。

2.1先以助记符拆分
mov eax,ebx

以上面mov指令为例,我们借用capstone反汇编引擎,解析出这条指令的类别为“mov”。

//判断是不是mov指令
	if (strcmp(insn.mnemonic, "mov") == 0)
		return(_mov());
add eax,ebx

同理以add指令为例,也需先解析出他的指令类别为“add”

//判断是不是add指令
	if (strcmp(insn.mnemonic, "add") == 0)
		return(_add());

以此初步地区分出目标指令为mov指令还是add指令或是其他的指令类别。

2.2再以Operand拆分

Operand又分为3种情况,分别为:

reg(寄存器),imm(立即数,常数),mem(内存)

以上文解析出的mov指令为例,搭配这3种Operand的组合,又可进一步分出5种指令类型:

mov reg,reg
mov reg,imm
mov reg,mem
mov mem,reg
mov mem,imm

我们只要针对这5种指令类型写混淆规则,就可以将x86mov指令的所有情况包括进来。

当然,Operand其实还可以再往下分:根据Operand的位数又可以继续分出8位、16位、32位、(64位)。

如果想针对性地写的更细一点,可以选择再分一次。

以下是判断Operand类型的代码

		//mov reg,reg
		if (x86->operands[0].type == X86_OP_REG && x86->operands[1].type == X86_OP_REG)
			return(_mov_reg_reg(x86->operands[0].reg, x86->operands[1].reg));
		//mov reg,imm
		if (x86->operands[0].type == X86_OP_REG && x86->operands[1].type == X86_OP_IMM) {
			imm.address = (DWORD)insn.address;
			imm.imm_value = (DWORD)x86->operands[1].imm;
			imm.imm_offset = x86->encoding.imm_offset;
			imm.imm_size = x86->encoding.imm_size;
			return(_mov_reg_imm(x86->operands[0].reg, &imm));
		}
		//mov_reg_mem
		if (x86->operands[0].type == X86_OP_REG && x86->operands[1].type == X86_OP_MEM) {
			mem.address = (DWORD)insn.address;
			mem.disp_offset = x86->encoding.disp_offset;
			mem.disp_size = x86->encoding.disp_size;
			mem.base = x86->operands[1].mem.base;
			mem.index = x86->operands[1].mem.index;
			mem.scale = x86->operands[1].mem.scale;
			mem.disp = x86->operands[1].mem.disp;
			mem.mem_size = x86->operands[1].size;
			return(_mov_reg_mem(x86->operands[0].reg, &mem));
		}

		//mov_mem_reg
		if (x86->operands[0].type == X86_OP_MEM && x86->operands[1].type == X86_OP_REG) {
			mem.address = (DWORD)insn.address;
			mem.disp_offset = x86->encoding.disp_offset;
			mem.disp_size = x86
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值