首页
社区
课程
招聘
什么函数可以得到NtWriteVirtualMemory函数地址?
发表于: 2010-12-5 00:49 8653

什么函数可以得到NtWriteVirtualMemory函数地址?

2010-12-5 00:49
8653
我查了下资料
好象NtWriteVirtualMemory不是ntoskrnl.exe的导出函数
MmGetSystemRoutineAddress好象不可以得到NtWriteVirtualMemory的地址
以下是
这个函数的
一些资料
以下代码反编译自XP+SP2内核文件ntoskrnl.exe(5.1.2600.3051)的 MmGetSystemRoutineAddress 函数

以下代码反编译自XP+SP2内核文件ntoskrnl.exe(5.1.2600.3051)的 MmGetSystemRoutineAddress 函数

    * 函数功能:用来获取内核导出函数的地址,与用户态的GetProcessAddress函数雷同
    * 功能引申:反编译这个函数,主要的作用是可借助它来定位PsLoadedModuleResource以及PsLoadedModuleList这个重量级内核变量

原代码如下(IDA反编译结果,已自动作了标识):

; PVOID __stdcall MmGetSystemRoutineAddress(PUNICODE_STRING SystemRoutineName)

public _MmGetSystemRoutineAddress@4

_MmGetSystemRoutineAddress@4 proc near



                   SystemRoutineName= dword ptr   8


8B FF                   mov edi, edi
55                      push ebp
8B EC                   mov ebp, esp
83 EC 20                sub esp, 20h
53                      push ebx
56                      push esi
57                      push edi
68 D8 9F 4E 00          push offset aNtoskrnl_exe         ; "ntoskrnl.exe"
8D 45 E8                lea eax, [ebp-18h]
33 F6                   xor esi, esi
50                      push eax
89 75 FC                mov [ebp-4], esi
89 75 F8                mov [ebp-8], esi
E8 53 83 F1 FF          call _RtlInitUnicodeString@8      ; RtlInitUnicodeString(x,x)
68 F4 9F 4E 00          push offset aHal_dll_0            ; "hal.dll"
8D 45 E0                lea eax, [ebp-20h]
50                      push eax
E8 45 83 F1 FF          call _RtlInitUnicodeString@8      ; RtlInitUnicodeString(x,x)



                   loc_4E9F62:                             ; CODE XREF: PAGE:005194DA j

6A 01                   push 1
FF 75 08                push dword ptr [ebp+8]
8D 45 F0                lea eax, [ebp-10h]
50                      push eax
E8 F7 D9 FB FF          call _RtlUnicodeStringToAnsiString@12 ; RtlUnicodeStringToAnsiString(x,x,x)
85 C0                   test eax, eax
0F 8C 56 F5 02 00       jl loc_5194CE
64 A1 24 01 00 00       mov eax, large fs:124h
6A 01                   push 1
8B F8                   mov edi, eax
FF 8F D4 00 00 00       dec dword ptr [edi+0D4h]
68 40 36 48 00          push offset _PsLoadedModuleResource
E8 14 84 F1 FF          call _ExAcquireResourceSharedLite@8 ; ExAcquireResourceSharedLite(x,x)
8B 35 20 36 48 00       mov esi, _PsLoadedModuleList
BB 20 36 48 00          mov ebx, offset _PsLoadedModuleList

;以上两行注意,可以8B35作特征码从MmGetSystemRoutineAddress起始地址搜索,并检测之后的双字与之后移6字节的双字
是否相同作特征检测. 此特征码目前适合的平台有待进一步考核.

                   loc_4E9F9D:                             ; CODE XREF: MmGetSystemRoutineAddress(x)+A3 j

3B F3                   cmp esi, ebx
74 69                   jz short loc_4EA00A
6A 01                   push 1
8D 46 2C                lea eax, [esi+2Ch]
50                      push eax
8D 45 E8                lea eax, [ebp-18h]
50                      push eax
E8 ED 1E FA FF          call _RtlEqualUnicodeString@12    ; RtlEqualUnicodeString(x,x,x)
84 C0                   test al, al
0F 84 5A FF FF FF       jz loc_4E9F12


                   loc_4E9FB8:                             ; CODE XREF: PAGE:004E9F23 j

FF 45 FC                inc dword ptr [ebp-4]
8D 45 F0                lea eax, [ebp-10h]
50                      push eax
FF 76 18                push dword ptr [esi+18h]
E8 F3 DA FF FF          call _MiFindExportedRoutineByName@8 ; MiFindExportedRoutineByName(x,x)
85 C0                   test eax, eax
89 45 F8                mov [ebp-8], eax
75 3C                   jnz short loc_4EA00A
83 7D FC 02             cmp dword ptr [ebp-4], 2
74 36                   jz short loc_4EA00A


                   loc_4E9FD4:                             ; CODE XREF: PAGE:004E9F29 j
