首页
论坛
专栏
课程

[原创]Windows系统程序设计之插入DLL和挂接API

2006-6-12 03:47 26976

[原创]Windows系统程序设计之插入DLL和挂接API

2006-6-12 03:47
26976
                   Windows系统程序设计之插入DLL和挂接API
【作者】北极星2003
【来源】看雪技术论坛(bbs.pediy.com)
【时间】2006年6月12日
【说明】关于本文的所有信息都可以在附件中下载

        首先简要介绍一下内容要点。
        在WINDOWS中,每个进程都有自己的私有地址空间,当用指针访问内存的时候只能访问到自己进程的地址空间,而无法进入其他进程的地址空间。而当自己的进程需要对其他进程进行一系列操作的时候,一个比较好的选择就是把这些操作封装在一个DLL中,然后把DLL插入到目标进程的私有地址空间中。这样,如果DLL中使用指针的话,就可以访问目标进程的地址空间。
        在程序中通常有两种方法来实现插入DLL:(1)使用远程线程(2)HOOK

        挂接API的目标是当系统调用API函数的时候能够执行我们的自定义函数,需要注意的是自定义函数的参数、返回类型、调用方式都必须和原API函数完全相同。这样我们就可以很便捷的取得或者修改参数来实现相应的目标,而无需考虑该API的内部实现。
        通常有两种方法可以实现挂接API:(1)修改IAT(2)API入口的覆盖。

        需要说明的是对知识点的简要概括,至于具体信息,无论在书本或者网络上都有很多,不再赘述。
       
        使用远程线程方法实现插入DLL可以参考我以前的文章《QQ盗号的核心技术(简单版)》http://bbs.pediy.com/showthread.php?threadid=14203

        这里主要讲解两个软件的制作。
(1)        IPPack――IP封包截获工具
原理:使用挂钩(HOOK)插入DLL,覆盖API入口地址挂接API
(2)        Watch IAT ――查看IAT信息
关于修改IAT来实现挂接API已经很普遍了,我也懒的再重复。这个工具软件是我很早以前写的,用来查看可执行文件的IAT信息,但有一个难点,由于IAT信息是在加载时候动态产生的,那么什么时候是最佳时机呢??

实例一 : IPPack ―― IP封包截获工具


1、设计目标
                把基本的DLL插入技术和HOOK API技术相联系,应用到实际。另外,在该软件中还设计进程间通信、线程同步、DLL实现等多种Windows程序设计中的基本技术。(经常有朋友说这个软件不能截获数据包,这里需要说明的是这个软件仅仅是一个技术实例,并不是工具软件。对目标进程进行测试的时候,最好先用PE分析工具查看一下,确认导入表中有send,recv,sendto,recvfrom这四个函数。)

2、设计思路
        第一步:把DLL插入到目标进程地址空间
  

        第二步:挂接API,取得相关的参数信息并传送到IPPack.exe
                        如果不熟悉管道通信机制,可以参考《Windows系统程序设计之进程间通信》
http://bbs.pediy.com/showthread.php?s=&threadid=26252  

3、难点
        插入DLL和挂接API的应用比较多,基本上没什么难度。
       
4、详细设计
(1)当启动IPPack.exe进行初始化时,启动命名管道线程服务
UINT ServerThread ( LPVOID lpParameter )
{
	……
	while ( true )
	{
		ConnectNamedPipe ( CurPipeInst.hPipe, &OverLapStruct ) ;
		WaitForSingleObject ( CurPipeInst.hEvent, INFINITE ) ;
		if ( !GetOverlappedResult ( CurPipeInst.hPipe, &OverLapStruct, &dwByte, true ) )
			break ;
		……
		// 从管道中读取数据并显示到界面
		……
		// 断开客户端的连接,以便等待下一客户的到来
		DisconnectNamedPipe ( CurPipeInst.hPipe ) ;
	}
	
	return 0 ;
}


(2)显示进程列表,需要提升本进程的权限
void CIPPackDlg::LookUpProcessPriviege ()
{
	TOKEN_PRIVILEGES tkp; 
	HANDLE hToken; 
	if (!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken))
		return ; 
	LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&tkp.Privileges[0].Luid);	tkp.PrivilegeCount = 1; 
	tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 
	AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0); 
}


