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