8B 36                   mov esi, [esi]
EB C5                   jmp short loc_4E9F9D
                  ; **************************************************************************?

                   aNtoskrnl_exe:                          ; DATA XREF: MmGetSystemRoutineAddress(x)+B o

6E 00 74 00 6F 00+       unicode 0, <ntoskrnl.exe>,0
00                      db     0
00                      db     0
                   aHal_dll_0:                             ; DATA XREF: MmGetSystemRoutineAddress(x)+21 o

68 00 61 00 6C 00+       unicode 0, <hal.dll>,0
CC                      db 0CCh ; ?
CC                      db 0CCh ; ?
CC                      db 0CCh ; ?
CC                      db 0CCh ; ?
CC                      db 0CCh ; ?
CC                      db 0CCh ; ?

                  ; **************************************************************************?



                   loc_4EA00A:                             ; CODE XREF: MmGetSystemRoutineAddress(x)+6C j

                                                          ; MmGetSystemRoutineAddress(x)+99 j ...
B9 40 36 48 00          mov ecx, offset _PsLoadedModuleResource
E8 3C A6 F1 FF          call @ExReleaseResourceLite@4     ; ExReleaseResourceLite(x)
FF 87 D4 00 00 00       inc dword ptr [edi+0D4h]
75 0B                   jnz short loc_4EA027
8D 47 34                lea eax, [edi+34h]
39 00                   cmp [eax], eax
0F 85 B8 F4 02 00       jnz loc_5194DF


                   loc_4EA027:                             ; CODE XREF: MmGetSystemRoutineAddress(x)+E7 j

                                                          ; PAGE:005194EB j
8D 45 F0                lea eax, [ebp-10h]
50                      push eax
E8 4A FB FA FF          call _RtlFreeAnsiString@4         ; RtlFreeAnsiString(x)
8B 45 F8                mov eax, [ebp-8]
5F                      pop edi
5E                      pop esi
5B                      pop ebx
C9                      leave
C2 04 00                retn 4

                   _MmGetSystemRoutineAddress@4 endp ; sp =   3Ch

到底什么函数可以得到NtWriteVirtualMemory的地址 ?
要考虑通用的办法 不能用硬件编码了

我今天虚拟机蓝了100多次
实在不知道怎么办了。

[课程]Android-CTF解题方法汇总!

收藏
免费 0
支持
分享
最新回复 (5)
雪    币: 6092
活跃值: (654)
能力值: ( LV4,RANK:45 )
在线值:
发帖
回帖
粉丝
2
查了下资料有点傻眼了。。

解析pdb文件得到未导出变量地址
对应驱动应该如何写  傻眼中
http://hi.baidu.com/sumcogito/blog/item/03e5685525114b58574e0052.html
程序要用到dbghelp.dll中的一些函数
http://msdn.microsoft.com/en-us/library/ms679291%28VS.85%29.aspx
要自己下载系统对应的符号文件

首先是一些初始化的东西:
设置符号选项,调用下面两个函数
   DWORD Options = SymGetOptions();
   Options = Options|SYMOPT_DEBUG;
   SymSetOptions(Options);

调用SymInitialize函数进行初始化(这是必须的)
   hProcess = GetCurrentProcess();
   BOOL bRet = SymInitialize(hProcess,0,FALSE);
   if(!bRet)
   {
    printf("SymInitialize error ...\n");
   }
可以用函数SymSetSearchPath(hProcess,SymbolPath);设置符号搜索路径

然后用SymLoadModule64加载模块,这里是ntoskrnl.exe
char FileName[256] ;
GetSystemDirectory(FileName,sizeof(FileName));
strcat(FileName,"\\ntoskrnl.exe");
BaseOfDll = SymLoadModule64(hProcess,NULL,FileName,NULL,0,0);

BaseOfDll返回加载的基址

然后就可以调用SymEnumSymbols查询符号了
SymEnumSymbols(hProcess,BaseOfDll,0,EnumSymCallBack,0);
参数EnumSymCallBack是一个回调函数,在里面得到未导出函数的VA,

BOOL CALLBACK EnumSymCallBack(PSYMBOL_INFO pSymInfo,ULONG SymbolSize,PVOID UserContext)
/*
   参数pSymInfo结构Name成员是符号名,Address是符号地址(The virtual address of the start of the symbol)
*/
{
   if(strcmp((pSymInfo->Name), "PspCreateProcessNotifyRoutine")==0)
   {
    printf("Oh,yeah! %s :%0x\n",pSymInfo->Name,pSymInfo->Address);
   }
   return TRUE;
}



