在看v校分享的代码的时候,看到他的NtQueueApcThread没有从r3传,而是从ssdt获取,代码里面另外的两个函数是查符号表得到的。我就在想能不能从r3获取也一起传。查了好久的api,就是弄不懂到底说的啥意思,后来发现SymLoadModuleEx是比较关键的。
大体的思路是通过NtQuerySystemInformation获得内核基地址ModuleBase。SymInitializeW设置一下符号表地址。然后把内核模块当做dll加载一次,不过使用DONT_RESOLVE_DLL_REFERENCES标记,别让内核执行。然后调用SymLoadModuleEx再加载一次得到了第一次的基地址DllBase,估计这个函数内部调用LoadLiabrary,不过发现已经加载就只是增加计数值了。然后用SymFromNameW得到查找函数的地址。不过得加上ModuleBase-DllBase,就是相应函数的地址了。之后就是SymCleanup和FreeLibrary。
不过有个问题是,我用的符号表是从windbg下载的里面找的,符号表是ntkrpamp.pdb,但是内核确实ntkrnlpa.exe。不知道为何,反正windbg能用ntkrpamp.pdb解析ntkrnlpa.exe
代码只是测试一下,用v校代码改的,和我一样的菜鸟可以改一改用用,高手请飘过。
PVOID SymGetProcAddressKernel(LPCWSTR szApiName)
{
PSYSTEM_MODULE_INFORMATION SystemInfo;
BOOL bFind =FALSE;
DWORD dwBufferSize;
WCHAR *wszKernels[]={
L"ntoskrnl",// - 单处理器,不支持PAE
L"ntkrnlpa",// - 单处理器,支持PAE
L"ntkrnlmp",// - 多处理器,不支持PAE
L"ntkrpamp"// - 多处理器,支持PAE
};
DWORD i;
BYTE memory[0x2000];
ZeroMemory(memory, sizeof(memory));
SYMBOL_INFOW * info = (SYMBOL_INFOW *)memory;
HMODULE hDll;
WCHAR wcsPdb[MAX_PATH]={0};
WCHAR wcsExe[MAX_PATH]={0};
PCHAR Ptr,Last;
PWCHAR PathPtr;
WCHAR path[MAX_PATH] = { 0 };
WCHAR wcsImageName[MAX_PATH] = {0};
NtQuerySystemInformation((SYSTEMINFOCLASS)11,0,0,&dwBufferSize);
SystemInfo = (PSYSTEM_MODULE_INFORMATION)malloc(dwBufferSize);
NtQuerySystemInformation((SYSTEMINFOCLASS)11,SystemInfo,dwBufferSize,0);
Ptr = (PCHAR)SystemInfo->aSM[0].ImageName + strlen(SystemInfo->aSM[0].ImageName)-1;
Last = Ptr;
while(*Ptr){
if(*Ptr == '\\'){
Last = Ptr+1;
break;
}
Ptr --;
}
MultiByteToWideChar(CP_ACP,
0,
Last,
-1,
wcsImageName,
sizeof(wcsImageName));
for(i=0;i<4;i++){
if(!wcsnicmp(wszKernels[i],wcsImageName,wcslen(wszKernels[i]))){
bFind =TRUE;
break;
}
}
DWORD ret=0;
if(bFind){
wcscpy(wcsPdb,L"ntkrpamp.pdb");
wcscpy(wcsExe,wszKernels[i]);
wcscat(wcsExe,L".exe");
GetModuleFileNameW(0, path, _countof(path));
PathPtr= path+wcslen(path);
while(*PathPtr!='\\')
PathPtr--;
*PathPtr =L'\0';
if (!SymInitializeW(GetCurrentProcess(),path, TRUE)){
return NULL;
}
hDll = LoadLibraryExW(wcsImageName,NULL,DONT_RESOLVE_DLL_REFERENCES);
printf("%s:基地址%x\n",(DWORD)SystemInfo->aSM[0].ImageName,(PCHAR)SystemInfo->aSM[0].Base);
SymLoadModuleExW(GetCurrentProcess(),NULL,wszKernels[i],0,(DWORD)hDll,0,0,0);
info->SizeOfStruct = sizeof(SYMBOL_INFOW);
info->MaxNameLen = MAX_SYM_NAME;
SymFromNameW(GetCurrentProcess(),szApiName,info);
ret =(DWORD)info->Address - (DWORD)hDll+(DWORD)SystemInfo->aSM[0].Base;
FreeLibrary(hDll);
SymCleanup(GetCurrentProcess());
}
return (PVOID)ret;
}
记得印象最深的就是别用Release版调试,各种错误,比如内部变量会显示不出来。还是要用Debug版本调试。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)