青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Do What You think !!

 

用戶層下攔截系統(tǒng)api的原理與實現(xiàn) (轉(zhuǎn)載)

文章作者:kiki

攔截api的技術(shù)有很多種,大體分為用戶層和內(nèi)核層的攔截.這里只說說用戶層的攔截.而用戶層也分為許多種:修改PE文件導(dǎo)入表,直接修改要攔截的api的內(nèi)存(從開始到最后,使程序跳轉(zhuǎn)到指定的地址執(zhí)行).不過大部分原理都是修改程序流程,使之跳轉(zhuǎn)到你要執(zhí)行的地方,然后再返回到原地址.原來api的功能必須還能實現(xiàn).否則攔截就失去作用了.修改文件導(dǎo)入表的方法的缺點是如果用戶程序動態(tài)加載(使用LoadLibrary和GetProcAddress函數(shù)),攔截將變得復(fù)雜一些.所以這里介紹一下第二種方法,直接修改api,當(dāng)然不是全局的.(后面會說到)

  需要了解的一些知識:

  1.windows內(nèi)存的結(jié)構(gòu)屬性和進程地址空間

  2.函數(shù)堆棧的一些知識



一:win2000和xp的內(nèi)存結(jié)構(gòu)和進程地址空間

  windows采用4GB平坦虛擬地址空間的做法。即每個進程單獨擁有4GB的地址空間。每個進程只能訪問自己的這4GB的虛擬空間,而對于其他進程的地址空間則是不可見的。這樣保證了進程的安全性和穩(wěn)定性。但是,這4GB的空間是一個虛擬空間,在使用之前,我們必須先保留一段虛擬地址,然后再為這段虛擬地址提交物理存儲器。可是我們的內(nèi)存大部分都還沒有1GB,那么這4GB的地址空間是如何實現(xiàn)的呢?事實上windows采用的內(nèi)存映射這種方法,即把物理磁盤當(dāng)作內(nèi)存來使用,比如我們打開一個可執(zhí)行文件的時候,操作系統(tǒng)會為我們開辟這個4GB的地址空間:0x00000000--0xffffffff。其中0x00000000--0x7fffffff是屬于用戶層的空間.0x80000000--0xffffffff則屬于共享內(nèi)核方式分區(qū),主要是操作系統(tǒng)的線程調(diào)度,內(nèi)存管理,文件系統(tǒng)支持,網(wǎng)絡(luò)支持和所有設(shè)備驅(qū)動程序。對于用戶層的進程,這些地址空間是不可訪問的。任何訪問都將導(dǎo)致一個錯誤。開辟這4GB的虛擬地址空間之后,系統(tǒng)會把磁盤上的執(zhí)行文件映射到進程的地址空間中去(一般是在地址0x00400000,可以通過修改編譯選項來修改這個地址)而一個進程運行所需要的動態(tài)庫文件則一般從0x10000000開始加載。但是如果所有的動態(tài)庫都加載到這個位置肯定會引起沖突。因此必須對一些可能引起沖突的dll編譯時重新修改基地址。但是對于所有的操作系統(tǒng)所提供的動態(tài)庫windows已經(jīng)定義好了映射在指定的位置。這個位置會隨著版本的不同而會有所改變,不過對于同一臺機器上的映射地址來說都是一樣的。即在a進程里映射的kernel32.dll的地址和在進程b里的kernel32.dll的地址是一樣的。對于文件映射是一種特殊的方式,使得程序不需要進行磁盤i/o就能對磁盤文件進行操作,而且支持多種保護屬性。對于一個被映射的文件,主要是使用CreateFileMapping函數(shù),利用他我們可以設(shè)定一些讀寫屬性:PAGE_READONLY,PAGE_READWRITE,PAGE_WRITECOPY.第一參數(shù)指定只能對該映射文件進行讀操作。任何寫操作將導(dǎo)致內(nèi)存訪問錯誤。第二個參數(shù)則指明可以對映射文件進行讀寫。這時候,任何對文件的讀寫都是直接操作文件的。而對于第三個參數(shù)PAGE_WRITECOPY顧名思義就是寫入時拷貝,任何向這段內(nèi)存寫入的操作(因為文件是映射到進程地址空間的,對這段空間的讀寫就相當(dāng)于對文件進行的直接讀寫)都將被系統(tǒng)捕獲,并重新在你的虛擬地址空間重新保留并分配一段內(nèi)存,你所寫入的一切東西都將在這里,而且你原先的指向映射文件的內(nèi)存地址也會實際指向這段重新分配的內(nèi)存,于是在進程結(jié)束后,映射文件內(nèi)容并沒有改變,只是在運行期間在那段私有拷貝的內(nèi)存里面存在著你修改的內(nèi)容。windows進程運行所需要映射的一些系統(tǒng)dll就是以這種方式映射的,比如常用的ntdll.dll,kernel32.dll,gdi32.dll.幾乎所有的進程都會加載這三個動態(tài)庫。如果你在一個進程里修改這個映射文件的內(nèi)容,并不會影響到其他的進程使用他們。你所修改的只是在本進程的地址空間之內(nèi)的。事實上原始文件并沒有被改變。
