青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

隨筆 - 74, 文章 - 0, 評論 - 26, 引用 - 0
數據加載中……

Windows CE API機制初探 轉

--[ 目錄

  1 - Windows CE架構

  2 - 列出所有系統API

  3 - Windows CE的系統調用

  4 - coredll.dll對API的包裹

  5 - 用系統調用實現shellcode

  6 - 小結

  7 - 感謝

  8 - 參考資料


--[ 1 - Windows CE架構

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

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

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

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

SystemAPISets共有32個CINFO結構的APIset,通過遍歷SystemAPISets成員,可以列出系統所有API。其中CINFO的結構在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 - 列出所有系統API

Dmitri Leman在他的cespy中有個DumpApis函數,略加修改后如下:

// 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
...

這 是最開始的一個APIset,它的ppfnMethods是0x8004B138,cMethods是185,根據這兩個數據得到185個地址,這些地址 實際上就是內核系統調用的實現地址。它們的索引相對PRIVATE\WINCEOS\COREOS\NK\KERNEL\kwin32.h里的 Win32Methods數組:

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的系統調用

Windows CE沒有使用ARM處理器的SWI指令來實現系統調用,SWI指令在Windows CE里是空的,就簡單的執行了"movs pc,lr"(詳見armtrap.s關于SWIHandler的實現)。Windows CE的系統調用使用了0xf0000000 - 0xf0010000的地址,當系統執行這些地址的時候將會觸發異常,產生一個PrefetchAbort的trap。在PrefetchAbort的實 現里(詳見armtrap.s)首先會檢查異常地址是否在系統調用trap區,如果不是,那么執行ProcessPrefAbort,否則執行 ObjectCall查找API地址來分派。

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


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

選擇一個沒有參數的SetCleanRebootFlag()進行分析,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

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

得先來了解一下lpvTls偏移-0x14的數據是什么。先看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

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

...
    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。也就是說系統在創建主線程的時候,根據程序當前的模式來設置KTHRDINFO的值,如果是內核模式,那么是1,否則是0。

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

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

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

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

通過分析coredll.dll對API包裹的實現,可以發現Windows CE在調用一部分API的時候會先判斷程序是否處于內核模式,如果是,那么不用系統調用方式,直接奔內核實現地址去了,否則就老老實實的用系統調用地址。


--[ 5 - 用系統調用實現shellcode

系 統調用地址相對固定,可以通過索引算出它的trap地址,而且搜索coredll.dll里API地址的方法在用戶態是無法實現的,因為模塊鏈表是在內核 空間,用戶態無法訪問。下面就是用系統調用實現的簡單shellcode,它的作用是軟重啟系統,我想對于smartphone的系統應該也是可用 (smartphone的ROM在編譯時沒有用Enable Full Kernel Mode選項)。

#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 - 小結

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


--[ 7 - 感謝

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

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

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            牛牛精品成人免费视频| 亚洲私人影吧| 久久精品国产亚洲a| 欧美日韩另类综合| 在线综合视频| 夜夜爽www精品| 欧美日韩一区在线视频| 在线视频精品一| 亚洲韩国青草视频| 欧美精品xxxxbbbb| 在线一区观看| 亚洲精品资源美女情侣酒店| 欧美日韩一二区| 亚洲欧美日韩另类| 香蕉久久夜色精品国产| 在线免费日韩片| 亚洲激情网站免费观看| 欧美性猛交视频| 久久国产色av| 美日韩精品免费| 亚洲一区二区在| 久久精品国产欧美激情 | 欧美国产日本在线| 亚洲视频一区二区| 午夜精品一区二区三区电影天堂| 国内精品福利| 亚洲精品欧美日韩| 国产一区二区三区在线观看网站 | 国语精品中文字幕| 亚洲激情精品| 国产欧美日韩视频一区二区三区| 久热re这里精品视频在线6| 欧美刺激性大交免费视频| 亚洲欧美另类在线| 美女91精品| 午夜精品三级视频福利| 美女主播视频一区| 欧美一区网站| 欧美黑人国产人伦爽爽爽| 欧美在线免费看| 欧美理论电影在线观看| 久久久久国产精品麻豆ai换脸| 欧美成人精品一区| 久久先锋资源| 国产精品海角社区在线观看| 欧美国产欧美综合| 韩日午夜在线资源一区二区| 日韩小视频在线观看| 亚洲福利一区| 欧美在线观看天堂一区二区三区| 亚洲素人在线| 欧美黄在线观看| 久久影音先锋| 国产午夜精品全部视频在线播放| 日韩午夜在线观看视频| 亚洲美女av网站| 久久综合九色综合欧美狠狠| 久久精品国产亚洲a| 国产精品美女久久久免费 | 一区二区精品| 欧美成人午夜免费视在线看片| 久久亚洲综合色| 国产欧美精品一区二区三区介绍 | 欧美中文字幕在线| 国产精品videossex久久发布| 亚洲欧洲精品一区二区三区不卡| 伊人狠狠色丁香综合尤物| 欧美一二区视频| 篠田优中文在线播放第一区| 国产精品久久久久99| 99综合在线| 亚洲免费婷婷| 国产伦精品一区二区三区照片91| 在线一区欧美| 小黄鸭精品aⅴ导航网站入口| 欧美视频一区在线观看| 亚洲欧美日韩一区二区| 亚洲精选国产| 美日韩在线观看| 久久久久久噜噜噜久久久精品| 在线视频亚洲| 日韩亚洲一区二区| 亚洲国产精品久久久久秋霞影院| 国产欧美一区二区三区在线看蜜臀| 国产麻豆日韩欧美久久| 欧美成人免费在线观看| 亚洲国产精品电影| 亚洲狠狠丁香婷婷综合久久久| 久久香蕉国产线看观看av| 欧美v国产在线一区二区三区| 在线日韩av| 欧美精品久久99| 一本久久综合亚洲鲁鲁五月天| 亚洲欧美日韩国产成人| 国产亚洲网站| 欧美国产激情| 中国女人久久久| 久久久久9999亚洲精品| 91久久在线| 国产精品剧情在线亚洲| 欧美一区二区三区日韩| 亚洲国产电影| 亚洲欧美日韩精品| 在线免费不卡视频| 国产精品久久久久aaaa九色| 久久精品国产成人| 一本大道久久精品懂色aⅴ| 久久另类ts人妖一区二区| 亚洲美洲欧洲综合国产一区| 国产精品日韩欧美一区二区三区 | 99re在线精品| 国产日产亚洲精品系列| 欧美成人蜜桃| 午夜伦欧美伦电影理论片| 亚洲电影免费在线| 欧美在线观看天堂一区二区三区| 91久久精品视频| 国产精品一区二区三区久久| 欧美成人影音| 久久精品国产精品亚洲| 一本色道久久综合亚洲精品小说| 麻豆精品视频在线观看视频| 亚洲在线成人精品| 亚洲精品中文字幕有码专区| 国产又爽又黄的激情精品视频| 欧美理论在线播放| 麻豆av一区二区三区| 午夜视频一区| 一区二区三区**美女毛片| 亚洲福利在线看| 久久尤物电影视频在线观看| 午夜精品亚洲| 亚洲视频一二| 一区二区三区 在线观看视频| 亚洲高清视频一区| 国产一区二区三区直播精品电影 | 亚洲一区欧美| 一区二区三区免费观看| 亚洲激情在线视频| 欧美激情一区二区在线| 麻豆精品视频在线| 麻豆久久婷婷| 美日韩精品视频| 久久男人资源视频| 久久久久国内| 久久一区国产| 久久一区二区三区国产精品| 久久夜色精品国产亚洲aⅴ| 久久久噜噜噜久久人人看| 久久久亚洲午夜电影| 久久久国产精彩视频美女艺术照福利| 西瓜成人精品人成网站| 香蕉国产精品偷在线观看不卡| 亚洲一区二区在线观看视频| 亚洲自拍高清| 欧美一区二区三区在线播放| 欧美一二三区在线观看| 久久国产主播精品| 久久久久久夜| 欧美大片第1页| 亚洲韩国日本中文字幕| 亚洲精品欧美极品| 亚洲午夜黄色| 欧美在线观看视频一区二区| 久久久亚洲人| 欧美激情视频给我| 欧美色大人视频| 国产欧美日韩视频| 精品成人国产| 亚洲精品日韩在线| 亚洲在线网站| 久久精品一区二区三区四区| 欧美va天堂va视频va在线| 亚洲激情另类| 亚洲一区在线看| 久久久精品动漫| 欧美剧在线观看| 国产精品最新自拍| 亚洲国产美女| 亚洲一区二区三区精品动漫| 久久久蜜桃精品| 最新国产の精品合集bt伙计| 亚洲午夜伦理| 美女主播一区| 国产精品久久久久久超碰| 黄色小说综合网站| 在线亚洲一区| 另类国产ts人妖高潮视频| 99精品视频一区二区三区| 欧美专区在线| 欧美日韩日韩| 在线播放豆国产99亚洲| 亚洲已满18点击进入久久| 久久综合五月天婷婷伊人| 亚洲最新色图| 另类图片国产| 国产日韩欧美一区二区三区在线观看| 亚洲国产精品久久| 欧美在线视频一区二区| 亚洲精品影院|