Click here to Skip to main content
15,742,323 members
Articles / Mobile Apps / Windows Phone 7
Posted 11 May 2012


7 bookmarked

Windows CE Hook (GWES.exe)

Rate me:
Please Sign up or sign in to vote.
4.00/5 (2 votes)
11 May 2012CPOL6 min read
WINDOWS CE API HOOKING and Replace Function inside GWES.exe on all models since pocket PC 2003 until Windows mobile 6.5


As we know, Windows CE threads can migrate between processes while executing API calls, it borrows the caller's thread and places it in the server process. Such servers are called "Protected Server Libraries" (PSLs) and are processes that export services like DLLs.

Protected Server Libraries (PSL) are used by Windows CE to create API sets that in their own process address space and can server multiple clients concurrently. Windows CE implements all of its system APIs using this technique including all WIN32 APIs, User interface, device driver, and many of its DirectX interfaces. There is a one to one mapping between an API call and its corresponding PSL entry.

Windows CE implements PSL support through a clever technique generating special processor fault conditions that cause the execution of PSL entry points. The system maintains a table of 32 PSL entries. All entries between 0 and 24 are preassigned and may not be used for custom PSLs. PSLs register their APIs, associating their API with one particular entry in the PSL table. Part of the PSL registration process is providing the system with a function table of all the API entry points for a particular PSL. There are also a set of macros defined in psyscall.h which take the PSL id and an index into the registered function table to indicate which particular function for the specified PSL is to be called. This macro generates a 'function pointer' that really is an invalid memory address. When this function pointer gets used, it causes the processor to fault. The fault handling code then inspects the faulty address and sees that it is one of the special PSL addresses and extracts the PSL id and function table index. It then turns around and calls the correct entry point in the PSL, just as if the caller had directly jumped to it – with one significant difference in that process address spaces have been jumped across as well. When the PSL function finishes execution and returns, the OS resumes the application that called the PSL to begin with by returning from the fault condition with the return value from the PSL function. The application resumes execution and it looks just as if a function call had occurred. Because PSLs are the core way APIs are implemented in the system, the code path for executing this process is very streamlined.

PSLs have four main components:

  1. Functions implementing the various entry points of the PSL.
  2. Function table (a Vtable) that is an array of function pointers containing all the entry points of the PSL. This is an array of pointers to the functions making up the API set (PSL entries). The first two entries are reserved for the kernel. The first entry is the notification procedure that the kernel will call any time a thread or a process is stopped or started, low memory occurs, or the system is booted. The second entry is reserved by the kernel and should be zero. All remaining entries are available to the PSL implementer.
  3. Signature table describing all the argument types for each function in the function table. Made up of an array of 2 or more entry points with a one to one correspondence to the API function table. You can use these macros: FNSIG0-12, DW - DWORD, PTR - Pointer, I64 - 64 bit integer. PSL functions can have one of three argument types (DW, PTR, I64) or no arguments at. Those types are a DWORD (unsigned long), a pointer (void *), or a 64 bit integer (long long). There return values are the same. They can be used in any combination within a function or across function. There can be no other parameter types but the current parameter types can be used to contain other types (like a WORD or WCHAR in a DWORD, a BSTR in a void *). PSL functions can have from zero to 12 arguments. As can be seen above, each PSL function signature is defined by using an FNSIG macro that is followed by the number of arguments the function has. The FNSIG macro is then filled in with an argument type specification for each argument it has.

    The data in the signature table is used by the kernel to marshal arguments for the PSL function calls across process address spaces so it is imperative that these be correct or arguments will not get passed correctly from a client calling your PSL into the actual function in your PSL that implements the API call.

  4. A .lib that clients of the PSL link to which contains the code that generates the special invalid memory address that causes the processor to fault and execute the PSL. The code also can be inline functions defined in the header file.

    Image 1


As I know, there are two ways to hook for primitive and one for Expert:

  • Basic Hooking
  • Advanced Hooking


One may suggest that in order to hook a system function (from application located in the ROM of the device), it is enough to replace the APISET functions pointers. This will work partially. This technique will intercept only the calls from part of the programs on the device: all third party applications and some of the ones in the ROM (depending which team in MS has built them probably). It will not intercept calls from the kernel itself.

The reason for this is that when the whole OS image is built with Platform Builder, the addresses of all system functions are known. So in order to gain efficiency, all system calls are replaced with the appropriate address. They do not go through the whole APISET mechanism (which is fast but not as fast as the direct call).


