Introduction
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:
- Functions implementing the various entry points of the PSL.
- 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.
- 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 signiture 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.
- 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.
Background
As I Know there are tow way to hook for for primitive and one for Expert
- Basic Hooking
- Advanced Hooking
BASIC 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 not go through the whole APISET mechanism (which is fast but not as fast
as the direct call).
ADVANCED HOOKING 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.
static void InitializePageSize()
{
PAGE_SIZE = UserKInfo[KINX_PAGESIZE];
if (PAGE_SIZE == 4096) {
VA_PAGE = 12;
PAGE_MASK = 0x00F;
} else {
VA_PAGE = 10;
PAGE_MASK = 0x03F;
}
}
VM is 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 loosing the capability to call 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 RegisterAPISet _APISET_CALL(BOOL, REGISTER, (HANDLE hASet, DWORD dwSetID))
#define CacheSync WIN32_CALL(void, CacheSync, (int flags))
#define GetRomFileInfo WIN32_CALL(void, GetRomFileInfo, (DWORD type, LPWIN32_FIND_DATA lpfd, DWORD count))

MEMBLOCK*
GetMemBlock(void *ptr) {
PSECTION pscn =
SectionTable[ ((ulong)ptr >> VA_SECTION) & SECTION_MASK];
return (*pscn)[((ulong)ptr >> VA_BLOCK) & BLOCK_MASK];
}
DWORD GetGwesBaseAddress(HANDLE *pHandle) {
DWORD *po = (DWORD *)UserKInfo[KINX_APISETS];
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
InitializePageSize();
SetKMode(1);
SetProcPermissions(0xffffffff);
This Very important code to set Access to patch your low level code .
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
http://windowsmobiledn.blog.com/