"UndocuMented Windows 2000 SECRETS" translation - Chapter 5 (2)

xiaoxiao2021-03-06  36

Chapter 5 Monitoring Native API Call

Translation: kendiv (fcczj@263.net)

Update:

Thursday, February 24, 2005

Disclaimer: Please indicate the source and guarantee the integrity of the article, and all rights to the translation.

Assembly language rescue action

The main barriers to general solutions are the typical parameter transfer mechanism for the C language. As you know, c is usually passed to the CPU stack before the entry point of the function is called. According to the number of parameters required by the function, the size of the parameter stack will have a big difference. The 248 Native API functions required by Windows 2000 is located in 0 to 68 bytes. This makes it very difficult to write a unique HOOK function. Microsoft's Visual C / C provides a complete assembly (ASM) compiler that handles complexity code. Ironically, the advantages of assembly language used in my solution are typically considered to be their maximum disadvantage: assembly language does not provide a strict type inspection mechanism. As long as the number of bytes is correct, you can store almost all things in any registers, and you can call any address without what is the content of the current stack. Although this is a very dangerous feature in application development, this is really easier to get: In assembly language, it is easy to call the same ordinary entry point with different parameter stacks, and will introduce the API Hook. Dispatcher will adopt this feature.

The Microsoft Visual C / C embedded assembler can be called by placing assembly code in a slightly blocking block with a keyword__asm ​​tag. Embedded assembly lacks macro definitions and Microsoft's Big Macro Assembler (MASM) evaluation capabilities, but these do not have serious limitations. The best feature of embedded assembly is: it can access all C variables and type definitions, so it is easy to mix C and ASM code. However, when there is an ASM code in the C function, it is necessary to obey certain important basic agreements of the C compiler to avoid conflicts between C code:

The L c function caller assumes that the CPU register EBP, EBX, ESI and EDI have been saved.

l If in a single function, mix the ASM code and C code together, you need to be careful to save the C code may be saved in the intermediate value in the register. Always save and restore all registers used in the __ASM statement.

L 8 bits of function result (char, byte, etc.) is returned by the register AL.

l 16 bits of function result (short, word, etc.) is returned by register AX.

l 32 bits of function results (int, long, dword, etc.) are returned by register EAX.

l 64 bits of function results (__int64, longlong, dwordlong, etc.) are returned by the registers pair EDX: EAX. Register EAX contains 0 to 31 bits, and EDX saves 32 to 63 bits.

l There is a function of determining the parameters typically perform the passage of parameters in the __stdcall agreement. From the caller's perspective, this means that the parameter must be pressed into the stack in the reverse order before the function call, and the called function is responsible for removing them from the stack before returning. From the perspective of the called function, this means that the stack pointer ESP points to the returned address of the caller, which follows the last parameter (according to the original order). (Demolition: This means that the first time the stack is the return address of the function.) The original order of the parameter is retained, because the stack is downward, from the high linear address to the low linear address. Therefore, the caller is pressed into the last parameter of the stack (ie, parameter # 1) will be the first parameter in the array pointed to by the ESP. l Some API functions with certainty parameters, such as the famous C run time library function (exported by NTDLL.DLL and NTOSKRNL.EXE), usually use the __cdecl call convention, which uses the same parameter order as __stdcall, but forced The caller cleans the parameter stack.

l Declaration of __fastcall modified, you want the first two parameters to be in the CPU register ECX and EDX. If more parameters are needed, they will pass into the stack in the opposite order, and finally the stack is cleaned by the caller, which is the same as __stdcall.

This is the function's prologue

Push EBP; Save Current Value EBP

MOV EBP, ESP; Set Stack Frame Base Address

SUB ESP, SizeOflocalStorage; Create Local Storage Area

This is the function's epilogue

MOV ESP, EBP; Destroy Local Storage Area

POP EBP; Restore Value Of EBP

RET

Listing 5-2. Stack frame, preamble, and end

