随笔 - 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 井泉 阅读(1457) | 评论 (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 井泉 阅读(558) | 评论 (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 井泉 阅读(511) | 评论 (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 井泉 阅读(746) | 评论 (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 井泉 阅读(1494) | 评论 (0)编辑 收藏

最近关注

函数式编程 haskell  F#
自动化测试管理 tcl/expect  tcl/tk   tcl 工具命令语言
嵌入式脚本 lua语言
Google Hacking 的实现以及应用

posted @ 2008-01-03 15:54 井泉 阅读(239) | 评论 (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 井泉 阅读(382) | 评论 (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 井泉 阅读(1913) | 评论 (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 井泉 阅读(283) | 评论 (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 井泉 阅读(1440) | 评论 (0)编辑 收藏

仅列出标题
共8页: 1 2 3 4 5 6 7 8