這樣,在后面的修改系統(tǒng)api的時候,實際就是修改這些動態(tài)庫地址內(nèi)的內(nèi)容。前面說到這不是修改全局api就是這個原因,因為他們都是以寫入時拷貝的方式來映射的。不過這已經(jīng)足夠了,windows提供了2個強大的內(nèi)存操作函數(shù)ReadProcessMemory和WriteProcessMemory.利用這兩個函數(shù)我們就可以隨便對任意進程的任意用戶地址空間進行讀寫了。但是,現(xiàn)在有一個問題,我們該寫什么,說了半天,怎么實現(xiàn)跳轉(zhuǎn)呢?現(xiàn)在來看一個簡單的例子:
MessageBox(NULL, "World", "Hello", 0);
我們在執(zhí)行這條語句的時候,調(diào)用了系統(tǒng)api MessageBox,實際上在程序中我沒有定義UNICODE宏,系統(tǒng)調(diào)用的是MessageBox的ANSI版本MessageBoxA,這個函數(shù)是由user32.dll導(dǎo)出的。下面是執(zhí)行這條語句的匯編代碼:
0040102A   push     0
0040102C   push     offset string "Hello" (0041f024)
00401031   push     offset string "World" (0041f01c)
00401036   push     0
00401038   call     dword ptr [__imp__MessageBoxA@16 (0042428c)]
前面四條指令分別為參數(shù)壓棧,因為MessageBoxA是__stdcall調(diào)用約定,所以參數(shù)是從右往左壓棧的。最后再CALL 0x0042428c

看看0042428c這段內(nèi)存的值:
0042428C 0B 05 D5 77 00 00 00
可以看到這個值0x77d5050b,正是user32.dll導(dǎo)出函數(shù)MessageBoxA的入口地址。

這是0x77D5050B處的內(nèi)容,
77D5050B 8B FF           mov       edi,edi
77D5050D 55             push     ebp
77D5050E 8B EC           mov       ebp,esp
理論上只要改變api入口和出口的任何機器碼,都可以攔截該api。這里我選擇最簡單的修改方法,直接修改api入口的前十個字節(jié)來實現(xiàn)跳轉(zhuǎn)。為什么是十字節(jié)呢?其實修改多少字節(jié)都沒有關(guān)系,只要實現(xiàn)了函數(shù)的跳轉(zhuǎn)之后,你能把他們恢復(fù)并讓他繼續(xù)運行才是最重要的。在CPU的指令里,有幾條指令可以改變程序的流程:JMP,CALL,INT,RET,RETF,IRET等指令。這里我選擇CALL指令,因為他是以函數(shù)調(diào)用的方式來實現(xiàn)跳轉(zhuǎn)的,這樣可以帶一些你需要的參數(shù)。到這里,我該說說函數(shù)的堆棧了。

總結(jié):windows進程所需要的動態(tài)庫文件都是以寫入時拷貝的方式映射到進程地址空間中的。這樣,我們只能攔截指定的進程。修改目標(biāo)進程地址空間中的指定api的入口和出口地址之間的任意數(shù)據(jù),使之跳轉(zhuǎn)到我們的攔截代碼中去,然后再恢復(fù)這些字節(jié),使之能順利工作。




二:函數(shù)堆棧的一些知識

  正如前面所看到MessageBoxA函數(shù)執(zhí)行之前的匯編代碼,首先將四個參數(shù)壓棧,然后CALL MessageBoxA,這時候我們的線程堆棧看起來應(yīng)該是這樣的:

|   |   <---ESP
|返回地址|
|參數(shù)1|
|參數(shù)2|
|參數(shù)3|
|參數(shù)4|
|..   |

我們再看MessageBoxA的匯編代碼,
77D5050B 8B FF           mov       edi,edi
77D5050D 55             push     ebp
77D5050E 8B EC           mov       ebp,esp
注意到堆棧的操作有PUSH ebp,這是保存當(dāng)前的基址指針,以便一會兒恢復(fù)堆棧后返回調(diào)用線程時使用,然后再有mov ebp,esp就是把當(dāng)前esp的值賦給ebp,這時候我們就可以使用 ebp+偏移 來表示堆棧中的數(shù)據(jù),比如參數(shù)1就可以表示成[ebp+8],返回地址就可以表示成[ebp+4]..如果我們在攔截的時候要對這些參數(shù)和返回地址做任何處理,就可以使用這種方法。如果這個時候函數(shù)有局部變量的話,就通過減小ESP的值的方式來為之分配空間。接下來就是保存一些寄存器:EDI,ESI,EBX.要注意的是,函數(shù)堆棧是反方向生長的。這時候堆棧的樣子:
|....|
|EDI| <---ESP
|ESI|
|EBX|
|局部變量|
|EBP   |  
|返回地址|
|參數(shù)1|
|參數(shù)2|
|參數(shù)3|
|參數(shù)4|
|..   |

在函數(shù)返回的時候,由函數(shù)自身來進行堆棧的清理,這時候清理的順序和開始入棧的順序恰恰相反,類似的匯編代碼可能是這樣的:

pop edi
pop esi
pop ebx
add esp, 4
pop ebp
ret 0010
先恢復(fù)那些寄存器的值,然后通過增加ESP的值的方式來釋放局部變量。這里可以用mov esp, ebp來實現(xiàn)清空所有局部變量和其他一些空閑分配空間。接著函數(shù)會恢復(fù)EBP的值,利用指令POP EBP來恢復(fù)該寄存器的值。接著函數(shù)運行ret 0010這個指令。該指令的意思是,函數(shù)把控制權(quán)交給當(dāng)前棧頂?shù)牡刂返闹噶睿瑫r清理堆棧的16字節(jié)的參數(shù)。如果函數(shù)有返回值的話,那在EAX寄存器中保存著當(dāng)前函數(shù)的返回值。如果是__cdecl調(diào)用方式,則執(zhí)行ret指令,對于堆棧參數(shù)的處理交給調(diào)用線程去做。如wsprintf函數(shù)。