(3)更新进程列表
void CSPDlg::UpdateProcess ()
{
	DWORD	cbNeededProcess, cbNeededModule;
	HMODULE	hMod ;
	CString TempStr ;
	EnumProcesses ( dwProcessId, sizeof(dwProcessId), &cbNeededProcess ) ;
	for ( unsigned i = 0; i < ( cbNeededProcess/sizeof(DWORD) ); i++ )
	{
		HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION |	\
                                   PROCESS_VM_READ,	FALSE, dwProcessId[i] );
		if ( hProcess != INVALID_HANDLE_VALUE )
		{
			EnumProcessModules( hProcess, &hMod, sizeof(hMod), &cbNeededModule ) ;
			GetModuleBaseName ( hProcess, hMod, szProcessName[i].GetBuffer(512), 512 ) ;

			TempStr.Format ( "%d", dwProcessId[i] ) ;
			m_ListCon.InsertItem ( i, TempStr, 0 ) ;
			m_ListCon.SetItemText ( i, 1, szProcessName[i] ) ;			
			CloseHandle ( hProcess ) ;
		}
	}
}


(4)取得目标进程的主线程ID
dwTarProcessId		= dwProcessId[nCurIndex] ;
szTarProcessName	= szProcessName[nCurIndex] ;

HANDLE hThreadSnap = CreateToolhelp32Snapshot ( TH32CS_SNAPTHREAD, 0 ) ;
if ( hThreadSnap == INVALID_HANDLE_VALUE ) 
	return ; 

THREADENTRY32 te32 = { sizeof(THREADENTRY32) } ;
if ( Thread32First ( hThreadSnap, &te32 ) )
{
	do{
		if ( te32.th32OwnerProcessID == dwTarProcessId )
		{
			dwTarThreadId = te32.th32ThreadID ; 
			break ;
		}
	}while ( Thread32Next ( hThreadSnap, &te32 ) ) ;
}


(5)封装HOOK API入口地址覆盖到CFEAHook类,FEAHook.h文件如下:
#ifndef _FEAHook_H
#define _FEAHook_H

class CFEAHook {
public:
	BOOL	isSuccess ;						// 标识是否成功
	PSTR	pModuleName, pFunName ;			// 模块名、函数名
	LPVOID	pOldFunEntry, pNewFunEntry ;	// 初始函数地址、HOOK后的函数地址
	BYTE	bOldByte[5], bNewByte[5] ;		// 原始字节、目标字节

public:
	CFEAHook () {	isSuccess	= false ;	}
	~CFEAHook() {	UnHook() ;		}
	void Hook ( PSTR szModuleName, PSTR szFunName, FARPROC pFun )
	{	
		HMODULE	hMod = GetModuleHandle ( szModuleName ) ;
		if ( hMod != NULL )
		{
			isSuccess		= true ;
			pModuleName		= szModuleName ;
			pFunName		= szFunName ;
			pNewFunEntry	= (LPVOID)pFun ;
			pOldFunEntry	= (LPVOID)GetProcAddress ( hMod, pFunName ) ;
			bNewByte[0]		= 0xE9 ;
			*((PDWORD)(&(bNewByte[1])))	= (DWORD)pNewFunEntry - (DWORD)pOldFunEntry - 5 ; 

			DWORD   dwProtect, dwWriteByte, dwReadByte ; 
			VirtualProtect ( (LPVOID)pOldFunEntry, 5, PAGE_READWRITE, &dwProtect );
			ReadProcessMemory	( GetCurrentProcess(), (LPVOID)pOldFunEntry, bOldByte, 5, &dwReadByte ) ;		
			WriteProcessMemory	( GetCurrentProcess(), (LPVOID)pOldFunEntry, bNewByte, 5, &dwWriteByte ) ;
			VirtualProtect ( (LPVOID)pOldFunEntry, 5, dwProtect, NULL ) ;
		}
	}
	void ReHook ()
	{
		DWORD	dwProtect, dwWriteByte ;
		VirtualProtect ( pOldFunEntry, 5, PAGE_READWRITE, &dwProtect );
		WriteProcessMemory ( GetCurrentProcess(), pOldFunEntry, bNewByte, 5, &dwWriteByte ) ;
		VirtualProtect ( pOldFunEntry, 5, dwProtect, NULL ) ;
	}
	void UnHook ()
	{
		DWORD	dwProtect, dwWriteByte ;
		VirtualProtect ( pOldFunEntry, 5, PAGE_READWRITE, &dwProtect );
		WriteProcessMemory ( GetCurrentProcess(), pOldFunEntry, bOldByte, 5, &dwWriteByte ) ;
		VirtualProtect ( pOldFunEntry, 5, dwProtect, NULL ) ;
	}
} ;

#endif

