# 载入第二个Ntdll绕Hook

## 简介

我不知道有没有人写过这个东西， 之前和我的亲兄弟[snowming](http://blog.leanote.com/post/snowming/a0366d1d01bf)师傅交流时回想起来用[CreateFileMapping->MapViewOfFile](https://idiotc4t.com/code-and-dll-process-injection/mapping-injection)以文件映射的形式打开，如果被打开文件时PE格式，那么这个文件会按照内存展开，那么我们猜想是不是这个被第二次载入内存的ntdll是不是就是一个干净的ntdll，能不能帮助我们绕过一些inline hook。

## 流程

1. 使用CreateFileMapping->MapViewOfFile映射一个ntdll
2. 自己实现一个GetProcAddress函数
3. 使用自写GetProcAddress函数获取nt函数
4. do it

## 调试

把代码写出来之后windbg调了一下，发现如果没有挂钩，那么这个代码其实和原ntdll是一模一样的，在windbg里面会显示第二个ntdll。(只是显示成ntdll\_xxx,在ldr链表里还是叫ntdll)。

![](https://3969710588-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M3GuIlaAXU8NbJTCRei%2F-MK4qsKoV0QA1K_WQyi_%2F-MK4sUyGPhkrHxVLUpYR%2Fimage.png?alt=media\&token=c5de6d78-613b-4c6f-908d-65b1c5f0c4d9)

![](https://3969710588-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M3GuIlaAXU8NbJTCRei%2F-MK4qsKoV0QA1K_WQyi_%2F-MK4t_P7FlxrBdxwDlhX%2Fimage.png?alt=media\&token=bad77e5f-c2b3-412f-abfb-74506de63de4)

如果使用windows api GetProcAddress函数获取函数地址的话会报错0126 找不到指定的模块。

![](https://3969710588-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M3GuIlaAXU8NbJTCRei%2F-MK50AFs6jyMZsHJVLfu%2F-MK51fyPmJRaSMvEkXFO%2Fimage.png?alt=media\&token=092b96fb-c3b5-44b0-910d-2b7a57297a10)

具体分析过程参考开源的reactos项目的代码。

![](https://3969710588-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M3GuIlaAXU8NbJTCRei%2F-MK5Ef3gMp_87CJu-DIP%2F-MK5EvnllVIhbfknQOlw%2Fimage.png?alt=media\&token=ff0f31a4-2398-4804-acd2-c643cbec10d2)

![](https://3969710588-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M3GuIlaAXU8NbJTCRei%2F-MK5Ef3gMp_87CJu-DIP%2F-MK5Erg0FbkBaWBu66Kh%2Fimage.png?alt=media\&token=2dfafe33-ef61-4b9f-806f-ef6ac281c5d5)

![](https://3969710588-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M3GuIlaAXU8NbJTCRei%2F-MK5Ef3gMp_87CJu-DIP%2F-MK5EzxLEmecRXk4eM9J%2Fimage.png?alt=media\&token=416beb46-18bd-4dc4-8946-2d8681facc01)

![](https://3969710588-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M3GuIlaAXU8NbJTCRei%2F-MK5P9v3txbw2zNeqh7d%2F-MK5PDoBcVZ6vE2Bty2R%2Fimage.png?alt=media\&token=1dfaa289-df89-4518-9cd0-1d4be949699e)

![errorcode 126](https://3969710588-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M3GuIlaAXU8NbJTCRei%2F-MK5P9v3txbw2zNeqh7d%2F-MK5PNuGc-MyDszhnij1%2Fimage.png?alt=media\&token=094a60f8-ad2a-416c-a1a2-367a76fad7d2)

![](https://3969710588-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M3GuIlaAXU8NbJTCRei%2F-MK5Ef3gMp_87CJu-DIP%2F-MK5F8KIgnawP5gywS4I%2Fimage.png?alt=media\&token=85af03e8-ef46-4d3e-8025-46bd4ac342ba)

但是如果我们直接自己编写一个GetProcAddress函数就可以获取到这个自己加载的ntdll内的函数地址并且执行成功。

![](https://3969710588-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M3GuIlaAXU8NbJTCRei%2F-MK51nnfSA_TWOlD2ycj%2F-MK526WhGHuPdDC0XoFz%2Fimage.png?alt=media\&token=f60e171a-6449-4f5e-ac3d-c6ea6144cf9e)

## 代码

```
#include <Windows.h>
#include <stdio.h>

#define DEREF( name )*(UINT_PTR *)(name)
#define DEREF_64( name )*(DWORD64 *)(name)
#define DEREF_32( name )*(DWORD *)(name)
#define DEREF_16( name )*(WORD *)(name)
#define DEREF_8( name )*(BYTE *)(name)

typedef NTSTATUS(NTAPI* pNtAllocateVirtualMemory)(
	HANDLE ProcessHandle,
	PVOID* BaseAddress,
	ULONG_PTR ZeroBits,
	PSIZE_T RegionSize,
	ULONG AllocationType,
	ULONG Protect);

FARPROC WINAPI GetProcAddressR(HANDLE hModule, LPCSTR lpProcName)
{
	UINT_PTR uiLibraryAddress = 0;
	FARPROC fpResult = NULL;

	if (hModule == NULL)
		return NULL;
	uiLibraryAddress = (UINT_PTR)hModule;

	__try
	{
		UINT_PTR uiAddressArray = 0;
		UINT_PTR uiNameArray = 0;
		UINT_PTR uiNameOrdinals = 0;
		PIMAGE_NT_HEADERS pNtHeaders = NULL;
		PIMAGE_DATA_DIRECTORY pDataDirectory = NULL;
		PIMAGE_EXPORT_DIRECTORY pExportDirectory = NULL;
		pNtHeaders = (PIMAGE_NT_HEADERS)(uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew);
		pDataDirectory = (PIMAGE_DATA_DIRECTORY)&pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
		pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)(uiLibraryAddress + pDataDirectory->VirtualAddress);
		uiAddressArray = (uiLibraryAddress + pExportDirectory->AddressOfFunctions);
		uiNameArray = (uiLibraryAddress + pExportDirectory->AddressOfNames);
		uiNameOrdinals = (uiLibraryAddress + pExportDirectory->AddressOfNameOrdinals);
		if (((DWORD)lpProcName & 0xFFFF0000) == 0x00000000)
		{
			uiAddressArray += ((IMAGE_ORDINAL((DWORD)lpProcName) - pExportDirectory->Base) * sizeof(DWORD));
			fpResult = (FARPROC)(uiLibraryAddress + DEREF_32(uiAddressArray));
		}
		else
		{
			DWORD dwCounter = pExportDirectory->NumberOfNames;
			while (dwCounter--)
			{
				char* cpExportedFunctionName = (char*)(uiLibraryAddress + DEREF_32(uiNameArray));
				if (strcmp(cpExportedFunctionName, lpProcName) == 0)
				{
					uiAddressArray += (DEREF_16(uiNameOrdinals) * sizeof(DWORD));
					fpResult = (FARPROC)(uiLibraryAddress + DEREF_32(uiAddressArray));

					break;
				}
				uiNameArray += sizeof(DWORD);
				uiNameOrdinals += sizeof(WORD);
			}
		}
	}
	__except (EXCEPTION_EXECUTE_HANDLER)
	{
		fpResult = NULL;
	}

	return fpResult;
}


int main() {

	HANDLE hNtdllfile = CreateFileA("c:\\windows\\system32\\ntdll.dll", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
	HANDLE hNtdllMapping = CreateFileMapping(hNtdllfile, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL);
	LPVOID lpNtdllmaping = MapViewOfFile(hNtdllMapping, FILE_MAP_READ, 0, 0, 0);

	pNtAllocateVirtualMemory NtAllocateVirtualMemory = (pNtAllocateVirtualMemory)GetProcAddressR((HMODULE)lpNtdllmaping, "NtAllocateVirtualMemory");

	int err = GetLastError();

	LPVOID Address = NULL;
	SIZE_T uSize = 0x1000;

	NTSTATUS status = NtAllocateVirtualMemory(GetCurrentProcess(), &Address, 0, &uSize, MEM_COMMIT, PAGE_READWRITE);
	
	

	return 0;
};
```

## LINKS

{% embed url="<http://blog.leanote.com/post/snowming/a0366d1d01bf>" %}

{% embed url="<https://github.com/stephenfewer/ReflectiveDLLInjection>" %}
