DLL注入

by admin on 2020年1月23日

演示工程下载:

测验用的TestDll.Dll源代码(它将被注入到prjzzhost.exe中去卡塔尔:

Delphi花了非常大力气用VCL还会有少年老成对七颠八倒的类把让我们得以尽或然不要API
于是会编制程序序但不领会API仍旧恐怕的
API被封装在kernel32.dll、user32.dll等动态链接Curry,程序采纳时候把DLL映射到温馨的内存了
编辑的时候大家常常需求从DLL导出这一个函数
function Beep; external ‘kernel32.dll’ name ‘Beep’;
这么导出多个beep函数
当然,实际上不要那样麻烦
Delphi已经把这个导出申明写在有的单元里面了(举个例子windows单元卡塔尔
uses windows后就足以一向用了
(并且组建窗口时候私下认可就能引用超级多单元)
故而实际上大家能够直接用的
本条驾驭一下就好了

澳门新葡亰信誉平台游戏 1

程序代码
library TestDll;

始发讲线程插入了
相同的话线程插入有2种办法
1.DLL注入
2.平素的长间距线程插入
DLL注入编写的时候比较轻易,方法也多,但有个毛病进度会多出个模块来,或者被察觉

{总体流程:
应用CreateToolhelp32Snapshot函数创设一个经过快速照相,然后使用Process32First函数和
Process32Next函数遍历出具有进程ID等音信,保存到ListView控件中。当拿到到进度ID后
交给OpenProcess函数使用张开三个经过,进而赢得叁个历程句柄,当获得进度句柄后则交
给VirtualAllocEx和WriteProcessMemory函数使用,进而进行虚构内部存款和储蓄器分配和写入。然后
则动用GetProcAddress函数和GetModuleHandle函数获取定的动态链接库’kernel32.dll’中
的’LoadLibraryA’函数地址。然后把那一个地点交给CreateRemoteThread函数使用。最终用
WaitForSingleObject、VirtualFreeEx、CloseHandle清楚现场。}

uses
SysUtils,
System,
windows,
Classes;

长途线程是一贯纠正对方内部存款和储蓄器的法子,就算蒙蔽性好,不过非常的大心也许会出点难点,比方您让不可能有分界面包车型大巴进度弹出个窗口,不能上网的经过开个端口,那就等着系统崩溃吧

unit Unit1;

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;

DLL注入首先要理解什么样是DLL,dll就是动态链接库,大家应该领悟吧?
怎么编写DLL呢?
和写普通程序大致是相近的
新建叁个工程,选DLL Wizard
察觉了吗?除了program改成library
余下大约是均等的,只是须求程序加载他的入口点

interface

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;

笔者们先编写制定个大概的DLL
library TestDll;
uses
  Windows;{$R *.res}
procedure func_a; 
  begin
    MessageBox(0,’I love delphi’,’Function form Tset DLL’,0);
  end;
procedure func_b(MSG:pchar);
  begin
    MessageBox(0,MSG,’Function form Tset DLL’,0);
  end;

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

end;

begin
   func_a;
   func_b(‘I like it too!’);
end.

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;

exports
Log;

正是特别testdll.dpr

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

begin
DllProc := @DllEntryPoint;
DllEntryPoint(DLL_PROCESS_ATTACH);
end.

看得懂吧,弹出2个音信框
好了封存下,F9运转..出错,哈哈,DLL是不可能一向运转的
那咋做?编译下(按过F9就绝不了,也会编写翻译好)
瞧见那一个DLL了吧?

{$R
*.dfm}

被注入的宿主进程prjzzhost.exe(它什么也未曾作,好无辜哦:卡塔尔国,这里就不付出代码了,因为太轻松了,哈哈.

笔者们弄个程序加载它的入口点
新建二个日常程序
加叁个按键
开关事件若是写一句loadlibrary(‘testdll.dll’State of Qatar;

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

最终,最注重的来了:
project1.exe的源代码:

MainShow.dpr
运作,单击按键,怎么养?弹出东西了吧
自然DLL还足以做函数库,财富库等明日暂不商讨
明天DLL理解写了呢?就是program改成library而已
您能够写本人的前后相继了

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(countState of Qatar+’个经过!’;
end;

程序代码
unit Unit1;

DLL会写了,以往的主题素材正是怎么注入了
大家指标只是让对方的程序运营一句loadlibrary(‘testdll.dll’卡塔尔;而已
一切就OK了

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

interface

常备有这么两种注入方法
1.用到全局音讯钩子
Win32下程序平日都要用收发音信
用钩子函数下全局钩子,程序收到任何新闻都加载大家的DLL的入口点
本来,用这种方法DLL步入后要判定自身是或不是被插进指标经过
是的话,执行代码
不是退出
本条主意很麻烦但通用性很好,只要WINDOWS都能够用(但是有个别系统经过音信是勾不住的,所以注入源源卡塔尔
早期的DLL注入超过1/4是用这几个原理达成的

procedure
TForm1.Button3Click(Sender: TObject);

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

2.写注册表
写HKEY_LOCAL_MAHINESoftwareMicrosoftWindows
NTCurrentVersionWindowsAppInit_DLLs
不过只可以是NT下,况且必需是调用过user32.dll(Windows的八个内核,只要有分界面的次序都调用它)的次序,在开机后全部程序会活动加载DLL,但是这几个dll无法被卸载,何况不可能调用有个别函数,不然系统会挂掉(有危殆性哦)
不引入应用

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;

type

3.施用远程线程注入来贯彻DLL注入
假定能张开句柄,就会打响(强吧?)何况完结起来比较简单
短处就是9X水源的轻微难度(亦非很狼狈)

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;

TLog = procedure(s : PChar);stdcall;
TServiceMain = procedure(argc : Integer; VAR argv : pchar);stdcall;

 

end.

EDLLLoadError = class(Exception);

大家今天就讲利用远程线程注入来完毕DLL注入吧!

{上边是所用到的函数的详尽表达:}

TForm1 = class(TForm)
Button3: TButton;
procedure Button3Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

您或者要问,既然刚才说了长途线程能够直接流入叁个线程,为啥还要节外生枝扭转再调用DLL呢?
那是因为,远程线程技术日常是一贯对指标程序的内部存款和储蓄器进行操作
笔者们掌握分歧程序的虚构内部存款和储蓄器是不均等的
于是众多函数的地址不肯定相像
而程序运维的时候实乃Call函数地址实行函数调用的
由此我们要小心精打细算非常多偏移之类的
这是特别麻烦的事情
还要像上边说的让无法有分界面包车型大巴长河弹出个窗口,那就欠有意思了
而DLL呢?
DLL调用时其实是被映射到进度内部存款和储蓄器里面
DLL具备和煦的导入表、财富、函数等东西,实际上就是三个全部的顺序
映入内部存款和储蓄器后和实行三个顺序效果是相符的
与上述同类大家就不用构思这一个三不乱齐的东西,只要安心的写成效就可以

澳门新葡亰信誉平台游戏,{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的值                                              }

var
Form1: TForm1;

好了,
要清楚远程线程首先当然要把程序本地线程搞精晓了
不领悟大家编三三十二线程程序的时候是或不是都用tthread类?
左右小编是不爱好那么些
大家看看Windows给大家的原始API吧(tthread类也是用它写的)

{表1:}
{MEM_COMMIT:    
为特定的页面区域分配内部存款和储蓄器中或磁盘的页面文件中的物理存款和储蓄      
}
{MEM_PHYSICAL
:  分配物理内部存款和储蓄器(仅用于地点窗口扩展内部存款和储蓄器)                      
}
{MEM_RESE中华VVE:    保留进程的设想地址空间,而不分红任何物理存款和储蓄。              
}
{                
保留页面可因而三番五次调用VirtualAlloc()而被清除              
}
{MEM_RESET :    
指明在内部存款和储蓄器中由参数lpAddress和dwSize钦命的数据无效            }
{MEM_TOP_DOWN:  
在玩命高的地方上分配内部存款和储蓄器(Windows 98忽略此标记)          
}
{MEM_WRITE_WATCH:必须与MEM_RESE大切诺基VE一同钦定,使系统追踪那多少个被写入              }
{                 分配区域的页面(仅针对Windows
98)                           }

implementation

function CreateThread(
lpThreadAttributes: Pointer; 
//安全指针日常nil就能够了
dwStackSize: DWORD; 
//线程带头化尺寸,日常用0,得到与主线程相符尺寸(非常不够本人会大增,别担忧)
lpStartAddress: TFNThreadStartRoutine;
//三个针对要试行线程函数的指针,那几个函数必得坚决守住stdcall约定,况兼可带一个参数,参数必得是指针类型
lpParameter: Pointer; 
//函数的参数
dwCreationFlags: DWORD;
//调节创造标记,用0表示线程立即实行
var lpThreadId: DWORD)
//再次来到标志变量笔者以为无妨用,反正句柄都有了
: THandle; 
//重回线程的句柄
stdcall;//标准调用 Windows下API经常都是明媒正礼调用

{表2:}
{PAGE_READONLY:
该区域为只读。若是应用程序试图访问区域中的页的时候,      }
{                将会被驳倒访问PAGE_READWSportageITE
区域可被应用程序读写        }
{PAGE_EXECUTE:  区域包蕴可被系统履行的代码。试图读写该区域的操作将被反驳回绝。}
{PAGE_EXECUTE_READ :    
区域包涵可进行代码,应用程序能够读该区域。       }
{PAGE_EXECUTE_READWEscortITE:
区域包涵可进行代码,应用程序能够读写该区域。     }
{PAGE_GUA卡宴D:
区域率先次被访谈时步入一个STATUS_GUARD_PAGE异常,            }
{            
这么些标记要和任何保险标记归拢使用,申明区域被第叁遍访谈的权位
}
{PAGE_NOACCESS: 任何访谈该区域的操作将被驳倒                           }
{PAGE_NOCACHE:  RAM中的页映射到该区域时将不会被计算机缓存(cached卡塔尔(قطر‎      
}

{$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);

大家把DLL源码里面包车型大巴func_b拷到刚刚拾叁分EXE上
多少校勘下
procedure func_b(MSG:pchar); stdcall;
  begin
    MessageBox(0,MSG,’Function form Tset DLL’,0);
    sleep(10000State of Qatar;//线程暂停N久(不超过10s)
  end;
加上2个按钮
第一个
procedure TForm1.Button2Click(Sender: TObject);
begin
  func_b(‘123’);
end;
第二个
procedure TForm1.Button3Click(Sender: TObject);
var tid:longword;//放再次回到值,不放她不让试行,烦扰
    str:pchar;//便于得到pointer
begin
  str:=’123′;
  createthread(nil, 
               0, 
               @func_b,  //函数名前边加@是得到函数指针
              
pointer(strState of Qatar,//固然str也是指针,但是delphi便是要pointer型的,这就转一下档次
                0 , tid卡塔尔(قطر‎;//tid纯属放着占格式的,平日大家用不到
end;
//上面CreateThread看得懂吧,大致都是暗中同意设置,以往套下去用就是了

{function OpenProcess(dwDesiredAccess: DWORD;
bInheritHandle: BOOL;
dwProcessId: DWORD): THandle; stdcall;}
{OpenProcess
函数用来开垦一个已存在的进程对象,并回到经过的句柄。}
{参数表达:}
{dwDesiredAccess是访谈进程的权杖。见上边表3}
{bInheritHandle 是句柄是还是不是持续进度属性。  
}
{dwProcessId    是进程ID。              
}

{ 获得快速照料中的第3个经过 }
{ 应当要安装布局的深浅,不然将赶回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;

实则都以调用func_b,只是其次个进度用了信新线程
可是意义是不均等的
率先个按键按下弹出窗口后,程序卡死了(暂停10000)
其次个却不会
缘何吧?
大家得以这么敞亮
窗口看做叁个主线程,施行func_b,弹出窗口,然后主线程挂起,于是卡死了
而第二个经过创设一个新线程,新线程推行func_b,弹出窗口,挂起10000,可是由于主线程未有挂起,所以看起来关掉窗口后没什么事情产生(实际上特别线程还在暗地里实践,直到线程代码运维完,只是它卡死不会影响你)

{表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 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);

其三头要理解了那么下边就轻松领会了
拜会那一个函数
function CreateRemoteThread(
         hProcess: THandle;
         lpThreadAttributes: Pointer;
         dwStackSize: DWORD;
         lpStartAddress: TFNThreadStartRoutine;
         lpParameter: Pointer;
         dwCreationFlags: DWORD;
         var lpThreadId: DWORD)
         : THandle; stdcall;

{********************************肉麻的分隔线******************************}

if Enabled then
TokenPri.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED
else
TokenPri.Privileges[0].Attributes := 0;

除了这些之外函数名不相似,下边包车型客车参数多了个hProcess: THandle;,剩下的一点一滴相符
呵呵,这些东西正是本节课的严重性了
先看函数名就驾驭是为啥用的了 ‘创立远程线程’
用法和刚刚基本生龙活虎致
固然hProcess: THandle是什么样吧?
那边要填的是被注入线经过的句柄

{function CreateToolhelp32Snapshot(dwFlags,
th32ProcessID: DWORD): THandle;  }
{CreateToolhelp32Snapshot函数功用:函数为钦点的进程、进度使用的堆[HEAP]、    
}
{模块[MODULE]、线程[THREAD])创设叁个快照[snapshot]。                        }
{参数1说明:dwFlags                                                          
}
{TH32CS_INHETucsonIT        评释快速照相句柄是可继续的。                              }
{TH32CS_SNAPALL        在快速照拂中包罗系统中兼有的进程和线程。                  }
{TH32CS_SNAPHEAPLIST  
在快速照管中包括在th32ProcessID中内定的进度的保有的堆。   }
{TH32CS_SNAPMODULE    
在快速照相中带有在th32ProcessID中钦赐的进程的具有的模块。 }
{TH32CS_SNAPPROCESS    在快速照拂中隐含系统中兼有的进度。                        }
{TH32CS_SNAPTHREAD    
在快照中含有系统中享有的线程。                        }
{参数2说明:th32ProcessID                                                    
}
{钦赐就要快速照相的长河ID。假设该参数为0意味着快照当前进度。该参数唯有在设置了    
}
{TH32CS_SNAPHEAPLIST或者TH32CS_SNAPMODULE后才使得,在任何情况下该参数被忽视,}
{全数的历程都会被快速照相。                                                      }
{返回值:                                                                    }
{调用成功,再次回到快速照相的句柄,调用退步,重临0。                                
}

rtnTemp := 0;
{ 设置新的权柄 }
AdjustTokenPrivileges(hTk,False,TokenPri,sizeof(TokenPri),nil,rtnTemp);

什么是句柄?
打个假诺,对象是三个门,句柄正是极度把手,通过句柄大家得以对门进行操作
也正是说大家选择句柄来操作有个别事物(包罗进度、线程等等)
你有未有介怀到,CreateThread和CreateRemoteThread都回来三个THandle,也正是线程的句柄
再有loadlibrary也会回到DLL的句柄,大家能够运用他们对相关对象开展操作

{********************************绝色的分隔线******************************}

Result := GetLastError = ERROR_SUCCESS;
CloseHandle(hTk);

那正是说怎么获得进度句柄呢?
相同选择先拿到进度PID再用上边包车型客车函数拿到句柄
function OpenProcess(
dwDesiredAccess: DWORD;
//访谈标识平时填写
PROCESS_ALL_ACCESS,那样这一个句柄可以拿到最大操作权限
bInheritHandle: BOOL; 
//可不可以继续,那些跟子程序有关,不在意了,填false和true都能够,反正我们团结能操作久能够
dwProcessId: DWO揽胜DState of Qatar: //要获得句柄的长河ID
THandle; stdcall;//重返句柄
一时会重临0,表达打开句柄战败了
诚如是您的权限远远不够(例如你想对Winlogon那个系统级程序操作)
那个时候大家供给进步权限 日常Debug权限就足以了(其实操作权限里面最高了)
升迁的进程自己写好了
平素调用就能够了(改过进度令牌到Debug等第,为何如此写这里不详细讲了,自个儿去网络搜寻下)
procedure GetDebugPrivs; 
var
  hToken: THandle;
  tkp: TTokenPrivileges;
  retval: dword;
begin
  If (OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or
TOKEN_QUERY, hToken)) then
  begin
    LookupPrivilegeValue(nil, ‘SeDebugPrivilege’  ,
tkp.Privileges[0].Luid);
    tkp.PrivilegeCount := 1;
    tkp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
    AdjustTokenPrivileges(hToken, False, tkp, 0, nil, retval);
  end;
end;

{PROCESSENTRY32结构}
{tagPROCESSENTRY32 = packed record
  dwSize: DWOHavalD;              构造的朗朗上口
  cntUsage: DWORD;            此进度的引用计数
  th32ProcessID: DWORD;       进程ID
  th32DefaultHeapID: DWOTucsonD;   进度暗许堆
  th32ModuleID: DWOHighlanderD;        进程模块IDThis
  cntThreads: DWOWranglerD;          此进度开启的线程计数
  th32ParentProcessID: DWOQashqaiD; 父进程的ID
  pcPriClassBase: Longint;    线程优先权
  dwFlags: DWORD;
  szExeFile: array[0..MAX_PATH – 1] of Char; 进程全名
end;}

end;
end;

不会晕吧?
有道是记得本身刚才提到了要PID,那怎么得到呢?
诚如用FindWindow和GetWindowThreadProcessId合作的到
这样写
先var Pid:longword;//积攒那几个PID
GetWindowThreadProcessId(FindWindow(‘Notepad’, nil), @PID);
如此就找到台式机的PID,再如’Shell_TrayWnd’可以找到Explorer的
窗口类名传闻能够用SPY++查询,可是那东西作者没见过,呵呵
自然还是能枚举进程判定进度名等等
那个先告一段落。

{********************************精粹的分隔线******************************}

{ 调节和测量试验函数 }
procedure OutPutText(var CH:PChar);
var
FileHandle: TextFile;
Begin
AssignFile(FileHandle,’zztest.txt’);
Append(FileHandle);
Writeln(FileHandle,CH);
Flush(FileHandle);
CloseFile(FileHandle);
END;

好了,拿Windows的记录簿动手吧
procedure TmyForm.Button4Click(Sender: TObject);
var h:longword;
//PID和THandle 的品类其实都以longword,改个名字而已,所以能够通用
begin
 winexec(‘notepad’,1卡塔尔(قطر‎;//运转笔记本
 GetWindowThreadProcessId(FindWindow(‘notepad’, nil),
@h);//得到Pid存在h
 h:=OpenProcess(PROCESS_ALL_ACCESS, False, h);
 //得到handle存在h,前边那一个是变量pid,算完放到后边的h是句柄(四个例外的东西,只是类型同样而已)
 sleep(2000);//等2秒
 TerminateProcess(h,0卡塔尔(قطر‎;//关闭台式机,h是这些句柄,0表示平常退出
end;

{function Process32First(hSnapshot: THandle; var
lppe: TProcessEntry32): BOOL; }
{Process32First
是叁个历程获得函数,当我们使用函数CreateToolhelp32Snapshot(State of Qatar    }
{得到当前运作进程的快速照相后,大家能够运用process32First函数来拿到第三个经过的句柄
}
{参数1说明:hSnapshot                                                          
}
{CreateToolhelp32Snapshot获取进度快照的句柄                                    }
{参数2说明:lppe                                                                }
{TProcessEntry32创造的布局体                                                  
}
{返回值:                                                                      }
{调用成功,再次来到True,调用失利,重临False。                                    
}

{ 注入远程进程 }
function InjectTo(const Host, Guest: string; const PID: DWORD = 0):
DWORD;
var
{ 被注入的进程句柄,进度ID}
hRemoteProcess: THandle;
dwRemoteProcessId: DWORD;

运维起来正是张开叁个台式机,大约2s狗关掉它
不知底我们看懂了从未,未有不妨,只是为了印证我们得以获得三个课操作的长河句柄

{********************************雅观的分隔线******************************}

{ 写入远程进度的内容大小 }
memSize: DWORD;

临近万事具有了吧?那试试远程线程了啊
再建三个开关
前边的如故那般写,再把极其创立线程的拷过来
改成CreateRemoteThread加上h参数
procedure TmyForm.Button5Click(Sender: TObject);
var
  h:longword;
  tid:longword;
  str:pchar;
begin
 str:=’123′;
 winexec(‘notepad’,1);
 GetWindowThreadProcessId(FindWindow(‘notepad’, nil), @h);
 h:=OpenProcess(PROCESS_ALL_ACCESS, False, h);
 CreateRemoteThread(h,nil,  0,  @func_b, pointer(str), 0 , tid);
end;
运作起来
笔记本出来了,对话框也出去了…
只是对话框却不是我们弄的非常,是个报错的
探望写了怎么样
内存’0x00000000’不能为’writen’
为啥吗?记得作者刚刚说的么
远程线程是在其他程序里运营一个线程
也正是让里三个函数施行CreateThread
据此,函数的地址不自然是如出大器晚成辙的,更并且台式机里面怎么恐怕会有func_b这些咱们同舟共济写的函数呢
这么一来当然要出错了

{function Process32Next(hSnapshot: THandle; var
lppe: TProcessEntry32): BOOL;  }
{Process32Next是三个进度拿到函数,当大家选拔函数CreateToolhelp32Snapshot(卡塔尔国      }
{拿到当前运转进度的快速照相后,我们得以行使Process32Next函数来获取下贰个经过的句柄  }
{参数1说明:hSnapshot                                                          
}
{CreateToolhelp32Snapshot获取进度快速照相的句柄                                    }
{参数2说明:lppe                                                                }
{TProcessEntry32创制的组织体                                                  
}
{返回值:                                                                      }
{调用成功,重返True,调用战败,重临False。                                    
}

{ 写入到长途进度后之处 }
pszLibFileRemote: Pointer;

这下傻了,那怎么注入大家要的函数呢?
记得大家要讲什么吧?-利用远程线程实行DLL注入
大家能够把函数写在DLL里面,用长途线程让对象经过加载它
如此那般函数就实施了
我们假若想方法让对方程序loadlibrary(‘testdll.dll’卡塔尔;这就OK了
看看LoadLibrary的原型
function LoadLibrary(lpLibFileName: PAnsiChar): HMODULE; stdcall;
您应当开掘了它和线程供给的函数格式大概同大器晚成
参数是指针型PAnsiChar正是pchar,一个指向性字符串的指针
归来HMODULE,HMODULE实质是longword(改个名字而已)
^_^,那就远程运营它吗

{********************************雅观的分隔线******************************}

iReturnCode: Boolean;
TempVar: DWORD;

那时你可能会想,LoadLibrary的地点要怎么获得呢?
要领会,LoadLibrary是叁个API(在Kernel32.dll里面卡塔尔,实际上,每一种Win32顺序都亟需中间的函数
之所以,大多数程序运维代码前会装入那么些DLL,把内部的函数映射到自个儿的内部存储器了
这么一来,只假使那个DLL里面同三个函数在富有的长河里地点都以均等的
嘿嘿,那样就便于了
地方我们平日用GetProcAddress
function GetProcAddress(
hModule: HMODULE;
//模块句柄,DLL被加载后就创造模块,等下报告我们怎么获得那一个
lpProcName: LPCSTR 
//函数在DLL中的导盛名LoadLibrary实际上是LoadLibraryA
//那些我们看看DelphiWindows单元的源码就知道了
卡塔尔: FARPROC; stdcall;//再次来到指针
那多少个类型看得乱乱的吧,不要管他们,在Delphi上不鼠标停在函数上,类型的原型就出去了
好了
这几天是怎么拿到那些模块的句柄的难题
用GetModuleHandle
function GetModuleHandle(
lpModuleName:
PChar卡塔尔(قطر‎//模块名,DLL被加载后就构建模块,所以正是DLL的文本名了
: HMODULE; stdcall;//重返模块句柄
好了。知道了这个获得函数地址就便于了
GetProcAddress(GetModuleHandle(‘KERNEL32.DLL’), ‘LoadLibraryA’);
一句化解
难点仿佛都解决了呢?
先别高兴,不要忘记记了,它还带了个参数,正是万分DLL的名字
参数类型是叁个针对字符串地址的指针
本条是个大标题,一来你不能够确认保障旁人的先后内部存款和储蓄器里有其一字符串
二来有你也不知情她的职位,这可如何是好吧?

{function WriteProcessMemory(hProcess: THandle;
const lpBaseAddress: Pointer;
lpBuffer: Pointer;nSize:DWORD; var lpNumberOfBytesWritten:
DWORD):BOOL;stdcall;}
{WriteProcessMemory是二个写内部存款和储蓄器函数                                            }
{参数表达:                                                                    
}
{hProcess:              进度的句柄                                            
}
{lpBaseAddress:        
写入进度的任务(地址)                                 }
{lpBuffer:              数据当前寄存地方                                      
}
{nSize:                
数据的尺寸                                             }
{lpNumberOfBytesWritten:实际数指标长度                                        
}

{ 指向函数LoadLibraryW的地址 }
pfnStartAddr: TFNThreadStartRoutine;

自己写!
大家把特别字符串写到对方内部存款和储蓄器里
呵呵,很霸气的秘技,但确确实实是个好措施
不赘述了,此前
我们率先要在指标经过申请一块内部存款和储蓄器,以便把卓殊参数写进去
申请内部存款和储蓄器用VirtualAllocEx,看看它的原型
function VirtualAllocEx(
 hProcess: THandle;//目的经过句柄,这些毫无说了呢
 lpAddress:
Pointer;//分配内存地方,日常用nil,那样会在系统以为最合适之处分配
 dwSize: DWO宝马X3D;//分配的地方范围,相当于高低了
 flAllocationType:
DWOHavalD;//如何分配地址,平日用MEM_COMMIT为钦命空间提交物理内存
 flProtect: DWOEvoqueD//该段内存的维护品种,PAGE_READW中华VITE代表可读可写
 卡塔尔(قطر‎: Pointer;
stdcall;//重临内部存款和储蓄器地址,哈哈,那便是我们要的非常参数的指针了

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

{ dll全路径,供给写到远程进度的内部存款和储蓄器中去 }
pszLibAFilename: PwideChar;
begin
Result := 0;
{ 设置权限 }
EnabledDebugPrivilege(True);

好了,分配完内部存款和储蓄器当然是要把大家的数据写过去了
这时须要用到WriteProcessMemory来写进度的内部存储器
function WriteProcessMemory(
   hProcess: THandle; //指标进程句柄
   const lpBaseAddress: Pointer;
   //要写的内部存储器地址,就填大家非常参数的指针
   lpBuffer: Pointer;
   //数据之处,大家把字符串存这里,让她拷
   nSize: DWORD;
   //要拷贝的数量长度
   //字符串在Windows定义是以null(正是16进制的0卡塔尔结尾的
   //所以长度就是字符串的长短+1
   var lpNumberOfBytesWritten: DWOCR-VD卡塔尔国//重返的什么样东西,没什么用
   : BOOL; stdcall; //重回成功或战败

{function LoadLibrary(lpLibFileName: PChar):
HMODULE; stdcall;                 }
{LoadLibrary函数载入钦定的动态链接库,并将它映射到当下进程使用之处空间。风流倜傥旦
}
{载入,就可以访谈库内保存的资源。                                                }
{参数表达:                                                                    
}
{lpLibFileName:钦点要载入的动态链接库的名号。                                  }
{返回值:                                                                      
}
{成功则重返库模块的句柄,零意味失败。                                          }

{ 为注入的dll文件路线分配内部存款和储蓄器大小,由于为WideChar,故要乘2 }
Getmem(pszLibAFilename, Length(Guest) * 2 + 1);
StringToWideChar(Guest, pszLibAFilename, Length(Guest) * 2 + 1);

笔者们来写个总体的代码吧
procedure TmyForm.Button6Click(Sender: TObject);
var
  h:longword; //放句柄,中间顺便暂放下PID
  tmp:longword;//那一个特意来占格式搜集废品
  DllName:pchar;
  Mysize:longword;//放字符串长度
  Parameter:pointer;//放那三个参数的指针(地方在目的经过内)
begin
 DLLName:=’Testdll.dll’;
 Mysize:=strlen(Dllname)+1;
 winexec(‘notepad’,1);
 GetWindowThreadProcessId(FindWindow(‘notepad’, nil), @h);
 h:=OpenProcess(PROCESS_ALL_ACCESS, False, h);
 Parameter:= VirtualAllocEx(h, nil, Mysize, MEM_COMMIT,
PAGE_READWRITE);
 WriteProcessMemory(h, Parameter, Pointer(DllName), MySize, tmp);
 CreateRemoteThread(h,nil,  0,
GetProcAddress(GetModuleHandle(‘KERNEL32.DLL’), ‘LoadLibraryA’),
Parameter, 0 , tmp);
end;
又看到这两个掌握的对话框了
哈哈哈,这么说大家中标了
如把这一个DLL换来其余的效劳,那就…

{********************************赏心悦目标分隔线******************************}

{ 获取进度ID }
if PID > 0 then
dwRemoteProcessID := PID
else
GetMyProcessID(Host, False, dwRemoteProcessID);

前天的事物大概就讲到这里
您或然想,单纯的中远间距线程是怎么贯彻的吧?
刚才我们能往对方内存里拷进去字符串
不可否认能够把方方面面函数拷进去
时间涉及不详细讲了
本身给大家三个函数可以一向用
本条是外国贰个叫Aphex的写的
本人看得不是很懂,也没很认真研商过

{function CreateRemoteThread(hProcess: THandle;
                            lpThreadAttributes: Pointer;
                            dwStackSize: DWORD;
                            lpStartAddress: TFNThreadStartRoutine;
                            lpParameter: Pointer;
                            dwCreationFlags: DWORD;
                            var lpThreadId: DWORD): THandle;
stdcall;}
{CreateRemoteThread函数在长途进度中创制线程                                        
}
{参数表达:                                                                          }
{hProcess:进程句柄                                                                  }
{lpThreadAttributes:线程安全描述字,指向SECUEscortITY_ATTMuranoIBUTES结构的指针              
}
{dwStackSize:线程栈大小,以字节表示                                                
}
{lpStartAddress:一个LPTHREAD_START_ROUTINE类型的指针,指向在长途进度中奉行的函数地址}
{lpParameter:传入参数                                                              
}
{dwCreationFlags:创立线程的其余标记                                                
}
{lpThreadId:线程身份标识,假诺为NULL,则不回去                                      
}
{返回值:                                                                            }
{成功再次来到新线程句柄,失利再次来到nil。                                                  }

{ 拿到远程进度句柄,具有写入权限}
hRemoteProcess := OpenProcess(PROCESS_CREATE_THREAD +
{允许远程创设线程}
PROCESS_VM_OPERATION + {允许远程VM操作}
PROCESS_VM_WENCOREITE, {允许远程VM写}
FALSE, dwRemoteProcessId);

procedure Inject(ProcessHandle: longword; EntryPoint: pointer);
var
  Module, NewModule: Pointer;
  Size, BytesWritten, TID: longword;
begin
  Module :=
Pointer(GetModuleHandle(nil卡塔尔卡塔尔国;//获得模块句柄,nil表示收获自个儿模块的
  Size := PImageOptionalHeader(Pointer(integer(Module) +
PImageDosHeader(Module)._lfanew + SizeOf(dword) +
SizeOf(TImageFileHeader))).SizeOfImage;
  VirtualFreeEx(ProcessHandle, Module, 0, MEM_RELEASE);
  NewModule := VirtualAllocEx(ProcessHandle, Module, Size, MEM_COMMIT
or MEM_RESERVE, PAGE_EXECUTE_READWRITE);
  WriteProcessMemory(ProcessHandle, NewModule, Module, Size,
BytesWritten);
  CreateRemoteThread(ProcessHandle, nil, 0, EntryPoint, Module, 0,
TID);
end;

{********************************奇妙的分隔线******************************}

{
用函数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);

用的时候写个无参数的函数(遵从标准调用卡塔尔比方func吧
inject(目的句柄,@func卡塔尔;
就OK了
留神充裕func里面只可以有API函数,本身写的函数都不可能调用,想用就一向写进程进去吧
再不会怎么样你尝试就了然了

{function WaitForSingleObject(hHandle: THandle;
dwMilliseconds: DWORD):
                              DWORD; stdcall;}
{WaitForSingleObject函数用来检查评定hHandle事件的非确定性信号状态,                        
}
{当函数的奉行时间抢先dw米尔iseconds就回来,                                    
}
{但假诺参数dwMilliseconds为INFINITE时函数将停止相适那时候间                        
}
{事件形成有实信号状态才再次来到,否则就直接等候下去,                                
}
{直到WaitForSingleObject有重临值才实施前边的代码。                              }
{参数表明:                                                                      }
{hHandle:同步对象的句柄                                                        
}
{dwMilliseconds:超时间距,单位为微秒,为INFINITE时超时是非常的                    }

if iReturnCode then
begin
pfnStartAddr := GetProcAddress(GetModuleHandle(‘Kernel32’),
‘LoadLibraryW’);
TempVar := 0;
{ 在长途进度中运维dll }
Result := CreateRemoteThread(hRemoteProcess, nil, 0, pfnStartAddr,
pszLibFileRemote, 0, TempVar);
end;

注意了
VirtualAllocEx
VirtualFreeEx
CreateRemoteThread
在NT下本领用
9X/me系统能够应用一些帮衬单元完成
预习包里面包车型大巴9X_Files里面有个
除此以外MadRemote等也能够实现

{********************************绝色的分隔线******************************}

{ 释放内存空间 }
Freemem(pszLibAFilename);
end;

{function GetProcAddress(hModule: HMODULE;
lpProcName: LPCSTR): FARPROC; stdcall;}
{GetProcAddress函数检索钦赐的动态链接库(DLL卡塔尔国中的输出库函数地址。                
}
{参数表明:                                                                      
}
{hModule:DLL模块句柄                                                            
}
{lpProcName:函数名                                                              
}
{返回值:                                                                        
}
{若是函数调用成功,再次回到值是DLL中的输出函数地址。
假若函数调用退步,重回值是nil   }

{ 测试 }
procedure TForm1.Button3Click(Sender: TObject);
begin

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

InjectTo(‘prjzzhost.exe’, extractfilepath(paramstr(0))+’TestDll.dll’);
end;

end.

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图