码迷,mamicode.com
首页 > 其他好文 > 详细

kernel32基地址获得学习笔记

时间:2015-02-03 12:42:25      阅读:157      评论:0      收藏:0      [点我收藏+]

标签:

原文:http://www.pediy.com/kssd/index.html -- 病毒技术 -- 病毒知识 -- Anti Virus专题

第一种方法

通过线程初始化时, 获得esp堆栈指针中的ExitThread函数的地址,然后通过搜索获得kernel32.dll的基地址。

线程在被初始化的时,其堆栈指针指向ExitThread函数的地址,windows这样做是为了通过ret返回时来调用ExitThread地址。所以一般我们可以在我们主线程的起始位置(也就是 程序入口点处)通过获得堆栈指针中ExitThread函数(当然你要想创建一个线程时候获得也可以)

我们直接通过 mov  edx, [esp] ;获得堆栈指针中ExitThread地址到edx寄存器。因为ExitThread地址在kernel32.dll空间中,所以我们可以通过它往上搜索来获得基地址。

分析过kernel32.dll的朋友应该都知道kernel32.dll的块对齐值是00001000h, 并且一般DLL以1M为边界,所以我们可以通过10000h (64k) 作为跨度,这样可以增加搜索速度。我们如何确定这个地址是基地址,我们都知道我们判断这个地址的前两个字节是否是"MZ",然后定位到PE头结构,然后判断是否是"PE",如果这两个都符合的话则表示我们的地址则是基地址了.

注意,程序要用汇编编写,至少我不会用VC来内联编写,应为这个方法需要在程序的一开始就获取,而用VC编写的会有启动函数,也就是mainCRTStartup这些

代码如下: 

	.386
	.model flat, stdcall
	option casemap:none
	
include windows.inc
include kernel32.inc
include user32.inc
includelib user32.lib
includelib kernel32.lib
	
	.const
szFormat	db ‘kernel32.dll address is: %x‘, 0dh, 0ah, 0
szFormat1	db ‘LoadLibrary kernel32.dll address is: %x‘, 0dh, 0ah, 0
szKrnl32	db ‘kernel32.dll‘, 0

	.data?
hStdOut		dd ?
dwWriteBytes	dd ?
szBuffer	db 1024 (?)

	.code
	
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 获取字符串长度
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
GetStrLen proc _lpString

	mov edi, _lpString
	or ecx, 0ffffffffh	; ecx初值等于-1
	xor eax, eax
	repnz scasb		; 循环扫描,每循环执行一次,ecx-1,直到出现0为止,0也会减1
	; 一个公式(摘自《C++反汇编与逆向分析技术揭秘》P183):
	; ecx(终值) = ecx(初值) - (Len + 1)
	; ecx(终值) = -1 - (Len + 1) = -(Len + 2)    : 将-1代入公式
	; neg(ecx(终值)) = Len + 2    : neg为求补,ecx(终值) = -(Len + 2),求补后为正Len + 2
	; not(ecx(终值)) + 1 = Len + 2
	; not(ecx(终值)) = Len + 1
    ; Len = not(ecx(终值)) - 1
    not ecx			
	dec ecx
	mov eax, ecx
	ret
	
GetStrLen endp 

start:
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 获取kernel32的基址
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
	mov edx, [esp]
Next:
	cmp word ptr [edx], ‘ZM‘       ; 因为读取后edx的内容是高地址在高位,所以需要倒过来写MZ和PE
	jz IsPe
	dec edx
	xor dx, dx
	jmp Next
	
IsPe:
	mov eax, [edx + 3ch]
	cmp word ptr [edx + eax], ‘EP‘
	jnz Next
	
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 将自己获取的和LoadLibrary获取的地址显示出来用于对比
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
	invoke GetStdHandle, STD_OUTPUT_HANDLE
	mov hStdOut, eax
	
	invoke wsprintf, addr szBuffer, addr szFormat, edx
	invoke GetStrLen, addr szBuffer
	invoke WriteConsole, hStdOut, addr szBuffer, ecx, addr dwWriteBytes, NULL
	
	invoke LoadLibrary, addr szKrnl32
	invoke wsprintf, addr szBuffer, addr szFormat1, eax
	invoke GetStrLen, addr szBuffer
	invoke WriteConsole, hStdOut, addr szBuffer, eax, addr dwWriteBytes, NULL
	
	invoke CloseHandle, hStdOut
	invoke ExitProcess, NULL
	
