閱讀877 返回首頁    go 阿裏雲 go 技術社區[雲棲]


[轉貼]Administrator用戶直接獲取SYSTEM權限

 Administrator用戶直接獲取SYSTEM權限


來源:https://www.nsfocus.com
作者:"scz" <scz@nsfocus.com>


標題: MSDN係列(3)--Administrator用戶直接獲取SYSTEM權限

日期: 2003-06-21 21:51
更新:

--------------------------------------------------------------------------

目錄:

  概述
  sysproc.c
  sysproc_now.c
  參考資源

--------------------------------------------------------------------------

概述

翻看[5]的時候,其書中例8.1演示如何以SYSTEM身份啟動cmd。以前我為了達到同樣
目的,利用at命令,但平日裏禁用Task Scheduler Service的,感覺操作很繞彎,不
爽得很。網上有現成的可執行程序直接獲取SYSTEM權限,不喜歡沒源碼的此類型小工
具,從未試用過。

麻雀兄 <sparrow@smth>在水木清華MSDN版上共享了一份Ashot Oganesyan K的源代碼,
也是直接獲取SYSTEM權限。

一下子有了兩份現成的短小精悍型源代碼,心癢難耐,決定演練。最後發現還是麻雀
兄給的代碼有實用價值。Gary Nebbett的代碼對於2K/XP實際上失去了實用價值,這
要感謝rain的指點,具體技術討論見後。

本文提供了兩份完整源代碼,sysproc.c、sysproc_now.c,前者演示Gary Nebbett的
辦法,後者演示Ashot Oganesyan K的辦法。

Ashot Oganesyan K的源代碼隻支持到2K,不清楚這位達人是否自己更新過,google
居然搜不到所提源代碼(再次感謝sparrow共享),沒辦法,我隻好自己增加了對XP和
2003 Server的支持。此外為方便使用,sysproc_now.c自己找出winlogon.exe的PID,
不必在命令行上指定擁有SYSTEM權限的PID了。

sysproc.c

Gary Nebbett的中心思想就是利用ZwCreateToken()自己創建一個SYSTEM令牌(Token),
作為CreateProcessAsUser()第一形參使用。這個想法很好,我也費了好大勁去讀令
牌相關的各類技術文檔,可是到2K/XP環境中實測時卻未達到預定效果。

開始完全按照Gary Nebbett所述編碼,2K中ZwCreateToken()失敗返回,說當前帳號
沒有足夠的權限。XP中說當前帳號不能指派為所偽造的SYSTEM令牌的所有者(Owner)。
關於這點參sysproc.c/CreateSystemToken()函數中的注釋,從中也可看出XP比2K多
做了一些安全檢查。後來統一使用sysproc.c中演示的方式,這下都成了權限不夠的
錯誤提示。

知道調用ZwCreateToken()需要SE_CREATE_TOKEN_NAME權限,因此在程序中Enable了
該權限,當時相關的代碼路徑上並未提示Enable失敗。因此對"權限不夠"感到非常困
惑。鑒於我對Privilege理解不足,幹脆不管三七二十一先將winnt.h中所列權限全部
Enable了,還是同樣的下場。由此我才想到Administrator是否缺省並未被Grant某些
權限,AdjustTokenPrivileges()隻能Enable/Disable那些已經Grant的權限,比如前
麵所提的SE_DEBUG_NAME權限,並不能Grant權限。正好rain來北京,我們聚了兩天,
順帶就此問題請教了rain和flier。rain為sysproc.c增加了一段代碼,顯示當前帳號
所擁有的權限,參CreateSystemToken()函數。從中發現Administrator果然沒有所需
的SE_CREATE_TOKEN_NAME權限。rain告訴我,2K/XP中這種權限需要顯式指派,也就
是"本地安全策略/用戶權利指派"所做的事,NT是否需要顯式指派我未證實過。缺省
情況下,CreateProcessAsUser()所需SE_ASSIGNPRIMARYTOKEN_NAME權限也未被指派
給管理員帳號。這兩種權限在"本地安全策略/用戶權利指派"中對應:

SE_CREATE_TOKEN_NAME     - Create a token object
SE_ASSIGNPRIMARYTOKEN_NAME - Replace a process level token

在此加深了對AdjustTokenPrivileges()的記憶。開始對MSDN中的描述並無感性認識,
隻判斷返回值為FALSE,而未判斷GetLastError()為ERROR_NOT_ALL_ASSIGNED的情況,
導致當時相關的代碼路徑上並未提示Enable失敗。

為管理員帳號手工增加這兩種權限,注銷並重新登錄後,Gary Nebbett的目的達到了。

可以不利用"本地安全策略/用戶權利指派",而是自己編程實現這個步驟([2])。利用
LsaOpenPolicy()、LsaAddAccountRights()即可,AddPrivilege()演示了這個過程。

但問題是無論如何都必須注銷/重登錄才會生效。這對我來說,事實上已經失去了利
用價值,我需要的是立即(now)獲取SYSTEM權限。

可能有人由ZwCreateToken()聯想到LogonUser(),關於後者可以參看[3]、[4],那不
是我需要的東西。

下麵給出sysproc.c的完整源代碼,秉承一貫風格,以不建工程(Solution/Project)
直接命令行編譯為原則。注釋相當冗長,那是寫給我本人看的,對這些API特別不熟,
不寫個注釋在附近,下次看不懂是很正常的事,誰讓該死的Windows API這麼多形參。

--------------------------------------------------------------------------
/*
* For x86/EWindows XP SP1 & VC 7
* cl sysproc.c /Os /G6 /W3
*
* Gary Nebbett
* rain
*/

/************************************************************************
*                                               *
*                     Head File                     *
*                                               *
************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <ntsecapi.h>

/************************************************************************
*                                               *
*                     Macro                       *
*                                               *
************************************************************************/

#pragma comment( linker, "/subsystem:console" )
#pragma comment( lib,   "advapi32.lib"     )

typedef LONG NTSTATUS;

/*
* you'll find a list of NTSTATUS status codes in the DDK header
* ntstatus.h (/WINDDK/2600.1106/inc/ddk/wxp/)
*/
#define NT_SUCCESS(status)       ((NTSTATUS)(status)>=0)
#define STATUS_SUCCESS         ((NTSTATUS)0x00000000L)

/*
*************************************************************************
* ntdef.h
*/