這個時候堆棧又恢復(fù)了原來的樣子。線程得以繼續(xù)往下執(zhí)行...
在攔截api的過程之中一個重要的任務(wù)就是保證堆棧的正確性。你要理清每一步堆棧中發(fā)生了什么。



三:形成思路
 
  呵呵,不知道你現(xiàn)在腦海是不是有什么想法。怎么去實現(xiàn)攔截一個api?
  這里給出一個思路,事實上攔截的方法真的很多,理清了一個,其他的也就容易了。而且上面所說的2個關(guān)鍵知識,也可以以另外的形式來利用。
  我以攔截CreateFile這個api為例子來簡單說下這個思路吧:
 
  首先,既然我們要攔截這個api就應(yīng)該知道這個函數(shù)在內(nèi)存中的位置吧,至少需要知道從哪兒入口。CreateFile這個函數(shù)是由kernel32.dll這個動態(tài)庫導(dǎo)出的。我們可以使用下面的方法來獲取他映射到內(nèi)存中的地址:
  HMODULE hkernel32 = LoadLibrary("Kernel32.dll");
  PVOID dwCreateFile = GetProcAddress(hkernei32, "CreateFileA");
這就可以得到createfile的地址了,注意這里是獲取的createfile的ansic版本。對于UNICODE版本的則獲取CreateFileW。這時dwCreateFile的值就是他的地址了。對于其他進程中的createfile函數(shù)也是這個地址,前面說過windows指定了他提供的所有的dll文件的加載地址。
 
  接下來,我們該想辦法實現(xiàn)跳轉(zhuǎn)了。最簡單的方法就是修改這個api入口處的代碼了。但是我們該修改多少呢?修改的內(nèi)容為什么呢?前面說過我們可以使用CALL的方式來實現(xiàn)跳轉(zhuǎn),這種方法的好處是可以為你的攔截函數(shù)提供一個或者多個參數(shù)。這里只要一個參數(shù)就足夠了。帶參數(shù)的函數(shù)調(diào)用的匯編代碼是什么樣子呢,前面也已經(jīng)說了,類似與調(diào)用MessageBoxA時的代碼:

PUSH 參數(shù)地址
CALL 函數(shù)入口地址(這里為一個偏移地址)

執(zhí)行這2條指令就能跳轉(zhuǎn)到你要攔截的函數(shù)了,但是我們該修改成什么呢。首先,我們需要知道這2條指令的長度和具體的機器代碼的值。其中PUSH對應(yīng)0x68,而CALL指令對應(yīng)的機器碼為0xE8,而后面的則分別對應(yīng)攔截函數(shù)的參數(shù)地址和函數(shù)的地址。注意第一個是一個直接的地址,而第二個則是一個相對地址。當(dāng)然你也可以使用0xFF0x15這個CALL指令來進行直接地址的跳轉(zhuǎn)。
下面就是計算這2個地址的值了,
對于參數(shù)和函數(shù)體的地址,要分情況而定,對于對本進程中api的攔截,則直接取地址就可以了。對于參數(shù),可以先定義一個參數(shù)變量,然后取變量地址就ok了。
如果是想攔截其他進程中的api,則必須使用其他一些方法,最典型的方法是利用VirtualAllocEx函數(shù)來在其他進程中申請和提交內(nèi)存空間。然后用WriteProcessMemory來分別把函數(shù)體和參數(shù)分別寫入申請和分配的內(nèi)存空間中去。然后再生成要修改的數(shù)據(jù),最后用WriteProcessMemory來修改api入口,把入口的前10字節(jié)修改為剛剛生成的跳轉(zhuǎn)數(shù)據(jù)。比如在遠程進程中你寫入的參數(shù)和函數(shù)體的內(nèi)存地址分別為0x00010000和0x00011000,則生成的跳轉(zhuǎn)數(shù)據(jù)為 68 00 00 01 00 E8 00 10 01 00(PUSH 00010000 CALL 00011000),這樣程序運行createfile函數(shù)的時候?qū)冗\行PUSH 00010000 CALL 00011000,這樣就達到了跳轉(zhuǎn)的目的。此刻我們應(yīng)該時刻注意堆棧的狀態(tài),對于CreateFile有
HANDLE CreateFile(
LPCTSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile
);
可以看到其有7個參數(shù),于是在調(diào)用之前,堆棧應(yīng)該已經(jīng)被壓入了這7個參數(shù),堆棧的樣子:
|....|   <---ESP
|createfile執(zhí)行后的下一條指令地址|
|參數(shù)1|
|參數(shù)2|
|參數(shù)3|
|參數(shù)4|
|參數(shù)5|
|參數(shù)6|
|參數(shù)7|
|..|

這是執(zhí)行到我們的跳轉(zhuǎn)語句:PUSH 00010000,于是堆棧又變了:

|....|   <---ESP
|00010000|
|createfile執(zhí)行后的下一條指令地址|
|參數(shù)1|
|參數(shù)2|
|參數(shù)3|
|參數(shù)4|
|參數(shù)5|
|參數(shù)6|
|參數(shù)7|
|..|

