Created:
Article attributes: original
Article submitted: San (san_at_xfocus.org)
A Preliminary Study on Windows ce api Mechanism
Sorting: San
Created: 2005.07.06
Updated: 2005.07.07
-- [Directory
1-Windows CE Architecture
2-List all system APIs
3-Windows CE system call
4-coredll. dll packages APIs
5-implement shellcode using system calls
6-Summary
7-Thanks
8-References
-- [1-Windows CE Architecture
The kdatastruct structure has been introduced in the article Windows CE, which is a very important data structure that can be accessed from user-State applications. The starting address is fixed puserkdata (defined in the SDK: Windows CE tools/wce420/Pocket PC 2003/include/armv4/kfuncs. h). For arm processors, the value is 0xffffc800, while for other processors, the value is 0x00005800. The offset kinfo_offset is the userkinfo array, which stores important system data, such as the module linked list, Kernel Heap, and apiset pointers table (systemapisets ). In the article Windows CE, the address of the API in coredll is searched through the module linked list. In this article, we will discuss the apiset pointers table at userkinfo [kinx_apisets.
The API mechanism of Windows CE uses psls (protected server libraries), which is a Client/Server mode. The psls process the export service like the DLL, and the export of the service is registered with apiset.
There are two types of apiset, inherent and handle-based. Inherent API sets are registered in the global table systemapisets. They can call their methods by combining API handle indexes and method indexes. Handle-based APIs are related to kernel objects, such as files, mutex, and events. These API methods can be called using an object's handle and method index.
Kfuncs. h defines the handle indexes of the inherent apiset, such as sh_win32, sh_gdi, and sh_wmgr. The handle-based API indexes are defined in public/common/oak/INC/psyscall. H, such as ht_event, ht_apiset, and ht_socket.
Systemapisets has 32 Cinfo-structured apiset. You can list all the system APIS by traversing the systemapisets members. The Cinfo structure is defined in private/winceos/coreos/nk/INC/kernel. h:
/**
* Data structures and functions for handle Manipulations
*/
Typedef struct Cinfo {
Char acname [4];/* 00: Object Type ID string */
Uchar disp;/* 04: type of dispatch */
Uchar type;/* 05: API handle type */
Ushort cmethods;/* 06: # of methods in dispatch table */
Const pfnvoid * ppfnmethods;/* 08: PTR to array of methods (in server address space )*/
Const DWORD * pdwsig;/* 0C: PTR to array of method signatures */
Pprocess pserver;/* 10: PTR to server process */
} Cinfo;/* Cinfo */
Typedef Cinfo * pcinfo;
-- [2-List all system APIs
Dmitri Leman has a dumpapis function in his cespy, which is slightly modified as follows:
// Dumpapis. cpp
//
# Include "stdafx. H"
Extern "C" DWORD _ stdcall setprocpermissions (DWORD );
# Define kinfo_offset 0x300
# Define kinx_api_mask 18
# Define kinx_apisets 24
# Define userkinfo (long *) (puserkdata + kinfo_offset ))
// Pointer to struct process declared in kernel. h.
Typedef void * pprocess;
// I will not bother redeclaring this large structure.
// I will only define offsets to 2 fields used in dumpapis ():
# Define process_num_offset 0 // process number (index of the slot)
# Define process_name_offset 0x20 // pointer to the process name
// Also declare structure Cinfo, which holds an information
// About an API (originally declared in
// Private/winceos/coreos/nk/INC/kernel. h ).
Typedef struct Cinfo {
Char acname [4];/* 00: Object Type ID string */
Uchar disp;/* 04: type of dispatch */
Uchar type;/* 05: API handle type */
Ushort cmethods;/* 06: # of methods in dispatch table */
Const pfnvoid * ppfnmethods;/* 08: PTR to array of methods (in server address space )*/
Const DWORD * pdwsig;/* 0C: PTR to array of method signatures */
Pprocess pserver;/* 10: PTR to server process */
} Cinfo;/* Cinfo */
# Define num_system_sets 32
/*-------------------------------------------------------------------
Function: processaddress
Purpose:
Returns an address of memory slot for the given process index.
Parameters:
Byte p_byprocnum-process number (slot index) between 0 and 31
Returns:
Address of the memory slot.
-------------------------------------------------------------------*/
Inline DWORD processaddress (byte p_byprocnum)
{
Return 0x02000000 * (p_byprocnum + 1 );
}
Int winapi winmain (hinstance,
Hinstance hprevinstance,
Lptstr lpcmdline,
Int ncmdshow)
{
File * FP;
DWORD l_dwoldpermissions = 0;
If (FP = fopen ("// apis.txt", "W") = NULL)
{
Return 1;
}
Fprintf (FP, "Dump APIs:/N ");
_ Try
{
// Get access to memory slots of other processes
Rochelle dwoldpermissions = setprocpermissions (-1 );
Cinfo ** l_psystemapisets = (Cinfo **) (userkinfo [kinx_apisets]);
For (INT I = 0; I <num_system_sets; I ++)
{
Cinfo * l_pset = l_psystemapisets [I];
If (! L_pset)
{
Continue;
}
Lpbyte l_pserver = (lpbyte) l_pset-> pserver;
Fprintf (FP,
"Apiset: % 02x acname: %. 4 s disp: % d type: % d cmethods: % d"
"Ppfnmethods: % 08x pdwsig: % 08x pserver: % 08x % ls/N ",
I,
Rochelle pset-> acname,
Rochelle pset-> disp,
Rochelle pset-> type,
Rochelle pset-> cmethods,
Rochelle pset-> ppfnmethods,
Rochelle pset-> pdwsig,
L_pserver,
L_pserver? (* (Lptstr *)
(L_pserver + process_name_offset): _ T (""));
// If this API is served by an application-get it's
// Address, if it is served by the kernel-use address 0
DWORD l_dwbaseaddress = 0;
If (l_pserver)
{
Rochelle dwbaseaddress = processaddress
(* (L_pserver + process_num_offset ));
}
// Add the base address to the method and signature
// Tables pointers
Pfnvoid * l_ppmethods = (pfnvoid *) l_pset-> ppfnmethods;
If (l_ppmethods & (DWORD) l_ppmethods <0x2000000)
{
L_ppmethods = (pfnvoid *)
(DWORD) l_ppmethods + l_dwbaseaddress );
}
DWORD * l_pdwmethodsignatures = (DWORD *) l_pset-> pdwsig;
If (l_pdwmethodsignatures &&
(DWORD) l_pdwmethodsignatures <0x2000000)
{
Rochelle pdwmethodsignatures = (DWORD *)
(DWORD) l_pdwmethodsignatures + l_dwbaseaddress );
}
If (l_ppmethods)
{
For (Int J = 0; j <l_pset-> cmethods; j ++)
{
Pfnvoid l_pmethod = l_ppmethods?
L_ppmethods [J]: 0;
If (l_pmethod & (DWORD) l_pmethod <0x2000000)
{
Rochelle method = (pfnvoid)
(DWORD) l_pmethod + l_dwbaseaddress );
}
DWORD l_dwsign = l_pdwmethodsignatures?
Rochelle pdwmethodsignatures [J]: 0;
Fprintf (FP,
"Meth # % 3I: % 08x sign % 08x/N ",
J,
Rochelle method,
Rochelle dwsign );
}
}
} // For (INT I = 0; I <num_system_sets; I ++)
}
_ Partition T (1)
{
Fprintf (FP, "exception in dumpapis/N ");
}
If (l_dwoldpermissions)
{
Setprocpermissions (l_dwoldpermissions );
}
Fclose (FP );
Return 0;
}
Let's take a look at the piece output by this program:
Apiset: 00 acname: wn32 disp: 3 type: 0 cmethods: 185 ppfnmethods: 8004b138 pdwsig: 00000000 pserver: 00000000
Meth #0: 8006c83c sign 00000000
Meth #1: 8006c844 sign 00000000
Meth #2: 800804c4 sign 00000000
Meth #3: 8006bf20 sign 00000000
Meth #4: 8006bf94 sign 00000000
Meth #5: 8006 BFEC sign 00000000
Meth #6: 8006c0a0 sign 00000000
Meth #7: 8008383c sign 00000000
Meth #8: 80068fc8 sign 00000000
Meth #9: 800694b0 sign 00000000
Meth #10: 8006968c sign 00000000
...
This is the first apiset. Its ppfnmethods is 0x8004b138, and cmethods is 185. Based on the two data, we get 185 addresses. These addresses are actually the Implementation addresses of kernel system calls. Their indexes are relative to the win32methods array in private/winceos/coreos/nk/kernel/kwin32.h:
Const pfnvoid win32methods [] = {
(Pfnvoid) SC _nop,
(Pfnvoid) SC _notsupported,
(Pfnvoid) SC _createapiset, // 2
(Pfnvoid) ext_virtualalloc, // 3
(Pfnvoid) ext_virtualfree, // 4
(Pfnvoid) ext_virtualprotect, // 5
(Pfnvoid) ext_virtualquery, // 6
(Pfnvoid) SC _virtualcopy, // 7
(Pfnvoid) SC _loadlibraryw, // 8
(Pfnvoid) SC _freelibrary, // 9
(Pfnvoid) SC _getprocaddressw, // 10
...
(Pfnvoid) SC _interruptmask, // 184
};
-- [3-Windows CE system call
Windows CE does not use the SWI command of the ARM processor to implement system calling. If the SWI command is empty in Windows CE, it simply executes "movs PC and LR" (see armtrap for details. s ). Windows CE uses the address 0xf0000000-0xf0010000 for system calls. When the system executes these addresses, an exception is triggered and a prefetchabort trap is generated. In the implementation of prefetchabort (for details, see armtrap. s), the system checks whether the abnormal address is in the system call trap zone. If not, processprefabort is executed; otherwise, objectcall is executed to locate the API address and assign it.
You can use the index of apiset and its API to calculate the system call address. The formula is 0xf0010000-(256 * apiset + apinr) * 4. For example, the system call to SC _createapiset can be calculated as follows: 0xf0010000-(256*0 + 2) * 4 = 0xf000fff8.
-- [4-coredll. dll package for API
Select a setcleanrebootflag () without parameters for analysis. The Decompilation of idapro is as follows:
. Text: 01f74f70 export setcleanrebootflag
. Text: 01f74f70 setcleanrebootflag
. Text: 01f74f70 127fd SP !, {R4, R5, LR}
. Text: 01f74f74 LDR R5, = 0xffffc800
. Text: 01f74f78 LDR R4, = unk_1fc6760
. Text: 01f74f7c LDR r0, [R5]; (2ff00-0x14)-> 1
. Text: 01f74f80 LDR R1, [r0, #-0x14]
. Text: 01f74f84 TST R1, #1
. Text: 01f74f88 ldrne r0, [R4]; 8004b138 ppfnmethods
. Text: 01f74f8c cmpne r0, #0
. Text: 01f74f90 ldrne R1, [r0, #0x134]
. Text: 01f74f94 ldreq R1, = 0xf000fecc
. Text: 01f74f98 mov LR, PC
. Text: 01f74f9c mov PC, R1; 80062aac SC _setcleanrebootflag
. Text: 01f74fa0 LDR R3, [R5]
. Text: 01f74fa4 LDR r0, [R3, #-0x14]
. Text: 01f74fa8 TST r0, #1
. Text: 01f74fac ldrne r0, [R4]; 8004b138 ppfnmethods
. Text: 01f74fb0 cmpne r0, #0
. Text: 01f74fb4 ldrne r0, [r0, # 0x25c]
. Text: 01f74fb8 movne LR, PC; 800810ec SC _killthreadifneeded
. Text: 01f74fbc movne PC, R0
. Text: 01f74fc0 ldmfd SP !, {R4, R5, PC}
. Text: 01f74fc0; end of function setcleanrebootflag
Write a small program that contains the setcleanrebootflag () function and use EVC for tracking and debugging. after entering the function by F11, the program first obtains the lpvtls member of kdatastruct, and then obtains the content of lpvtls offset-0x14, test whether the content is 1.
First, let's take a look at the data of lpvtls offset-0x14. Let's first look at several definitions in public/common/oak/INC/pkfuncs. h:
# Define curtlsptr_offset 0x000
# Define utlsptr () (* (lpdword *) (puserkdata + curtlsptr_offset ))
# Define pretls_thrdinfo-5 // current thread's information (bit fields, only bit 0 used for now)
# Define utls_inkmode 0x00000001 // bit 1 set if in kmode
It seems that lpvtls offset-0x14 stores the current thread information, and only 0th bits are used. Let's look at the mdcreatemainthread2 function in private/winceos/coreos/nk/kernel/ARM/mdram. C:
...
If (kmode | ballkmode ){
PTH-> CTX. PSR = kernel_mode;
Kthrdinfo (PTH) | = utls_inkmode;
} Else {
PTH-> CTX. PSR = user_mode;
Kthrdinfo (PTH) & = ~ Utls_inkmode;
}
...
Kthrdinfo (PTH) is defined in private/winceos/coreos/nk/INC/kernel. h:
# Define kthrdinfo (PTH)-> tlsptr [pretls_thrdinfo])
It is the lpvtls offset-0x14. That is to say, when the system creates the main thread, it sets the value of kthrdinfo according to the current program mode. If it is in kernel mode, it is 1; otherwise, it is 0.
Return to the implementation of setcleanrebootflag in coredll. dll. You can check whether the lpvtls offset-0x14 is used to check whether the kernel mode is used. Since the enable full Kernel Mode option is used in Pocket PC Rom compilation, all programs run in kernel mode. Then we can see the content of 0x1fc6760 during debugging. After the result is obtained, the R0 value is 0x8004b138, which is exactly the ppfnmethods of the first apiset output by the dumpapis program. Run the following command:
. Text: 01f74f90 ldrne R1, [r0, #0x134]
. Text: 01f74f94 ldreq R1, = 0xf000fecc
Because the program is in kernel mode, the value of the previous command is successfully retrieved, and the other one is invalid. At this time, the value of R1 is 0x80062aac, which matches the address output by the dumpapis program. According to the index, it is found that this address is the implementation of SC _setcleanrebootflag in the kernel. In fact, the index can also be obtained based on the offset of this command: 0x134/4 = 0x4d (77). According to the index of win32methods in kwin32.h, SC _setcleanrebootflag is directly matched. In kernel mode, SC _killthreadifneeded will be executed later.
In user mode, the system executes the address 0xf000fecc, which is obviously a system call trap address. Calculate the index value based on the formula above: (0xf000000-0xf000fecc)/4 = 0x4d (77). According to the index of win32methods in kwin32.h, this is also SC _setcleanrebootflag.
By analyzing coredll. by implementing the dll api package, we can find that Windows CE first checks whether the program is in kernel mode when calling some APIs. If yes, the system call method is not required, run the kernel implementation address directly. Otherwise, the system call address will be used honestly.
-- [5-implement shellcode using system calls
The system call address is relatively fixed. You can use the index to calculate its trap address and search for coredll. the API address method in DLL cannot be implemented in the user State, because the module linked list is in the kernel space and the user State cannot be accessed. The following is a simple shellcode implemented by using a system call. Its function is to restart the system, I think the smartphone system should also be available (the enable full Kernel Mode option is not used for the smartphone Rom during compilation ).
# Include "stdafx. H"
Int shellcode [] =
{
0xe59f0014, // LDR r0, [PC, #20]
0xe59f4014, // LDR R4, [PC, #20]
0xe3a01000, // mov R1, #0
0xe3a02000, // mov R2, #0
0xe3a03000, // mov R3, #0
0xe1a0e00f, // mov LR, PC
0xe1a0f004, // mov PC, r4
0x0101003c, // ioctl_hal_reboot
0xf000fe74, // trap address of kerneliocontrol
};
Int winapi winmain (hinstance,
Hinstance hprevinstance,
Lptstr lpcmdline,
Int ncmdshow)
{
(Void (*) (void) & shellcode )();
Return 0;
}
-- [6-Summary
Through this article, we can understand the rough outline of the Windows ce api mechanism, and the specific process of system calling, that is, the specific process after trap, is not very clear. This article is also a piece of broken bricks, I hope I can discuss it with several people ;)
If there are any errors in this article, I hope you can see xcon '05.
-- [7-Thanks
Thanks to nasiry for helping me complete this article with his help.
-- [8-References
[1] spy: A Windows ce api interceptor by Dmitri Leman
Dr. Dobb's journal October 2003
[2] MISC notes on the xda and Windows CE
Http://www.xs4all.nl /~ Itsme/projects/xda/
[3] WindowsCE exceptions and service interruptions by nasiry
Http://www.cnblogs.com/nasiry/archive/2004/12/27/82476.html
Http://www.cnblogs.com/nasiry/archive/2005/01/06/87381.html
[4] Windows CE 4.2 source code
Http://msdn.microsoft.com/embedded/windowsce/default.aspx