(6)HOOK四个函数
CFEAHook	HOOK_send ;
CFEAHook	HOOK_recv ;
CFEAHook	HOOK_sendto ;
CFEAHook	HOOK_recvfrom ;
HOOK_send.Hook		( "wsock32.dll", "send",		(FARPROC)MY_send ) ;
HOOK_recv.Hook		( "wsock32.dll", "recv",		(FARPROC)MY_recv ) ;
HOOK_sendto.Hook		( "wsock32.dll", "sendto",		(FARPROC)MY_sendto ) ;
HOOK_recvfrom.Hook	("wsock32.dll",	"recvfrom",(FARPROC)MY_recvfrom ) ;


实例二:Watch IAT ―― 查看IAT信息


1、        设计目标
查看可执行文件的IAT信息。这个软件虽然与修改IAT的HOOK API没有直接的联系,但我觉得非常有必要放到这个部分,至于必要性请看下文。

2、        存在的难点
由于IAT信息是在可执行文件初始化时经过PE加载器改写的,而不是原本的磁盘文件中的数据。问题就在这里,什么时候才是对IAT进行操作的最佳时机?PE加载器对IAT部分的改写是在什么时候完成的?如果仅仅创建挂起的进程,此时的加载器是否写入IAT信息?

3、问题的分析与设计
利用调试API实现对远程进程的创建、入口点的控制。
其实,可以通过先到达程序入口点,同时让程序挂起。这就可以利用调试API来实现,先创建目标进程(即可执行的目标文件,要查看IAT信息必须要让PE文件执行,从而才能使加载器改写功能的实现),该进程需带有DEBUG_ONLY_THIS_PROCES标志,这样该进程就具有可被本线程调试的权限,然后在主线程中建立一个调试循环体用于对目标进程执行流程的控制。当内核在完成进程装载和初始化之后会在被调试进程的上下文环境中自己调用一次int 3的(原本我在创建该进程的时候还带有CREATE_SUSPENDED标志,然后在入口点写入__int 3断点(0xcc),这样就等于做了重复工作,感谢drwch的指点),利用WaitForDebugEvent实现对目标进程EXCEPTION_DEBUG_EVENT异常的捕捉,这样程序就中断在程序入口点,同时可以读取所需的IAT信息。
这里还有一个关键之处在于目标进程的DEBUG_ONLY_THIS_PROCESS
标志。该目标进程与常见它的母体有个令人比较讨厌的特性,由于目标进程是DEBUG子程式,如果母程式存在,子程式就不会结束。原本想利用DebugActiveProcessStop来实现子程式与母程式的分离,但该函数对于平台的要求比较特殊,最终决定用开辟线程的方式来解决这个问题。线程一旦结束,该子程式自然也就结束了。

3、        详细设计(关键代码如下)
DWORD WINAPI GetIATInfo ( LPVOID lpParameter )
{
	……
	STARTUPINFO				stStartUp;
	PROCESS_INFORMATION		stProcInfo;
	GetStartupInfo ( &stStartUp ) ;
	if( !CreateProcess(BaseInfo.szFileName,NULL,NULL,NULL,FALSE, \
		DEBUG_ONLY_THIS_PROCESS,NULL,NULL,&stStartUp,&stProcInfo) )   
	{
		SetEvent ( hEvent ) ;
		return dwErrorCode ;
	}
	else
	{		
		DEBUG_EVENT devent ;
		BOOL bIsContinue = true ;
		while ( bIsContinue )
		{
			if ( WaitForDebugEvent( &devent, 100 ) )
			{
				switch ( devent.dwDebugEventCode )
				{
				case EXCEPTION_DEBUG_EVENT:
					// 取IAT信息
					for ( UINT uIATEntryIndex = 0; DllItemInfo[uIATEntryIndex].dwIATEntry; uIATEntryIndex++ )
					{
						DWORD dwIATEntry = DllItemInfo[uIATEntryIndex].dwIATEntry + BaseInfo.dwImageBase ;
						DWORD dwIAT = 0, dwNumberOfByte = 0 ;
						UINT count = 0 ;
						
						while ( ReadProcessMemory(stProcInfo.hProcess,(LPVOID)(dwIATEntry),&dwIAT,0X4,&dwNumberOfByte) )
						{
							if ( dwIAT ) 
							{
								DllItemInfo[uIATEntryIndex].FunctionItemInfo[count].dwFunctionEntry = dwIAT ;
								DllItemInfo[uIATEntryIndex].FunctionItemInfo[count++].dwImageRVa = dwIATEntry-BaseInfo.dwImageBase;
								DllItemInfo[uIATEntryIndex].dwIATSize += 4 ;
								dwIAT = 0 ;
								dwIATEntry += 4 ;
							}	
							else
								break ;
						}		
					}
	
					bIsContinue = false ;
					break ;
				} //switch
				
				ContinueDebugEvent ( devent.dwProcessId, devent.dwThreadId, DBG_CONTINUE ) ;
			} // if
		} // while		
	} // else


	SetEvent ( hEvent ) ;
	return 0; 
}