完整代码:
[code]
#include <stdio.h>
#include <windows.h>
#include "dbghelp.h"

#pragma comment(lib,"dbghelp.lib")

BOOL CALLBACK EnumSymCallBack(PSYMBOL_INFO pSymInfo,ULONG SymbolSize,PVOID UserContext);

int main(int argc, char* argv[])
{
HANDLE hProcess;
DWORD64 BaseOfDll;
PIMAGEHLP_SYMBOL pSymbol = NULL;

DWORD Options = SymGetOptions();

Options = Options|SYMOPT_DEBUG;
SymSetOptions(Options);

hProcess = GetCurrentProcess();
BOOL bRet = SymInitialize(hProcess,0,FALSE);
if(!bRet)
{
   printf("SymInitialize error ...\n");
}
char SymbolPath[256];
GetCurrentDirectory(sizeof(SymbolPath),SymbolPath);
strcat(SymbolPath,"\\symbols");
SymSetSearchPath(hProcess,SymbolPath);

char FileName[256] ;
GetSystemDirectory(FileName,sizeof(FileName));
strcat(FileName,"\\ntoskrnl.exe");
BaseOfDll = SymLoadModule64(hProcess,NULL,FileName,NULL,0,0);
if(BaseOfDll == 0)
{
   DWORD nErr = GetLastError();
}
SymEnumSymbols(hProcess,BaseOfDll,0,EnumSymCallBack,0);
SymUnloadModule64(hProcess,BaseOfDll);
SymCleanup(hProcess);
for(;;);

return 0;
}

BOOL CALLBACK EnumSymCallBack(PSYMBOL_INFO pSymInfo,ULONG SymbolSize,PVOID UserContext)
{
if(strcmp((pSymInfo->Name), "PspCreateProcessNotifyRoutine")==0)
{
   printf("Oh,yeah! %s :%0x\n",pSymInfo->Name,pSymInfo->Address);
}
if(strcmp((pSymInfo->Name), "PspLoadImageNotifyRoutine")==0)
{
   printf("Oh,yeah! %s :%0x\n",pSymInfo->Name,pSymInfo->Address);
}
if(strcmp((pSymInfo->Name), "PspCreateThreadNotifyRoutine")==0)
{
   printf("Oh,yeah! %s :%0x\n",pSymInfo->Name,pSymInfo->Address);
}
if(strcmp((pSymInfo->Name), "CmpCallBackVector")==0)
{
   printf("Oh,yeah! %s :%0x\n",pSymInfo->Name,pSymInfo->Address);
}
if(strcmp((pSymInfo->Name), "KeBugCheckCallBackListHead")==0)
{
   printf("Oh,yeah! %s :%0x\n",pSymInfo->Name,pSymInfo->Address);
}

return TRUE;
}
2010-12-5 01:04
0
雪    币: 6092
活跃值: (654)
能力值: ( LV4,RANK:45 )
在线值:
发帖
回帖
粉丝
3
*******
2010-12-5 01:05
0
雪    币: 6092
活跃值: (654)
能力值: ( LV4,RANK:45 )
在线值:
发帖
回帖
粉丝
4
做个记录 找到一个方法
http://bbs.pediy.com/showthread.php?t=74411
2010-12-5 01:12
0
雪    币: 25
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
虽然ntoskrnl.exe没有导出NtWriteVirtualMemory函数,但ntdll.dll导出了这个函数,我们可以通过ntdll.dll来获取NtWriteVirtualMemory的地址,继而获取SSDT表中NtWriteVirtualMemory的序号, 具体看代码吧,不是原创,在原创的基础上小改了一下,希望对LZ有用。
//加载DLL文件镜像,返回DLL的基地址
NTSTATUS CreateDllSection(IN IN PUNICODE_STRING pDllName, OUT PHANDLE pSection, OUT PPVOID pBaseAddress)
{
 HANDLE hFile;
 OBJECT_ATTRIBUTES oa = {sizeof oa, 0, pDllName, OBJ_CASE_INSENSITIVE};
 IO_STATUS_BLOCK iosb;
 SIZE_T size=0;
 NTSTATUS status;
 ASSERT(pSection&&pBaseAddress);
 *pBaseAddress = NULL;
 status = ZwOpenFile(&hFile, FILE_EXECUTE | SYNCHRONIZE, &oa, &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);
 if (NT_SUCCESS(status)) {
  oa.ObjectName = 0;
  status = ZwCreateSection(pSection, SECTION_ALL_ACCESS, &oa, 0,PAGE_EXECUTE, SEC_IMAGE, hFile);
  if (NT_SUCCESS(status)) {
   status = ZwMapViewOfSection(*pSection, ZwCurrentProcess(), pBaseAddress, 0, 1000, 0, &size, (SECTION_INHERIT)1, MEM_TOP_DOWN, PAGE_READWRITE);
   if (!NT_SUCCESS(status)) {
    ZwClose(*pSection);
   }
  }
  ZwClose(hFile);
 }
 return status;
}
//通过函数名和DLL的基地址查找函数地址
PVOID GetSectionDllFuncAddr(IN PCHAR lpFunctionName, IN PVOID BaseAddress) 
{
 PVOID functionAddress = NULL;
 PIMAGE_DOS_HEADER dosheader;
 PIMAGE_OPTIONAL_HEADER opthdr;
 PIMAGE_EXPORT_DIRECTORY pExportTable;
 PDWORD arrayOfFunctionAddresses;
 PDWORD arrayOfFunctionNames;
 PWORD arrayOfFunctionOrdinals;
 DWORD Base;
 STRING ntFunctionName, ntFunctionNameSearch;
 PCHAR functionName;
 DWORD functionOrdinal;
 ULONG x;
 ASSERT(lpFunctionName&&BaseAddress);
 dosheader = (PIMAGE_DOS_HEADER)BaseAddress;
 opthdr =(PIMAGE_OPTIONAL_HEADER) ((PBYTE)BaseAddress+dosheader->e_lfanew+24);
 pExportTable =(PIMAGE_EXPORT_DIRECTORY)((PBYTE)BaseAddress + opthdr->DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT]. VirtualAddress);
 // now we can get the exported functions, but note we convert from RVA to address
 arrayOfFunctionAddresses = (PDWORD)( (PBYTE)BaseAddress + pExportTable->AddressOfFunctions);
 arrayOfFunctionNames = (PDWORD)( (PBYTE)BaseAddress + pExportTable->AddressOfNames);
 arrayOfFunctionOrdinals = (PWORD)( (PBYTE)BaseAddress + pExportTable->AddressOfNameOrdinals);
 Base = pExportTable->Base;
 RtlInitString(&ntFunctionNameSearch, lpFunctionName);
 for (x = 0; x < pExportTable->NumberOfFunctions; x++) {
  functionName = (PCHAR)( (PBYTE)BaseAddress + 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]!!
  if (RtlCompareString(&ntFunctionName, &ntFunctionNameSearch, TRUE) == 0) {
   functionAddress = (PBYTE)BaseAddress + arrayOfFunctionAddresses[functionOrdinal];
   break;
  }
 }
 return functionAddress;
}