typedef struct _OBJECT_ATTRIBUTES
{
  ULONG       Length;
  HANDLE       RootDirectory;
  PUNICODE_STRING ObjectName;
  ULONG       Attributes;
  PVOID       SecurityDescriptor;
  PVOID       SecurityQualityOfService;
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;

/*
* ntdef.h
*************************************************************************
*/

/*
* 參看DDK文檔以及<<Windows NT/2000 Native API Reference>> - Gary Nebbett
* 這些Native API由ntdll.dll輸出
*/
typedef ULONG   ( __stdcall *RTLNTSTATUSTODOSERROR ) ( IN NTSTATUS Status );
typedef NTSTATUS ( __stdcall *ZWCREATETOKEN       ) ( OUT PHANDLE TokenHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN TOKEN_TYPE Type, IN PLUID AuthenticationId, IN PLARGE_INTEGER ExpirationTime, IN PTOKEN_USER User, IN PTOKEN_GROUPS Groups, IN PTOKEN_PRIVILEGES Privileges, IN PTOKEN_OWNER Owner, IN PTOKEN_PRIMARY_GROUP PrimaryGroup, IN PTOKEN_DEFAULT_DACL DefaultDacl, IN PTOKEN_SOURCE Source );

/************************************************************************
*                                               *
*                   Function Prototype                 *
*                                               *
************************************************************************/

static BOOL   AddCurrentProcessPrivilege
                    ( LPWSTR PrivilegeName );
static BOOL   AddPrivilege     ( LSA_HANDLE PolicyHandle,
                      PSID AccountSid, LPWSTR PrivilegeName );
static HANDLE CreateSystemToken ( void );
static BOOL   DisableCurrentProcessSomePrivilege
                    ( void );
static BOOL   EnableCurrentProcessSomePrivilege
                    ( void );
static PVOID GetFromToken     ( HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass );
static BOOL   LocateNtdllEntry ( void );
static void   PrintWin32Error   ( char *message, DWORD dwMessageId );
static void   PrintZwError     ( char *message, NTSTATUS status );
static BOOL   RemoveCurrentProcessPrivilege
                    ( LPWSTR PrivilegeName );
static BOOL   RemovePrivilege   ( LSA_HANDLE PolicyHandle,
                      PSID AccountSid, LPWSTR PrivilegeName );
static BOOL   SetCurrentProcessPrivilege
                    ( LPCTSTR PrivilegeName, BOOL EnableFlag );
static BOOL   SetPrivilege     ( HANDLE TokenHandle, LPCTSTR PrivilegeName,
                      BOOL EnableFlag );

/************************************************************************
*                                               *
*                   Static Global Var                 *
*                                               *
************************************************************************/

/*
* 由ntdll.dll輸出的Native API函數指針
*/
static RTLNTSTATUSTODOSERROR RtlNtStatusToDosError = NULL;
static ZWCREATETOKEN       ZwCreateToken       = NULL;

/************************************************************************/

static BOOL AddCurrentProcessPrivilege ( LPWSTR PrivilegeName )
{
  NTSTATUS         status;
  BOOL             ret           = FALSE;
  LSA_HANDLE         PolicyHandle     = NULL;
  LSA_OBJECT_ATTRIBUTES ObjectAttributes;
  HANDLE           CurrentProcessToken = NULL;
  PTOKEN_USER       token_user       = NULL;

  ZeroMemory( &ObjectAttributes, sizeof( ObjectAttributes ) );
  /*
  * NTSTATUS LsaOpenPolicy
  * (
  *   PLSA_UNICODE_STRING   SystemName,
  *   PLSA_OBJECT_ATTRIBUTES ObjectAttributes,
  *   ACCESS_MASK         DesiredAccess,
  *   PLSA_HANDLE         PolicyHandle
  * );
  */
  status = LsaOpenPolicy( NULL, &ObjectAttributes, POLICY_ALL_ACCESS, &PolicyHandle );
  if ( status != STATUS_SUCCESS )
  {
    PrintWin32Error( "LsaOpenPolicy() failed", LsaNtStatusToWinError( status ) );
    goto AddCurrentProcessPrivilege_exit;
  }
  if ( FALSE == OpenProcessToken( GetCurrentProcess(),
                        TOKEN_QUERY,
                        &CurrentProcessToken ) )
  {
    PrintWin32Error( "OpenProcessToken() failed", GetLastError() );
    goto AddCurrentProcessPrivilege_exit;
  }
  if ( NULL == ( token_user = ( PTOKEN_USER )GetFromToken( CurrentProcessToken, TokenUser ) ) )
  {
    goto AddCurrentProcessPrivilege_exit;
  }
  if ( FALSE == AddPrivilege( PolicyHandle,
                    token_user->User.Sid,
                    PrivilegeName ) )
  {
    goto AddCurrentProcessPrivilege_exit;
  }
  ret   = TRUE;

AddCurrentProcessPrivilege_exit:

  if ( NULL != token_user )
  {
    free( token_user );
    token_user = NULL;
  }
  if ( NULL != CurrentProcessToken )
  {
    CloseHandle( CurrentProcessToken );
    CurrentProcessToken = NULL;
  }
  if ( NULL != PolicyHandle )
  {
    LsaClose( PolicyHandle );
    PolicyHandle = NULL;
  }
  return( ret );
} /* end of AddCurrentProcessPrivilege */

/*
* 留心第二形參是寬字符串
*/
static BOOL AddPrivilege ( LSA_HANDLE PolicyHandle, PSID AccountSid, LPWSTR PrivilegeName )
{
  BOOL           ret = FALSE;
  LSA_UNICODE_STRING UserRights;
  USHORT         StringLength;
  NTSTATUS       status;

  if ( PrivilegeName == NULL )
  {
    goto AddPrivilege_exit;
  }
  StringLength         = wcslen( PrivilegeName );
  UserRights.Buffer     = PrivilegeName;
  UserRights.Length     = StringLength * sizeof( WCHAR );
  UserRights.MaximumLength = ( StringLength + 1 ) * sizeof( WCHAR );
  /*
  * Header : Declared in Ntsecapi.h.
  * Library: Use Advapi32.lib.
  *
  * NTSTATUS LsaAddAccountRights
  * (
  *   LSA_HANDLE       PolicyHandle,
  *   PSID           AccountSid,
  *   PLSA_UNICODE_STRING UserRights,
  *   ULONG           CountOfRights
  * );
  */
  status             = LsaAddAccountRights( PolicyHandle, AccountSid, &UserRights, 1 );
  if ( status != STATUS_SUCCESS )
  {
    PrintWin32Error( "LsaAddAccountRights() failed", LsaNtStatusToWinError( status ) );
    goto AddPrivilege_exit;
  }
  ret               = TRUE;

AddPrivilege_exit:

  return( ret );
} /* end of AddPrivilege */

static HANDLE CreateSystemToken ( void )
{
  NTSTATUS             status;
  HANDLE               CurrentProcessToken       = NULL;
  HANDLE               SystemToken           = NULL;
  SID_IDENTIFIER_AUTHORITY   sid_identifier_authority   = SECURITY_NT_AUTHORITY;
  PTOKEN_PRIVILEGES       token_privileges         = NULL;
  /*
  * typedef struct _TOKEN_USER
  * {
  *   SID_AND_ATTRIBUTES User;
  * } TOKEN_USER, *PTOKEN_USER;
  *
  * typedef struct _SID_AND_ATTRIBUTES
  * {
  *   PSID Sid;
  *   DWORD Attributes;
  * } SID_AND_ATTRIBUTES, *PSID_AND_ATTRIBUTES;
  */
  TOKEN_USER             token_user             = { { NULL, 0 } };
  /*
  * typedef struct _TOKEN_SOURCE
  * {
  *   Char SourceName[8];
  *   LUID SourceIdentifier;
  * } TOKEN_SOURCE, *PTOKEN_SOURCE;
  *
  * typedef struct _LUID
  * {
  *   DWORD LowPart;
  *   LONG HighPart;
  * } LUID, *PLUID;
  */
  TOKEN_SOURCE           token_source           =
  {
    { '*', '*', 'A', 'N', 'O', 'N', '*', '*' },
    { 0, 0 }
  };
  /*
  * typedef struct _TOKEN_STATISTICS
  * {
  *   LUID                 TokenId;
  *   LUID                 AuthenticationId;
  *   LARGE_INTEGER           ExpirationTime;
  *   TOKEN_TYPE             TokenType;
  *   SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
  *   DWORD                 DynamicCharged;
  *   DWORD                 DynamicAvailable;
  *   DWORD                 GroupCount;
  *   DWORD                 PrivilegeCount;
  *   LUID                 ModifiedId;
  * } TOKEN_STATISTICS, *PTOKEN_STATISTICS;
  */
  PTOKEN_STATISTICS       token_statistics         = NULL;
  /*
  * typedef struct _TOKEN_OWNER
  * {
  *   PSID Owner;
  * } TOKEN_OWNER, *PTOKEN_OWNER;
  */
  TOKEN_OWNER           token_owner           = { NULL };
  LUID                 AuthenticationId         = SYSTEM_LUID;
  /*
  * typedef struct _SECURITY_QUALITY_OF_SERVICE
  * {
  *   DWORD                 Length;
  *   SECURITY_IMPERSONATION_LEVEL   ImpersonationLevel;
  *   SECURITY_CONTEXT_TRACKING_MODE ContextTrackingMode;
  *   BOOLEAN                 EffectiveOnly;
  * } SECURITY_QUALITY_OF_SERVICE, *PSECURITY_QUALITY_OF_SERVICE;
  */
  SECURITY_QUALITY_OF_SERVICE security_quality_of_service =
  {
    sizeof( security_quality_of_service ),
    SecurityAnonymous,
    // SecurityDelegation,
    SECURITY_STATIC_TRACKING,
    FALSE
  };
  OBJECT_ATTRIBUTES       object_attributes       =
  {
    sizeof( object_attributes ),
    NULL,
    NULL,
    0,
    NULL,
    &security_quality_of_service
  };
  DWORD               PrivilegeCount;
  char                 PrivilegeName[256];
  char                 PrivilegeDisplayName[256];
  DWORD               NameSize;
  DWORD               LanguageId;

  if ( FALSE == OpenProcessToken( GetCurrentProcess(),
                        TOKEN_QUERY | TOKEN_QUERY_SOURCE,
                        &CurrentProcessToken ) )
  {
    PrintWin32Error( "OpenProcessToken() failed", GetLastError() );
    goto CreateSystemToken_exit;
  }
  /*
  * BOOL AllocateAndInitializeSid
  * (
  *   PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,
  *   BYTE               nSubAuthorityCount,
  *   DWORD               dwSubAuthority0,
  *   DWORD               dwSubAuthority1,
  *   DWORD               dwSubAuthority2,
  *   DWORD               dwSubAuthority3,
  *   DWORD               dwSubAuthority4,
  *   DWORD               dwSubAuthority5,
  *   DWORD               dwSubAuthority6,
  *   DWORD               dwSubAuthority7,
  *   PSID               *pSid
  * );
  */
  if ( FALSE == AllocateAndInitializeSid( &sid_identifier_authority,
                            1,
                            SECURITY_LOCAL_SYSTEM_RID,
                            0,
                            0,
                            0,
                            0,
                            0,
                            0,
                            0,
                            &token_user.User.Sid ) )
  {
    PrintWin32Error( "AllocateAndInitializeSid() failed", GetLastError() );
    goto CreateSystemToken_exit;
  }
  token_owner.Owner = token_user.User.Sid;
  AllocateLocallyUniqueId( &token_source.SourceIdentifier );
  if ( NULL == ( token_statistics = ( PTOKEN_STATISTICS )GetFromToken( CurrentProcessToken, TokenStatistics ) ) )
  {
    goto CreateSystemToken_exit;
  }
  token_privileges = GetFromToken( CurrentProcessToken, TokenPrivileges );
  for ( PrivilegeCount = 0; PrivilegeCount < token_privileges->PrivilegeCount; PrivilegeCount++ )
  {
    /*
      * BOOL LookupPrivilegeName
      * (
      *   LPCTSTR lpSystemName,
      *   PLUID   lpLuid,
      *   LPTSTR lpName,
      *   LPDWORD cbName
      * );
      *
      * BOOL LookupPrivilegeDisplayName
      * (
      *   LPCTSTR lpSystemName,
      *   LPCTSTR lpName,
      *   LPTSTR lpDisplayName,
      *   LPDWORD cbDisplayName,
      *   LPDWORD lpLanguageId
      * );
      */
    NameSize = sizeof( PrivilegeName );
    if ( FALSE == LookupPrivilegeName( NULL, &token_privileges->Privileges[PrivilegeCount].Luid,
                            PrivilegeName, &NameSize ) )
    {
        PrintWin32Error( "LookupPrivilegeName() failed", GetLastError() );
        goto CreateSystemToken_exit;
    }
    NameSize = sizeof( PrivilegeDisplayName );
    if ( FALSE == LookupPrivilegeDisplayName( NULL, PrivilegeName, PrivilegeDisplayName,
                                &NameSize, &LanguageId ) )
    {
        PrintWin32Error( "LookupPrivilegeDisplayName() failed", GetLastError() );
        goto CreateSystemToken_exit;
    }
    printf( "%40s (%s)/n", PrivilegeDisplayName, PrivilegeName );
  } /* end of for */
  status = ZwCreateToken
        (
          &SystemToken,
          TOKEN_ALL_ACCESS,
          &object_attributes,
          TokenPrimary,
          // &token_statistics->AuthenticationId,
          &AuthenticationId,
          &token_statistics->ExpirationTime,
          &token_user,
          GetFromToken( CurrentProcessToken, TokenGroups ),
          //GetFromToken( CurrentProcessToken, TokenPrivileges ),
          token_privileges,
          //
          // GetFromToken( CurrentProcessToken, TokenOwner ),
          //
          // XP中如果像上麵這樣編碼,就會導致如下錯誤信息,
          // ZwCreateToken() failed: 這個安全 ID 不能指派為此對象的所有者。
          // 2K中可以像上麵這樣編碼。
          //
          &token_owner,
          GetFromToken( CurrentProcessToken, TokenPrimaryGroup ),
          GetFromToken( CurrentProcessToken, TokenDefaultDacl ),
          &token_source
        );
  if ( !NT_SUCCESS( status ) )
  {
    PrintZwError( "ZwCreateToken() failed", status );
    goto CreateSystemToken_exit;
  }

CreateSystemToken_exit:

  if ( token_user.User.Sid != NULL )
  {
    FreeSid( token_user.User.Sid );
    token_user.User.Sid = NULL;
  }
  if ( CurrentProcessToken != NULL )
  {
    CloseHandle( CurrentProcessToken );
    CurrentProcessToken = NULL;
  }
  return( SystemToken );
} /* end of CreateSystemToken */

static BOOL DisableCurrentProcessSomePrivilege ( void )
{
  SetCurrentProcessPrivilege( SE_CREATE_TOKEN_NAME, FALSE );
  SetCurrentProcessPrivilege( SE_ASSIGNPRIMARYTOKEN_NAME, FALSE );
  RemoveCurrentProcessPrivilege( L"SeCreateTokenPrivilege" );
  RemoveCurrentProcessPrivilege( L"SeAssignPrimaryTokenPrivilege" );
  return( TRUE );
} /* end of DisableCurrentProcessSomePrivilege */

static BOOL EnableCurrentProcessSomePrivilege ( void )
{
  /*
  * 對於2K、XP來說,這兩種特權缺省並未賦予Administrator用戶。下麵這兩行
  * 代碼也就是"本地安全策略/用戶權利指派"所做的事,因此同樣需要注銷重登
  * 錄後才能生效,實際上失去了利用價值。
  */
  AddCurrentProcessPrivilege( L"SeCreateTokenPrivilege" );
  AddCurrentProcessPrivilege( L"SeAssignPrimaryTokenPrivilege" );
  SetCurrentProcessPrivilege( SE_CREATE_TOKEN_NAME, TRUE );
  SetCurrentProcessPrivilege( SE_ASSIGNPRIMARYTOKEN_NAME, TRUE );
  return( TRUE );
} /* end of EnableCurrentProcessSomePrivilege */

static PVOID GetFromToken ( HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass )
{
  DWORD needed = 0;
  PVOID buf   = NULL;
  DWORD error;
  BOOL errflag = FALSE;

  /*
  * BOOL GetTokenInformation
  * (
  *   HANDLE             TokenHandle,
  *   TOKEN_INFORMATION_CLASS TokenInformationClass,
  *   LPVOID             TokenInformation,
  *   DWORD             TokenInformationLength,
  *   PDWORD             ReturnLength
  * );
  */
  if ( FALSE == GetTokenInformation( TokenHandle, TokenInformationClass, NULL, 0, &needed ) )
  {
    error = GetLastError();
    if ( error != ERROR_INSUFFICIENT_BUFFER )
    {
        PrintWin32Error( "GetTokenInformation() failed", error );
        errflag = TRUE;
        goto GetFromToken_exit;
    }
  }
  if ( NULL == ( buf = calloc( needed, 1 ) ) )
  {
    fprintf( stderr, "calloc( %u, 1 ) failed/n", needed );
    goto GetFromToken_exit;
  }
  if ( FALSE == GetTokenInformation( TokenHandle, TokenInformationClass, buf, needed, &needed ) )
  {
    PrintWin32Error( "GetTokenInformation() failed", GetLastError() );
    errflag = TRUE;
    goto GetFromToken_exit;
  }

GetFromToken_exit:

  if ( errflag == TRUE )
  {
    if ( buf != NULL )
    {
        free( buf );
        buf = NULL;
    }
  }
  return( buf );
} /* end of GetFromToken */

/*
* ntdll.dll輸出了所有的Native API
*/
static BOOL LocateNtdllEntry ( void )
{
  BOOLEAN bool_ret   = FALSE;
  char   NTDLL_DLL[] = "ntdll.dll";
  HMODULE ntdll_dll   = NULL;

  /*
  * returns a handle to a mapped module without incrementing its
  * reference count
  */
  if ( ( ntdll_dll = GetModuleHandle( NTDLL_DLL ) ) == NULL )
  {
    PrintWin32Error( "GetModuleHandle() failed", GetLastError() );
    return( FALSE );
  }
  if ( !( RtlNtStatusToDosError = ( RTLNTSTATUSTODOSERROR )GetProcAddress( ntdll_dll, "RtlNtStatusToDosError" ) ) )
  {
    goto LocateNtdllEntry_return;
  }
  if ( !( ZwCreateToken = ( ZWCREATETOKEN )GetProcAddress( ntdll_dll, "ZwCreateToken" ) ) )
  {
    goto LocateNtdllEntry_return;
  }
  bool_ret = TRUE;

LocateNtdllEntry_return:

  if ( FALSE == bool_ret )
  {
    PrintWin32Error( "GetProcAddress() failed", GetLastError() );
  }
  ntdll_dll = NULL;
  return( bool_ret );
} /* end of LocateNtdllEntry */

static void PrintWin32Error ( char *message, DWORD dwMessageId )
{
  char *errMsg;

  FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
            dwMessageId,
            MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
            ( LPTSTR )&errMsg, 0, NULL );
  fprintf( stderr, "%s: %s", message, errMsg );
  LocalFree( errMsg );
  return;
} /* end of PrintWin32Error */

