首页  编辑  

以系统账户运行进程

Tags: /超级猛料/OS.操作系统/Process.进程/   Date Created:

How to create process as system privilege?

作者:lysoft 日期:2006-09-27

How to create process as system privilege?

here is a way to do this in kernel mode driver: (for WinXP/2003)

Hook undocumented API: ZwCreateProcessEx

then set the fouth parameter to SYSTEM handle info.

typedef NTSTATUS (*ZWCreatePROCESSEX)(

 OUT PHANDLE ProcessHandle,

 IN ACCESS_MASK DesiredAccess,

 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,

 IN HANDLE ParentProcess,

 IN BOOLEAN InheritObjectTable,

 IN HANDLE SectionHandle OPTIONAL,

 IN HANDLE DebugPort OPTIONAL,

 IN HANDLE ExceptionPort OPTIONAL,

 IN HANDLE Unknown );

ZWCreatePROCESSEX  OldZwCreateProcessEx;

NTSTATUS

NTAPI

ZwOpenProcess(OUT PHANDLE  ProcessHandle,  

 IN ACCESS_MASK  DesiredAccess,  

 IN POBJECT_ATTRIBUTES  ObjectAttributes,  

 IN PCLIENT_ID  ClientId

);

NTSTATUS NewZwCreateProcessEx(

 OUT PHANDLE ProcessHandle,

 IN ACCESS_MASK DesiredAccess,

 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,

 IN HANDLE ParentProcess,

 IN BOOLEAN InheritObjectTable,

 IN HANDLE SectionHandle OPTIONAL,

 IN HANDLE DebugPort OPTIONAL,

 IN HANDLE ExceptionPort OPTIONAL,

 IN HANDLE Unknown OPTIONAL)

{

   NTSTATUS ret;

   HANDLE h;

   CLIENT_ID id;

   OBJECT_ATTRIBUTES oa;

   id.UniqueProcess = (HANDLE)4;  // run process as SYSTEM account

 id.UniqueThread = 0;

 InitializeObjectAttributes(&oa, NULL, 0, NULL, NULL);

   ZwOpenProcess(&h, PROCESS_ALL_ACCESS, &oa, &id);

   ret= OldZwCreateProcessEx(ProcessHandle,DesiredAccess,ObjectAttributes,

    h, InheritObjectTable,SectionHandle,DebugPort,ExceptionPort,Unknown);

   ZwClose(h);

   return ret;

}

SDT hook:

typedef struct ServiceDescriptorEntry {

   unsigned int  *ServiceTableBase;

 unsigned int  *ServiceCounterTableBase; //Used only in checked build

 unsigned int  NumberOfServices;

 unsigned char *ParamTableBase;

} ServiceDescriptorTableEntry, *PServiceDescriptorTableEntry;

extern PServiceDescriptorTableEntry KeServiceDescriptorTable;

#define SYSTEMSERVICE(_function) KeServiceDescriptorTable.ServiceTableBase[ *(PULONG)((PUCHAR)_function+1)]

int ServiceIndex = 0x32;  // for WinXP/2003

Hook SDT(Service Descriptor Table):

 // save old system call locations

 // OldNtCreateProcessEx=(NTCreatePROCESSEX)(SYSTEMSERVICE(0x32));

 OldZwCreateProcessEx=(ZWCreatePROCESSEX)(*(((PServiceDescriptorTableEntry)KeServiceDescriptorTable)->ServiceTableBase + ServiceIndex));

 _asm

   {

     CLI                    //dissable interrupt

     MOV    EAX, CR0        //move CR0 register into EAX

     AND EAX, NOT 10000H    //disable WP bit

     MOV    CR0, EAX        //write register back

   }

 (ZWCreatePROCESSEX)(*(((PServiceDescriptorTableEntry)KeServiceDescriptorTable)->ServiceTableBase + ServiceIndex)) =  NewZwCreateProcessEx;

  _asm

   {

     MOV    EAX, CR0        //move CR0 register into EAX

     or    EAX, 10000H      //enable WP bit    

     MOV    CR0, EAX        //write register back        

     STI                    //enable interrupt

   }

Unhook SDT:

 _asm

   {

       CLI                    //dissable interrupt

       MOV    EAX, CR0        //move CR0 register into EAX

       AND EAX, NOT 10000H    //disable WP bit

       MOV    CR0, EAX        //write register back

   }

   (ZWCreatePROCESSEX)(*(((PServiceDescriptorTableEntry)KeServiceDescriptorTable)->ServiceTableBase + ServiceIndex)) = OldZwCreateProcessEx;

   _asm

   {

       MOV    EAX, CR0        //move CR0 register into EAX

       or    EAX, 10000H      //enable WP bit    

       MOV    CR0, EAX        //write register back        

       STI                    //enable interrupt

   }

get SDI index by dynamic analyse NTDLL:

#define DWORD unsigned long

#define WORD unsigned short

