探索黑客技术攻防,实战研究与安全创新

导航菜单

ShellcodeInX64Findkernel32.dll

网上对于X64下Shellcode的讨论比较少,本文我们将着重讨论X64下的Shellcode的实现。

shellcode的第一步。第一步都是找到某模块基址,如kernel32.dll。

由于kernel32.dll内含一些很重要的函数,如LoadLibrary和GetProcAddress,获取这些函数后,病毒或者shellcode就可以为所欲为的加载其他模块。

X64下shellcode的编写和32位下的区别由于X64下_asm关键字的取消,我们没有办法在VC中内联汇编了,所以需要找一款64位的汇编工具,可以选择微软的masm,但本文推荐fasm,基本不需要进行什么设置,只需把本文给出的.asm文件直接打开或者复制粘贴后编译就可以看到效果了。

虚拟机X64的硬件环境

硬件:拥有两块硬盘的台式机或者笔记本,内存最好大于4GB。笔记本可以加装光驱位硬盘,或者内存条,两块硬盘的好处就是真实的系统在主盘上启动,虚拟机放在从盘。即使同时启动3、4个虚拟机(我是说同时点虚拟机的power按钮),真实的操作系统也不是很卡。我的笔记本硬件是I3380M2.53Ghz的主频,两块硬盘,主盘5400rpm,从盘7200rpm。

其实本文很简单,只要弄懂下面几行代码就完成任务了。


GetKrnlBase3:
movrsi,[gs:60h]
movrsi,[rsi+18h]
movrsi,[rsi+30h]
;
pebfromteb
;_peb_ldr_datafrompeb
movrsi,[rsi]
movrsi,[rsi]
;kernelbase.dll
;kernel32.dll
movrsi,[rsi+10h];payattentiontodanwei
ret


X64下的一些基础知识

1)X64下增加了r8~r15这8个64位通用寄存器。16位进化成32位,32位又进化成64位,即ax-eax-rax,兼容以前的寄存器。

2)pushad、popad等命令在X64下无法使用。

3)记住这个顺序:r9r8rdxrcx。X64下都是用的__fastcall方式,4个寄存器用完之后才用堆栈传递参数。

4)fs,x64下换成了gs,[fs:0]的指向自然由[gs:0]继承。

WinDBG查看结构和代码解释findkernel32.dll,本文只说一种方法,通用于win8x64。customer验证的方法就是把本文给出的程序直接拖进X64Win8虚拟机,即会看到kernel32.dll的地址被打印出来。


movrsi,[gs:60h]
movrsi,[rsi+18h]
;
pebfromteb
;_peb_ldr_datafrompeb


这两行代码不用解释,我们看“movrsi,[rsi+30h];InInitializationOrderModuleList.Flink”。

本文采用的是从InInitializationOrderModuleList这个链表来找寻kernel32.dll的。我所查阅到的国外一些X64shellcode都是从InLoadOrderModuleList来找的,当然方法是一样的。

我们来看一下InInitializationOrderModuleList的结构。在Windbg中连续输入以下命令:


/*
PROCESSfffffa800b429b30
SessionId:1Cid:04b0
Peb:7fffffd9000ParentCid:048c
Image:explorer.exe
*/
!process00
//.processexplorer.exe的PROCESS值
.processfffffa800b429b30
.reload


看到如下的提示后:


ConnectedtoWindows77601x64targetat(FriAug3100:34:01.0412012(UTC+8:00)),
ptr64TRUE
LoadingKernelSymbols
...............................................................
................................................................
.............................
LoadingUserSymbols//千万要注意UserSymbols是否加载成功
................................................................
................................................................
.............................................................
Loadingunloadedmodulelist
..........................................


继续输入“!peb”,可以得到如下结果。