接著執(zhí)行CALL 00011000,堆棧變?yōu)椋?br>|...| <---ESP
|api入口之后的第11個字節(jié)的指令的地址|  
|00010000|
|createfile執(zhí)行后的下一條指令地址|
|參數(shù)1|
|參數(shù)2|
|參數(shù)3|
|參數(shù)4|
|參數(shù)5|
|參數(shù)6|
|參數(shù)7|
|..|

接下來就到了我們的攔截函數(shù)中拉,當(dāng)然,函數(shù)肯定也會做一些類似動作,把EBP壓棧,為局部變量分配空間等。這時候堆棧的樣子又變了:

|EDI| <---ESP
|ESI|
|EBX|
|局部變量|
|EBP|   <---EBP
|api入口之后的第11個字節(jié)的指令的地址|  
|00010000|
|createfile執(zhí)行后的下一條指令地址|
|參數(shù)1|
|參數(shù)2|
|參數(shù)3|
|參數(shù)4|
|參數(shù)5|
|參數(shù)6|
|參數(shù)7|
|..|

這時候,你想做什么就盡情地做吧,獲取參數(shù)信息,延緩執(zhí)行CreateFile函數(shù)等等。拿獲取打開文件句柄的名字來說吧,文件名是第一個參數(shù),前面說過我們可以用[EBP+8]來獲取參數(shù),但是對照上面的堆棧形狀,中間又加了另外一些數(shù)據(jù),所以我們用[EBP+16]來獲取第一個參數(shù)的地址。比如:
char* PFileName = NULL;
__asm{
MOV EAX,[EBP+16]
MOV [szFileName], EAX
}

比如我們用一個messagebox來彈出一個信息,說明該程序即將打開一個某謀路徑的文件句柄。但是有一個要注意的是,如果你想攔截遠程進程的話,對于那個攔截函數(shù)中所使用到的任何函數(shù)或者以任何形式的相對地址的調(diào)用都要停止。因為每個進程中的地址分配都是獨立的,比如上面的CALL MessageBoxA改成直接地址的調(diào)用。對于使用messagebox,我們應(yīng)該定義一個函數(shù)指針,然后把這個指針的值賦值為user32.dll中導(dǎo)出該函數(shù)的直接地址。然后利用這個指針來進行函數(shù)調(diào)用。對于messagebox函數(shù)的調(diào)用可以這樣,在源程序中定義一個參數(shù)結(jié)構(gòu)體,參數(shù)中包含一個導(dǎo)出函數(shù)的地址,把這個地址設(shè)為MessageBoxA的直接地址,獲取地址的方法就不說了。然后把這個參數(shù)傳給攔截函數(shù),就可以使用拉。這也是利用一個參數(shù)的原因。類似代碼如下:


typedef struct _RemoteParam {
  DWORD dwMessageBox;
} RemoteParam, * PRemoteParam;

typedef int (__stdcall * PFN_MESSAGEBOX)(HWND, LPCTSTR, LPCTSTR, DWORD);//定義一個函數(shù)指針

//攔截函數(shù)
void HookCreateFile(LPVOID lParam)
{
RemoteParam* pRP = (RemoteParam*)lParam;//獲取參數(shù)地址
char* PFileName = NULL;//定義一個指針
__asm{
MOV EAX,[EBP+16]
MOV [szFileName], EAX //把CreateFile第一個參數(shù)的值,文件的路徑的地址傳               //給szFileName
}

//定 義一個函數(shù)指針
PFN_MESSAGEBOX pfnMessageBox = (PFN_MESSAGEBOX)pRP->dwMessageBox;

pfnMessageBox(NULL, PFileName, PFileName, MB_ICONINFORMATION |MB_OK);
//輸出要打開的文件的路徑
//.....
}

對于你要使用的其他函數(shù),都是使用同樣的方式,利用這個參數(shù)來傳遞我們要傳遞的函數(shù)的絕對地址,然后定義這個函數(shù)指針,就可以使用了。


好了,接下來我們該讓被攔截的api正常工作了,這個不難,把他原來的數(shù)據(jù)恢復(fù)一下就可以了。那入口的10個字節(jié)。我們在改寫他們的時候應(yīng)該保存一下,然后也把他放在參數(shù)中傳遞給攔截函數(shù),呵呵,參數(shù)的作用可多了。接著我們就可以用WriteProcessMemory函數(shù)來恢復(fù)這個api的入口了,代碼如下:
PFN_GETCURRENTPROCESS pfnGetCurrentProcess = (PFN_GETCURRENTPROCESS)pRP->dwGetCurrentProcess;
PFN_WRITEPROCESSMEMORY pfnWriteProcessMemory = (PFN_WRITEPROCESSMEMORY)pRP->dwWriteProcessMemory;
 
if(!pfnWriteProcessMemory(pfnGetCurrentProcess(),
                            (LPVOID)pfnConnect,
                            (LPCVOID)pRP->szOldCode,
                            10,
                            NULL))
pfnMessageBox(NULL, pRP->szModuleName1, pRP->szModuleName2, MB_ICONINFORMATION | MB_OK);
其中這些函數(shù)指針的定義和上面的類似。
而參數(shù)中的szoldcode則是在源程序中在修改api之前保存好,然后傳給攔截函數(shù),在源程序中是用ReadProcessMemory函數(shù)來獲取他的前10個字節(jié)的:
ReadProcessMemory(GetCurrentProcess(),
                      (LPCVOID)RParam.dwCreateFile,
                      oldcode,
                      10,
                      &dwPid)
