【 tulaoshi.com - 编程语言 】
                             
                              花了一个下午翻了MSDN,写了这个例子,为了安全,我用Delphi建了个什么也没有作的程序prjzzhost.exe,将它用作被注入的宿主进程.
  写了一个TestDll.Dll,里面只有一个Log函数,用来在文件Test.Txt中输出信息.最重要的一个程序project1.exe是用来注入的.
  测试环境: windows server 2003 + delphi 7.0
  程序很简单,高手就不用看了.废话不说了,看代码吧!
  
  测试用的TestDll.Dll源代码(它将被注入到prjzzhost.exe中去):
  

 程序代码
  library TestDll;  
  uses
    SysUtils,
    System,
    windows,
    Classes;  
    procedure Log( s : PChar);stdcall;
    var
      F : TextFile;
    begin
      assignfile(f,'Test.txt');
      if fileexists('Test.txt') then append(f)
      else rewrite(f);
      writeln(f,s);
      closefile(f);
    end;  
    procedure DllEntryPoint(dwReason:DWord);
    begin
        case dwReason of
        DLL_PROCESS_ATTACH:
          Log('dll process Attach');
        DLL_PROCESS_DETACH:
        Log('dll process Detach');
        DLL_THREAD_ATTACH:
          Log('dll thread Attach');
        DLL_THREAD_DETACH:
          Log('dll thread Detach');
        end;  
    end;  
    exports
      Log;  
  begin
    DllProc := @DllEntryPoint;
    DllEntryPoint(DLL_PROCESS_ATTACH);
  end.  
  
  
  
  被注入的宿主进程prjzzhost.exe(它什么也没有作,好无辜哦:),这里就不给出代码了,因为太简单了,哈哈.
  
  
  最后,最重要的来了:
  project1.exe的源代码:
  
(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)
 程序代码
  unit Unit1;  
  interface  
  uses
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
    Dialogs, StdCtrls,tlhelp32;  
  type  
    TLog = procedure(s : PChar);stdcall;
    TServiceMain = procedure(argc : Integer; VAR argv : pchar);stdcall;  
    EDLLLoadError = class(Exception);  
    TForm1 = class(TForm)
      Button3: TButton;
      procedure Button3Click(Sender: TObject);
    private
      { Private declarations }
    public
      { Public declarations }
    end;    
  var
    Form1: TForm1;  
  implementation  
  {$R *.dfm}  
  { 列举进程 }
  procedure GetMyProcessID(const AFilename: string; const PathMatch: Boolean; var ProcessID: 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);
    while FoundAProc do
    begin
      { 进行匹配 }
      if PathMatch then
        FoundOK := AnsiStricomp(lppe.szExefile, PChar(AFilename)) = 0
      else
        FoundOK := AnsiStricomp(PChar(ExtractFilename(lppe.szExefile)), PChar(ExtractFilename(AFilename))) = 0;
      if FoundOK then
      begin
        ProcessID := lppe.th32ProcessID;
        break;
      end;
      { 未找到,继续下一个进程 }
      FoundAProc := Process32Next(SsHandle, lppe);
    end;
    CloseHandle(SsHandle);
  end;    
  { 设置权限 }
  function EnabledDebugPrivilege(const Enabled : 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);  
      if Enabled then
        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;    
  { 调试函数 }
  procedure OutPutText(var CH:PChar);
  var
    FileHandle: TextFile;
  Begin
    AssignFile(FileHandle,'zztest.txt');
    Append(FileHandle);
    Writeln(FileHandle,CH);
    Flush(FileHandle);
    CloseFile(FileHandle);
  END;  
  { 注入远程进程 }
  function InjectTo(const Host, Guest: string; const PID: 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 }
    if PID  0 then
       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);  
    if iReturnCode then
    begin
      pfnStartAddr := GetProcAddress(GetModuleHandle('Kernel32'), 'LoadLibraryW');
      TempVar := 0;
      { 在远程进程中启动dll }
      Result := CreateRemoteThread(hRemoteProcess, nil, 0, pfnStartAddr, pszLibFileRemote, 0, TempVar);
    end;  
    { 释放内存空间 }
    Freemem(pszLibAFilename);
  end;  
    { 测试 }
  procedure TForm1.Button3Click(Sender: TObject);
  begin  
    InjectTo('prjzzhost.exe', extractfilepath(paramstr(0))+'TestDll.dll');
  end;  
  end.  
  
  
  
  代码中并没有考虑dll被载入后的善后处理,请不要使用系统进程进行测试,以免发生意外.
  
(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)