static void PrintZwError ( char *message, NTSTATUS status )
{
  char *errMsg;

  FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
            RtlNtStatusToDosError( status ),
            MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
            ( LPTSTR )&errMsg, 0, NULL );
  fprintf( stderr, "%s: %s", message, errMsg );
  LocalFree( errMsg );
  return;
} /* end of PrintZwError */

static BOOL RemoveCurrentProcessPrivilege ( LPWSTR PrivilegeName )
{
  NTSTATUS         status;
  BOOL             ret           = FALSE;
  LSA_HANDLE         PolicyHandle     = NULL;
  LSA_OBJECT_ATTRIBUTES ObjectAttributes;
  HANDLE           CurrentProcessToken = NULL;
  PTOKEN_USER       token_user       = NULL;

  ZeroMemory( &ObjectAttributes, sizeof( ObjectAttributes ) );
  /*
  * NTSTATUS LsaOpenPolicy
  * (
  *   PLSA_UNICODE_STRING   SystemName,
  *   PLSA_OBJECT_ATTRIBUTES ObjectAttributes,
  *   ACCESS_MASK         DesiredAccess,
  *   PLSA_HANDLE         PolicyHandle
  * );
  */
  status = LsaOpenPolicy( NULL, &ObjectAttributes, POLICY_ALL_ACCESS, &PolicyHandle );
  if ( status != STATUS_SUCCESS )
  {
    PrintWin32Error( "LsaOpenPolicy() failed", LsaNtStatusToWinError( status ) );
    goto RemoveCurrentProcessPrivilege_exit;
  }
  if ( FALSE == OpenProcessToken( GetCurrentProcess(),
                        TOKEN_QUERY,
                        &CurrentProcessToken ) )
  {
    PrintWin32Error( "OpenProcessToken() failed", GetLastError() );
    goto RemoveCurrentProcessPrivilege_exit;
  }
  if ( NULL == ( token_user = ( PTOKEN_USER )GetFromToken( CurrentProcessToken, TokenUser ) ) )
  {
    goto RemoveCurrentProcessPrivilege_exit;
  }
  if ( FALSE == RemovePrivilege( PolicyHandle,
                      token_user->User.Sid,
                      PrivilegeName ) )
  {
    goto RemoveCurrentProcessPrivilege_exit;
  }
  ret   = TRUE;

RemoveCurrentProcessPrivilege_exit:

  if ( NULL != token_user )
  {
    free( token_user );
    token_user = NULL;
  }
  if ( NULL != CurrentProcessToken )
  {
    CloseHandle( CurrentProcessToken );
    CurrentProcessToken = NULL;
  }
  if ( NULL != PolicyHandle )
  {
    LsaClose( PolicyHandle );
    PolicyHandle = NULL;
  }
  return( ret );
} /* end of RemoveCurrentProcessPrivilege */

