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