throbber
CSCO-1041
`Cisco v. SSL, |PR2015-01754
`Page 1 of 72
`
`CSCO-1041
`Cisco v. SSL, IPR2015-01754
`Page 1 of 72
`
`

`
`CSCO-1041
`Cisco v. SSL, IPR2015-01754
`Page 2 of 72
`
`

`
`Windows 95 System Programming SECRETS
`Published by
`IDG Books Worldwide, Inc.
`An International Data Group Company
`919 East Hillsdale Boulevard, Suite 400
`Foster City, CA 94404
`
`‘-
`Copyright
`Copyright © 1995 by IDG Books Worldwide. All rights reserved. No part of this book (including
`interior design, cover design, and illustrations) may be reproduced or transmitted in any form, by
`any means (electronic, photocopying, recording, or otherwise), without the prior written
`permission of the publisher.
`
`Library of Congress Catalog Card No.: 95-75057
`
`ISBN 1-56884-318-6
`
`Printed in the United States of America
`
`First Printing, November, 1995
`
`10 9 8 7 6 5 4 3 2 1
`
`Distributed in the United States by IDG Books Worldwide, Inc.
`
`Limit of Liability/Disclaimer of Warranty
`The author and publisher of this book have used their best efforts in preparing this book. IDG
`Books Worldwide, Inc., International Data Group, Inc., and the author make no representation
`or warranties with respect to the accuracy or completeness of the contents of this book or the
`material on this disk included with this book, and specifically disclaim any implied warranties
`of merchantability or fitness for any particular purpose, and shall in no event be liable for any
`loss of profit or any other commercial damage, including but not limited to special, incidental,
`consequential or other damages.
`
`Trademarks
`
`All brand names and product names used in this book are trademarks, registered trademarks,
`or trade names of their respective holders. IDG Books Worldwide, Inc., is 11ot associated with
`any product or vendor mentioned in this book.
`
`‘PROGIUIMHIERS
`
`]
`
`Published in the United States
`
`WORLDWIDE
`
`P
`
`R
`
`E » S V;
`
`CSCO-1041
`Cisco v. SSL, IPR2015-01754
`Page 3 of 72
`
`

`
`CSCO-1041
`Cisco v. SSL, |PR2015-01754
`Page 4 of 72
`
`CSCO-1041
`Cisco v. SSL, IPR2015-01754
`Page 4 of 72
`
`

`
`686
`
`Windows 95
`
`Doing this is only a function call away with the code I’ll be presenting. If
`you’re just interested in getting the code to intercept API function calls, skip
`ahead to the last section in this chapter (“Intercepting Functions in Your
`Own Programs”). However, if you’re interested in Win32 system—level
`programming and learning how this technique works, ‘read on.
`Why bother writing a simple API spy program when more powerful ones,
`such as BoundsChecker32, are available commercially? By writing you own
`API spy for Win32 programs, you can gain a thorough understanding of the
`Win32 operating system philosophy, and develop an in-depth knowledge
`about the important differences between the three Win32 implementations
`(Windows NT, Windows 95, and Win32s).
`On the surface, the subject of this chapter appears to be “How to build an
`API spy program.” However, my real goal is to present a set of real—world
`Win32 programming problems, and show how they can be solved. In the
`process, you should see many facets of the Win32 architecture. As you’ll
`soon realize, writing an API spy for Win32 programs forces you to come into
`Contact with such issues as address spaces, rnultithreading, dynamic linking,
`debugging mechanisms, process management, and thread control. In short,
`the program I’ll be building will give you a good tour of many core Wi1132
`concepts.
`Before jumping into details about the program, I need to list the API spy
`program specifications:
`
`1. For a given Win32 process, the program should log the function calls it
`makes to a given list of DLLs.
`2. The set of DLLS to be monitored should be extendible by the user via a
`configuration file.
`
`. If the parameters to a function are known, they can be specified in the
`configuration file, and their values will be logged along with the
`function name.
`
`4. The spy program must log the return Values of functions.
`. The spy program should be able to run on Windows NT, Windows 95,
`and Win32s.
`W
`
`. No modification to the program’s source code or executable file should
`be required.
`
`. Log output should go to a disk file, rather than being shown live.
`
`CSCO-1041
`Cisco v. SSL, IPR2015-01754
`Page 5 of 72
`
`

`
`7" w;:;:;;.sw;.a2 Am Spy
`
`537
`
`When this program is completed (at the end of the chapter), it will be
`able to do several things: it will let you pick another program to spy on, it
`will run that program, and it will produce an ASCII text file with the logged
`information. After the chosen program terminates, you can View the text file
`with an editor or viewer of your choice.
`An important limitation of this spy program —- and one that needs to be
`pointed out very clearly — is that this program is a per-process API spy.
`Unlike programs such as the Win16 WinScopc spy program, my Win32 API
`spy doesn’t watch calls made by all processes iii the system. Rather, it
`watches only the calls made by a single process. In a system with separate
`address space for each process, writing a global API spy is a significant
`undertaking and beyond the scope of this chapter. (How’s that for truth in
`advertising?)
`
`INTERCEPTING THE FUNCTIONS
`
`The basic idea behind any sort of spy program is that the spy program
`inserts itself into the flow of control of the program being spied on. The spy
`program gets control before the intended target of the call is reached, and
`does whatever logging it needs to before transferring control to the original
`intended target of the call. The first problem we’re faced with is how to let
`our spy program gain control somewhere between the “spyee’s” call to a
`DLL function, and the execution of the function in the DLL.
`One approach to this problem that’s been used in the past is to make
`your own DLL that exports functions with the same names as the functions
`you want to intercept. For example, if you wanted to intercept calls to the
`GetProcAddress function in KERNEL32.DLL, you’d make your own DLL
`with an exported GetProcAddress function. By putting this DLL’s import
`library first in the list of import libraries, the linker will fix up calls to
`GetProcAddress to point to your interception DLL, rather than to
`KERNEL32.DLL. The interception DLL logs the information about the call
`before jumping to the real function (for example, GetProcAddress in
`KERNEL32.DLL). As an alternative to creating an import library, you
`could just alias the imported functions in your DEF file. However, both of
`these approaches share the common characteristic of requiring the linker to
`set up the API interception at link time — something that’s not an option if
`the program you’re spying on isn’t one you wrote.
`
`CSCO-1041
`Cisco v. SSL, IPR2015-01754
`Page 6 of 72
`
`

`
`Windows 95 Systéniifl’riogi.rieiiIinjfi
`
`This method of intercepting calls to API functions is exactly what the
`Microsoft API parameter profiler in the Win32 SDK does. Included with
`this profiler are five DLLS: ZDI32.DLL, ZDVAPI32.DLL, ZERNEL32.DLL,
`ZRTDLLDLL, and ZSER32.DLL; these DLLS intercept calls to GDI32.DLL,
`ADVAPI32.DLL, KERNEL32.DLL, CRTDLLDLL, and USER32.DLL,
`respectively. Instead of linking with these DLLs, you run a program
`(APF32CVT) that modifies the EXE you want to spy on. The net effect is
`the same as if you had linked with the import libraries. At least no source
`code is required to use APF32CVT.
`For our purposes, there are two problems with this dummy DLL
`approach. First, it’s not easy to extend it to accommodate new DLLs. For
`each new API function you want to intercept, you need to modify the inter-
`ception DLL and rebuild it. You also have to relink or modify the EXE to
`be spied on. The second, and bigger, problem is that this approach requires
`changing the program to be spied on, which is a direct violation of one of
`our design specifications.
`Another approach to intercepting calls to API functions is to somehow
`modify the target of the call. By changing the initial portion of the function
`being called, a program can enable itself to get control before the body of
`the function is executed. There are two methods of modifying a function’s
`prologue code to transfer control elsewhere. The first and most obvious
`method is to place a breakpoint instruction (opcode OXCC) at the first byte
`in the function’s code. When the function is called, an interrupt handler
`installed by the spy program gets control and does its logging. The spy pro-
`gram then restores the original byte of. the function before making the CPU
`execute exactly one instruction (via the trap flag single—step mechanism). In
`its single—step exception handler, the API spy program then reinserts the
`breakpoint opcode so that subsequent calls to the function will be caught.
`Although some Win16 spy programs use breakpoints to intercept calls
`to DLL functions, trying to do something similar under Win32 would be
`more difficult. For starters, under Wi1132, one process can’t see another
`process’s exceptions unless it’s acting as a debugger to that process. Next,
`forcing every call to an API function to go through the Win32 structured
`exception—handling code could seriously impair performance. Also, the
`separate address spaces of processes under Win32 would force the spy
`program to use ReadProcessMemory to see the target applications’s function
`parameters. This is far clunkier than being able to read the memory directly.
`The second method of modifying a function’s prologue code to transfer
`control to the spying code is to insert 21 ]MP or CALL instruction at the
`start of the function. One problem with this approach is that in 32-bit code,
`
`CSCO-1041
`Cisco v. SSL, IPR2015-01754
`Page 7 of 72
`
`

`
`genomes; in Spy
`
`539
`
`a JMP or a CALL instruction will take at least 5 bytes. If the DLL has func-
`tions less than 5 bytes apart (yes, this has happened!), patching in a JMP or
`CALL becomes impractical because the function that comes later in the
`code will start in the middle of a JMP or CALL instruction. Unlike break-
`points that can be handled by another process, patching in ]MPs and
`CALLs,requires your code to be running in the process context of the program
`being spied on. To run in any arbitrary process requires that your code be in
`a DLL. However, as you’ll see later, running your spy code in the context of
`the process being spied on isn’t such a bad idea. Still, patching ]MPs or
`CAHsmmflmpmmmmmgwmdmmamflnmmmgwmdwywmnm
`need to constantly switch between the original code and your JMP/CALL
`instructions.
`
`Having looked at and discarded two obvious approaches to interception
`(linking to a custom DLL and patching the API function’s code), let’s look
`at a third approach that’s not so obvious. Nothing in the rule book says that
`the target code in the API function has to be patched. It’s equally valid to
`modify the call to the API function. If the spy program can somehow find
`the CALLS to the API functions, it can modify the CALL to point to the spy
`program’s logging code. As in a previously discussed method, the spy pro-
`gram’s logging code will need to execute in the process context of the program
`being spied on. The “Injecting a DLL into Another Process” section will
`show how it’s possible to “inject” a DLL into the address space of a
`process. Here, we’re concentrating on the interception part of the problem.
`You might be thinking to yourself, “A program might have hundreds or
`even thousands of calls to API functions in just the system DLLS alone.
`How on earth can I hope to find all those CALL instructions?” Never fear,
`the manner in which Win32 EXES and DLLS dynamically link to each other
`makes this almost incredibly easy: All calls to a given API function end up
`traveling through the same spot in the executable file. By patching that one
`location to point at the spy’s logging code, you intercept all calls made by
`theED(Etothatfuncfion.
`To see how this works, let’s look at the actual code generated for three
`separate calls to the GetVersion() API function in KERNEL32.DLL. Let’s
`start with the following small C program:
`
`int ma1'n()
`I
`
`GetVers1'on( );
`GetVersion( ):
`GetVersion( );
`
`CSCO-1041
`Cisco v. SSL, IPR2015-01754
`Page 8 of 72
`
`

`
`69O
`
`Windows
`
`From this program, the compiler generates the following assembler code:
`
`410052: CALL
`
`@@4Z@03C
`
`410057: CALL
`410050: CALL
`
`0@420@3C
`@@4Z0fl3C
`
`4Z@03C:
`
`JMP
`
`DWORD PTR [@@44@064]
`
`The important thing to notice here is that CALL instructions don’t call
`directly to the GetVersion() code in KERNEL32.DLL. Instead, each call
`transfers control to 21 ]MP statement elsewhere in the EXE’s code. That JMP
`instruction dereferences a DWORD in memory a11d jumps to that location.
`In the above example, the DWORD is at address 00440064. What’s the
`address stored in this DWORD? As you might suspect, it’s the address of
`GetVersion() in KERNEL32.DLL. All calls to API functions end up going
`through a JMP DWORD PTR [XXXXXXXX] thunk. For each function
`that an executable imports, there’s a c0rrespor1ding]MP DWORD PTR
`[XXXXXXXX]. Who generates these JMP thunks? In Microsoft compilers,
`the JMP thunks are code in the import libraries for the DLLs being linked
`to. In Borland C++, the linker (TLINK) generates the JMP thunks.
`The questions that naturally arise from this JMP thu11k mechanism are
`“Where is the DWORD with the function’s address found?” and “Who’s
`responsible for initializing it?” The DWORD containing the imported function’s
`address is found in what is known as the import address table (or IAT, for
`short). The IAT typically resides in the .idata (import data) section of each
`executable. For each DLL that an executable links to, there’s an associated
`array of DWORDS containing addresses of functions in the imported DLL.
`When the Win32 loader brings an executable into memory, it fills in the
`array of DWORD with the proper addresses, as shown in Figure 10-1. In
`the executable file prior to loading, each DWORD contains an offset to an
`ASCHZ string that names the desired function (for example Get‘/ersion).
`When the loader brings the executable into memory, it overwrites the array
`of names offsets with the actual addresses of the functions.
`Having seen how an executable imports functions from other DLLs, it’s
`easy to understand how a spy program can intercept and log those functions
`with a minimum of fuss and overhead. The spy program merely needs to
`find the array of function addresses in the executable’s imports section and
`overwrite those addresses with the addresses of its own logging routines. No
`actual code patching is required, so there’s no need to constantly switch
`between the original code and the code as modified by the spy program.
`The executable ends up calling the API spy’s code directly, so the only over-
`
`CSCO-1041
`Cisco v. SSL, IPR2015-01754
`Page 9 of 72
`
`

`
`_¢5;i.i-47‘, uiéiiiiiiig uiwiinaz API Spy
`
`591
`
`head is that of the logging functions. After the spy code has logged the
`function’s data, it ]MPs to the original intended target of the JMP DWORD
`PTR [XXXXXXXX] thunk. Simple, no?
`
`Array of
`|MAGE_lMPOFlT_DESCHlPTOR
`structures
`
`MYEXE.EXE
`Other
`
`import Address Table
`(function pointers)
`{>
`
`USER32.DLL
`
`sections
`.re|oc
`
`Section
`
`.idata
`
`section
`Data
`section
`
`Code
`
`PE
`
`MZ
`header
`
`“USER32.DLL"
`
`"KEFiNEL32.DLL”
`
`GetMessage
`code
`
`-
`
`MessageBox
`code
`
`KERNEL32.DLL
`
`HeapAlloc
`
`code
`
`CreateProcess
`code
`
`Figure 10-!
`The jdoto section of the executable usually holds the DWORD containing the imported
`function's address, although the imports table can be located elsewhere.
`
`'"
`
`Even if spying isn’t your goal, you can use this trick of modifying the
`addresses in the imports section to selectively intercept APIs. For example,
`you might want to replace a function in a DLL with your own custom-written
`code. It’s easy to implement a function that takes a DLL name and function
`name and returns a pointer to the D\X/ORD in the imported data section that
`holds the functions’s address. Your code would then overwrite the DWORD
`with the address of your own custom function. If you want to chain on to
`the original address, simply save off the original DWORD value before
`overwriting it.
`
`CSCO-1041
`Cisco v. SSL, IPR2015-01754
`Page 10 of 72
`
`

`
`Windows 95‘ ;c;,o...osscisaj.,j
`
`In the spy program I’ll be building in this chapter, I’ve chosen to inter-
`cept calls to API functions in the manner just described. In making this deci-
`sion, I’ve committed myself to running the spy’s logging code in the process
`context of the application being spied on. Since the design goals for the API
`spy program don’t allow relinking or modification of the target application,
`I need to somehow force the logging code into the target program’s address
`space. It also means that the majority of the API spy program’s code must
`reside in a DLL.
`
`INJECTING A DLL INTO ANOTHER PROCESS
`
`Now that we know how we’ll intercept calls to API functions, the next hurdle
`is to force the spying code into the target application’s address space. In 16-bit
`Windows, this wouldn’t be an issue since all programs share a common
`address space. In Win32, however, each process has its own address space, and
`its own set of loaded DLLs. Just because one process is using a DLL doesn’t
`mean that another process can use it. Each process that wants to use a DLL
`needs to load the DLL for its own use, either by implicitly linking to it, or by
`calling LoadLibrary(). Since the programs we’ll Want to spy on have no knowl-
`edge of our API spy DLL, we’ll need to resort to dirty tricks to force the DLL
`into their address space.
`There are at least three ways to inject a DLL into the context of an
`arbitrary process. Jeffrey Richter’s May 1994 Microsoft Systems journal
`article describes each approach in quite a bit of detail. Here, I’ll give a brief
`overview of the two methods that we won’t take advantage of, and then
`spend more time on the DLL injection method that the API spy program
`will actually use. The final method that Richter chooses for a general-purpose
`implementation is similar (but not identical) to the method I’ll use for
`our spy program. The key difference is that Richter’s method uses the
`CreateRemoteThread function, which isn’t available in Win32s or Windows
`95. My version of injecting the DLL is portable to all three platforms.
`The first and best known way to force a DLL into another pr0cess’s
`address space is to install a windows hook using SetWindowsHookEx(). If
`you specify an hThread for a different process, or if you request a systemwide
`hook, the operating system automatically loads the DLL containing the hook
`procedure into the address spaces of all processes affected by the hook.
`Installing a windows hook to force our API spy DLL to load is ineffective
`for two reasons. The first reason is that you have to have an existing
`
`CSCO-1041
`Cisco v. SSL, IPR2015-01754
`Page 11 of 72
`
`

`
`ad Win32 API Spy
`
`693
`
`process to install the hook for. By the time this occurs, the target process has
`undoubtedly called API functions. The spy program would miss all the API
`function calls made by the target process up to that point. The second reason
`is that the hook DLL won’t actually be loaded in the target process until
`that process takes some action that causes the hoolccallback to be invoked.
`Trying to use hooks to force a DLL to load in another process context just
`doesn’t offer enough precision with regard to when the DLL loads.
`A second way to force a DLL into the address space of a process falls
`into the barely documented category. It seems there’s an obscure registry key
`value buried deep down in the registry hierarchy:
`
`HKEY_LOCAL_MACHINE\Softwa re\M1' crosoft\w1'ndows NT\CurrentVers1' 0n\H1 ndows\APP1N1T_DLLS
`
`By adding your DLL’s name to this key, the operating system automatically
`loads the DLL i11to the address space of each process as the process starts up.
`There are several reasons why this method isn’t suitable for a spy program.
`The primary reason is that this change to the registry won’t have an effect
`until the next time the system is booted. To spy on a program, you’d have to
`reboot the system first. Not feasible! Another downside to this approach is
`that the spy DLL will need to determine on a case by case basis if it wants
`to spy on the process it was just loaded for. For applications you don’t want
`to spy on, the API spy DLL should return 0 in its DllMain() procedure in
`response to the DLL_PROCESS_ATTACl-I notification. Returning 0 from
`DllMain tells the operating system that this DLL shouldn’t be loaded for
`this process. Yet another problem is that the operating system will try to
`load the DLL in every process, even in those hidden processes that you don’t
`interact with (like MPREXE.EXE). This slows down the entire system.
`The third way to inject a DLL into another process is the brute—force
`approach; this is the approach I’ll use in the API spy program. In an ideal
`world, we would somehow convey to the target process that it should call
`LoadLibrary to load our spy DLL, and that it should call LoadLibrary
`immediately upon starting up. While we can’t do this directly, there’s no
`reason why we ean’t trick the process into loading the DLL for us.
`Let’s look at an analogy to get a better feel for what I’m proposing.
`Suppose you wanted access to a vault that’s locked via a Voice-recognition
`lock. Only one person has the proper voice pattern to unlock the door, and
`you’re not that person. The person with the proper voice won’t willingly
`unlock the door for you. However, you could hypnotize the person, and
`while they’re in the trance, tell them to speak the words tolunlock the door.
`Before bringing them out of the hypnotic state, you tell them to forget
`everything that just happened.
`
`CSCO-1041
`Cisco v. SSL, IPR2015-01754
`Page 12 of 72
`
`

`
`Windows 95
`
`Progirdiifi
`
`So, how does this apply to loading a DLL? If we can freeze (or hypnotize,
`if you prefer) the target process, we can modify the process’s memory and reg-
`isters so that it looks like the process is calling LoadLibrary of its own volition.
`After setting up the registers and memory properly, we unfreeze the program
`and let it execute. The end result is that the target process calls LoadLibrary,
`and the operating system obliges by loading the API spying DLL into the target
`process’s address space. After the LoadLibrary call returns, we freeze the target
`process again, restore the memory and registers to their original values, and
`let the process resume as if nothing happened.
`As you might imagine, the code to fake the target process into calling
`LoadLibrary is complex. It’ll be modifying the code of the target process, so
`the first step is to calculate which code page it will modify and save that
`page away for later restoration. The injection code also needs to modify
`registers in the target process, so it should save away a copy of all the original
`register values. Luckily, Win32 provides the GetThreadContext function,
`which retrieves all the register values for a given thread into a C structure.
`Next, my code creates a code snippet to call LoadLibrary from within
`the context of the target process. Included in this code snippet is an ASCII
`string with the name of the spy DLL (APISPY32.DLL). Immediately after
`the call to LoadLibrary in the code snippet is a breakpoint instruction that
`allows the loader program to gain control immediately after the LoadLibrary
`executes. Once the code snippet is created, I write it out to the first page of
`the target process with the WriteProcessMemory function. Immediately
`after, I’ll change the EIP register in the target process so that execution will
`resume at the beginning of my code snippet.
`After setting up the memory and registers just so, the API spy program
`lets the target process execute. If all goes according to plan, the process
`successfully executes the LoadLibrary code and returns to the breakpoint I
`set. W/hen it hits the breakpoint, the target process is temporarily frozen
`again. The spy program takes this opportunity to restore the original code
`page it saved away, and to restore the original register values (again, using
`SetThreadConteXt()). With everything back to the way it was originally
`(except for the addition of our API spy DLL to the process’s address space),
`the breakpoint handler lets the target process resume execution. I’ll come
`back to this method of forcing another process to load a DLL in more detail
`when I show the code for the program in “The APISPY32 Code” section.
`
`CSCO-1041
`Cisco v. SSL, IPR2015-01754
`Page 13 of 72
`
`

`
`,;.,;.cw;.s2 API Spy
`
`595
`
`Usme THE DEBUG API TO
`
`CONTROL THE TARGET PROCESS
`
`When loading a DLL in another process’s context, it’s essential to have precise
`control over the child process’s execution. The Win32 debug API provides all
`the essential information we’ll need. In particular, we need to know exactly
`when the target process is about to execute the first instruction so that we can
`inject the spy’s DLL. We’ll also need the debug API to know when the target
`process terminates. In addition, when we’re performing surgery in the target
`process’s address space, we need to be sure that the process isn’t going to take
`off and start executing while we’re in the middle of it. Using the debugging
`API takes care of this problem. Whenever the debugged process reports some-
`thing to the debugger, all threads in the debuggee are suspended until the
`debugger tells the operating system to let the debuggee resume execution.
`If we were writing a spy program for 16-bit Windows programs, the
`TOOLHELP NotifyRegister and InterruptRegister functions would be just
`the ticket. The TOOLHELP NFY_STARTTASK notification would allow us
`to know when the new task is about to begin execution, but before it actually
`executes any of the task’s code. Unfortunately, the TOOLHELP model of
`notification callbacks assumes a single address space for all processes. The
`TOOLHELP notification callback model won’t work under the separate
`address spaces of NT and Windows 95, so we’ll need to use the closest
`equivalent, the Win32 debug API.
`Using the Win32 debug API to monitor the target process’s execution
`imposes a certain architecture on our API spy program. The API spy will
`consist of two components. The first component is the code that intercepts
`the API functions in the target process and logs them. This code must reside
`in a DLL since we’ll be injecting it into the address space of the process to
`be spied on. The second component of the API spy consists of a loader pro-
`gram that loads the process to be spied upon. After loading the program,
`the spy executable enters into a debugging loop, which consists primarily of
`calls to WaitFo_rDebugEvent() and ContinueDcbugEvent(). As debugging
`events are returned by WaitForDebugEvent(), the loader program examines
`the events and takes whatever action is necessary. The type of events that
`can be returned by WaitForDebugEvent()are
`
`EXCEPTION_DEBUG_EVENT
`CREATE_THRE/\D_DEBUG_EVENT
`CREATE_PROCESS_DEBUG_EVENT
`
`CSCO-1041
`Cisco v. SSL, IPR2015-01754
`Page 14 of 72
`
`

`
`696
`
`Windows 95iSlysi'eii1i
`
`EXIT_THREAD_DEBUG,EVENT
`EXIT_P ROCESS_DEBUG_EVENT
`LOAD DLL,DEBUG_EVENT
`UN LOAD_DLL_DEBUG_EVENT
`0UTPUT_DEBUG_STRING_EVENT
`RIP_EVENT
`
`Incidentally, if you compare the Win32 debug events to the notifications
`returned by a Win16 NotifyRegister callback function, you’ll notice a striking
`similarity. Also, if you want a program that uses \X/aitForDebugEvent and
`displays all the possible information returned by it, check out the DEB sample
`program in the Win32 SDK.
`Once our loader program has handled the debug event notification, it
`calls ContinueDebugEvent() to inform the operating system that it’s okay
`for the debuggee to resume execution. By putting WaitForDebugEvent and
`ContineDebugEvent() in a loop, the loader can see all significant events in
`the life of the process being spied on.
`The most important debug event for our API spy program is the
`EXCEPTION_DEBUG_EVENT. Immediately before a process is about to
`begin execution, WaitForDebugEvent() returns an EXCEPTION_DEBUG_
`EVENT notification, with the exception being of type STATUS_BREAK—
`POINT. The API spy loader program takes this as its cue to force the spy
`DLL into the process’s address space in the manner I described earlier.
`When the LoadLibrary call returns to the breakpoint we inserted into the
`process’s code area, the loader program sees another STATUS_BREAK-
`POINT exception. The loader program uses this to know when it should
`restore the original registers and memory pages that we modified earlier.
`Once the loader program has executed the target process past the two
`breakpoint exceptions, its work is mostly done. However, the Win32 API
`apparently doesn’t offer a way for a debugger to tell the system that it
`doesn’t want to receive debug notifications anymore. Once you begin using
`the debug API on a process, that process will be suspended each time it
`generates a debug event. A debugger call to ContinueDebugEvent for each
`debug event is the only way to keep the debuggee process running. Because
`of this, the API spy loader program needs to spin around in a WaitFor—
`DebugEvent and ContinueDebugEvent loop until the target process terminates.
`Even though we only really need a couple of the debug events, we’re forced
`to receive them all. We can ignore any debug event that we’re not interested
`in, and call ContinueDebugEvent without any further processing. In
`pseudocode form, the API spy loader looks like this:
`
`CSCO-1041
`Cisco v. SSL, IPR2015-01754
`Page 15 of 72
`
`

`
`Load Process to be spied on
`while ( TRUE )
`[
`
`NaitForDebugEvent()
`
`it ( dehud event is a breakpoint
`{
`
`)
`
`)
`if ( first breakpoint
`modify debuggee to make it load the spy DLL
`else if ( second breakpoint
`)
`restore original register and data pages of debuggee
`
`lse if ( debug event is an EXIT_PROCESS )
`break out of loop
`
`l e
`
`ContinueDebugEvent()
`
`BUILDING STUBS TO Loc; API FUNCTIONS
`
`At this point, we’Ve worked out the major architectural questions relating to
`the operating system:
`
`ll How API functions will be intercepted
`
`I How to load the spy DLL into the target process’s address space
`
`I How to precisely control the target process’s execution
`
`There are still other issues to deal with, but they’re not as directly
`related to operating system concerns. One such area is the code that will
`handle the redirected API function calls. While it would be tempting to try
`to make a single entry point for all the function calls we redirect to our spy
`DLL, that just isn’t feasible. There would be no way for a single entry point
`in the spy DLL to know which function call it’s currently logging. Instead,
`We’ll need to create a unique block of code for each function that We inter-
`cept. The word thunk is commonly used to describe short pieces of code
`that do some processing before transferring control elsewhere. While the
`blocks of code I’ll be creating could be called thunks, I’ll use the term stub
`to avoid ambiguity between my code and Window’s thunks. All the code
`stubs for our spy program will be similar, but will differ slightly. When each
`stub receives a redirected function call, it pushes information unique to that
`function onto the stack before calling a common routine to log the call.
`
`CSCO-1041
`Cisco v. SSL, IPR2015-01754
`Page 16 of 72
`
`

`
`698
`
`Windows 95 Syslem
`
`If all we needed to do was to intercept a known fixed set of functions, it
`would be easy to create some macros and generate all the code stubs at com-
`pile time. Since our specification dictates that this API spy be extendible, build-
`ing the stubs when we compile the spy program isn’t an option. Instead, we’ll
`need to dynamically create the stubs based on information in a configuration
`file. Luckily, under Win32 this isn’t hard.
`For each stub we need, we can simply allocate some memory and write
`the appropriate code into it. Under 16-bit Windows this would be harder,
`since we would need to somehow allocate memory in code segments, rather
`than in the data segments returned by memory allocation functions. Once
`we had proper code segments, we couldn’t just write our stub code into the
`memory block because writing into code segments isn’t allowed. To write
`to the code stubs, we’d have to use alias selectors or the TOOLHELP
`MemoryWrite() function. Under Win32 these issues don’t come up since both
`the code data segments map to the identical range of addresses. We can write
`out our code using regular flat model data pointers and later execute through
`that code.
`
`To build the stubs, the spy DLL reads an input file (APISPY32.API) that
`contains the following information about each function to be intercepted:
`
`I The DLL containing the function
`I The name of the function
`
`I Optional information about the function’s parameters
`
`For each function, the spy DLL builds a stub containing code and data,
`a11d which is of the form shown in Figur

This document is available on Docket Alarm but you must sign up to view it.


Or .

Accessing this document will incur an additional charge of $.

After purchase, you can access this document again without charge.

Accept $ Charge
throbber

Still Working On It

This document is taking longer than usual to download. This can happen if we need to contact the court directly to obtain the document and their servers are running slowly.

Give it another minute or two to complete, and then try the refresh button.

throbber

A few More Minutes ... Still Working

It can take up to 5 minutes for us to download a document if the court servers are running slowly.

Thank you for your continued patience.

This document could not be displayed.

We could not find this document within its docket. Please go back to the docket page and check the link. If that does not work, go back to the docket and refresh it to pull the newest information.

Your account does not support viewing this document.

You need a Paid Account to view this document. Click here to change your account type.

Your account does not support viewing this document.

Set your membership status to view this document.

With a Docket Alarm membership, you'll get a whole lot more, including:

  • Up-to-date information for this case.
  • Email alerts whenever there is an update.
  • Full text search for other cases.
  • Get email alerts whenever a new case matches your search.

Become a Member

One Moment Please

The filing “” is large (MB) and is being downloaded.

Please refresh this page in a few minutes to see if the filing has been downloaded. The filing will also be emailed to you when the download completes.

Your document is on its way!

If you do not receive the document in five minutes, contact support at support@docketalarm.com.

Sealed Document

We are unable to display this document, it may be under a court ordered seal.

If you have proper credentials to access the file, you may proceed directly to the court's system using your government issued username and password.


Access Government Site

We are redirecting you
to a mobile optimized page.





Document Unreadable or Corrupt

Refresh this Document
Go to the Docket

We are unable to display this document.

Refresh this Document
Go to the Docket