DLL注入

作者在 2010-10-05 18:15:53 发布以下内容
演示工程下载:http://down.bccn.net/472.html

{总体流程:
利用CreateToolhelp32Snapshot函数创建一个进程快照,然后利用Process32First函数和
Process32Next函数遍历出所有进程ID等信息,保存到ListView控件中。当获取到进程ID后
交给OpenProcess函数使用打开一个进程,从而获取一个进程句柄,当获取进程句柄后则交
给VirtualAllocEx和WriteProcessMemory函数使用,从而进行虚拟内存分配和写入。然后
则利用GetProcAddress函数和GetModuleHandle函数获取定的动态链接库'kernel32.dll'中
的'LoadLibraryA'函数地址。然后把这个地址交给CreateRemoteThread函数使用。最后用
WaitForSingleObject、VirtualFreeEx、CloseHandle清楚现场。
}

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, TLHelp32, ComCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    ListView1: TListView;
    Button2: TButton;
    Button3: TButton;
    OpenDialog1: TOpenDialog;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure ListView1SelectItem(Sender: TObject; Item: TListItem;
      Selected: Boolean);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  hProcess:THandle;
  Procedure GetProcess();
  function LoadLibraryA(lpLibFileName: PAnsiChar): HMODULE; stdcall;
  external kernel32 name 'LoadLibraryA';
implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);begin
    GetProcess;
end;

Procedure GetProcess();
var
  hSnapshot:THandle;
  pe32:TProcessEntry32;
  item:TListItem;
  count:Integer;
begin
    count:=1;
    hSnapshot:=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
    if hSnapshot=0 then begin
        Form1.Caption:='创建进程快照失败!';
        Abort();
    end else begin
        Form1.Caption:='创建进程快照成功!';
    end;
    pe32.dwSize:=SizeOf(PROCESSENTRY32);
    if not Process32First(hSnapshot,pe32) then begin
        Form1.Caption:='获取第'+IntToStr(count)+'个进程失败!';
    end else begin
        Form1.Caption:='获取第'+IntToStr(count)+'个进程成功!';
    end;
    Form1.ListView1.Clear;
    repeat
         count:=count+1;
         Form1.Caption:='获取第'+IntToStr(count)+'个进程成功!';
         item:=Form1.ListView1.Items.Add;
         item.Caption:=IntToStr(pe32.th32ProcessID);
         item.SubItems.Add(pe32.szExeFile);
         item.SubItems.Add(IntToStr(pe32.pcPriClassBase));
         item.SubItems.Add(IntToStr(pe32.th32ParentProcessID));
    until not Process32Next(hSnapshot,pe32);
    Form1.Caption:='成功获取'+IntToStr(count)+'个进程!';
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
    ShowMessage('程序名称:DLL注入'+#13+
                '版本:1.0.0.0'+#13+
                '日期:2010-10-5'+#13+
                '作者:江湖一键客'+#13+
                '业务联系QQ:82530662');
end;

procedure TForm1.Button3Click(Sender: TObject);

var
    lpBaseAddress:Pointer;
    flProtect: DWORD;
    lNOBW: DWORD;
    fileName:String;
    len:Integer;
    wFlag:Bool;
    pLoadLibrary:FARPROC;
    lpThreadId:DWORD;
    hThread:THandle;
begin
    if OpenDialog1.Execute then begin
       fileName:=OpenDialog1.FileName;
       len:=Length(fileName)+1;
    end else begin
       Abort();
    end;
    lpBaseAddress:=VirtualAllocEx(hProcess,nil,Len,MEM_COMMIT,PAGE_READWRITE);
    if lpBaseAddress=nil then begin
       Form1.Caption:='分配虚拟内存失败!';
       Abort();
    end;
    Form1.Caption:='分配虚拟内存成功';
    wFlag:=WriteProcessMemory(hProcess,lpBaseAddress,pchar(@fileName[1]),len,lNOBW);
    if (not wFlag) and (lNOBW<>len) then begin
       Form1.Caption:='写入内存失败!';
       VirtualFreeEx(hProcess, lpBaseAddress,len,MEM_COMMIT);
       CloseHandle(hProcess);
       Abort();
    end;
    Form1.Caption:='写入内存成功!';
    pLoadLibrary:=GetProcAddress(GetModuleHandle('kernel32.dll'),'LoadLibraryA');
    if pLoadLibrary=nil then begin
       Form1.Caption:='获取输出库函数地址失败!';
       Abort();
    end;
    Form1.Caption:='获取输出库函数地址成功!';
    hThread:=CreateRemoteThread(hProcess,nil,0,pLoadLibrary,
                                lpBaseAddress,0,lpThreadId);
    if hThread=0 then begin
       Form1.Caption:='创建远程线程失败!';
    end;
    Form1.Caption:='创建远程线程成功!';
    WaitForSingleObject(hThread,INFINITE);
    VirtualFreeEx(hProcess, lpBaseAddress,len,MEM_COMMIT);
    CloseHandle(hThread);
    CloseHandle(hProcess);