static BOOL RemovePrivilege ( LSA_HANDLE PolicyHandle, PSID AccountSid, LPWSTR PrivilegeName )
{
  BOOL           ret = FALSE;
  LSA_UNICODE_STRING UserRights;
  USHORT         StringLength;
  NTSTATUS       status;

  if ( PrivilegeName == NULL )
  {
    goto RemovePrivilege_exit;
  }
  StringLength         = wcslen( PrivilegeName );
  UserRights.Buffer     = PrivilegeName;
  UserRights.Length     = StringLength * sizeof( WCHAR );
  UserRights.MaximumLength = ( StringLength + 1 ) * sizeof( WCHAR );
  /*
  * Header : Declared in Ntsecapi.h.
  * Library: Use Advapi32.lib.
  *
  * NTSTATUS LsaRemoveAccountRights
  * (
  *   LSA_HANDLE       PolicyHandle,
  *   PSID           AccountSid,
  *   BOOLEAN         AllRights,
  *   PLSA_UNICODE_STRING UserRights,
  *   ULONG           CountOfRights
  * );
  */
  status             = LsaRemoveAccountRights( PolicyHandle, AccountSid, FALSE, &UserRights, 1 );
  if ( status != STATUS_SUCCESS )
  {
    PrintWin32Error( "LsaRemoveAccountRights() failed", LsaNtStatusToWinError( status ) );
    goto RemovePrivilege_exit;
  }
  ret               = TRUE;

RemovePrivilege_exit:

  return( ret );
} /* end of RemovePrivilege */