end start

第二种方法:

Note:这个方法适用于XP, win7上获得是ntdll.dll的地址。

这个方法是遍历遍历seh异常链,然后获得EXCEPTION_REGISTRATION结构prev为-1的异常处理过程地址,这个异常处理过程地址是位于kernel32.dll,通过它搜索得到kernel32.dll的基地址。 搜索的方法在上面我已经说了,通过减去跨度,然后判断地址前两字节是否是"MZ",是的话,继续定位到PE头结构,然后判断前两个字节是否是"PE",不是的话继续减去跨度搜索。直到是为止。
  struct EXCEPTION_REGISTRATION          prev dd ?                                handler dd ?                      ends 
  遍历的方法也很简单,我们都知道[fs:0]的ExceptionList 指向EXCEPTION_REGISTRATION结构,所以通过[fs:0]获得EXCEPTION_REGISTRATION结构后,判断prev成员是否是-1,如果是的话则取
异常处理过程地址,然后进行搜索。 

#include <stdio.h>
#include <tchar.h>
#include <windows.h>

int _tmain(int argc, _TCHAR* argv[])
{
	DWORD dwKrnlAddr = 0;

	__asm
	{
		mov edx, fs:[0]		// 获得EXCEPTION_REGISTRATION结构地址
Next:
		inc dword ptr [edx]	// 将prev+1,如果是-1为0
		jz Krnl
		dec dword ptr [edx]	// 不为-1,还原
		mov edx, [edx]		// 获得prev指向的地址
		jmp Next

Krnl:
		dec dword ptr [edx]	// 恢复
		mov edx, [edx + 4]	// 获得handle指向的地址

Looop:
		cmp word ptr [edx], ‘ZM‘
		jz IsPe
		dec edx
		xor dx, dx
		jmp Looop

IsPe:
		mov eax, dword ptr [edx + 3ch]
		cmp word ptr [edx + eax], ‘EP‘
		jnz Next
		mov dwKrnlAddr, edx
	}
	_tprintf(TEXT("Kernel32.dll address: %x\r\n"), dwKrnlAddr);
	_tprintf(TEXT("GetModuleHandle Kernel32.dll address: %x\r\n"), 
		GetModuleHandle(TEXT("kernel32.dll")));

	return 0;
}

 

 

 

第三种方法:

此方法是通过TEB获得PEB结构地址,然后再获得PEB_LDR_DATA结构地址,然后遍历模块列表,查找kernel32.dll模块的基地址。
  TEB是线程环境块(Thread Environment Block)结构, 我们的fs段选择子所对应的段指向TEB,也就是fs:[0]指向TEB.那么TEB的ProcessEnvironmentBlock结构成员指 向我们的PEB进程环境块结构(Process Environment Block),然后通过PEB结构来获得PEB_LDR_DATA。 接下来我们通过windbg来查看下相关结构。
我们首先来看下TEB结构,通过windbg的dt命令。
lkd> dt _TEB nt!_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
   ......省略
我们可以看到TEB结构的0x30偏移处存储的我们的PEB结构的地址。。
   然后接下来我们来看PEB结构。
