文章转自http://www.x64asm.com/Charme/article/content/art1.html
some thing about the kernel32.dll base address in X64
---2010.1.19 20:30---
32:
之前在病毒里涉及到很多时候都要用kernel32.dll的基址
通过这个基址搜索EAT来获得导出函数LoadLibrary和GetProcAddress
然后利用这两个函数获取其他的函数,当然也可以直接搜索导出表获得想要的函数!
现在装了win7,测试之前写的病毒不起作用,调试发现基址是错误的!虽然是64位系统,但是Wow64下面应
该是可以运行的!
所以确定必然是基址的获得方法有改变。
第一种方法-------------
xor ebx, ebx
mov ebx, fs:[ 0x30 ] ;PEB
mov ebx, [ ebx + 0x0C ] ;PEB->Ldr
mov ebx, [ ebx + 0x1C ] ;PEB->Ldr.InInitializationOrderModuleList.Flink
mov ebx, [ ebx ] ;next entry
mov ebx, [ ebx + 0x08 ] ;base address (kernel32.dll)
在xp vista 2000上都是这样的!运行没有问题!
但是win7上面在加载kernel32.dll之前要先加载kernelbase.dll
所以mov ebx,[ebx]的时候实际上是接近了kernelbase.dll
所以要获得kernel32.dll我们需要修正下之前的做法
第二种方法:
xor ebx, ebx
mov ebx, fs:[ 0x30 ] ;PEB
mov ebx, [ ebx + 0x0C ] ;PEB->Ldr
mov ebx, [ ebx + 0x14 ] ;PEB->Ldr.InMemoryOrderModuleList.Flink (1st entry)
mov ebx, [ ebx ] ;next entry (2nd entry)
mov ebx, [ ebx ] ;entry (3rd entry)
mov ebx, [ ebx + 0x10 ] ;base address (kernel32.dll)
但是我的一个外国朋友bitRAKE说,这样貌似在2000上有些时候是失效的,问题就在
InMemoryOrderModuleList的地址上!
更为妥当而且稳定的方法是这样的(多做一些判断):
第三种方法:
cld
xor edx, edx
mov edx, [fs:edx+0x30] ;PEB
mov edx, [edx+0x0C] ;PEB->Ldr
mov edx, [edx+0x14] ;;PEB->Ldr.InMemoryOrderModuleList.Flink (1st entry)
next_mod:
mov esi, [edx+0x28] ;modules name (unicode string)
push byte 24 ;push down the length we want to check
pop ecx
xor edi, edi ;store the hash of the module name
loop_modname:
xor eax, eax
lodsb
cmp al, 'a' ;some versions of Windows use lower case module names
jl not_lowercase
sub al, 0x20 ;up
not_lowercase:
ror edi, 13
add edi, eax ;add the next byte of the name to the hash
loop loop_modname
cmp edi, 0x6A4ABC5B ;compare the hash with that of KERNEL32.DLL
mov ebx, [edx+0x10] ;get this modules base address
mov edx, [edx] ;get the next module
jne next_mod
现在ebx里面就是kernel32的基址
那么在我们写个程序在我当前的系统上做个测试(win7 x64)
测试结果是这样的:
-------------------------------------------------------------
GetModuleHandleA( "kernelbase.dll" ) = 0x75030000
GetModuleHandleA( "kernel32.dll" ) = 0x75360000
GetModuleHandleA( "ntdll.dll" ) = 0x76F20000
-------------------------------------------------------------
Method 1: Kernel32 Base Address = 0x75030000 (Correct: NO!)
Method 2: Kernel32 Base Address = 0x75360000 (Correct: YES)
Method 3: Kernel32 Base Address = 0x75360000 (Correct: YES)
-------------------------------------------------------------
很显然之前的方法一是不行了。呼呼!!
这样的方法是比较稳妥的。
64:
我跟bitRAKE说,我想研究64位,他回答我说,你根本没有必要专门的来研究64.
只需要找到你最拿手的领域稍微的修改下就可以了!
我有点感叹,中国人看到64不敢尝试,甚至排斥,说什么现在32呢还早呢!!!
根本不是一个思路想问题,那么我们也这样的来尝试下,仅仅把64作为一个稍微改进了的机制。
不要把它认为是多么难搞的东西!
具体的64 的东西我不提,第一,我也初涉及,第二,有的是官方文档。
貌似国外的derko针对x64写过类似的东西,而且也进行了其他几个方面的研究
(要承认国外研究64比我们要早,这不可否认)是这样的:
xor rdx, rdx ; Zero rdx
mov rdx, [gs:rdx+96] ; Get a pointer to the PEB
mov rdx, [rdx+24] ; Get PEB->Ldr
mov rdx, [rdx+32] ; Get the first module from the InMemoryOrder module list
next_mod: ;
mov rsi, [rdx+80] ; Get pointer to modules name (unicode string)
movzx rcx, word [rdx+74] ; Set rcx to the length we want to check
xor r9, r9 ; Clear r9 which will store the hash of the module name
loop_modname: ;
xor rax, rax ; Clear rax
lodsb ; Read in the next byte of the name
cmp al, 'a' ; Some versions of Windows use lower case module names
jl not_lowercase ;
sub al, 0x20 ; If so normalise to uppercase
not_lowercase: ;
ror r9d, 13 ; Rotate right our hash value
add r9d, eax ; Add the next byte of the name
loop loop_modname ; Loop untill we have read enough
; We now have the module hash computed
push rdx ; Save the current position in the module list for later
push r9 ; Save the current module hash for later
; Proceed to itterate the export address table,
mov rdx, [rdx+32] ; Get this modules base address
我用fasm写过一个测试程序,上面的方法没有成功!
fdbg跟踪了下:
0000000000402018 65488B5260 GS mov rdx,[rdx+60] ; [000007FFFFFDE060]
=000007FFFFFD3000
这里应该是PEB的地址
我用windbg查看的时候貌似看到peb应该是在000007fffffda000,,所以这里没有获得有效的东西!
可是又想,win7里面有动态基址的技术(是win7 不是64 cpu)
也就是说PEB的地址对于不同的进程是不一样的!
我拿起windbg有看了下,peb at 000007fffffd8000,,,,,,,,法克and史特
那么想到用函数来动态的获取!
NtCurrentTeb?呼呼。然后从teb获取peb!!
貌似这样做是克瑞科特的!
我还是不心甘,简单修改了下上面那个:
mov rax,[gs:30h] ; RAX points to TEB (Thread Environment Block)
mov rcx,[rax+60h] ; RCX points to PEB (Process Environment Block)
考虑代码的优化,也可以这样写:
push 60h
pop rsi
gs lodsq ; RAX points to PEB
我写了个测试的程序:
;-----------------------------------------------------------------------------;
; Author: charme (http://www.x64asm.com/)
; Compatible: Windows 7(i only test about this,OTHER maybe)
; Architecture: x64
; Size: 3kb
;-----------------------------------------------------------------------------;
;then our coce start,have a fun!
format PE64 GUI
include 'C:/asm/tool/fasm/fasmw/INCLUDE/win64axp.inc'
.data
crc db 400h dup (?)
sz db 'charme',0
szformat db 'baseaddr=0x%.16IX',0
buff rb 1024
.code
start:
;;stack
cld
sub rsp,8*(4+4-1) ;bcs the .code macro has 'sub rsp,8h'
push rsi
push 60h
pop rsi
gs lodsq ; RAX points to PEB
mov rdx,rax
mov rdx,[rdx+24] ;PEB->Ldr
mov rdx,[rdx+32] ;first module(InMemoryOrder module list)
next_mod: ;
mov rsi, [rdx+80] ; Get pointer to modules name (unicode string)
movzx rcx, word [rdx+74] ; Set rcx to the length we want to check
xor r9, r9 ; Clear r9 which will store the hash of the module name
loop_modname:
xor rax, rax ; Clear rax
lodsb ; Read in the next byte of the name
cmp al, 'a' ; Some versions of Windows use lower case module names
jl not_lowercase
sub al, 0x20 ; If so normalise to uppercase
not_lowercase:
ror r9d, 13 ; Rotate right our hash value
add r9d, eax
dec rcx
test rcx,rcx
jne loop_modname
cmp r9d,092af16dah ;kernel32.dll
jne _next
mov RbX,[RDX+32]
xchg rbx,rax
lea rcx,[buff]
lea rdx,[szformat]
mov r8,rax
call [wsprintf]
xor r9,r9
lea r8,[sz]
lea rdx,[buff]
xor rcx,rcx
call [MessageBoxA]
jmp _exit
_next:
mov rdx,[rdx]
jmp next_mod
_exit:
add rcx,8*(4+4-1)
xor rcx,rcx
call [ExitProcess]
.end start
输出结果:
baseaddr:000000076B20000H
我还没有搭建好windbg!没有办法验证!不过我估计是没有问题的!