static BOOL SetCurrentProcessPrivilege ( LPCTSTR PrivilegeName, BOOL EnableFlag )
{
  HANDLE TokenHandle = ( HANDLE )-1;
  BOOL   ret       = TRUE;

  /*
  * Header : Declared in Winbase.h; include Windows.h.
  * Library: Use Advapi32.lib.
  *
  * BOOL OpenProcessToken
  * (
  *   HANDLE ProcessHandle,
  *   DWORD   DesiredAccess,
  *   PHANDLE TokenHandle
  * );
  */
  if ( FALSE == OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &TokenHandle ) )
  {
    PrintWin32Error( "OpenProcessToken() failed", GetLastError() );
    ret = FALSE;
    goto SetCurrentProcessPrivilege_exit;
  }
  ret = SetPrivilege( TokenHandle, PrivilegeName, EnableFlag );

SetCurrentProcessPrivilege_exit:

  if ( TokenHandle != ( HANDLE )-1 )
  {
    CloseHandle( TokenHandle );
    TokenHandle = ( HANDLE )-1;
  }
  return( ret );
} /* end of SetCurrentProcessPrivilege */

static BOOL SetPrivilege ( HANDLE TokenHandle, LPCTSTR PrivilegeName, BOOL EnableFlag )
{
  DWORD         error;
  BOOL         ret = TRUE;
  /*
  *
  * typedef struct _TOKEN_PRIVILEGES
  * {
  *   DWORD           PrivilegeCount;
  *   LUID_AND_ATTRIBUTES Privileges[];
  * } TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES;
  *
  * typedef struct _LUID_AND_ATTRIBUTES
  * {
  *   LUID Luid;
  *   DWORD Attributes;
  * } LUID_AND_ATTRIBUTES, *PLUID_AND_ATTRIBUTES;
  */
  TOKEN_PRIVILEGES tp =
  {
    1,
    {
        { { 0, 0 }, 0 }
    }
  };

  if ( EnableFlag == TRUE )
  {
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  }
  /*
  * BOOL LookupPrivilegeValue
  * (
  *   LPCTSTR lpSystemName,
  *   LPCTSTR lpName,
  *   PLUID   lpLuid
  * );
  *
  * 第二形參的可取值在winnt.h中有定義,"NT Defined Privileges"
  */
  if ( FALSE == LookupPrivilegeValue( NULL, PrivilegeName, &tp.Privileges[0].Luid ) )
  {
    PrintWin32Error( "LookupPrivilegeValue() failed", GetLastError() );
    ret = FALSE;
    goto SetPrivilege_exit;
  }
  /*
  * BOOL AdjustTokenPrivileges
  * (
  *   HANDLE         TokenHandle,
  *   BOOL         DisableAllPrivileges,
  *   PTOKEN_PRIVILEGES NewState,
  *   DWORD         BufferLength,
  *   PTOKEN_PRIVILEGES PreviousState,
  *   PDWORD         ReturnLength
  * );
  *
  * The AdjustTokenPrivileges function cannot add new privileges to the
  * access token. It can only enable or disable the token's existing
  * privileges. To determine the token's privileges, call the
  * GetTokenInformation function.
  */
  if ( FALSE == AdjustTokenPrivileges( TokenHandle, FALSE, &tp, sizeof( tp ), NULL, NULL ) )
  {
    PrintWin32Error( "AdjustTokenPrivileges() failed", GetLastError() );
    ret = FALSE;
    goto SetPrivilege_exit;
  }
  else
  {
    error = GetLastError();
    /*
      * 這種情況帶來的誤判很隱蔽,務必留心。
      *
      * ERROR_NOT_ALL_ASSIGNED
      */
    if ( ERROR_SUCCESS != error )
    {
        PrintWin32Error( "AdjustTokenPrivileges() failed", error );
        ret = FALSE;
        goto SetPrivilege_exit;
    }
  }

SetPrivilege_exit:

  return( ret );
} /* end of SetPrivilege */

int main ( int argc, char * argv[] )
{
  STARTUPINFO       si = { sizeof( si ) };
  PROCESS_INFORMATION pi;

  if ( 2 != argc )
  {
    fprintf( stderr, "Usage: %s <command line>/n", argv[0] );
    return( EXIT_FAILURE );
  }
  if ( FALSE == LocateNtdllEntry() )
  {
    fprintf( stderr, "LocateNtdllEntry() failed/n" );
    return( EXIT_FAILURE );
  }
  EnableCurrentProcessSomePrivilege();
  /*
  * Header : Declared in Winbase.h; include Windows.h.
  * Library: Use Advapi32.lib.
  *
  * BOOL CreateProcessAsUser
  * (
  *   HANDLE           hToken,           // handle to user token
  *   LPCTSTR           lpApplicationName,   // name of executable module
  *   LPTSTR           lpCommandLine,     // command-line string
  *   LPSECURITY_ATTRIBUTES lpProcessAttributes, // SD
  *   LPSECURITY_ATTRIBUTES lpThreadAttributes,   // SD
  *   BOOL             bInheritHandles,     // inheritance option
  *   DWORD           dwCreationFlags,     // creation flags
  *   LPVOID           lpEnvironment,     // new environment block
  *   LPCTSTR           lpCurrentDirectory,   // current directory name
  *   LPSTARTUPINFO       lpStartupInfo,     // startup information
  *   LPPROCESS_INFORMATION lpProcessInformation // process information
  * );
  *
  * Typically, the process that calls the CreateProcessAsUser function
  * must have the SE_ASSIGNPRIMARYTOKEN_NAME and SE_INCREASE_QUOTA_NAME
  * privileges.
  */
  if ( FALSE == CreateProcessAsUser
            (
              CreateSystemToken(),
              NULL,
              argv[1],
              NULL,
              NULL,
              FALSE,
              CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
              NULL,
              NULL,
              &si,
              &pi
            ) )
  {
    PrintWin32Error( "CreateProcessAsUser() failed", GetLastError() );
    return( EXIT_FAILURE );
  }
  /*
  * CreateProcessAsUser()無論是否成功,都返回。
  */
  DisableCurrentProcessSomePrivilege();
  /*
  * 主調進程馬上要退出了,懶得顯式關閉PROCESS_INFORMATION中的句柄,由操
  * 作係統隱式關閉去吧。事實上CreateSystemToken()中調用GetFromToken(),
  * 後者在堆區分配過內存,不過這次也不需要顯式釋放了。
  */
  return( EXIT_SUCCESS );
} /* end of main */

/************************************************************************/

--------------------------------------------------------------------------

如果第一次執行失敗,注銷/重登錄再次執行即可成功。如果第一次執行成功,注銷/
重登錄再次執行將會失敗。這隻是演示如何編程實現"本地安全策略/用戶權利指派"。

執行regedit,如果能看到下列內容,表示已經獲取SYSTEM權限:

HKEY_LOCAL_MACHINE/SAM/SAM/Domains/Builtin

缺省情況下,管理員帳號隻能看到:

HKEY_LOCAL_MACHINE/SAM/SAM

個人準備將sysproc.c扔進垃圾堆,離我所需相去甚遠。

sysproc_now.c

麻雀兄解釋了Ashot Oganesyan K的中心思想,Win32 API/CreateProcess()最終會調
用Native API/ZwCreateProcess(),後者的第四形參是InheritFromProcessHandle,
子進程的主令牌(Primary Token)繼承自這個進程句柄,一般情況下也就是父進程句
柄。將ZwCreateProcess()攔截(Hook),修改第四形參,使之對應一個擁有SYSTEM權
限的進程句柄,於是所創建的子進程將擁有SYSTEM權限。