l Many C compilers will build a stack frame for the function parameters immediately after entering the function, which requires the use of the CPU's base address pointer register EBP. Listing 5-2 gives this code, which is often referred to as "preamble" and "end" of functions. Some compilers use a more concise i386 ENTER and Leave operators, after the preface is executed, the stack will be divided into two parts of the function's parameter stack as a split point as a split point: (1) Partial storage area, which contains all local variables (2) caller stacks defined within the function range, where EBP is stored and returned. Note that Microsoft's Visual C / C is stored in the latest version of the default Stack frame. Alternatively, the code accesses the value in the stack through the ESP register, but this requires the specified variable to be offset relative to the top of the current stack. This type of code is very difficult to read because each PUSH and POP instructions will affect The value of the ESP and the offset of all parameters. In this case, the EBP is no longer needed, which will be an additional universal register.

l You must be very careful when accessing C variables. The bug that frequently appears in embedded ASM is: load the address of a variable rather than its value to the register. There is a potential ampieracy using the PTR and OFFSET address operators. For example, instructions: MOV EAX, DWORD PTR SomeVariable will load the value of the SomeVariable variable of the DWORD type to the EAX register, but Mov Eax, Offset SomeVariable will load its linear address into EAX. Figure 5-3. Typical layout of the stack frame

Hook Dispatch (Hook Dispatcher)

This part of the code will be more difficult to understand. The writing of them spent a lot of time, and I also appreciate countless blue screens in this process. My initial method is to provide a module written in assembly language. However, this method has brought a lot of trouble in the link level, so I changed to use embedded compilation in the C module. In order to avoid creating drivers for another kernel mode, I decided to integrate the Hook code into the SPY device driver. Remember the IOCTL function listed in the bottom of Table 4-2? Now we will contact them to contact them. The latter code is from W2K_SPY.C and W2K_SPY.H, which can be found in the / src / w2k_spy of the book CD.

Listing 5-3 The core part of the Native API Hook mechanism is implemented. The list begins to be a pair of constants and structural definitions, and the aspyhooks behind them are required. Tight with this array is a macro. This macro is actually three-line embedded compilation statements. These three lines of assembled statements are very important. I will introduce them later. The last part of the list 5-3 is used to create a spyhookInitializeex () function. I saw it, the function of this function seems to be difficult to understand. This function combines two functions:

1. The surface portion of SpyHOKInitializeEx () includes a paragraph C code to set the AspyHooks [] array, which initializes the AspyHooks [] array with the HOOK function pointer of the SPY device and the string format protocol associated with it. SpyhookInitializeex () function can be split into two parts: the first part to the first __asm ​​statement JMP Spyhook9 instruction. The second part is obviously starting from the ASM tag ---- Spyhook9, which is at the end of the second __ASM statement block.

2. The inner part of SpyhookInitializeEx () includes all code between the two C code segments. This part uses a Spyhook macro at the beginning, followed by a large complicated assembly code. Maybe you have guessed, these assembly code is the general HOOK routine mentioned earlier.

#define spy_calls 0x00000100 // max API Call Nesting Level

#define SDT_SYMBOLS_NT4 0xD3

#define sdt_symbols_nt5 0xF8

#define SDT_SYMBOLS_MAX SDT_SYMBOLS_NT5

/ / -------------------------------------------------------------------------------------------- -----------------

Typedef struct _sspy_hook_entry

{

NTProc Handler;

PBYTE PBFORMAT;

}

SPY_HOOK_ENTRY, * pspy_hook_entry, ** ppspy_hook_ENTRY

#DEFINE SPY_HOK_ENTRY_SEOF (SPY_HOOK_ENTRY)

/ / -------------------------------------------------------------------------------------------- -----------------

Typedef struct _spy_call {

Bool Finuse; // set if used entry

Handle hthread; // id of calling thread

PSPY_HOOK_ENTRY PSHE; // Associated Hook Entry

Pvoid ​​Pcaller; // Caller's Return Address

DWORD DPARETERS; // Number of Parameters

DWord Adparameters [1 256]; // Result and Parameters

}

SPY_CALL, * pspy_call, ** ppspy_call;

#define spy_call_ sizeof (spy_call)

/ / -------------------------------------------------------------------------------------------- -----------------

SPY_HOOK_ENTRY AspyHooks [SDT_SYMBOLS_MAX];

/ / -------------------------------------------------------------------------------------------- -----------------

// the spyhook macro defines a hook entry point in inline assembly

// Language. The Common Entry Point Spyhook2 is entered by a call

// instruction, allowing the hook to be identified by its return