1:kd!peb
PEBat000007fffffd9000
InheritedAddressSpace:
No
ReadImageFileExecOptions:No
Beingdebugged:
ImageBaseAddress:
Ldr
No
00000000ffa20000
0000000077742640
Ldr.Initialized:
Yes
Ldr.InInitializationOrderModuleList:00000000000627a0.00000000084dda10
Ldr.InLoadOrderModuleList:
Ldr.InMemoryOrderModuleList:
0000000000062690.00000000084dd9f0
00000000000626a0.00000000084dda00
Module
ffa200004ce7a144Nov2018:21:562010C:\Windows\Explorer.EXE
776100004ce7c8f9Nov2021:11:212010C:\Windows\SYSTEM32\ntdll.dll
773f00004ce7c78bNov2021:05:152010C:\Windows\system32\kernel32.dll
7fefd730000
4ce7c78c
Nov
20
21:05:16
2010
C:\Windows\system32\KERNELBASE.dll
7fefeb700004a5bde6bJul1409:24:592009C:\Windows\system32\ADVAPI32.dll


我们主要关心InInitializationOrderModuleList,下面分步进行说明。

1)查看Ldr.InInitializationOrderModuleList。


1:kddd00000000000627a0
00000000`000627a0
00000000`000627b0
77610000
00062c90000000007774267000000000
77610000000000000000000000000000ntdll.dll的基地址
00000000`000627c0
00000000`000627d0
00000000`000627e0
00000000`000627f0
00000000`00062800
00000000`00062810
001a900000000000003c003a00000000
00062600000000000014001200000000
777253f800000000000040040000ffff
000cb510000000007774aac000000000
4ce7c8f9000000000000000000000000
00000000000000000006281800000000


2)查看模块入口dd00062c90。


1:kddd00000000000627a0
00000000`000627a0
00000000`000627b0
77610000
00062c90000000007774267000000000
77610000000000000000000000000000ntdll.dll的基地址
00000000`000627c0
00000000`000627d0
00000000`000627e0
00000000`000627f0
00000000`00062800
00000000`00062810
001a900000000000003c003a00000000
00062600000000000014001200000000
777253f800000000000040040000ffff
000cb510000000007774aac000000000
4ce7c8f9000000000000000000000000
00000000000000000006281800000000


3)接下来就是查找kernel32.dll了。


1:kddd00062b20
00000000`00062b20
00000000`00062b30
773f0000
00063ab00000000000062c9000000000
773f00000000000077405ea000000000kernel32.dll的基地址
00000000`00062b40
00000000`00062b50
00000000`00062b60
00000000`00062b70
00000000`00062b80
00000000`00062b90
0011f000000000000042004000000000
00062ab000000000001a001800000000
00062ad800000000000840040000ffff
041401d0000000007774aa4000000000
4ce7c78b000000000000000000000000
000000000000000000063dc000000000


参考上面的几条命令,下面的两条命令也自然可以理解了。


movrsi,[rsi]
movrsi,[rsi]
;kernelbase.dll
;kernel32.dll


之后只剩下下面这条指令了。

movrsi,[rsi+10h];payattentiontodanwei

其中的10h也就是10进制的16。


1:kddt_LIST_ENTRY
ntdll!_LIST_ENTRY
+0x000Flink
:Ptr64_LIST_ENTRY
:Ptr64_LIST_ENTRY
+0x008Blink


由上面的结果可知,在X64下,Flink和Blink的两个指针长度由4变成了8。那么,为什么加上指针的长度就得到了kernel32.dll的基地址呢?我们可以看下面这条命令的执行结果,此处用的是InInitializationOrderLinks,所以加2个指针长度就可以了;如果用的是InLoadOrderLinks,得加几个指针长度呢?大家可以自行计算下。


1:kddt_LDR_DATA_TABLE_ENTRY
ntdll!_LDR_DATA_TABLE_ENTRY
+0x000InLoadOrderLinks:_LIST_ENTRY
+0x010InMemoryOrderLinks:_LIST_ENTRY
+0x020InInitializationOrderLinks:_LIST_ENTRY
+0x030DllBase
:Ptr64Void
+0x038EntryPoint
+0x040SizeOfImage
+0x048FullDllName
+0x058BaseDllName
+0x068Flags
:Ptr64Void
:Uint4B
:_UNICODE_STRING
:_UNICODE_STRING
:Uint4B


下面给出一个64位的FASM程序,通用于WIN7和WIN8,运行之后可以打印出kernel32.dll的基地址。


