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.改写代码

 

 

未完待续....