解讀 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;
當然,這個函數并不需要通過這種方法進行調用,隻是為了熟悉函數的調用方法而已。