在Ring0下HOOK Ntdll.dll的Nt*函数的方法

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;

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

    IO_STATUS_BLOCK iosb;

    
//_asm int 3;
    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, 010000&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;
}

这段代码可以直接使用,举例如下:
DWORD functionAddress;
Unicode_String dllName;
RtlInitUnicodeString(
&dllName, L"\\Device\\HarddiskVolume1\\Windows\\System32\\ntdll.dll");
functionAddress 
= GetDllFunctionAddress("ZwCreateProcessEx"&dllName);
position 
= *((WORD*)(functionAddress+1));
DbgPrint(
"ZwCreateProcessEx's Id:%d\n", position);
上面的代码从驱动层加载NTDLL,再从输出表中找出函数地址,从而进行挂钩。
比如可以通过hook ZwCreateProcessEx来监控进程的创建,hook ZwQuerySystemInformation来实现进程的隐藏等等。
原文地址:https://www.cnblogs.com/dflower/p/1425435.html