lkd> dt _PEB nt!_PEB    +0x000 InheritedAddressSpace : UChar    +0x001 ReadImageFileExecOptions : UChar    +0x002 BeingDebugged    : UChar    +0x003 SpareBool        : UChar    +0x004 Mutant           : Ptr32 Void    +0x008 ImageBaseAddress : Ptr32 Void    +0x00c Ldr              : Ptr32 _PEB_LDR_DATA    ..........省略
我们可以看到PEB结构的0x0c偏移处存储的我们的_PEB_LDR_DATA结构地址。
然后我们再来查看 _PEB_LDR_DATA结构
lkd> dt _PEB_LDR_DATA nt!_PEB_LDR_DATA    +0x000 Length           : Uint4B    +0x004 Initialized      : UChar    +0x008 SsHandle         : Ptr32 Void    +0x00c InLoadOrderModuleList : _LIST_ENTRY    +0x014 InMemoryOrderModuleList : _LIST_ENTRY    +0x01c InInitializationOrderModuleList : _LIST_ENTRY    +0x024 EntryInProgress  : Ptr32 Void
我们看到这个结构中的模块立标有3个_LIST_ENTRY结构,它们分别是 InLoadOrderModuleList (加载顺序模块列表) InMemoryOrderModuleList(内存顺序模块排列) InInitializationOrderModuleList(初始化顺序模块列表)
然后我们继续查看这个结构。
nt!_LIST_ENTRY    +0x000 Flink            : Ptr32 _LIST_ENTRY    +0x004 Blink            : Ptr32 _LIST_ENTRY    这个结构我们可以看到它是一个双向链表,Flink表示从前往后, Blink表示从后往前。
并且这三个链表的结点是均是指向此结构
typedef struct _LDR_MODULE {     LIST_ENTRY        InLoadOrderModuleList;            // +0x00     LIST_ENTRY        InMemoryOrderModuleList;          // +0x08     LIST_ENTRY        InInitializationOrderModuleList;  // +0x10     PVOID             BaseAddress;                      // +0x18     PVOID             EntryPoint;                       // +0x1c     ULONG             SizeOfImage;                      // +0x20     UNICODE_STRING    FullDllName;                      // +0x24     UNICODE_STRING    BaseDllName;                      // +0x2c     ULONG             Flags;                            // +0x34     SHORT             LoadCount;                        // +0x38     SHORT             TlsIndex;                         // +0x3a     LIST_ENTRY        HashTableEntry;                   // +0x3c     ULONG             TimeDateStamp;                    // +0x44                                                         // +0x48 } LDR_MODULE, *PLDR_MODULE;
技术分享技术分享 我们一般取它的初始化顺序结构(InInitializationOrderModuleList)的Flink成员指向的_LDR_MODULE结构的BaseAddress成员则为我们需要的基地址,当然由于第一个是 ntdll,所以取第二个则为我们的Kernel32.dll。

注意,这里在Win7中为第3个, 第2个是kernelbase.dll,可以通过LDR_MODULE结构的BaseDllName比较dll名称后来获取,参见:

windows7平台下定位kernel32基址的方法

windows 7下的病毒感染

 

  1. #include <stdio.h>  
  2. #include <tchar.h>  
  3. #include <windows.h>  
  4.   
  5. int _tmain(int argc, _TCHAR* argv[])  
  6. {  
  7.     DWORD dwKrnlAddr = 0;  
  8.   
  9.     __asm  
  10.     {  
  11.         mov edx, fs:[30h]       // 取得PEB  
  12.         mov edx, [edx + 0ch]    // PEB_LDR_DATA  
  13.         mov edx, [edx + 1ch]    // 获得InInitializationOrderModuleList.Flink指向的地址,也即指向第一个LDR_MODULE                  
  14.         mov edx, [edx]      // 因为edx当前为InInitializationOrderModuleList  
  15.                     // 而它的第一成员Flink又指向下一个LDR_MODULE, 所以直接读取就是下一个  
  16.         mov edx, [edx + 8h]  
  17.         mov dwKrnlAddr, edx  
  18.     }  
  19.     _tprintf(TEXT("Kernel32.dll address: %x\r\n"), dwKrnlAddr);  
  20.     _tprintf(TEXT("GetModuleHandle Kernel32.dll address: %x\r\n"),   
  21.         GetModuleHandle(TEXT("kernel32.dll")));  
  22.   
  23.     return 0;  
  24. }  

kernel32基地址获得学习笔记

标签:

原文地址:http://www.cnblogs.com/Acg-Check/p/4269393.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!