4、        心得体会
这个软件写的比较久了,回忆了下。加深对加载过程的了解,熟悉WIN32调试API。
【参考文献】
[1].Windows核心编程 Jeffrey Richter著
【版权声明】必须注明原创于看雪技术论坛(bbs.pediy.com) 及作者,并保持文章的完整性。

[公告][征集寄语] 看雪20周年年会 | 感恩有你,一路同行

上传的附件:
最新回复 (58)
北极星2003 25 2006-6-12 04:09
2
0
搞的太晚,头晕了
光发贴也至少编辑了十次
如有疏忽或者错误之处,请指出
drwch 3 2006-6-12 04:22
3
0
以DEBUG状态创建的进程不用加CREATE_SUSPENDED标志吧,内核在完成进程装载和初始化之后会在被调试进程的上下文环境中自己调用一次int 3的
prince 16 2006-6-12 09:45
4
0
北极星辛苦!
北极星2003 25 2006-6-12 10:10
5
0
Originally posted by drwch
以DEBUG状态创建的进程不用加CREATE_SUSPENDED标志吧,内核在完成进程装载和初始化之后会在被调试进程的上下文环境中自己调用一次int 3的


多谢指点
我测试了你说的,完全正确
在这个地方,我确实做了重复工作
CCDebuger 24 2006-6-12 10:25
6
0
呵呵,系列开始继续了?还怕你受刺激,不搞了呢。支持北极星!
hnhuqiong 10 2006-6-12 10:30
7
0
严重支持.....期待好文继续
北极星2003 25 2006-6-12 10:33
8
0
Originally posted by CCDebuger
呵呵,系列开始继续了?还怕你受刺激,不搞了呢。支持北极星!


这个系列又没有停止过,只不过跟我的初衷不同
原本是想让各位高手出手,但是……
至于我自己嘛,有时间还是会继续的,只不过这样的话,整个流程会拉长。

刚看到的时候是受了点刺激,但是对我的积极性并没有影响

何况,还有你们这些朋友的支持
WAKU 7 2006-6-12 11:59
9
0
唉...现在像北极星版版的好人不多了
误入楼台 1 2006-6-12 13:14
10
0
支持这个东西 学习
sbright 2 2006-6-12 13:32
11
0
最初由 北级星 发布
这个软件写的比较久了,回忆了下。加深对加载过程的了解,熟悉WIN32调试API。

大哥如果写文章太累,可以把自己可以发的代码发出来,写个大概说明就好.
其他牛b的大虾们也支持一下啊,多发发你们的程序.强烈支持北极星,来,亲一个.....
franke 2006-6-12 19:52
12
0
很详细的资料,可以减少小虾们的入门时间.把附件下了,仔细看看.多谢北极星
figofuture 2006-6-12 20:03
13
0
强烈支持一下啊!!!!!!!
scwlf 2006-6-12 22:23
14
0
非常感谢,大大辛苦了
萝卜 1 2006-6-12 23:32
15
0
支持!下载回头看
drwch 3 2006-6-13 00:19
16
0
最初由 北极星2003 发布
多谢指点
我测试了你说的,完全正确
在这个地方,我确实做了重复工作


不必客气,好文是要支持的

顺便问一下有没有办法直接提升每日许可发帖的数量,我想PM一下看雪,但是发现论坛连短消息系统都被关掉了
CCDebuger 24 2006-6-13 00:35
17
0
drwch 兄可以来篇精华让我们学习一下,最快的方法就是来一篇精华帖,将会没有发帖限制,还可以上传文件,使用FTP
ngaut 6 2006-6-13 03:43
18
0
辛苦了,支持!
myd 2006-6-13 12:27
19
0
辛苦了,好帖哦!
alpsdew 4 2006-6-13 13:36
20
0
向所有写作者致敬!

学习ing...
drwch 3 2006-6-13 18:24
21
0
最初由 CCDebuger 发布
drwch 兄可以来篇精华让我们学习一下,最快的方法就是来一篇精华帖,将会没有发帖限制,还可以上传文件,使用FTP