我主要做了兩處改進。一是利用ZwQuerySystemInformation()自己找出winlogon.exe
的PID,並獲取進程句柄,從而不必在命令行上指定擁有SYSTEM權限的PID。二是增加
對XP、2003 Server的支持。

一開始我攔截ZwCreateProcess(),發現對於XP無效,懷疑CreateProcess()已經不調
用ZwCreateProcess()。增加了一點調試代碼,確認流程並未經過ZwCreateProcess()。
然後我就到處亂找能跟蹤係統調用的工具,最後用了BindView的strace工具([1])。
0.3版的strace為了在XP上使用,需要在注冊表中做如下設置,重啟後生效:

--------------------------------------------------------------------------
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Session Manager/Memory Management]
"EnforceWriteProtection"=dword:00000000
--------------------------------------------------------------------------

跟蹤結果中隻有NtCreateProcessEx(),而沒有NtCreateProcess()。於是我換成攔截
ZwCreateProcessEx(),搞定。

不清楚ZwCreateProcessEx()的函數原型是什麼,形參為九個,比ZwCreateProcess()
多一個。按照MS的一貫作風,應該不會動前八個形參,僅僅是擴展出第九個形參,因
此第四形參仍為InheritFromProcessHandle。ZwCreateProcess()的函數原型可參看
[5]。順便說一句,編寫、偵測rootkit時要留心XP/2003上的這種變化。

為了區分2000/XP/2003,用GetVersionEx()做精確的OS版本判斷。用IDA Pro 4.3.0
反匯編ntdll.dll即可找出下列信息:

--------------------------------------------------------------------------
XP

  ZwCreateProcess   2Fh
  ZwCreateProcessEx 30h

2003 Server

  ZwCreateProcess   31h
  ZwCreateProcessEx 32h
--------------------------------------------------------------------------

可能你看到的不是熟悉的int 2Eh,而類似如下代碼:

--------------------------------------------------------------------------
ZwCreateProcessEx proc near
  mov   eax, 32h
  mov   edx, 7FFE0300h
  call   edx
  retn   24h
ZwCreateProcessEx endp
--------------------------------------------------------------------------

0x7FFE0300處是什麼東西,用kd查看一下:

--------------------------------------------------------------------------
lkd> u 0x7ffe0300
SharedUserData!SystemCallStub:
7ffe0300 8bd4         mov   edx,esp
7ffe0302 0f34         sysenter
7ffe0304 c3           ret
--------------------------------------------------------------------------

這就是所謂"快速係統調用接口"。參看Intel卷II中對sysenter指令的解釋。VC 7不
支持sysenter,我用_emit直接嵌入機器碼。從Windows 2000/PII開始引入這個與傳
統int 2Eh並存的快速係統調用接口,但你硬是要用int 2Eh仍然可以成功。ntoskrnl
中與這兩種係統調用接口相對應的是KiFastCallEntry()、KiSystemService()。

--------------------------------------------------------------------------
lkd> u nt!KiFastCallEntry
nt!KiFastCallEntry:
8052d480 368b0d40f0dfff   mov   ecx,ss:[ffdff040]
8052d487 368b6104       mov   esp,ss:[ecx+0x4]
8052d48b b90403fe7f     mov   ecx,0x7ffe0304
8052d490 3b2504f0dfff   cmp   esp,[ffdff004]
8052d496 0f84ce030000   je     nt!KiServiceExit2+0x143 (8052d86a)
8052d49c 6a23         push   0x23
8052d49e 52           push   edx
8052d49f 83c208       add   edx,0x8
lkd> u nt!KiSystemService
nt!KiSystemService:
8052d4ad 6a00         push   0x0
8052d4af 55           push   ebp
8052d4b0 53           push   ebx
8052d4b1 56           push   esi
8052d4b2 57           push   edi
8052d4b3 0fa0         push   fs
8052d4b5 bb30000000     mov   ebx,0x30
8052d4ba 668ee3       mov   fs,bx
lkd>
--------------------------------------------------------------------------

要想攔截KiFastCallEntry(),可比攔截KiSystemService()複雜一些,關於這個就不
多解釋了,反正這次的主要目的也不是攔截內核空間的什麼東東。不過務必要記住這
件事,隻攔截KiSystemService()很可能會得出錯誤結論。

[6]是一份不錯的關於此方麵內容的文檔。

sysproc_now.c中演示了這兩種係統調用接口,但是用條件編譯注釋掉了其中一種,
你可以根據自己的愛好選用任一種,均可成功達到目的。

--------------------------------------------------------------------------
/*
* For x86/EWindows XP SP1 & VC 7
* cl sysproc_now.c /Os /G6 /W3
*
* Support for Windows NT3.51 NT4.0 2000
* (c)1999 Ashot Oganesyan K, SmartLine, Inc
* Ashot Oganesyan K <ashot@aha.ru>
*
* Add support for Windows XP/2003 by scz <scz@nsfocus.com>
* 2003-06-21 21:22
*/

/************************************************************************
*                                               *
*                     Head File                     *
*                                               *
************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>

/************************************************************************
*                                               *
*                     Macro                       *
*                                               *
************************************************************************/

#pragma comment( linker, "/subsystem:console" )
#pragma comment( lib,   "kernel32.lib"     )
#pragma comment( lib,   "advapi32.lib"     )

typedef LONG NTSTATUS;

/*
* you'll find a list of NTSTATUS status codes in the DDK header
* ntstatus.h (/WINDDK/2600.1106/inc/ddk/wxp/)
*/
#define NT_SUCCESS(status)       ((NTSTATUS)(status)>=0)
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)

/*
*************************************************************************
* ntddk.h
*/

typedef LONG KPRIORITY;

/*
* ntddk.h
*************************************************************************
*/

/*
*************************************************************************
* ntdef.h
*/