// Address on the stack. The call is executed through a register to

// Remove Any Degrees of FreeDom from the encoding of the call.

#define spyhook /

__asm ​​push eax /

__ASM MOV Eax, Offset Spyhook2 /

__ASM Call EAX

/ / -------------------------------------------------------------------------------------------- -----------------

// the spiokinitializeex () function initializes the asseryook []

// array with the hook entry point points and format strings. It also

// Hosts the hook entry points and the hook dispatcher.

/ / -------------------------------------------------------------------------------------------- -----------------

// the spiokinitializeex () function initializes the asseryook []

// array with the hook entry point points and format strings. It also

// Hosts the hook entry points and the hook dispatcher.

Void SpyHOKInitializeEx (PPByte PPBSymbols,

PPBYTE PPBFORMATS)

{

DWORD DHOOKS1, DHOOKS2, I, J, N; __ ASM

{

JMP Spyhook9

ALIGN 8

Spyhook1:; Start of hook entry point section

}

// the number of entry points defined in this section

// must be equal to sdt_symbols_max (i.e. 0xf8)

Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook SpyHOOK SPYHOOK / / 08

Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook SpyHOOK SPYHOOK / / 10

Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook SpyHOOK SPYHOOK / / 18

Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook SpyHOOK SPYHOOK / / 20

Spyhook Spyhook Spyhook Spyhook Spyhook SPYHOOK SPYHOOK / / 2

Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook // 30

Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook SpyHOOK SPYHOOK / / / 38

Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook SpyHOOK SPYHOOK / / 4

Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook // 48

Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook SpyHOOK SPYHOOK / / 50

Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook SpyHOOK SPYHOOK / / / 58

Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook SpyHOOK SPYHOOK / / / 60

Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook //68

Spyhook Spyhook Spyhook SpyHOOK SPYHOOK SPYHOOK SPYHOOK SPYHOOK / / / 70

Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook SpyHOOK SPYHOOK / / / / 78

Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook SpyHOOK SPYHOOK / / 80

Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook SpyHOOK SPYHOOK / / / 88

Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook SpyHOOK SPYHOOK / / / 90

Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook // 98

Spyhook Spyhook Spyhook SpyHOOK SPYHOOK SPYHOOK SPYHOOK SPYHOOK / / A0

Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook SpyHOOK SPYHOOK / / A8

SpYHOOK SPYHOOK SPYHOOK SPYHOOK SPYHOOK // B0SPYHOOK SPYHOOK SPYHOOK SPYHOOK SPYHOOK SPYHOOK SPYHOOK SPYHOOK SPYHOOK SPYHOOK SPYHOOK SPYHOOK SPYHOOK SPYHOOK SPYHOOK SPYHOOK SPYHOOK SPYHOOK SPYHOOK SPYHOOK SPYHOOK SPYHOOK SPYHOOK SPYHOOK SPYHOOK SPYHOOK SPYHOOK SPYHOOK SPYHOOK Spyhook // B

Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook SpyHOOK SPYHOOK / / C0

Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook SpyHOOK SPYHOOK / / / C8

Spyhook Spyhook Spyhook SpyHOOK SPYHOOK SPYHOOK SPYHOOK SPYHOOK / / D0

Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook // D8

Spyhook Spyhook Spyhook SpyHOOK SPYHOOK SPYHOOK SPYHOOK SPYHOOK / / E0

Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook SpyHOOK SPYHOOK / / E8

Spyhook Spyhook Spyhook SpyHOOK SPYHOOK SPYHOOK SPYHOOK SPYHOOK / / F0

Spyhook Spyhook Spyhook Spyhook Spyhook Spyhook SpyHOOK SPYHOOK / / F8

__ASM

{

Spyhook2:; End of hook entry point section

POP EAX; Get Stub Return Address

Pushfd

Push EBX

Push ECX

Push Edx

Push EBP

PUSH ESI

Push EDI

Sub Eax, Offset Spyhook1; Compute Entry Point Index

MOV ECX, SDT_SYMBOLS_MAX

Mul ECX

Mov ECX, Offset SPYHOK2

Sub ECX, Offset Spyhook1

Div ECX

Dec EAX

MOV ECX, GFSPYHOOKPAUSE; TEST PAUSE FLAG

Add ECX, -1

SBB ECX, ECX

NOT ECX

Lea Edx, [AspyHooks Eax * Size SPY_HOOK_ENTRY]

Test ECX, [edx.pbformat]; format string == NULL?

JZ Spyhook5

Push EAX

Push Edx

Call psgetcurrentthreadid; get thread ID

MOV EBX, EAX

POP EDX

POP EAX

CMP EBX, GHSPYHOOKTHREAD; IGNORE HOOK INSTALLER

JZ Spyhook5

MOV EDI, GPDEVICECONTEXT

Lea edi, [edi.spycalls]; Get Call Context Array

MOV ESI, SPY_CALLS; GET NUMBER OF ENTRIES

Spyhook3:

MOV ECX, 1; Set in-use flag

XCHG ECX, [EDI.FINUSE] JECXZ Spyhook4; Unused Entry Found

Add Edi, Size SPY_CALL; TRY NEXT Entry

Dec ESI

Jnz Spyhook3

MOV EDI, GPDEVICECONTEXT

INC [edi.dmisses]; Count Misses

JMP Spyhook5; Array Overflow

Spyhook4:

MOV ESI, GPDeviceContext

INC [ESI.DLEVEL]; SET NESTING LEVEL

MOV [edi.hthread], EBX; Save thread ID

Mov [edi.pshe], edx; save pspy_hook_entry

Mov ECX, Offset Spyhook6; SET New Return Address

XCHG ECX, [ESP 20H]

Mov [edi.pcaller], ECX; Save Old Return Address

MOV ECX, KeserviceDescriptable

MOV ECX, [ECX] .ntoskrnl.ArgumentTable

Movzx ECX, Byte PTR [ECX EAX]; Get Argument Stack Size

SHR ECX, 2

INC ECX; add 1 for result slot

Mov [edi.dparameters], ECX; Save Number of Parameters

Lea edi, [edi.adparameters]

Xor Eax, Eax; Initialize Result Slot

Stosd

Dec ECX

JZ Spyhook5; No Arguments

Lea ESI, [ESP 24h]; Save Argument Stack

REP MOVSD

Spyhook5:

Mov Eax, [edx.handler]; get Original Handler

POP EDI

POP ESI

POP EBP

POP EDX

POP ECX

POP EBX

POPFD

XCHG Eax, [ESP]; Restore Eax and ...

Ret; ... Jump to Handler

Spyhook6:

Push EAX

Pushfd

Push EBX

Push ECX

Push Edx

Push EBP

PUSH ESI

Push EDI

Push EAX

Call psgetcurrentthreadid; get thread ID

MOV EBX, EAX

POP EAX

MOV EDI, GPDEVICECONTEXT

Lea edi, [edi.spycalls]; Get Call Context Array

MOV ESI, SPY_CALLS; GET NUMBER OF ENTRIESSPYHOK7:

CMP EBX, [EDI.HTHREAD]; Find Matching Thread ID

JZ Spyhook8

Add Edi, Size SPY_CALL; TRY NEXT Entry

Dec ESI

JNZ Spyhook7

Push ebx; entry not found?!?

Call Kebugcheck

Spyhook8:

Push EDI; Save Spy_Call Pointer

Mov [edparameters], EAX; Store NTSTATUS

Push EDI

Call SpyhookProtocol

POP EDI; Restore Spy_Call Pointer

Mov eax, [edi.pcaller]

MOV [edi.hthread], 0; Clear Thread ID

MOV ESI, GPDeviceContext

Dec [esi.dlevel]; reset Nesting Level

Dec [edi.finuse]; Clear in-use flag

POP EDI

POP ESI

POP EBP

POP EDX

POP ECX

POP EBX

POPFD

XCHG Eax, [ESP]; Restore Eax and ...

Ret; ... return to caller

Spyhook9:

Mov dhooks1, offset spyhook1

Mov Dhook2, Offset Spyhook2

}

n = (DHOOKS2 - DHOOKS1) / SDT_SYMBOLS_MAX;

For (i = j = 0; i

{

IF (ppbsymbols! = null) && (ppbformats! = NULL) &&

(ppbsymbols [j]! = null))

{

Aspyhook [i] .handler = (ntproc) DHOOKS1;

askHOOKS [I] .pbformat =

SpysearchFormat (PPBSYMBOLS [J ], PPBFORMATS);

}

Else

{

Aspyhooks [i] .handler = NULL;

Aspyhook [i] .pbformat = null;

}

}

Return;

}

