NTSTATUS GetModuleBaseInformation(
IN PCHAR pModuleName,
OUT PSYSTEM_MODULE_INFORMATION psmi
)
{
PSYSTEM_MODULE_INFORMATION psmi2=0;
ULONG i;
ULONG uCount;
PCHAR pName;
ULONG dData;
PCHAR BaseAddress=NULL;
NTSTATUS rc;
ULONG cbBuffer = 0x8000;
PVOID pBuffer = NULL;
do
{
pBuffer = ExAllocatePool (PagedPool, cbBuffer);
if (pBuffer == NULL)
{
return rc;
}
rc = ZwQuerySystemInformation(
SystemModuleInformation, pBuffer, cbBuffer, &dData);
if (rc == STATUS_INFO_LENGTH_MISMATCH)
{
ExFreePool(pBuffer);
cbBuffer *= 2;
}
else if (!NT_SUCCESS(rc))
{
ExFreePool(pBuffer);
return rc;
}
}
while (rc == STATUS_INFO_LENGTH_MISMATCH);
uCount = (ULONG) *( (PULONG) pBuffer);
psmi2 = (PSYSTEM_MODULE_INFORMATION)((ULONG)pBuffer+sizeof(ULONG));
for ( i = 0; i < uCount; i++ )
{
DbgPrint("%s/n", (psmi2->ImageName+psmi2->ModuleNameOffset));
if(!_strnicmp(pModuleName, psmi2->ImageName+psmi2->ModuleNameOffset, strlen(pModuleName)))
{
*psmi = *psmi2;
break;
}
psmi2 = (PSYSTEM_MODULE_INFORMATION)((ULONG)psmi2 + sizeof(SYSTEM_MODULE_INFORMATION));
}
ExFreePool(pBuffer);
return rc;
}
IN PCHAR pModuleName,
OUT PSYSTEM_MODULE_INFORMATION psmi
)
{
PSYSTEM_MODULE_INFORMATION psmi2=0;
ULONG i;
ULONG uCount;
PCHAR pName;
ULONG dData;
PCHAR BaseAddress=NULL;
NTSTATUS rc;
ULONG cbBuffer = 0x8000;
PVOID pBuffer = NULL;
do
{
pBuffer = ExAllocatePool (PagedPool, cbBuffer);
if (pBuffer == NULL)
{
return rc;
}
rc = ZwQuerySystemInformation(
SystemModuleInformation, pBuffer, cbBuffer, &dData);
if (rc == STATUS_INFO_LENGTH_MISMATCH)
{
ExFreePool(pBuffer);
cbBuffer *= 2;
}
else if (!NT_SUCCESS(rc))
{
ExFreePool(pBuffer);
return rc;
}
}
while (rc == STATUS_INFO_LENGTH_MISMATCH);
uCount = (ULONG) *( (PULONG) pBuffer);
psmi2 = (PSYSTEM_MODULE_INFORMATION)((ULONG)pBuffer+sizeof(ULONG));
for ( i = 0; i < uCount; i++ )
{
DbgPrint("%s/n", (psmi2->ImageName+psmi2->ModuleNameOffset));
if(!_strnicmp(pModuleName, psmi2->ImageName+psmi2->ModuleNameOffset, strlen(pModuleName)))
{
*psmi = *psmi2;
break;
}
psmi2 = (PSYSTEM_MODULE_INFORMATION)((ULONG)psmi2 + sizeof(SYSTEM_MODULE_INFORMATION));
}
ExFreePool(pBuffer);
return rc;
}
ULONG
NTAPI GetHeaders(
PUCHAR ibase,
PIMAGE_FILE_HEADER *pfh,
PIMAGE_OPTIONAL_HEADER32 *poh,
PIMAGE_SECTION_HEADER *psh
)
{
NTSTATUS rc = STATUS_DEVICE_CONFIGURATION_ERROR;
__try {
PIMAGE_DOS_HEADER mzhead=(PIMAGE_DOS_HEADER)ibase;
if ( (mzhead->e_magic == IMAGE_DOS_SIGNATURE) &&
(ibaseDD[mzhead->e_lfanew] == IMAGE_NT_SIGNATURE) )
{
*pfh=(PIMAGE_FILE_HEADER)&ibase[mzhead->e_lfanew];
if (((PIMAGE_NT_HEADERS)*pfh)->Signature==IMAGE_NT_SIGNATURE)
{
*pfh=(PIMAGE_FILE_HEADER)((PBYTE)*pfh+sizeof(IMAGE_NT_SIGNATURE));
*poh=(PIMAGE_OPTIONAL_HEADER32)((PBYTE)*pfh+sizeof(IMAGE_FILE_HEADER));
if ((*poh)->Magic==IMAGE_NT_OPTIONAL_HDR32_MAGIC)
{
*psh=(PIMAGE_SECTION_HEADER)((PBYTE)*poh+sizeof(IMAGE_OPTIONAL_HEADER32));
rc = STATUS_SUCCESS;
}
}
}
} __except(EXCEPTION_EXECUTE_HANDLER)
{
return rc;
}
return rc;
}
// searches for the specified api in the import table and returns its rva
ULONG
NTAPI FindImport(
PUCHAR hModule,
PUCHAR Exporter,
PUCHAR ApiName
)
{
PIMAGE_FILE_HEADER pfh;
PIMAGE_OPTIONAL_HEADER poh;
PIMAGE_SECTION_HEADER psh;
PIMAGE_IMPORT_DESCRIPTOR pid;
PIMAGE_THUNK_DATA ptd;
PIMAGE_IMPORT_BY_NAME pibn;
__try {
GetHeaders(hModule,&pfh,&poh,&psh);
if (poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress) {
pid=(PIMAGE_IMPORT_DESCRIPTOR)RVATOVA(hModule,poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
__asm int 3
while (pid->FirstThunk && (pid->FirstThunk<poh->SizeOfImage)) {
if (!_stricmp((PCHAR)RVATOVA(hModule,pid->Name),Exporter)) {
for (ptd=(PIMAGE_THUNK_DATA)RVATOVA(hModule,pid->FirstThunk);ptd->u1.Function;ptd++) {
pibn=RVATOVA(hModule,ptd->u1.Function);
if (!strcmp(pibn->Name,ApiName))
return (ULONG)&ptd->u1.Function-(ULONG)hModule;
}
}
pid++;
}
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
}
return 0;
}
GetHeaders(hModule,&pfh,&poh,&psh);
if (poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress) {
pid=(PIMAGE_IMPORT_DESCRIPTOR)RVATOVA(hModule,poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
__asm int 3
while (pid->FirstThunk && (pid->FirstThunk<poh->SizeOfImage)) {
if (!_stricmp((PCHAR)RVATOVA(hModule,pid->Name),Exporter)) {
for (ptd=(PIMAGE_THUNK_DATA)RVATOVA(hModule,pid->FirstThunk);ptd->u1.Function;ptd++) {
pibn=RVATOVA(hModule,ptd->u1.Function);
if (!strcmp(pibn->Name,ApiName))
return (ULONG)&ptd->u1.Function-(ULONG)hModule;
}
}
pid++;
}
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
}
return 0;
}
ULONG
NTAPI FindExport(
PUCHAR hModule,
PUCHAR ApiName
)
{
PIMAGE_FILE_HEADER pfh;
PIMAGE_OPTIONAL_HEADER poh;
PIMAGE_SECTION_HEADER psh;
PIMAGE_EXPORT_DIRECTORY ped;
BOOL bDumbLinker;
BOOL bFindByOrdinal;
DWORD i = 0;
DWORD dwOrdinals = 0;
PDWORD pName;
WORD nOrdinal;
DWORD dwFuncRva = 0;
DWORD dwReturnRva = 0;
__try {
bFindByOrdinal = ((DWORD)ApiName == (WORD)ApiName);
GetHeaders(hModule,&pfh,&poh,&psh);
if (poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) {
ped = (PIMAGE_EXPORT_DIRECTORY)RVATOVA(hModule,poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
pName = (PDWORD)RVATOVA(hModule,ped->AddressOfNames);
for (i=0;i<ped->NumberOfFunctions;i++,pName++) {
bDumbLinker=FALSE;
// hack to avoid access violation when addressing bad pointers:
// some dumb linkers set NumberOfFunctions to the largest ordinal
// and NumberOfNames to the real functions number.
if (i*2+(DWORD)RVATOVA(hModule,ped->AddressOfNameOrdinals)==
(DWORD)RVATOVA(hModule,ped->Name)) {
bDumbLinker=TRUE;
break;
}
__try {
nOrdinal = ((PWORD)RVATOVA(hModule,ped->AddressOfNameOrdinals))[i];
dwFuncRva = ((PDWORD)(RVATOVA(hModule,ped->AddressOfFunctions)))[nOrdinal];
} __except(EXCEPTION_EXECUTE_HANDLER) {
bDumbLinker = TRUE;
}
// don't want to mess up my stack
if (bDumbLinker) break;
nOrdinal += (WORD)ped->Base;
if (!bFindByOrdinal && pName && i<ped->NumberOfNames) {
if (!strcmp(ApiName,(PCHAR)RVATOVA(hModule,*pName))) {
dwReturnRva = dwFuncRva;
break;
}
} else
if (bFindByOrdinal && (nOrdinal==(WORD)ApiName)) {
dwReturnRva = dwFuncRva;
break;
}
}
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
}
return dwReturnRva;
}
bFindByOrdinal = ((DWORD)ApiName == (WORD)ApiName);
GetHeaders(hModule,&pfh,&poh,&psh);
if (poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) {
ped = (PIMAGE_EXPORT_DIRECTORY)RVATOVA(hModule,poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
pName = (PDWORD)RVATOVA(hModule,ped->AddressOfNames);
for (i=0;i<ped->NumberOfFunctions;i++,pName++) {
bDumbLinker=FALSE;
// hack to avoid access violation when addressing bad pointers:
// some dumb linkers set NumberOfFunctions to the largest ordinal
// and NumberOfNames to the real functions number.
if (i*2+(DWORD)RVATOVA(hModule,ped->AddressOfNameOrdinals)==
(DWORD)RVATOVA(hModule,ped->Name)) {
bDumbLinker=TRUE;
break;
}
__try {
nOrdinal = ((PWORD)RVATOVA(hModule,ped->AddressOfNameOrdinals))[i];
dwFuncRva = ((PDWORD)(RVATOVA(hModule,ped->AddressOfFunctions)))[nOrdinal];
} __except(EXCEPTION_EXECUTE_HANDLER) {
bDumbLinker = TRUE;
}
// don't want to mess up my stack
if (bDumbLinker) break;
nOrdinal += (WORD)ped->Base;
if (!bFindByOrdinal && pName && i<ped->NumberOfNames) {
if (!strcmp(ApiName,(PCHAR)RVATOVA(hModule,*pName))) {
dwReturnRva = dwFuncRva;
break;
}
} else
if (bFindByOrdinal && (nOrdinal==(WORD)ApiName)) {
dwReturnRva = dwFuncRva;
break;
}
}
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
}
return dwReturnRva;
}
NTSTATUS LoadImage(
IN PUCHAR ModuleName,
OUT PMODULE_INFORMATION pmi
)
{
NTSTATUS rc = STATUS_DEVICE_CONFIGURATION_ERROR;
WCHAR wSystemRoot[MAX_PATH+1];
UNICODE_STRING uSystemRoot;
SYSTEM_MODULE_INFORMATION smi;
WCHAR wFilePath[MAX_PATH+1];
PCHAR PathName;
PCHAR ImageName;
ANSI_STRING AnsiPath;
UNICODE_STRING UnicodePath;
PVOID ptr2;
__try {
rc = GetModuleBaseInformation(ModuleName, &smi);
if (NT_SUCCESS(rc))
{
pmi->dwImageBase = smi.Base;
RtlInitUnicodeString(&uSystemRoot, wSystemRoot);
rc = GetSystemRoot(&uSystemRoot);
if (NT_SUCCESS(rc))
{
PathName = smi.ImageName + smi.ModuleNameOffset;
ImageName = smi.ImageName;
if (((PWORD)ImageName)[0]=='?//')
{
RtlInitAnsiString(&AnsiPath, ImageName);
rc = RtlAnsiStringToUnicodeString(&UnicodePath, &AnsiPath, TRUE);
if (NT_SUCCESS(rc))
{
_snwprintf((PWCHAR)&wFilePath, sizeof(wFilePath), L"%s",UnicodePath.Buffer);
RtlFreeUnicodeString(&UnicodePath);
rc = MapImage((PWCHAR)&wFilePath, pmi);
if (NT_SUCCESS(rc)) {
return rc;
}
}
} else
{
rc = STATUS_DEVICE_CONFIGURATION_ERROR;
}
if (!NT_SUCCESS(rc))
{
RtlInitAnsiString(&AnsiPath, PathName);
rc = RtlAnsiStringToUnicodeString(&UnicodePath, &AnsiPath, TRUE);
if (NT_SUCCESS(rc))
{
_snwprintf((PWCHAR)&wFilePath, sizeof(wFilePath), L"%ssystem32//drivers//%s", (PWCHAR)&wSystemRoot, UnicodePath.Buffer);
RtlFreeUnicodeString(&UnicodePath);
rc = MapImage((PWCHAR)&wFilePath, pmi);
if (NT_SUCCESS(rc)) {
return rc;
}
}
} if (!NT_SUCCESS(rc))
{
RtlInitAnsiString(&AnsiPath, PathName);
rc = RtlAnsiStringToUnicodeString(&UnicodePath, &AnsiPath, TRUE);
if (NT_SUCCESS(rc))
{
_snwprintf((PWCHAR)&wFilePath, sizeof(wFilePath), L"%ssystem32//%s", (PWCHAR)&wSystemRoot, UnicodePath.Buffer);
RtlFreeUnicodeString(&UnicodePath);
rc = MapImage((PWCHAR)&wFilePath, pmi);
if (NT_SUCCESS(rc)) {
return rc;
}
}
}
}
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
pmi->hModule=0;
}
if (!pmi->hModule)
rc = STATUS_DEVICE_CONFIGURATION_ERROR;
return rc;
}
NTSTATUS MapImage(
IN PWCHAR pwFileName,
OUT PMODULE_INFORMATION pmi
)
{
NTSTATUS rc = STATUS_DEVICE_CONFIGURATION_ERROR;
UNICODE_STRING uFileName;
OBJECT_ATTRIBUTES oa;
IO_STATUS_BLOCK iosb;
HANDLE FileHandle;
FILE_STANDARD_INFORMATION fsi;
LARGE_INTEGER ByteOffset;
PVOID FilePool = 0;
PIMAGE_FILE_HEADER pfh;
PIMAGE_OPTIONAL_HEADER poh;
PIMAGE_SECTION_HEADER psh;
ULONG i;
__try {
RtlInitUnicodeString(&uFileName, pwFileName);
InitializeObjectAttributes(&oa,&uFileName,OBJ_CASE_INSENSITIVE,NULL,NULL);
RtlZeroMemory(&iosb, sizeof(iosb));
rc = ZwOpenFile(&FileHandle,
GENERIC_READ | SYNCHRONIZE,
&oa,
&iosb,
FILE_SHARE_READ,
FILE_SYNCHRONOUS_IO_NONALERT
);
if (NT_SUCCESS(rc))
{
rc = ZwQueryInformationFile(FileHandle,&iosb,&fsi,sizeof(FILE_STANDARD_INFORMATION),FileStandardInformation);
if (NT_SUCCESS(rc))
{
FilePool = ExAllocatePool(PagedPool,fsi.EndOfFile.LowPart);
if (FilePool)
{
RtlZeroMemory(FilePool,fsi.EndOfFile.LowPart);
ByteOffset.QuadPart = 0;
rc = ZwReadFile(FileHandle,
NULL,
NULL,
NULL,
&iosb,
FilePool,
fsi.EndOfFile.LowPart,
&ByteOffset,
NULL);
if (NT_SUCCESS(rc))
{
rc = GetHeaders(FilePool,&pfh,&poh,&psh);
if (NT_SUCCESS(rc))
{
pmi->hModule=ExAllocatePool(PagedPool,poh->SizeOfImage);
if (pmi->hModule)
{
RtlZeroMemory(pmi->hModule,poh->SizeOfImage);
// copy header to the virtual image buffer
memcpy(pmi->hModule,FilePool,poh->SizeOfHeaders);
// copy sections
for (i=0;i<pfh->NumberOfSections;i++,psh++)
memcpy(pmi->hModule+psh->VirtualAddress,
(PVOID)((ULONG)FilePool+(ULONG)psh->PointerToRawData),
psh->SizeOfRawData);
}
}
}
ExFreePool(FilePool);
}
}
ZwClose(FileHandle);
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
}
return rc;
}
NTSTATUS UnMapImage(
OUT PMODULE_INFORMATION pmi
)
{
NTSTATUS rc = STATUS_DEVICE_CONFIGURATION_ERROR;
__try {
ExFreePool(pmi->hModule);
RtlZeroMemory(pmi,sizeof(MODULE_INFORMATION));
} __except(EXCEPTION_EXECUTE_HANDLER) {
}
return rc;
}
ULONG SearchKiServiceTable(
PUCHAR hModule,
ULONG dwKSDT
)
{
PIMAGE_FILE_HEADER pfh;
PIMAGE_OPTIONAL_HEADER poh;
PIMAGE_SECTION_HEADER psh;
PIMAGE_BASE_RELOCATION pbr;
PIMAGE_FIXUP_ENTRY pfe;
DWORD dwFixups=0;
DWORD i;
DWORD dwPointerRva;
DWORD dwPointsToRva;
DWORD dwKiServiceTable;
BOOL bFirstChunk;
GetHeaders((char*)(PBYTE)hModule,&pfh,&poh,&psh);
// loop thru relocs to speed up the search
if ((poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress) &&
(!((pfh->Characteristics)&IMAGE_FILE_RELOCS_STRIPPED)))
{
pbr = (PIMAGE_BASE_RELOCATION)RVATOVA(poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,hModule);
bFirstChunk = TRUE;
// 1st IMAGE_BASE_RELOCATION.VirtualAddress of ntoskrnl is 0
while (bFirstChunk || pbr->VirtualAddress) {
bFirstChunk=FALSE;
pfe=(PIMAGE_FIXUP_ENTRY)((DWORD)pbr+sizeof(IMAGE_BASE_RELOCATION));
for (i=0;i<(pbr->SizeOfBlock-sizeof(IMAGE_BASE_RELOCATION))>>1;i++,pfe++) {
if (pfe->type==IMAGE_REL_BASED_HIGHLOW) {
dwFixups++;
dwPointerRva=pbr->VirtualAddress+pfe->offset;
// DONT_RESOLVE_DLL_REFERENCES flag means relocs aren't fixed
dwPointsToRva=*(PDWORD)((DWORD)hModule+dwPointerRva)-(DWORD)poh->ImageBase;
// does this reloc point to KeServiceDescriptorTable.Base?
if (dwPointsToRva==dwKSDT) {
// check for mov [mem32],imm32. we are trying to find
// "mov ds:_KeServiceDescriptorTable.Base, offset _KiServiceTable"
// from the KiInitSystem.
if (*(PWORD)((DWORD)hModule+dwPointerRva-2)==0x05c7) {
// should check for a reloc presence on KiServiceTable here
// but forget it
dwKiServiceTable=*(PDWORD)((DWORD)hModule+dwPointerRva+4)-poh->ImageBase;
return dwKiServiceTable;
}
}
} else if (pfe->type!=IMAGE_REL_BASED_ABSOLUTE)
// should never get here
DbgPrint("/trelo type %d found at .%X/n",pfe->type,pbr->VirtualAddress+pfe->offset);
}
*(PDWORD)&pbr+=pbr->SizeOfBlock;
}
}
if (!dwFixups)
// should never happen - nt, 2k, xp kernels have relocation data
DbgPrint("No fixups!/n");
return 0;
}
NTSTATUS FindKiSystemService(
PDWORD _KiServiceTable
)
{
SYSTEM_MODULE_INFORMATION smi;
MODULE_INFORMATION mi;
NTSTATUS rc = STATUS_DEVICE_CONFIGURATION_ERROR;
ULONG RVAKiSystemService = 0;
ULONG RVATableShadow = 0;
__try {
*_KiServiceTable = 0;
rc = LoadImage("ntoskrnl.exe", &mi);
if (NT_SUCCESS(rc)) {
RVAKiSystemService = FindExport(mi.hModule,"KeServiceDescriptorTable");
if (RVAKiSystemService != 0) {
*_KiServiceTable = SearchKiServiceTable(mi.hModule,RVAKiSystemService);
}
RVATableShadow = FindExport(mi.hModule,"KeAddSystemServiceTable");
if (RVATableShadow != 0) {
*_KiServiceTable = (ULONG)GetKeServiceDescriptorTableShadow((PUCHAR)mi.hModule + RVATableShadow);
}
UnMapImage(&mi);
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
}
return rc;
}