Форум АНТИЧАТ

Форум АНТИЧАТ (https://forum.antichat.xyz/index.php)
-   Реверсинг (https://forum.antichat.xyz/forumdisplay.php?f=94)
-   -   EncodePointer (https://forum.antichat.xyz/showthread.php?t=92589)

0x0c0de 19.11.2008 21:39

EncodePointer
 
[EncodePointer].

*my system: Windows XP SP3 [тестила и на win xp2 то же]

Пишу сию небольшую заметочку про EncodePointer. Статьей это => не является.

Некогда довелось мне заниматься VEH и писать плаг под Olly, перебирающий все обработчики в дебажимом процессе. И функция EncodePointer создала мне на системах с SP (в виндах без СП, как выяснилось этой функции нет вовсе) некоторые проблемы и при получении адреса вех-обработчика я извращалась с трейсом.
Как вы можете прочесть в msdn

Цитата:

The EncodePointer function encodes the specified pointer. Encoded pointers can be used to provide another layer of protection for pointer values.
PVOID EncodePointer(
PVOID Ptr
);
Здесь все предельно понятно. И вех-обработчики в системах с SP как раз-таки подвергаются такой обработке.
Функция шифрует адрес Ptr неким значением, уникальным для каждого процесса. Теперь попробуем разобраться в общих чертах как оно работает и откуда это значение берется.

Код функции RtlEncodePointer

Код:


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


Код:

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.

Код:

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)

Код:

PAGE:004A0E8B                jmp    ds:off_4A18CA[eax*4]
Попадаем сюда

Код:

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


Обратите внимание на сделанное мной обозначение. То есть, если передан хендл не текущего процесса, то

Код:

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

Ну оно и верно. Если бы этот дворд можно было получить из другого процесса, было бы странно. Теперь продолжим. Если мы интересуемся своим процессом

Код:

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.

Если значение нулевое, то

Код:

PAGE:004A0EBB                test    eax, eax
PAGE:004A0EBD                jz      get_time

Получаем системное время

Код:

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

Цитата:

The KeQuerySystemTime routine obtains the current system time.
VOID
KeQuerySystemTime(
OUT PLARGE_INTEGER CurrentTime
);


Теперь мы знаем откуда берется это значение и можно написать драйвер, который по id процесса будет возвращать уникальный дворд. Использовать NtQueryInformationProcess мы не можем напрямую, поэтому просто осуществим аналогичные действия (начиная с метки get_timе я опустила, ибо лень, могу сказать, что все корректно определяется). И соответственно программа, которая этот драйвер использует. В самом драйвере пишем

Код:

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;

}

В вызывающей программе

Код:

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


Время: 10:11