具体的函数用法为:
#define SYSCALL_INDEX(_Function) *(PULONG)((PUCHAR)_Function+1)
#define HOOK_SSDTCALL_BY_ID(_Funcid, _Hook, _Orig ) (LONG)_Orig = InterlockedExchange((PLONG)&KeServiceDescriptorTable.ServiceTableBase[_Funcid], (LONG)_Hook)
NTSTATUS status;
UNICODE_STRING tmpStr;
HANDLE hSection;
PVOID ntdllBaseAddress;
//对于未导出函数,使用GetSectionDllFuncAddr函数获取其服务索引号(地址在用户态)
RtlInitUnicodeString(&tmpStr, L"[URL="file://\\SystemRoot\\System32\\ntdll.dll"]\\SystemRoot\\System32\\ntdll.dll[/URL]");
//加载DLL文件
status = CreateDllSection(&tmpStr, &hSection, &ntdllBaseAddress);
ASSERT(NT_SUCCESS(status));
//获取ZwWriteVirtualMemory函数地址
ZwWriteVirtualMemory = (ZWWRITEVIRTUALMEMORY)GetSectionDllFuncAddr("ZwWriteVirtualMemory", ntdllBaseAddress);
//获取ZwWriteVirtualMemory在SSDT中的序号
ZwWriteVirtualMemoryId = SYSCALL_INDEX(ZwWriteVirtualMemory);
KdPrint(("SYS:ZwWriteVirtualMemory's Id:%d\n", ZwWriteVirtualMemoryId));
//关闭DLL文件
ZwClose(hSection);
//HOOK ZwWriteVirtualMemoryId函数
HOOK_SSDTCALL_BY_ID(ZwWriteVirtualMemoryId, HookZwWriteVirtualMemory, RealZwWriteVirtualMemory);//HOOK ZwWriteVirtualMemory函数

这种方法在XP及更高版本的Windows系统都有效
2010-12-5 10:24
0
雪    币: 6092
活跃值: (654)
能力值: ( LV4,RANK:45 )
在线值:
发帖
回帖
粉丝
6
太感谢了
你既给了方法 又给了代码
虽然不知道能否使用
但是还是先给你kx奖励吧
难得有人这么热心
2010-12-5 15:38
0
游客
登录 | 注册 方可回帖
返回
//