1.简介
在nt6.0 内核以上,windows对系统重要进程和服务进程划分到一个会话中,该会话为会话0.
用户登陆后分配一个会话,在该用户启动的的进程将归于会话1 或者更多(多用户登陆).
此时os会对这会话0和其他会话中的进程之间的操作进行限制. 如会话1中的进程不能容易创建远程线程注入dll
到会话0中的进程.本文将实现远程线程注入到会话0
2.问题分析
下面以windows 7 32位系统为例
经调试发现,这几个函数运行正常:
OpenProcess
VirtualAllocEx
WriteProcessMemory
到了 CreateRemoteThread 函数运行失败.因此通过od加载后跟进该函数:
发现od显示为arg的参数就是调用CreateRemoteThread 的7个参数,CreateRemoteThread 函数调用了CreateRemoteThreadEx ,该函数为:
HANDLE
WINAPI
CreateRemoteThreadEx(
_In_ HANDLE hProcess,
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ SIZE_T dwStackSize,
_In_ LPTHREAD_START_ROUTINE lpStartAddress,
_In_opt_ LPVOID lpParameter,
_In_ DWORD dwCreationFlags,
_In_opt_ LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList, //该处即为多出的那个0
_Out_opt_ LPDWORD lpThreadId
);
图中的push 0x0 作为lpAttributeList的值. 继续跟进:
又调用了ntdll.ZwCreateThreadEx, 继续跟进后就进入内核了. 该函数又是个未公开的函数.google搜了一下发现:
NTSYSCALLAPI NTSTATUS NTAPI NtCreateThreadEx ( _Out_ PHANDLE ThreadHandle, _In_ ACCESS_MASK DesiredAccess, _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, _In_ HANDLE ProcessHandle, _In_ PVOID StartRoutine, _In_opt_ PVOID Argument, _In_ ULONG CreateFlags, _In_opt_ ULONG_PTR ZeroBits, _In_opt_ SIZE_T StackSize, _In_opt_ SIZE_T MaximumStackSize, _In_opt_ PVOID AttributeList );
且第7个参数是挂起计数的这样的一个东西. 根据<<windows核心编程 第5版>>的166页,
线程内核对象有个值代表线程的挂起计数. 调用CreateProcess和CreateThread将查看是否有CREATE_SUSPENDED标记传入.
如果有就让创建的新线程处于挂起状态,否则挂起计数为0就会是可调度的线程. 这时联想到CreateThread 函数创建线程时也会调用
ZwCreateThreadEx API, 所以就可以不以挂起方式创建一个线程,然后再以挂起方式创建一个线程, 然后比较这3次调用ZwCreateThreadEx API
时的参数. 最后很遗憾的发现第7个参数都是1. 所以这种思路没有验证第7个参数是挂起计数.
注入时调用的参数:
0042F644 0042F6D0
0042F648 001FFFFF
0042F64C 00000000
0042F650 00000020
0042F654 75EB28B2 kernel32.LoadLibraryW
0042F658 00BF0000
0042F65C 00000001 ;改为0
0042F660 00000000
0042F664 00000000
0042F668 00000000
0042F66C 0042F7BC
3.改写代码
未完待续....