使用遠程線程製作不死進程

遠程線程指把當前進程部分代碼注入到其他進程做爲線程執行,雖然鉤子程序能掛鉤其他程序的消息,但鉤子程序退出,注入的dll也就退出了,而遠程線程不會 隨着本地進程退出而結束。而且可以處理更多的事情,而不侷限於消息。由於98不支持所以只能在nt內核上運行,下面是製作遠程線程需要使用的api。
獲取進程句柄方法之一是使用GetWindowThreadProcessId函數,這個函數可以從一個窗口句柄獲得創建窗口進程的id,而獲得一個窗口句柄可以用FindWindow輕易得到。
HWND FindWindow(LPCTSTR lpClassName, LPCTSTR lpWindowName);
lpClassName, // 窗口類名稱,可以指定爲NULL,光指定窗口名稱即可
lpWindowName // 窗口名稱。
如果兩個參數都爲0,則獲得最頂層窗口的句柄。
DWORD GetWindowThreadProcessId(HWND hWnd,LPDWORD lpdwProcessId);
Hwnd 進程擁有的窗口句柄
LpdwProcessID 指向用來存放進程ID的變量
得到進程ID 之後,可以使用 OpenProcess函數來獲得進程句柄
HANDLE OpenProcess(DWORD dwDesiredAccess,BOOL bInheritHandle,DWORD dwProcessId);
DwDesiredAccess,對打開的進程的訪問權限,可以是下列值的組合:
PROCESS_ALL_ACCESS--------------------等於下面所有權限的組合
PROCESS_CREATE_THREAD-----------------允許創建遠程線程
PROCESS_DUP_HANDLE--------------------允許進程句柄被複制
PROCESS_QUERY_INFORMATION-------------允許使用GetExitCodeProcess函數查詢和GetProrityClass 查詢進程信息
PROCESS_SET_INFORMATION---------------允許使用SetPriorityClass函數設置進程的優先級
PROCESS_TERMINATE----------------------允許結束進程
PROCESS_VM_OPERATION-------------------允許使用WriteProcessMemory函數或者VirtualProtectEx來修改進程的地址空間
PROCESS_VM_READ------------------------允許對讀取進程地址空間
PROCESS_VM_WRITE-----------------------允許使用寫入進程地址空間
BInheritHandle參數,指定返回的進程句柄是否可以被當前進程的子進程繼承
DwProcessId 參數指定目標進程的進程ID

還有一種方法是使用CreateToolhelp32Snapshot(快照)函數來獲得進程句柄,上面的方法進程必須要有窗口,而快照函數不需要進程擁有窗口,暫不介紹