Listing 5-3. Hook Dispatcher implementation

What is the actual spyhook macro? In the spyhookInitializeex () function, this macro has been repeated 248 (0xF8) times, which is exactly the number of Windows 2000 Native API functions. At the top of the list 5-3, this number is defined as an SDT_SYMBOLS_MAX constant, which can make SDT_SYMBOLS_NT4 or SDT_SYMBOLS_NT5. Because I intend to support Windows NT 4.0. Go back to the Spyhook macro: the assembly statement of the macro call is given in Listing 5-4. Each spyhook produces the same three-line code: 1. First line, saving the contents of the current EAX register to the stack.

2. Second line, save the linear address of Spyhook2 to EAX.

3. Third line, call the address in EAX (ie: Call Eax).

You may be surprised: what happens when this call returns. Will the next group of Spyhook code will be called? No ---- this CALL does not support returning, because after reaching SpyHook2, the return address of this Call will be immediately removed from the stack, and the last POP EAX instruction can prove this. This kind of code that seems to be undoubted in ancient assembler design age has been widely discussed, just like today we discuss the object-oriented programming. When the ASM old master needs to build an array, each of the arrays has a similar entry point, but this skill is used when it is assigned to an independent function. Almost the same code for all entry points can ensure equal interval between them, so the client can easily calculate the index value in the array in the array through the return address of the CALL instruction, and the base address of the array. How many items and arrays