formatPE64CONSOLE
macro.text{section.texcodereadableexecutablewriteable}
macro.code{section.codecodereadableexecutable}
macro.data{section.datadatareadablewriteable}
entry
__Entry
includewin64axp.inc
.text
__Entry:
;
;
;
push
call
dword[esp]
GetKrnlBase
GetKrnlBase2
GetKrnlBase3
call
call
xorrcx,rcx
cinvokeprintf,type,rsi
ccall
[printf],hello_msg
;
cinvokeprintf,type,0
cinvokegetch
invokeExitProcess,rcx
;
moveax,[fs:30h]
;
;
mov
mov
eax,[eax+0ch];Get_PEB_LDR_DATA
eax,[eax+1ch];GetInInitializationOrderModuleList.Flink,


此时eax指向的是ntdll模块的InInitializationOrderModuleList线性地址,所以我们获得它的下一个地址则是kernel32.dll


mov
mov
ret
eax,[eax]
eax,[eax+8h]
GetKrnlBase3:
movrsi,[gs:60h];pebfromteb
movrsi,[rsi+18h]
movrsi,[rsi+30h]
;_peb_ldr_datafrompeb
;InInitializationOrderModuleList.Flink,
;rsi==00232c9000000000
movrsi,[rsi]
;rsi=00232b2000000000
;kernelbase.dll
movrsi,[esi]
;kernel32.dll
movrsi,[rsi+10h];payattentiontodanwei
ret
.data
type
db"%I64x",0
hello_msg
db0Dh,0Ah
section.IDAtaimportdatareadablewritable
librarykernel,KERNEL32.DLL,\
msvcrt,msvcrt.dll
importkernel,\
ExitProcess,ExitProcess
importmsvcrt,\
printf,printf,\
getch,_getch


其中[gs:0]指向teb,使用Windbg即可查看teb。


1:kddt_teb
ntdll!_TEB
+0x000NtTib
+0x038EnvironmentPointer:Ptr64Void
+0x040ClientId:_CLIENT_ID
:_NT_TIB
+0x050ActiveRpcHandle:Ptr64Void
+0x058ThreadLocalStoragePointer:Ptr64Void
+0x060ProcessEnvironmentBlock:Ptr64_PEB
1:kddt_peb
ntdll!_PEB
+0x000InheritedAddressSpace:UChar
+0x001ReadImageFileExecOptions:UChar
+0x002BeingDebugged
+0x003BitField
:UChar
:UChar
+0x003ImageUsesLargePages:Pos0,1Bit
+0x003IsProtectedProcess:Pos1,1Bit
+0x003IsLegacyProcess:Pos2,1Bit
+0x003IsImageDynamicallyRelocated:Pos3,1Bit
+0x003SkipPatchingUser32Forwarders:Pos4,1Bit
+0x003SpareBits
+0x008Mutant
:Pos5,3Bits
:Ptr64Void
+0x010ImageBaseAddress:Ptr64Void
+0x018Ldr
:Ptr64_PEB_LDR_DATA
1:kddt_PEB_LDR_DATA
ntdll!_PEB_LDR_DATA
+0x000Length
:Uint4B
:UChar
:Ptr64Void
+0x004Initialized
+0x008SsHandle
+0x010InLoadOrderModuleList:_LIST_ENTRY
+0x020InMemoryOrderModuleList:_LIST_ENTRY
+0x030InInitializationOrderModuleList:_LIST_ENTRY
1:kddt_LIST_ENTRY
ntdll!_LIST_ENTRY
+0x000Flink
+0x008Blink
:Ptr64_LIST_ENTRY
:Ptr64_LIST_ENTRY
1:kddt_LDR_DATA_TABLE_ENTRY
ntdll!_LDR_DATA_TABLE_ENTRY
+0x000InLoadOrderLinks:_LIST_ENTRY
+0x010InMemoryOrderLinks:_LIST_ENTRY
+0x020InInitializationOrderLinks:_LIST_ENTRY
+0x030DllBase
:Ptr64Void
+0x038EntryPoint
+0x040SizeOfImage
+0x048FullDllName
+0x058BaseDllName
+0x068Flags
:Ptr64Void
:Uint4B
:_UNICODE_STRING
:_UNICODE_STRING
:Uint4B


(完)

本文内容所提及均为本地测试或经过目标授权同意,旨在提供教育和研究信息,内容已去除关键敏感信息和代码,以防止被恶意利用。文章内提及的漏洞均已修复,作者不鼓励或支持任何形式的非法行为。