strcat((char*)RParam.szOldCode, (char*)oldcode);


接下來如果你還繼續(xù)保持對該api的攔截,則又該用WriteProcessMemory 來修改入口了,跟前面的恢復(fù)入口是一樣的,只不過把szOldCode換成了szNewCode了而已。這樣你又能對CreateFile繼續(xù)攔截了。

好了,接下來該進行堆棧的清理了,也許你還要做點其他事情,盡管做去。但是清理堆棧是必須要做的,在函數(shù)結(jié)束的時候,因為在我們放任api恢復(fù)執(zhí)行之后,他又return 到我們的函數(shù)中來了,這個時候的堆棧是什么樣子呢?
|EDI| <---ESP
|ESI|
|EBX|
|局部變量|
|EBP|   <---EBP
|api入口之后的第11個字節(jié)的指令的地址|  
|00010000|
|createfile執(zhí)行后的下一條指令地址|
|參數(shù)1|
|參數(shù)2|
|參數(shù)3|
|參數(shù)4|
|參數(shù)5|
|參數(shù)6|
|參數(shù)7|
|..|

我們的目標(biāo)是把返回值記錄下來放到EAX寄存器中去,把返回地址記錄下來,同時把堆棧恢復(fù)成原來的樣子。
首先我們恢復(fù)那些寄存器的值,接著釋放局部變量,可以用mov esp, ebp.因為我們不清楚具體的局部變量分配了多少空間。所以使用這個方法。


__asm
{POP EDI
POP ESI
POP EBX   //恢復(fù)那些寄存器
MOV EDX, [NextIpAddr]//把返回地址放到EDX中,因為待會兒             //EBX被恢復(fù)后,線程中的所有局部變量就不能正常使用了。
     
MOV EAX, [RetValue]//返回值放到EAX中,當(dāng)然也可以修改這個返回值
MOV ESP, EBP//清理局部變量
POP EBP//恢復(fù)EBP的值
ADD ESP, 28H //清理參數(shù)和返回地址,注意一共(7+1+1+1)*4
PUSH EDX //把返回地址壓棧,這樣棧中就只有這一個返回地址了,返回之后棧       //就空了
RET
}

這樣,一切就完成了,堆棧恢復(fù)了應(yīng)該有的狀態(tài),而你想攔截的也攔截到了。


四:后記
  攔截的方式多種多樣,不過大體的思路卻都相同。要時刻注意你要攔截的函數(shù)的堆棧狀態(tài)以及在攔截函數(shù)中的對數(shù)據(jù)的引用和函數(shù)的調(diào)用(地址問題)。

 
//////////////////////////////////////////////////////////////////////
附錄:一個攔截CreateFile函數(shù)的簡單實現(xiàn)
//////////////////////////////////////////////////////////////////////
Copy code
#include <stdio.h>
#include <windows.h>
#include <Psapi.h>

#pragma comment(lib, "psapi.lib")

typedef struct _RemoteParam {
  DWORD dwCreateFile;
  DWORD dwMessageBox;
  DWORD dwGetCurrentProcess;
  DWORD dwWriteProcessMemory;
  unsigned char szOldCode[10];
  DWORD FunAddr;
} RemoteParam, * PRemoteParam;

typedef HANDLE (__stdcall * PFN_CREATEFILE)(LPCTSTR,DWORD,DWORD,LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE);
typedef int (__stdcall * PFN_MESSAGEBOX)(HWND, LPCTSTR, LPCTSTR, DWORD);
typedef BOOL (__stdcall * PFN_WRITEPROCESSMEMORY)(HANDLE,LPVOID,LPCVOID,SIZE_T,SIZE_T*);
typedef HANDLE (__stdcall * PFN_GETCURRENTPROCESS)(void);

#define PROCESSNUM 128
#define MYMESSAGEBOX "MessageBoxW"
#define MYCREATEFILE "CreateFileW"

