您的位置:首页 > 其它

create process as system privilege

2008-06-23 11:25 369 查看
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: