解读 RtlGetVersion
获得系统版本号。
NTSTATUS RtlGetVersion(OSVERSIONINFOW &VersionInformation)
{
UINT_PTR pfn = CalcFunctionAddress(phWCP, pfb_RtlGetVersion);
typedef signed int(__stdcall * fnRtlGetVersion)(OSVERSIONINFOW&);
fnRtlGetVersion g_fnRtlGetVersion = (fnRtlGetVersion)*(UINT_PTR*)pfn;
VersionInformation.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
memset(&VersionInformation.dwMajorVersion, ,
sizeof(VersionInformation.szCSDVersion));
NTSTATUS result = g_fnRtlGetVersion(VersionInformation);
return result;
}
这个函数比较特别的是,属
于导入函数,在 WCP.dll 中只有函数的地址。
在 64 位版本下有个备注,可以知道其地址:
1802449C0: using guessed type int __fastcall RtlGetVersion(_QWORD);
32 位版本却没有任何信息。
从 ida 中找到导入函数:
584904D0 RtlGetVersion ntdll
再减去 wcp.dll 的起始地址:
using load address 58210000
得到 RtlGetVersion 在 wcp.dll 中的函数的偏移地址,0x102804D0。
这样就可以用与本地函数基本相同的方法访问导入函数了。
既然是基本相同,那就肯定有不同了。
本地函数,用偏移地址经过计算出来的地址就是函数地址了,可以直接进行调用。
而导入函数,用偏移地址经过计算出来的地址并不是该函数的真正地址,而是,原函数在本地统一编址的地址,这个地址中保存的值才是原函数的真正地址,0x7753bd40。可以看到,这明显是另外一
相比较本地函数,导入函数要多取一次地址值的过程,(UINT_PTR):
本地函数:
fnRtlGetVersion g_fnRtlGetVersion = (fnRtlGetVersion)pfn;
导入函数:
fnRtlGetVersion g_fnRtlGetVersion = (fnRtlGetVersion)(UINT_PTR)pfn;
当然,这个函数并不需要通过这种方法进行调用,只是为了熟悉函数的调用方法而已。