来到看雪,胆子都变小了,好多大牛,导致连贴子都不敢发。
今天为了求个激活码,斗胆献丑,希望版主大哥赏赐!
对与驱动编程中的入门,我说下这几天学习得问题。
我发现很多新手学驱动上来就是SSDT HOOK,inline hook,包括我自己。
但是对一些基础却一无所知,就比如获取函数地址,连地址都不知道怎么获取就HOOK,也太勉强了。
今天就讨论这获取函数地址。
内核函数有导出与未导出函数,
导出或未导出看ntoskrnl.exe导出表就晓得了。可以用导出表查看工具或PE文件工具查看。
也可以到DDK的帮助文档里查找,没有则说明未导出。如果有都会指出声明所在的头文件。
导出函数只要声明下就可以直接调用MmGetSystemRoutineAddress获取地址
当然就转换下类型也可得到。如:(ULONG)NtFunname...
导出与未导出函数声明都可查看下面的网站
http://undocumented.ntinternals.net/
未导出函数的地址获取会麻烦些。
首先了解下SSDT中的函数,如果SSDT中有,可以通过获取SSDT的地址加索引得到。
别告诉我SSDT地址都不知道怎么获取。
typedef struct _SYSTEM_SERVICE_TABLE
{
unsigned int *ServiceTableBase;
unsigned int *ServiceCounterTableBase;
unsigned int NumberOfServices;
unsigned char *ParamTableBase;
}
SYSTEM_SERVICE_TABLE,
*PSYSTEM_SERVICE_TABLE,
**PPSYSTEM_SERVICE_TABLE;
__declspec(dllimport) SYSTEM_SERVICE_TABLE KeServiceDescriptorTable;//得到SSDT地址
还不知道你可以用看雪刚推出的
www.kanxue.con搜索去了。
#define SYSTEMSERVICE(ID) KeServiceDescriptorTable.ServiceTableBase[ID]
加上这个宏就可以通过服务号得到函数地址了。
关于如何获取服务号可以从下面的页面查看
http://www.pediy.com/document/Windows_System_Call_Table/Windows_System_Call_Table.htm大牛们也提供了通过ntdll.dll获取服务号的函数。(尾部贴出代码这里写下使用)
#define SYSCALL_INDEX(_Function) *(PULONG) ((PUCHAR)_Function+1)
用这个宏得到服务号。
原理:---------------------------------------------------------------------------------
lkd> u NtReadVirtualMemory
nt!NtReadVirtualMemory:
805b40bc 6a1c push 1Ch
805b40be 68f0ae4d80 push offset nt!MmClaimParameterAdjustDownTime+0x90 (804daef0)
805b40c3 e89888f8ff call nt!_SEH_prolog (8053c960)
805b40c8 64a124010000 mov eax,dword ptr fs:[00000124h]
805b40ce 8bf8 mov edi,eax
lkd> u ZwReadVirtualMemory
nt!ZwReadVirtualMemory:
80501b94 b8ba000000 mov eax,0BAh ;此处0BAh就是NtReadVirtualMemory的服务号
80501b99 8d542404 lea edx,[esp+4]
80501b9d 9c pushfd
80501b9e 6a08 push 8
80501ba0 e88c060400 call nt!KiSystemService (80542231)
80501ba5 c21400 ret 14h
--------------------------------------------------------------------------------------
UNICODE_STRING dllName;
DWORD functionAddress;
int position;
RtlInitUnicodeString( &dllName, L"\\Device\\HarddiskVolume1\\Windows\\System32\\ntdll.dll" );
functionAddress = GetDllFunctionAddress("NtReadVirtualMemory", &dllName);
position = SYSCALL_INDEX(functionAddress);
//获取NtReadVirtualMemory的服务号完毕!
SYSTEMSERVICE(position);
就可得到地址。
SSDT中没有,可以再看看shadow ssdt。shadow ssdt中的函数是GUI函数。
对shadow ssdt不太了解的可以查看shadow ssdt 学习笔记一贴,写的比较详细。
http://bbs.pediy.com/showthread.php?t=56955
shadow ssdt与SSDT一样,都有它的索引表。我没找到,有的朋友可以共享份,先谢谢了。
我是通过XueTr工具查看的。小巧简洁的工具,挺强大。
前面的序号就是shadow ssdt中的索引了。注意shadow ssdt中的地址需要GUI线程上下文才有效。
未导出函数不在SSDT 或 shadow ssdt中那将是最麻烦的事了。
拿KiAttachProcess作例子。
我们知道有个KeAttachProcess是导出函数并且中间是调用了KiAttachProcess。
我们可以用windbg查看下KeAttachProcess
lkd> uf KeAttachProcess
nt!KeAttachProcess:
804f9afc 8bff mov edi,edi
804f9afe 55 push ebp
804f9aff 8bec mov ebp,esp
804f9b01 56 push esi
804f9b02 57 push edi
804f9b03 64a124010000 mov eax,dword ptr fs:[00000124h]
804f9b09 8b7d08 mov edi,dword ptr [ebp+8]
804f9b0c 8bf0 mov esi,eax
804f9b0e 397e44 cmp dword ptr [esi+44h],edi
804f9b11 742f je nt!KeAttachProcess+0x46 (804f9b42)
nt!KeAttachProcess+0x17:
804f9b13 80be6501000000 cmp byte ptr [esi+165h],0
804f9b1a 752c jne nt!KeAttachProcess+0x4c (804f9b48)
nt!KeAttachProcess+0x20:
804f9b1c 64a194090000 mov eax,dword ptr fs:[00000994h]
804f9b22 85c0 test eax,eax
804f9b24 7522 jne nt!KeAttachProcess+0x4c (804f9b48)
nt!KeAttachProcess+0x2a:
804f9b26 33c9 xor ecx,ecx
804f9b28 ff1588904d80 call dword ptr [nt!_imp_KeAcquireQueuedSpinLockRaiseToSynch
(804d9088)]
804f9b2e 884508 mov byte ptr [ebp+8],al
804f9b31 8d864c010000 lea eax,[esi+14Ch]
804f9b37 50 push eax
804f9b38 ff7508 push dword ptr [ebp+8]
804f9b3b 57 push edi
804f9b3c 56 push esi
804f9b3d e890feffff call nt!KiAttachProcess (804f99d2) ;---------------------这行
nt!KeAttachProcess+0x46:
804f9b42 5f pop edi
804f9b43 5e pop esi
804f9b44 5d pop ebp
804f9b45 c20400 ret 4
好了,看下e890feffff call nt!KiAttachProcess (804f99d2)这里
调用了KiAttachProcess。我们就利用它来获取KiAttachProcess的地址。
ULONG Addres;
Addres = (ULONG)KeAttachProcess+0x42; //经过计算call nt!KiAttachProcess的偏移量0x42
Addres = *(ULONG*)Addres; //得到KiAttachProcess地址的偏移量
Addres = (ULONG)KeAttachProcess + 0x46 + Addres;//相加得到KiAttachProcess的地址
就是这样了。可以根据不同情况扩展。还有哪些方法希望大牛们可以指导指导。
/*************大牛提供的获取函数地址********/
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;
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);
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;
functionAddress = (DWORD)( (BYTE*)hMod + arrayOfFunctionAddresses[functionOrdinal]);
if (RtlCompareString(&ntFunctionName, &ntFunctionNameSearch, TRUE) == 0)
{
ZwClose(hSection);
return functionAddress;
}
}
ZwClose(hSection);
return 0;
}
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!