Spyhook1:

Push EAX

Mov Eax, Offset SPYHOK2

Call EAX

Push EAX

Mov Eax, Offset SPYHOK2

Call EAX

; 244 Boring Repetitions Cimitted

Push EAX

Mov Eax, Offset SPYHOK2

Call EAX

Push EAX

Mov Eax, Offset SPYHOK2

Call EAX

Spyhook2:

POP EAX

Listing 5-4. Extension Spyhook macro

For example, the return address of the first CALL EAX instruction in the list 5-4 is the address of its next statement. Typically, the return address of the Nth Call EAX instruction is the address of the Nth 1 statement, but the last one except, the last one will return Spyhook2. Therefore, the index of all the entry points starting from 0 can be calculated from the general formula in Figures 5-4. The potential rules in these three rules are: SDT_SYMBOLS_MAX enters the point in line with memory block Spyhook2 --- Spyhook1. So how many of the enterments meet RETURNADDRESS --- Spyhook1? Because the calculation result is a value located in 0 to SDT_SYMBOLS_MAX, it is sure to use this value to get an index starting from 0.

Figure 5-4. Return address of the entry point through the hook Determine a hook entry point

The implementation of the formula shown in Figure 5-4 can be found in the list 5-3, on the right side of the assembly tag spYHOOK2. The implementation code of the formula is also given in the lower left corner of Figures 5-5, which shows the basic principles of the Hook Dispatcher mechanism. Note that the MUL instruction of the I386 generates a 64-bit result value in the EDX: EAX register, which is desirable for the subsequent DIV instructions, so there is no danger of integer overflow here. In the upper left corner of Figures 5-5, it is a description of KiserventAlle that will be modified by the entry point address generated by the Spyhook Macro. The middle part of the figure shows the expanded macro code (from the list 5-4). The linear address of the entry point is located on the right hand side of the figure. To be exactly the same, each of the entry points is 8 bytes, so by multiplying the index value of each function in the kiServentetable by 8, then add the product plus the address of Spyhook1, the address of the entry point can be obtained. In fact, each entry point is not all pure 8-bytes long. I spend a lot of time to find the best way to achieve the best HOOK function. Despite the 32-bit boundary to the code, it is not necessary, but this is never bad idea because this will improve performance. Of course, it is very limited in performance. You may be strange: Why do I have to call Spyhook2 through the EAX register, not directly using the Call Spyhook2 instruction, is this not more efficient? Yes it is! However, the problem is that I386's Call (also JMP) instructions can have a variety of implementations, and they have the same effect, but the resulting instruction size is different. Please refer to: Intel's Instruction Set Reference of The Pentium CPU Family (Intel 199C). Because the final implementation is to be determined by the compiler / assembler, this cannot guarantee that all the entry points will have the same encoding. In other words, MOV EAX and a 32-bit constant operand always encode the same way, the same, which also applies to Call EAX instructions.

