Csrss.exe初始化源代码分析
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\SubSystems]
"Windows"=%SystemRoot%\system32\csrss.exe
ObjectDirectory=\Windows SharedSection=1024,3072,512
Windows=On SubSystemType=Windows
ServerDll=basesrv,1
ServerDll=winsrv:UserServerDllInitialization,3
ServerDll=winsrv:ConServerDllInitialization,2
ProfileControl=Off MaxRequestThreads=16
ServerDll等号后面是动态库的文件名,如basesrv.dll。逗号后面的是这个库注册的序号。如basesrv.dll的就是1
冒号后面的名字是子系统加载这个动态库时候调用的函数名,如果没有提供,就默认是“ServerDllInitialization”
上面说到注册,子系统csrss.exe用一个数组来保存这些注册的动态库。
这个数组名叫 CsrLoadedServerDll,这个变量是在csrsrv.dll中,一共只有4个元素。
每个元素是一个_CSR_SERVER_DLL结构。包括上面注册表提供的3个,再加上csrss.exe初始化时,提供的一个序号0的元素,一共4个。
其实csrss只是一个外壳,很多处理函数都是在csrsrv.dll中。
csrss.exe在初始化时候,调用csrsrv.dll的导出函数
int __stdcall CsrServerInitialization(unsigned int argc, char **argv)
{
//这个函数里面会创建那个核心LPC端口"\\Windows\\ApiPort",
并且会创建一个线程CsrApiRequestThread专门来处理来自这个端口的各种LPC请求
int __stdcall CsrApiPortInitialize();
//这个函数里面会创建LPC端口"\\Windows\\SbApiPort",
并且会创建一个线程CsrSbApiRequestThread专门来处理来自这个端口的各种LPC请求
int __stdcall CsrSbApiPortInitialize();
int __stdcall CsrParseServerCommandLine(unsigned int argc, char **argv)
}
CsrParseServerCommandLine就会解析上面注册表提供的参数。
逐个加载进来。并为每个dll申请一个_CSR_SERVER_DLL结构。
接着调用dll提供的初始化函数,如上面注册表的就是那些冒号后面的函数。
参数就是_CSR_SERVER_DLL结构。
这样每个dll都可以有一次初始化提供自己私有数据初始化_CSR_SERVER_DLL结构的机会。
最重要的一个私有数据字段是_CSR_SERVER_DLL->ApiDispatchTable。
这个字段指明一个函数分发表。
以后"\\Windows\\ApiPort" 这个LPC有请求的时候,一般客户端发起请求是,是调用下面的函数:CsrClientCallServer()
Status = CsrClientCallServer(
&m,
CaptureBuffer,
CSR_MAKE_API_NUMBER( CSRSRV_SERVERDLL_INDEX,CsrpClientConnect),
sizeof( *a )
);
CsrApiRequestThread会根据其中的APINUMBER来索引对应的_CSR_SERVER_DLL结构。
和_CSR_SERVER_DLL->ApiDispatchTable[xxx]处理函数,所以这个apinumber比较特殊,它能够索引对应的dll和对应的分发处理函数。
所以winsrv.dll里面有两个重要的保存函数的表:ConsoleServerApiDispatchTable(控制台管理),UserServerApiDispatchTable(终端登录之类)。
最后我们发现basesrv.DLL也存在一张保存函数的表:BaseServerApiDispatchTable,
Csrsrv.dll存在CsrServerApiDispatchTable这张表。
四个分发表序号如下:
CsrServerApiDispatchTable:0
BaseServerApiDispatchTable:1
ConsoleServerApiDispatchTable:2
UserServerApiDispatchTable:3
第一部分:
base/win32/csrss/csrss.c文件中的main()函数调用
base/win32/server/srvinit.c文件中的CsrServerInitialization()函数
int
_cdecl
main(
IN ULONG argc,
IN PCH argv[],
IN PCH envp[],
IN ULONG DebugFlag OPTIONAL
)
{
NTSTATUS Status;
ULONG ErrorResponse;
KPRIORITY SetBasePriority;
SetBasePriority = FOREGROUND_BASE_PRIORITY + 4;
Status = NtSetInformationProcess (NtCurrentProcess(),
ProcessBasePriority,
(PVOID) &SetBasePriority,
sizeof(SetBasePriority));
ASSERT (NT_SUCCESS (Status));
Status = CsrServerInitialization( argc, argv );
if (!NT_SUCCESS( Status )) {
IF_DEBUG {
DbgPrint( "CSRSS: Unable to initialize server. status == %X\n",
Status
);
}
NtTerminateProcess( NtCurrentProcess(), Status );
}
DisableErrorPopups();
if (NtCurrentPeb()->SessionId == 0) {
//
// Make terminating the root csrss fatal
//
RtlSetProcessIsCritical(TRUE, NULL, FALSE);
}
NtTerminateThread( NtCurrentThread(), Status );
return( 0 );
}
第二部分:
base/win32/server/srvinit.c
CsrParseServerCommandLine()函数
// Though this function does not seem to cleanup on failure, failure
// will cause CSRSS to exit, so any allocated memory will be freed and
// any open handle will be closed.
NTSTATUS
CsrServerInitialization(
IN ULONG argc,
IN PCH argv[]
)
{
NTSTATUS Status;
ULONG i;
PVOID ProcessDataPtr;
PCSR_SERVER_DLL LoadedServerDll;
#if DBG
BOOLEAN bIsRemoteSession = NtCurrentPeb()->SessionId != 0;
#endif
//
// Initialize Wow64 stuffs
//
#ifdef _WIN64
InitializeWow64OnBoot(1);
#endif
//
// Save away system information in a global variable
//
Status = NtQuerySystemInformation( SystemBasicInformation,
&CsrNtSysInfo,
sizeof( CsrNtSysInfo ),
NULL
);
ASSERT( NT_SUCCESS( Status ) || bIsRemoteSession );
if (!NT_SUCCESS( Status )) {
return Status;
}
//
// Use the process heap for memory allocation.
//
CsrHeap = RtlProcessHeap();
CsrBaseTag = RtlCreateTagHeap( CsrHeap,
0,
L"CSRSS!",
L"TMP\0"
L"INIT\0"
L"CAPTURE\0"
L"PROCESS\0"
L"THREAD\0"
L"SECURITY\0"
L"SESSION\0"
L"WAIT\0"
);
//
// Set up CSRSS process security
//
Status = CsrSetProcessSecurity();
ASSERT(NT_SUCCESS(Status) || bIsRemoteSession);
if (!NT_SUCCESS(Status)) {
return Status;
}
//
// Initialize the Session List
//
Status = CsrInitializeNtSessionList();
ASSERT(NT_SUCCESS(Status) || bIsRemoteSession);
if (!NT_SUCCESS(Status)) {
return Status;
}
//
// Initialize the Process List
//
Status = CsrInitializeProcessStructure();
ASSERT(NT_SUCCESS(Status) || bIsRemoteSession);
if (!NT_SUCCESS(Status)) {
return Status;
}
//
// Process the command line arguments
//
Status = CsrParseServerCommandLine(argc, argv);
ASSERT(NT_SUCCESS(Status) || bIsRemoteSession);
if (!NT_SUCCESS(Status)) {
return Status;
}
#if DBG
Status = RtlInitializeCriticalSection(&CsrTrackLpcLock);
if (!NT_SUCCESS(Status)) {
return Status;
}
LpcTrackIndex = 0;
#endif
//
// Fix up per-process data for root process
//
ProcessDataPtr = (PCSR_PROCESS)RtlAllocateHeap( CsrHeap,
MAKE_TAG( PROCESS_TAG ) | HEAP_ZERO_MEMORY,
CsrTotalPerProcessDataLength
);
if (ProcessDataPtr == NULL) {
return STATUS_NO_MEMORY;
}
for (i=0; i<CSR_MAX_SERVER_DLL; i++) {
LoadedServerDll = CsrLoadedServerDll[ i ];
if (LoadedServerDll && LoadedServerDll->PerProcessDataLength) {
CsrRootProcess->ServerDllPerProcessData[i] = ProcessDataPtr;
ProcessDataPtr = (PVOID)QUAD_ALIGN((PCHAR)ProcessDataPtr + LoadedServerDll->PerProcessDataLength);
}
else {
CsrRootProcess->ServerDllPerProcessData[i] = NULL;
}
}
//
// Let server dlls know about the root process.
//
for (i=0; i<CSR_MAX_SERVER_DLL; i++) {
LoadedServerDll = CsrLoadedServerDll[ i ];
if (LoadedServerDll && LoadedServerDll->AddProcessRoutine) {
(*LoadedServerDll->AddProcessRoutine)( NULL, CsrRootProcess );
}
}
//
// Initialize the Windows Server API Port, and one or more
// request threads.
//
Status = CsrApiPortInitialize();
ASSERT( NT_SUCCESS( Status ) || bIsRemoteSession );
if (!NT_SUCCESS( Status )) {
return Status;
}
//
// Initialize the Server Session Manager API Port and one
// request thread.
//
Status = CsrSbApiPortInitialize();
ASSERT( NT_SUCCESS( Status ) || bIsRemoteSession);
if (!NT_SUCCESS( Status )) {
return Status;
}
//
// Connect to the session manager so we can start foreign sessions
//
Status = SmConnectToSm( &CsrSbApiPortName,
CsrSbApiPort,
IMAGE_SUBSYSTEM_WINDOWS_GUI,
&CsrSmApiPort
);
ASSERT( NT_SUCCESS( Status ) || bIsRemoteSession );
if (!NT_SUCCESS( Status )) {
return Status;
}
//
// Only on Console (HYDRA)
//
if (NtCurrentPeb()->SessionId == 0) {
Status = NtSetDefaultHardErrorPort(CsrApiPort);
}
return( Status );
}
第三部分:
base/win32/server/srvinit.c
NTSTATUS
CsrParseServerCommandLine(
IN ULONG argc,
IN PCH argv[]
)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
ULONG i, ServerDllIndex;
PCH KeyName, KeyValue, s;
PCH InitRoutine;
CsrTotalPerProcessDataLength = 0;
CsrObjectDirectory = NULL;
CsrMaxApiRequestThreads = CSR_MAX_THREADS;
SessionId = NtCurrentPeb()->SessionId;
//
// Create session specific object directories
//
Status = CsrCreateSessionObjectDirectory ( SessionId );
if (!NT_SUCCESS(Status)) {
if (SessionId == 0) {
ASSERT( NT_SUCCESS( Status ) );
DbgPrint("CSRSS: CsrCreateSessionObjectDirectory failed status = %lx\n", Status);
} else {
DbgPrint("CSRSS: CsrCreateSessionObjectDirectory failed status = %lx\n", Status);
return Status;
}
}
for (i=1; i<argc ; i++) {
KeyName = argv[ i ];
KeyValue = NULL;
while (*KeyName) {
if (*KeyName == '=') {
*KeyName++ = '\0';
KeyValue = KeyName;
break;
}
KeyName++;
}
KeyName = argv[ i ];
if (!_stricmp( KeyName, "ObjectDirectory" )) {
ANSI_STRING AnsiString;
ULONG attributes;
CHAR SessionDirectory[MAX_SESSION_PATH];
if (SessionId != 0) {
//
// Non-Console session
//
_snprintf(SessionDirectory, sizeof (SessionDirectory), "%ws\\%ld%s", SESSION_ROOT, SessionId, KeyValue);
SessionDirectory[MAX_SESSION_PATH-1] = '\0';
}
//
// Create an object directory in the object name space with the
// name specified. It will be the root for all object names
// created by the Server side of the Client Server Runtime
// SubSystem.
//
attributes = OBJ_OPENIF | OBJ_CASE_INSENSITIVE;
if (SessionId == 0) {
attributes |= OBJ_PERMANENT;
RtlInitString( &AnsiString, KeyValue );
} else {
RtlInitString( &AnsiString, SessionDirectory );
}
Status = RtlAnsiStringToUnicodeString( &CsrDirectoryName, &AnsiString, TRUE );
ASSERT(NT_SUCCESS(Status) || SessionId != 0);
if (!NT_SUCCESS( Status )) {
break;
}
InitializeObjectAttributes( &ObjectAttributes,
&CsrDirectoryName,
attributes,
NULL,
NULL
);
Status = NtCreateDirectoryObject( &CsrObjectDirectory,
DIRECTORY_ALL_ACCESS,
&ObjectAttributes
);
if (!NT_SUCCESS( Status )) {
break;
}
Status = CsrSetDirectorySecurity( CsrObjectDirectory );
if (!NT_SUCCESS( Status )) {
break;
}
}
else
if (!_stricmp( KeyName, "SubSystemType" )) {
}
else
if (!_stricmp( KeyName, "MaxRequestThreads" )) {
Status = RtlCharToInteger( KeyValue,
0,
&CsrMaxApiRequestThreads
);
}
else
if (!_stricmp( KeyName, "RequestThreads" )) {
#if 0
Status = RtlCharToInteger( KeyValue,
0,
&CsrNumberApiRequestThreads
);
#else
//
// wait until hive change !
//
Status = STATUS_SUCCESS;
#endif
}
else
if (!_stricmp( KeyName, "ProfileControl" )) {
}
else
if (!_stricmp( KeyName, "SharedSection" )) {
Status = CsrSrvCreateSharedSection( KeyValue );
if (!NT_SUCCESS( Status )) {
IF_DEBUG {
DbgPrint( "CSRSS: *** Invalid syntax for %s=%s (Status == %X)\n",
KeyName,
KeyValue,
Status
);
}
return Status;
}
Status = CsrLoadServerDll( "CSRSS", NULL, CSRSRV_SERVERDLL_INDEX );
}
else
if (!_stricmp( KeyName, "ServerDLL" )) {
s = KeyValue;
InitRoutine = NULL;
Status = STATUS_INVALID_PARAMETER;
while (*s) {
if ((*s == ':') && (InitRoutine == NULL)) {
*s++ = '\0';
InitRoutine = s;
}
if (*s++ == ',') {
Status = RtlCharToInteger ( s, 10, &ServerDllIndex );
if (NT_SUCCESS( Status )) {
s[ -1 ] = '\0';
}
break;
}
}
if (!NT_SUCCESS( Status )) {
IF_DEBUG {
DbgPrint( "CSRSS: *** Invalid syntax for ServerDll=%s (Status == %X)\n",
KeyValue,
Status
);
}
}
else {
IF_CSR_DEBUG( INIT) {
DbgPrint( "CSRSS: Loading ServerDll=%s:%s\n", KeyValue, InitRoutine );
}
Status = CsrLoadServerDll( KeyValue, InitRoutine, ServerDllIndex);
if (!NT_SUCCESS( Status )) {
IF_DEBUG {
DbgPrint( "CSRSS: *** Failed loading ServerDll=%s (Status == 0x%x)\n",
KeyValue,
Status
);
}
return Status;
}
}
}
else
//
// This is a temporary hack until Windows & Console are friends.
//
if (!_stricmp( KeyName, "Windows" )) {
}
else {
Status = STATUS_INVALID_PARAMETER;
}
}
return( Status );
}
第四部分:
base/subsys/csr/server/srvloadr.c:122:CsrLoadServerDll(
NTSTATUS
CsrLoadServerDll(
IN PCH ModuleName,
IN PCH InitRoutineString,
IN ULONG ServerDllIndex
)
{
NTSTATUS Status;
ANSI_STRING ModuleNameString;
UNICODE_STRING ModuleNameString_U;
HANDLE ModuleHandle;
PCSR_SERVER_DLL LoadedServerDll;
STRING ProcedureNameString;
PCSR_SERVER_DLL_INIT_ROUTINE ServerDllInitialization;
ULONG n;
if (ServerDllIndex >= CSR_MAX_SERVER_DLL) {
return( STATUS_TOO_MANY_NAMES );
}
if (CsrLoadedServerDll[ ServerDllIndex ] != NULL) {
return( STATUS_INVALID_PARAMETER );
}
ASSERT( ModuleName != NULL );
RtlInitAnsiString( &ModuleNameString, ModuleName );
if (ServerDllIndex != CSRSRV_SERVERDLL_INDEX) {
Status = RtlAnsiStringToUnicodeString(&ModuleNameString_U, &ModuleNameString, TRUE);
if (!NT_SUCCESS(Status)) {
return Status;
}
Status = LdrLoadDll( UNICODE_NULL, NULL, &ModuleNameString_U, &ModuleHandle );
if ( !NT_SUCCESS(Status) ) {
PUNICODE_STRING ErrorStrings[2];
UNICODE_STRING ErrorDllPath;
ULONG ErrorResponse;
NTSTATUS ErrorStatus;
ErrorStrings[0] = &ModuleNameString_U;
ErrorStrings[1] = &ErrorDllPath;
RtlInitUnicodeString(&ErrorDllPath,L"Default Load Path");
//
// need to get image name
//
ErrorStatus = NtRaiseHardError(
(NTSTATUS)STATUS_DLL_NOT_FOUND,
2,
0x00000003,
(PULONG_PTR)ErrorStrings,
OptionOk,
&ErrorResponse
);
}
RtlFreeUnicodeString(&ModuleNameString_U);
if (!NT_SUCCESS( Status )) {
return( Status );
}
}
else {
ModuleHandle = NULL;
}
n = sizeof( *LoadedServerDll ) + ModuleNameString.MaximumLength;
LoadedServerDll = RtlAllocateHeap( CsrHeap, MAKE_TAG( INIT_TAG ), n );
if (LoadedServerDll == NULL) {
if (ModuleHandle != NULL) {
LdrUnloadDll( ModuleHandle );
}
return( STATUS_NO_MEMORY );
}
RtlZeroMemory( LoadedServerDll, n );
LoadedServerDll->SharedStaticServerData = CsrSrvSharedSectionHeap;
LoadedServerDll->Length = n;
LoadedServerDll->ModuleName.Length = ModuleNameString.Length;
LoadedServerDll->ModuleName.MaximumLength = ModuleNameString.MaximumLength;
LoadedServerDll->ModuleName.Buffer = (PCH)(LoadedServerDll+1);
if (ModuleNameString.Length != 0) {
strncpy( LoadedServerDll->ModuleName.Buffer,
ModuleNameString.Buffer,
ModuleNameString.Length
);
}
LoadedServerDll->ServerDllIndex = ServerDllIndex;
LoadedServerDll->ModuleHandle = ModuleHandle;
if (ModuleHandle != NULL) {
RtlInitString(
&ProcedureNameString,
(InitRoutineString == NULL) ? "ServerDllInitialization" : InitRoutineString);
Status = LdrGetProcedureAddress( ModuleHandle,
&ProcedureNameString,
0,
(PVOID *) &ServerDllInitialization
);
}
else {
ServerDllInitialization = CsrServerDllInitialization;
Status = STATUS_SUCCESS;
}
if (NT_SUCCESS( Status )) {
try {
Status = (*ServerDllInitialization)( LoadedServerDll );
}
except ( CsrUnhandledExceptionFilter( GetExceptionInformation() ) ){
Status = GetExceptionCode();
}
if (NT_SUCCESS( Status )) {
CsrTotalPerProcessDataLength += (ULONG)QUAD_ALIGN(LoadedServerDll->PerProcessDataLength);
CsrLoadedServerDll[ LoadedServerDll->ServerDllIndex ] =
LoadedServerDll;
if ( LoadedServerDll->SharedStaticServerData != CsrSrvSharedSectionHeap ) {
CsrSrvSharedStaticServerData[LoadedServerDll->ServerDllIndex] = LoadedServerDll->SharedStaticServerData;
}
}
else {
if (ModuleHandle != NULL) {
LdrUnloadDll( ModuleHandle );
}
RtlFreeHeap( CsrHeap, 0, LoadedServerDll );
}
}
else {
if (ModuleHandle != NULL) {
LdrUnloadDll( ModuleHandle );
}
RtlFreeHeap( CsrHeap, 0, LoadedServerDll );
}
return( Status );
}
第五部分:
base/subsys/csr/server/sbinit.c:123:CsrSbApiPortInitialize( VOID )
NTSTATUS
CsrSbApiPortInitialize( VOID )
{
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE Thread;
CLIENT_ID ClientId;
ULONG n;
PSECURITY_DESCRIPTOR pCsrSbApiPortSD;
n = CsrDirectoryName.Length +
sizeof( CSR_SBAPI_PORT_NAME ) +
sizeof( OBJ_NAME_PATH_SEPARATOR );
CsrSbApiPortName.Buffer = RtlAllocateHeap( CsrHeap, MAKE_TAG( INIT_TAG ), n );
if (CsrSbApiPortName.Buffer == NULL) {
return( STATUS_NO_MEMORY );
}
CsrSbApiPortName.Length = 0;
CsrSbApiPortName.MaximumLength = (USHORT)n;
RtlAppendUnicodeStringToString( &CsrSbApiPortName, &CsrDirectoryName );
RtlAppendUnicodeToString( &CsrSbApiPortName, L"\\" );
RtlAppendUnicodeToString( &CsrSbApiPortName, CSR_SBAPI_PORT_NAME );
IF_CSR_DEBUG( LPC ) {
DbgPrint( "CSRSS: Creating %wZ port and associated thread\n",
&CsrSbApiPortName );
}
Status = CsrCreateLocalSystemSD( &pCsrSbApiPortSD );
if (!NT_SUCCESS(Status)) {
return Status;
}
InitializeObjectAttributes( &ObjectAttributes, &CsrSbApiPortName, 0,
NULL, pCsrSbApiPortSD );
Status = NtCreatePort( &CsrSbApiPort,
&ObjectAttributes,
sizeof( SBCONNECTINFO ),
sizeof( SBAPIMSG ),
sizeof( SBAPIMSG ) * 32
);
if (pCsrSbApiPortSD != NULL) {
RtlFreeHeap( CsrHeap, 0, pCsrSbApiPortSD );
}
if (!NT_SUCCESS(Status)) {
return Status;
}
Status = RtlCreateUserThread( NtCurrentProcess(),
NULL,
TRUE,
0,
0,
0,
CsrSbApiRequestThread,
NULL,
&Thread,
&ClientId
);
if (!NT_SUCCESS(Status)) {
return Status;
}
CsrSbApiRequestThreadPtr = CsrAddStaticServerThread(Thread,&ClientId,0);
Status = NtResumeThread( Thread, NULL );
return( Status );
}
第六部分:
base/win32/server/srvinit.c
NTSTATUS
CsrServerDllInitialization(
IN PCSR_SERVER_DLL LoadedServerDll
)
{
LoadedServerDll->ApiNumberBase = CSRSRV_FIRST_API_NUMBER;
LoadedServerDll->MaxApiNumber = CsrpMaxApiNumber;
LoadedServerDll->ApiDispatchTable = CsrServerApiDispatchTable;
LoadedServerDll->ApiServerValidTable = CsrServerApiServerValidTable;
#if DBG
LoadedServerDll->ApiNameTable = CsrServerApiNameTable;
#endif
LoadedServerDll->PerProcessDataLength = 0;
LoadedServerDll->ConnectRoutine = NULL;
LoadedServerDll->DisconnectRoutine = NULL;
return( STATUS_SUCCESS );
}