闲着没事整理了一下DLL的N种注入方法.docx
- 文档编号:6737979
- 上传时间:2023-01-09
- 格式:DOCX
- 页数:57
- 大小:45.40KB
闲着没事整理了一下DLL的N种注入方法.docx
《闲着没事整理了一下DLL的N种注入方法.docx》由会员分享,可在线阅读,更多相关《闲着没事整理了一下DLL的N种注入方法.docx(57页珍藏版)》请在冰豆网上搜索。
闲着没事整理了一下DLL的N种注入方法
闲着没事整理了一下DLL的N种注入方法,对学习外挂的朋友,应该有用!
第一种方法:
利用CreateRemoteThread远程建立线程的方式注入DLL.
首先,我们要提升自己的权限,因为远程注入必不可免的要访问到目
标进程的内存空间,如果没有足够的系统权限,将无法作任何事.下
面是这个函数是用来提升我们想要的权限用的.
functionEnableDebugPriv:
Boolean;
var
hToken:
THANDLE;
tp:
TTokenPrivileges;
rl:
Cardinal;
begin
result:
=false;
//打开进程令牌环
OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGESorTOKEN_QUERY,hToken);
//获得进程本地唯一ID
ifLookupPrivilegeValue(nil,'SeDebugPrivilege',
tp.Privileges[0].Luid)then
begin
tp.PrivilegeCount:
=1;
tp.Privileges[0].Attributes:
=SE_PRIVILEGE_ENABLED;
//调整权限
result:
=AdjustTokenPrivileges(hToken,False,tp,
sizeof(tp),nil,rl);
end;
end;
关于OpenProcessToken()和AdjustTokenPrivileges()两个API
的简单介绍:
OpenProcessToken():
获得进程访问令牌的句柄.
functionOpenProcessToken(
ProcessHandle:
THandle;//要修改访问权限的进程句柄
DesiredAccess:
DWORD;//指定你要进行的操作类型
varTokenHandle:
THandle
):
BOOL;//返回的访问令牌指针
AdjustTokenPrivileges():
调整进程的权限.
functionAdjustTokenPrivileges(
TokenHandle:
THandle; //访问令牌的句柄
DisableAllPrivileges:
BOOL;//决定是进行权限修改还是除
能(Disable)所有权限
constNewState:
TTokenPrivileges; //指明要修改的权限,
是一个指向TOKEN_PRIVILEGES结构的指针,该结构包含一个数组,数
据组的每个项指明了权限的类型和要进行的操作;
BufferLength:
DWORD; //结构PreviousState的长度,如果
PreviousState为空,该参数应为0
varPreviousState:
TTokenPrivileges;//指向
TOKEN_PRIVILEGES结构的指针,存放修改前的访问权限的信息
varReturnLength:
DWORD//实际PreviousState结构返回的大
小
):
BOOL;
远程注入DLL其实是通过CreateRemoteThread建立一个远程线程调
用LoadLibrary函数来加载我们指定的DLL,可是如何能让远程线程
知道我要加载DLL呢,要知道在Win32系统下,每个进程都拥有自己的
4G虚拟地址空间,各个进程之间都是相互独立的。
所我们需要在远程
进程的内存空间里申请一块内存空间,写入我们的需要注入的DLL
的路径.需要用到的API函数有:
OpenProcess():
打开目标进程,得到目标进程的操作权限,详细参
看MSDN
functionOpenProcess(
dwDesiredAccess:
DWORD; //希望获得的访问权限
bInheritHandle:
BOOL; //指明是否希望所获得的句柄可以继
承
dwProcessId:
DWORD//要访问的进程ID
):
THandle;
VirtualAllocEx():
用于在目标进程内存空间中申请内存空间以写入
DLL的文件名
functionVirtualAllocEx(
hProcess:
THandle; //申请内存所在的进程句柄
lpAddress:
Pointer; //保留页面的内存地址;一般用nil自
动分配
dwSize, //欲分配的内存大小,字节单位;注意实际分配的
内存大小是页内存大小的整数倍
flAllocationType:
DWORD;
flProtect:
DWORD
):
Pointer;
WriteProcessMemory():
往申请到的空间中写入DLL的文件名
functionWriteProcessMemory(
hProcess:
THandle; //要写入内存数据的目标进程句柄
constlpBaseAddress:
Pointer;//要写入的目标进程的内存指
针,需以VirtualAllocEx()来申请
lpBuffer:
Pointer;//要写入的数据
nSize:
DWORD;//写入数据的大小
varlpNumberOfBytesWritten:
DWORD//实际写入的大小
):
BOOL;
然后就可以调用CreateRemoteThread建立远程线程调用
LoadLibrary函数来加载我们指定的DLL.
CreateRemoteThread() //在一个远程进程中建立线程
functionCreateRemoteThread(
hProcess:
THandle; //远程进程的句柄
lpThreadAttributes:
Pointer;//线程安全描述字,指向
SECURITY_ATTRIBUTES结构的指针
dwStackSize:
DWORD; //线程栈大小,以字节表示
lpStartAddress:
TFNThreadStartRoutine; //一个
TFNThreadStartRoutine类型的指针,指向在远程进程中执行的函数
地址
lpParameter:
Pointer;//传入参数的指针
dwCreationFlags:
DWORD; //创建线程的其它标志
varlpThreadId:
DWORD//线程身份标志,如果为0,则不返回
):
THandle;
整个远程注入DLL的具体实现代码如下:
functionInjectDll(constDllFullPath:
string;const
dwRemoteProcessId:
Cardinal):
boolean;
var
hRemoteProcess,hRemoteThread:
THANDLE;
pszLibFileRemote:
Pointer;
pszLibAFilename:
PwideChar;
pfnStartAddr:
TFNThreadStartRoutine;
memSize,WriteSize,lpThreadId:
Cardinal;
begin
result:
=FALSE;
//调整权限,使程序可以访问其他进程的内存空间
ifEnableDebugPrivthen
begin
//打开远程线程PROCESS_ALL_ACCESS参数表示打开所有的权限
hRemoteProcess:
=OpenProcess(PROCESS_ALL_ACCESS,FALSE,
dwRemoteProcessId);
try
//为注入的dll文件路径分配内存大小,由于为WideChar,故要
乘2
GetMem(pszLibAFilename,Length(DllFullPath)*2+1);
//之所以要转换成WideChar,是因为当DLL位于有中文字符
的路径下时不会出错
StringToWideChar(DllFullPath,pszLibAFilename,Length
(DllFullPath)*2+1);
//计算pszLibAFilename的长度,注意,是以字节为单元的
长度
memSize:
=(1+lstrlenW(pszLibAFilename))*sizeof
(WCHAR);
//使用VirtualAllocEx函数在远程进程的内存地址空间分配
DLL文件名空间
pszLibFileRemote:
=VirtualAllocEx(hRemoteProcess,
nil,memSize,MEM_COMMIT,PAGE_READWRITE);
ifAssigned(pszLibFileRemote)then
begin
//使用WriteProcessMemory函数将DLL的路径名写入到远程
进程的内存空间
ifWriteProcessMemory(hRemoteProcess,
pszLibFileRemote,pszLibAFilename,memSize,WriteSize)and
(WriteSize=memSize)then
begin
lpThreadId:
=0;
//计算LoadLibraryW的入口地址
pfnStartAddr:
=GetProcAddress(LoadLibrary
('Kernel32.dll'),'LoadLibraryW');
//启动远程线程LoadLbraryW,通过远程线程调用创建新
的线程
hRemoteThread:
=CreateRemoteThread
(hRemoteProcess,nil,0,pfnStartAddr,pszLibFileRemote,0,
lpThreadId);
//如果执行成功返回 True;
if(hRemoteThread<>0)then
result:
=TRUE;
//释放句柄
CloseHandle(hRemoteThread);
end;
end;
finally
//释放句柄
CloseHandle(hRemoteProcess);
end;
end;
end;
接下来要说的是如何卸载注入目标进程中的DLL,其实原理和注入DLL
是完全相同的,只是远程调用调用的函数不同而已,这里要调用的是
FreeLibrary.代码如下:
functionUnInjectDll(constDllFullPath:
string; const
dwRemoteProcessId:
Cardinal):
Boolean;
//进程注入和取消注入其实都差不多,只是运行的函数不同而已
var
hRemoteProcess,hRemoteThread:
THANDLE;
pszLibFileRemote:
pchar;
pszLibAFilename:
PwideChar;
pfnStartAddr:
TFNThreadStartRoutine;
memSize,WriteSize,lpThreadId,dwHandle:
Cardinal;
begin
result:
=FALSE;
//调整权限,使程序可以访问其他进程的内存空间
ifEnableDebugPrivthen
begin
//打开远程线程PROCESS_ALL_ACCESS参数表示打开所有的权限
hRemoteProcess:
=OpenProcess(PROCESS_ALL_ACCESS,FALSE,
dwRemoteProcessId);
try
//为注入的dll文件路径分配内存大小,由于为WideChar,故要
乘2
GetMem(pszLibAFilename,Length(DllFullPath)*2+1);
//之所以要转换成WideChar,是因为当DLL位于有中文字符
的路径下时不会出错
StringToWideChar(DllFullPath,pszLibAFilename,Length
(DllFullPath)*2+1);
//计算pszLibAFilename的长度,注意,是以字节为单元的
长度
memSize:
=(1+lstrlenW(pszLibAFilename))*sizeof
(WCHAR);
//使用VirtualAllocEx函数在远程进程的内存地址空间分配
DLL文件名空间
pszLibFileRemote:
=VirtualAllocEx(hRemoteProcess,
nil,memSize, MEM_COMMIT,PAGE_READWRITE);
ifAssigned(pszLibFileRemote)then
begin
//使用WriteProcessMemory函数将DLL的路径名写入到远程
进程的内存空间
ifWriteProcessMemory(hRemoteProcess,
pszLibFileRemote,pszLibAFilename,memSize,WriteSize)and
(WriteSize=memSize)then
begin
//计算GetModuleHandleW的入口地址
pfnStartAddr:
=GetProcAddress(LoadLibrary
('Kernel32.dll'),'GetModuleHandleW');
//使目标进程调用GetModuleHandleW,获得DLL在目标进
程中的句柄
hRemoteThread:
=CreateRemoteThread
(hRemoteProcess,nil,0,
pfnStartAddr,pszLibFileRemote,0,lpThreadId);
//等待GetModuleHandle运行完毕
WaitForSingleObject(hRemoteThread,INFINITE);
//获得GetModuleHandle的返回值,存在dwHandle变量中
GetExitCodeThread(hRemoteThread,dwHandle);
//计算FreeLibrary的入口地址
pfnStartAddr:
=GetProcAddress(LoadLibrary
('Kernel32.dll'),'FreeLibrary');
//使目标进程调用FreeLibrary,卸载DLL
hRemoteThread:
=CreateRemoteThread
(hRemoteProcess,nil,0,
pfnStartAddr,Pointer(dwHandle),0,lpThreadId);
//等待FreeLibrary卸载完毕
WaitForSingleObject(hRemoteThread,INFINITE);
//如果执行成功返回 True;
ifhRemoteProcess<>0then
result:
=TRUE;
//释放目标进程中申请的空间
VirtualFreeEx(hRemoteProcess,pszLibFileRemote,
Length(DllFullPath)+1,MEM_DECOMMIT);
//释放句柄
CloseHandle(hRemoteThread);
end;
end;
finally
//释放句柄
CloseHandle(hRemoteProcess);
end;
end;
end;
第二种方法:
采用CreateProcess的方法,实现起来比较复杂,但没有上面几种方法的局限性。
且可以用其他工
具(VC等)调试注入的DLL。
下面进行介绍。
原理如下:
1. 用CreateProcess(CREATE_SUSPENDED)启动目标进程。
2. 找到目标进程的入口,用ImageHlp中的函数可以实现。
3. 将目标进程入口的代码保存起来。
4. 在目标进程的入口写入LoadLibrary(MyDll)实现Dll的注入。
5. 用ResumeThread运行目标进程。
6. 目标进程就运行了LoadLibrary(MyDll),实现DLL的注入。
7. 目标进程运行完LoadLibrary(MyDll)后,将原来的代码写回目标进程的入口。
8. 目标进程Jmp至原来的入口,继续运行程序。
从原理上可以看出,DLL的注入在目标进程的开始就运行了,而且不是用Debug的方案,这样,就
没有上面方案的局限性了。
该方案的关键在6,7,8三步,实现方法需要监视进程和DLL合作。
下
面,结合代码进行分析。
在监视进程中,创建FileMapping,用来保存目标进程的入口代码,同时保证DLL中可以访问。
在
第7步实现将原目标代码写回目标进程的入口。
//监视程序和DLL共用的结构体
#pragmapack(push,1) //保证下面的结构体采用BYTE对齐(必须)
typedefstruct
{
BYTE int_PUSHAD; //pushad 0x60
BYTE int_PUSH; //push&szDLL 0x68
DWORDpush_Value; // &szDLL="ApiSpy.dll"的path
BYTE int_MOVEAX; // moveeax&LoadLibrary 0xB8
DWORDeax_Value; // &LoadLibrary
WORD call_eax; // calleax 0xD0FF(FFD0)(LoadLibrary
("ApiSpy.dll");
BYTE jmp_MOVEAX; // moveeax&ReplaceOldCode 0xB8
DWORDjmp_Value; // JMP的参数
WORD jmp_eax; // jmpeax 0xE0FF(FFE0)jmpReplaceOldCode;
charszDLL[MAX_PATH];// "ApiSpy.dll"的FullPath
}INJECT_LOADLIBRARY_CODE,*LPINJECT_CODE;
#pragmapack(pop,1)
上面结构体的代码为汇编代码,对应的汇编为:
pushad
pushszDll
moveax,&LoadLibraryA
calleax //实现调用LoadLibrary(szDll)的代码
moveax,oldentry
jmpeax//实现在LoadLibrary运行完后,跳至目标进程的入口继续运行
//FileMaping的结构体
typedefstruct
{
LPBYTE lpEntryPoint; //目标进程的入口地址
BYTE oldcode[sizeof(INJECT_CODE)]; //目标进程的代码保存
}SPY_MEM_SHARE,*LPSPY_MEM_SHARE;
准备工作:
第一步:
用CreateProcess(CREATE_SUSPENDED)启动目标进程。
CreateProcessA(0,szRunFile,0,0,FALSE,CREATE_SUSPENDED
0,NULL,&stInfo,
&m_proInfo);
//用CreateProcess启动一个暂停的目标进程
//找到目标进程的入口点,函数如下
第二步:
找到目标进程的入口,用I
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 闲着 没事 整理 一下 DLL 注入 方法