[EncodePointer]. *my system: Windows XP SP3 [тестила и на win xp2 то же] Пишу сию небольшую заметочку про EncodePointer. Статьей это => не является. Некогда довелось мне заниматься VEH и писать плаг под Olly, перебирающий все обработчики в дебажимом процессе. И функция EncodePointer создала мне на системах с SP (в виндах без СП, как выяснилось этой функции нет вовсе) некоторые проблемы и при получении адреса вех-обработчика я извращалась с трейсом. Как вы можете прочесть в msdn Здесь все предельно понятно. И вех-обработчики в системах с SP как раз-таки подвергаются такой обработке. Функция шифрует адрес Ptr неким значением, уникальным для каждого процесса. Теперь попробуем разобраться в общих чертах как оно работает и откуда это значение берется. Код функции RtlEncodePointer Code: 7C9133DF ntdll.RtlEncodePointer /$ 8BFF MOV EDI,EDI ; ntdll.7C910208 7C9133E1 |. 55 PUSH EBP 7C9133E2 |. 8BEC MOV EBP,ESP 7C9133E4 |. 51 PUSH ECX ; ntdll.7C9164EE 7C9133E5 |. 6A 00 PUSH 0 ; /pReqsize = NULL 7C9133E7 |. 6A 04 PUSH 4 ; |Bufsize = 4 7C9133E9 |. 8D45 FC LEA EAX,[LOCAL.1] ; | 7C9133EC |. 50 PUSH EAX ; |Buffer = NULL 7C9133ED |. 6A 24 PUSH 24 ; |InfoClass = 24 (36.) 7C9133EF |. 6A FF PUSH -1 ; |hProcess = FFFFFFFF 7C9133F1 |. E8 EAA3FFFF CALL ZwQueryInformationProcess ; \ZwQueryInformationProcess 7C9133F6 |. 8B45 FC MOV EAX,[LOCAL.1] 7C9133F9 |. 3345 08 XOR EAX,[ARG.1] 7C9133FC |. C9 LEAVE 7C9133FD \. C2 0400 RET 4 То есть мы вызываем ZwQueryInformationProcess с InfoClass = SystemContextSwitchInformation (36) и ксорим с адресом, переданным функции в качестве аргумента. Ясное дело, что в ntdll более нам делать нечего, надо спускаться в ядро и смотреть откуда берется этот уникальный дворд. Загружаем ntoskrnl.exe в IDA и смотрим функцию NtQueryInformationProcess. Весь код функции, приводить, конечно, не буду, ибо нет смысла. Выделю только основные моменты. Найдем то место в функции, которое обрабатывает InfoClass = SystemContextSwitchInformation = 36 = 0x24 Code: PAGE:0049CEFA mov eax, [ebp+ProcessInformationClass] PAGE:0049CEFD push 16h PAGE:0049CEFF pop ecx PAGE:0049CF00 cmp eax, ecx PAGE:0049CF02 jg loc_4A0E7F PAGE:0049CF08 jz loc_4A1379 Ну тут ясно, что в eax в нашем случае (0049CF00) будет 24h, а в ecx 16h. Значит нам по адресу loc_4A0E7F. Code: loc_4A0E7F: ; CODE XREF: NtQueryInformationProcess(x,x,x,x,x)+53 PAGE:004A0E7F add eax, -17h ; switch 15 cases PAGE:004A0E82 cmp eax, 0Eh PAGE:004A0E85 ja Invalid_InfoClass ; default PAGE:004A0E8B jmp ds:off_4A18CA[eax*4] ; switch jump Мысленно(или на калькуляторе %) ) eax(==24h) +(-17h). Получаем 0D. Далее Выполняем джамп (при eax = 0d) Code: PAGE:004A0E8B jmp ds:off_4A18CA[eax*4] Попадаем сюда Code: PAGE:004A0E92 SystemContextSwitchInformation_0: ; DATA XREF: PAGE:off_4A18CA o PAGE:004A0E92 cmp edi, edx ; case 0x24 PAGE:004A0E94 jnz InfoLengthMismatch PAGE:004A0E9A cmp [ebp+Handle], 0FFFFFFFFh PAGE:004A0E9E jnz not_current_process Обратите внимание на сделанное мной обозначение. То есть, если передан хендл не текущего процесса, то Code: PAGE:004A1578 not_current_process: ; CODE XREF: NtQueryInformationProcess(x,x,x,x,x)+3FEF j PAGE:004A1578 ; NtQueryInformationProcess(x,x,x,x,x)+46BA j ... PAGE:004A1578 mov eax, STATUS_INVALID_PARAMETER Ну оно и верно. Если бы этот дворд можно было получить из другого процесса, было бы странно. Теперь продолжим. Если мы интересуемся своим процессом Code: PAGE:004A0EA4 mov eax, large fs:124h PAGE:004A0EAA mov eax, [eax+44h] PAGE:004A0EAD mov [ebp+var_34], eax PAGE:004A0EB0 get_dw: ; CODE XREF: NtQueryInformationProcess(x,x,x,x,x)+18E71 j PAGE:004A0EB0 mov edi, [ebp+PEPROCESS] PAGE:004A0EB3 add edi, 258h PAGE:004A0EB9 mov eax, [edi] PAGE:004A0EBB test eax, eax PAGE:004A0EBD jz get_time Некоторым первые строки покажутся очень знакомыми. В eax после их исполнения окажется указатель на структуру EPROCESS текущего процесса. Далее мы добавляем к началу EPROCESS 258h. И берем по этому адресу dword. Если значение нулевое, то Code: PAGE:004A0EBB test eax, eax PAGE:004A0EBD jz get_time Получаем системное время Code: PAGE:004B5CF6 get_time: ; CODE XREF: NtQueryInformationProcess(x,x,x,x,x)+400E j PAGE:004B5CF6 lea eax, [ebp+CurrentTime] PAGE:004B5CF9 push eax ; CurrentTime PAGE:004B5CFA call _KeQuerySystemTime@4 ; KeQuerySystemTime(x) PAGE:004B5CFF mov eax, large fs:_KPRCB PAGE:004B5D05 mov ecx, [eax+_KPRCB.KeSystemCalls] PAGE:004B5D0B xor ecx, [eax+_KPRCB.InterruptTime] PAGE:004B5D11 xor ecx, [ebp+CurrentTime.HighPart] PAGE:004B5D14 xor ecx, [ebp+CurrentTime.LowPart] PAGE:004B5D17 xor eax, eax PAGE:004B5D19 lock cmpxchg [edi], ecx PAGE:004B5D1D push 4 PAGE:004B5D1F pop edx PAGE:004B5D20 jmp get_dw И дубль 2 =) Пробуем снова получить дворд… Смотрим описание функции KeQuerySystemTime Теперь мы знаем откуда берется это значение и можно написать драйвер, который по id процесса будет возвращать уникальный дворд. Использовать NtQueryInformationProcess мы не можем напрямую, поэтому просто осуществим аналогичные действия (начиная с метки get_timе я опустила, ибо лень, могу сказать, что все корректно определяется). И соответственно программа, которая этот драйвер использует. В самом драйвере пишем Code: ULONG ProcessDwordByProcessId(ULONG piD) { ULONG dwDbg; PEPROCESS cproc; if(NT_SUCCESS(PsLookupProcessByProcessId(piD,&cproc))) { _asm{ mov edi,cproc add edi,0x258 mov edi,dword ptr[edi] mov dwDbg,edi } return dwDbg; } return 0; } В вызывающей программе Code: DWORD GetPrDword(DWORD pID){ //Аргумент - id процесса DWORD mag=0,BytesReturned=0; if( !DeviceIoControl(hHandle,IOCTL_GET_PROCESS_DWORD,&pID, 4,&mag,4,&BytesReturned, NULL )) { printf("Error in DeviceIoControl\n"); return 0; } // возвращаемое значение - process dword return mag; } Скрин http://img56.imageshack.us/my.php?image=23297865ee9.jpg Program http://rapidshare.com/files/165383629/tst.rar.html