Figure 5-5. Hook Dispatcher's functional principle

There is still a point in the list 5-3 to clarify. Let us start from the last fast C code segment after the Spyhook9 tag. The assembly code following SPYHOK9 saves the linear address of Spyhook1 and SpyHook2 in DHOOK1 and DHOK2 variables. Next, the variable N is set to the size of each entry point (divided by the size of the entry point array). Of course, this value will be 8. The remainder of the list 5-3 is a loop statement to initialize all items in the global array aspyhooks []. The SPY_HOK_ENTRY structure included in this array is defined at the top of the list 5-3, each of which corresponds to a Native API function. To understand how the Handler and PBFormat members in this structure are set, it is necessary to further understand the ppbsymbols and ppbformats parameters delivered to SpyHOKInitializeex (), and the list 5-5 gives an outsourcing function spyhookInitialize (), which selects the appropriate current The parameter of the OS version calls SpyHOKInitializeEx (). As mentioned earlier, the code I use does not directly test the OS version or build number, but compares the value of the ServiceLiMit member associated with Ntoskrnl.exe with the constant spy_symbols_nt4, spy_symbols_nt5, and SDT. If there is no match, the SPY device will initialize the AspyHooks [] array content to NULL, thereby valid for the Native API Hook mechanism.

Bool SpyhookInitialize (Void)

{

BOOL fok = true;

Switch (keserviceDescriptable-> ntoskrnl.serviceLimit)

{

Case SDT_SYMBOLS_NT4:

{

SpyhookInitializeEx (APBSDTSYMBOLSNT4, APBSDTFORMATS);

Break;

}

Case SDT_SYMBOLS_NT5:

{

SpyhookInitializeEx (APBSDTSYMBOLSNT5, APBSDTFORMATS);

Break;

}

DEFAULT:

{

SpyhookInitializeEx (NULL, NULL);

Fok = false;

Break;

}

}

Return fok;

}

Listing 5-5. SpyHOKInitialize () Select the symbol table that matches the current OS version

Pass the global array: APBSDTSYMBOLSNT4 [] and APBSDTSYMBOLSNT5 [] to the spyhookInitializeex () function as its first parameter PPBSymbols, which is just a simple string array, including the name of all Native API functions of Windows NT 4.0 and Windows 2000. In order to store in the index order in Kiserventetable, finally end with NULL. Listing 5-6 gives an APBSTDFORMATS [] string array. This format string list is also a very important part of the Hook mechanism because it determines the format of the Native API call, and each record. Obviously, the structure of these strings draws on the PRINTF () function in the C running library, but modifications for the data types that are often used in Native APIs. Table 5-2 lists all formatting IDs that can be identified by the API Logger.

PBYTE APBSDTFORMATS [] =

{

"% s = ntcanceliofile (%!,% i)",

"% s = NTCLOSE (% -)",

"% s = ntcreatefile (% ,% N,% o,% i,% L,% N,% N,% N,% N,% p,% n),

"% s = NTCREATEKEY (% ,% n,% o,% N,% u,% n,% d)",

"% s = ntdeletefile (% o)",

"% s = ntdeletekey (% -)",

"% s = ntdeletevaluekey (%!,% u)",

"% s = NTDEVICEIOCONTROLFILE (%!,% p,% p,% p,% i,% n,% p,% n,% p,% n)",

"% s = nTenumerateKey (%!,% n,% n,% p,% n,% d)",

"% s = nTenumeratevalueKey (%!,% n,% n,% p,% n,% d)",

"% s = NTFLUSHBUFFERSFILE (%!,% i)",

"% s = NTFLUSHKEY (%!)",

"% s = ntfscontrolfile (%!,% p,% p,% p,% i,% n,% p,% n,% p,% n),

"% s = ntloadKey (% o,% o)",

"% s = ntloadKey2 (% O,% O,% N)",

"% s = ntNotifyChangeKey (%!,% p,% p,% p,% i,% n,% b,% p,% n,% b)",

"% s = ntnotifychangemultipleKeys (%!,% n,% o,% p,% p,% p,% i,% n,% B,% p,% n,% b),

"% s = ntopenfile (% ,% n,% o,% i,% n),"% s = NTOPENKEY (% ,% N,% o) ",

"% s = NTOPENPROCESS (% ,% n,% o,% c)",

"% s = NTOPENTHREAD (% ,% N,% o,% c)",

"% s = ntquerydirectoryfile (%!,% p,% p,% p,% i,% p,% n,% n,% b,% u,% b),

"% s = ntqueryinformationfile (%!,% i,% p,% n,% n),

"% s = ntqueryinformation process (%!,% n,% p,% n,% d)",

"% s = ntqueryinformationthread (%!,% n,% p,% n,% d)",

"% s = ntQueryKey (%!,% n,% p,% n,% d)",

"% s = ntquerymultiplevaluekey (%!,% p,% n,% p,% d,% d)",

"% s = ntQueryOpenSubkeys (% o,% d)",

"% s = ntquerysysteminformation (% n,% p,% n,% d)",

"% s = ntQuerySystemTime (% L)",

"% s = ntqueryvaluekey",%!,% u,% n,% p,% n,% d) ",