void HookCreateFile(LPVOID lParam)
{

  RemoteParam* pRP = (RemoteParam*)lParam;


  DWORD NextIpAddr = 0;
  DWORD dwParamaAddr = 0;

  HANDLE RetFpHdl = INVALID_HANDLE_VALUE;
  LPCTSTR lpFileName;
  DWORD dwDesiredAccess;
  DWORD dwShareMode;
  LPSECURITY_ATTRIBUTES lpSecurityAttributes;
  DWORD dwCreationDisposition;
  DWORD dwFlagsAndAttributes;
  HANDLE hTemplateFile;
  PFN_CREATEFILE pfnCreatefile = (PFN_CREATEFILE)pRP->dwCreateFile;


  __asm
  {
  MOV EAX,[EBP+8]
  MOV [dwParamaAddr], EAX
  MOV EAX,[EBP+12]      
  MOV [NextIpAddr], EAX
  MOV EAX,[EBP+16]
  MOV [lpFileName], EAX
  MOV EAX,[EBP+20]
  MOV [dwDesiredAccess],EAX
  MOV EAX,[EBP+24]
  MOV [dwShareMode],EAX
  MOV EAX,[EBP+28]
  MOV [lpSecurityAttributes],EAX
  MOV EAX,[EBP+32]
  MOV [dwCreationDisposition],EAX
  MOV EAX,[EBP+36]
  MOV [dwFlagsAndAttributes],EAX
  MOV EAX,[EBP+40]
  MOV [hTemplateFile],EAX  
  }

  PFN_MESSAGEBOX pfnMessageBox = (PFN_MESSAGEBOX)pRP->dwMessageBox;
  int allowFlag = pfnMessageBox(NULL, lpFileName, NULL, MB_ICONINFORMATION | MB_YESNO);
 
  if(allowFlag == IDYES)
  {
  unsigned char szNewCode[10];
  int PramaAddr = (int)dwParamaAddr;
  szNewCode[4] = PramaAddr>>24;
  szNewCode[3] = (PramaAddr<<8)>>24;
  szNewCode[2] = (PramaAddr<<16)>>24;
  szNewCode[1] = (PramaAddr<<24)>>24;
  szNewCode[0] = 0x68;
 
  int funaddr = (int)pRP->FunAddr - (int)pfnCreatefile - 10 ;
  szNewCode[9] = funaddr>>24;
  szNewCode[8] = (funaddr<<8)>>24;
  szNewCode[7] = (funaddr<<16)>>24;
  szNewCode[6] = (funaddr<<24)>>24;
  szNewCode[5] = 0xE8;
 
 
  PFN_GETCURRENTPROCESS pfnGetCurrentProcess = (PFN_GETCURRENTPROCESS)pRP->dwGetCurrentProcess;
  PFN_WRITEPROCESSMEMORY pfnWriteProcessMemory = (PFN_WRITEPROCESSMEMORY)pRP->dwWriteProcessMemory;
  pfnWriteProcessMemory(pfnGetCurrentProcess(),
                (LPVOID)pfnCreatefile,
                (LPCVOID)pRP->szOldCode,
                10,
                NULL);

  RetFpHdl = pfnCreatefile(lpFileName,
                  dwDesiredAccess,
                  dwShareMode,
                  lpSecurityAttributes,
                  dwCreationDisposition,
                  dwFlagsAndAttributes,
                  hTemplateFile);
  pfnWriteProcessMemory(pfnGetCurrentProcess(),
                (LPVOID)pfnCreatefile,
                (LPCVOID)szNewCode,
                10,
                NULL);
  }


  __asm
    {POP EDI
      POP ESI
      POP EBX
      MOV EDX, [NextIpAddr]
      MOV EAX, [RetFpHdl]
      MOV ESP, EBP
      POP EBP
      ADD ESP, 28H
      PUSH EDX
      RET
    }

 
}



BOOL AdjustProcessPrivileges(LPCSTR szPrivilegesName)
{
  HANDLE hToken;
  TOKEN_PRIVILEGES tkp;

  if(!OpenProcessToken(GetCurrentProcess(),
    TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken))
  {
    return FALSE;
  }

  if(!LookupPrivilegeValue(NULL,szPrivilegesName,
                  &tkp.Privileges[0].Luid))
  {
    CloseHandle(hToken);
    return FALSE;
  }
 
  tkp.PrivilegeCount = 1;
  tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
 
  if(!AdjustTokenPrivileges(hToken,FALSE,&tkp,sizeof(tkp),NULL,NULL))
  {
    CloseHandle(hToken);
    return FALSE;
  }
 
  CloseHandle(hToken);
  return TRUE;
}


void printProcessNameByPid( DWORD ProcessId )
{
  HANDLE pHd;
  HMODULE pHmod;
  char ProcessName[MAX_PATH] = "unknown";
  DWORD cbNeeded;
  pHd = OpenProcess( PROCESS_QUERY_INFORMATION |PROCESS_VM_READ, FALSE, ProcessId );
  if(pHd == NULL)
    return;
 
  if(!EnumProcessModules( pHd, &pHmod, sizeof(pHmod), &cbNeeded))
    return;
  if(!GetModuleFileNameEx( pHd, pHmod, ProcessName, MAX_PATH))
    return;
 
  printf( "%d\t%s\n", ProcessId, ProcessName);
  CloseHandle( pHd );
  return;
}