typedef struct _UNICODE_STRING
{
  USHORT Length;
  USHORT MaximumLength;
  PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

typedef struct _OBJECT_ATTRIBUTES
{
  ULONG       Length;
  HANDLE       RootDirectory;
  PUNICODE_STRING ObjectName;
  ULONG       Attributes;
  PVOID       SecurityDescriptor;
  PVOID       SecurityQualityOfService;
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;

/*
* ntdef.h
*************************************************************************
*/

/*
*************************************************************************
* <<Windows NT/2000 Native API Reference>> - Gary Nebbett
*/

typedef enum _SYSTEM_INFORMATION_CLASS
{
  SystemProcessesAndThreadsInformation = 5
} SYSTEM_INFORMATION_CLASS;

/*
* Information Class 5
*
* 為了便於編譯,我將InheritedFromProcessId之後的成員扔掉了
*/
typedef struct _SYSTEM_PROCESSES
{
  ULONG       NextEntryDelta;
  ULONG       ThreadCount;
  ULONG       Reserved1[6];
  LARGE_INTEGER CreateTime;
  LARGE_INTEGER UserTime;
  LARGE_INTEGER KernelTime;
  UNICODE_STRING ProcessName;
  KPRIORITY     BasePriority;
  ULONG       ProcessId;
  ULONG       InheritedFromProcessId;
} SYSTEM_PROCESSES, *PSYSTEM_PROCESSES;

/*
* <<Windows NT/2000 Native API Reference>> - Gary Nebbett
*************************************************************************
*/

/*
* 參看DDK文檔以及<<Windows NT/2000 Native API Reference>> - Gary Nebbett
* 這些Native API由ntdll.dll輸出
*/
typedef ULONG   ( __stdcall *RTLNTSTATUSTODOSERROR   ) ( IN NTSTATUS Status );
typedef NTSTATUS ( __stdcall *ZWCREATEPROCESS       ) ( OUT PHANDLE ProcessHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN HANDLE InheritFromProcessHandle, IN BOOLEAN InheritHandles, IN HANDLE SectionHandle OPTIONAL, IN HANDLE DebugPort OPTIONAL, IN HANDLE ExceptionPort OPTIONAL );
typedef NTSTATUS ( __stdcall *ZWQUERYSYSTEMINFORMATION ) ( IN SYSTEM_INFORMATION_CLASS SystemInformationClass, IN OUT PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength OPTIONAL );

#pragma pack(push, 1)

typedef struct
{
  unsigned char     mov_eax;
  void           *address;
  unsigned short int jmp_eax;
} ASMJUMP, *PASMJUMP;

#pragma pack(pop)

/************************************************************************
*                                               *
*                   Function Prototype                 *
*                                               *
************************************************************************/

static BOOL DisableCurrentProcessDebugPrivilege
                    ( void );
static BOOL EnableCurrentProcessDebugPrivilege
                    ( void );
static DWORD GetPidFromProcessName
                    ( wchar_t *ProcessName );
static BOOL LocateNtdllEntry ( void );
static void PrintWin32Error ( char *message, DWORD dwMessageId );
static void PrintZwError   ( char *message, NTSTATUS status );
static BOOL SetCurrentProcessPrivilege
                    ( LPCTSTR PrivilegeName, BOOL EnableFlag );
static BOOL SetPrivilege   ( HANDLE TokenHandle, LPCTSTR PrivilegeName,
                    BOOL EnableFlag );

/************************************************************************
*                                               *
*                   Static Global Var                 *
*                                               *
************************************************************************/

/*
* 由ntdll.dll輸出的Native API函數指針
*/
static RTLNTSTATUSTODOSERROR   RtlNtStatusToDosError   = NULL;
static ZWCREATEPROCESS       ZwCreateProcess       = NULL;
static ZWQUERYSYSTEMINFORMATION ZwQuerySystemInformation = NULL;
/*
* 這是XP/2003新增的Native API,總共九個形參,比ZwCreateProcess()多一個
*/
static PVOID             ZwCreateProcessEx     = NULL;

/*
* winlogon.exe的進程句柄
*/
static HANDLE             winlogon           = NULL;
static DWORD             ZwCreateProcessNum     = 0;
static DWORD             ZwCreateProcessExNum   = 0;

/************************************************************************/

static BOOL DisableCurrentProcessDebugPrivilege ( void )
{
  return( SetCurrentProcessPrivilege( SE_DEBUG_NAME, FALSE ) );
} /* end of DisableCurrentProcessDebugPrivilege */

static BOOL EnableCurrentProcessDebugPrivilege ( void )
{
  return( SetCurrentProcessPrivilege( SE_DEBUG_NAME, TRUE ) );
} /* end of EnableCurrentProcessDebugPrivilege */

static DWORD GetPidFromProcessName ( wchar_t *ProcessName )
{
  NTSTATUS       status;
  PVOID         buf   = NULL;
  ULONG         size = 1;
  PSYSTEM_PROCESSES proc = NULL;
  ULONG         delta = 0;
  DWORD         pid   = 0;

  for ( size = 1; ; size *= 2 )
  {
    if ( NULL == ( buf = calloc( size, 1 ) ) )
    {
        fprintf( stderr, "calloc( %u, 1 ) failed/n", size );
        goto GetPidFromProcessName_exit;
    }
    status = ZwQuerySystemInformation( SystemProcessesAndThreadsInformation, buf, size, NULL );
    if ( !NT_SUCCESS( status ) )
    {
        if ( STATUS_INFO_LENGTH_MISMATCH == status )
        {
          free( buf );
          buf = NULL;
        }
        else
        {
          PrintZwError( "ZwQuerySystemInformation() failed", status );
          goto GetPidFromProcessName_exit;
        }
    }
    else
    {
        /*
        * printf( "size = %u/n", size );
        */
        break;
    }
  } /* end of for */
  proc = ( PSYSTEM_PROCESSES )buf;
  do
  {
    if ( NULL != proc->ProcessName.Buffer )
    {
        if ( 0 == _wcsicmp( ProcessName, proc->ProcessName.Buffer ) )
        {
          pid = proc->ProcessId;
          break;
        }
    }
    delta = proc->NextEntryDelta;
    proc = ( PSYSTEM_PROCESSES )( ( char * )proc + delta );
  }
  while ( 0 != delta );

GetPidFromProcessName_exit:

  if ( buf != NULL )
  {
    free( buf );
    buf = NULL;
  }
  return( pid );
} /* end of GetPidFromProcessName */

static void __declspec(naked) HackedZwCreateProcess ( void )
{
  /*
  *********************************************************************
  * 這兩個__asm{}之間的代碼隻是調試代碼,沒有實際意義。
  */
  __asm
  {
    pushad
    pushfd
  }

  printf( "HackedZwCreateProcess()/n" );

  __asm
  {
    popfd
    popad
  }
  /*
  * 這兩個__asm{}之間的代碼隻是調試代碼,沒有實際意義。
  *********************************************************************
  */

  /*
  * 第四形參是InheritFromProcessHandle
  * [esp]是返回地址
  */
  __asm
  {
    mov   eax,winlogon
    mov   dword ptr [esp+16],eax
    /*
      * EAX是調用號
      */
    mov   eax,ZwCreateProcessNum
    /*
      * EDX指向形參區域
      */
    lea   edx,dword ptr [esp+4]
    int   2Eh
    /*
      * __stdcall調用風格,由被調函數自己負責堆棧平衡。
      */
    retn   20h
  }
} /* end of HackedZwCreateProcess */

#if 0
static void __declspec(naked) HackedZwCreateProcessEx ( void )
{
  /*
  *********************************************************************
  * 這兩個__asm{}之間的代碼隻是調試代碼,沒有實際意義。
  */
  __asm
  {
    pushad
    pushfd
  }

  printf( "HackedZwCreateProcessEx()/n" );

  __asm
  {
    popfd
    popad
  }
  /*
  * 這兩個__asm{}之間的代碼隻是調試代碼,沒有實際意義。
  *********************************************************************
  */

  /*
  * 第四形參是InheritFromProcessHandle
  * [esp]是返回地址
  */
  __asm
  {
    mov   eax,winlogon
    mov   dword ptr [esp+16],eax
    /*
      * EAX是調用號
      */
    mov   eax,ZwCreateProcessExNum
    /*
      * EDX指向形參區域
      */
    lea   edx,dword ptr [esp+4]
    int   2Eh
    /*
      * __stdcall調用風格,由被調函數自己負責堆棧平衡。注意這次有九個形
      * 參,平衡堆棧時要比前麵多彈一個DWORD。
      */
    retn   24h
  }
} /* end of HackedZwCreateProcessEx */
#endif

#if 0
static void __declspec(naked) HackedZwCreateProcessEx ( void )
{
  /*
  *********************************************************************
  * 這兩個__asm{}之間的代碼隻是調試代碼,沒有實際意義。
  */
  __asm
  {
    pushad
    pushfd
  }

  printf( "HackedZwCreateProcessEx()/n" );

  __asm
  {
    popfd
    popad
  }
  /*
  * 這兩個__asm{}之間的代碼隻是調試代碼,沒有實際意義。
  *********************************************************************
  */

  /*
  * 第四形參是InheritFromProcessHandle
  * [esp]是返回地址
  */
  __asm
  {
    mov   eax,winlogon
    mov   dword ptr [esp+16],eax
    /*
      * EAX是調用號
      */
    mov   eax,ZwCreateProcessExNum
    /*
      * lkd> u 0x7ffe0300
      * SharedUserData!SystemCallStub:
      * 7ffe0300 8bd4         mov   edx,esp
      * 7ffe0302 0f34         sysenter
      * 7ffe0304 c3           ret
      */
    mov   edx,7FFE0300h
    call   edx
    /*
      * __stdcall調用風格,由被調函數自己負責堆棧平衡。注意這次有九個形
      * 參,平衡堆棧時要比前麵多彈一個DWORD。
      */
    retn   24h
  }
} /* end of HackedZwCreateProcessEx */
#endif

/*
* 上麵被條件編譯注釋掉的兩段代碼均可工作於XP/2003上。int 2Eh是傳統係統調
* 用接口,sysenter是所謂"快速係統調用接口",參看Intel卷II中對該指令的解釋。
* VC 7不支持sysenter,我用_emit直接嵌入機器碼。
*/
static void __declspec(naked) HackedZwCreateProcessEx ( void )
{
  /*
  *********************************************************************
  * 這兩個__asm{}之間的代碼隻是調試代碼,沒有實際意義。
  */
  __asm
  {
    pushad
    pushfd
  }

  printf( "HackedZwCreateProcessEx()/n" );

  __asm
  {
    popfd
    popad
  }
  /*
  * 這兩個__asm{}之間的代碼隻是調試代碼,沒有實際意義。
  *********************************************************************
  */

  /*
  * 第四形參是InheritFromProcessHandle
  * [esp]是返回地址
  */
  __asm
  {
    mov   eax,winlogon
    mov   dword ptr [esp+16],eax
    /*
      * EAX是調用號
      */
    mov   eax,ZwCreateProcessExNum
    call   SystemCallStub
    retn   24h

SystemCallStub:

    mov   edx,esp
    /*
      * 0f34 sysenter
      */
    _emit   0x0f
    _emit   0x34
    ret
  }
} /* end of HackedZwCreateProcessEx */

/*
* ntdll.dll輸出了所有的Native API
*/
static BOOL LocateNtdllEntry ( void )
{
  BOOL   ret       = FALSE;
  char   NTDLL_DLL[] = "ntdll.dll";
  HMODULE ntdll_dll   = NULL;

  /*
  * returns a handle to a mapped module without incrementing its
  * reference count
  */
  if ( ( ntdll_dll = GetModuleHandle( NTDLL_DLL ) ) == NULL )
  {
    PrintWin32Error( "GetModuleHandle() failed", GetLastError() );
    return( FALSE );
  }
  if ( !( RtlNtStatusToDosError = ( RTLNTSTATUSTODOSERROR )GetProcAddress( ntdll_dll, "RtlNtStatusToDosError" ) ) )
  {
    goto LocateNtdllEntry_exit;
  }
  if ( !( ZwCreateProcess = ( ZWCREATEPROCESS )GetProcAddress( ntdll_dll, "ZwCreateProcess" ) ) )
  {
    goto LocateNtdllEntry_exit;
  }
  if ( !( ZwQuerySystemInformation = ( ZWQUERYSYSTEMINFORMATION )GetProcAddress( ntdll_dll, "ZwQuerySystemInformation" ) ) )
  {
    goto LocateNtdllEntry_exit;
  }
  if ( ZwCreateProcessExNum != 0 )
  {
    if ( !( ZwCreateProcessEx = ( PVOID )GetProcAddress( ntdll_dll, "ZwCreateProcessEx" ) ) )
    {
        goto LocateNtdllEntry_exit;
    }
  }
  ret = TRUE;

LocateNtdllEntry_exit:

  if ( FALSE == ret )
  {
    PrintWin32Error( "GetProcAddress() failed", GetLastError() );
  }
  ntdll_dll = NULL;
  return( ret );
} /* end of LocateNtdllEntry */

static void PrintWin32Error ( char *message, DWORD dwMessageId )
{
  char *errMsg;

  FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
            dwMessageId,
            MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
            ( LPTSTR )&errMsg, 0, NULL );
  fprintf( stderr, "%s: %s", message, errMsg );
  LocalFree( errMsg );
  return;
} /* end of PrintWin32Error */

static void PrintZwError ( char *message, NTSTATUS status )
{
  char *errMsg;

  FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
            RtlNtStatusToDosError( status ),
            MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
            ( LPTSTR )&errMsg, 0, NULL );
  fprintf( stderr, "%s: %s", message, errMsg );
  LocalFree( errMsg );
  return;
} /* end of PrintZwError */

