花了一個下午翻了MSDN,寫了這個例子,為了安全,我用Delphi建了個什麼也沒有作的程序PRjzzhost.exe,將它用作被注入的宿主進程.
寫了一個TestDll.Dll,裡面只有一個Log函數,用來在文件Test.Txt中輸出信息.最重要的一個程序project1.exe是用來注入的.
測試環境:windowsserver2003+delphi7.0
程序很簡單,高手就不用看了.廢話不說了,看代碼吧!
測試用的TestDll.Dll源代碼(它將被注入到prjzzhost.exe中去):
程序代碼libraryTestDll;
uses
SysUtils,
System,
windows,
Classes;
procedureLog(s:PChar);stdcall;
var
F:TextFile;
begin
assignfile(f,'Test.txt');
iffileexists('Test.txt')thenappend(f)
elserewrite(f);
writeln(f,s);
closefile(f);
end;
procedureDllEntryPoint(dwReason:DWord);
begin
casedwReasonof
DLL_PROCESS_ATTACH:
Log('dllprocessAttach');
DLL_PROCESS_DETACH:
Log('dllprocessDetach');
DLL_THREAD_ATTACH:
Log('dllthreadAttach');
DLL_THREAD_DETACH:
Log('dllthreadDetach');
end;
end;
exports
Log;
begin
DllProc:=@DllEntryPoint;
DllEntryPoint(DLL_PROCESS_ATTACH);
end.
被注入的宿主進程prjzzhost.exe(它什麼也沒有作,好無辜哦:),這裡就不給出代碼了,因為太簡單了,哈哈.
最後,最重要的來了:
project1.exe的源代碼:
程序代碼unitUnit1;
interface
uses
Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,
Dialogs,StdCtrls,tlhelp32;
type
TLog=procedure(s:PChar);stdcall;
TServiceMain=procedure(argc:Integer;VARargv:pchar);stdcall;
EDLLLoadError=class(Exception);
TForm1=class(TForm)
Button3:TButton;
procedureButton3Click(Sender:TObject);
private
{Privatedeclarations}
public
{Publicdeclarations}
end;
var
Form1:TForm1;
implementation
{$R*.dfm}
{列舉進程}
procedureGetMyProcessID(constAFilename:string;constPathMatch:Boolean;varProcessID:DWORD);
var
lppe:TProcessEntry32;
SsHandle:Thandle;
FoundAProc,FoundOK:boolean;
begin
ProcessID:=0;
{創建系統快照}
SsHandle:=CreateToolHelp32SnapShot(TH32CS_SnapProcess,0);
{取得快照中的第一個進程}
{一定要設置結構的大小,否則將返回False}
lppe.dwSize:=sizeof(TProcessEntry32);
FoundAProc:=Process32First(Sshandle,lppe);
whileFoundAProcdo
begin
{進行匹配}
ifPathMatchthen
FoundOK:=AnsiStricomp(lppe.szExefile,PChar(AFilename))=0
else
FoundOK:=AnsiStricomp(PChar(ExtractFilename(lppe.szExefile)),PChar(ExtractFilename(AFilename)))=0;
ifFoundOKthen
begin
ProcessID:=lppe.th32ProcessID;
break;
end;
{未找到,繼續下一個進程}
FoundAProc:=Process32Next(SsHandle,lppe);
end;
CloseHandle(SsHandle);
end;
{設置權限}
functionEnabledDebugPrivilege(constEnabled:Boolean):Boolean;
var
hTk:THandle;{打開令牌句柄}
rtnTemp:Dword;{調整權限時返回的值}
TokenPri:TOKEN_PRIVILEGES;
const
SE_DEBUG='SeDebugPrivilege';{查詢值}
begin
Result:=False;
{獲取進程令牌句柄,設置權限}
if(OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,hTk))then
begin
TokenPri.PrivilegeCount:=1;
{獲取Luid值}
LookupPrivilegeValue(nil,SE_DEBUG,TokenPri.Privileges[0].Luid);
ifEnabledthen
TokenPri.Privileges[0].Attributes:=SE_PRIVILEGE_ENABLED
else
TokenPri.Privileges[0].Attributes:=0;
rtnTemp:=0;
{設置新的權限}
AdjustTokenPrivileges(hTk,False,TokenPri,sizeof(TokenPri),nil,rtnTemp);
Result:=GetLastError=ERROR_SUCCESS;
CloseHandle(hTk);
end;
end;
{調試函數}
procedureOutPutText(varCH:PChar);
var
FileHandle:TextFile;
Begin
AssignFile(FileHandle,'zztest.txt');
Append(FileHandle);
Writeln(FileHandle,CH);
Flush(FileHandle);
CloseFile(FileHandle);
END;
{注入遠程進程}
functionInjectTo(constHost,Guest:string;constPID:DWORD=0):DWORD;
var
{被注入的進程句柄,進程ID}
hRemoteProcess:THandle;
dwRemoteProcessId:DWORD;
{寫入遠程進程的內容大小}
memSize:DWORD;
{寫入到遠程進程後的地址}
pszLibFileRemote:Pointer;
iReturnCode:Boolean;
TempVar:DWORD;
{指向函數LoadLibraryW的地址}
pfnStartAddr:TFNThreadStartRoutine;
{dll全路徑,需要寫到遠程進程的內存中去}
pszLibAFilename:PwideChar;
begin
Result:=0;
{設置權限}
EnabledDebugPrivilege(True);
{為註入的dll文件路徑分配內存大小,由於為WideChar,故要乘2}
Getmem(pszLibAFilename,Length(Guest)*2+1);
StringToWideChar(Guest,pszLibAFilename,Length(Guest)*2+1);
{獲取進程ID}
ifPID>0then
dwRemoteProcessID:=PID
else
GetMyProcessID(Host,False,dwRemoteProcessID);
{取得遠程進程句柄,具有寫入權限}
hRemoteProcess:=OpenProcess(PROCESS_CREATE_THREAD+{允許遠程創建線程}
PROCESS_VM_OperaTION+{允許遠程VM操作}
PROCESS_VM_WRITE,{允許遠程VM寫}
FALSE,dwRemoteProcessId);
{用函數VirtualAllocex在遠程進程分配空間,並用WriteProcessMemory中寫入dll路徑}
memSize:=(1+lstrlenW(pszLibAFilename))*sizeof(WCHAR);
pszLibFileRemote:=PWIDESTRING(VirtualAllocEx(hRemoteProcess,nil,memSize,MEM_COMMIT,PAGE_READWRITE));
TempVar:=0;
iReturnCode:=WriteProcessMemory(hRemoteProcess,pszLibFileRemote,pszLibAFilename,memSize,TempVar);
ifiReturnCodethen
begin
pfnStartAddr:=GetProcAddress(GetModuleHandle('Kernel32'),'LoadLibraryW');
TempVar:=0;
{在遠程進程中啟動dll}
Result:=CreateRemoteThread(hRemoteProcess,nil,0,pfnStartAddr,pszLibFileRemote,0,TempVar);
end;
{釋放內存空間}
Freemem(pszLibAFilename);
end;
{測試}
procedureTForm1.Button3Click(Sender:TObject);
begin
InjectTo('prjzzhost.exe',extractfilepath(paramstr(0))+'TestDll.dll');
end;
end.
代碼中並沒有考慮dll被載入後的善後處理,請不要使用系統進程進行測試,以免發生意外.