我不知道该写些什么好啊,好像我会的这里基本上都有提到
littlepotato 2006-6-14 01:13
22
0
【时间】2007年6月12日
you8107 1 2006-6-14 10:42
23
0
北极星2003 25 2006-6-14 11:39
24
0
Originally posted by littlepotato
【时间】2007年6月12日


这个错误可以载入史册了
我爱罗 2006-6-14 13:48
25
0
各位大侠,我是一个菜鸟,不过我对这个很感兴趣,希望各位大侠多多帮助.
lennon 2006-6-14 13:50
26
0
太好了,好文一定要顶
我爱罗 2006-6-15 11:16
27
0
楼主为啥子?
我下 下来的代码运行不起,还报错:cannot open include file 'res\IPPack,rc2'

而且软件运行的也不理想
北极星2003 25 2006-6-15 11:51
28
0
最初由 我爱罗 发布
楼主为啥子?
我下 下来的代码运行不起,还报错:cannot open include file 'res\IPPack,rc2'

而且软件运行的也不理想


在上传附件的时候不小心把图标资源res文件夹删了,
编译报错,一直按F4,把对应行注释掉就行了,不影响程序执行

运行不理想很正常,
这个小软件的目标是演示HOOK API 及插入DLL的实际应用,
仅仅HOOK了send, sendto, recv, recvfrom四个函数,如果目标进程用其他的函数进行数据传输的话,就根本不起作用
真正要效果好的话,要在驱动级别实现
Saver 2006-6-15 22:08
29
0
回完贴,然后开始仔细看
xiluoyou 2006-6-15 23:42
30
0
顶一下,收藏慢慢学习!
xinix 2006-6-16 15:36
31
0
不错

如果论坛多几个北极

就好了
Vegeta 13 2006-6-18 10:19
32
0
作得想个毕业设计,恐怕真是毕业设计的话老师没几个看得懂的。
我爱罗 2006-6-20 15:20
33
0
好象,不能截获数据包
独孤无剑 2006-6-21 05:42
34
0
学习之中...............
我爱罗 2006-6-21 17:18
35
0
版主:好象,不能截获数据包,我都调试了两天了,
我都快疯了.你能把调试好的,能截获数据包的程序发给我吗?
我的把它搞明白啊.
我的EMAIL:monk0123456@126.com
北极星2003 25 2006-6-21 22:29
36
0
最初由 我爱罗 发布
版主:好象,不能截获数据包,我都调试了两天了,
我都快疯了.你能把调试好的,能截获数据包的程序发给我吗?
我的把它搞明白啊.
我的EMAIL:monk0123456@126.com


已经给你发了
这个帖子的附件里也有
我爱罗 2006-6-22 11:11
37
0
我写了一个简单的通讯程序,为什么不能捕获数据包了?
为什么我运行这个程序的时候,并不是像你在贴子上演示的呢?
我的邮箱不能发邮件了,你可以加我的QQ吗?
QQ:279405290
iiiila 2006-6-22 11:26
38
0
不错,顶一下先。
北极星2003 25 2006-6-22 12:24
39
0
最初由 我爱罗 发布
我写了一个简单的通讯程序,为什么不能捕获数据包了?
为什么我运行这个程序的时候,并不是像你在贴子上演示的呢?
我的邮箱不能发邮件了,你可以加我的QQ吗?
QQ:279405290


HOOK_send.Hook                ( "wsock32.dll", "send",                (FARPROC)MY_send ) ;
HOOK_recv.Hook                ( "wsock32.dll", "recv",                (FARPROC)MY_recv ) ;
HOOK_sendto.Hook        ( "wsock32.dll", "sendto",                (FARPROC)MY_sendto ) ;
HOOK_recvfrom.Hook        ( "wsock32.dll", "recvfrom",        (FARPROC)MY_recvfrom ) ;
注意这里,我HOOK的是wsock32.dll

而你的TcpServer用PE打开后没有wsock32.dll,只有win2_32.dll,函数库不同,所以也就是说HOOK失败
这里我的软件写的也有漏洞,在CFEAHook失败时没抱错

你的软件我这里不能编译
#include "../common/InitSock.h"
估计你在这里导入了win2_32.dll

试着让他导入wsock32.dll
#include "winsock2.h"
#pragma comment ( lib, "ws2_32.lib" )