static BOOL SetCurrentProcessPrivilege ( LPCTSTR PrivilegeName, BOOL EnableFlag )
{
  HANDLE TokenHandle = ( HANDLE )-1;
  BOOL   ret       = TRUE;

  /*
  * Header : Declared in Winbase.h; include Windows.h.
  * Library: Use Advapi32.lib.
  *
  * BOOL OpenProcessToken
  * (
  *   HANDLE ProcessHandle,
  *   DWORD   DesiredAccess,
  *   PHANDLE TokenHandle
  * );
  */
  if ( FALSE == OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &TokenHandle ) )
  {
    PrintWin32Error( "OpenProcessToken() failed", GetLastError() );
    ret = FALSE;
    goto SetCurrentProcessPrivilege_exit;
  }
  ret = SetPrivilege( TokenHandle, PrivilegeName, EnableFlag );

SetCurrentProcessPrivilege_exit:

  if ( TokenHandle != ( HANDLE )-1 )
  {
    CloseHandle( TokenHandle );
    TokenHandle = ( HANDLE )-1;
  }
  return( ret );
} /* end of SetCurrentProcessPrivilege */

static BOOL SetPrivilege ( HANDLE TokenHandle, LPCTSTR PrivilegeName, BOOL EnableFlag )
{
  DWORD         error;
  BOOL         ret = TRUE;
  /*
  *
  * typedef struct _TOKEN_PRIVILEGES
  * {
  *   DWORD           PrivilegeCount;
  *   LUID_AND_ATTRIBUTES Privileges[];
  * } TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES;
  *
  * typedef struct _LUID_AND_ATTRIBUTES
  * {
  *   LUID Luid;
  *   DWORD Attributes;
  * } LUID_AND_ATTRIBUTES, *PLUID_AND_ATTRIBUTES;
  */
  TOKEN_PRIVILEGES tp =
  {
    1,
    {
        { { 0, 0 }, 0 }
    }
  };

  if ( EnableFlag == TRUE )
  {
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  }
  /*
  * BOOL LookupPrivilegeValue
  * (
  *   LPCTSTR lpSystemName,
  *   LPCTSTR lpName,
  *   PLUID   lpLuid
  * );
  *
  * 第二形參的可取值在winnt.h中有定義,"NT Defined Privileges"
  */
  if ( FALSE == LookupPrivilegeValue( NULL, PrivilegeName, &tp.Privileges[0].Luid ) )
  {
    PrintWin32Error( "LookupPrivilegeValue() failed", GetLastError() );
    ret = FALSE;
    goto SetPrivilege_exit;
  }
  /*
  * BOOL AdjustTokenPrivileges
  * (
  *   HANDLE         TokenHandle,
  *   BOOL         DisableAllPrivileges,
  *   PTOKEN_PRIVILEGES NewState,
  *   DWORD         BufferLength,
  *   PTOKEN_PRIVILEGES PreviousState,
  *   PDWORD         ReturnLength
  * );
  *
  * The AdjustTokenPrivileges functio

最後更新:2017-04-02 00:06:22

  上一篇:go AnkhSVN 1.0.2778 簡體中文版
  下一篇:go AnkhSVN 1.0.2778 簡體中文版 截圖