end;

procedure TForm1.ListView1SelectItem(Sender: TObject; Item: TListItem;
  Selected: Boolean);
var
    dwProcessId:DWORD;
begin
      dwProcessId:=StrToInt(Trim(item.Caption));
      hProcess:=OpenProcess(PROCESS_ALL_ACCESS ,False, dwProcessId);
      if hProcess=0 then begin
          Form1.Caption:='打开进程失败!';
          CloseHandle(hProcess);
          Abort();
      end;
      Form1.Caption:='打开进程成功!';
end;

end.

{下面是所用到的函数的详细说明:}

{function VirtualAllocEx(hProcess: THandle; lpAddress: Pointer;
                      dwSize, flAllocationType: DWORD; flProtect: DWORD):
                      Pointer; stdcall;
}
{VirtualAllocEx 函数的作用是在指定进程的虚拟空间保留或提交内存区域,           }
{               除非指定MEM_RESET参数,否则将该内存区域置0。                   }
{参数说明:                                                                     }
{hProcess: 申请内存所在的进程句柄。                                            }
{lpAddress:保留页面的内存地址;一般用nil自动分配 。                            }
{dwSize:欲分配的内存大小,字节单位;注意实际分 配的内存大小是页内存大小的整数倍}
{flAllocationType:可取下面表1的值                                              }
{flProtect:       可取下面表2的值                                              }

{表1:}
{MEM_COMMIT:     为特定的页面区域分配内存中或磁盘的页面文件中的物理存储       }
{MEM_PHYSICAL :  分配物理内存(仅用于地址窗口扩展内存)                       }
{MEM_RESERVE:    保留进程的虚拟地址空间,而不分配任何物理存储。               }
{                 保留页面可通过继续调用VirtualAlloc()而被占用               }
{MEM_RESET :     指明在内存中由参数lpAddress和dwSize指定的数据无效            }
{MEM_TOP_DOWN:   在尽可能高的地址上分配内存(Windows 98忽略此标志)           }
{MEM_WRITE_WATCH:必须与MEM_RESERVE一起指定,使系统跟踪那些被写入              }
{                 分配区域的页面(仅针对Windows 98)                           }

{表2:}
{PAGE_READONLY: 该区域为只读。如果应用程序试图访问区域中的页的时候,      }
{                将会被拒绝访问PAGE_READWRITE 区域可被应用程序读写        }
{PAGE_EXECUTE:  区域包含可被系统执行的代码。试图读写该区域的操作将被拒绝。}
{PAGE_EXECUTE_READ :     区域包含可执行代码,应用程序可以读该区域。       }
{PAGE_EXECUTE_READWRITE: 区域包含可执行代码,应用程序可以读写该区域。     }
{PAGE_GUARD: 区域第一次被访问时进入一个STATUS_GUARD_PAGE异常,            }
{             这个标志要和其他保护标志合并使用,表明区域被第一次访问的权限 }
{PAGE_NOACCESS: 任何访问该区域的操作将被拒绝                            }
{PAGE_NOCACHE:  RAM中的页映射到该区域时将不会被微处理器缓存(cached)       }

{********************************优伤的分隔线******************************}

{function OpenProcess(dwDesiredAccess: DWORD; bInheritHandle: BOOL;
dwProcessId: DWORD): THandle; stdcall;
}
{OpenProcess 函数用来打开一个已存在的进程对象,并返回进程的句柄。}
{参数说明:}
{dwDesiredAccess是访问进程的权限。见下面表3}
{bInheritHandle 是句柄是否继承进程属性。   }
{dwProcessId    是进程ID。               }