HOOK_send.Hook                ( "wsock32.dll", "send",        (FARPROC)MY_send ) ;
HOOK_recv.Hook                ( "wsock32.dll", "recv",        (FARPROC)MY_recv ) ;
HOOK_sendto.Hook        ( "wsock32.dll", "sendto",        (FARPROC)MY_sendto ) ;
HOOK_recvfrom.Hook        ( "wsock32.dll", "recvfrom",        (FARPROC)MY_recvfrom ) ;
或者你可以直接把wsock32.dll直接改成win2_32.dll

总之问题就在这里,知道了原因,至于怎么改都无所谓了

由于我的失误,对你在学习时造成不必要的麻烦,深感谦意
bjaoyun 2006-7-1 13:57
40
0
好文章,学了很多东西
天涯浪人 2 2006-7-1 15:18
41
0
支持一下
netarmy 2006-7-1 23:23
42
0
真是强人呀
我要是会就好了
jipo400 2 2006-7-3 10:46
43
0
强烈支持学习中...
torelax 1 2006-7-6 22:32
44
0
支持楼主,好铁
lengie 2006-7-7 14:30
45
0
第一次看的时候,没看明白,所以没回贴
今天看明白了点,所以回贴,做个记录点,嘻嘻
Aker 4 2006-7-7 15:49
46
0
最初由 sbright 发布

大哥如果写文章太累,可以把自己可以发的代码发出来,写个大概说明就好.
其他牛b的大虾们也支持一下啊,多发发你们的程序.强烈支持北极星,来,亲一个.....

zhuliang 5 2006-7-15 17:34
47
0
最初由 prince 发布
北极星辛苦!
wangn 2006-7-22 05:40
48
0
支持!下载学习学习
bookworm 3 2006-8-3 06:17
49
0
1。一般的方法使用CreateRemoteThread()在目标进程中创建一个thread,让该thread来LoadLibrary(你的DLL)。

到目前为止我在网上看到的该方法的实现代码都基本上雷同,一个共同的大前提是假定在你的process和目标process里,LoadLibrary(A/W)的entry point是一样的。因为LoadLibraryA/LoadLibraryW是kernel32.dll输出的,而该DLL一般而言在不同的进程的virtual memory space里是在同样的地方(不同的Windows版本倒是有可能不同),不太会被rebase。所以看看你自己的进程里LoadLibrary的起始地址,就可以假定目标进程的LoadLibrary也是同样的起始地址。

2。用GetProcAddress()可以得到API的起始地址。但kernel32.dll是可以被rebase的,如果你的进程或者目标进程里的该DLL ImageBase变了,你的代码插入程序不会有事情,创建的远程线程倒是会垮掉。

3。这里作者的代码,比如(5)封装HOOK API入口地址覆盖到CFEAHook类,是有bug的。你怎么知道要patch的函数入口点的头5个字节一定是一个指令?万一它的第一个指令是1个到4个字节呢?你要使你的方法尽量通用化,就不能作这个假定。可以参考微软的Detours (http://research.microsoft.com/sn/detours/),看看它的entry point patching是如何做的。

4。API hook(SetWindowsHookEx):该方法的前提是进程有UI,或者说有user32.DLL。对Console program是白搭。

5。Hook的方法很多,可以参考

http://www.codeproject.com/system/hooksys.asp

6。原文:
“2、  存在的难点
由于IAT信息是在可执行文件初始化时经过PE加载器改写的,而不是原本的磁盘文件中的数据。问题就在这里,什么时候才是对IAT进行操作的最佳时机?PE加载器对IAT部分的改写是在什么时候完成的?如果仅仅创建挂起的进程,此时的加载器是否写入IAT信息?“

PE加载器在创建一个进程的时候,CreateProcess(...,CREATE_SUSPENDED, ...),它会遍历程序的import table,把相关的DLL加载进来,更新IAT,然后先是运行该DLL的CRTDllMain(),接着是它的DllMain()。如果该DLL依赖其它的DLL,就先载入其它的DLL,有些类似C++里对象的创建,先做父类的工作(constructor),然后是子类。IAT就是这个时候更新的。一直等到主要的thread context等等资源分配完毕,然后PE Loader就ResumeThread(你的主线程的threadid)。到这个时候DLL里的export table基本上没有用了,因为主程序的IAT里已经有了具体的地址。以后程序运行过程中也不会去看DLL的Export Table,直接到Import Table里去查去了,然后jump。
jiangqixdu 2006-8-15 20:29
50
0
下载来看看,还是源码好点
游客
登录 | 注册 方可回帖
返回