原文链接:(void(*)()exec)()的理解
(void(*)()exec)()的理解最近开始看一些免杀了,发现shellcode加载器里面有这个代码,现在看懂了拿出来记一下 看一个最简单的shellcode加载器
int main(){
unsigned char buf[] = "shellcode";
void* exec = VirtualAlloc(0, sizeof buf, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, buf, sizeof buf);
((void(*)())exec)();
return 0;
}
|
干脆就所有代码都看一下吧反正就这么几行 看懂这个加载器只需要知道两个函数就行,VirtualAlloc,memcpy,还有最后一句话就行 0x01 VirtualAlloc这个是一个开辟内存的函数,要让shellcode执行起来需要先把shellcode放到内存中,这个函数就可以开一块内存 先看一下需要的参数
LPVOID VirtualAlloc(
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flAllocationType,
DWORD flProtect
);
|
lpAddress 分配内存区域的地址,如果为null将有系统来分配 dwSize 要分配或者保留的区域大小,这个参数以字节为单位 flAllocationType 这个数值有三个可选择MEM_COMMIT ,MEM_RESERVE,MEM_RESET,具体的区别不能很明确的说出来,一般都是用MEM_COMMIT flProtect指定了被分配区域的访问保护方式,其实就是选择可读可写可执行的权限 参数 数值 权限
PAGE_READONLY0x02只读
PAGE_EXECUTE0x10可执行,不可读不可写
PAGE_EXECUTE_READ0x20可执行,只读
PAGE_READWRITE0x04可读可写不可执行
PAGE_EXECUTE_READWRITE0x40可读可写可执行这里的每个参数都是有一个数值的,是用宏定义,可以Ctrl+左键查看,就算函数面直接写数值也是可以的 上面的不是很全,就把常用的写了一下,具体的可以在这里看 https://baike.baidu.com/item/VirtualAlloc 现在应该就可以理解这句话了
void* exec = VirtualAlloc(0, sizeof buf, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
第一个参数传0也就是null,第二个传shellcode的长度表开始开多大的内存,第三个就这么写吧,最后一个就是shellcode这段内存设置可读可写可执行 这个函数最后返回一个指针,指向分配的首地址 0x02 memcpy这函数就是把shellcode放到刚开的内存中 第一个参数是存储复制内容的地址,强制转换为void*指针 第二个参数是要复制到第一个参数里面的数据,强制转换为void* 指针 第三个参数是要被复制的字节数
memcpy(exec, buf, sizeof buf);
|
把buf里面的shellcode放入exec中 0x03 (void(*)()exec)()的理解这个其实很好理解,首先要知道C语言的强制类型转换
C语言的强制类型转换就是在要转换的参数前面加上 (类型) 现在再了解一下函数指针
void hello(){
printf("helloworld");
}
int main(){
hello(); //简化调用
(*hello)(); //标准调用
return 0;
}
|
hello是一个返void类型的函数,hello的声明是· void (*hello)() 看到了声明就可以得到这个函数类型的类型转换符了 void(*)() 然后加上前面的强制类型转换
这句代码的意思就是把exec强制转换为一个返回void类型的函数指针然后执行,就成功执行了shellcode
|