int main(void)
{

  if(!AdjustProcessPrivileges(SE_DEBUG_NAME))
  {
      printf("AdjustProcessPrivileges Error!\n");
      return -1;
  }

  DWORD Pids[PROCESSNUM];
  DWORD dwProcessNum = 0;
  if(!EnumProcesses(Pids, sizeof(Pids), &dwProcessNum))
  {
      printf("EnumProcess Error!\n");
      return -1;
  }
 
  for( DWORD num = 0; num < (dwProcessNum / sizeof(DWORD)); num++)
      printProcessNameByPid(Pids[num]);

  printf("\nAll %d processes running. \n", dwProcessNum / sizeof(DWORD));

  DWORD dwPid = 0;
  printf("\n請輸入要攔截的進程id:");
  scanf("%d", &dwPid);
 
  HANDLE hTargetProcess = OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ, FALSE, dwPid);
  if(hTargetProcess == NULL)
  {
      printf("OpenProcess Error!\n");
      return -1;
  }

  DWORD dwFunAddr = (DWORD)VirtualAllocEx(hTargetProcess, NULL, 8192,
                              MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
 
  if((LPVOID)dwFunAddr == NULL)
  {
      printf("申請線程內(nèi)存失敗!\n");
      CloseHandle(hTargetProcess);
      return -1;
  }

  DWORD dwPramaAddr = (DWORD)VirtualAllocEx(hTargetProcess, NULL, sizeof(RemoteParam),
                              MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);

  if((LPVOID)dwPramaAddr == NULL)
  {
      printf("申請參數(shù)內(nèi)存失敗!\n");
      CloseHandle(hTargetProcess);
      return -1;
  }

  printf("\n線程內(nèi)存地址:%.8x\n"
        "參數(shù)內(nèi)存地址:%.8x\n",
        dwFunAddr, dwPramaAddr);
    RemoteParam RParam;
  ZeroMemory(&RParam, sizeof(RParam));
  HMODULE hKernel32 = LoadLibrary("kernel32.dll");
  HMODULE hUser32 = LoadLibrary("user32.dll");

  RParam.dwCreateFile = (DWORD)GetProcAddress(hKernel32, MYCREATEFILE);
  RParam.dwGetCurrentProcess = (DWORD)GetProcAddress(hKernel32, "GetCurrentProcess");
  RParam.dwWriteProcessMemory = (DWORD)GetProcAddress(hKernel32, "WriteProcessMemory");
  RParam.dwMessageBox = (DWORD)GetProcAddress(hUser32, MYMESSAGEBOX);
 
  unsigned char oldcode[10];
  unsigned char newcode[10];
  int praadd = (int)dwPramaAddr;
  int threadadd = (int)dwFunAddr;
  newcode[4] = praadd>>24;
  newcode[3] = (praadd<<8)>>24;
  newcode[2] = (praadd<<16)>>24;
  newcode[1] = (praadd<<24)>>24;
  newcode[0] = 0x68;
 
  int offsetaddr = threadadd - (int)RParam.dwCreateFile - 10 ;
  newcode[9] = offsetaddr>>24;
  newcode[8] = (offsetaddr<<8)>>24;
  newcode[7] = (offsetaddr<<16)>>24;
  newcode[6] = (offsetaddr<<24)>>24;
  newcode[5] = 0xE8;

  printf("NewCode:");
  for(int j = 0; j < 10; j++)
      printf("0x%.2x ",newcode[j]);
  printf("\n\n");



  if(!ReadProcessMemory(GetCurrentProcess(),
                  (LPCVOID)RParam.dwCreateFile,
                  oldcode,
                  10,
                  &dwPid))
  {
      printf("read error");
      CloseHandle(hTargetProcess);
      FreeLibrary(hKernel32);
      return -1;
  }

  strcat((char*)RParam.szOldCode, (char*)oldcode);
  RParam.FunAddr = dwFunAddr;

  printf(
        "RParam.dwCreateFile:%.8x\n"
        "RParam.dwMessageBox:%.8x\n"
        "RParam.dwGetCurrentProcess:%.8x\n"
        "RParam.dwWriteProcessMemory:%.8x\n"
        "RParam.FunAddr:%.8x\n",
        RParam.dwCreateFile,
        RParam.dwMessageBox,
        RParam.dwGetCurrentProcess,
        RParam.dwWriteProcessMemory,
        RParam.FunAddr);
  printf("RParam.szOldCode:");
  for( int i = 0; i< 10; i++)
      printf("0x%.2x ", RParam.szOldCode[i]);
  printf("\n");
 
 
  if(!WriteProcessMemory(hTargetProcess, (LPVOID)dwFunAddr, (LPVOID)&HookCreateFile, 8192, &dwPid))
  {
      printf("WriteRemoteProcessesMemory Error!\n");
      CloseHandle(hTargetProcess);
      FreeLibrary(hKernel32);
      return -1;
  }

  if(!WriteProcessMemory(hTargetProcess, (LPVOID)dwPramaAddr, (LPVOID)&RParam, sizeof(RemoteParam), &dwPid))
  {
      printf("WriteRemoteProcessesMemory Error!\n");
      CloseHandle(hTargetProcess);
      FreeLibrary(hKernel32);
      return -1;
  }
 
  if(!WriteProcessMemory(hTargetProcess, (LPVOID)RParam.dwCreateFile, (LPVOID)newcode, 10, &dwPid))
  {
      printf("WriteRemoteProcessesMemory Error!\n");
      CloseHandle(hTargetProcess);
      FreeLibrary(hKernel32);
      return -1;
  }

  printf("\nThat's all, good luck :)\n");
  CloseHandle(hTargetProcess);
  FreeLibrary(hKernel32);
  return 0;
}

posted on 2007-04-28 17:23 零宇 閱讀(641) 評論(0)  編輯 收藏 引用


只有注冊用戶登錄后才能發(fā)表評論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


導(dǎo)航

統(tǒng)計

常用鏈接

留言簿(4)

隨筆檔案(8)

文章分類(4)

文章檔案(4)

Windows Mobile 論壇

道中人

最新隨筆

搜索

