• <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
            數據加載中……

            如何在Visual Studio 2005環境下用c語言調用ARM匯編,以便了解ARM指令

            在網上找到了一個這樣的例子,是Larry Bank寫的。貼出來以供大家學習。讓大家了解ARM匯編指令,并用vs2005進行調試跟蹤。

            工程是pocket pc 2003的工程,主要包含兩個文件:main.c, armtest.asm。

            對armtest.asm需要自定義編譯選項,

            命令行為 armasm -g armtest.asm
            輸出為   armtest.obj

            源碼如下:

            main.c 源碼

            // Windows CE Sample Application

            // Demonstrations how to use ARM assembly language within a C program

            // Written by Larry Bank 3/25/2007

            #include <windows.h>

            int iGlobal;

            int ARMTEST1(int, int, int , int);

            /****************************************************************************

            * FUNCTION : WinMain(HANDLE, HANDLE, LPSTR, int)                                               *

            * PURPOSE : Program entrypoint                                                                               * ****************************************************************************/

            int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)

            {

                  int iResult;

                  TCHAR szTemp[256];

                  iGlobal = 5;

                  iResult = ARMTEST1(1,2,3,4);

                  wsprintf(szTemp, L"Result = %d", iResult);

                  MessageBox(HWND_DESKTOP, szTemp, L"ASM Result", MB_OK);

                 return 0;

            } /* WinMain() */

            armtest.asm 源碼:

            ; TITLE("Sample App")

            ;++

                 AREA sample, CODE, READONLY ; name this block of code

                 EXPORT ARMTEST1

               IMPORT iGlobal

            ; Called from C as int ARMTEST1(int, int, int, int);

            ; The first 4 parameters are passed in r0-r3, more parameters would be passed on the stack

            ARMTEST1 proc

                add r0,r0,r1 ; add all of the inputs together

                add r0,r0,r2

                add r0,r0,r3 

               ldr r1,=iGlobal ; get the value of our global variable

                  ldr r1,[r1] ; dereference the pointer (I know there's a pipe stall here)

                add r0,r0,r1 ; we're not concerned with performance in this example

                mov pc,lr ; return to C with the value in R0

                 endp

                 LTORG ; allow room for the address constant of our global (loaded relative to PC)

                 END

            posted @ 2008-09-22 10:36 井泉 閱讀(1473) | 評論 (0)編輯 收藏

            hook其他進程的API 轉

            hook其他進程的API

                                                  

            今天終于有了一個小小的進步就算是自己的努力來完成的,沒想到HOOK其他進程的API原來這樣的簡單。其實就是兩個關鍵的技術(HOOK-API和遠程線程注入)。

            HOOK是一種WINDOWS下存在很久的技術了。
            HOOK一般分兩種
            1。HOOK MESSAGE
            2。HOOK API
            本問討論的是HOOK API。(如果你是HOOK高手就不要看了)
            在最初學HOOK-API的時候通常都是通過"覆蓋地址"和"修改IAT"的方法。
            通過這兩種技術,我們基本都可以實現對本進程的API函數進行HOOK了。但是在高興之余會有點遺憾,
            怎么才能HOOK其他進程的API函數呢?怎么才能對一個API函數進行全局的HOOK呢?
            下面是我的一個簡單的“HOOK其他進程API函數”的實現。(對另一進程的MessageBoxA這個函數進行HOOK)

            里面的應用了兩個技術
            1。遠程線程注入
            2。修改IAT,HOOK-API

            好了貼出代碼如下:
            一共是3個文件
            install.c  注入程序
            fundll.cpp  DLL程序
            test.cpp  測試程序  

            //-------------------------install.c--------------------------
            //
            //write by Gxter
            //install.c

            #include "windows.h"
            #include "tlhelp32.h"

            #pragma comment(lib,"th32.lib")

            const char *pkill="fundll.dll";        //DLL文件的路徑

            //這個路徑很有意思,這個路徑是相對于目標進程的,而不是自身進程。
            //所以要嘛寫成絕對路徑,要嘛寫成相對于目標進程的相對路徑。
            //如果寫成相對于自身的路徑就要麻煩了,本程序就找不到DLL文件了。

            char *prosess="test.exe";   //要注入的進程名(目標進程名)

            int main()
            {
                HANDLE hSnap;
                HANDLE hkernel32;    //被注入進程的句柄
                PROCESSENTRY32 pe;
                BOOL bNext;
                HANDLE hToken;
                TOKEN_PRIVILEGES tp;
                LUID Luid;
                LPVOID p;
                FARPROC pfn;

                if (!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken))
                {
                    return 1;
                }

                if (!LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&Luid))
                {
                    return 1;
                }

                tp.PrivilegeCount = 1;
                tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
                tp.Privileges[0].Luid = Luid;

                if (!AdjustTokenPrivileges(hToken,0,&tp,sizeof(TOKEN_PRIVILEGES),NULL,NULL))
                {
                    return 1;
                }

                pe.dwSize = sizeof(pe);
                hSnap=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
                bNext=Process32First(hSnap, &pe);
                while(bNext)
                {
                    if(!stricmp(pe.szExeFile,prosess))        //--->>
                    {
                        hkernel32=OpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_WRITE|PROCESS_VM_OPERATION,1,pe.th32ProcessID);
                        break;
                    }
                    bNext=Process32Next(hSnap, &pe);
                }

                CloseHandle(hSnap);

                p=VirtualAllocEx(hkernel32,NULL,strlen(pkill),MEM_COMMIT,PAGE_READWRITE);
                WriteProcessMemory(hkernel32,p,pkill,strlen(pkill),NULL);
                pfn=GetProcAddress(GetModuleHandle("kernel32.dll"),"LoadLibraryA");
                CreateRemoteThread(hkernel32,NULL,0,pfn,p,NULL,0);

                return 0;
            }


            //----------------------fundll.cpp-----------------------------
            //
            //write by Gxter
            //
            //fundll.cpp

            #include "windows.h"
            #include "process.h"
            #include "tlhelp32.h"
            #include "stdio.h"

            #pragma comment(lib,"th32.lib")

            PIMAGE_DOS_HEADER  pDosHeader;
            PIMAGE_NT_HEADERS  pNTHeaders;
            PIMAGE_OPTIONAL_HEADER   pOptHeader;
            PIMAGE_IMPORT_DESCRIPTOR  pImportDescriptor;
            PIMAGE_THUNK_DATA         pThunkData;
            PIMAGE_IMPORT_BY_NAME     pImportByName;
            HMODULE hMod;


            // 定義MessageBoxA函數原型
            typedef int (WINAPI *PFNMESSAGEBOX)(HWND, LPCSTR, LPCSTR, UINT uType);
            int WINAPI MessageBoxProxy(IN HWND hWnd, IN LPCSTR lpText, IN LPCSTR lpCaption, IN UINT uType);

            int * addr = (int *)MessageBoxA;    //保存函數的入口地址
            int * myaddr = (int *)MessageBoxProxy;


            void ThreadProc(void *param);//線程函數


            BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
            {
                if(fdwReason==DLL_PROCESS_ATTACH)    
                    _beginthread(ThreadProc,0,NULL);    

                return TRUE;
            }


            //結束進程的函數

            void ThreadProc(void *param)
            {
                //------------hook api----------------
                hMod = GetModuleHandle(NULL);

                pDosHeader = (PIMAGE_DOS_HEADER)hMod;
                pNTHeaders = (PIMAGE_NT_HEADERS)((BYTE *)hMod + pDosHeader->e_lfanew);
                pOptHeader = (PIMAGE_OPTIONAL_HEADER)&(pNTHeaders->OptionalHeader);

                pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((BYTE *)hMod + pOptHeader->DataDirectory[1].VirtualAddress);

                while(pImportDescriptor->FirstThunk)
                {
                    char * dllname = (char *)((BYTE *)hMod + pImportDescriptor->Name);

                    pThunkData = (PIMAGE_THUNK_DATA)((BYTE *)hMod + pImportDescriptor->OriginalFirstThunk);

                    int no = 1;
                    while(pThunkData->u1.Function)
                    {
                        char * funname = (char *)((BYTE *)hMod + (DWORD)pThunkData->u1.AddressOfData + 2);
                        PDWORD lpAddr = (DWORD *)((BYTE *)hMod + (DWORD)pImportDescriptor->FirstThunk) +(no-1);
                    
                        //修改內存的部分
                        if((*lpAddr) == (int)addr)
                        {
                            //修改內存頁的屬性
                            DWORD dwOLD;
                            MEMORY_BASIC_INFORMATION  mbi;
                            VirtualQuery(lpAddr,&mbi,sizeof(mbi));
                            VirtualProtect(lpAddr,sizeof(DWORD),PAGE_READWRITE,&dwOLD);
                            
                            WriteProcessMemory(GetCurrentProcess(),
                                    lpAddr, &myaddr, sizeof(DWORD), NULL);
                            //恢復內存頁的屬性
                            VirtualProtect(lpAddr,sizeof(DWORD),dwOLD,0);
                        }
                        //---------
                        no++;
                        pThunkData++;
                    }

                    pImportDescriptor++;
                }
                //-------------------HOOK END-----------------
            }

            //new messagebox function
            int WINAPI MessageBoxProxy(IN HWND hWnd, IN LPCSTR lpText, IN LPCSTR lpCaption, IN UINT uType)
            {
                return     ((PFNMESSAGEBOX)addr)(NULL, "gxter_test", "gxter_title", 0);
                //這個地方可以寫出對這個API函數的處理代碼
            }


            //----------------------------test.cpp------------------------------------
            //
            //write by Gxter
            //test.cpp

            #include "stdio.h"
            #include "windows.h"

            int main()
            {
                printf("test---\n");
                while(1)
                {
                    getchar();
                    MessageBoxA(NULL, "原函數", "09HookDemo", 0);
                }
                return 0;
            }

            //---------------------------THE--END--------------------------------------

            測試過程:先運行TEST不要關閉(建立目標),再運行install(進行注入)。但要注意FUNDLL和TEST文件位置。

            上面的代碼進本上就實現了對其他進程的API進行HOOK了。
            但還有一個問題就是對“API函數進行全局的HOOK”。我的想法就是注入所有進程就可以實現了。
            只要簡單的改一下上面的代碼就可以實現了。 這好象有點像SetWindowsHookEx這個函數的的實現過程。
            以上就是我想法了,如有錯誤還請斧正。

            Gxter.安康
            200501022

            posted @ 2008-09-18 16:11 井泉 閱讀(570) | 評論 (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 @ 2008-08-14 15:36 井泉 閱讀(526) | 評論 (0)編輯 收藏

            【轉帖】Windwos CE 跨進程內存注入(PocketPC)

            近日,由于程序設計需要,我對WincowsCE 的內存布局進行了研究,由于發現國內在這方面的文檔資料較少,于是在研究告一段落之際,形成這篇示例文檔,以望拋磚引玉,得到別的高手的指正。

              一、程序實現的先決條件

              由于windows系統的窗體消息總是投遞至一個特定進程的指定窗體消息函數中。于是在本地進程(自己的應用程序)中取得屬于其它進程的窗體的消息必須實現以下兩個部分:

              1、將需要掛接窗體的代碼放到目標進程的地址空間中去。

              2、執行這一段代碼,并獲得目標進程窗體的消息。

              這兩步看起來很簡單,但在實現過程中就比較困難。由于Windows CE作為嵌入式移動設備操作系統,與windows 98/2000/XP等桌面操作系統在 內核的設計理念以及API的支持上有極大的區別。這就直接導致了常規的桌面系統利用全局鼠標鉤子注入/遠程線程注入等方法在CE中完全得不通。不過可喜的 是,微軟在開發工具中提供的remotexxx等遠程調試程序使我清楚這個目標并不是不可能的任務,微軟既然可以做到,那就是說在CE的內部一定有一套完 整的跨進程內存訪問/代碼注入的機制。

              二、程序實現的基本原理

            經過兩天的google 搜索,在網上我發現了一個沒有在微軟文檔中聲明的有趣的API函數:PerformCallBack4,傳說中這個函數可以在自己的應用程序中執行指定的 進程中的一個函數,So Cool!這好象正是我所需要的東西。雖然網上也傳聞這個函數在wm5不受支持,其實經過實踐這個傳聞只是謠傳而已!

              PerformCallBack4函數的定義:

            [DllImport("coredll.dll")]
            public static extern uint PerformCallBack4(ref CallBackInfo CallBackInfo,
            IntPtr ni_pVoid1,IntPtr ni_pVoid2,IntPtr ni_pVoid3);

              其中函數的參數CallBackInfo結構定義:

            [StructLayout(LayoutKind.Sequential)]
            public struct CallBackInfo
            {
            public IntPtr hProc; //遠程的目標進程
            public IntPtr pfn; //指向遠程目標進程的函數地址的指針
            public IntPtr pvArg0; //函數的需要的第一個參數
            }//end struct

              而PerformCallback4的 ni_pVoid1、ni_pVoid2、ni_pVoid3為傳遞到遠程目標進程執行函數的其它三個參數。

              至于將代碼放到目標進程的內存空間,我們可以利用CE設計上的一個特性:

              1、為了節約內存使用,CE將所有程序調用的動態鏈接庫(DLL)都映射到同一個內存地址中。

              2、CE的內存布局中劃分有一個slot0的內存位置,這個內存位置是由正在執行的進程所占有的,每一個特定的時間片,只能有一個進程可以占有這個內存空 間。在進程要求執行時,系統并不直接執行進程所處內存位置的代碼,而是將該進程的執行代碼復制到slot0的內存位置中產生一個副本執行。也就是說進程在 執行時內存將會有進程執行代碼的兩個完全一樣的版本:存在于slot0中正在執行的進程代碼和進程本身所處的內存中的代碼。

              在這個特 性下,可以得到結論:如果進程A通過LoadLibrary函數裝載Test.dll,而進程B也通過LoadLibrary函數裝載同一個 Test.dll,這個Test.dll的所有函數在進程A和進程B中執行時,相對于slot0中的進程執行代碼都會得到同一地址。

            3、在CE中,系統在內存中劃分出33個slot,slot0保留給正在執行的進程,然后在進程啟動時將所有的代碼放到除slot0以外的一個slot中 (這就是臭名昭著的CE系統中內存最多只能有不多于32個程序執行的限制的來由)。在進程執行時,每個應用程序的內存訪問默認只能訪問slot0內存空間 中的地址以及進程所處的slot內存空間的地址。 但為使設備驅動程序可以訪問到它們所需的其它應用程序數據,CE提供了兩個函數以打破這個限制,SetKmode和 SetProcPermission,SetKmode函數告訴系統,當前運行的進程是否需要在內核模式中執行;SetProcPermission函數 可以接受一個位掩碼,每一位代碼一個slot的訪問控制,1代表可以訪問該slot的內存內容。0表示不能訪問該slot的內存內容。這兩個函數在 msdn中有幫助文檔,可參閱msdn的文檔說明。

              本文我們對實現的原理進行了剖析,在下一篇文章中我們將以一個小示例程序演示實現的全過程。



            在文章《淺析Windows CE跨進程內存注入實現窗體消息掛接(上)》中,我們已經得到了這個七巧板游戲所需要的所有小板塊,剩下的事就是等待我們按一定順序將合適的板塊放到合適的位置,本章我們開始進行真刀真槍的實戰演練。

            程序目標:捕獲explore窗體(也就是程序窗體的消息并輸出到WinProcInfo.txt中)

            程序的執行步驟設計如下:

            1、編寫一個窗體消息掛接DLL,這個DLL提供一個,函數中利用setwindowlong函數將窗體的默認消息處理過程改為這個掛接DLL中定義的一個窗體過程。

            2、在C#程序中利用findwindow等API函數獲得exlore類窗體的句柄及窗體所屬的進程,并使用performcallback4在目標進程空間中執行coredll.dll的loadLibrary函數將我們寫的掛接dll放到目標進程中。

            3、在C#程序中使用performcallback4在目標進程空間中執行掛接DLL提供的導出接口函數實現跨進程窗體消息截獲.

            一、程序的實現如下:

            在VS2005中建立一個智能設備的MFC DLL,命名為HookWindowsProcMFCDLL。

            在HookWindowsProcMFCDLL.cpp中進行掛接DLL的核心編碼:

            LRESULT CALLBACK fnHookWindowProc(HWND hwnd,UINT msg,WPARAM wparam, LPARAM lparam);

            int __declspec(dllexport) WINAPI fnAttachWinProc(HWND ni_hAttatchWin,PVOID ,PVOID,PVOID);

            int __declspec(dllexport) WINAPI fnDetachWinMsgProc(HWND ni_hDetachWin);

            WNDPROC tpOldWindowProc;

            FILE *m_pDebugOutputFile;

            //將一個窗體消息處理掛接到net精簡版MessageWindow對象上的代碼
            typedef struct
            {
             WNDPROC OldWinProc;//保留窗體原始消息處理過程的函數指針
             HWND WindowHandle;//保存net精簡版中對應的窗口掛接的MessageWindow對象的句柄
            } DEFUDT_AttachWinInfo; //end struct

            CMap<HWND,HWND,DEFUDT_AttachWinInfo,DEFUDT_AttachWinInfo> m_aAttachWinInfoMap;

            //對指定的窗口進程進行掛接
            int __declspec(dllexport) WINAPI fnAttachWinProc(HWND ni_hAttatchWin,
            PVOID ni_0,
            PVOID ni_1,
            PVOID ni_2 )
            {
             DEFUDT_AttachWinInfo tudtAttachWinInfo;
             m_pDebugOutputFile = fopen("\\Storage Card\\WinProcInfo.txt", "w");
             WNDPROC tpOldWindowProc=(WNDPROC)::SetWindowLong(ni_hAttatchWin, GWL_WNDPROC,(LONG) fnHookWindowProc );
             fprintf(m_pDebugOutputFile,"Attatch successfully! OldWindowProc: %08X\n",tpOldWindowProc);
             tudtAttachWinInfo.OldWinProc=tpOldWindowProc ;
             tudtAttachWinInfo.WindowHandle=ni_hAttatchWin;
             m_aAttachWinInfoMap.SetAt(ni_hAttatchWin,tudtAttachWinInfo);
             fclose(m_pDebugOutputFile);
             return 77;// (int)tpOldWindowProc ;
            }//end function

            int __declspec(dllexport) WINAPI fnDetachWinMsgProc(HWND ni_hDetachWin)
            {
             DEFUDT_AttachWinInfo tudtAttachWinInfo;
             WNDPROC tpOldWindowProc;

             //取得在ncf中消息接收窗口對應的原始消息處理函數的函數指針
             m_aAttachWinInfoMap.Lookup(ni_hDetachWin,tudtAttachWinInfo) ;

             //將窗體的消息處理函數設為默認的處理過程
             tpOldWindowProc =(WNDPROC) SetWindowLong(ni_hDetachWin,GWL_WNDPROC , (LONG)tudtAttachWinInfo.OldWinProc);

             //將掛接信息消息處理映謝類中刪除
             m_aAttachWinInfoMap.RemoveKey(ni_hDetachWin);

             return (int)tpOldWindowProc ;

            }//end function


            LRESULT CALLBACK fnHookWindowProc(HWND hwnd,UINT msg,WPARAM wparam, LPARAM lparam)
            {
             DEFUDT_AttachWinInfo tudtAttachWinInfo;
             m_aAttachWinInfoMap.Lookup(hwnd,tudtAttachWinInfo) ;
             m_pDebugOutputFile = fopen("\\Storage Card\\WinProcInfo.txt", "a");
             if (m_pDebugOutputFile!=NULL)
             {
              fprintf(m_pDebugOutputFile,"HWND: %08X Msg: %08X Wparam %08X Lparam %08X \n",
            hwnd,msg,wparam,lparam);

             }//EHD IF

             fclose(m_pDebugOutputFile);
             //tudtAttachWin=maatt
             LRESULT tobjResult= ::CallWindowProc(tudtAttachWinInfo.OldWinProc ,hwnd,msg,wparam,lparam);
             return tobjResult;
            }//end function

            而在C#的主程序中,我們使用這個DLL掛接explore類的程序窗體,以下給出掛接部分的代碼:

            int m_hTargetWindow;//要掛接的目標窗體句柄
            IntPtr m_hTargetProcess;//目標窗體所屬的進程
            IntPtr m_hModule; //掛接DLL的句柄

            private void Form1_Load(object sender, EventArgs e)
            {
             IntPtr tpTemp = IntPtr.Zero, tpTempa = IntPtr.Zero;
             uint tuntApiRet;

             m_hTargetWindow = (int)clsCECoreAPI.FindWindow("Explore", null );//資源管理器 0x0013e800;

             //掛接指定的進程窗體消息
             IntPtr thCurrentProcess = clsCECoreAPI.GetCurrentProcess();
             m_hTargetProcess=IntPtr.Zero ;// (IntPtr) (unchecked((int)0xedd84e4a));
             tuntApiRet= clsCECoreAPI.GetWindowThreadProcessId(new IntPtr(unchecked((int) m_hTargetWindow)),
            ref m_hTargetProcess);

             string tstrArgument;
             tstrArgument = "\\Program Files\\processinject\\HookWindowsProcMFCDLL.dll";// HookWindowsProcMFCDLL.dll";
             IntPtr tpArg0;

             int tintOriginalKMode = clsCECoreAPI.SetKMode(1);
             int tintOriginalProcPermission = (int)clsCECoreAPI.SetProcPermissions(0xffffffff);

             IntPtr tpFuncProc = clsCECoreAPI.GetProcAddress(clsCECoreAPI.GetModuleHandle("coredll.dll"), "LoadLibraryW");

             CallBackInfo tudtCALLBACKINFO;

             tpArg0 = clsCECoreAPI.MapPtrToProcess(tstrArgument, thCurrentProcess);

             tudtCALLBACKINFO.hProc = m_hTargetProcess;// Proc;
             tudtCALLBACKINFO.pfn = clsCECoreAPI.MapPtrToProcess(tpFuncProc, m_hTargetProcess);
             tudtCALLBACKINFO.pvArg0 = tpArg0;
             m_hModule =new IntPtr(unchecked(
            (int) clsCECoreAPI.PerformCallBack4(ref tudtCALLBACKINFO,IntPtr.Zero,IntPtr.Zero,IntPtr.Zero )));
             //clsCECoreAPI.Sleep(1000);

             IntPtr thModule = clsCECoreAPI.LoadLibrary("HookWindowsProcMFCDLL.dll");
             tpFuncProc = clsCECoreAPI.GetProcAddress(thModule, "fnAttachWinProc");

             tpArg0 = (IntPtr) m_hTargetWindow;// clsCECoreAPI.MapPtrToProcess(ref thTargetWindow, thCurrentProcess);

             tudtCALLBACKINFO.hProc = m_hTargetProcess;
             tudtCALLBACKINFO.pfn = clsCECoreAPI.MapPtrToProcess(tpFuncProc, m_hTargetProcess);
             tudtCALLBACKINFO.pvArg0 = tpArg0 ;
             tuntApiRet = clsCECoreAPI.PerformCallBack4(ref tudtCALLBACKINFO,IntPtr.Zero,IntPtr.Zero,IntPtr.Zero );
             //clsCECoreAPI.Sleep(5000);
            }

            [DllImport("HookWindowsProcMFCDLL.dll")]
            public static extern int fnAttachWinProc(IntPtr ni_hAttatchWin);

            [DllImport("HookWindowsProcMFCDLL.dll")]
            public static extern int fnDetachWinMsgProc(IntPtr ni_hDetachWin);

            取消掛接的代碼根據上述代碼很容易就可以建立,不再細敘。

            注:clsCECoreAPI的函數全是封裝的標準CE API,由于這些API在msdn 中都有詳細的文檔注釋,因篇幅所限,不再將代碼一一列舉.

            在執行這個程序時,將模擬器的共享路徑設為PC機的桌面,這樣模擬器的storage card目錄就等同桌面了,點模擬器的開始菜單,選程序,你就可以看到explore窗體的消息都輸出到桌面的WinProcInfo.txt文件中了,運行結果如下:

              

             目前本程序只在PPC2003/wm5 for PPC測試通過,由于smartphone系統在編譯時使用了和ppc系統不同的機制,內存運作不明,本程序在smartphone上無法正確運行,有好的建議的話請指教一二,謝謝.

            posted @ 2008-08-14 09:29 井泉 閱讀(771) | 評論 (0)編輯 收藏

            MapPtrToProcess 用法 WINCE驅動分析3 轉

            可以使用下面的應用程序代碼測試這個driver,使用evc編譯。

            #include <windows.h>

            #include<Windev.h>

            #include <stdio.h>

            #include "objbase.h"

            #include "initguid.h"

             

            #include "foo.h"

             

            //char data1[10];

            int  WinMain(void)

            {

             

             

                HANDLE hnd;

                COPY_STRUCT cs[1];

                int i;

                //static char data1[10];

              auto char data1[10];

                auto char data2[10];

             

                static char* p1,*p2;

             

                //cs.pBuffer1 = (char *)malloc(10);

                //cs.pBuffer2 = (char*)malloc(10);

                //cs.nLen = 10;

             

                p1 = (char *)LocalAlloc(LPTR,10);

                p2 = (char *)malloc(10);

             

                //cs[0].pBuffer1 = (char *)malloc(10);

                //cs[0].pBuffer2 = (char*)malloc(10);

                cs[0].pBuffer1 = &data1[0];

                cs[0].pBuffer2 = &data2[0];

                cs[0].nLen = 10;

             

                memset(cs[0].pBuffer1,'a',10);

             

                hnd = CreateFile(FOO_DEV_NAME,GENERIC_READ|GENERIC_WRITE,0,NULL,0,0,NULL);

             

                if(hnd==NULL)

                {

                       printf("Open device falied!\n");

                       return;

                }

             

                DeviceIoControl(hnd,IOCTL_FOO_XER,&cs[0],sizeof(COPY_STRUCT),NULL,0,NULL,NULL);

             

                //for(i=0;i<9;i++)

                //{

                       //printf(" %c",*(cs.pBuffer2++));

                //}

             

                printf("\n");

             

                CloseHandle(hnd);

             

            //  free(cs[0].pBuffer1);

            //  free(cs[0].pBuffer2);

             

             

            }

             

            可以通過evc的單步調試看結果。好了一切都完成了,我們來看看系統是怎么工作的吧,從應用程序開始,

            CreateFile(FOO_DEV_NAME,GENERIC_READ|GENERIC_WRITE,0,NULL,0,0,NULL);

             

            會調用到

            FOO_Open(DWORD dwContext, DWORD AccessCode, DWORD ShareMode)

             

            FOO_DEV_NAME名字定義在foo.h里面。

            #define       FOO_DEV_NAME L"Foo1:"

            注意后面是 1 ,這個是和注冊表的這一項匹配的

            "Index"=dword:1

             

            當調用CreateFile發生了什么,slot之間的轉換,一系列系統操作后,調用到我們自己的driver函數FOO_Open,在這個函數里我們返回了一個句柄,它可以用來存儲我們的自己driver的信息。在其它I/O操作中可以使用。

             

            Driver什么時候加載的?在注冊表里,device manager會一個個的加載,會調用到FOO_Init函數。這個函數返回一個指針,在調用FOO_Open又傳回來了,這樣我們就可以實現初始化一些自己driver的東西。

             

            接著一個重要的函數,

            DeviceIoControl(hnd,IOCTL_FOO_XER,&cs[0],sizeof(COPY_STRUCT),NULL,0,NULL,NULL);

            調用到

            FOO_IOControl

             

            走到這里

            case IOCTL_FOO_XER:

                       if((pInBuf==NULL))

                              {

                                     SetLastError(ERROR_INVALID_PARAMETER);

                                     break;

                              }

             

                              pcs = (COPY_STRUCT*)pInBuf;

                             

                              __try{

                                     pMap1 =  MapPtrToProcess(pcs->pBuffer1,GetCallerProcess());

                                     pMap2 =  MapPtrToProcess(pcs->pBuffer2,GetCallerProcess());

             

                                     DEBUG_OUT(1, (TEXT("+FOO_IOControl(0x%x,0x%x)\r\n"),pcs->pBuffer1,pcs->pBuffer2));

             

                                     memcpy(pcs->pBuffer2,pcs->pBuffer1,pcs->nLen);

             

                                     bResult = TRUE;

                                     }

                              __except(EXCEPTION_EXECUTE_HANDLER){

                                     DEBUG_OUT(1,(TEXT("Exception:FOO_IOCTL\r\n")));

                                     break;                         

                              }

                             

                              break;

                       default:

                              break;

             

            這里又很多東西要研究,

             

            從應用程序傳來的參數有, control codeIOCTL_FOO_XER和一個重要的輸入參數&cs[0],它是一個指針。cs 是一個結構體,定義在FOO.H

            typedef struct {

                char* pBuffer1;

                char* pBuffer2;

                int nLen;

             

            }COPY_STRUCT;

             

            而且這個結構體里有兩個指針。

            DeviceIoControl 傳過來的指針可以用嗎?它包含的兩個指針可以直接用嗎?

             

            按照PB連接幫助文檔看,

            The operating system (OS ) manages pointers passed directly as parameters. Drivers must map all pointers contained in structures. DeviceIoControl buffers are often structures that contain data, some of which might be pointers.

            You can map a pointer contained in a structure by calling MapPtrToProcess, setting the first parameter to the pointer, and then setting the second parameter to GetCallerProcess.

            cs指針已經映射好了,但是它指向的結構里的指針我們需要自己使用MapPtrToProcess函數映射。

            這也就是:

                                     pMap1 =  MapPtrToProcess(pcs->pBuffer1,GetCallerProcess());

                                     pMap2 =  MapPtrToProcess(pcs->pBuffer2,GetCallerProcess());

            的由來,可是后面的代碼沒有使用pMap1pMap2。而是直接使用:

            memcpy(pcs->pBuffer2,pcs->pBuffer1,pcs->nLen);

             

            而且它還工作了,沒有出現exception。很奇怪。我第一次在一個家伙的代碼里看見這種情況,很吃驚,但是它工作的很好,是文檔出錯了?

            我們來分析一下,看看應用程序的代碼:

                COPY_STRUCT cs[1];

              auto char data1[10];

                auto char data2[10];

            cs結構和data1data2數組都是自動變量,存放在堆棧里。假設這個應用程序被加載到0x18000000位置的slot里,那么他們的地址都是0x18XXXXXX。不熟悉wince memory architecture的可以看看資料,了解一下slot。當調用了

            DeviceIoControl,按照文檔的說法,cs指針得到了轉換,因為從應用程序的進程轉到了device.exe進程,而device進程又是當前的運行的進程,被映射到了slot0,系統負責轉換cs指針。而cs包含的pBuffer1pBuffer2是沒有映射不能直接用的。

            事實上,我們傳過來的指針根本就是不需要映射,因為他們都是0x18xxxxxx,在應用程序的slot里,所以只要device.exe有訪問應用程序的權限,就可以了。而這個權限,系統已經幫我們設置好了。

             

            那什么情況下要自己映射呢?

            如果應用程序在定義 data1data2使用static關鍵字,或者使用LocalAllocHeapAlloc的時候,一定要自己映射cs里的指針。

            在應用程序里這樣寫:

                cs.pBuffer1 = (char *)malloc(10);

                cs.pBuffer2 = (char*)malloc(10);

                cs.nLen = 10;

            如果不使用MapPtrToProcess完成映射,那就出現data abort exception.

             

            為什么呢?

            因為這些變量都是在堆里分配的,而當應用程序運行時,被映射到slot0,堆的地址也就是處于slot的范圍內,傳遞到device.exe后,device.exe被映射到了slot0,這個時候必須要將應用程序的指針映射回應用程序所在的slot。否則訪問的是device.exe的空間,會發生不可知道的結果。

             

            驗證一下上面說的地址分配問題。

             

            我們這樣定義

            COPY_STRUCT cs[1];

              static char data1[10]; 堆里

              auto char data2[10];   棧里

             

            這樣賦值:

             

              cs[0].pBuffer1 = &data1[0];

              cs[0].pBuffer2 = &data2[0];

              cs[0].nLen = 10;

             

            調試信息:

            cs[0].pBuffer1 = &data1[0];

             

            180112D0   ldr       r2, [pc, #0xD0]

            180112D4   str       r2, [sp, #0x10]

             

            讀取&data1[0]使用的是PC作為基址,而此時的應用程序處于運行階段映射到slot0,那么pc也就在0~01ffffff范圍,我的調試結果是在0x000112D0+8,使用的是arm,流水線機制,當前指令地址+8才是pc值。

             

            143:      cs[0].pBuffer2 = &data2[0];

            180112D8   add       r0, sp, #0x20

            180112DC   str       r0, [sp, #0x14]

            讀取&data2[0]采用的是sp作為基址,sp在應用程序加載到slot的時候就確定了的。所以保持了在應用程序slot的值,處于0x18xxxxxx范圍。

             

            我們看到因為winceslot機制,我們有時候需要映射,有時候不需要。所以wince文檔說結構里的指針要映射。畢竟你不知道應用程序怎么寫。

            當然,你可以根本不映射,只要把那個結構屏蔽調,寫一個STATIC LIBRARY給用戶使用,自己保證使用正確的地址分配就可以了。上面我說的那個家伙就是這么干的。

             

            好了,接著

            調用:

              CloseHandle(hnd);

            程序結束了,完成了一次簡單的拷貝。

             

            這個框架完成了,driver的基本接口設計,強調了內存指針的使用問題。但是相對于一個真正的driver,還缺少點東西,就是訪問硬件的方法。下面繼續討論如何訪問硬件。

            posted @ 2008-08-14 09:28 井泉 閱讀(1512) | 評論 (0)編輯 收藏

            最近關注

            函數式編程 haskell  F#
            自動化測試管理 tcl/expect  tcl/tk   tcl 工具命令語言
            嵌入式腳本 lua語言
            Google Hacking 的實現以及應用

            posted @ 2008-01-03 15:54 井泉 閱讀(252) | 評論 (0)編輯 收藏

            windows 命令大全

             winver---------檢查windows版本
            wmimgmt.msc----打開windows管理體系結構(wmi)
            wupdmgr--------windows更新程序
            wscript--------windows腳本宿主設置
            write----------寫字板
            winmsd---------系統信息
            wiaacmgr-------掃描儀和照相機向導
            winchat--------xp自帶局域網聊天
            mem.exe--------顯示內存使用情況
            msconfig.exe---系統配置實用程序
            mplayer2-------簡易widnows media player
            mspaint--------畫圖板
            mstsc----------遠程桌面連接
            mplayer2-------媒體播放機
            magnify--------放大鏡實用程序
            mmc------------打開控制臺
            mobsync--------同步命令

            --------------------------------------------------------------------------------

            dxdiag---------檢查directx信息
            drwtsn32------ 系統醫生
            devmgmt.msc--- 設備管理器
            dfrg.msc-------磁盤碎片整理程序
            diskmgmt.msc---磁盤管理實用程序
            dcomcnfg-------打開系統組件服務
            ddeshare-------打開dde共享設置
            dvdplay--------dvd播放器

            --------------------------------------------------------------------------------

            net stop messenger-----停止信使服務
            net start messenger----開始信使服務
            notepad--------打開記事本
            nslookup-------網絡管理的工具向導
            ntbackup-------系統備份和還原
            narrator-------屏幕“講述人”
            ntmsmgr.msc----移動存儲管理器
            ntmsoprq.msc---移動存儲管理員操作請求
            netstat -an----(tc)命令檢查接口

            --------------------------------------------------------------------------------

            syncapp--------創建一個公文包
            sysedit--------系統配置編輯器
            sigverif-------文件簽名驗證程序
            sndrec32-------錄音機
            shrpubw--------創建共享文件夾
            secpol.msc-----本地安全策略
            syskey---------系統加密,一旦加密就不能解開,保護windows xp系統的雙重密碼
            services.msc---本地服務設置
            sndvol32-------音量控制程序
            sfc.exe--------系統文件檢查器
            sfc /scannow---windows文件保護

            --------------------------------------------------------------------------------

            tsshutdn-------60秒倒計時關機命令
            tourstart------xp簡介(安裝完成后出現的漫游xp程序)
            taskmgr--------任務管理器

            --------------------------------------------------------------------------------

            eventvwr-------事件查看器
            eudcedit-------造字程序
            explorer-------打開資源管理器

            --------------------------------------------------------------------------------

            packager-------對象包裝程序
            perfmon.msc----計算機性能監測程序
            progman--------程序管理器

            --------------------------------------------------------------------------------

            regedit.exe----注冊表
            rsop.msc-------組策略結果集
            regedt32-------注冊表編輯器
            rononce -p ----15秒關機
            regsvr32 /u *.dll----停止dll文件運行
            regsvr32 /u zipfldr.dll------取消zip支持

            --------------------------------------------------------------------------------

            cmd.exe--------cmd命令提示符
            chkdsk.exe-----chkdsk磁盤檢查
            certmgr.msc----證書管理實用程序
            calc-----------啟動計算器
            charmap--------啟動字符映射表
            cliconfg-------sql server 客戶端網絡實用程序
            clipbrd--------剪貼板查看器
            conf-----------啟動netmeeting
            compmgmt.msc---計算機管理
            cleanmgr-------垃圾整理
            ciadv.msc------索引服務程序

            --------------------------------------------------------------------------------

            osk------------打開屏幕鍵盤
            odbcad32-------odbc數據源管理器
            oobe/msoobe /a----檢查xp是否激活
            lusrmgr.msc----本機用戶和組
            logoff---------注銷命令

            --------------------------------------------------------------------------------

            iexpress-------木馬捆綁工具,系統自帶

            --------------------------------------------------------------------------------

            nslookup-------ip地址偵測器

            --------------------------------------------------------------------------------

            fsmgmt.msc-----共享文件夾管理器

            --------------------------------------------------------------------------------

            utilman--------輔助工具管理器

            --------------------------------------------------------------------------------

            gpedit.msc-----組策略

            posted @ 2008-01-03 15:21 井泉 閱讀(396) | 評論 (0)編輯 收藏

            <轉貼>在VS.net中配置LUA


            第1步:
            從官方主頁www.lua.org下載Lua源代碼,最新版本為5.1.2。
            解壓之后找到“src”文件夾,這里面就是Lua了,不過還不能直接使用。

            第2步:
            使用任意ANSI C編譯器,在這里使用VS2005編譯LUA。具體步驟如下:
            1、新建一個空的Console工程,在這里該工程名暫為“lua”
            2、將src中的文件全部拷貝到該項目文件夾下
            3、根據生成的文件來添加需要編譯的文件
            4、使用Release配置來進行編譯

            以下是各類生成文件的詳細說明:

            動態庫編譯 定義def文件 或者

            首先需要修改一下Lua.h頭文件。如下:
              /* mark for all API functions */
              //#ifndef LUA_API
              //#define LUA_API extern
              //#endif
              #ifdef LUA502_EXPORTS // 根據自己的項目而定
               #define LUA_API __declspec(dllexport)
              #else
               #define LUA_API __declspec(dllimport)
              #endif
              然后用vc建立一個win32 dll,包含*.h和*.c文件(參考一),編譯即可。

            靜態庫文件lua.lib

            1、添加除了“lua.c”與“luac.c”以外的全部文件到工程
            2、更改[項目屬性]->[配置屬性]->[常規]->[項目類型]為“靜態庫文件(.lib)”

            解釋器lua.exe

            1、添加除了“luac.c”以外的全部文件到工程
            2、更改Release狀態下[項目屬性]->[配置屬性]->[常規]->[項目類型]為“應用程序(.exe)”

            編譯器luac.exe

            3.1、添加除了“lua.c”以外的全部文件到工程
            3.2、更改Release狀態下[項目屬性]->[配置屬性]->[常規]->[項目類型]為“應用程序(.exe)”
            注意:該文件生成時的名字為lua.exe,因為該項目名稱為“lua”。如果之前生成過解釋器lua.exe,則應該將解釋器移走之后再生成。

            2、使用LUA

            使用靜態庫lua.lib

            1、新建一個空的console工程,并添加一個空的源文件
            2、在該文件中添加以下代碼,并自行修改關于路徑的部分
            //================================================================================================================
            //                      Lua Test Object
            //                      C++ Source lua_test.cpp
            //================================================================================================================
            //================================================================================================================
            //                      Include Files
            //================================================================================================================
            extern "C"
            {
            #include "D:\\My Documents\\Visual Studio 2005\\Projects\\lua\\lua\\lua.h"
            #include "D:\\My Documents\\Visual Studio 2005\\Projects\\lua\\lua\\lualib.h"
            #include "D:\\My Documents\\Visual Studio 2005\\Projects\\lua\\lua\\lauxlib.h"
            }
            //================================================================================================================
            //                      Libraries
            //================================================================================================================
            #pragma comment( lib ,"D:\\My Documents\\Visual Studio 2005\\Projects\\lua\\release\\lua.lib")
            //================================================================================================================
            //                      Main Functions
            //================================================================================================================
            int main( void)
            {
              return 1;
            }
            3、如果編譯通過,表示靜態庫文件lua.lib配置成功。

            使用解釋器lua.exe

            1、設置系統環境變量
                   我的電腦->屬性->高級->環境變量(N )->系統變量->Path->在尾部添加 ;+lua.exe所在路徑,如
                   ;d:\My Documents\Visual Studio 2005\Projects\lua\release,重啟機器。
            2、新建文本文件,輸入 print("Hello World"),退出將文件名改為 a.lua
            3、在CMD中輸入 lua a.lua
            4、如果出現字符串 Hellow World,表示解釋器lua.exe配置成功

            使用編譯器luac.exe

            1、設置系統環境變量
                   我的電腦->屬性->高級->環境變量(N )->系統變量->Path->在尾部添加 ;+lua.exe所在路徑,如
                   ;d:\My Documents\Visual Studio 2005\Projects\lua\release,重啟機器。
            2、新建文本文件,輸入 print("Hello World"),退出將文件名改為 a.lua(可以直接使用之前的a.lua)
            3、在CMD中輸入 luac a.lua
            4、如果在a.lua所在的目錄下出現luac.out文件,表示解釋器luac.exe配置成功

            posted @ 2008-01-02 16:37 井泉 閱讀(1931) | 評論 (1)編輯 收藏

            在CPP中調用Jscript中的函數(轉)

            CPP中調用Jscript中的函數

             

            C++中調用Jscript的函數非常簡單,Windows提供了一個msscript.ocx的控件,利用這個控件可以直接操作Jscript: 執行一段Jscript腳本,或者調用指定的函數。我寫了一個簡單的例子:

             

            l         導入msscript.ocx。下面這條指令會在項目目錄中生成msscript.tlimsscript.tlh兩個文件,里面有msscript.ocx中所有接口的描述和IID的定義。

            #import "msscript.ocx" no_namespace

             

            l         聲明一個對象。

            CComPtr<IScriptControl> m_iScriptControl;

             

            l         創建對象實例

            if(SUCCEEDED(m_iScriptControl.CoCreateInstance(__uuidof(ScriptControl))))

             

            l         設置語言等屬性。

            m_iScriptControl->PutLanguage(L"JScript");

            m_iScriptControl->PutAllowUI(VARIANT_FALSE);

             

            l         加入Jscript代碼。

            m_iScriptControl->AddCode(L"function test(str1, str2) { return str1 + \"-ok-\" + str2; }");

             

            l         獲得函數,這里要說明的是GetItem的參數是1n,而不是0n-1

            CComPtr<IScriptProcedureCollection> aProcedureSet = m_iScriptControl->GetProcedures();

            long n = aProcedureSet->GetCount();

             

            CComPtr<IScriptProcedure> aProcedure = aProcedureSet->GetItem(_variant_t(n));

            _bstr_t strFunction = aProcedure->GetName();

             

             

            l         準備函數參數。

            VARIANT va = {0};

            va.vt = VT_BSTR;

             

            n = 2;

            SAFEARRAYBOUND bounds[1] = {0};

            bounds[0].cElements = n;

            SAFEARRAY* psa = SafeArrayCreate(VT_VARIANT, 1, bounds);

             

            long i = 0;

            for(i = 0; i < n; i++)

            {

                     va.bstrVal = SysAllocString(L"test");

                     SafeArrayPutElement(psa, &i, &va);

            }

             

            l         調用函數。

            _variant_t Result = m_iScriptControl->Run(strFunction, &psa);

             

            l         釋放參數。

            for(i = 0; i < n; i++)

            {

                     va.bstrVal = SysAllocString(L"test");

                     SafeArrayGetElement(psa, &i, &va);

                     SysFreeString(va.bstrVal);

            }

            SafeArrayDestroy(psa);

            有個開源的工具 clipp,clipp.sourceforge.net ,比 OCX 出色的多

            posted @ 2008-01-02 10:41 井泉 閱讀(296) | 評論 (0)編輯 收藏

            windows mobile 函數

             Windows Mobile 6為開發人員帶來的新特性 本次課程將為您介紹Windows Mobile 6提供的最新API,其中包括聲音,WISP(Windows Ink Services for Pen (WISP)),DLOCK,Home Screen和其它可供開發人員在Windows Mobile中使用的API。
            Outlook DLock allows you to unlock locked attached files in Outlook XP.
            NETCFv2.wm.armv4i.cab     ,System_SR_CHS_wm.cab  


            以下 API 通過 AYGShell 公開。

            編程元素 說明
            SHChangeNotifyDeregister
             該函數禁用窗口接收文件更改通知的功能。
             
            SHChangeNotifyFree
             該函數清除文件更改通知。
             
            SHChangeNotifyRegister
             該函數登記用于接收更改通知的應用程序。
             
            SHCloseApps
             該函數嘗試為應用程序釋放內存。
             
            SHCreateMenuBar
             該函數在屏幕底部創建菜單欄。
             
            SHCreateNewItem
             該函數以編程方式創建新的項,好像該項是從全局 NEW 下拉菜單中選擇的。
             
            SHDoneButton
             該函數允許應用程序基于應用程序的狀態動態顯示或隱藏 OK 按鈕。
             
            SHEnumPropSheetHandlers
             該函數通過枚舉類項 hkey 下面的子項來支持屬性表擴展。
             
            SHFindMenuBar
             該函數用來獲得菜單欄窗口的句柄。
             
            SHFreeContextMenuExtensions
             該函數釋放為處理上下文菜單而分配的內存。
             
            SHFullScreen
             該函數用來接管某些屏幕區域。
             
            SHGetAppKeyAssoc
             該函數用于確定導航控件是否被映射到應用程序。
             
            SHGetAutoRunPath
             該函數搜索第一個存儲卡,并構造用來查找自動運行文件的路徑。
             
            SHHandleWMActivate
             該函數用來幫助管理輸入面板和您的應用程序。
             
            SHHandleWMSettingChange
             該函數用來幫助管理輸入面板和您的應用程序。
             
            SHInitDialog
             該函數調整對話框的大小,使其適合軟件輸入面板。
             
            SHInitExtraControls
             該函數調整對話框的大小,使其適合軟件輸入面板。
             
            SHInputDialog
             該函數用于處理輸入對話框。
             
            SHInvokeContextMenuCommand
             該函數調用上下文菜單中的命令。
             
            SHLoadContextMenuExtensions
             該函數從指定的上下文和類的配對所對應的注冊表中列出的處理程序加載上下文菜單擴展。
             
            SHNotificationAdd
             該函數將通知異步地添加到通知欄。
             
            SHNotificationGetData
             該函數獲得通知的數據。
             
            SHNotificationRemove
             該函數刪除通知。
             
            SHNotificationUpdate
             該函數更新掛起通知的某些方面的內容。
             
            SHRecognizeGesture
             該函數被自定義控件用來識別某些筆針的筆勢。
             
            SHSetAppKeyWndAssoc
             該函數指派某個窗口負責接收特定硬件按鍵的按鍵消息。
             
            SHSetNavBarText
             該函數設置任務欄中的標題文本。
             
            SHSipInfo
             該函數向外殼查詢與輸入面板和輸入方法有關的信息。
             
            SHSipPreference
             該函數為輸入面板請求位置。


            通過provxml文件配置的,

            這個文件必須要編到BIN檔里,如果修改文件名,bib也要相應修改。

            platform.bib

            posted @ 2007-12-25 10:00 井泉 閱讀(1456) | 評論 (0)編輯 收藏

            僅列出標題
            共8頁: 1 2 3 4 5 6 7 8 
            中文字幕亚洲综合久久2| 94久久国产乱子伦精品免费| 狠狠色综合网站久久久久久久| 久久99精品国产麻豆| 久久国产AVJUST麻豆| 午夜视频久久久久一区| 久久人人爽人人爽人人片AV东京热| 国产精品久久久久影院色| 丰满少妇高潮惨叫久久久| 久久这里只有精品18| 久久久久久亚洲精品成人| 97久久超碰成人精品网站| 国产一区二区精品久久| 91视频国产91久久久| 91精品婷婷国产综合久久| 国产成人久久精品二区三区| 久久99精品久久久久久9蜜桃| 91精品国产91久久| 久久性精品| 99久久精品免费看国产一区二区三区 | 久久精品国产亚洲精品2020 | 久久国产免费观看精品3| 久久国产精品99国产精| 91久久精品电影| 午夜精品久久久久9999高清| 久久综合亚洲色HEZYO社区| 亚洲精品无码久久久久久| 国产成人精品久久免费动漫| 大香网伊人久久综合网2020| 久久天天躁狠狠躁夜夜2020老熟妇 | 久久无码AV中文出轨人妻| 久久久一本精品99久久精品66 | 亚洲国产成人久久综合碰| 亚洲AV无码久久精品成人| 久久久久综合网久久| 日韩中文久久| 国内精品久久人妻互换 | 亚洲AⅤ优女AV综合久久久| 欧美大香线蕉线伊人久久| 国内精品久久久久国产盗摄| 色天使久久综合网天天|