{表3}
{PROCESS_ALL_ACCESS        所有能获得的权限                          }
{PROCESS_CREATE_PROCESS    需要创建一个进程                          }
{PROCESS_CREATE_THREAD     需要创建一个线程                          }
{PROCESS_DUP_HANDLE        重复使用DuplicateHandle句柄               }
{PROCESS_QUERY_INFORMATION 获得进程信息的权限,如它的退出代码、优先级}
{PROCESS_QUERY_LIMITED_INFORMATION    获得某些信息的权限,如果获得了 }
{                                     PROCESS_QUERY_INFORMATION,    }
{也拥有PROCESS_QUERY_LIMITED_INFORMATION权限                         }
{PROCESS_SET_INFORMATION   设置某些信息的权限,如进程优先级69        }
{PROCESS_SET_QUOTA         设置内存限制的权限,
                           使用SetProcessWorkingSetSize              
}
{PROCESS_SUSPEND_RESUME    暂停或恢复进程的权限                      }
{PROCESS_TERMINATE         终止一个进程的权限,使用TerminateProcess  }
{PROCESS_VM_OPERATION      操作进程内存空间的权限
                           (可用VirtualProtectEx和WriteProcessMemory)
}
{PROCESS_VM_READ           读取进程内存空间的权限,可使用ReadProcessMemory }
{PROCESS_VM_WRITE          读取进程内存空间的权限,可使用WriteProcessMemory}
{SYNCHRONIZE               等待进程终止                                    }

{********************************性感的分隔线******************************}

{function CreateToolhelp32Snapshot(dwFlags, th32ProcessID: DWORD): THandle;  }
{CreateToolhelp32Snapshot函数功能:函数为指定的进程、进程使用的堆[HEAP]、     }
{模块[MODULE]、线程[THREAD])建立一个快照[snapshot]。                        }
{参数1说明:dwFlags                                                           }
{TH32CS_INHERIT        声明快照句柄是可继承的。                              }
{TH32CS_SNAPALL        在快照中包含系统中所有的进程和线程。                  }
{TH32CS_SNAPHEAPLIST   在快照中包含在th32ProcessID中指定的进程的所有的堆。   }
{TH32CS_SNAPMODULE     在快照中包含在th32ProcessID中指定的进程的所有的模块。 }
{TH32CS_SNAPPROCESS    在快照中包含系统中所有的进程。                        }
{TH32CS_SNAPTHREAD     在快照中包含系统中所有的线程。                        }
{参数2说明:th32ProcessID                                                     }
{指定将要快照的进程ID。如果该参数为0表示快照当前进程。该参数只有在设置了     }
{TH32CS_SNAPHEAPLIST或者TH32CS_SNAPMODULE后才有效,在其他情况下该参数被忽略,}
{所有的进程都会被快照。                                                      }
{返回值:                                                                    }
{调用成功,返回快照的句柄,调用失败,返回0。                                 }

{********************************优美的分隔线******************************}

{PROCESSENTRY32结构}
{tagPROCESSENTRY32 = packed record
  dwSize: DWORD;              结构的大小
  cntUsage: DWORD;            此进程的引用计数
  th32ProcessID: DWORD;       进程ID
  th32DefaultHeapID: DWORD;   进程默认堆
  th32ModuleID: DWORD;        进程模块IDThis
  cntThreads: DWORD;          此进程开启的线程计数
  th32ParentProcessID: DWORD; 父进程的ID
  pcPriClassBase: Longint;    线程优先权
  dwFlags: DWORD;
  szExeFile: array[0..MAX_PATH - 1] of Char; 进程全名
end;
}

{********************************优美的分隔线******************************}

{function Process32First(hSnapshot: THandle; var lppe: TProcessEntry32): BOOL; }
{Process32First 是一个进程获取函数,当我们利用函数CreateToolhelp32Snapshot()    }
{获得当前运行进程的快照后,我们可以利用process32First函数来获得第一个进程的句柄 }
{参数1说明:hSnapshot                                                           }
{CreateToolhelp32Snapshot获取进程快照的句柄                                    }
{参数2说明:lppe                                                                }
{TProcessEntry32创建的结构体                                                   }
{返回值:                                                                      }
{调用成功,返回True,调用失败,返回False。                                     }

