|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
то f_ptr'у может быть присвоен адрес stub'а, принадлежащего вашему модулю:
а может быть и так, что избраная вами функция просто начинается с такой инструкции. Например, начиная с Windows 2000
Плюс еще некоторые антивирусы, firewall'ы и другие более или менее полезные драйвера могут вставлять в системные функции первой иструкцией JMP на себя. А еще некоторые могут перехватывать загрузку модулей и менять адреса импортов прямо в вашем модуле. Так вот. Это я к тому, что абсолютного решения нет и при использовании описаных методов требуется некоторая внимательность. А еще к тому, что если вы сами пишете такую хитрую систему, подумайте еще и о совместимости с другими хитрецами ;). Для надежности я бы порекомендовал проверить, не совпадает ли полученый ModuleHandle с нашим собственным, и если совпал - значит нам подсунули stub из нашего собственного модуля и из него нужно извлечь настоящий адрес точки входа в экспортируемую функцию. Например с помощью SkipImportStub(). Когда мы уже думаем, что у нас в руках правильный ModuleHandle, еще неплохо бы убедиться, что из этого модуля экспортируется та функция, с адреса которой мы начали. Т.е. если вдруг окажется, что отталкиваясь от адреса DbgPrint мы придем к модулю, который не экспортирует такой функции, значит нас обманули. Note 2: Exkurs предложил более правильный подход - импортировать NtBuildNumber из ntoskrnl.exe. Во-первых, эта эта константа присутствует во всех версиях WinNT, а во-вторых - не нужно проверять, является ли полученый адрес call stub'ом. О недостатках: Помимо того, что это совсем уж хакерский метод, его недостатком смело можно назвать невозможность найти произвольный модуль по одному лишь имени. ModuleBaseByPeb()Для полноты картины стоит упомянуть еще один метод - KernelGetModuleBaseByPeb(). Он похож на KernelGetModuleBase3(). Отличие состоит в том, что LDR_DATA_TABLE_ENTRY берется из PEB - Process Environment Block. А т.к. PEB присущ только Win32 процессам, в kernel-mode этим методом можно воспользоваться только в соответствующем контексте (т.е. в контексте Win32 или Native приложения). В system-thread работать не будет. Note: Вскрытие показало, что начиная с Windows 2003 R2 изменилась структура KTHREAD_HDR, из которой мы PEB получаем. См. сюда. MiLocateExportNameВ порядке общего образование: начиная с Win 2000 существует такая неэкспортируемая функция:
Делает то же, что и KernelGetProcAddress(). Спасибо DeastSoft за информацию. Функции и таблица применимости
Исходники
KernelGetModuleBaseNT 4.0 и старше
PVOID
KernelGetModuleBase(
PCHAR pModuleName
)
{
PVOID pModuleBase = NULL;
PULONG pSystemInfoBuffer = NULL;
__try
{
NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
ULONG SystemInfoBufferSize = 0;
status = ZwQuerySystemInformation(SystemModuleInfo,
&SystemInfoBufferSize,
0,
&SystemInfoBufferSize);
if (!SystemInfoBufferSize)
return NULL;
pSystemInfoBuffer = (PULONG)ExAllocatePool(NonPagedPool, SystemInfoBufferSize*2);
if (!pSystemInfoBuffer)
return NULL;
memset(pSystemInfoBuffer, 0, SystemInfoBufferSize*2);
status = ZwQuerySystemInformation(SystemModuleInfo,
pSystemInfoBuffer,
SystemInfoBufferSize*2,
&SystemInfoBufferSize);
if (NT_SUCCESS(status))
{
PSYSTEM_MODULE_ENTRY pSysModuleEntry =
((PSYSTEM_MODULE_INFORMATION)(pSystemInfoBuffer))->Module;
ULONG i;
for (i = 0; i <((PSYSTEM_MODULE_INFORMATION)(pSystemInfoBuffer))->Count; i++)
{
if (_stricmp(pSysModuleEntry[i].ModuleName +
pSysModuleEntry[i].ModuleNameOffset, pModuleName) == 0)
{
pModuleBase = pSysModuleEntry[i].ModuleBaseAddress;
break;
}
}
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
pModuleBase = NULL;
}
if(pSystemInfoBuffer) {
ExFreePool(pSystemInfoBuffer);
}
return pModuleBase;
} // end KernelGetModuleBase()
SYSTEM_MODULE_INFORMATION
// Class 11
typedef struct _SYSTEM_MODULE_INFORMATION_ENTRY
{
ULONG Unknown1;
ULONG Unknown2;
#ifdef _WIN64
ULONG Unknown3;
ULONG Unknown4;
#endif
PVOID Base;
ULONG Size;
ULONG Flags;
USHORT Index;
USHORT NameLength;
USHORT LoadCount;
USHORT PathLength;
CHAR ImageName[256];
} SYSTEM_MODULE_INFORMATION_ENTRY, *PSYSTEM_MODULE_INFORMATION_ENTRY;
typedef struct _SYSTEM_MODULE_INFORMATION
{
ULONG Count;
SYSTEM_MODULE_INFORMATION_ENTRY Module[1];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
RtlImageDirectoryEntryToData
PVOID
RtlImageDirectoryEntryToData(
IN PVOID Base,
IN BOOLEAN MappedAsImage,
IN USHORT DirectoryEntry,
OUT PULONG Size
);
KernelGetProcAddress
PVOID
KernelGetProcAddress(
PVOID ModuleBase,
PCHAR pFunctionName
)
{
PVOID pFunctionAddress = NULL;
__try
{
#ifndef WIN9X_SUPPORT
ULONG size = 0;
PIMAGE_EXPORT_DIRECTORY exports =(PIMAGE_EXPORT_DIRECTORY)
RtlImageDirectoryEntryToData(ModuleBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size);
ULONG addr = (PUCHAR)((ULONG)exports-(ULONG)ModuleBase);
#else
PIMAGE_DOS_HEADER dos =(PIMAGE_DOS_HEADER) ModuleBase;
PIMAGE_NT_HEADERS nt =(PIMAGE_NT_HEADERS)((ULONG) ModuleBase + dos->e_lfanew);
PIMAGE_DATA_DIRECTORY expdir = (PIMAGE_DATA_DIRECTORY)
(nt->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_EXPORT);
ULONG addr = expdir->VirtualAddress;
PIMAGE_EXPORT_DIRECTORY exports =(PIMAGE_EXPORT_DIRECTORY)((ULONG) ModuleBase + addr);
#endif
PULONG functions =(PULONG)((ULONG) ModuleBase + exports->AddressOfFunctions);
PSHORT ordinals =(PSHORT)((ULONG) ModuleBase + exports->AddressOfNameOrdinals);
PULONG names =(PULONG)((ULONG) ModuleBase + exports->AddressOfNames);
ULONG max_name =exports->NumberOfNames;
ULONG max_func =exports->NumberOfFunctions;
ULONG i;
for (i = 0; i < max_name; i++)
{
ULONG ord = ordinals[i];
if(i >= max_name || ord >= max_func) {
return NULL;
}
if (functions[ord] < addr || functions[ord] >= addr + size)
{
if (strcmp((PCHAR) ModuleBase + names[i], pFunctionName) == 0)
{
pFunctionAddress =(PVOID)((PCHAR) ModuleBase + functions[ord]);
break;
}
}
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
pFunctionAddress = NULL;
}
return pFunctionAddress;
} // end KernelGetProcAddress()
LDR_DATA_TABLE_ENTRY
typedef struct _LDR_DATA_TABLE_ENTRY {
LIST_ENTRY LoadOrder;
LIST_ENTRY MemoryOrder;
LIST_ENTRY InitializationOrder;
PVOID ModuleBaseAddress;
PVOID EntryPoint;
ULONG ModuleSize;
UNICODE_STRING FullModuleName;
UNICODE_STRING ModuleName;
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
union {
LIST_ENTRY Hash;
struct {
PVOID SectionPointer;
ULONG CheckSum;
};
};
ULONG TimeStamp;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
KernelGetModuleBase3NT 3.51 и старше
PLIST_ENTRY g_LoadOrderListHead = NULL;
PVOID
KernelGetModuleBase3(
PDRIVER_OBJECT DriverObject,
PCHAR pModuleName
)
{
PVOID pModuleBase = NULL;
PLIST_ENTRY Next;
PLIST_ENTRY LoadOrderListHead;
UNICODE_STRING uStr;
PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
PLDR_DATA_TABLE_ENTRY LdrDataTableEntry0;
ULONG len;
BOOLEAN FreeUstr = FALSE;
uStr.Buffer = NULL;
__try
{
if(!g_LoadOrderListHead) {
LdrDataTableEntry0 = (PLDR_DATA_TABLE_ENTRY)DriverObject->DriverSection;
uStr.Length = sizeof(L"NTOSKRNL.EXE")-sizeof(WCHAR);
uStr.MaximumLength = sizeof(L"NTOSKRNL.EXE");
uStr.Buffer = L"NTOSKRNL.EXE";
Next = LdrDataTableEntry0->LoadOrder.Blink;
while ( TRUE ) {
LdrDataTableEntry = CONTAINING_RECORD( Next,
LDR_DATA_TABLE_ENTRY,
LoadOrder
);
Next = Next->Blink;
if(!LdrDataTableEntry->ModuleName.Buffer) {
return NULL;
}
if(RtlCompareUnicodeString(&LdrDataTableEntry->ModuleName, &uStr, TRUE) == 0)
{
LoadOrderListHead = Next;
break;
}
if(LdrDataTableEntry == LdrDataTableEntry0)
return NULL;
}
g_LoadOrderListHead = LoadOrderListHead;
} else {
LoadOrderListHead = g_LoadOrderListHead;
}
len = strlen(pModuleName);
if(!len)
return NULL;
len = (len+1)*sizeof(WCHAR);
uStr.MaximumLength = (USHORT)len;
uStr.Length = (USHORT)len - sizeof(WCHAR);
uStr.Buffer = (PWCHAR)ExAllocatePool(NonPagedPool, len);
FreeUstr = TRUE;
swprintf(uStr.Buffer, L"%S", pModuleName);
Next = LoadOrderListHead->Flink;
while ( Next != LoadOrderListHead ) {
LdrDataTableEntry = CONTAINING_RECORD( Next,
LDR_DATA_TABLE_ENTRY,
LoadOrder
);
if(RtlCompareUnicodeString(&LdrDataTableEntry->ModuleName, &uStr, TRUE) == 0)
{
pModuleBase = LdrDataTableEntry->ModuleBaseAddress;
break;
}
Next = Next->Flink;
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
pModuleBase = NULL;
}
if(FreeUstr && uStr.Buffer) {
ExFreePool(uStr.Buffer);
}
return pModuleBase;
} // end KernelGetModuleBase3()
SkipImportStubДля всего 32-битного семейства Windows на x86 (в т.ч. ReactOS, Win9x)
PVOID
SkipImportStub(
PVOID p
)
{
if(((PUCHAR)p)[0] == 0xff && ((PUCHAR)p)[1] == 0x25) {
p = (PVOID)(*(PULONG)(*(PULONG)((ULONG)p+2)));
}
return p;
} // end SkipImportStub()
KernelGetModuleBaseByPtrДля всего 32-битного семейства Windows на x86 (в т.ч. ReactOS, Win9x)
PVOID
KernelGetModuleBaseByPtr(
IN PVOID ptrInSection,
IN PCHAR ptrExportedName
)
{
PUCHAR p;
PIMAGE_DOS_HEADER dos;
PIMAGE_NT_HEADERS nt;
p = (PUCHAR)((ULONG)ptrInSection & ~(PAGE_SIZE-1));
for(;p;p -= PAGE_SIZE) {
__try
{
dos = (PIMAGE_DOS_HEADER)p;
if(dos->e_magic != 0x5a4d) // MZ
continue;
nt = (PIMAGE_NT_HEADERS)((ULONG)dos + dos->e_lfanew);
if((ULONG)nt >= (ULONG)ptrInSection)
continue;
if((ULONG)nt <= (ULONG)dos)
continue;
if(nt->Signature != 0x00004550) // PE
continue;
if(!ptrExportedName) {
break;
} else {
if(ptrInSection == KernelGetProcAddress(p, ptrExportedName)) {
break;
}
}
p = NULL;
break;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
}
return p;
} // end KernelGetModuleBaseByPtr()
PEB_LDR_DATA
typedef struct _PEB_LDR_DATA {
ULONG Length;
BOOLEAN Initialized;
HANDLE SsHandle;
LIST_ENTRY LoadOrder;
LIST_ENTRY MemoryOrder;
LIST_ENTRY InitializationOrder;
} PEB_LDR_DATA, *PPEB_LDR_DATA;
PEB
typedef struct _PEB {
BOOLEAN InheritedAddressSpace;
BOOLEAN ReadImageFileExecOptions;
BOOLEAN BeingDebugged;
BOOLEAN SpareBool;
HANDLE Mutant;
PVOID ImageBaseAddress;
PPEB_LDR_DATA Ldr;
struct _RTL_USER_PROCESS_PARAMETERS *ProcessParameters;
PVOID SubSystemData;
PVOID ProcessHeap;
PVOID FastPebLock;
PVOID FastPebLockRoutine;
PVOID FastPebUnlockRoutine;
ULONG EnvironmentUpdateCount;
PVOID KernelCallbackTable;
HANDLE EventLogSection;
PVOID EventLog;
PPEB_FREE_BLOCK FreeList;
ULONG TlsExpansionCounter;
PVOID TlsBitmap;
ULONG TlsBitmapBits[2]; // relates to TLS_MINIMUM_AVAILABLE
PVOID ReadOnlySharedMemoryBase;
PVOID ReadOnlySharedMemoryHeap;
PVOID *ReadOnlyStaticServerData;
PVOID AnsiCodePageData;
PVOID OemCodePageData;
PVOID UnicodeCaseTableData;
// Useful information for LdrpInitialize
ULONG NumberOfProcessors;
ULONG NtGlobalFlag;
// Passed up from MmCreatePeb from Session Manager registry key
LARGE_INTEGER CriticalSectionTimeout;
ULONG HeapSegmentReserve;
ULONG HeapSegmentCommit;
ULONG HeapDeCommitTotalFreeThreshold;
ULONG HeapDeCommitFreeBlockThreshold;
// Where heap manager keeps track of all heaps created for a process
// Fields initialized by MmCreatePeb. ProcessHeaps is initialized
// to point to the first free byte after the PEB and MaximumNumberOfHeaps
// is computed from the page size used to hold the PEB, less the fixed
// size of this data structure.
ULONG NumberOfHeaps;
ULONG MaximumNumberOfHeaps;
PVOID *ProcessHeaps;
//
//
PVOID GdiSharedHandleTable;
PVOID ProcessStarterHelper;
PVOID GdiDCAttributeList;
PVOID LoaderLock;
// Following fields filled in by MmCreatePeb from system values and/or
// image header.
ULONG OSMajorVersion;
ULONG OSMinorVersion;
ULONG OSBuildNumber;
ULONG OSPlatformId;
ULONG ImageSubsystem;
ULONG ImageSubsystemMajorVersion;
ULONG ImageSubsystemMinorVersion;
ULONG ImageProcessAffinityMask;
ULONG GdiHandleBuffer[GDI_HANDLE_BUFFER_SIZE];
} PEB, *PPEB;
TEB
typedef struct _TEB {
NT_TIB NtTib;
PVOID EnvironmentPointer;
CLIENT_ID ClientId;
PVOID ActiveRpcHandle;
PVOID ThreadLocalStoragePointer;
PPEB ProcessEnvironmentBlock;
ULONG LastErrorValue;
ULONG CountOfOwnedCriticalSections;
PVOID CsrClientThread;
PVOID Win32ThreadInfo; // PtiCurrent
ULONG Win32ClientInfo[WIN32_CLIENT_INFO_LENGTH]; // User32 Client Info
PVOID WOW32Reserved; // used by WOW
LCID CurrentLocale;
ULONG FpSoftwareStatusRegister;
PVOID SystemReserved1[54]; // Used by FP emulator
PVOID Spare1; // unused
NTSTATUS ExceptionCode; // for RaiseUserException
UCHAR SpareBytes1[40];
PVOID SystemReserved2[10]; // Used by user/console for temp obja
GDI_TEB_BATCH GdiTebBatch; // Gdi batching
ULONG gdiRgn;
ULONG gdiPen;
ULONG gdiBrush;
CLIENT_ID RealClientId;
HANDLE GdiCachedProcessHandle;
ULONG GdiClientPID;
ULONG GdiClientTID;
PVOID GdiThreadLocalInfo;
PVOID UserReserved[5]; // unused
PVOID glDispatchTable[280]; // OpenGL
ULONG glReserved1[26]; // OpenGL
PVOID glReserved2; // OpenGL
PVOID glSectionInfo; // OpenGL
PVOID glSection; // OpenGL
PVOID glTable; // OpenGL
PVOID glCurrentRC; // OpenGL
PVOID glContext; // OpenGL
ULONG LastStatusValue;
UNICODE_STRING StaticUnicodeString;
WCHAR StaticUnicodeBuffer[STATIC_UNICODE_BUFFER_LENGTH];
PVOID DeallocationStack;
PVOID TlsSlots[TLS_MINIMUM_AVAILABLE];
LIST_ENTRY TlsLinks;
PVOID Vdm;
PVOID ReservedForNtRpc;
PVOID DbgSsReserved[2];
ULONG HardErrorsAreDisabled;
PVOID Instrumentation[16];
PVOID WinSockData; // WinSock
ULONG GdiBatchCount;
ULONG Spare2;
ULONG Spare3;
ULONG Spare4;
PVOID ReservedForOle;
ULONG WaitingOnLoaderLock;
} TEB;
KTHREAD_HDR, KTHREAD_HDR_2003_R2По всей видимости для всех ОС младше 2003-R2.
typedef struct _KTHREAD_HDR {
// The dispatcher header and mutant listhead are faifly infrequently
// referenced, but pad the thread to a 32-byte boundary (assumption
// that pool allocation is in units of 32-bytes).
DISPATCHER_HEADER Header;
LIST_ENTRY MutantListHead;
// The following fields are referenced during trap, interrupts, or
// context switches.
//
// N.B. The Teb address and TlsArray are loaded as a quadword quantity
// on MIPS and therefore must to on a quadword boundary.
PVOID InitialStack;
PVOID StackLimit;
PVOID Teb ;
PVOID TlsArray;
PVOID KernelStack;
BOOLEAN DebugActive;
UCHAR State;
BOOLEAN Alerted[MaximumMode];
UCHAR Iopl;
UCHAR NpxState;
BOOLEAN Saturation;
SCHAR Priority;
/*
.........
*/
} KTHREAD_HDR, *PKTHREAD_HDR;
typedef struct _KTHREAD_HDR_2003_R2 {
DISPATCHER_HEADER Header;
LIST_ENTRY MutantListHead;
PVOID InitialStack;
PVOID StackLimit;
/*
Several new items here
*/
PVOID Teb ; // offset 0x74
/*
.........
*/
} KTHREAD_HDR_2003_R2, *PKTHREAD_HDR_2003_R2;
KernelGetModuleBaseByPeb
__declspec (naked)
PVOID
__stdcall
GetCurrentKThread(void)
{
_asm {
mov eax,fs:[124h]
ret
}
}
/************************/
PKTHREAD_HDR KThread;
PPEB Peb = NULL;
PPEB_LDR_DATA Ldr = NULL;
PTEB Teb;
PLIST_ENTRY InitialEntry;
PLIST_ENTRY LoadOrderListHead;
PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
KThread = (PKTHREAD_HDR)GetCurrentKThread();
if(!KThread)
return NULL;
if(WinVer_Id() >= WIN_VER_2003_R2) {
Teb = (PTEB)(( ((PKTHREAD_HDR_2003_R2)KThread) ->Teb);
} else {
Teb = (PTEB)(KThread->Teb);
}
if(!Teb)
return NULL;
Peb = Teb->ProcessEnvironmentBlock;
if(!Peb)
return NULL;
Ldr = Peb->Ldr;
if(!Ldr)
return NULL;
InitialEntry = Ldr->InitializationOrder.Flink;
LdrDataTableEntry = CONTAINING_RECORD( InitialEntry,
LDR_DATA_TABLE_ENTRY,
InitializationOrder
);
LoadOrderListHead = LdrDataTableEntry->LoadOrder.Blink;
/************************/
ПримерыПример 1
PVOID NtKrnlModuleHandle;
PVOID ptrNtBuildNumber;
PVOID ptrIofCallDriver;
// get address of variable inside "ntoskrnl.exe"
ptrNtBuildNumber = &NtBuildNumber;
// get base address of "ntoskrnl.exe" image
NtKrnlModuleHandle = KernelGetModuleBaseByPtr(ptrNtBuildNumber, "NtBuildNumber");
// locate exported function "IofCallDriver" inside "ntoskrnl.exe"
ptrIofCallDriver = KernelGetProcAddress(NtKrnlModuleHandle, "IofCallDriver");
Пример 2
PVOID NtKrnlModuleHandle;
PVOID ptrDbgPrint;
PVOID ptrIofCallDriver;
// get address of function inside "ntoskrnl.exe"
ptrDbgPrint = SkipImportStub(DbgPrint);
// get base address of "ntoskrnl.exe" image
NtKrnlModuleHandle = KernelGetModuleBaseByPtr(ptrDbgPrint, "DbgPrint");
// locate exported function "IofCallDriver" inside "ntoskrnl.exe"
ptrIofCallDriver = KernelGetProcAddress(NtKrnlModuleHandle, "IofCallDriver");
Пример 3
PVOID OurDriverModuleHandle;
// get base address of our driver image
OurDriverModuleHandle = KernelGetModuleBaseByPtr(DriverEntry, "DriverEntry");
Пример 4
PVOID NtKrnlModuleHandle;
PVOID ptrIofCallDriver;
// get base address of our driver image
NtKrnlModuleHandle = KernelGetModuleBase3(DriverObject, "ntoskrnl.exe");
// locate exported function "IofCallDriver" inside "ntoskrnl.exe"
ptrIofCallDriver = KernelGetProcAddress(NtKrnlModuleHandle, "IofCallDriver");
2006.08.27 PS. Старые версии этой статьи тоже сохранились:
См. также | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||