完成 windows nt 系列的 DLL injection 功能的开发
今天终于完成了往 vista 内所有 ring 3 进程的注入. 包括 csrss.exe 进程.
主要的中心思想就是,
1. 提升本进程访问令牌, 使其有调试权限.
2. 获得本进程的当前线程的内核对象的安全描述符, 将其复制出来备用.
3. 准备远程线程的执行代码以及执行参数. 其中包括 loadlibrarya 和 RtlExitUserThread 调用, 例子嘛, 本来前一篇文章里有, 再次贴在这里方便各位看官.
#define
LoadLibraryA_ADDR 0xDDDDDDDD
#define RtlExitUserThread_ADDR 0xEEEEEEEE
static __declspec(naked) DWORD WINAPI ThreadDummy(LPVOID lpParam)
{
__asm {
push dword ptr [esp + 4 ] ; // 将传进来的线程函数的参数压栈
mov eax, LoadLibraryA_ADDR ; // LoadLibraryA 或 FreeLibrary 函数的地址
call eax ; // 调用 LoadLibraryA 函数
push eax ; // 将 RtlExitUserThread 函数的参数压栈
mov eax, RtlExitUserThread_ADDR ; // RtlExitUserThread 函数的地址
call eax ; // 调用 RtlExitUserThread 函数
ret 4 ; // 返回
}
}
#define RtlExitUserThread_ADDR 0xEEEEEEEE
static __declspec(naked) DWORD WINAPI ThreadDummy(LPVOID lpParam)
{
__asm {
push dword ptr [esp + 4 ] ; // 将传进来的线程函数的参数压栈
mov eax, LoadLibraryA_ADDR ; // LoadLibraryA 或 FreeLibrary 函数的地址
call eax ; // 调用 LoadLibraryA 函数
push eax ; // 将 RtlExitUserThread 函数的参数压栈
mov eax, RtlExitUserThread_ADDR ; // RtlExitUserThread 函数的地址
call eax ; // 调用 RtlExitUserThread 函数
ret 4 ; // 返回
}
}
4. 以第 2 步获取的安全描述符以及第 3 步准备的代码和数据作为参数调用 RtlCreateUserThread 函数, 在目标进程创建远线程. 等待执行完毕.
5. 清理第 2 步和第 3 步分配的内存. 整个过程完毕.
总结: 整个 dll injection 的探索开发历时月余, 开始看似顺利, 后期艰难困苦. 特别是那个超级变态要求: 必须注入到 csrss.exe 进程里去. 从普通的 SetWindowHookEx 和 known dll, 到 CreateRemoteThread, 最后到 NtCreateThread 以及 NtCreateThreadEx, 最后回归到 RtlCreateUserThread 函数. 中间夹杂了 DPC, APC, 以及在内核修改 knowndlls\\kernel32.dll 可执行映像 inline hook CreateThread 函数等等等等. 从应用层到内核, 再回归应用层, 搞了个遍.
现在我可以牛逼哄哄的说一句了, Injection DLL? Just so so!!!
顺便 BS 一下 Rising, 这个宝贝杀软竟然直接 kill 掉了所有远程线程函数, 不对用户做任何通知和给用户选择的机会. 但我在内核修改任何可执行映像时, 这个宝贝却愉快的告诉我, 我的系统很安全. 再次 BS 一下.
一个小小的测试程序, 在 这里下载