![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
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;
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
DWORD GetDllFunctionAddress(char* lpFunctionName, PUNICODE_STRING pDllName)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
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;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
OBJECT_ATTRIBUTES oa =
{sizeof oa, 0, pDllName, OBJ_CASE_INSENSITIVE};
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
IO_STATUS_BLOCK iosb;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//_asm int 3;
ZwOpenFile(&hFile, FILE_EXECUTE | SYNCHRONIZE, &oa, &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
oa.ObjectName = 0;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
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);
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
pExportTable =(IMAGE_EXPORT_DIRECTORY*)((BYTE*) hMod + opthdr->DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT]. VirtualAddress);
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// now we can get the exported functions, but note we convert from RVA to address
arrayOfFunctionAddresses = (DWORD*)( (BYTE*)hMod + pExportTable->AddressOfFunctions);
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
arrayOfFunctionNames = (DWORD*)( (BYTE*)hMod + pExportTable->AddressOfNames);
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
arrayOfFunctionOrdinals = (WORD*)( (BYTE*)hMod + pExportTable->AddressOfNameOrdinals);
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
Base = pExportTable->Base;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
RtlInitString(&ntFunctionNameSearch, lpFunctionName);
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
for(x = 0; x < pExportTable->NumberOfFunctions; x++)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
functionName = (char*)( (BYTE*)hMod + arrayOfFunctionNames[x]);
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
RtlInitString(&ntFunctionName, functionName);
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
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]![](https://www.cnblogs.com/Images/dot.gif)
// oh no
thats too simple. it is actually arrayOfFunctionAddresses[functionOrdinal]!!
functionAddress = (DWORD)( (BYTE*)hMod + arrayOfFunctionAddresses[functionOrdinal]);
if (RtlCompareString(&ntFunctionName, &ntFunctionNameSearch, TRUE) == 0)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
ZwClose(hSection);
return functionAddress;
}
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
ZwClose(hSection);
return 0;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
这段代码可以直接使用,举例如下:
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);
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
上面的代码从驱动层加载NTDLL,再从输出表中找出函数地址,从而进行挂钩。
比如可以通过hook ZwCreateProcessEx来监控进程的创建,hook ZwQuerySystemInformation来实现进程的隐藏等等。