• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆 - 74, 文章 - 0, 評論 - 26, 引用 - 0
            數(shù)據(jù)加載中……

            Windows CE API機(jī)制初探 轉(zhuǎn)

            --[ 目錄

              1 - Windows CE架構(gòu)

              2 - 列出所有系統(tǒng)API

              3 - Windows CE的系統(tǒng)調(diào)用

              4 - coredll.dll對API的包裹

              5 - 用系統(tǒng)調(diào)用實(shí)現(xiàn)shellcode

              6 - 小結(jié)

              7 - 感謝

              8 - 參考資料


            --[ 1 - Windows CE架構(gòu)

            在 《Windows CE初探》一文中已經(jīng)介紹了KDataStruct的結(jié)構(gòu),這是一個(gè)非常重要的數(shù)據(jù)結(jié)構(gòu),可以從用戶態(tài)的應(yīng)用程序訪問。其開始地址是固定的 PUserKData(在SDK中定義:Windows CE Tools\wce420\POCKET PC 2003\Include\Armv4\kfuncs.h),對于ARM處理器是0xFFFFC800,而其它處理器是0x00005800。偏移 KINFO_OFFSET是UserKInfo數(shù)組,里面保存了重要的系統(tǒng)數(shù)據(jù),比如模塊鏈表、內(nèi)核堆、APIset pointers表(SystemAPISets)。《Windows CE初探》一文中通過模塊鏈表最終來搜索API在coredll中的地址,本文我們將討論一下UserKInfo[KINX_APISETS]處的 APIset pointers表。

            Windows CE的API機(jī)制使用了PSLs(protected server libraries),是一種客戶端/服務(wù)端模式。PSLs象DLL一樣處理導(dǎo)出服務(wù),服務(wù)的導(dǎo)出通過注冊APIset。

            有 兩種類型的APIset,分別是固有的和基于句柄的。固有的API sets注冊在全局表SystemAPISets中,可以以API句柄索引和方法索引的組合來調(diào)用他們的方法。基于句柄的API和內(nèi)核對象相關(guān),如文件、 互斥體、事件等。這些API的方法可以用一個(gè)對象的句柄和方法索引來調(diào)用。

            kfuncs.h中定義了固有APIset的句柄索引, 如:SH_WIN32、SH_GDI、SH_WMGR等。基于句柄的API索引定義在PUBLIC\COMMON\OAK\INC\psyscall.h 中,如:HT_EVENT、HT_APISET、HT_SOCKET等。

            SystemAPISets共有32個(gè)CINFO結(jié)構(gòu)的APIset,通過遍歷SystemAPISets成員,可以列出系統(tǒng)所有API。其中CINFO的結(jié)構(gòu)在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 - 列出所有系統(tǒng)API

            Dmitri Leman在他的cespy中有個(gè)DumpApis函數(shù),略加修改后如下:

            // 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,
                                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
                    l_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: %.4s   disp: %d   type: %d   cMethods: %d   "
                            "ppfnMethods: %08X   pdwSig: %08X   pServer: %08X %ls\n",
                            i,
                            l_pSet->acName,
                            l_pSet->disp,
                            l_pSet->type,
                            l_pSet->cMethods,
                            l_pSet->ppfnMethods,
                            l_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)
                        {
                            l_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)
                        {
                            l_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)
                                {
                                    l_pMethod = (PFNVOID)
                                        ((DWORD)l_pMethod + l_dwBaseAddress);
                                }
                                DWORD l_dwSign = l_pdwMethodSignatures?
                                    l_pdwMethodSignatures[j] : 0;
                                fprintf(fp,
                                    "  meth #%3i: %08X sign %08X\n",
                                    j,
                                    l_pMethod,
                                    l_dwSign);
                            }
                        }
                    }//for(int i = 0; i < NUM_SYSTEM_SETS; i++)
                }
                __except(1)
                {
                    fprintf(fp, "Exception in DumpApis\n");
                }

                if(l_dwOldPermissions)
                {
                    SetProcPermissions(l_dwOldPermissions);
                }
                fclose(fp);

                return 0;
            }

            來看一下此程序輸出的片斷:

            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: 8006BFEC 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
            ...

            這 是最開始的一個(gè)APIset,它的ppfnMethods是0x8004B138,cMethods是185,根據(jù)這兩個(gè)數(shù)據(jù)得到185個(gè)地址,這些地址 實(shí)際上就是內(nèi)核系統(tǒng)調(diào)用的實(shí)現(xiàn)地址。它們的索引相對PRIVATE\WINCEOS\COREOS\NK\KERNEL\kwin32.h里的 Win32Methods數(shù)組:

            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的系統(tǒng)調(diào)用

            Windows CE沒有使用ARM處理器的SWI指令來實(shí)現(xiàn)系統(tǒng)調(diào)用,SWI指令在Windows CE里是空的,就簡單的執(zhí)行了"movs pc,lr"(詳見armtrap.s關(guān)于SWIHandler的實(shí)現(xiàn))。Windows CE的系統(tǒng)調(diào)用使用了0xf0000000 - 0xf0010000的地址,當(dāng)系統(tǒng)執(zhí)行這些地址的時(shí)候?qū)|發(fā)異常,產(chǎn)生一個(gè)PrefetchAbort的trap。在PrefetchAbort的實(shí) 現(xiàn)里(詳見armtrap.s)首先會檢查異常地址是否在系統(tǒng)調(diào)用trap區(qū),如果不是,那么執(zhí)行ProcessPrefAbort,否則執(zhí)行 ObjectCall查找API地址來分派。

            通過APIset和其API的索引可以算出系統(tǒng)調(diào)用地址,其公式 是:0xf0010000-(256*apiset+apinr)*4。比如對于SC_CreateAPISet的系統(tǒng)調(diào)用可以這樣算出 來:0xf0010000-(256*0+2)*4=0xF000FFF8。


            --[ 4 - coredll.dll對API的包裹

            選擇一個(gè)沒有參數(shù)的SetCleanRebootFlag()進(jìn)行分析,IDAPro對其的反匯編如下:

            .text:01F74F70                 EXPORT SetCleanRebootFlag
            .text:01F74F70 SetCleanRebootFlag
            .text:01F74F70                 STMFD   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

            寫一個(gè)包含SetCleanRebootFlag()函數(shù)的小程序用EVC進(jìn)行跟蹤調(diào)試,按F11進(jìn)入該函數(shù)以后,程序首先取KDataStruct的lpvTls成員,然后取lpvTls偏移-0x14的內(nèi)容,測試該內(nèi)容是否是1。

            得先來了解一下lpvTls偏移-0x14的數(shù)據(jù)是什么。先看PUBLIC\COMMON\OAK\INC\pkfuncs.h里的幾個(gè)定義:

            #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

            看來lpvTls偏移-0x14保存的是當(dāng)前線程信息,只有第0比特被使用。再來看PRIVATE\WINCEOS\COREOS\NK\KERNEL\ARM\mdram.c里的MDCreateMainThread2函數(shù):

            ...
                if (kmode || bAllKMode) {
                    pTh->ctx.Psr = KERNEL_MODE;
                    KTHRDINFO (pTh) |= UTLS_INKMODE;
                } else {
                    pTh->ctx.Psr = USER_MODE;
                    KTHRDINFO (pTh) &= ~UTLS_INKMODE;
                }
            ...

            KTHRDINFO (pTh)在PRIVATE\WINCEOS\COREOS\NK\INC\kernel.h里定義:

            #define KTHRDINFO(pth)        ((pth)->tlsPtr[PRETLS_THRDINFO])

            它就是lpvTls偏移-0x14。也就是說系統(tǒng)在創(chuàng)建主線程的時(shí)候,根據(jù)程序當(dāng)前的模式來設(shè)置KTHRDINFO的值,如果是內(nèi)核模式,那么是1,否則是0。

            回 到coredll.dll中SetCleanRebootFlag的實(shí)現(xiàn),這時(shí)可以知道判斷l(xiāng)pvTls偏移-0x14的內(nèi)容是為了檢查當(dāng)前是否內(nèi)核模 式。由于Pocket PC ROM編譯時(shí)使用了Enable Full Kernel Mode選項(xiàng),所以程序都是以內(nèi)核模式運(yùn)行。于是接著調(diào)試時(shí)可以看到取0x1FC6760的內(nèi)容,取出來后,R0的值時(shí)0x8004B138,這個(gè)值正好 是DumpApis程序輸出的第一個(gè)APIset的ppfnMethods。接下來執(zhí)行:

            .text:01F74F90                 LDRNE   R1, [R0,#0x134]
            .text:01F74F94                 LDREQ   R1, =0xF000FECC

            由 于程序是內(nèi)核模式,所以前一條指令成功取出值,后一條無效。這時(shí)R1的值是0x80062AAC,和DumpApis程序輸出的一個(gè)地址匹配,根據(jù)索引, 發(fā)現(xiàn)這個(gè)地址是SC_SetCleanRebootFlag在內(nèi)核中的實(shí)現(xiàn)。其實(shí)索引也可以根據(jù)這條指令的偏移來取:0x134/4=0x4D(77), 根據(jù)kwin32.h里Win32Methods的索引直接就對應(yīng)出SC_SetCleanRebootFlag。內(nèi)核模式的話,后面還會執(zhí)行 SC_KillThreadIfNeeded。

            如果是用戶模式的話,系統(tǒng)會執(zhí)行0xF000FECC這個(gè)地址,這顯然是一個(gè)系統(tǒng)調(diào)用 trap地址。根據(jù)上面的公式算出索引值:(0xf0010000-0xF000FECC)/4=0x4D(77),根據(jù)kwin32.h里 Win32Methods的索引也對應(yīng)出這是SC_SetCleanRebootFlag。

            通過分析coredll.dll對API包裹的實(shí)現(xiàn),可以發(fā)現(xiàn)Windows CE在調(diào)用一部分API的時(shí)候會先判斷程序是否處于內(nèi)核模式,如果是,那么不用系統(tǒng)調(diào)用方式,直接奔內(nèi)核實(shí)現(xiàn)地址去了,否則就老老實(shí)實(shí)的用系統(tǒng)調(diào)用地址。


            --[ 5 - 用系統(tǒng)調(diào)用實(shí)現(xiàn)shellcode

            系 統(tǒng)調(diào)用地址相對固定,可以通過索引算出它的trap地址,而且搜索coredll.dll里API地址的方法在用戶態(tài)是無法實(shí)現(xiàn)的,因?yàn)槟K鏈表是在內(nèi)核 空間,用戶態(tài)無法訪問。下面就是用系統(tǒng)調(diào)用實(shí)現(xiàn)的簡單shellcode,它的作用是軟重啟系統(tǒng),我想對于smartphone的系統(tǒng)應(yīng)該也是可用 (smartphone的ROM在編譯時(shí)沒有用Enable Full Kernel Mode選項(xiàng))。

            #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,
                                HINSTANCE hPrevInstance,
                                LPTSTR    lpCmdLine,
                                int       nCmdShow)
            {
                ((void (*)(void)) & shellcode)();

                return 0;
            }


            --[ 6 - 小結(jié)

            通過本文可以了解到Windows CE API機(jī)制的大概輪廓,對于系統(tǒng)調(diào)用的具體流程,也就是trap后的具體流程還不是很清晰,本文也就一塊破磚頭,希望能砸到幾個(gè)人,可以一起討論;)
            文中如有錯(cuò)誤還望不吝賜教,希望Xcon''05見。


            --[ 7 - 感謝

            非常感謝Nasiry對我的幫助,在他的幫助下才得以完成此文。

            posted on 2008-08-14 15:36 井泉 閱讀(525) 評論(0)  編輯 收藏 引用 所屬分類: c code

            久久成人国产精品| 午夜欧美精品久久久久久久| 久久久久一区二区三区| 久久久久亚洲AV综合波多野结衣| 狠狠色综合久久久久尤物| 伊人色综合久久天天人守人婷| 国产一级持黄大片99久久| 亚洲午夜久久久久久久久电影网| 91秦先生久久久久久久| 久久精品国内一区二区三区 | 亚洲va久久久噜噜噜久久| 国产∨亚洲V天堂无码久久久 | 99久久精品免费看国产一区二区三区 | 久久精品国产99久久久| 热综合一本伊人久久精品 | 日本欧美久久久久免费播放网| 伊人久久亚洲综合影院| 精品久久久久久久久中文字幕| 亚洲精品97久久中文字幕无码| 国产高潮国产高潮久久久| 免费无码国产欧美久久18| 亚洲午夜精品久久久久久浪潮| 国产精品一久久香蕉国产线看| 嫩草伊人久久精品少妇AV| 欧美日韩精品久久久久| 国内精品久久久久久久coent| AV无码久久久久不卡网站下载| 久久人妻少妇嫩草AV蜜桃| 亚洲∧v久久久无码精品| 麻豆av久久av盛宴av| 午夜精品久久久久久| 久久最新免费视频| 久久综合亚洲色HEZYO国产| 久久激情亚洲精品无码?V| 久久亚洲AV无码精品色午夜| 久久er国产精品免费观看8| 亚洲综合精品香蕉久久网97| 久久综合狠狠色综合伊人| 国产激情久久久久影院| 香蕉久久永久视频| 一本色综合久久|