If we want to intercept all possible calls - other technique is required. We should place our hook at the address that kernel calls for particular function. We cannot replace the existing code there - since it is located in ROM. So the only choice left is to tweak the virtual memory (VM) mappings and fool the system.

/* initializes the VM related variables */
static void InitializePageSize() 

	if (PAGE_SIZE == 4096) {
		VA_PAGE = 12;
		PAGE_MASK = 0x00F;
	} else {
		VA_PAGE = 10;
		PAGE_MASK = 0x03F;

VM is an old concept. Basically, the OS keeps table(s) describing mappings between the physical memory pages and virtual memory addresses (all applications work with virtual addresses and the pointer in the APISET tables are virtual).

We do the following steps:

  1. Find the virtual address of the function we want to hook
  2. Find the physical page mapping (in VM tables) for this address
  3. Allocate new physical pages and copy our code in it
  4. Switch the mapping found in step (2) to point to the page allocated in (3)

By carefully designing the code in step (3), we are able to intercept the calls without losing the capability to call the original function.

We got this Value form Platform Builder:

#define W32_SetKMode			108
#define W32_CreateAPISet		 2
#define W32_CacheSync			34
#define W32_SetProcPermissions	72
#define W32_QueryAPISetID		112
#define W32_LockPages			138
#define W32_GetRomFileInfo		32
#define W32_GetCallerProcess 	68
#define W32_GetProcAddrBits		63
#define W32_GetProcFromPtr		61
#define W32_GetOwnerProcess		67 
#define GetProcAddrEx	WIN32_CALL(FARPROC,GetProcAddressW,(HMODULE,LPCWSTR))
#define QueryAPISetID	WIN32_CALL(int, QueryAPISetID, (char *))
#define GetProcAddrBits		WIN32_CALL(DWORD, GetProcAddrBits, (HANDLE))
#define GetCallerProcess	WIN32_CALL(HANDLE, GetCallerProcess, (void))
#define GetOwnerProcess	WIN32_CALL(HANDLE, GetOwnerProcess, (void))
#define GetProcFromPtr	WIN32_CALL(HANDLE, GetProcFromPtr, (LPVOID))
#define GetKPhys	WIN32_CALL(BOOL, GetKPhys, (void *, DWORD))
#define ProcGetIndex(h)	((DWORD (*)(HANDLE))IMPLICIT_CALL(SH_WIN32,W32_ProcGetIndex))(h)
#define LockPages WIN32_CALL(BOOL, LockPages, 
(LPVOID lpvAddress, DWORD cbSize, PDWORD pPFNs, int fOptions))
#define SetProcPermissions WIN32_CALL(DWORD, SetProcPermissions, (DWORD))
#define SetKMode WIN32_CALL(BOOL, SetKMode, (BOOL))
#define CreateAPISet WIN32_CALL(HANDLE, CreateAPISet, 
(char acName[4], USHORT cFunctions, const PFNVOID *ppfnMethods, const DWORD *pdwSig))
#define CacheSync WIN32_CALL(void, CacheSync, (int flags))
#define GetRomFileInfo WIN32_CALL(void, GetRomFileInfo, 
(DWORD type, LPWIN32_FIND_DATA lpfd, DWORD count)) 

Image 2

/* return to pointer Virtual Memory mapping */

GetMemBlock(void *ptr) {

	PSECTION pscn =
        SectionTable[ ((ulong)ptr >> VA_SECTION) & SECTION_MASK];

	return (*pscn)[((ulong)ptr >> VA_BLOCK) & BLOCK_MASK];
DWORD GetGwesBaseAddress(HANDLE *pHandle) {
	po += SH_GDI;
	CINFO *pogdi = (CINFO *)(*po);
	PPROCESS p = (PPROCESS)pogdi->pServer;
	if (pHandle)
		*pHandle = p->hProc;
	return (p->dwVMBase);

To get Address of Gwes inside memory:


This very important code is to set Access to patch your low level code.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Written By
Software Developer (Senior)
Jordan Jordan
Mobile Developer with deep Experience in Handheld Device Pocket Pc, Smart Phone in Win32, MFC With more than 8 years ago."Arabizer, Hook Function, Poom, Wirless Application, and low level Application". By C++ MFC and win32

Comments and Discussions

QuestionGreat info, unfortunately no full example, only theory Pin
hjgode21-Oct-13 0:03
hjgode21-Oct-13 0:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.