下面是讀寫進程數據的兩個api函數:
BOOL ReadProcessMemory(
HANDLE hProcess, // 進程句柄
LPCVOID lpBaseAddress, // 要讀取的目標進程起始內存
LPVOID lpBuffer, // 本地進程用來存放讀取內容的數據緩衝區
SIZE_T nSize, // 要從目標進程讀取得數據長度
SIZE_T * lpNumberOfBytesRead // 要讀出的到本地的數量,爲NULL則忽略這個參數

BOOL WriteProcessMemory(
HANDLE hProcess, // handle to process
LPVOID lpBaseAddress, // base of memory area
LPVOID lpBuffer, // data buffer
SIZE_T nSize, // count of bytes to write
SIZE_T * lpNumberOfBytesWritten // count of bytes written
);

要注入遠程線程,必須要在目標進程中開闢一段空間,來存放遠程線程代碼。
LPVOID VirtualAllocEx(
HANDLE hProcess, // 要開闢內存的進程
LPVOID lpAddress, // 從進程那個地址開始分配,爲NULL,則系統決定
SIZE_T dwSize, // 要分配的空間大小
DWORD flAllocationType, // 分配的類型,一般用 MEM_COMMIT即可
DWORD flProtect // 這段內存訪問的權限,PAGE_EXECUTE_READWRITE,遠程線程所處空間必須可讀可執行
);

下面是注入遠程線程的需要使用的函數:
HANDLE CreateRemoteThread(
HANDLE hProcess, // 要寫入遠程線程進程句柄
LPSECURITY_ATTRIBUTES lpThreadAttributes, // 線程安全屬性
DWORD dwStackSize, // 初始化堆棧大小
LPTHREAD_START_ROUTINE lpStartAddress, // 遠程線程函數
LPVOID lpParameter, // 遠程線程參數
DWORD dwCreationFlags, // 標誌,可以創建掛起的線程等等
LPDWORD lpThreadId // 用來返回線程ID的指針
);
代碼重定位
有 了這些函數就可以把一段代碼插入到目標進程,這段代碼將作爲目標進程中一個獨立的線程運行。但是代碼編譯時,全局變量、Api函數等等,將被編譯爲地址形 式,這是地址對於本地進程是可讀可執行的,對於目標進程,讀取這些地址是非法的,windows這樣做,可以保證每個進程都擁有自己獨立的4GB空間,而 不互相干擾(處於ring3的進程互相訪問是非法的)。對於所有的高級語言,包括C語言,根本不能解決重定位問題,程序只能先寫一個dll文件,然後用 CreateRemoteThread 把LoadLibrary 函數注入到目標進程中。LoadLibrary 函數調用dll 文件,執行自己想要的功能,不過這樣用一些進程工具可以看到目標進程多了一個dll。重定位是彙編語言的拿手好戲。
Call @F
@@:
pop ebx
sub ebx,offset @B
現在 ebx 即得到了代碼的實際地址和彙編地址之間的偏差,所以在需要重定位的代碼上加上這個偏移值即可。

遠程線程小例子
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;使用遠程線程注入到explorer中,避免出現在win2k任務管理器中,並實現看護win2k進程,發現進程退出
;馬上啓動同樣的另一個進程
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 使用 nmake 或下列命令進行編譯和鏈接:
; ml /c /coff RemoteThread.asm
; rc RemoteThread.rc
; Link /subsystem:windows RemoteThread.obj RemoteThread.res
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.386
.model flat,stdcall
option casemap:none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include /masm32/include/windows.inc
include /masm32/include/user32.inc
include /masm32/include/kernel32.inc
includelib /masm32/lib/user32.lib
includelib /masm32/lib/kernel32.lib
include macro.inc
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
KnlOpenProcessStr db 'OpenProcess',0
KnlWaitForObjectStr db 'WaitForSingleObject',0
KnlWinExecStr db 'WinExec',0
KnlGetModuleHandleStr db 'GetModuleHandleA',0
KnlGetProcAddressStr db 'GetProcAddress',0
FileName db 'nodead.exe',0
szDllKernel db 'Kernel32.dll',0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;下面兩個變量是explorer.exe 進程窗口的類名(RegisterClassA參數中設定的)和進程標題名字
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
szDesktopClass db 'Progman',0
szDesktopWindow db 'Program Manager',0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data?
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
KnlOpenProcess dd ?
KnlWaitForSingleObject dd ?
KnlWinExec dd ?
KnlGetModuleHandle dd ?
KnlGetProcAddress dd ?
dwProcessID dd ?
dwThreadID dd ?
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include RemoteCode.asm
Start:
invoke GetModuleHandle,addr szDllKernel
mov ebx,eax
invoke GetProcAddress,ebx,offset KnlOpenProcessStr
mov KnlOpenProcess,eax
invoke GetProcAddress,ebx,offset KnlWaitForObjectStr
mov KnlWaitForSingleObject,eax
invoke GetProcAddress,ebx,offset KnlWinExecStr
mov KnlWinExec,eax
invoke GetProcAddress,ebx,offset KnlGetProcAddressStr
mov KnlGetProcAddress,eax
invoke GetProcAddress,ebx,offset KnlGetModuleHandleStr
mov KnlGetModuleHandle,eax

invoke FindWindow,addr szDesktopClass,addr szDesktopWindow
invoke GetWindowThreadProcessId,eax,offset dwProcessID
mov dwThreadID,eax
invoke OpenProcess,PROCESS_ALL_ACCESS,FALSE,dwProcessID
test eax,eax
jz OpenProcessError
mov ebx,eax
invoke VirtualAllocEx,ebx,NULL,REMOTE_CODE_LENGTH,MEM_COMMIT,PAGE_EXECUTE_READWRITE
or eax,eax
jz OpenProcessError
mov edi,eax
push eax
invoke WriteProcessMemory,ebx,edi,offset REMOTE_CODE_START,REMOTE_CODE_LENGTH,NULL
invoke WriteProcessMemory,ebx,edi,offset KnlOpenProcess,sizeof dword * 5,NULL
add edi,offset Protect2kProc - offset REMOTE_CODE_START
invoke CreateRemoteThread,ebx,NULL,0,edi,0,0,NULL
invoke CloseHandle,ebx
invoke Sleep,100h
invoke MessageBoxA,0,offset FileName,offset FileName,0
OpenProcessError:
invoke ExitProcess,0
end Start
macro.inc
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 將參數列表的順序翻轉
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
reverseArgs macro arglist:VARARG
local txt,count

txt TEXTEQU <>
count = 0
for i,
count = count + 1
txt TEXTEQU @CatStr(i,,<%txt>)
endm
if count GT 0
txt SUBSTR txt,1,@SizeStr(%txt)-1
endif
exitm txt
endm
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 建立一個類似於 invoke 的 Macro
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_invoke macro _Proc,args:VARARG
local count

count = 0
% for i,< reverseArgs( args ) >
count = count + 1
push i
endm
call dword ptr _Proc

endm

RemoteThread.asm
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 注入遠程進程執行的代碼
;equ this [:類型],則變量包含的段和偏移地址都和下一句相同,類型指變量類型
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
REMOTE_CODE_START equ this byte
_KnlOpenProcess dd ?
_KnlWaitForSingleObject dd ?
_KnlWinExec dd ?
_KnlGetModuleHandle dd ?
_KnlGetProcAddress dd ?

_KnlSleep dd ?
_Error2 db 'overflow2',0;循環把這個字符串覆蓋了?
_FileName db 'c:/wap32.exe',0; 要看護的進程路徑
_WinName db 'Our First Dialog Box',0;要看護的進程窗口名字
_hInstance dd ?
_KnlFindWindow dd ?
_KnlMessageBox dd ?
_ErrorMsg db 'overflow',0 ;循環把這個字符串覆蓋了?
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 要從User32 中提取使用的api函數名稱
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_szDllUser db 'user32.dll',0
_szDllKernel db 'kernel32.dll',0
szFindWindow db 'FindWindowA',0
szMessageBox db 'MessageBoxA',0,0 ;多一個0用於結束循環

szSleep db 'Sleep',0,0

Protect2kProc proc uses ebx edi esi
local hModuleUser
local hModuleKernel
call @F
@@:
pop ebx
sub ebx,offset @B
_invoke [ebx+ _KnlGetModuleHandle],NULL
test eax,eax
jz ExitProtectProc
mov [ebx+ _hInstance],eax
lea eax,[ebx+ offset _szDllUser]
_invoke [ebx+_KnlGetModuleHandle],eax
mov hModuleUser,eax
lea esi,[ebx+offset szFindWindow]
lea edi,[ebx+offset _KnlFindWindow]
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 從User32.dll中取api函數地址的循環
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.while TRUE
_invoke [ebx+_KnlGetProcAddress],hModuleUser,esi
mov [edi],eax
add edi,4
@@:
lodsb
or al,al
jnz @B
.break .if ! byte ptr [esi+1]
.endw
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 從Kernel32.dll中取api函數地址的循環
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
lea eax,[ebx+ offset _szDllKernel]
_invoke [ebx+_KnlGetModuleHandle],eax
mov hModuleKernel,eax
lea esi,[ebx+offset szSleep]
lea edi,[ebx+offset _KnlSleep]
.while TRUE
_invoke [ebx+_KnlGetProcAddress],hModuleKernel,esi
mov [edi],eax
add edi,4
@@:
lodsb
or al,al
jnz @B
.break .if ! byte ptr [esi+1]
.endw
call _WinMain
ExitProtectProc:
ret
Protect2kProc endp

_WinMain proc uses ebx esi edi
call @F
@@:
pop ebx
sub ebx,@B
lea edi,[ebx+ offset _ErrorMsg]
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 看護循環,發現進程退出馬上重啓一個
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.while TRUE
lea esi,[ebx+offset _WinName]
_invoke [ebx+_KnlFindWindow],NULL,esi
.if ! eax
lea esi,[ebx+ offset _FileName]
_invoke [ebx+_KnlWinExec],esi,SW_SHOWNORMAL
.endif
_invoke [ebx+_KnlSleep],110h
.endw
ret
_WinMain endp

REMOTE_CODE_END equ this byte
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;REMOTE_CODE_LENGTH 獲取整個插入代碼的長度,在nodead.asm中,VirtualAllocEx 中制定遠程線程
;長度可以使用此參數
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
REMOTE_CODE_LENGTH equ offset REMOTE_CODE_END - offset REMOTE_CODE_START
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章