Contents

[从零开始的免杀生活]03.混淆视听

0x00.序

从上篇的特征码的定位我们可以了解到杀软的一直查杀方式,但是我们定位到了特征的位置,该如何去修改他呢? 今天给大家介绍一个东西 花指令,这个词熟悉逆向的朋友应该都知道,当我们通过加花的形式可以让ida的F5识别错误,同样的也可以让杀软的所匹配的特征码无法匹配。当然不懂逆向的朋友也不要紧,花指令就是一串无关紧要且无意义的代码.

0x01.花指令设计

不同于反ida的F5伪代码生成,我们只需要打乱特征即可。

1.Sleep 函数

顾名思义函数为睡眠,我们让在定位的特征附近加上Sleep(0); 让程序睡眠0秒,起到一个混淆视听的作用,当然可能这个函数和NOP 一样被杀烂了。

2.MSVC 内联汇编添加花指令

在MSVC编译器中我们可以通过__asm{} 来在C/C++函数中添加汇编代码,可以使用汇编进行加花的操作 例如

__asm{
    nop
    nop
    add eax,1
    sub eax,1
}

3.无意义的算法?

添加例如冒泡排序,二叉树的遍历,图的遍历,之类的函数,尽可能混淆关键代码

4.利用万用门

vmp的方法,通过万用门构造xor,nor,add,sub等 也可以使用一些新的如量子门? 公式如下

not(a) = P(a,a)
and(a,b) = P(P(a,a),P(b,b))
or(a,b) = P(P(a,b),P(a,b))
xor(a,b) = P(P(P(a,a),P(b,b)),P(a,b))

5.SEH异常处理

通过添加_try{}_except{} 抛出异常然后通过throw 抛出异常实现在catch中执行恶意代码,此方法不仅可以迷惑杀毒也可以迷惑一些 “新手” 逆向分析研究者。

6.对字符串加密

例如使用多层BASE64 或使用一些加密方法的魔改版本,最好是自己做点小修改。

0x03 使用OLLVM 混淆程序流

OLLVM包括控制流平坦化,拆分基本块,伪控制流等编译选项

0
clang -mllvm -sub -mllvm -split -mllvm -fla -mllvm -bcf main.c

由于ollvm在LLVM4.0版本后就不在维护,后续版本为其他人的维护版本 这里贴出几个链接

Pluto-Obfuscator(OLLVM12):https://github.com/bluesadi/Pluto-Obfuscator ollvm16:https://github.com/wwh1004/ollvm-16

链接内有具体的详细安装过程,可以使用cmake也可以使用ninjia进行编译。如果实在会安装也可以等我后面出个安装教程?(大概会出吧。

0x04.加壳

加壳可以绕过的杀软其实少的可怜,现在的杀软对熵(程序混乱程度) 值来判断是否加壳,某数字杀软更是对只要有加壳特征的程序就一律封杀,可谓是宁可错杀一千不可放过一个。

但加强壳还是能很好的防止分析,但是至少得用SDK里的宏标记一下函数吧。不要只是套了一个壳结果没对函数做VM,一加载到内存里直接DUMP下来就可以分析了。

回归正题,壳的种类有这几种

  1. 压缩壳
    • UPX
    • ASPack
  2. 加密壳/VM壳
    • VMP
    • SE
    • Themida
    • Enigma

使用起来基本是傻瓜式了。这里就不过多赘述了。下面提一下upx的特征的去除

  1. 将下图的UPX0 UPX1 两个区段名给填0

https://s1.ax1x.com/2023/09/11/pPgUSG6.jpg

  1. 下图的数据是给upx -d 脱壳使用的,我们可以完全填0 PS:该部分填0后将无法用upx -d 进行脱壳

https://s1.ax1x.com/2023/09/11/pPgUmJP.jpg

HASH值
40 00 00 C0 33
TAG&压缩信息
2E 39 36 00
55 50 58 21
0D 24 08 05
3E A4 49 63
F9 0D FA 1F
6A 09 24 00
47 16 11 00
00 D2 1D

0x05.隐藏IAT(导入

可以使用LoadLibrary + GetProcAddress 这两个Win API 实现对导入表函数的隐藏,该方法也有动态调用 一词

两个函数的定义

// 一个参数为要加载的动态库地址
HMODULE LoadLibraryA(
  [in] LPCSTR lpLibFileName
);
//第一个为模块句柄
//第二个参数为函数名称
FARPROC GetProcAddress(
  [in] HMODULE hModule,
  [in] LPCSTR  lpProcName
);

需要注意的就是要动态调用的函数所在的动态库(DLL) 一般可以在MSDN上通过函数名称找到相关的定义在最下面有个依赖

https://s1.ax1x.com/2023/09/11/pPgUgW6.jpg

例子: 实现对VirtualAlloc函数的动态调用

 0
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
//定义函数指针
typedef LPVOID(*MyVirtualAlloc)(
LPVOID lpAddress, // 要分配的内存区域的地址
DWORD dwSize, // 分配的大小
DWORD flAllocationType, // 分配的类型
DWORD flProtect // 该内存的初始保护属性
)
//通过GetProcAddress与LoadLibrary获取VirtualAlloc的函数地址
//在强转成函数指针类型
MyVirtualAlloc vir = (MyVirtualAlloc)GetProcAddress(LoadLibraryA("kernel32.dll"), "VirtualAlloc");
//通过函数指针调用
//这里就不写参数了。。。
vir(xxxxx);

0x06.总结

无论是花指令,Ollvm还是加壳都是有效的对分析者或AI分析的干扰,通过这些方法加上上篇文章的组合拳相信大多数杀软的静态查杀你都可以Bypass的。当然免杀的方法不局限于我上面讲的这些,由于篇幅有限,此系列文章仅仅为一个引子,希望大家通过这篇文章的启发站在杀毒软件开发者的角度来思考找到一些更加巧妙的方法。