{********************************优美的分隔线******************************}

{function Process32Next(hSnapshot: THandle; var lppe: TProcessEntry32): BOOL;  }
{Process32Next是一个进程获取函数,当我们利用函数CreateToolhelp32Snapshot()      }
{获得当前运行进程的快照后,我们可以利用Process32Next函数来获得下一个进程的句柄  }
{参数1说明:hSnapshot                                                           }
{CreateToolhelp32Snapshot获取进程快照的句柄                                    }
{参数2说明:lppe                                                                }
{TProcessEntry32创建的结构体                                                   }
{返回值:                                                                      }
{调用成功,返回True,调用失败,返回False。                                     }

{********************************优美的分隔线******************************}

{function WriteProcessMemory(hProcess: THandle; const lpBaseAddress: Pointer;
lpBuffer: Pointer;nSize:DWORD; var lpNumberOfBytesWritten: DWORD):BOOL;stdcall;
}
{WriteProcessMemory是一个写内存函数                                            }
{参数说明:                                                                     }
{hProcess:              进程的句柄                                             }
{lpBaseAddress:         写入进程的位置(地址)                                 }
{lpBuffer:              数据当前存放地址                                       }
{nSize:                 数据的长度                                             }
{lpNumberOfBytesWritten:实际数据的长度                                         }

{********************************优美的分隔线******************************}

{function LoadLibrary(lpLibFileName: PChar): HMODULE; stdcall;                 }
{LoadLibrary函数载入指定的动态链接库,并将它映射到当前进程使用的地址空间。一旦 }
{载入,即可访问库内保存的资源。                                                }
{参数说明:                                                                     }
{lpLibFileName:指定要载入的动态链接库的名称。                                  }
{返回值:                                                                       }
{成功则返回库模块的句柄,零表示失败。                                          }

{********************************优美的分隔线******************************}

{function CreateRemoteThread(hProcess: THandle;
                            lpThreadAttributes: Pointer;
                            dwStackSize: DWORD;
                            lpStartAddress: TFNThreadStartRoutine;
                            lpParameter: Pointer;
                            dwCreationFlags: DWORD;
                            var lpThreadId: DWORD): THandle; stdcall;
}
{CreateRemoteThread函数在远程进程中创建线程                                         }
{参数说明:                                                                          }
{hProcess:进程句柄                                                                  }
{lpThreadAttributes:线程安全描述字,指向SECURITY_ATTRIBUTES结构的指针               }
{dwStackSize:线程栈大小,以字节表示                                                 }
{lpStartAddress:一个LPTHREAD_START_ROUTINE类型的指针,指向在远程进程中执行的函数地址}
{lpParameter:传入参数                                                               }
{dwCreationFlags:创建线程的其它标志                                                 }
{lpThreadId:线程身份标志,如果为NULL,则不返回                                       }
{返回值:                                                                            }
{成功返回新线程句柄,失败返回nil。                                                  }

{********************************优美的分隔线******************************}

{function WaitForSingleObject(hHandle: THandle; dwMilliseconds: DWORD):
                              DWORD; stdcall;
}
{WaitForSingleObject函数用来检测hHandle事件的信号状态,                         }
{当函数的执行时间超过dwMilliseconds就返回,                                     }
{但如果参数dwMilliseconds为INFINITE时函数将直到相应时间                         }
{事件变成有信号状态才返回,否则就一直等待下去,                                 }
{直到WaitForSingleObject有返回值才执行后面的代码。                              }
{参数说明:                                                                      }
{hHandle:同步对象的句柄                                                         }
{dwMilliseconds:超时间隔,单位为毫秒,为INFINITE时超时是无限的                    }

{********************************优美的分隔线******************************}

{function GetProcAddress(hModule: HMODULE; lpProcName: LPCSTR): FARPROC; stdcall;}
{GetProcAddress函数检索指定的动态链接库(DLL)中的输出库函数地址。                 }
{参数说明:                                                                       }
{hModule:DLL模块句柄                                                             }
{lpProcName:函数名                                                               }
{返回值:                                                                         }
{如果函数调用成功,返回值是DLL中的输出函数地址。 如果函数调用失败,返回值是nil   }

{********************************优美的分隔线******************************}

API备忘录 | 阅读 2693 次
文章评论,共0条
游客请输入验证码