"% s = ntqueryvolumeinformationfile (%!,% i,% p,% n,% n)",

"% s = ntreadfile (%!,% p,% p,% p,% i,% p,% n,% l,% d),

"% s = ntreplacekey", "

"% s = ntsetinformationKey (%!,% n,% p,% n)",

"% s = ntsetinformationfile (%!,% i,% p,% n,% n)",

"% s = ntsetinformation process (%!,% n,% p,% n)",

"% s = ntsetinformationthread (%!,% n,% p,% n)",

"% s = ntsetsysteminformation (% n,% p,% n)",

"% s = ntsetsystemTime (% L,% L)",

"% s = ntsetValueKey (%!,% u,% n,% n,% p,% n)",

"% s = ntsetvolumeinformationfile (%!,% i,% p,% n,% n)",

"% s = ntunloadKey (% o)",

"% s = ntwritefile (%!,% p,% p,% p,% i,% p,% n,% l,% d),

NULL

}

Listing 5-6. Native API logger used formatted string

It is particularly proposed here that each format string requires the correct spelling of the function name. SpyhookInitializeEx () traverses it accepts the Native API symbol list (via ppbsymbols parameters) and try to find a format string that matches the function name from the PPBFormats list. This function is called by the Help Function SpySearchFormat () to make a comparison work, and the function is called in the IF statement at the bottom of the list 5-3. Because you want to perform a lot of string lookup operations, I use a highly optimized lookup engine that is based on the "Shift / And" search algorithm. If you want more to learn its implementation, please look at the spysearch * () function in the SRC/W2K_SPY/W2K_SPY.C source file with the book CD. When SpyHOKInitializeEx () launches a loop, all Handler members in AspyHooks [] will point to the appropriate Hook entry point, and the PBFormat member provides the format string with it. For Windows NT 4.0, all index values ​​are set to NULL in 0xD3 - 0xF8, because they are not defined in NT4. Table 5-2. Recognitive Format Control ID

Id

Name

Describe

% Handle (registration) writes the handle and the object name into the log and add it to the handle. %! Handle (retrieve) writes the handle to the log and retrieves its corresponding object name from the handle table. % - handle (revocation registration) writes the handle and the object name into the log, and removes the% a ANSI string from the handle table to write a string of the string of 8 ANSI characters to enters the log% B boolean will be 8 bits. Log% C Client_ID * Write a member of the client_ID structure to log% D DWORD * Write the value of the variable of the DWORD to the log% i io_status_block * Write the member of the IO_STATUS_BLOCK structure to log% l la L marge_integer * A LARGE_INTEGER's value write log% N value (DWORD) Write a 32-bit unsigned number to log% o Object_attributes * Write the object's objectName to write the log% S state (NTSTATUS) ) Write NT status code to log% u unicode_string * Write the buffer member of the Unicod_String structure to the log% w width string to write a string of strings consisting of 16-bit characters to write a log %% percent symbol will be one " % "Write to the log

……………..to be continued…………….

转载请注明原文地址:https://www.9cbs.com/read-54472.html

New Post(0)