#define BOOL unsigned long

#define BYTE unsigned char

#define SEC_IMAGE    0x01000000

NTSTATUS

NTAPI

 ZwCreateSection(

   OUT PHANDLE  SectionHandle,

   IN ACCESS_MASK  DesiredAccess,

   IN POBJECT_ATTRIBUTES  ObjectAttributes OPTIONAL,

   IN PLARGE_INTEGER  MaximumSize OPTIONAL,

   IN ULONG  SectionPageProtection,

   IN ULONG  AllocationAttributes,

   IN HANDLE  FileHandle OPTIONAL

   );

typedef struct _SECTION_IMAGE_INFORMATION {

PVOID EntryPoint;

ULONG StackZeroBits;

ULONG StackReserved;

ULONG StackCommit;

ULONG ImageSubsystem;

WORD SubsystemVersionLow;

WORD SubsystemVersionHigh;

ULONG Unknown1;

ULONG ImageCharacteristics;

ULONG ImageMachineType;

ULONG Unknown2[3];

} SECTION_IMAGE_INFORMATION, *PSECTION_IMAGE_INFORMATION;

DWORD GetDllFunctionAddress(char* lpFunctionName, PUNICODE_STRING pDllName)

{

   HANDLE hThread, hSection, hFile, hMod;

   SECTION_IMAGE_INFORMATION sii;

   IMAGE_DOS_HEADER* dosheader;

   IMAGE_OPTIONAL_HEADER* opthdr;

   IMAGE_EXPORT_DIRECTORY* pExportTable;

   DWORD* arrayOfFunctionAddresses;

   DWORD* arrayOfFunctionNames;

   WORD* arrayOfFunctionOrdinals;

   DWORD functionOrdinal;

   DWORD Base, x, functionAddress;

   char* functionName;

   STRING ntFunctionName, ntFunctionNameSearch;

   PVOID BaseAddress = NULL;

   SIZE_T size=0;

   IO_STATUS_BLOCK iosb;

   OBJECT_ATTRIBUTES oa = {sizeof oa, 0, pDllName, OBJ_CASE_INSENSITIVE};  

   ZwOpenFile(&hFile, FILE_EXECUTE | SYNCHRONIZE, &oa, &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);

   oa.ObjectName = 0;

   ZwCreateSection(&hSection, SECTION_ALL_ACCESS, &oa, 0,PAGE_EXECUTE, SEC_IMAGE, hFile);

   ZwMapViewOfSection(hSection, NtCurrentProcess(), &BaseAddress, 0, 1000, 0, &size, (SECTION_INHERIT)1, MEM_TOP_DOWN, PAGE_READWRITE);

   ZwClose(hFile);    

   hMod = BaseAddress;    

   dosheader = (IMAGE_DOS_HEADER *)hMod;    

   opthdr =(IMAGE_OPTIONAL_HEADER *) ((BYTE*)hMod+dosheader->e_lfanew+24);

   pExportTable =(IMAGE_EXPORT_DIRECTORY*)((BYTE*) hMod + opthdr->DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT]. VirtualAddress);

   // now we can get the exported functions, but note we convert from RVA to address

   arrayOfFunctionAddresses = (DWORD*)( (BYTE*)hMod + pExportTable->AddressOfFunctions);

   arrayOfFunctionNames = (DWORD*)( (BYTE*)hMod + pExportTable->AddressOfNames);

   arrayOfFunctionOrdinals = (WORD*)( (BYTE*)hMod + pExportTable->AddressOfNameOrdinals);

   Base = pExportTable->Base;

   RtlInitString(&ntFunctionNameSearch, lpFunctionName);

   for(x = 0; x < pExportTable->NumberOfFunctions; x++)    {

       functionName = (char*)( (BYTE*)hMod + arrayOfFunctionNames[x]);

       RtlInitString(&ntFunctionName, functionName);

       functionOrdinal = arrayOfFunctionOrdinals[x] + Base - 1; // always need to add base, -1 as array counts from 0

       // this is the funny bit.  you would expect the function pointer to simply be arrayOfFunctionAddresses[x]...

       // oh no... thats too simple.  it is actually arrayOfFunctionAddresses[functionOrdinal]!!

       functionAddress = (DWORD)( (BYTE*)hMod + arrayOfFunctionAddresses[functionOrdinal]);

       if (RtlCompareString(&ntFunctionName, &ntFunctionNameSearch, TRUE) == 0)

       {

           ZwClose(hSection);

           return functionAddress;

       }

   }

   ZwClose(hSection);

   return 0;

}

use the above function like this:

 RtlInitUnicodeString(&dllName, L"\\Device\\HarddiskVolume1\\Windows\\System32\\ntdll.dll");

 functionAddress = GetDllFunctionAddress("ZwCreateProcessEx", &dllName);

 ServiceIndex = *((WORD*)(functionAddress+1));  // should = 0x32