積分與排名

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美视频亚洲视频| 久热精品视频| 欧美日韩亚洲综合| 久久久久国色av免费看影院| 亚洲视频在线播放| 久久精品国产亚洲高清剧情介绍| 亚洲作爱视频| 日韩视频一区二区三区| 最新热久久免费视频| 亚洲东热激情| 亚洲片区在线| 99精品国产在热久久婷婷| 免费成人激情视频| 久久精精品视频| 久久成人免费日本黄色| 久久精品1区| 一区二区三区视频免费在线观看| 亚洲精品久久久久久久久久久久久 | 久久蜜桃精品| 在线视频欧美日韩| 亚洲一区二区三区免费观看| 一本久久青青| 亚洲一区欧美一区| 亚洲欧美日本视频在线观看| 亚洲人成77777在线观看网| 欧美激情视频在线免费观看 欧美视频免费一 | 亚洲片在线观看| 99热在线精品观看| 在线观看欧美一区| 亚洲免费精品| 欧美有码视频| 欧美激情视频在线播放| 一区二区日韩免费看| 午夜欧美理论片| 久久久www成人免费精品| 欧美黄色影院| 欧美人妖另类| 亚洲欧美日本视频在线观看| 午夜久久影院| 欧美成人午夜视频| 国产精品亚洲第一区在线暖暖韩国| 欧美激情精品久久久六区热门 | 欧美va天堂| 久久国产夜色精品鲁鲁99| 欧美成年人视频网站欧美| 亚洲精品一区在线| 亚洲男人天堂2024| 你懂的亚洲视频| 国产综合视频| 欧美一区亚洲二区| 亚洲精品欧美在线| 男人的天堂亚洲| 欧美在线视频一区| 国产欧美精品va在线观看| 中日韩美女免费视频网址在线观看| 免费的成人av| 久久夜色撩人精品| 亚洲国产日韩欧美在线动漫| 久久久久久久一区二区| 性色一区二区| 韩国女主播一区二区三区| 久久高清福利视频| 午夜精品影院| 激情欧美一区二区| 老司机免费视频久久| 久久九九免费| 亚洲二区视频| 亚洲区中文字幕| 欧美美女福利视频| 亚洲欧美国内爽妇网| 亚洲一区二区三区午夜| 国产精品视区| 久久久亚洲综合| 欧美成人自拍| 亚洲午夜女主播在线直播| 一区二区三区三区在线| 国产精品日韩| 久久午夜国产精品| 你懂的网址国产 欧美| 中文欧美日韩| 欧美亚洲免费| 亚洲激情视频网站| 99国产精品视频免费观看| 国产精品美女久久福利网站| 欧美一区影院| 欧美成人精品一区二区| 亚洲美女在线观看| 午夜精品一区二区三区在线播放| 激情久久中文字幕| 日韩视频三区| 怡红院av一区二区三区| 日韩视频一区二区在线观看| 国产三级精品在线不卡| 欧美电影免费观看大全| 久久久久久9| 一区二区三区四区国产精品| 国产精品久久久久77777| 久久午夜视频| 国产精品v一区二区三区| 免费不卡中文字幕视频| 欧美日韩和欧美的一区二区| 欧美第一黄色网| 久久激情五月丁香伊人| 欧美精品福利在线| 久久婷婷麻豆| 国产九九精品视频| 亚洲国产精品免费| 韩国成人福利片在线播放| 亚洲精品视频免费观看| 在线成人国产| 亚洲午夜久久久久久尤物| 久久久久久久一区二区| 亚洲在线一区二区三区| 欧美jizz19性欧美| 免费成人在线观看视频| 国产精品久久网| 日韩午夜中文字幕| 亚洲精品视频二区| 久久久久久久久蜜桃| 久久se精品一区精品二区| 欧美精品久久天天躁| 欧美成人有码| 亚洲大胆av| 久久久青草青青国产亚洲免观| 午夜亚洲精品| 国产精品久久毛片a| 夜夜嗨av一区二区三区| 一区二区国产精品| 欧美人妖另类| 亚洲乱码国产乱码精品精天堂| 最新亚洲视频| 农村妇女精品| 亚洲国产岛国毛片在线| 精品av久久久久电影| 午夜亚洲视频| 欧美与黑人午夜性猛交久久久| 欧美日韩视频免费播放| 亚洲欧洲在线一区| 亚洲美女免费精品视频在线观看| 鲁大师成人一区二区三区| 欧美α欧美αv大片| 亚洲激情国产| 欧美日韩黄视频| 亚洲深夜影院| 久久aⅴ国产欧美74aaa| 国自产拍偷拍福利精品免费一| 久久国产欧美日韩精品| 久久免费视频网站| 最新国产の精品合集bt伙计| 欧美激情按摩在线| 一本色道88久久加勒比精品 | 久久婷婷国产综合精品青草| 红桃视频国产精品| 欧美顶级大胆免费视频| 日韩亚洲欧美综合| 亚洲一区二区视频| 国产嫩草一区二区三区在线观看| 欧美一区二区精品在线| 欧美a级片网站| 在线午夜精品| 国产一区三区三区| 久久精品国产第一区二区三区最新章节 | 欧美日韩亚洲一区三区 | 亚洲国产视频一区二区| 欧美日本乱大交xxxxx| 亚洲综合欧美| 韩国精品久久久999| 免费观看一区| 亚洲一区中文| 亚洲国产精品成人综合色在线婷婷| 在线一区视频| 亚洲高清在线精品| 欧美视频在线观看| 久久这里只精品最新地址| 一区二区三区视频免费在线观看| 久久一区二区精品| 这里只有视频精品| 一区二区自拍| 国产精品青草久久| 欧美另类高清视频在线| 欧美一区二区三区四区高清| 99国产精品视频免费观看一公开| 久久av红桃一区二区小说| 99re视频这里只有精品| 黄色亚洲大片免费在线观看| 欧美日韩在线视频一区二区| 老鸭窝91久久精品色噜噜导演| 亚洲综合二区| 一卡二卡3卡四卡高清精品视频| 免费日韩视频| 久久久久久久性| 亚洲综合三区| 9色porny自拍视频一区二区| 在线成人黄色| 国产日韩精品电影| 国产精品v日韩精品v欧美精品网站 | 欧美在线一区二区| 99视频精品免费观看| 亚洲黄色视屏| 亚洲成色777777女色窝|