轉自蝦總
前段時間寫的一段無聊代碼,可能對大家有點用。用於在驅動裏調用一些沒有直接導出的Zw函數,如ZwProtectVirtualMemory。在此感謝alpha提供思路。
BOOLEAN CallZwFunction(CONST CHAR *FunctionName,PVOID pCallRet,ULONG ArgNum,...)
{
char *vl;
BOOLEAN retval = FALSE;
ULONG FunctionIndex;
ULONG CallRet;
ULONG Argv[20],temp;
LONG i;
ULONG FunctionAddr;
BYTE Sign[]="\xb8\x44\x00\x00\x00";
BYTE *p;
FunctionIndex = GetDllFunctionIndex(FunctionName);
if(!FunctionIndex || FunctionIndex==-1)
goto END;
FunctionAddr = 0;
*(ULONG *)(Sign+1)=FunctionIndex;
p=(BYTE *)GetSystemFunctionAddrW(L"ZwAccessCheckAndAuditAlarm");
for(i=0;i<0x2000;i++)
{
if(memcmp(p+i,Sign,5)==0)
{
FunctionAddr=(ULONG)p+i;
break;
}
}
if(!FunctionAddr)
goto END;
va_start(vl, ArgNum);
memcpy(Argv,vl,sizeof(ULONG)*ArgNum);
va_end(vl);
for(i=ArgNum-1;i>=0;i--)
{
temp=Argv[i];
__asm
{
push temp;
}
}
__asm
{
mov eax,FunctionAddr;
call eax;
mov CallRet,eax;
}
*(ULONG *)pCallRet = CallRet;
retval = TRUE;
END:
return retval;
}
調用示例代碼如下:
CallZwFunction("ZwProtectVirtualMemory",&status,5,(HANDLE)-1,&Addr2,&size,PAGE_EXECUTE_READWRITE,&old);
此函數中使用到兩個函數,這兩個函數相信很多人都有,但我還是貼一下這兩個函數的代碼吧
ULONG GetDllFunctionIndex(char* lpFunctionName)
{
HANDLE hSection, hFile, hMod;
IMAGE_DOS_HEADER* dosheader;
IMAGE_OPTIONAL_HEADER* opthdr;
IMAGE_EXPORT_DIRECTORY* pExportTable;
ULONG* arrayOfFunctionAddresses;
ULONG* arrayOfFunctionNames;
USHORT* arrayOfFunctionOrdinals;
ULONG functionOrdinal;
ULONG 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;
NTSTATUS status;
ULONG uIndex=-1;
UNICODE_STRING pDllName;
RtlInitUnicodeString(&pDllName,L"\\SystemRoot\\system32\\ntdll.dll");
InitializeObjectAttributes ( &oa, &pDllName, OBJ_KERNEL_HANDLE|OBJ_CASE_INSENSITIVE, NULL, NULL);
status=ZwOpenFile(&hFile, FILE_EXECUTE | SYNCHRONIZE, &oa, &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);
if(status!=STATUS_SUCCESS)
{
//FILE_SUPERSEDED
KdPrint(("ZwOpenFile Error:0x%x,0x%x",status,iosb.Information));
return 0;
}
oa.ObjectName = 0;
status=ZwCreateSection(&hSection, SECTION_ALL_ACCESS, &oa, 0,PAGE_EXECUTE, 0x01000000, hFile);
if(status!=STATUS_SUCCESS)
{
KdPrint(("ZwCreateSection Error"));
ZwClose(hFile);
return 0;
}
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 = (ULONG*)( (BYTE*)hMod + pExportTable->AddressOfFunctions);
arrayOfFunctionNames = (ULONG*)( (BYTE*)hMod + pExportTable->AddressOfNames);
arrayOfFunctionOrdinals = (USHORT*)( (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]!!
//KdPrint(("0x%x\t0x%x \n",x,functionOrdinal));
functionAddress = (ULONG)( (BYTE*)hMod + arrayOfFunctionAddresses[functionOrdinal]);
if (RtlCompareString(&ntFunctionName, &ntFunctionNameSearch, TRUE) == 0)
{
//INT3
uIndex=*(PULONG)((PUCHAR)functionAddress+1);
break;
//return functionAddress;
}
}
ZwClose(hSection);
ZwUnmapViewOfSection(NtCurrentProcess(),BaseAddress);
return uIndex;
}
PVOID GetSystemFunctionAddrW(CONST WCHAR *FunctionName)
{
UNICODE_STRING uniFunctionName;
RtlInitUnicodeString(&uniFunctionName,FunctionName);
return MmGetSystemRoutineAddress(&uniFunctionName);
}