病毒技术二:获取kernel32.dll基址
--------为何要动态取得kernel32.dll基址--------“取得kernel32.dll的基址有何用?直接链接不就行了。”想必不少人会这么问;当然,如果你不想你的病毒兼容各个Windows平台,这一步是不需要的。
我们都知道,链接器动态链接的原理其实是将操作系统DLL中的API地址导入到我们的程序中,因为不同版本的Windows上DLL的基址会有所不同,所以你在WIN7上导入的"GetProcAddress"不一定能在WIN10上工作(因为地址不一样)。获取了kernel32.dll基址后就可以获取LoadLibrary()和GetProcAddress()的地址,有了它们之后我们之后就不用大费周章的去找API了。
--------取得kernel32.dll基址的方法--------
取得kernel32.dll基址的办法很多,这里介绍很简单的一种(但是背后的原理很繁琐),下面是取得其基址的一个子过程代码:
;NASM版本:
GETKERNEL32ADDR:
XCHG EAX,EBX
MOV EBX,[FS:30H] ;从TIB(Thread Information Block)中取得PEB(Process Environment Block)的地址
MOV EBX,[EBX+0CH] ;从PEB中取得LDR类的基址
MOV EBX,[EBX+14H] ;从LDR中获取InMemoryOrderModuleList.Flink的地址(入口1,属于主进程)
MOV EBX,[EBX] ;从InMemoryOrderModuleList.Flink取得InMemoryOrderModuleList.Flink.Flink的地址(入口2,属于ntdll.dll)
MOV EBX,[EBX] ;同上,取得InMemoryOrderModuleList.Flink.Flink.Flink的地址(入口3,属于kernel32.dll)
MOV EBX,[EBX+10H] ;通过InMemoryOrderModuleList.Flink.Flink.Flink提供的_LDR_DATA_TABLE_ENTRY,再从中最终获取入口3的基址,也就是kernel32.dll的基址了
XCHG EAX,EBX ;此过程的返回kernel32.dll的基址,存于EAX寄存器中
RETN
;MASM版本:
GETKERNEL32ADDR PROC
XCHG EAX,EBX
MOV EBX,FS:[30H] ;从TIB(Thread Information Block)中取得PEB(Process Environment Block)的地址
MOV EBX,[EBX+0CH] ;从PEB中取得LDR类的基址
MOV EBX,[EBX+14H] ;从LDR中获取InMemoryOrderModuleList.Flink的地址(入口1,属于主进程)
MOV EBX,[EBX] ;从InMemoryOrderModuleList.Flink取得InMemoryOrderModuleList.Flink.Flink的地址(入口2,属于ntdll.dll)
MOV EBX,[EBX] ;同上,取得InMemoryOrderModuleList.Flink.Flink.Flink的地址(入口3,属于kernel32.dll)
MOV EBX,[EBX+10H] ;通过InMemoryOrderModuleList.Flink.Flink.Flink提供的_LDR_DATA_TABLE_ENTRY,再从中最终获取入口3的基址,也就是kernel32.dll的基址了
XCHG EAX,EBX ;此过程的返回kernel32.dll的基址,存于EAX寄存器中
RETN
GETKERNEL32ADDR ENDP
这段代码可以通过C语言中用以下表达式验证:
unsigned int Kernel32Address = (unsigned int)GetModuleHandleA("kernel32.dll");
--------以上代码取得kernel32.dll基址的原理--------
以下为PEB的结构:
typedef struct _PEB {
BYTE Reserved1[2]; //2字节
BYTE BeingDebugged; //1字节
BYTE Reserved2[1]; //1字节
PVOID Reserved3[2]; //8字节
PPEB_LDR_DATA Ldr; //LDR的地址为{此类地址 + 2 + 1 + 1 + 8} = {此类地址 + 12(0CH)},前面代码中MOV EBX,[EBX+0CH]的原理
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
BYTE Reserved4[104];
PVOID Reserved5[52];
PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
BYTE Reserved6[128];
PVOID Reserved7[1];
ULONG SessionId;
} PEB, *PPEB;
------------------------------------------------------------------------------------------------------------
以下为LDR的结构:
typedef struct _PEB_LDR_DATA {
BYTE Reserved1[8]; //8字节
PVOID Reserved2[3]; //12字节
LIST_ENTRY InMemoryOrderModuleList; //InMemoryOrderModuleList中有两个LIST_ENTRY指针,其地址为{此类地址 + 8 + 12} = {此类地址 + 20(14H)},前面代码中MOV EBX,[EBX+14H]的原理
} PEB_LDR_DATA, *PPEB_LDR_DATA;
以下为InMemoryOrderModuleList的结构:
typedef struct _LIST_ENTRY {
struct _LIST_ENTRY *Flink; //这两个类相互链接,指向LDR_DATA_TABLE_ENTRY类的地址(指针)
struct _LIST_ENTRY *Blink;
} LIST_ENTRY, *PLIST_ENTRY, *RESTRICTED_POINTER PRLIST_ENTRY;
以下为LDR_DATA_TABLE_ENTRY的结构:
typedef struct
{
LIST_ENTRY InMemoryOrderLinks; //上面的那个类,8字节
LIST_ENTRY InInitializationOrderLinks; //8字节
PVOID DllBase; //DLL基址,我们想要的东西,其地址为{此类地址 + 8 + 8} = {此类地址 + 16(10H)},前面代码中MOV EBX,[EBX+10H]的原理
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
WORD LoadCount;
WORD TlsIndex;
union
{
LIST_ENTRY HashLinks;
struct
{
PVOID SectionPointer;
ULONG CheckSum;
};
};
union
{
ULONG TimeDateStamp;
PVOID LoadedImports;
};
_ACTIVATION_CONTEXT * EntryPointActivationContext;
PVOID PatchInformation;
LIST_ENTRY ForwarderLinks;
LIST_ENTRY ServiceTagLinks;
LIST_ENTRY StaticLinks;
} LDR_DATA_TABLE_ENTRY_, *PLDR_DATA_TABLE_ENTRY_;
PEB的详细信息:https://msdn.(v=vs.85).aspx
PEB_LDR_DATA的详细信息:https://msdn.(v=vs.85).aspx
前面的章节:
病毒技术一:程序的重定位--http://bbs.bccn.net/thread-464424-1-1.html
[此贴子已经被作者于2016-5-29 05:15编辑过]